1<?php 2 3/** 4 * compose.php 5 * 6 * This code sends a mail. 7 * 8 * There are 4 modes of operation: 9 * - Start new mail 10 * - Add an attachment 11 * - Send mail 12 * - Save As Draft 13 * 14 * @copyright 1999-2021 The SquirrelMail Project Team 15 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 16 * @version $Id: compose.php 14921 2021-05-12 05:12:06Z pdontthink $ 17 * @package squirrelmail 18 */ 19 20/** This is the compose page */ 21define('PAGE_NAME', 'compose'); 22 23/** 24 * Path for SquirrelMail required files. 25 * @ignore 26 */ 27define('SM_PATH','../'); 28 29/* SquirrelMail required files. */ 30require_once(SM_PATH . 'include/validate.php'); 31require_once(SM_PATH . 'functions/global.php'); 32require_once(SM_PATH . 'functions/imap.php'); 33require_once(SM_PATH . 'functions/date.php'); 34require_once(SM_PATH . 'functions/mime.php'); 35require_once(SM_PATH . 'functions/plugin.php'); 36require_once(SM_PATH . 'functions/display_messages.php'); 37require_once(SM_PATH . 'class/deliver/Deliver.class.php'); 38require_once(SM_PATH . 'functions/addressbook.php'); 39require_once(SM_PATH . 'functions/forms.php'); 40require_once(SM_PATH . 'functions/identity.php'); 41 42/* --------------------- Get globals ------------------------------------- */ 43/** COOKIE VARS */ 44sqgetGlobalVar('key', $key, SQ_COOKIE); 45 46/** SESSION VARS */ 47sqgetGlobalVar('username', $username, SQ_SESSION); 48sqgetGlobalVar('onetimepad',$onetimepad, SQ_SESSION); 49sqgetGlobalVar('base_uri', $base_uri, SQ_SESSION); 50sqgetGlobalVar('delimiter', $delimiter, SQ_SESSION); 51 52sqgetGlobalVar('composesession', $composesession, SQ_SESSION); 53sqgetGlobalVar('compose_messages', $compose_messages, SQ_SESSION); 54 55// compose_messages only useful in SESSION when a forward-as-attachment 56// has been preconstructed for us and passed in via that mechanism; once 57// we have it, we can clear it from the SESSION 58// -- No, this is useful in other scenarios, too -- removing: 59// sqsession_unregister('compose_messages'); 60 61/** SESSION/POST/GET VARS */ 62sqgetGlobalVar('send', $send, SQ_POST); 63// Send can only be achieved by setting $_POST var. If Send = true then 64// retrieve other form fields from $_POST 65if (isset($send) && $send) { 66 $SQ_GLOBAL = SQ_POST; 67} else { 68 $SQ_GLOBAL = SQ_FORM; 69} 70sqgetGlobalVar('smaction',$action, $SQ_GLOBAL); 71if (!sqgetGlobalVar('smtoken',$submitted_token, $SQ_GLOBAL)) { 72 $submitted_token = ''; 73} 74sqgetGlobalVar('session',$session, $SQ_GLOBAL); 75sqgetGlobalVar('mailbox',$mailbox, $SQ_GLOBAL); 76sqgetGlobalVar('identity',$orig_identity, $SQ_GLOBAL); 77if ( !sqgetGlobalVar('identity',$identity, $SQ_GLOBAL) ) { 78 $identity = 0; 79} 80sqgetGlobalVar('send_to',$send_to, $SQ_GLOBAL); 81sqgetGlobalVar('send_to_cc',$send_to_cc, $SQ_GLOBAL); 82sqgetGlobalVar('send_to_bcc',$send_to_bcc, $SQ_GLOBAL); 83sqgetGlobalVar('subject',$subject, $SQ_GLOBAL); 84sqgetGlobalVar('body',$body, $SQ_GLOBAL); 85sqgetGlobalVar('mailprio',$mailprio, $SQ_GLOBAL); 86sqgetGlobalVar('request_mdn',$request_mdn, $SQ_GLOBAL); 87sqgetGlobalVar('request_dr',$request_dr, $SQ_GLOBAL); 88sqgetGlobalVar('html_addr_search',$html_addr_search, SQ_FORM); 89sqgetGlobalVar('mail_sent',$mail_sent, SQ_FORM); 90sqgetGlobalVar('passed_id',$passed_id, $SQ_GLOBAL); 91sqgetGlobalVar('passed_ent_id',$passed_ent_id, $SQ_GLOBAL); 92 93sqgetGlobalVar('attach',$attach, SQ_POST); 94sqgetGlobalVar('draft',$draft, SQ_POST); 95sqgetGlobalVar('draft_id',$draft_id, $SQ_GLOBAL); 96sqgetGlobalVar('ent_num',$ent_num, $SQ_GLOBAL); 97sqgetGlobalVar('saved_draft',$saved_draft, SQ_FORM); 98 99if ( sqgetGlobalVar('delete_draft',$delete_draft) ) { 100 $delete_draft = (int)$delete_draft; 101} 102 103if ( sqgetGlobalVar('startMessage',$startMessage) ) { 104 $startMessage = (int)$startMessage; 105} else { 106 $startMessage = 1; 107} 108 109/** POST VARS */ 110sqgetGlobalVar('sigappend', $sigappend, SQ_POST); 111sqgetGlobalVar('from_htmladdr_search', $from_htmladdr_search, SQ_POST); 112sqgetGlobalVar('addr_search_done', $html_addr_search_done, SQ_POST); 113sqgetGlobalVar('send_to_search', $send_to_search, SQ_POST); 114sqgetGlobalVar('do_delete', $do_delete, SQ_POST); 115sqgetGlobalVar('delete', $delete, SQ_POST); 116sqgetGlobalVar('attachments', $attachments, SQ_POST); 117// Not used any more, but left for posterity 118//sqgetGlobalVar('restoremessages', $restoremessages, SQ_POST); 119if ( sqgetGlobalVar('return', $temp, SQ_POST) ) { 120 $html_addr_search_done = 'Use Addresses'; 121} 122 123/** GET VARS */ 124// (none) 125 126/** 127 * Here we decode the data passed in from mailto.php. 128 */ 129if ( sqgetGlobalVar('mailtodata', $mailtodata, SQ_GET) ) { 130 $trtable = array('to' => 'send_to', 131 'cc' => 'send_to_cc', 132 'bcc' => 'send_to_bcc', 133 'body' => 'body', 134 'subject' => 'subject'); 135 $mtdata = unserialize($mailtodata); 136 137 foreach ($trtable as $f => $t) { 138 if ( !empty($mtdata[$f]) ) { 139 $$t = $mtdata[$f]; 140 } 141 } 142 unset($mailtodata,$mtdata, $trtable); 143} 144 145/* Location (For HTTP 1.1 Header("Location: ...") redirects) */ 146$location = get_location(); 147/* Identities (fetch only once) */ 148$idents = get_identities(); 149 150/* --------------------- Specific Functions ------------------------------ */ 151 152function replyAllString($header) { 153 global $include_self_reply_all, $username, $data_dir; 154 $excl_ar = array(); 155 /** 156 * 1) Remove the addresses we'll be sending the message 'to' 157 */ 158 $url_replytoall_avoid_addrs = ''; 159 if (isset($header->reply_to) && is_array($header->reply_to) && count($header->reply_to)) { 160 $excl_ar = $header->getAddr_a('reply_to'); 161 } else if (is_object($header->reply_to)) { /* unneccesarry, just for failsafe purpose */ 162 $excl_ar = $header->getAddr_a('reply_to'); 163 } else { 164 $excl_ar = $header->getAddr_a('from'); 165 } 166 /** 167 * 2) Remove our identities from the CC list (they still can be in the 168 * TO list) only if $include_self_reply_all is turned off 169 */ 170 if (!$include_self_reply_all) { 171 global $idents; 172 foreach($idents as $id) { 173 $excl_ar[strtolower(trim($id['email_address']))] = ''; 174 } 175 } 176 177 /** 178 * 3) get the addresses. 179 */ 180 $url_replytoall_ar = $header->getAddr_a(array('to','cc'), $excl_ar); 181 182 /** 183 * 4) generate the string. 184 */ 185 $url_replytoallcc = ''; 186 foreach( $url_replytoall_ar as $email => $personal) { 187 if ($personal) { 188 // always quote personal name (can't just quote it if 189 // it contains a comma separator, since it might still 190 // be encoded) 191 $url_replytoallcc .= ", \"$personal\" <$email>"; 192 } else { 193 $url_replytoallcc .= ', '. $email; 194 } 195 } 196 $url_replytoallcc = substr($url_replytoallcc,2); 197 198 return $url_replytoallcc; 199} 200 201function getReplyCitation($orig_from, $orig_date) { 202 global $reply_citation_style, $reply_citation_start, $reply_citation_end; 203 204 // FIXME: why object is rewritten with string. 205 206 if (!is_object($orig_from)) { 207 $orig_from = ''; 208 } else { 209 $orig_from = decodeHeader($orig_from->getAddress(false),false,false,true); 210 } 211 212 /* First, return an empty string when no citation style selected. */ 213 if (($reply_citation_style == '') || ($reply_citation_style == 'none')) { 214 return ''; 215 } 216 217 /* Make sure our final value isn't an empty string. */ 218 if ($orig_from == '') { 219 return ''; 220 } 221 222 /* Otherwise, try to select the desired citation style. */ 223 switch ($reply_citation_style) { 224 case 'author_said': 225 /** 226 * To translators: %s is for author's name 227 */ 228 $full_reply_citation = sprintf(_("%s wrote:"),$orig_from); 229 break; 230 case 'quote_who': 231 $start = '<' . _("quote") . ' ' . _("who") . '="'; 232 $end = '">'; 233 $full_reply_citation = $start . $orig_from . $end; 234 break; 235 case 'date_time_author': 236 /** 237 * To translators: 238 * first %s is for date string, second %s is for author's name. Date uses 239 * formating from "D, F j, Y g:i a" and "D, F j, Y H:i" translations. 240 * Example string: 241 * "On Sat, December 24, 2004 23:59, Santa wrote:" 242 * If you have to put author's name in front of date string, check comments about 243 * argument swapping at http://www.php.net/sprintf 244 */ 245 $full_reply_citation = sprintf(_("On %s, %s wrote:"), getLongDateString($orig_date), $orig_from); 246 break; 247 case 'user-defined': 248 $start = $reply_citation_start . 249 ($reply_citation_start == '' ? '' : ' '); 250 $end = $reply_citation_end; 251 $full_reply_citation = $start . $orig_from . $end; 252 break; 253 default: 254 return ''; 255 } 256 257 /* Add line feed and return the citation string. */ 258 return ($full_reply_citation . "\n"); 259} 260 261function getforwardHeader($orig_header) { 262 global $editor_size; 263 264 $display = array( _("Subject") => strlen(_("Subject")), 265 _("From") => strlen(_("From")), 266 _("Date") => strlen(_("Date")), 267 _("To") => strlen(_("To")), 268 _("Cc") => strlen(_("Cc")) ); 269 $maxsize = max($display); 270 $indent = str_pad('',$maxsize+2); 271 foreach($display as $key => $val) { 272 $display[$key] = $key .': '. str_pad('', $maxsize - $val); 273 } 274 $from = decodeHeader($orig_header->getAddr_s('from',"\n$indent"),false,false,true); 275 $from = str_replace(' ',' ',$from); 276 $to = decodeHeader($orig_header->getAddr_s('to',"\n$indent"),false,false,true); 277 $to = str_replace(' ',' ',$to); 278 $subject = decodeHeader($orig_header->subject,false,false,true); 279 $subject = str_replace(' ',' ',$subject); 280 $bodyTop = str_pad(' '._("Original Message").' ',$editor_size -2,'-',STR_PAD_BOTH) . 281 "\n". $display[_("Subject")] . $subject . "\n" . 282 $display[_("From")] . $from . "\n" . 283 $display[_("Date")] . getLongDateString( $orig_header->date, $orig_header->date_unparsed ). "\n" . 284 $display[_("To")] . $to . "\n"; 285 if ($orig_header->cc != array() && $orig_header->cc !='') { 286 $cc = decodeHeader($orig_header->getAddr_s('cc',"\n$indent"),false,false,true); 287 $cc = str_replace(' ',' ',$cc); 288 $bodyTop .= $display[_("Cc")] .$cc . "\n"; 289 } 290 $bodyTop .= str_pad('', $editor_size -2 , '-') . 291 "\n\n"; 292 return $bodyTop; 293} 294/* ----------------------------------------------------------------------- */ 295 296/* 297 * If the session is expired during a post this restores the compose session 298 * vars. 299 */ 300$session_expired = false; 301if (sqsession_is_registered('session_expired_post')) { 302 sqgetGlobalVar('session_expired_post', $session_expired_post, SQ_SESSION); 303 /* 304 * extra check for username so we don't display previous post data from 305 * another user during this session. 306 */ 307 if (!empty($session_expired_post['username']) 308 && $session_expired_post['username'] == $username) { 309 // these are the vars that we can set from the expired composed session 310 $compo_var_list = array ('send_to', 'send_to_cc', 'body', 'mailbox', 311 'startMessage', 'passed_body', 'use_signature', 'signature', 312 'attachments', 'subject', 'newmail', 'send_to_bcc', 'passed_id', 313 'from_htmladdr_search', 'identity', 'draft_id', 'delete_draft', 314 'mailprio', 'edit_as_new', 'request_mdn', 'request_dr', 315 'composesession', /* Not used any more: 'compose_messsages', */); 316 317 foreach ($compo_var_list as $var) { 318 if ( isset($session_expired_post[$var]) && !isset($$var) ) { 319 $$var = $session_expired_post[$var]; 320 } 321 } 322 323 if (!empty($attachments)) 324 $attachments = unserialize($attachments); 325 326 sqsession_register($composesession,'composesession'); 327 328 if (isset($send)) { 329 unset($send); 330 } 331 $session_expired = true; 332 } 333 unset($session_expired_post); 334 sqsession_unregister('session_expired_post'); 335 session_write_close(); 336 if (!isset($mailbox)) { 337 $mailbox = ''; 338 } 339 if ($compose_new_win == '1') { 340 compose_Header($color, $mailbox); 341 } else { 342 displayPageHeader($color, $mailbox); 343 } 344 showInputForm($session, false); 345 exit(); 346} 347 348if (!isset($composesession)) { 349 $composesession = 0; 350 sqsession_register(0,'composesession'); 351} else { 352 $composesession = (int)$composesession; 353} 354 355if (!isset($session) || (isset($newmessage) && $newmessage)) { 356 sqsession_unregister('composesession'); 357 $session = "$composesession" +1; 358 $composesession = $session; 359 sqsession_register($composesession,'composesession'); 360} 361if (!empty($compose_messages[$session])) { 362 $composeMessage = $compose_messages[$session]; 363} else { 364 $composeMessage = new Message(); 365 $rfc822_header = new Rfc822Header(); 366 $composeMessage->rfc822_header = $rfc822_header; 367 $composeMessage->reply_rfc822_header = ''; 368} 369 370// re-add attachments that were already in this message 371// FIXME: note that technically this is very bad form - 372// should never directly manipulate an object like this 373if (!empty($attachments)) { 374 $attachments = unserialize($attachments); 375 if (!empty($attachments) && is_array($attachments)) { 376 // sanitize the "att_local_name" since it is user-supplied and used to access the file system 377 // it must be alpha-numeric and 32 characters long (see the use of GenerateRandomString() below) 378 foreach ($attachments as $i => $attachment) { 379 if (empty($attachment->att_local_name) || strlen($attachment->att_local_name) !== 32) { 380 unset($attachments[$i]); 381 continue; 382 } 383 // probably marginal difference between (ctype_alnum + function_exists) and preg_match 384 if (function_exists('ctype_alnum')) { 385 if (!ctype_alnum($attachment->att_local_name)) 386 unset($attachments[$i]); 387 } 388 else if (preg_match('/[^0-9a-zA-Z]/', $attachment->att_local_name)) 389 unset($attachments[$i]); 390 } 391 if (!empty($attachments)) 392 $composeMessage->entities = $attachments; 393 } 394} 395 396if (!isset($mailbox) || $mailbox == '' || ($mailbox == 'None')) { 397 $mailbox = 'INBOX'; 398} 399 400if ($draft) { 401 402 // validate security token 403 // 404 sm_validate_security_token($submitted_token, -1, TRUE); 405 406 /* 407 * Set $default_charset to correspond with the user's selection 408 * of language interface. 409 */ 410 set_my_charset(); 411 if (! deliverMessage($composeMessage, true)) { 412 showInputForm($session); 413 exit(); 414 } else { 415 $draft_message = _("Draft Email Saved"); 416 /* If this is a resumed draft, then delete the original */ 417 if(isset($delete_draft)) { 418 if ( !isset($pageheader_sent) || !$pageheader_sent ) { 419 Header("Location: $location/delete_message.php?mailbox=" . urlencode($draft_folder) . 420 "&message=$delete_draft&sort=$sort&startMessage=1&saved_draft=yes&smtoken=" . sm_generate_security_token()); 421 } else { 422 echo ' <br><br><center><a href="' . $location 423 . "/delete_message.php?mailbox=" . urlencode($draft_folder) 424 . "&message=$delete_draft&sort=$sort&startMessage=1&saved_draft=yes&smtoken=" . sm_generate_security_token() . "\">" 425 . _("Return") . '</a></center>'; 426 } 427 exit(); 428 } 429 else { 430 if ($compose_new_win == '1') { 431 if ( !isset($pageheader_sent) || !$pageheader_sent ) { 432 Header("Location: $location/compose.php?saved_draft=yes&session=$composesession"); 433 } else { 434 echo ' <br><br><center><a href="' . $location 435 . "/compose.php?saved_draft=yes&session=$composesession\">" 436 . _("Return") . '</a></center>'; 437 } 438 exit(); 439 } 440 else { 441 if ( !isset($pageheader_sent) || !$pageheader_sent ) { 442 Header("Location: $location/right_main.php?mailbox=" . urlencode($draft_folder) . 443 "&sort=$sort&startMessage=1¬e=".urlencode($draft_message)); 444 } else { 445 echo ' <br><br><center><a href="' . $location 446 . "/right_main.php?mailbox=" . urlencode($draft_folder) 447 . "&sort=$sort&startMessage=1¬e=".urlencode($draft_message) 448 . "\">" . _("Return") . '</a></center>'; 449 } 450 exit(); 451 } 452 } 453 } 454} 455 456if ($send) { 457 458 // validate security token 459 // 460 sm_validate_security_token($submitted_token, -1, TRUE); 461 462 if (isset($_FILES['attachfile']) && 463 $_FILES['attachfile']['tmp_name'] && 464 $_FILES['attachfile']['tmp_name'] != 'none') { 465 $AttachFailure = saveAttachedFiles($session); 466 } 467 if (checkInput(false) && !isset($AttachFailure)) { 468 if ($mailbox == "All Folders") { 469 /* We entered compose via the search results page */ 470 $mailbox = 'INBOX'; /* Send 'em to INBOX, that's safe enough */ 471 } 472 $urlMailbox = urlencode($mailbox); 473 if (! isset($passed_id)) { 474 $passed_id = 0; 475 } 476 /** 477 * Set $default_charset to correspond with the user's selection 478 * of language interface. 479 */ 480 set_my_charset(); 481 /** 482 * This is to change all newlines to \n 483 * We'll change them to \r\n later (in the sendMessage function) 484 */ 485 $body = str_replace("\r\n", "\n", $body); 486 $body = str_replace("\r", "\n", $body); 487 488 /** 489 * Rewrap $body so that no line is bigger than $editor_size 490 * This should only really kick in the sqWordWrap function 491 * if the browser doesn't support "VIRTUAL" as the wrap type. 492 */ 493 $body = explode("\n", $body); 494 $newBody = ''; 495 foreach ($body as $line) { 496 if( $line <> '-- ' ) { 497 $line = rtrim($line); 498 } 499 if (sq_strlen($line, $default_charset) <= $editor_size + 1) { 500 $newBody .= $line . "\n"; 501 } else { 502 sqWordWrap($line, $editor_size, $default_charset); 503 $newBody .= $line . "\n"; 504 505 } 506 507 } 508 $body = $newBody; 509 510 $Result = deliverMessage($composeMessage); 511 do_hook('compose_send_after', $Result, $composeMessage); 512 if (! $Result) { 513 showInputForm($session); 514 exit(); 515 } 516 517 /* if it is resumed draft, delete draft message */ 518 if ( isset($delete_draft)) { 519 Header("Location: $location/delete_message.php?mailbox=" . urlencode( $draft_folder ). 520 "&message=$delete_draft&sort=$sort&startMessage=1&mail_sent=yes&smtoken=" . sm_generate_security_token()); 521 exit(); 522 } 523 if ($compose_new_win == '1') { 524 525 Header("Location: $location/compose.php?mail_sent=yes"); 526 } 527 else { 528 global $return_to_message_after_reply; 529 if (($action === 'reply' || $action === 'reply_all' || $action === 'forward' || $action === 'forward_as_attachment') 530 && $return_to_message_after_reply) 531 Header("Location: $location/read_body.php?passed_id=$passed_id&mailbox=$urlMailbox&sort=$sort". 532 "&startMessage=$startMessage"); 533 else 534 Header("Location: $location/right_main.php?mailbox=$urlMailbox&sort=$sort". 535 "&startMessage=$startMessage"); 536 } 537 } else { 538 if ($compose_new_win == '1') { 539 compose_Header($color, $mailbox); 540 } 541 else { 542 displayPageHeader($color, $mailbox); 543 } 544 if (isset($AttachFailure)) { 545 plain_error_message(_("Could not move/copy file. File not attached"), 546 $color); 547 } 548 checkInput(true); 549 showInputForm($session); 550 /* sqimap_logout($imapConnection); */ 551 } 552} elseif (isset($html_addr_search_done)) { 553 554 // validate security token 555 // 556 sm_validate_security_token($submitted_token, -1, TRUE); 557 558 if ($compose_new_win == '1') { 559 compose_Header($color, $mailbox); 560 } 561 else { 562 displayPageHeader($color, $mailbox); 563 } 564 565 if (isset($send_to_search) && is_array($send_to_search)) { 566 foreach ($send_to_search as $k => $v) { 567 if (substr($k, 0, 1) == 'T') { 568 if ($send_to) { 569 $send_to .= ', '; 570 } 571 $send_to .= $v; 572 } 573 elseif (substr($k, 0, 1) == 'C') { 574 if ($send_to_cc) { 575 $send_to_cc .= ', '; 576 } 577 $send_to_cc .= $v; 578 } 579 elseif (substr($k, 0, 1) == 'B') { 580 if ($send_to_bcc) { 581 $send_to_bcc .= ', '; 582 } 583 $send_to_bcc .= $v; 584 } 585 } 586 } 587 showInputForm($session); 588} elseif (isset($html_addr_search)) { 589 if (isset($_FILES['attachfile']) && 590 $_FILES['attachfile']['tmp_name'] && 591 $_FILES['attachfile']['tmp_name'] != 'none') { 592 if(saveAttachedFiles($session)) { 593 plain_error_message(_("Could not move/copy file. File not attached"), $color); 594 } 595 } 596 /* 597 * I am using an include so as to elminiate an extra unnecessary 598 * click. If you can think of a better way, please implement it. 599 */ 600 include_once('./addrbook_search_html.php'); 601} elseif (isset($attach)) { 602 603 // validate security token 604 // 605 sm_validate_security_token($submitted_token, -1, TRUE); 606 607 if (saveAttachedFiles($session)) { 608 plain_error_message(_("Could not move/copy file. File not attached"), $color); 609 } 610 if ($compose_new_win == '1') { 611 compose_Header($color, $mailbox); 612 } else { 613 displayPageHeader($color, $mailbox); 614 } 615 showInputForm($session); 616} 617elseif (isset($sigappend)) { 618 619 // validate security token 620 // 621 sm_validate_security_token($submitted_token, -1, TRUE); 622 623 $signature = $idents[$identity]['signature']; 624 625 $body .= "\n\n".($prefix_sig==true? "-- \n":'').$signature; 626 if ($compose_new_win == '1') { 627 compose_Header($color, $mailbox); 628 } else { 629 displayPageHeader($color, $mailbox); 630 } 631 showInputForm($session); 632} elseif (isset($do_delete)) { 633 634 // validate security token 635 // 636 sm_validate_security_token($submitted_token, -1, TRUE); 637 638 if ($compose_new_win == '1') { 639 compose_Header($color, $mailbox); 640 } else { 641 displayPageHeader($color, $mailbox); 642 } 643 644 if (isset($delete) && is_array($delete)) { 645 foreach($delete as $index) { 646 if (!empty($composeMessage->entities) && isset($composeMessage->entities[$index])) { 647 $composeMessage->entities[$index]->purgeAttachments(); 648 // FIXME: one person reported that unset() didn't do anything at all here, so this is a work-around... but it triggers PHP notices if the unset() doesn't work, which should be fixed... but bigger question is if unset() doesn't work here, what about everywhere else? Anyway, uncomment this if you think you need it 649 //$composeMessage->entities[$index] = NULL; 650 unset ($composeMessage->entities[$index]); 651 } 652 } 653 $new_entities = array(); 654 foreach ($composeMessage->entities as $entity) { 655 $new_entities[] = $entity; 656 } 657 $composeMessage->entities = $new_entities; 658 } 659 showInputForm($session); 660} else { 661 /* 662 * This handles the default case as well as the error case 663 * (they had the same code) --> if (isset($smtpErrors)) 664 */ 665 666 if ($compose_new_win == '1') { 667 compose_Header($color, $mailbox); 668 } else { 669 displayPageHeader($color, $mailbox); 670 } 671 672 $newmail = true; 673 674 if (!isset($passed_ent_id)) { 675 $passed_ent_id = ''; 676 } 677 if (!isset($passed_id)) { 678 $passed_id = ''; 679 } 680 if (!isset($mailbox)) { 681 $mailbox = ''; 682 } 683 if (!isset($action)) { 684 $action = ''; 685 } 686 687 $values = newMail($mailbox,$passed_id,$passed_ent_id, $action, $session); 688 689 // forward as attachment - subject is in the message in session 690 // 691 if (sqgetGlobalVar('forward_as_attachment_init', $forward_as_attachment_init, SQ_GET) 692 && $forward_as_attachment_init) 693 $subject = $composeMessage->rfc822_header->subject; 694 695 /* in case the origin is not read_body.php */ 696 if (isset($send_to)) { 697 $values['send_to'] = $send_to; 698 } 699 if (isset($send_to_cc)) { 700 $values['send_to_cc'] = $send_to_cc; 701 } 702 if (isset($send_to_bcc)) { 703 $values['send_to_bcc'] = $send_to_bcc; 704 } 705 if (isset($subject)) { 706 $values['subject'] = $subject; 707 } 708 if (isset($mailprio)) { 709 $values['mailprio'] = $mailprio; 710 } 711 if (isset($orig_identity)) { 712 $values['identity'] = $orig_identity; 713 } 714 showInputForm($session, $values); 715} 716 717exit(); 718 719/**************** Only function definitions go below *************/ 720 721 722/* This function is used when not sending or adding attachments */ 723function newMail ($mailbox='', $passed_id='', $passed_ent_id='', $action='', $session='') { 724 global $editor_size, $default_use_priority, $body, $idents, 725 $use_signature, $composesession, $data_dir, $username, 726 $username, $key, $imapServerAddress, $imapPort, $imap_stream_options, 727 $composeMessage, $body_quote, $strip_sigs, $do_not_reply_to_self; 728 global $languages, $squirrelmail_language, $default_charset, $compose_messages; 729 730 /* 731 * Set $default_charset to correspond with the user's selection 732 * of language interface. $default_charset global is not correct, 733 * if message is composed in new window. 734 */ 735 set_my_charset(); 736 737 $send_to = $send_to_cc = $send_to_bcc = $subject = $identity = ''; 738 $mailprio = 3; 739 740 if ($passed_id) { 741 $imapConnection = sqimap_login($username, $key, $imapServerAddress, 742 $imapPort, 0, $imap_stream_options); 743 744 sqimap_mailbox_select($imapConnection, $mailbox); 745 $message = sqimap_get_message($imapConnection, $passed_id, $mailbox); 746 747 $body = ''; 748 if ($passed_ent_id) { 749 /* redefine the messsage in case of message/rfc822 */ 750 $message = $message->getEntity($passed_ent_id); 751 /* message is an entity which contains the envelope and type0=message 752 * and type1=rfc822. The actual entities are childs from 753 * $message->entities[0]. That's where the encoding and is located 754 */ 755 756 $entities = $message->entities[0]->findDisplayEntity 757 (array(), $alt_order = array('text/plain')); 758 if (!count($entities)) { 759 $entities = $message->entities[0]->findDisplayEntity 760 (array(), $alt_order = array('text/plain','text/html')); 761 } 762 $orig_header = $message->rfc822_header; /* here is the envelope located */ 763 /* redefine the message for picking up the attachments */ 764 $message = $message->entities[0]; 765 766 } else { 767 $entities = $message->findDisplayEntity (array(), $alt_order = array('text/plain')); 768 if (!count($entities)) { 769 $entities = $message->findDisplayEntity (array(), $alt_order = array('text/plain','text/html')); 770 } 771 $orig_header = $message->rfc822_header; 772 } 773 774 $encoding = $message->header->encoding; 775 $type0 = $message->type0; 776 $type1 = $message->type1; 777 foreach ($entities as $ent) { 778 $unencoded_bodypart = mime_fetch_body($imapConnection, $passed_id, $ent); 779 $body_part_entity = $message->getEntity($ent); 780 $bodypart = decodeBody($unencoded_bodypart, 781 $body_part_entity->header->encoding); 782 783 // type of the actual entity should be here; 784 // fall back to parent only if not 785 if (!empty($body_part_entity->type0)) 786 $type0 = $body_part_entity->type0; 787 if (!empty($body_part_entity->type1)) 788 $type1 = $body_part_entity->type1; 789 790 if ($type1 == 'html') { 791 $bodypart = str_replace("\n", ' ', $bodypart); 792 $bodypart = preg_replace(array('/<\/?p>/i','/<div><\/div>/i','/<br\s*(\/)*>/i','/<\/?div>/i'), "\n", $bodypart); 793 $bodypart = str_replace(array(' ','>','<'),array(' ','>','<'),$bodypart); 794 $bodypart = strip_tags($bodypart); 795 } 796 if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && 797 function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) { 798 if (mb_detect_encoding($bodypart) != 'ASCII') { 799 $bodypart = $languages[$squirrelmail_language]['XTRA_CODE']('decode', $bodypart); 800 } 801 } 802 803 // charset encoding in compose form stuff 804 if (isset($body_part_entity->header->parameters['charset'])) { 805 $actual = $body_part_entity->header->parameters['charset']; 806 } else { 807 $actual = 'us-ascii'; 808 } 809 810 if ( $actual && is_conversion_safe($actual) && $actual != $default_charset){ 811 $bodypart = charset_convert($actual,$bodypart,$default_charset,false); 812 } 813 // end of charset encoding in compose 814 815 $body .= $bodypart; 816 } 817 if ($default_use_priority) { 818 $mailprio = substr($orig_header->priority,0,1); 819 if (!$mailprio) { 820 $mailprio = 3; 821 } 822 } else { 823 $mailprio = ''; 824 } 825 826 $identity = ''; 827 $from_o = $orig_header->from; 828 if (is_array($from_o)) { 829 if (isset($from_o[0])) { 830 $from_o = $from_o[0]; 831 } 832 } 833 if (is_object($from_o)) { 834 $orig_from = $from_o->getAddress(); 835 } else { 836 $orig_from = ''; 837 } 838 839 $identities = array(); 840 if (count($idents) > 1) { 841 foreach($idents as $nr=>$data) { 842 $enc_from_name = '"'.$data['full_name'].'" <'. $data['email_address'].'>'; 843 $identities[] = $enc_from_name; 844 } 845 846 $identity_match = $orig_header->findAddress($identities); 847 if ($identity_match !== FALSE) { 848 $identity = $identity_match; 849 } 850 } 851 852 switch ($action) { 853 case ('draft'): 854 $use_signature = FALSE; 855 $composeMessage->rfc822_header = $orig_header; 856 $send_to = decodeHeader($orig_header->getAddr_s('to'),false,false,true); 857 $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'),false,false,true); 858 $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'),false,false,true); 859 $identity = 0; 860 if (count($idents) > 1) { 861 $identity_match = $orig_header->findAddress($identities, TRUE); 862 if ($identity_match !== FALSE) { 863 $identity = $identity_match; 864 } 865 } 866 $subject = decodeHeader($orig_header->subject,false,false,true); 867 /* remember the references and in-reply-to headers in case of an reply */ 868 $composeMessage->rfc822_header->more_headers['References'] = $orig_header->references; 869 $composeMessage->rfc822_header->more_headers['In-Reply-To'] = $orig_header->in_reply_to; 870 $body_ary = explode("\n", $body); 871 $cnt = count($body_ary) ; 872 $body = ''; 873 for ($i=0; $i < $cnt; $i++) { 874 if (!preg_match('/^[>\s]*$/', $body_ary[$i]) || !$body_ary[$i]) { 875 sqWordWrap($body_ary[$i], $editor_size, $default_charset ); 876 $body .= $body_ary[$i] . "\n"; 877 } 878 unset($body_ary[$i]); 879 } 880 sqUnWordWrap($body); 881 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection); 882 if (!empty($orig_header->x_sm_flag_reply)) 883 $composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply'] = $orig_header->x_sm_flag_reply; 884//TODO: completely unclear if should be using $compose_session instead of $session below 885 $compose_messages[$session] = $composeMessage; 886 sqsession_register($compose_messages,'compose_messages'); 887 break; 888 case ('edit_as_new'): 889 $send_to = decodeHeader($orig_header->getAddr_s('to'),false,false,true); 890 $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'),false,false,true); 891 $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'),false,false,true); 892 $subject = decodeHeader($orig_header->subject,false,false,true); 893 $mailprio = $orig_header->priority; 894 $orig_from = ''; 895 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection); 896 sqUnWordWrap($body); 897 break; 898 case ('forward'): 899 $send_to = ''; 900 $subject = decodeHeader($orig_header->subject,false,false,true); 901 if ((substr(strtolower($subject), 0, 4) != 'fwd:') && 902 (substr(strtolower($subject), 0, 5) != '[fwd:') && 903 (substr(strtolower($subject), 0, 6) != '[ fwd:')) { 904 $subject = '[Fwd: ' . $subject . ']'; 905 } 906 $body = getforwardHeader($orig_header) . $body; 907 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection); 908 $body = "\n" . $body; 909 break; 910 case ('forward_as_attachment'): 911 $subject = decodeHeader($orig_header->subject,false,false,true); 912 $subject = trim($subject); 913 if (substr(strtolower($subject), 0, 4) != 'fwd:') { 914 $subject = 'Fwd: ' . $subject; 915 } 916 $composeMessage = getMessage_RFC822_Attachment($message, $composeMessage, $passed_id, $passed_ent_id, $imapConnection); 917 $body = ''; 918 break; 919 case ('reply_all'): 920 if(isset($orig_header->mail_followup_to) && $orig_header->mail_followup_to) { 921 $send_to = $orig_header->getAddr_s('mail_followup_to'); 922 } else { 923 $send_to_cc = replyAllString($orig_header); 924 $send_to_cc = decodeHeader($send_to_cc,false,false,true); 925 $send_to_cc = str_replace('""', '"', $send_to_cc); 926 } 927 case ('reply'): 928 if (!$send_to) { 929 $send_to = $orig_header->reply_to; 930 if (is_array($send_to) && count($send_to)) { 931 $send_to = $orig_header->getAddr_s('reply_to', ',', FALSE, TRUE); 932 } else if (is_object($send_to)) { /* unneccesarry, just for failsafe purpose */ 933 $send_to = $orig_header->getAddr_s('reply_to', ',', FALSE, TRUE); 934 } else { 935 $send_to = $orig_header->getAddr_s('from', ',', FALSE, TRUE); 936 } 937 } 938 $send_to = decodeHeader($send_to,false,false,true); 939 $send_to = str_replace('""', '"', $send_to); 940 941 942 // If user doesn't want replies to her own messages 943 // going back to herself (instead send again to the 944 // original recipient of the message being replied to), 945 // then iterate through identities, checking if the TO 946 // field is one of them (if the reply is to ourselves) 947 // 948 // Note we don't bother if the original message doesn't 949 // have anything in the TO field itself (because that's 950 // what we use if we change the recipient to be that of 951 // the previous message) 952 // 953 if ($do_not_reply_to_self && !empty($orig_header->to)) { 954 955 $orig_to = ''; 956 957 foreach($idents as $id) { 958 959 if (!empty($id['email_address']) 960 && strpos($send_to, $id['email_address']) !== FALSE) { 961 962 // if this is a reply-all, the original recipient 963 // is already in the CC field, so we can just blank 964 // the recipient (TO field) (as long as the CC field 965 // isn't empty that is)... but then move the CC into 966 // the TO, so TO isn't empty 967 // 968 if ($action == 'reply_all' && !empty($send_to_cc)) { 969 $orig_to = $send_to_cc; 970 $send_to_cc = ''; 971 break; 972 } 973 974 $orig_to = $orig_header->to; 975 if (is_array($orig_to) && count($orig_to)) { 976 $orig_to = $orig_header->getAddr_s('to', ',', FALSE, TRUE); 977 } else if (is_object($orig_to)) { /* unneccesarry, just for failsafe purpose */ 978 $orig_to = $orig_header->getAddr_s('to', ',', FALSE, TRUE); 979 } else { 980 $orig_to = ''; 981 } 982 $orig_to = decodeHeader($orig_to,false,false,true); 983 $orig_to = str_replace('""', '"', $orig_to); 984 985 break; 986 } 987 } 988 989 // if the reply was addressed back to ourselves, 990 // we will send it to the TO of the previous message 991 // 992 if (!empty($orig_to)) { 993 994 $send_to = $orig_to; 995 996 // in this case, we also want to reset the FROM 997 // identity as well (it should match the original 998 // *FROM* header instead of TO or CC) 999 // 1000 if (count($idents) > 1) { 1001 $identity = ''; 1002 foreach($idents as $i => $id) { 1003 if (!empty($id['email_address']) 1004 && strpos($orig_from, $id['email_address']) !== FALSE) { 1005 $identity = $i; 1006 break; 1007 } 1008 } 1009 } 1010 1011 } 1012 1013 } 1014 1015 1016 $subject = decodeHeader($orig_header->subject,false,false,true); 1017 $subject = trim($subject); 1018 if (substr(strtolower($subject), 0, 3) != 're:') { 1019 $subject = 'Re: ' . $subject; 1020 } 1021 /* this corrects some wrapping/quoting problems on replies */ 1022 $rewrap_body = explode("\n", $body); 1023 $from = (is_array($orig_header->from) && !empty($orig_header->from)) ? $orig_header->from[0] : $orig_header->from; 1024 sqUnWordWrap($body); 1025 $body = ''; 1026 $cnt = count($rewrap_body); 1027 for ($i=0;$i<$cnt;$i++) { 1028 if ($strip_sigs && $rewrap_body[$i] == '-- ') { 1029 break; 1030 } 1031 sqWordWrap($rewrap_body[$i], $editor_size, $default_charset); 1032 if (preg_match("/^(>+)/", $rewrap_body[$i], $matches)) { 1033 $gt = $matches[1]; 1034 $body .= $body_quote . str_replace("\n", "\n" . $body_quote 1035 . "$gt ", rtrim($rewrap_body[$i])) ."\n"; 1036 } else { 1037 $body .= $body_quote . (!empty($body_quote) ? ' ' : '') . str_replace("\n", "\n" . $body_quote . (!empty($body_quote) ? ' ' : ''), rtrim($rewrap_body[$i])) . "\n"; 1038 } 1039 unset($rewrap_body[$i]); 1040 } 1041 $body = getReplyCitation($from , $orig_header->date) . $body; 1042 $composeMessage->reply_rfc822_header = $orig_header; 1043 1044 break; 1045 default: 1046 break; 1047 } 1048 session_write_close(); 1049 sqimap_logout($imapConnection); 1050 } 1051 $ret = array( 'send_to' => $send_to, 1052 'send_to_cc' => $send_to_cc, 1053 'send_to_bcc' => $send_to_bcc, 1054 'subject' => $subject, 1055 'mailprio' => $mailprio, 1056 'body' => $body, 1057 'identity' => $identity ); 1058 1059 return ($ret); 1060} /* function newMail() */ 1061 1062function getAttachments($message, &$composeMessage, $passed_id, $entities, $imapConnection) { 1063 global $attachment_dir, $username, $data_dir, $squirrelmail_language, $languages; 1064 $hashed_attachment_dir = getHashedDir($username, $attachment_dir); 1065 if (!count($message->entities) || 1066 ($message->type0 == 'message' && $message->type1 == 'rfc822')) { 1067 if ( !in_array($message->entity_id, $entities) && $message->entity_id) { 1068 switch ($message->type0) { 1069 case 'message': 1070 if ($message->type1 == 'rfc822') { 1071 $filename = $message->rfc822_header->subject; 1072 if ($filename == "") { 1073 $filename = "untitled-".$message->entity_id; 1074 } 1075 $filename .= '.eml'; 1076 } else { 1077 $filename = $message->getFilename(); 1078 } 1079 break; 1080 default: 1081 if (!$message->mime_header) { /* temporary hack */ 1082 $message->mime_header = $message->header; 1083 } 1084 $filename = $message->getFilename(); 1085 break; 1086 } 1087 1088 $filename = decodeHeader($filename, false, false, true); 1089 if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && 1090 function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) { 1091 $filename = $languages[$squirrelmail_language]['XTRA_CODE']('encode', $filename); 1092 } 1093 $localfilename = GenerateRandomString(32, '', 7); 1094 $full_localfilename = "$hashed_attachment_dir/$localfilename"; 1095 while (file_exists($full_localfilename)) { 1096 $localfilename = GenerateRandomString(32, '', 7); 1097 $full_localfilename = "$hashed_attachment_dir/$localfilename"; 1098 } 1099 $fp = fopen ("$hashed_attachment_dir/$localfilename", 'wb'); 1100 1101 $message->att_local_name = $localfilename; 1102 1103 $composeMessage->initAttachment($message->type0.'/'.$message->type1,$filename, 1104 $localfilename); 1105 1106 /* Write Attachment to file 1107 The function mime_print_body_lines writes directly to the 1108 provided resource $fp. That prohibits large memory consumption in 1109 case of forwarding mail with large attachments. 1110 */ 1111 mime_print_body_lines ($imapConnection, $passed_id, $message->entity_id, $message->header->encoding, $fp); 1112 fclose ($fp); 1113 } 1114 } else { 1115 for ($i=0, $entCount=count($message->entities); $i<$entCount;$i++) { 1116 $composeMessage=getAttachments($message->entities[$i], $composeMessage, $passed_id, $entities, $imapConnection); 1117 } 1118 } 1119 return $composeMessage; 1120} 1121 1122function getMessage_RFC822_Attachment($message, $composeMessage, $passed_id, 1123 $passed_ent_id='', $imapConnection=NULL) { 1124 global $attachment_dir, $username, $data_dir, $uid_support; 1125 $hashed_attachment_dir = getHashedDir($username, $attachment_dir); 1126 if (!$passed_ent_id) { 1127 $body_a = sqimap_run_command($imapConnection, 1128 'FETCH '.$passed_id.' RFC822', 1129 TRUE, $response, $readmessage, 1130 $uid_support); 1131 } else { 1132 $body_a = sqimap_run_command($imapConnection, 1133 'FETCH '.$passed_id.' BODY['.$passed_ent_id.']', 1134 TRUE, $response, $readmessage, $uid_support); 1135 $message = $message->parent; 1136 } 1137 if ($response == 'OK') { 1138 $subject = encodeHeader($message->rfc822_header->subject); 1139 array_shift($body_a); 1140 array_pop($body_a); 1141 $body = implode('', $body_a) . "\r\n"; 1142 1143 $localfilename = GenerateRandomString(32, 'FILE', 7); 1144 $full_localfilename = "$hashed_attachment_dir/$localfilename"; 1145 1146 $fp = fopen($full_localfilename, 'w'); 1147 fwrite ($fp, $body); 1148 fclose($fp); 1149 $composeMessage->initAttachment('message/rfc822',$subject.'.eml', 1150 $localfilename); 1151 } 1152 return $composeMessage; 1153} 1154 1155function showInputForm ($session, $values=false) { 1156 global $send_to, $send_to_cc, $body, $startMessage, $attachments, 1157 $session_expired, 1158 $passed_body, $color, $use_signature, $signature, $prefix_sig, 1159 $editor_size, $editor_height, $subject, $newmail, 1160 $use_javascript_addr_book, $send_to_bcc, $passed_id, $mailbox, 1161 $from_htmladdr_search, $location_of_buttons, $attachment_dir, 1162 $username, $data_dir, $identity, $idents, $draft_id, $delete_draft, 1163 $mailprio, $default_use_mdn, $mdn_user_support, $compose_new_win, 1164 $saved_draft, $mail_sent, $sig_first, $edit_as_new, $action, 1165 $username, $composesession, $default_charset, $composeMessage, 1166 $javascript_on, $compose_onsubmit; 1167 1168 if ($javascript_on) 1169 $onfocus = ' onfocus="alreadyFocused=true;"'; 1170 else 1171 $onfocus = ''; 1172 1173 if ($values) { 1174 $send_to = $values['send_to']; 1175 $send_to_cc = $values['send_to_cc']; 1176 $send_to_bcc = $values['send_to_bcc']; 1177 $subject = $values['subject']; 1178 $mailprio = $values['mailprio']; 1179 $body = $values['body']; 1180 $identity = (int) $values['identity']; 1181 } else { 1182 $send_to = decodeHeader($send_to, true, false); 1183 $send_to_cc = decodeHeader($send_to_cc, true, false); 1184 $send_to_bcc = decodeHeader($send_to_bcc, true, false); 1185 } 1186 1187 if ($use_javascript_addr_book) { 1188 echo "\n". '<script language="JavaScript">'."\n<!--\n" . 1189 'function open_abook() { ' . "\n" . 1190 ' var nwin = window.open("addrbook_popup.php","abookpopup",' . 1191 '"width=670,height=300,resizable=yes,scrollbars=yes");' . "\n" . 1192 ' if((!nwin.opener) && (document.windows != null))' . "\n" . 1193 ' nwin.opener = document.windows;' . "\n" . 1194 "}\n" . 1195 "// -->\n</script>\n\n"; 1196 } 1197 1198 echo "\n" . '<form name="compose" action="compose.php" method="post" ' . 1199 'enctype="multipart/form-data"'; 1200 1201 $compose_onsubmit = array(); 1202 do_hook('compose_form'); 1203 1204 // Plugins that use compose_form hook can add an array entry 1205 // to the globally scoped $compose_onsubmit; we add them up 1206 // here and format the form tag's full onsubmit handler. 1207 // Each plugin should use "return false" if they need to 1208 // stop form submission but otherwise should NOT use "return 1209 // true" to give other plugins the chance to do what they need 1210 // to do; SquirrelMail itself will add the final "return true". 1211 // Onsubmit text is enclosed inside of double quotes, so plugins 1212 // need to quote accordingly. 1213 // 1214 // Also, plugin authors should try to retain compatibility with 1215 // the Compose Extras plugin by resetting its compose submit 1216 // counter when preventing form submit. Use this code: 1217 // if (your-code-here) { submit_count = 0; return false; } 1218 // 1219 if ($javascript_on) { 1220 if (empty($compose_onsubmit)) 1221 $compose_onsubmit = array(); 1222 else if (!is_array($compose_onsubmit)) 1223 $compose_onsubmit = array($compose_onsubmit); 1224 1225 $onsubmit_text = ''; 1226 foreach ($compose_onsubmit as $text) { 1227 $text = trim($text); 1228 if (!empty($text)) { 1229 if (substr($text, -1) != ';' && substr($text, -1) != '}') 1230 $text .= '; '; 1231 $onsubmit_text .= $text; 1232 } 1233 } 1234 1235 if (!empty($onsubmit_text)) 1236 echo ' onsubmit="' . $onsubmit_text . ' return true;"'; 1237 } 1238 1239 echo ">\n"; 1240 1241 echo addHidden('smtoken', sm_generate_security_token()); 1242 echo addHidden('startMessage', $startMessage); 1243 1244 if ($action == 'draft') { 1245 echo addHidden('delete_draft', $passed_id); 1246 } 1247 if (isset($delete_draft)) { 1248 echo addHidden('delete_draft', $delete_draft); 1249 } 1250 if (isset($session)) { 1251 echo addHidden('session', $session); 1252 } 1253 1254 // NB: passed_id is set to empty string elsewhere, so this ALWAYS gets added, which is better anyway IMO 1255 if (isset($passed_id)) { 1256 echo addHidden('passed_id', $passed_id); 1257 } 1258 1259 if ($saved_draft == 'yes') { 1260 echo '<br /><center><b>'. _("Your draft has been saved.").'</center></b>'; 1261 } 1262 if ($mail_sent == 'yes') { 1263 echo '<br /><center><b>'. _("Your mail has been sent.").'</center></b>'; 1264 } 1265 if ($compose_new_win == '1') { 1266 echo '<table align="center" bgcolor="'.$color[0].'" width="100%" border="0">'."\n" . 1267 ' <tr><td></td>'.html_tag( 'td', '', 'right' ). 1268 '<input type="button" name="Close" onclick="return self.close()" value="'. 1269 _("Close").'" /></td></tr>'."\n"; 1270 } else { 1271 echo '<table align="center" cellspacing="0" border="0">' . "\n"; 1272 } 1273 if ($location_of_buttons == 'top') { 1274 showComposeButtonRow(); 1275 } 1276 1277 /* display select list for identities */ 1278 if (count($idents) > 1) { 1279 echo ' <tr>' . "\n" . 1280 html_tag( 'td', '', 'right', $color[4], 'width="10%"' ) . 1281 _("From:") . '</td>' . "\n" . 1282 html_tag( 'td', '', 'left', $color[4], 'width="90%"' ) . 1283 ' <select name="identity">' . "\n"; 1284 1285 foreach($idents as $nr => $data) { 1286 echo '<option value="' . $nr . '"'; 1287 if (isset($identity) && $identity == $nr) { 1288 echo ' selected="selected"'; 1289 } 1290 echo '>' . sm_encode_html_special_chars( 1291 $data['full_name'] . ' <' . 1292 $data['email_address'] . '>') . 1293 "</option>\n"; 1294 } 1295 1296 echo '</select>' . "\n" . 1297 ' </td>' . "\n" . 1298 ' </tr>' . "\n"; 1299 } 1300 1301 echo ' <tr>' . "\n" . 1302 html_tag( 'td', '', 'right', $color[4], 'width="10%"' ) . 1303 _("To:") . '</td>' . "\n" . 1304 html_tag( 'td', '', 'left', $color[4], 'width="90%"' ) . 1305 substr(addInput('send_to', $send_to, 60), 0, -3). $onfocus . ' /><br />' . "\n" . 1306 ' </td>' . "\n" . 1307 ' </tr>' . "\n" . 1308 ' <tr>' . "\n" . 1309 html_tag( 'td', '', 'right', $color[4] ) . 1310 _("Cc:") . '</td>' . "\n" . 1311 html_tag( 'td', '', 'left', $color[4] ) . 1312 substr(addInput('send_to_cc', $send_to_cc, 60), 0, -3). $onfocus . ' /><br />' . "\n" . 1313 ' </td>' . "\n" . 1314 ' </tr>' . "\n" . 1315 ' <tr>' . "\n" . 1316 html_tag( 'td', '', 'right', $color[4] ) . 1317 _("Bcc:") . '</td>' . "\n" . 1318 html_tag( 'td', '', 'left', $color[4] ) . 1319 substr(addInput('send_to_bcc', $send_to_bcc, 60), 0, -3). $onfocus . ' /><br />' . "\n" . 1320 ' </td>' . "\n" . 1321 ' </tr>' . "\n" . 1322 ' <tr>' . "\n" . 1323 html_tag( 'td', '', 'right', $color[4] ) . 1324 _("Subject:") . '</td>' . "\n" . 1325 html_tag( 'td', '', 'left', $color[4] ) . "\n"; 1326 echo ' '.substr(addInput('subject', $subject, 60), 0, -3). $onfocus . 1327 ' /> </td>' . "\n" . 1328 ' </tr>' . "\n\n"; 1329 1330 if ($location_of_buttons == 'between') { 1331 showComposeButtonRow(); 1332 } 1333 1334 /* why this distinction? */ 1335 if ($compose_new_win == '1') { 1336 echo ' <tr>' . "\n" . 1337 ' <td bgcolor="' . $color[0] . '" colspan="2" align="center">' . "\n" . 1338 ' <textarea name="body" id="body" rows="' . (int)$editor_height . 1339 '" cols="' . (int)$editor_size . '" wrap="virtual"' . $onfocus . ">\n"; 1340 } 1341 else { 1342 echo ' <tr>' . "\n" . 1343 ' <td bgcolor="' . $color[4] . '" colspan="2">' . "\n" . 1344 ' <textarea name="body" id="body" rows="' . (int)$editor_height . 1345 '" cols="' . (int)$editor_size . '" wrap="virtual"' . $onfocus . ">\n"; 1346 } 1347 1348 if ($use_signature == true && $newmail == true && !isset($from_htmladdr_search)) { 1349 $signature = $idents[$identity]['signature']; 1350 1351 if ($sig_first == '1') { 1352 if ($default_charset == 'iso-2022-jp') { 1353 echo "\n\n".($prefix_sig==true? "-- \n":'').mb_convert_encoding($signature, 'EUC-JP'); 1354 } else { 1355 echo "\n\n".($prefix_sig==true? "-- \n":'').decodeHeader($signature,false,false,true); 1356 } 1357 echo "\n\n".sm_encode_html_special_chars(decodeHeader($body,false,false,true)); 1358 } 1359 else { 1360 echo "\n\n".sm_encode_html_special_chars(decodeHeader($body,false,false,true)); 1361 if ($default_charset == 'iso-2022-jp') { 1362 echo "\n\n".($prefix_sig==true? "-- \n":'').mb_convert_encoding($signature, 'EUC-JP'); 1363 }else{ 1364 echo "\n\n".($prefix_sig==true? "-- \n":'').decodeHeader($signature,false,false,true); 1365 } 1366 } 1367 } else { 1368 echo sm_encode_html_special_chars(decodeHeader($body,false,false,true)); 1369 } 1370 echo '</textarea><br />' . "\n" . 1371 ' </td>' . "\n" . 1372 ' </tr>' . "\n"; 1373 1374 1375 if ($location_of_buttons == 'bottom') { 1376 showComposeButtonRow(); 1377 } else { 1378 echo ' <tr>' . "\n" . 1379 html_tag( 'td', '', 'right', '', 'colspan="2"' ) . "\n" . 1380 ' ' . addSubmit(_("Send"), 'send'). 1381 ' <br /><br />' . "\n" . 1382 ' </td>' . "\n" . 1383 ' </tr>' . "\n"; 1384 } 1385 1386 // composeMessage can be empty when coming from a restored session 1387 if (is_object($composeMessage) && $composeMessage->entities) 1388 $attach_array = $composeMessage->entities; 1389 if ($session_expired && !empty($attachments) && is_array($attachments)) 1390 $attach_array = $attachments; 1391 1392 /* This code is for attachments */ 1393 if ((bool) ini_get('file_uploads')) { 1394 1395 /* Calculate the max size for an uploaded file. 1396 * This is advisory for the user because we can't actually prevent 1397 * people to upload too large files. */ 1398 $sizes = array(); 1399 /* php.ini vars which influence the max for uploads */ 1400 $configvars = array('post_max_size', 'memory_limit', 'upload_max_filesize'); 1401 foreach($configvars as $var) { 1402 /* skip 0 or empty values, and -1 which means 'unlimited' */ 1403 if( $size = getByteSize(ini_get($var)) ) { 1404 if ( $size != '-1' ) { 1405 $sizes[] = $size; 1406 } 1407 } 1408 } 1409 1410 if(count($sizes) > 0) { 1411 $maxsize_text = '(max. ' . show_readable_size( min( $sizes ) ) . ')'; 1412 $maxsize_input = addHidden('MAX_FILE_SIZE', min( $sizes )); 1413 } else { 1414 $maxsize_text = $maxsize_input = ''; 1415 } 1416 echo ' <tr>' . "\n" . 1417 ' <td colspan="2">' . "\n" . 1418 ' <table width="100%" cellpadding="1" cellspacing="0" align="center"'. 1419 ' border="0" bgcolor="'.$color[9].'">' . "\n" . 1420 ' <tr>' . "\n" . 1421 ' <td>' . "\n" . 1422 ' <table width="100%" cellpadding="3" cellspacing="0" align="center"'. 1423 ' border="0">' . "\n" . 1424 ' <tr>' . "\n" . 1425 html_tag( 'td', '', 'right', '', 'valign="middle"' ) . 1426 _("Attach:") . '</td>' . "\n" . 1427 html_tag( 'td', '', 'left', '', 'valign="middle"' ) . 1428 $maxsize_input . 1429 ' <input name="attachfile" size="48" type="file" />' . "\n" . 1430 ' <input type="submit" name="attach"' . 1431 ' value="' . _("Add") .'" />' . "\n" . 1432 $maxsize_text . 1433 ' </td>' . "\n" . 1434 ' </tr>' . "\n"; 1435 1436 $s_a = array(); 1437 global $username, $attachment_dir, $upload_filesize_divisor; 1438 if (empty($upload_filesize_divisor)) 1439 $upload_filesize_divisor = 1000; // *not* 1024 -- does this break for some users? 1440 $hashed_attachment_dir = getHashedDir($username, $attachment_dir); 1441 if (!empty($attach_array)) { 1442 $attachment_count = 0; 1443 foreach ($attach_array as $key => $attachment) { 1444 $attached_file = $attachment->att_local_name; 1445 if ($attachment->att_local_name || $attachment->body_part) { 1446 $attached_filename = decodeHeader($attachment->mime_header->getParameter('name')); 1447 $type = $attachment->mime_header->type0.'/'. 1448 $attachment->mime_header->type1; 1449 1450 $s_a[] = '<table bgcolor="'.$color[0]. 1451 '" border="0"><tr><td>'. 1452 addCheckBox('delete[]', FALSE, $key, 'id="delete' . ++$attachment_count . '"'). 1453 "</td><td><label for='delete" . $attachment_count . "'>\n" . $attached_filename . 1454 '</label></td><td><label for="delete' . $attachment_count . '">-</label></td><td><label for="delete' . $attachment_count . '"> ' . $type . '</label></td><td><label for="delete' . $attachment_count . '">('. 1455 show_readable_size(filesize($hashed_attachment_dir . '/' . $attached_file), $upload_filesize_divisor) . 1456 ')</label></td></tr></table>'."\n"; 1457 } 1458 } 1459 } 1460 if (count($s_a)) { 1461 foreach ($s_a as $s) { 1462 echo '<tr>' . html_tag( 'td', '', 'left', $color[0], 'colspan="2"' ) . $s .'</td></tr>'; 1463 } 1464 echo '<tr><td colspan="2"><input type="submit" name="do_delete" value="' . 1465 _("Delete selected attachments") . "\" />\n" . 1466 '</td></tr>'; 1467 } 1468 echo ' </table>' . "\n" . 1469 ' </td>' . "\n" . 1470 ' </tr>' . "\n" . 1471 ' </table>' . "\n" . 1472 ' </td>' . "\n" . 1473 ' </tr>' . "\n"; 1474 } // End of file_uploads if-block 1475 /* End of attachment code */ 1476 echo '</table>' . "\n" . 1477 addHidden('username', $username). 1478 addHidden('smaction', $action). 1479 addHidden('mailbox', $mailbox); 1480 sqgetGlobalVar('QUERY_STRING', $queryString, SQ_SERVER); 1481 /* 1482 store the complete ComposeMessages array in a hidden input value 1483 so we can restore them in case of a session timeout. 1484 */ 1485 echo addHidden('composesession', $composesession). 1486 addHidden('querystring', $queryString). 1487 (!empty($attach_array) ? 1488 addHidden('attachments', serialize($attach_array)) : ''). 1489 "</form>\n"; 1490 if (!(bool) ini_get('file_uploads')) { 1491 /* File uploads are off, so we didn't show that part of the form. 1492 To avoid bogus bug reports, tell the user why. */ 1493 echo '<p style="text-align:center">' 1494 . _("Because PHP file uploads are turned off, you can not attach files to this message. Please see your system administrator for details.") 1495 . "</p>\r\n"; 1496 } 1497 1498 do_hook('compose_bottom'); 1499 echo '</body></html>' . "\n"; 1500} 1501 1502 1503function showComposeButtonRow() { 1504 global $use_javascript_addr_book, $save_as_draft, 1505 $default_use_priority, $mailprio, $default_use_mdn, 1506 $request_mdn, $request_dr, 1507 $data_dir, $username; 1508 1509 echo ' <tr>' . "\n" . 1510 ' <td></td>' . "\n" . 1511 ' <td>' . "\n"; 1512 if ($default_use_priority) { 1513 if(!isset($mailprio)) { 1514 $mailprio = '3'; 1515 } 1516 echo ' ' . _("Priority") . 1517 addSelect('mailprio', array( 1518 '1' => _("High"), 1519 '3' => _("Normal"), 1520 '5' => _("Low") ), $mailprio, TRUE); 1521 } 1522 $mdn_user_support=getPref($data_dir, $username, 'mdn_user_support',$default_use_mdn); 1523 if ($default_use_mdn) { 1524 if ($mdn_user_support) { 1525 echo ' ' . _("Receipt") .': '. 1526 addCheckBox('request_mdn', $request_mdn == '1', '1', 'id="request_mdn"') . '<label for="request_mdn">' . _("On Read") . '</label>' . 1527 addCheckBox('request_dr', $request_dr == '1', '1', 'id="request_dr"') . '<label for="request_dr">' . _("On Delivery") . '</label>'; 1528 } 1529 } 1530 1531 echo ' </td>' . "\n" . 1532 ' </tr>' . "\n" . 1533 ' <tr>' . "\n" . 1534 ' <td></td>' . "\n" . 1535 ' <td>' . "\n" . 1536 ' <input type="submit" name="sigappend" value="' . _("Signature") . '" />' . "\n"; 1537 if ($use_javascript_addr_book) { 1538 echo " <script language=\"JavaScript\"><!--\n document.write(\"". 1539 " <input type=button value=\\\""._("Addresses"). 1540 "\\\" onclick=\\\"javascript:open_abook();\\\" />\");". 1541 " // --></script><noscript>\n". 1542 ' <input type="submit" name="html_addr_search" value="'. 1543 _("Addresses").'" />'. 1544 " </noscript>\n"; 1545 } else { 1546 echo ' <input type="submit" name="html_addr_search" value="'. 1547 _("Addresses").'" />' . "\n"; 1548 } 1549 1550 if ($save_as_draft) { 1551 echo ' <input type="submit" name ="draft" value="' . _("Save Draft") . "\" />\n"; 1552 } 1553 1554 echo ' <input type="submit" name="send" value="'. _("Send") . '" />' . "\n"; 1555 do_hook('compose_button_row'); 1556 1557 echo ' </td>' . "\n" . 1558 ' </tr>' . "\n\n"; 1559} 1560 1561function checkInput ($show) { 1562 /* 1563 * I implemented the $show variable because the error messages 1564 * were getting sent before the page header. So, I check once 1565 * using $show=false, and then when i'm ready to display the error 1566 * message, show=true 1567 */ 1568 global $body, $send_to, $send_to_cc, $send_to_bcc, $subject, $color; 1569 1570 $send_to = trim($send_to); 1571 $send_to_cc = trim($send_to_cc); 1572 $send_to_bcc = trim($send_to_bcc); 1573 if (empty($send_to) && empty($send_to_cc) && empty($send_to_bcc)) { 1574 if ($show) { 1575 plain_error_message(_("You have not filled in the \"To:\" field."), $color); 1576 } 1577 return false; 1578 } 1579 return true; 1580} /* function checkInput() */ 1581 1582 1583/* True if FAILURE */ 1584function saveAttachedFiles($session) { 1585 global $_FILES, $attachment_dir, $username, 1586 $data_dir, $composeMessage; 1587 1588 /* get out of here if no file was attached at all */ 1589 if (! is_uploaded_file($_FILES['attachfile']['tmp_name']) ) { 1590 return true; 1591 } 1592 1593 $hashed_attachment_dir = getHashedDir($username, $attachment_dir); 1594 $localfilename = GenerateRandomString(32, '', 7); 1595 $full_localfilename = "$hashed_attachment_dir/$localfilename"; 1596 while (file_exists($full_localfilename)) { 1597 $localfilename = GenerateRandomString(32, '', 7); 1598 $full_localfilename = "$hashed_attachment_dir/$localfilename"; 1599 } 1600 1601 // FIXME: we SHOULD prefer move_uploaded_file over rename because 1602 // m_u_f works better with restricted PHP installs (safe_mode, open_basedir) 1603 if (!@rename($_FILES['attachfile']['tmp_name'], $full_localfilename)) { 1604 if (!@move_uploaded_file($_FILES['attachfile']['tmp_name'],$full_localfilename)) { 1605 return true; 1606 } 1607 } 1608 $type = strtolower($_FILES['attachfile']['type']); 1609 $name = $_FILES['attachfile']['name']; 1610 $composeMessage->initAttachment($type, $name, $localfilename); 1611} 1612 1613/* parse values like 8M and 2k into bytes */ 1614function getByteSize($ini_size) { 1615 1616 if(!$ini_size) { 1617 return FALSE; 1618 } 1619 1620 $ini_size = trim($ini_size); 1621 1622 // if there's some kind of letter at the end of the string we need to multiply. 1623 if(!is_numeric(substr($ini_size, -1))) { 1624 1625 switch(strtoupper(substr($ini_size, -1))) { 1626 case 'G': 1627 $bytesize = 1073741824; 1628 break; 1629 case 'M': 1630 $bytesize = 1048576; 1631 break; 1632 case 'K': 1633 $bytesize = 1024; 1634 break; 1635 } 1636 1637 return ($bytesize * (int)substr($ini_size, 0, -1)); 1638 } 1639 1640 return $ini_size; 1641} 1642 1643 1644/** 1645 * temporary function to make use of the deliver class. 1646 * In the future the responsible backend should be automaticly loaded 1647 * and conf.pl should show a list of available backends. 1648 * The message also should be constructed by the message class. 1649 * 1650 * @param object $composeMessage The message being sent. Please note 1651 * that it is passed by reference and 1652 * will be returned modified, with additional 1653 * headers, such as Message-ID, Date, In-Reply-To, 1654 * References, and so forth. 1655 * 1656 * @return boolean FALSE if delivery failed, or some non-FALSE value 1657 * upon success. 1658 * 1659 */ 1660function deliverMessage(&$composeMessage, $draft=false) { 1661 global $send_to, $send_to_cc, $send_to_bcc, $mailprio, $subject, $body, 1662 $username, $popuser, $usernamedata, $identity, $idents, $data_dir, 1663 $request_mdn, $request_dr, $default_charset, $color, $useSendmail, 1664 $domain, $action, $default_move_to_sent, $move_to_sent, $session, $compose_messages; 1665 global $imapServerAddress, $imapPort, $imap_stream_options, $sent_folder, $key; 1666 1667 $rfc822_header = $composeMessage->rfc822_header; 1668 1669 // clear Date header so drafts don't end up with a stale date 1670 // (does this cause issues with some other scenario where a 1671 // message with an existing date header should be preserved??) 1672 unset($rfc822_header->date); 1673 1674 $abook = addressbook_init(false, true); 1675 $rfc822_header->to = $rfc822_header->parseAddress($send_to,true, array(), '', $domain, array(&$abook,'lookup')); 1676 $rfc822_header->cc = $rfc822_header->parseAddress($send_to_cc,true,array(), '',$domain, array(&$abook,'lookup')); 1677 $rfc822_header->bcc = $rfc822_header->parseAddress($send_to_bcc,true, array(), '',$domain, array(&$abook,'lookup')); 1678 $rfc822_header->priority = $mailprio; 1679 $rfc822_header->subject = $subject; 1680 1681 $special_encoding=''; 1682 if (strtolower($default_charset) == 'iso-2022-jp') { 1683 if (mb_detect_encoding($body) == 'ASCII') { 1684 $special_encoding = '8bit'; 1685 } else { 1686 $body = mb_convert_encoding($body, 'JIS'); 1687 $special_encoding = '7bit'; 1688 } 1689 } 1690 $composeMessage->setBody($body); 1691 1692 if (preg_match('|^([^@%/]+)[@%/](.+)$|', $username, $usernamedata)) { 1693 $popuser = $usernamedata[1]; 1694 $domain = $usernamedata[2]; 1695 unset($usernamedata); 1696 } else { 1697 $popuser = $username; 1698 } 1699 $reply_to = ''; 1700 $from_mail = $idents[$identity]['email_address']; 1701 $full_name = $idents[$identity]['full_name']; 1702 $reply_to = $idents[$identity]['reply_to']; 1703 if (!$from_mail) { 1704 $from_mail = "$popuser@$domain"; 1705 } 1706 $rfc822_header->from = $rfc822_header->parseAddress($from_mail,true); 1707 if (!$rfc822_header->from[0]->host) $rfc822_header->from[0]->host = $domain; 1708 if ($full_name) { 1709 $from = $rfc822_header->from[0]; 1710 $full_name_encoded = encodeHeader('"' . $full_name . '"'); 1711 if ($full_name_encoded != $full_name) { 1712 $from_addr = $full_name_encoded .' <'.$from->mailbox.'@'.$from->host.'>'; 1713 } else { 1714 $from_addr = '"'.$full_name .'" <'.$from->mailbox.'@'.$from->host.'>'; 1715 } 1716 $rfc822_header->from = $rfc822_header->parseAddress($from_addr,true); 1717 } 1718 if ($reply_to) { 1719 $rfc822_header->reply_to = $rfc822_header->parseAddress($reply_to,true); 1720 if (!$rfc822_header->reply_to[0]->host) $rfc822_header->reply_to[0]->host = $domain; 1721 } 1722 /* Receipt: On Read */ 1723 if (isset($request_mdn) && $request_mdn) { 1724 $rfc822_header->dnt = $rfc822_header->parseAddress($from_mail,true); 1725 } 1726 1727 /* Receipt: On Delivery */ 1728 if (isset($request_dr) && $request_dr) { 1729 $rfc822_header->more_headers['Return-Receipt-To'] = $from_mail; 1730 } 1731 1732 /* multipart messages */ 1733 if (count($composeMessage->entities)) { 1734 $message_body = new Message(); 1735 $message_body->body_part = $composeMessage->body_part; 1736 $composeMessage->body_part = ''; 1737 $mime_header = new MessageHeader; 1738 $mime_header->type0 = 'text'; 1739 $mime_header->type1 = 'plain'; 1740 if ($special_encoding) { 1741 $mime_header->encoding = $special_encoding; 1742 } else { 1743 $mime_header->encoding = '8bit'; 1744 } 1745 if ($default_charset) { 1746 $mime_header->parameters['charset'] = $default_charset; 1747 } 1748 $message_body->mime_header = $mime_header; 1749 array_unshift($composeMessage->entities, $message_body); 1750 $content_type = new ContentType('multipart/mixed'); 1751 } else { 1752 $content_type = new ContentType('text/plain'); 1753 if ($special_encoding) { 1754 $rfc822_header->encoding = $special_encoding; 1755 } else { 1756 $rfc822_header->encoding = '8bit'; 1757 } 1758 if ($default_charset) { 1759 $content_type->properties['charset']=$default_charset; 1760 } 1761 } 1762 1763 $rfc822_header->content_type = $content_type; 1764 $composeMessage->rfc822_header = $rfc822_header; 1765 if ($action == 'reply' || $action == 'reply_all') { 1766 global $passed_id, $passed_ent_id; 1767 $reply_id = $passed_id; 1768 $reply_ent_id = $passed_ent_id; 1769 } else { 1770 $reply_id = ''; 1771 $reply_ent_id = ''; 1772 } 1773 1774 /* Here you can modify the message structure just before we hand 1775 it over to deliver */ 1776 $hookReturn = do_hook('compose_send', $composeMessage, $draft); 1777 /* Get any changes made by plugins to $composeMessage. */ 1778 if ( is_object($hookReturn[1]) ) { 1779 $composeMessage = $hookReturn[1]; 1780 } 1781 /* Get any changes made by plugins to $draft. */ 1782 if ( !empty($hookReturn[2]) || $hookReturn[2] === FALSE ) { 1783 $draft = $hookReturn[2]; 1784 } 1785 1786 // remove special header if present and prepare to mark 1787 // a message that a draft was composed in reply to 1788 if (!empty($composeMessage->rfc822_header->x_sm_flag_reply) && !$draft) { 1789 global $passed_id, $mailbox, $action; 1790 // tricks the code below that marks the reply 1791 list($action, $passed_id, $mailbox) = explode('::', $rfc822_header->x_sm_flag_reply, 3); 1792 unset($composeMessage->rfc822_header->x_sm_flag_reply); 1793 unset($composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply']); 1794 } 1795 1796 if (!$useSendmail && !$draft) { 1797 require_once(SM_PATH . 'class/deliver/Deliver_SMTP.class.php'); 1798 $deliver = new Deliver_SMTP(); 1799 global $smtpServerAddress, $smtpPort, $smtp_stream_options, 1800 $pop_before_smtp, $pop_before_smtp_host; 1801 1802 $authPop = (isset($pop_before_smtp) && $pop_before_smtp) ? true : false; 1803 1804 $user = ''; 1805 $pass = ''; 1806 if (empty($pop_before_smtp_host)) 1807 $pop_before_smtp_host = $smtpServerAddress; 1808 1809 get_smtp_user($user, $pass); 1810 1811 $stream = $deliver->initStream($composeMessage,$domain,0, 1812 $smtpServerAddress, $smtpPort, $user, $pass, $authPop, $pop_before_smtp_host, $smtp_stream_options); 1813 } elseif (!$draft) { 1814 require_once(SM_PATH . 'class/deliver/Deliver_SendMail.class.php'); 1815 global $sendmail_path, $sendmail_args; 1816 // Check for outdated configuration 1817 if (!isset($sendmail_args)) { 1818 if ($sendmail_path=='/var/qmail/bin/qmail-inject') { 1819 $sendmail_args = ''; 1820 } else { 1821 $sendmail_args = '-i -t'; 1822 } 1823 } 1824 $deliver = new Deliver_SendMail(array('sendmail_args'=>$sendmail_args)); 1825 $stream = $deliver->initStream($composeMessage,$sendmail_path); 1826 } elseif ($draft) { 1827 global $draft_folder; 1828 $imap_stream = sqimap_login($username, $key, $imapServerAddress, 1829 $imapPort, 0, $imap_stream_options); 1830 if (sqimap_mailbox_exists ($imap_stream, $draft_folder)) { 1831//TODO: this can leak private information about folders and message IDs if messages are accessed/sent from another client --- should this feature be optional? 1832 // make note of the message to mark as having been replied to 1833 global $passed_id, $mailbox, $action; 1834 if ($action == 'reply' || $action == 'reply_all') { 1835 $composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply'] = $action . '::' . $passed_id . '::' . $mailbox; 1836 } 1837 1838 require_once(SM_PATH . 'class/deliver/Deliver_IMAP.class.php'); 1839 $imap_deliver = new Deliver_IMAP(); 1840 $succes = $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $draft_folder); 1841 sqimap_logout($imap_stream); 1842 unset ($imap_deliver); 1843 $composeMessage->purgeAttachments(); 1844//TODO: completely unclear if should be using $compose_session instead of $session below 1845 unset($compose_messages[$session]); 1846 sqsession_register($compose_messages,'compose_messages'); 1847 return $succes; 1848 } else { 1849 $msg = '<br />'.sprintf(_("Error: Draft folder %s does not exist."), 1850 sm_encode_html_special_chars($draft_folder)); 1851 plain_error_message($msg, $color); 1852 return false; 1853 } 1854 } 1855 $succes = false; 1856 if ($stream) { 1857 $deliver->mail($composeMessage, $stream, $reply_id, $reply_ent_id); 1858 $succes = $deliver->finalizeStream($stream); 1859 } 1860 if (!$succes) { 1861 $msg = _("Message not sent.") . ' ' . _("Server replied:") 1862 . "\n<blockquote>\n" 1863 . (isset($deliver->dlv_msg) ? $deliver->dlv_msg : '') 1864 . '<br />' 1865 . (isset($deliver->dlv_ret_nr) ? $deliver->dlv_ret_nr . ' ' : '') 1866 . (isset($deliver->dlv_server_msg) ? $deliver->dlv_server_msg : '') 1867 . "</blockquote>\n\n"; 1868 plain_error_message($msg, $color); 1869 } else { 1870 unset ($deliver); 1871 $imap_stream = sqimap_login($username, $key, $imapServerAddress, $imapPort, 0, $imap_stream_options); 1872 1873 1874 // mark original message as having been replied to if applicable 1875 global $passed_id, $mailbox, $action; 1876 if ($action == 'reply' || $action == 'reply_all') { 1877 // select errors here could be due to a draft reply being sent 1878 // after the original message's mailbox is moved or deleted 1879 $result = sqimap_mailbox_select ($imap_stream, $mailbox, false); 1880 // a non-empty return from above means we can proceed 1881 if (!empty($result)) 1882 sqimap_messages_flag ($imap_stream, $passed_id, $passed_id, 'Answered', false); 1883 } 1884 1885 1886 // copy message to sent folder 1887 $move_to_sent = getPref($data_dir,$username,'move_to_sent', $default_move_to_sent); 1888 if (isset($default_move_to_sent) && ($default_move_to_sent != 0)) { 1889 $svr_allow_sent = true; 1890 } else { 1891 $svr_allow_sent = false; 1892 } 1893 1894 if (isset($sent_folder) && (($sent_folder != '') || ($sent_folder != 'none')) 1895 && sqimap_mailbox_exists( $imap_stream, $sent_folder)) { 1896 $fld_sent = true; 1897 } else { 1898 $fld_sent = false; 1899 } 1900 1901 if ((isset($move_to_sent) && ($move_to_sent != 0)) || (!isset($move_to_sent))) { 1902 $lcl_allow_sent = true; 1903 } else { 1904 $lcl_allow_sent = false; 1905 } 1906 1907 if (($fld_sent && $svr_allow_sent && !$lcl_allow_sent) || ($fld_sent && $lcl_allow_sent)) { 1908 require_once(SM_PATH . 'class/deliver/Deliver_IMAP.class.php'); 1909 $imap_deliver = new Deliver_IMAP(); 1910 $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $sent_folder); 1911 unset ($imap_deliver); 1912 } 1913 $composeMessage->purgeAttachments(); 1914//TODO: completely unclear if should be using $compose_session instead of $session below 1915 unset($compose_messages[$session]); 1916 sqsession_register($compose_messages,'compose_messages'); 1917 sqimap_logout($imap_stream); 1918 } 1919 return $succes; 1920} 1921 1922