f6c7a3047ece10e533b20a0eb3ccc8d87c69d94e
5 * This code sends a mail.
7 * There are 4 modes of operation:
13 * @copyright © 1999-2007 The SquirrelMail Project Team
14 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
16 * @package squirrelmail
19 /** This is the compose page */
20 define('PAGE_NAME', 'compose');
23 * Include the SquirrelMail initialization file.
25 require('../include/init.php');
27 /* If email_address not set and admin wants us to ask user for it,
28 * redirect to options page. */
29 if ( $ask_user_info && getPref($data_dir, $username,'email_address') == "" ) {
30 header("Location: " . get_location() . "/options.php?optpage=personal");
34 /* SquirrelMail required files. */
35 require_once(SM_PATH
. 'functions/imap_general.php');
36 require_once(SM_PATH
. 'functions/imap_messages.php');
37 require_once(SM_PATH
. 'functions/date.php');
38 require_once(SM_PATH
. 'functions/mime.php');
39 require_once(SM_PATH
. 'functions/compose.php');
40 require_once(SM_PATH
. 'class/deliver/Deliver.class.php');
41 require_once(SM_PATH
. 'functions/addressbook.php');
42 require_once(SM_PATH
. 'functions/forms.php');
43 require_once(SM_PATH
. 'functions/identity.php');
45 /* --------------------- Get globals ------------------------------------- */
48 sqgetGlobalVar('delimiter', $delimiter, SQ_SESSION
);
50 sqgetGlobalVar('delayed_errors', $delayed_errors, SQ_SESSION
);
51 sqgetGlobalVar('composesession', $composesession, SQ_SESSION
);
52 sqgetGlobalVar('compose_messages', $compose_messages, SQ_SESSION
);
54 // compose_messages only useful in SESSION when a forward-as-attachment
55 // has been preconstructed for us and passed in via that mechanism; once
56 // we have it, we can clear it from the SESSION
57 sqsession_unregister('compose_messages');
59 // Turn on delayed error handling in case we wind up redirecting below
60 $oErrorHandler->setDelayedErrors(true);
62 /** SESSION/POST/GET VARS */
63 sqgetGlobalVar('send', $send, SQ_POST
);
64 // Send can only be achieved by setting $_POST var. If Send = true then
65 // retrieve other form fields from $_POST
66 if (isset($send) && $send) {
71 sqgetGlobalVar('session',$session, $SQ_GLOBAL);
72 sqgetGlobalVar('mailbox',$mailbox, $SQ_GLOBAL);
73 if(!sqgetGlobalVar('identity',$identity, $SQ_GLOBAL)) {
76 sqgetGlobalVar('send_to',$send_to, $SQ_GLOBAL);
77 sqgetGlobalVar('send_to_cc',$send_to_cc, $SQ_GLOBAL);
78 sqgetGlobalVar('send_to_bcc',$send_to_bcc, $SQ_GLOBAL);
79 sqgetGlobalVar('subject',$subject, $SQ_GLOBAL);
80 sqgetGlobalVar('body',$body, $SQ_GLOBAL);
81 sqgetGlobalVar('mailprio',$mailprio, $SQ_GLOBAL);
82 sqgetGlobalVar('request_mdn',$request_mdn, $SQ_GLOBAL);
83 sqgetGlobalVar('request_dr',$request_dr, $SQ_GLOBAL);
84 sqgetGlobalVar('html_addr_search',$html_addr_search, $SQ_GLOBAL);
85 sqgetGlobalVar('mail_sent',$mail_sent, $SQ_GLOBAL);
86 sqgetGlobalVar('passed_id',$passed_id, $SQ_GLOBAL);
87 sqgetGlobalVar('passed_ent_id',$passed_ent_id, $SQ_GLOBAL);
89 sqgetGlobalVar('attach',$attach, SQ_POST
);
90 sqgetGlobalVar('draft',$draft, SQ_POST
);
91 sqgetGlobalVar('draft_id',$draft_id, $SQ_GLOBAL);
92 sqgetGlobalVar('ent_num',$ent_num, $SQ_GLOBAL);
93 sqgetGlobalVar('saved_draft',$saved_draft, SQ_FORM
);
95 if ( sqgetGlobalVar('delete_draft',$delete_draft) ) {
96 $delete_draft = (int)$delete_draft;
99 if ( sqgetGlobalVar('startMessage',$startMessage) ) {
100 $startMessage = (int)$startMessage;
107 sqgetGlobalVar('sigappend', $sigappend, SQ_POST
);
108 sqgetGlobalVar('from_htmladdr_search', $from_htmladdr_search, SQ_POST
);
109 sqgetGlobalVar('addr_search_done', $html_addr_search_done, SQ_POST
);
110 sqgetGlobalVar('addr_search_cancel', $html_addr_search_cancel, SQ_POST
);
111 sqgetGlobalVar('send_to_search', $send_to_search, SQ_POST
);
112 sqgetGlobalVar('do_delete', $do_delete, SQ_POST
);
113 sqgetGlobalVar('delete', $delete, SQ_POST
);
114 sqgetGlobalVar('attachments', $attachments, SQ_POST
);
115 if ( sqgetGlobalVar('return', $temp, SQ_POST
) ) {
116 $html_addr_search_done = 'Use Addresses';
120 if ( sqgetGlobalVar('account', $temp, SQ_GET
) ) {
121 $iAccount = (int) $temp;
128 if ( !sqgetGlobalVar('smaction',$action) )
130 if ( sqgetGlobalVar('smaction_reply',$tmp) ) $action = 'reply';
131 if ( sqgetGlobalVar('smaction_reply_all',$tmp) ) $action = 'reply_all';
132 if ( sqgetGlobalVar('smaction_forward',$tmp) ) $action = 'forward';
133 if ( sqgetGlobalVar('smaction_attache',$tmp) ) $action = 'forward_as_attachment';
134 if ( sqgetGlobalVar('smaction_draft',$tmp) ) $action = 'draft';
135 if ( sqgetGlobalVar('smaction_edit_new',$tmp) ) $action = 'edit_as_new';
139 * Here we decode the data passed in from mailto.php.
141 if ( sqgetGlobalVar('mailtodata', $mailtodata, SQ_GET
) ) {
142 $trtable = array('to' => 'send_to',
143 'cc' => 'send_to_cc',
144 'bcc' => 'send_to_bcc',
146 'subject' => 'subject');
147 $mtdata = unserialize($mailtodata);
149 foreach ($trtable as $f => $t) {
150 if ( !empty($mtdata[$f]) ) {
154 unset($mailtodata,$mtdata, $trtable);
157 /* Location (For HTTP 1.1 header("Location: ...") redirects) */
158 $location = get_location();
159 /* Identities (fetch only once) */
160 $idents = get_identities();
162 /* --------------------- Specific Functions ------------------------------ */
164 function replyAllString($header) {
165 global $include_self_reply_all, $idents;
168 * 1) Remove the addresses we'll be sending the message 'to'
170 if (isset($header->reply_to
)) {
171 $excl_ar = $header->getAddr_a('reply_to');
174 * 2) Remove our identities from the CC list (they still can be in the
175 * TO list) only if $include_self_reply_all is turned off
177 if (!$include_self_reply_all) {
178 foreach($idents as $id) {
179 $excl_ar[strtolower(trim($id['email_address']))] = '';
184 * 3) get the addresses.
186 $url_replytoall_ar = $header->getAddr_a(array('to','cc'), $excl_ar);
189 * 4) generate the string.
191 $url_replytoallcc = '';
192 foreach( $url_replytoall_ar as $email => $personal) {
194 // if personal name contains address separator then surround
195 // the personal name with double quotes.
196 if (strpos($personal,',') !== false) {
197 $personal = '"'.$personal.'"';
199 $url_replytoallcc .= ", $personal <$email>";
201 $url_replytoallcc .= ', '. $email;
204 $url_replytoallcc = substr($url_replytoallcc,2);
206 return $url_replytoallcc;
210 * creates top line in reply citations
212 * Line style depends on user preferences.
213 * $orig_date argument is available only from 1.4.3 and 1.5.1 version.
214 * @param object $orig_from From: header object.
215 * @param integer $orig_date email's timestamp
216 * @return string reply citation
218 function getReplyCitation($orig_from, $orig_date) {
219 global $reply_citation_style, $reply_citation_start, $reply_citation_end;
221 if (!is_object($orig_from)) {
224 $sOrig_from = decodeHeader($orig_from->getAddress(false),false,false,true);
227 /* First, return an empty string when no citation style selected. */
228 if (($reply_citation_style == '') ||
($reply_citation_style == 'none')) {
232 /* Make sure our final value isn't an empty string. */
233 if ($sOrig_from == '') {
237 /* Otherwise, try to select the desired citation style. */
238 switch ($reply_citation_style) {
240 // i18n: %s is for author's name
241 $full_reply_citation = sprintf(_("%s wrote:"),$sOrig_from);
244 $start = '<quote who="';
246 $full_reply_citation = $start . $sOrig_from . $end;
248 case 'date_time_author':
250 // The first %s is for date string, the second %s is for author's name.
251 // The date uses formating from "D, F j, Y g:i a" and "D, F j, Y H:i"
254 // "On Sat, December 24, 2004 23:59, Santa wrote:"
255 // If you have to put author's name in front of date string, check comments about
256 // argument swapping at http://php.net/sprintf
257 $full_reply_citation = sprintf(_("On %s, %s wrote:"), getLongDateString($orig_date), $sOrig_from);
260 $start = $reply_citation_start .
261 ($reply_citation_start == '' ?
'' : ' ');
262 $end = $reply_citation_end;
263 $full_reply_citation = $start . $sOrig_from . $end;
269 /* Add line feed and return the citation string. */
270 return ($full_reply_citation . "\n");
274 * Creates header fields in forwarded email body
276 * $default_charset global must be set correctly before you call this function.
277 * @param object $orig_header
280 function getforwardHeader($orig_header) {
281 global $editor_size, $default_charset;
283 // using own strlen function in order to detect correct string length
284 $display = array( _("Subject") => sq_strlen(_("Subject"),$default_charset),
285 _("From") => sq_strlen(_("From"),$default_charset),
286 _("Date") => sq_strlen(_("Date"),$default_charset),
287 _("To") => sq_strlen(_("To"),$default_charset),
288 _("Cc") => sq_strlen(_("Cc"),$default_charset) );
289 $maxsize = max($display);
290 $indent = str_pad('',$maxsize+
2);
291 foreach($display as $key => $val) {
292 $display[$key] = $key .': '. str_pad('', $maxsize - $val);
294 $from = decodeHeader($orig_header->getAddr_s('from',"\n$indent"),false,false,true);
295 $from = str_replace(' ',' ',$from);
296 $to = decodeHeader($orig_header->getAddr_s('to',"\n$indent"),false,false,true);
297 $to = str_replace(' ',' ',$to);
298 $subject = decodeHeader($orig_header->subject
,false,false,true);
299 $subject = str_replace(' ',' ',$subject);
301 // using own str_pad function in order to create correct string pad
302 $bodyTop = sq_str_pad(' '._("Original Message").' ',$editor_size -2,'-',STR_PAD_BOTH
,$default_charset) .
303 "\n". $display[_("Subject")] . $subject . "\n" .
304 $display[_("From")] . $from . "\n" .
305 $display[_("Date")] . getLongDateString( $orig_header->date
, $orig_header->date_unparsed
). "\n" .
306 $display[_("To")] . $to . "\n";
307 if ($orig_header->cc
!= array() && $orig_header->cc
!='') {
308 $cc = decodeHeader($orig_header->getAddr_s('cc',"\n$indent"),false,false,true);
309 $cc = str_replace(' ',' ',$cc);
310 $bodyTop .= $display[_("Cc")] .$cc . "\n";
312 $bodyTop .= str_pad('', $editor_size -2 , '-') .
316 /* ----------------------------------------------------------------------- */
319 * If the session is expired during a post this restores the compose session
322 $session_expired = false;
323 if (sqsession_is_registered('session_expired_post')) {
324 sqgetGlobalVar('session_expired_post', $session_expired_post, SQ_SESSION
);
326 * extra check for username so we don't display previous post data from
327 * another user during this session.
329 if (!empty($session_expired_post['username'])
330 && $session_expired_post['username'] == $username) {
331 // these are the vars that we can set from the expired composed session
332 $compo_var_list = array ('send_to', 'send_to_cc', 'body',
333 'startMessage', 'passed_body', 'use_signature', 'signature',
334 'subject', 'newmail', 'send_to_bcc', 'passed_id', 'mailbox',
335 'from_htmladdr_search', 'identity', 'draft_id', 'delete_draft',
336 'mailprio', 'edit_as_new', 'attachments', 'composesession',
337 'request_mdn', 'request_dr');
339 foreach ($compo_var_list as $var) {
340 if ( isset($session_expired_post[$var]) && !isset($
$var) ) {
341 $
$var = $session_expired_post[$var];
345 if (!empty($attachments))
346 $attachments = unserialize(urldecode($attachments));
348 sqsession_register($composesession,'composesession');
353 $session_expired = true;
355 unset($session_expired_post);
356 sqsession_unregister('session_expired_post');
357 session_write_close();
358 if (!isset($mailbox)) {
361 if ($compose_new_win == '1') {
362 compose_Header($color, $mailbox);
364 $sHeaderJs = (isset($sHeaderJs)) ?
$sHeaderJs : '';
365 if (strpos($action, 'reply') !== false && $reply_focus) {
366 $sBodyTagJs = 'onload="checkForm(\''.$replyfocus.'\');"';
368 $sBodyTagJs = 'onload="checkForm();"';
370 displayPageHeader($color, $mailbox,$sHeaderJs,$sBodyTagJs);
372 showInputForm($session, false);
376 if (!isset($composesession)) {
378 sqsession_register(0,'composesession');
380 $composesession = (int)$composesession;
383 if (!isset($session) ||
(isset($newmessage) && $newmessage)) {
384 sqsession_unregister('composesession');
385 $session = "$composesession" +
1;
386 $composesession = $session;
387 sqsession_register($composesession,'composesession');
389 if (!empty($compose_messages[$session])) {
390 $composeMessage = $compose_messages[$session];
392 $composeMessage = new Message();
393 $rfc822_header = new Rfc822Header();
394 $composeMessage->rfc822_header
= $rfc822_header;
395 $composeMessage->reply_rfc822_header
= '';
398 // re-add attachments that were already in this message
399 // FIXME: note that technically this is very bad form -
400 // should never directly manipulate an object like this
401 if (!empty($attachments)) {
402 $attachments = unserialize(urldecode($attachments));
403 if (!empty($attachments) && is_array($attachments))
404 $composeMessage->entities
= $attachments;
407 if (empty($mailbox)) {
413 * Set $default_charset to correspond with the user's selection
414 * of language interface.
417 if (! deliverMessage($composeMessage, true)) {
418 showInputForm($session);
421 $draft_message = _("Draft Email Saved");
422 /* If this is a resumed draft, then delete the original */
423 if(isset($delete_draft)) {
424 $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false);
425 sqimap_mailbox_select($imap_stream, $draft_folder);
426 // force bypass_trash=true because message should be saved when deliverMessage() returns true.
427 // in current implementation of sqimap_msgs_list_flag() single message id can
428 // be submitted as string. docs state that it should be array.
429 sqimap_msgs_list_delete($imap_stream, $draft_folder, $delete_draft, true);
431 sqimap_mailbox_expunge($imap_stream, $draft_folder, true);
433 sqimap_logout($imap_stream);
436 $oErrorHandler->saveDelayedErrors();
437 session_write_close();
439 if ($compose_new_win == '1') {
440 if ( !isset($pageheader_sent) ||
!$pageheader_sent ) {
441 header("Location: $location/compose.php?saved_draft=yes&session=$composesession");
443 //FIXME: DON'T ECHO HTML FROM CORE!
444 echo ' <br><br><div style="text-align: center;"><a href="' . $location
445 . '/compose.php?saved_sent=yes&session=' . $composesession . '">'
446 . _("Return") . '</a></div>';
450 if ( !isset($pageheader_sent) ||
!$pageheader_sent ) {
451 header("Location: $location/right_main.php?mailbox=" . urlencode($draft_folder) .
452 "&startMessage=1¬e=".urlencode($draft_message));
454 //FIXME: DON'T ECHO HTML FROM CORE!
455 echo ' <br><br><div style="text-align: center;"><a href="' . $location
456 . '/right_main.php?mailbox=' . urlencode($draft_folder)
457 . '&startMessage=1&note=' . urlencode($draft_message) .'">'
458 . _("Return") . '</a></div>';
466 if (isset($_FILES['attachfile']) &&
467 $_FILES['attachfile']['tmp_name'] &&
468 $_FILES['attachfile']['tmp_name'] != 'none') {
469 $AttachFailure = saveAttachedFiles($session);
471 if (checkInput(false) && !isset($AttachFailure)) {
472 if ($mailbox == "All Folders") {
473 /* We entered compose via the search results page */
474 $mailbox = 'INBOX'; /* Send 'em to INBOX, that's safe enough */
476 $urlMailbox = urlencode($mailbox);
477 if (! isset($passed_id)) {
481 * Set $default_charset to correspond with the user's selection
482 * of language interface.
486 * This is to change all newlines to \n
487 * We'll change them to \r\n later (in the sendMessage function)
489 $body = str_replace("\r\n", "\n", $body);
490 $body = str_replace("\r", "\n", $body);
493 * Rewrap $body so that no line is bigger than $editor_size
495 $body = explode("\n", $body);
497 foreach ($body as $line) {
498 if( $line <> '-- ' ) {
499 $line = rtrim($line);
501 if (sq_strlen($line, $default_charset) <= $editor_size +
1) {
502 $newBody .= $line . "\n";
504 sqWordWrap($line, $editor_size, $default_charset);
505 $newBody .= $line . "\n";
512 $Result = deliverMessage($composeMessage);
519 // NOTE: this hook changed in 1.5.2 from sending $Result and
520 // $composeMessage as args #2 and #3 to being in an array
522 $temp = array(&$Result, &$composeMessage, &$mail_sent);
523 do_hook('compose_send_after', $temp);
525 showInputForm($session);
529 /* if it is resumed draft, delete draft message */
530 if ( isset($delete_draft)) {
531 $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false);
532 sqimap_mailbox_select($imap_stream, $draft_folder);
533 // bypass_trash=true because message should be saved when deliverMessage() returns true.
534 // in current implementation of sqimap_msgs_list_flag() single message id can
535 // be submitted as string. docs state that it should be array.
536 sqimap_msgs_list_delete($imap_stream, $draft_folder, $delete_draft, true);
538 sqimap_mailbox_expunge($imap_stream, $draft_folder, true);
540 sqimap_logout($imap_stream);
543 * Store the error array in the session because they will be lost on a redirect
545 $oErrorHandler->saveDelayedErrors();
546 session_write_close();
548 if ($compose_new_win == '1') {
549 if ( !isset($pageheader_sent) ||
!$pageheader_sent ) {
550 header("Location: $location/compose.php?mail_sent=$mail_sent");
552 //FIXME: DON'T ECHO HTML FROM CORE!
553 echo ' <br><br><div style="text-align: center;"><a href="' . $location
554 . '/compose.php?mail_sent=$mail_sent">'
555 . _("Return") . '</a></div>';
559 if ( !isset($pageheader_sent) ||
!$pageheader_sent ) {
560 header("Location: $location/right_main.php?mailbox=$urlMailbox".
561 "&startMessage=$startMessage&mail_sent=$mail_sent");
563 //FIXME: DON'T ECHO HTML FROM CORE!
564 echo ' <br><br><div style="text-align: center;"><a href="' . $location
565 . "/right_main.php?mailbox=$urlMailbox"
566 . "&startMessage=$startMessage&mail_sent=$mail_sent\">"
567 . _("Return") . '</a></div>';
572 if ($compose_new_win == '1') {
573 compose_Header($color, $mailbox);
576 displayPageHeader($color, $mailbox);
578 if (isset($AttachFailure)) {
579 plain_error_message(_("Could not move/copy file. File not attached"),
583 showInputForm($session);
584 /* sqimap_logout($imapConnection); */
586 } elseif (isset($html_addr_search_done)) {
587 if ($compose_new_win == '1') {
588 compose_Header($color, $mailbox);
591 displayPageHeader($color, $mailbox);
594 if (isset($send_to_search) && is_array($send_to_search)) {
595 foreach ($send_to_search as $k => $v) {
596 if (substr($k, 0, 1) == 'T') {
602 elseif (substr($k, 0, 1) == 'C') {
608 elseif (substr($k, 0, 1) == 'B') {
610 $send_to_bcc .= ', ';
616 showInputForm($session);
617 } elseif (isset($html_addr_search) && !isset($html_addr_search_cancel)) {
618 if (isset($_FILES['attachfile']) &&
619 $_FILES['attachfile']['tmp_name'] &&
620 $_FILES['attachfile']['tmp_name'] != 'none') {
621 if(saveAttachedFiles($session)) {
622 plain_error_message(_("Could not move/copy file. File not attached"));
626 * I am using an include so as to elminiate an extra unnecessary
627 * click. If you can think of a better way, please implement it.
629 include_once('./addrbook_search_html.php');
630 } elseif (isset($attach)) {
631 if ($compose_new_win == '1') {
632 compose_Header($color, $mailbox);
634 displayPageHeader($color, $mailbox);
636 if (saveAttachedFiles($session)) {
637 plain_error_message(_("Could not move/copy file. File not attached"));
639 showInputForm($session);
641 elseif (isset($sigappend)) {
642 $signature = $idents[$identity]['signature'];
644 $body .= "\n\n".($prefix_sig==true?
"-- \n":'').$signature;
645 if ($compose_new_win == '1') {
646 compose_Header($color, $mailbox);
648 displayPageHeader($color, $mailbox);
650 showInputForm($session);
651 } elseif (isset($do_delete)) {
652 if ($compose_new_win == '1') {
653 compose_Header($color, $mailbox);
655 displayPageHeader($color, $mailbox);
658 if (isset($delete) && is_array($delete)) {
659 foreach($delete as $index) {
660 if (!empty($composeMessage->entities
) && isset($composeMessage->entities
[$index])) {
661 $composeMessage->entities
[$index]->purgeAttachments();
662 // 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
663 //$composeMessage->entities[$index] = NULL;
664 unset ($composeMessage->entities
[$index]);
667 $new_entities = array();
668 foreach ($composeMessage->entities
as $entity) {
669 $new_entities[] = $entity;
671 $composeMessage->entities
= $new_entities;
673 showInputForm($session);
676 * This handles the default case as well as the error case
677 * (they had the same code) --> if (isset($smtpErrors))
680 if ($compose_new_win == '1') {
681 compose_Header($color, $mailbox);
683 displayPageHeader($color, $mailbox);
688 if (!isset($passed_ent_id)) {
691 if (!isset($passed_id)) {
694 if (!isset($mailbox)) {
697 if (!isset($action)) {
701 $values = newMail($mailbox,$passed_id,$passed_ent_id, $action, $session);
703 /* in case the origin is not read_body.php */
704 if (isset($send_to)) {
705 $values['send_to'] = $send_to;
707 if (isset($send_to_cc)) {
708 $values['send_to_cc'] = $send_to_cc;
710 if (isset($send_to_bcc)) {
711 $values['send_to_bcc'] = $send_to_bcc;
713 if (isset($subject)) {
714 $values['subject'] = $subject;
716 showInputForm($session, $values);
721 /**************** Only function definitions go below *************/
723 function getforwardSubject($subject)
725 if ((substr(strtolower($subject), 0, 4) != 'fwd:') &&
726 (substr(strtolower($subject), 0, 5) != '[fwd:') &&
727 (substr(strtolower($subject), 0, 6) != '[ fwd:')) {
728 $subject = '[Fwd: ' . $subject . ']';
733 /* This function is used when not sending or adding attachments */
734 function newMail ($mailbox='', $passed_id='', $passed_ent_id='', $action='', $session='') {
735 global $editor_size, $default_use_priority, $body, $idents,
736 $use_signature, $data_dir, $username,
737 $key, $imapServerAddress, $imapPort,
738 $composeMessage, $body_quote, $request_mdn, $request_dr,
739 $mdn_user_support, $languages, $squirrelmail_language,
743 * Set $default_charset to correspond with the user's selection
744 * of language interface. $default_charset global is not correct,
745 * if message is composed in new window.
749 $send_to = $send_to_cc = $send_to_bcc = $subject = $identity = '';
753 $imapConnection = sqimap_login($username, false, $imapServerAddress,
756 sqimap_mailbox_select($imapConnection, $mailbox);
757 $message = sqimap_get_message($imapConnection, $passed_id, $mailbox);
760 if ($passed_ent_id) {
761 /* redefine the messsage in case of message/rfc822 */
762 $message = $message->getEntity($passed_ent_id);
763 /* message is an entity which contains the envelope and type0=message
764 * and type1=rfc822. The actual entities are childs from
765 * $message->entities[0]. That's where the encoding and is located
768 $entities = $message->entities
[0]->findDisplayEntity
769 (array(), $alt_order = array('text/plain'));
770 if (!count($entities)) {
771 $entities = $message->entities
[0]->findDisplayEntity
772 (array(), $alt_order = array('text/plain','text/html'));
774 $orig_header = $message->rfc822_header
; /* here is the envelope located */
775 /* redefine the message for picking up the attachments */
776 $message = $message->entities
[0];
779 $entities = $message->findDisplayEntity (array(), $alt_order = array('text/plain'));
780 if (!count($entities)) {
781 $entities = $message->findDisplayEntity (array(), $alt_order = array('text/plain','text/html'));
783 $orig_header = $message->rfc822_header
;
786 $type0 = $message->type0
;
787 $type1 = $message->type1
;
788 foreach ($entities as $ent) {
789 $msg = $message->getEntity($ent);
790 $type0 = $msg->type0
;
791 $type1 = $msg->type1
;
792 $unencoded_bodypart = mime_fetch_body($imapConnection, $passed_id, $ent);
793 $body_part_entity = $message->getEntity($ent);
794 $bodypart = decodeBody($unencoded_bodypart,
795 $body_part_entity->header
->encoding
);
796 if ($type1 == 'html') {
797 $bodypart = str_replace("\n", ' ', $bodypart);
798 $bodypart = preg_replace(array('/<\/?p>/i','/<div><\/div>/i','/<br\s*(\/)*>/i','/<\/?div>/i'), "\n", $bodypart);
799 $bodypart = str_replace(array(' ','>','<'),array(' ','>','<'),$bodypart);
800 $bodypart = strip_tags($bodypart);
802 if (isset($languages[$squirrelmail_language]['XTRA_CODE']) &&
803 function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode')) {
804 if (mb_detect_encoding($bodypart) != 'ASCII') {
805 $bodypart = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode', $bodypart);
809 // charset encoding in compose form stuff
810 if (isset($body_part_entity->header
->parameters
['charset'])) {
811 $actual = $body_part_entity->header
->parameters
['charset'];
813 $actual = 'us-ascii';
816 if ( $actual && is_conversion_safe($actual) && $actual != $default_charset){
817 $bodypart = charset_convert($actual,$bodypart,$default_charset,false);
819 // end of charset encoding in compose
823 if ($default_use_priority) {
824 $mailprio = substr($orig_header->priority
,0,1);
832 $from_o = $orig_header->from
;
833 if (is_array($from_o)) {
834 if (isset($from_o[0])) {
835 $from_o = $from_o[0];
838 if (is_object($from_o)) {
839 $orig_from = $from_o->getAddress();
844 $identities = array();
845 if (count($idents) > 1) {
846 foreach($idents as $nr=>$data) {
847 $enc_from_name = '"'.$data['full_name'].'" <'. $data['email_address'].'>';
848 if(strtolower($enc_from_name) == strtolower($orig_from)) {
850 // don't stop! need to build $identities array for idents match below
853 $identities[] = $enc_from_name;
856 $identity_match = $orig_header->findAddress($identities);
857 if ($identity_match) {
858 $identity = $identity_match;
864 $use_signature = FALSE;
865 $composeMessage->rfc822_header
= $orig_header;
866 $send_to = decodeHeader($orig_header->getAddr_s('to'),false,false,true);
867 $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'),false,false,true);
868 $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'),false,false,true);
869 $send_from = $orig_header->getAddr_s('from');
870 $send_from_parts = new AddressStructure();
871 $send_from_parts = $orig_header->parseAddress($send_from);
872 $send_from_add = $send_from_parts->mailbox
. '@' . $send_from_parts->host
;
873 $identity = find_identity(array($send_from_add));
874 $subject = decodeHeader($orig_header->subject
,false,false,true);
876 // Remember the receipt settings
877 $request_mdn = $mdn_user_support && !empty($orig_header->dnt
) ?
'1' : '0';
878 $request_dr = $mdn_user_support && !empty($orig_header->drnt
) ?
'1' : '0';
880 /* remember the references and in-reply-to headers in case of an reply */
881 //FIXME: it would be better to fiddle with headers inside of the message object or possibly when delivering the message to its destination (drafts folder?); is this possible?
882 $composeMessage->rfc822_header
->more_headers
['References'] = $orig_header->references
;
883 $composeMessage->rfc822_header
->more_headers
['In-Reply-To'] = $orig_header->in_reply_to
;
884 // rewrap the body to clean up quotations and line lengths
885 sqBodyWrap($body, $editor_size);
886 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
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
;
895 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
896 // rewrap the body to clean up quotations and line lengths
897 sqBodyWrap($body, $editor_size);
901 $subject = getforwardSubject(decodeHeader($orig_header->subject
,false,false,true));
902 $body = getforwardHeader($orig_header) . $body;
903 // the logic for calling sqUnWordWrap here would be to allow the browser to wrap the lines
904 // forwarded message text should be as undisturbed as possible, so commenting out this call
905 // sqUnWordWrap($body);
906 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
908 //add a blank line after the forward headers
909 $body = "\n" . $body;
911 case ('forward_as_attachment'):
912 $subject = getforwardSubject(decodeHeader($orig_header->subject
,false,false,true));
913 $composeMessage = getMessage_RFC822_Attachment($message, $composeMessage, $passed_id, $passed_ent_id, $imapConnection);
917 if(isset($orig_header->mail_followup_to
) && $orig_header->mail_followup_to
) {
918 $send_to = $orig_header->getAddr_s('mail_followup_to');
920 $send_to_cc = replyAllString($orig_header);
921 $send_to_cc = decodeHeader($send_to_cc,false,false,true);
924 // skip this if send_to was already set right above here
926 $send_to = $orig_header->reply_to
;
927 if (is_array($send_to) && count($send_to)) {
928 $send_to = $orig_header->getAddr_s('reply_to');
929 } else if (is_object($send_to)) { /* unneccesarry, just for failsafe purpose */
930 $send_to = $orig_header->getAddr_s('reply_to');
932 $send_to = $orig_header->getAddr_s('from');
935 $send_to = decodeHeader($send_to,false,false,true);
936 $subject = decodeHeader($orig_header->subject
,false,false,true);
937 $subject = str_replace('"', "'", $subject);
938 $subject = trim($subject);
939 if (substr(strtolower($subject), 0, 3) != 're:') {
940 $subject = 'Re: ' . $subject;
942 /* this corrects some wrapping/quoting problems on replies */
943 $rewrap_body = explode("\n", $body);
944 $from = (is_array($orig_header->from
) && !empty($orig_header->from
)) ?
$orig_header->from
[0] : $orig_header->from
;
946 $strip_sigs = getPref($data_dir, $username, 'strip_sigs');
947 foreach ($rewrap_body as $line) {
948 if ($strip_sigs && substr($line,0,3) == '-- ') {
951 if (preg_match("/^(>+)/", $line, $matches)) {
953 $body .= $body_quote . str_replace("\n", "\n$body_quote$gt ", rtrim($line)) ."\n";
955 $body .= $body_quote . (!empty($body_quote) ?
' ' : '') . str_replace("\n", "\n$body_quote" . (!empty($body_quote) ?
' ' : ''), rtrim($line)) . "\n";
959 //rewrap the body to clean up quotations and line lengths
960 $body = sqBodyWrap ($body, $editor_size);
962 $body = getReplyCitation($from , $orig_header->date
) . $body;
963 $composeMessage->reply_rfc822_header
= $orig_header;
969 //FIXME: we used to register $compose_messages in the session here, but not any more - so do we still need the session_write_close() and sqimap_logout() here? We probably need the IMAP logout, but what about the session closure?
970 session_write_close();
971 sqimap_logout($imapConnection);
973 $ret = array( 'send_to' => $send_to,
974 'send_to_cc' => $send_to_cc,
975 'send_to_bcc' => $send_to_bcc,
976 'subject' => $subject,
977 'mailprio' => $mailprio,
979 'identity' => $identity );
982 } /* function newMail() */
985 * downloads attachments from original message, stores them in attachment directory and adds
986 * them to composed message.
987 * @param object $message
988 * @param object $composeMessage
989 * @param integer $passed_id
990 * @param mixed $entities
991 * @param mixed $imapConnection
994 function getAttachments($message, &$composeMessage, $passed_id, $entities, $imapConnection) {
995 global $squirrelmail_language, $languages, $username, $attachment_dir;
997 if (!count($message->entities
) ||
998 ($message->type0
== 'message' && $message->type1
== 'rfc822')) {
999 if ( !in_array($message->entity_id
, $entities) && $message->entity_id
) {
1000 switch ($message->type0
) {
1002 if ($message->type1
== 'rfc822') {
1003 $filename = $message->rfc822_header
->subject
;
1004 if ($filename == "") {
1005 $filename = "untitled-".$message->entity_id
;
1007 $filename .= '.eml';
1009 $filename = $message->getFilename();
1013 if (!$message->mime_header
) { /* temporary hack */
1014 $message->mime_header
= $message->header
;
1016 $filename = $message->getFilename();
1019 $filename = str_replace(' ', ' ', decodeHeader($filename));
1020 if (isset($languages[$squirrelmail_language]['XTRA_CODE']) &&
1021 function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode')) {
1022 $filename = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode', $filename);
1025 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
1026 $localfilename = sq_get_attach_tempfile();
1027 $message->att_local_name
= $localfilename;
1029 $composeMessage->initAttachment($message->type0
.'/'.$message->type1
,$filename,
1032 /* Write Attachment to file */
1033 $fp = fopen ($hashed_attachment_dir . '/' . $localfilename, 'wb');
1034 mime_print_body_lines ($imapConnection, $passed_id, $message->entity_id
, $message->header
->encoding
, $fp);
1038 for ($i=0, $entCount=count($message->entities
); $i<$entCount;$i++
) {
1039 $composeMessage=getAttachments($message->entities
[$i], $composeMessage, $passed_id, $entities, $imapConnection);
1042 return $composeMessage;
1045 function getMessage_RFC822_Attachment($message, $composeMessage, $passed_id,
1046 $passed_ent_id='', $imapConnection) {
1047 if (!$passed_ent_id) {
1048 $body_a = sqimap_run_command($imapConnection,
1049 'FETCH '.$passed_id.' RFC822',
1050 TRUE, $response, $readmessage,
1053 $body_a = sqimap_run_command($imapConnection,
1054 'FETCH '.$passed_id.' BODY['.$passed_ent_id.']',
1055 TRUE, $response, $readmessage, TRUE);
1056 $message = $message->parent
;
1058 if ($response == 'OK') {
1059 $subject = encodeHeader($message->rfc822_header
->subject
);
1060 array_shift($body_a);
1062 $body = implode('', $body_a) . "\r\n";
1064 global $username, $attachment_dir;
1065 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
1066 $localfilename = sq_get_attach_tempfile();
1067 $fp = fopen($hashed_attachment_dir . '/' . $localfilename, 'wb');
1068 fwrite ($fp, $body);
1070 $composeMessage->initAttachment('message/rfc822',$subject.'.eml',
1073 return $composeMessage;
1076 function showInputForm ($session, $values=false) {
1077 global $send_to, $send_to_cc, $send_to_bcc,
1078 $body, $startMessage, $action, $attachments,
1079 $use_signature, $signature, $prefix_sig, $session_expired,
1080 $editor_size, $editor_height, $subject, $newmail,
1081 $use_javascript_addr_book, $passed_id, $mailbox,
1082 $from_htmladdr_search, $location_of_buttons, $attachment_dir,
1083 $username, $data_dir, $identity, $idents, $delete_draft,
1084 $mailprio, $compose_new_win, $saved_draft, $mail_sent, $sig_first,
1085 $composeMessage, $composesession, $default_charset,
1086 $compose_onsubmit, $oTemplate, $oErrorHandler;
1088 if (checkForJavascript()) {
1089 $onfocus = ' onfocus="alreadyFocused=true;"';
1090 $onfocus_array = array('onfocus' => 'alreadyFocused=true;');
1094 $onfocus_array = array();
1098 $send_to = $values['send_to'];
1099 $send_to_cc = $values['send_to_cc'];
1100 $send_to_bcc = $values['send_to_bcc'];
1101 $subject = $values['subject'];
1102 $mailprio = $values['mailprio'];
1103 $body = $values['body'];
1104 $identity = (int) $values['identity'];
1106 $send_to = decodeHeader($send_to, true, false);
1107 $send_to_cc = decodeHeader($send_to_cc, true, false);
1108 $send_to_bcc = decodeHeader($send_to_bcc, true, false);
1111 if ($use_javascript_addr_book) {
1112 //FIXME: NO HTML IN CORE!
1113 echo "\n". '<script type="text/javascript">'."\n<!--\n" .
1114 'function open_abook() { ' . "\n" .
1115 ' var nwin = window.open("addrbook_popup.php","abookpopup",' .
1116 '"width=670,height=300,resizable=yes,scrollbars=yes");' . "\n" .
1117 ' if((!nwin.opener) && (document.windows != null))' . "\n" .
1118 ' nwin.opener = document.windows;' . "\n" .
1120 "// -->\n</script>\n\n";
1123 //FIXME: NO HTML IN CORE!
1124 echo "\n" . '<form name="compose" action="compose.php" method="post" ' .
1125 'enctype="multipart/form-data"';
1127 $compose_onsubmit = array();
1129 do_hook('compose_form', $null);
1131 // Plugins that use compose_form hook can add an array entry
1132 // to the globally scoped $compose_onsubmit; we add them up
1133 // here and format the form tag's full onsubmit handler.
1134 // Each plugin should use "return false" if they need to
1135 // stop form submission but otherwise should NOT use "return
1136 // true" to give other plugins the chance to do what they need
1137 // to do; SquirrelMail itself will add the final "return true".
1138 // Onsubmit text is enclosed inside of double quotes, so plugins
1139 // need to quote accordingly.
1140 if (checkForJavascript()) {
1141 $onsubmit_text = ' onsubmit="';
1142 if (empty($compose_onsubmit))
1143 $compose_onsubmit = array();
1144 else if (!is_array($compose_onsubmit))
1145 $compose_onsubmit = array($compose_onsubmit);
1147 foreach ($compose_onsubmit as $text) {
1148 $text = trim($text);
1149 if (substr($text, -1) != ';' && substr($text, -1) != '}')
1151 $onsubmit_text .= $text;
1154 //FIXME: DON'T ECHO HTML FROM CORE!
1155 echo $onsubmit_text . ' return true;"';
1159 //FIXME: NO HTML IN CORE!
1162 //FIXME: DON'T ECHO HTML FROM CORE!
1163 echo addHidden('startMessage', $startMessage);
1165 if ($action == 'draft') {
1166 //FIXME: DON'T ECHO HTML FROM CORE!
1167 echo addHidden('delete_draft', $passed_id);
1169 if (isset($delete_draft)) {
1170 //FIXME: DON'T ECHO HTML FROM CORE!
1171 echo addHidden('delete_draft', $delete_draft);
1173 if (isset($session)) {
1174 //FIXME: DON'T ECHO HTML FROM CORE!
1175 echo addHidden('session', $session);
1178 if (isset($passed_id)) {
1179 //FIXME: DON'T ECHO HTML FROM CORE!
1180 echo addHidden('passed_id', $passed_id);
1183 if ($saved_draft == 'yes') {
1184 $oTemplate->assign('note', _("Your draft has been saved."));
1185 $oTemplate->display('note.tpl');
1187 if ($mail_sent == 'yes') {
1188 $oTemplate->assign('note', _("Your mail has been sent."));
1189 $oTemplate->display('note.tpl');
1191 if ($compose_new_win == '1') {
1192 $oTemplate->display('compose_newwin_close.tpl');
1195 if ($location_of_buttons == 'top') {
1196 //FIXME: DON'T ECHO HTML FROM CORE!
1197 showComposeButtonRow();
1200 $identities = array();
1201 if (count($idents) > 1) {
1203 foreach($idents as $id => $data) {
1204 $identities[$id] = $data['full_name'].' <'.$data['email_address'].'>';
1208 $oTemplate->assign('identities', $identities);
1209 $oTemplate->assign('identity_def', $identity);
1210 $oTemplate->assign('input_onfocus', 'onfocus="'.join(' ', $onfocus_array).'"');
1212 $oTemplate->assign('to', htmlspecialchars($send_to));
1213 $oTemplate->assign('cc', htmlspecialchars($send_to_cc));
1214 $oTemplate->assign('bcc', htmlspecialchars($send_to_bcc));
1215 $oTemplate->assign('subject', htmlspecialchars($subject));
1217 $oTemplate->display('compose_header.tpl');
1219 if ($location_of_buttons == 'between') {
1220 //FIXME: DON'T ECHO HTML FROM CORE!
1221 showComposeButtonRow();
1225 if ($use_signature == true && $newmail == true && !isset($from_htmladdr_search)) {
1226 $signature = $idents[$identity]['signature'];
1228 if ($sig_first == '1') {
1230 * FIXME: test is specific to ja_JP translation implementation.
1231 * This test might apply incorrect conversion to other translations, but
1232 * use of 7bit iso-2022-jp charset in other translations might have other
1235 if ($default_charset == 'iso-2022-jp') {
1236 $body_str = "\n\n".($prefix_sig==true?
"-- \n":'').mb_convert_encoding($signature, 'EUC-JP');
1238 $body_str = "\n\n".($prefix_sig==true?
"-- \n":'').decodeHeader($signature,false,false);
1240 $body_str .= "\n\n".htmlspecialchars(decodeHeader($body,false,false));
1242 $body_str = "\n\n".htmlspecialchars(decodeHeader($body,false,false));
1243 // FIXME: test is specific to ja_JP translation implementation. See above comments.
1244 if ($default_charset == 'iso-2022-jp') {
1245 $body_str .= "\n\n".($prefix_sig==true?
"-- \n":'').mb_convert_encoding($signature, 'EUC-JP');
1247 $body_str .= "\n\n".($prefix_sig==true?
"-- \n":'').decodeHeader($signature,false,false);
1251 $body_str = htmlspecialchars(decodeHeader($body,false,false));
1254 $oTemplate->assign('editor_width', (int)$editor_size);
1255 $oTemplate->assign('editor_height', (int)$editor_height);
1256 $oTemplate->assign('input_onfocus', 'onfocus="'.join(' ', $onfocus_array).'"');
1257 $oTemplate->assign('body', $body_str);
1258 $oTemplate->assign('show_bottom_send', $location_of_buttons!='bottom');
1260 $oTemplate->display ('compose_body.tpl');
1262 if ($location_of_buttons == 'bottom') {
1263 //FIXME: DON'T ECHO HTML FROM CORE!
1264 showComposeButtonRow();
1267 // composeMessage can be empty when coming from a restored session
1268 if (is_object($composeMessage) && $composeMessage->entities
)
1269 $attach_array = $composeMessage->entities
;
1270 if ($session_expired && !empty($attachments) && is_array($attachments))
1271 $attach_array = $attachments;
1273 /* This code is for attachments */
1274 if ((bool) ini_get('file_uploads')) {
1276 /* Calculate the max size for an uploaded file.
1277 * This is advisory for the user because we can't actually prevent
1278 * people to upload too large files. */
1280 /* php.ini vars which influence the max for uploads */
1281 $configvars = array('post_max_size', 'memory_limit', 'upload_max_filesize');
1282 foreach($configvars as $var) {
1283 /* skip 0 or empty values, and -1 which means 'unlimited' */
1284 if( $size = getByteSize(ini_get($var)) ) {
1285 if ( $size != '-1' ) {
1292 global $username, $attachment_dir;
1293 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
1294 if (!empty($attach_array)) {
1295 foreach ($attach_array as $key => $attachment) {
1296 $attached_file = $attachment->att_local_name
;
1297 if ($attachment->att_local_name ||
$attachment->body_part
) {
1298 $attached_filename = decodeHeader($attachment->mime_header
->getParameter('name'));
1299 $type = $attachment->mime_header
->type0
.'/'.
1300 $attachment->mime_header
->type1
;
1304 $a['FileName'] = $attached_filename;
1305 $a['ContentType'] = $type;
1306 $a['Size'] = filesize($hashed_attachment_dir . '/' . $attached_file);
1313 $oTemplate->assign('max_file_size', empty($max) ?
-1 : $max);
1314 $oTemplate->assign('attachments', $attach);
1316 $oTemplate->display('compose_attachments.tpl');
1317 } // End of file_uploads if-block
1318 /* End of attachment code */
1320 //FIXME: no direct echoing to browser, no HTML output in core!
1321 echo addHidden('username', $username).
1322 addHidden('smaction', $action).
1323 addHidden('mailbox', $mailbox);
1324 sqgetGlobalVar('QUERY_STRING', $queryString, SQ_SERVER
);
1325 //FIXME: no direct echoing to browser, no HTML output in core!
1326 echo addHidden('composesession', $composesession).
1327 addHidden('querystring', $queryString).
1328 (!empty($attach_array) ?
1329 addHidden('attachments', urlencode(serialize($attach_array))) : '').
1331 if (!(bool) ini_get('file_uploads')) {
1332 /* File uploads are off, so we didn't show that part of the form.
1333 To avoid bogus bug reports, tell the user why. */
1334 //FIXME: no direct echoing to browser, no HTML output in core!
1335 echo '<p style="text-align:center">'
1336 . _("Because PHP file uploads are turned off, you can not attach files to this message. Please see your system administrator for details.")
1340 if ($compose_new_win=='1') {
1341 $oTemplate->display('compose_newwin_close.tpl');
1344 do_hook('compose_bottom', $null);
1346 $oErrorHandler->setDelayedErrors(false);
1347 $oTemplate->display('footer.tpl');
1351 function showComposeButtonRow() {
1352 global $use_javascript_addr_book, $save_as_draft,
1353 $default_use_priority, $mailprio, $default_use_mdn,
1354 $request_mdn, $request_dr,
1355 $data_dir, $username;
1357 global $oTemplate, $buffer_hook;
1359 if ($default_use_priority) {
1360 $priorities = array('1'=>_("High"), '3'=>_("Normal"), '5'=>_("Low"));
1361 $priority = isset($mailprio) ?
$mailprio : 3;
1363 $priorities = array();
1367 $mdn_user_support=getPref($data_dir, $username, 'mdn_user_support',$default_use_mdn);
1369 if ($use_javascript_addr_book && checkForJavascript()) {
1370 $addr_book = addButton(_("Addresses"), null, array('onclick' => 'javascript:open_abook();'));
1372 $addr_book = addSubmit(_("Addresses"), 'html_addr_search');
1375 $oTemplate->assign('allow_priority', $default_use_priority==1);
1376 $oTemplate->assign('priority_list', $priorities);
1377 $oTemplate->assign('current_priority', $priority);
1379 $oTemplate->assign('notifications_enabled', $mdn_user_support==1);
1380 $oTemplate->assign('read_receipt', $request_mdn=='1');
1381 $oTemplate->assign('delivery_receipt', $request_dr=='1');
1383 $oTemplate->assign('drafts_enabled', $save_as_draft);
1384 $oTemplate->assign('address_book_button', $addr_book);
1386 $oTemplate->display('compose_buttons.tpl');
1389 function checkInput ($show) {
1391 * I implemented the $show variable because the error messages
1392 * were getting sent before the page header. So, I check once
1393 * using $show=false, and then when i'm ready to display the error
1394 * message, show=true
1396 global $send_to, $send_to_cc, $send_to_bcc;
1398 $send_to = trim($send_to);
1399 $send_to_cc = trim($send_to_cc);
1400 $send_to_bcc = trim($send_to_bcc);
1401 if (empty($send_to) && empty($send_to_cc) && empty($send_to_bcc)) {
1403 plain_error_message(_("You have not filled in the \"To:\" field."));
1408 } /* function checkInput() */
1411 /* True if FAILURE */
1412 function saveAttachedFiles($session) {
1413 global $composeMessage, $username, $attachment_dir;
1415 /* get out of here if no file was attached at all */
1416 if (! is_uploaded_file($_FILES['attachfile']['tmp_name']) ) {
1420 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
1421 $localfilename = sq_get_attach_tempfile();
1422 $fullpath = $hashed_attachment_dir . '/' . $localfilename;
1424 // m_u_f works better with restricted PHP installs (safe_mode, open_basedir),
1425 // if that doesn't work, try a simple rename.
1426 if (!sq_call_function_suppress_errors('move_uploaded_file', array($_FILES['attachfile']['tmp_name'], $fullpath))) {
1427 if (!sq_call_function_suppress_errors('rename', array($_FILES['attachfile']['tmp_name'], $fullpath))) {
1431 $type = strtolower($_FILES['attachfile']['type']);
1432 $name = $_FILES['attachfile']['name'];
1433 $composeMessage->initAttachment($type, $name, $localfilename);
1436 /* parse values like 8M and 2k into bytes */
1437 function getByteSize($ini_size) {
1443 $ini_size = trim($ini_size);
1445 // if there's some kind of letter at the end of the string we need to multiply.
1446 if(!is_numeric(substr($ini_size, -1))) {
1448 switch(strtoupper(substr($ini_size, -1))) {
1450 $bytesize = 1073741824;
1453 $bytesize = 1048576;
1460 return ($bytesize * (int)substr($ini_size, 0, -1));
1468 * temporary function to make use of the deliver class.
1469 * In the future the responsible backend should be automaticly loaded
1470 * and conf.pl should show a list of available backends.
1471 * The message also should be constructed by the message class.
1473 * @param object $composeMessage The message being sent. Please note
1474 * that it is passed by reference and
1475 * will be returned modified, with additional
1476 * headers, such as Message-ID, Date, In-Reply-To,
1477 * References, and so forth.
1479 * @return boolean FALSE if delivery failed, or some non-FALSE value
1483 function deliverMessage(&$composeMessage, $draft=false) {
1484 global $send_to, $send_to_cc, $send_to_bcc, $mailprio, $subject, $body,
1485 $username, $identity, $idents, $data_dir,
1486 $request_mdn, $request_dr, $default_charset, $useSendmail,
1487 $domain, $action, $default_move_to_sent, $move_to_sent,
1488 $imapServerAddress, $imapPort, $sent_folder, $key;
1490 $rfc822_header = $composeMessage->rfc822_header
;
1492 $abook = addressbook_init(false, true);
1493 $rfc822_header->to
= $rfc822_header->parseAddress($send_to,true, array(), '', $domain, array(&$abook,'lookup'));
1494 $rfc822_header->cc
= $rfc822_header->parseAddress($send_to_cc,true,array(), '',$domain, array(&$abook,'lookup'));
1495 $rfc822_header->bcc
= $rfc822_header->parseAddress($send_to_bcc,true, array(), '',$domain, array(&$abook,'lookup'));
1496 $rfc822_header->priority
= $mailprio;
1497 $rfc822_header->subject
= $subject;
1499 $special_encoding='';
1500 if (strtolower($default_charset) == 'iso-2022-jp') {
1501 if (mb_detect_encoding($body) == 'ASCII') {
1502 $special_encoding = '8bit';
1504 $body = mb_convert_encoding($body, 'JIS');
1505 $special_encoding = '7bit';
1508 $composeMessage->setBody($body);
1511 $reply_to = $idents[$identity]['reply_to'];
1513 $from_addr = build_from_header($identity);
1514 $rfc822_header->from
= $rfc822_header->parseAddress($from_addr,true);
1516 $rfc822_header->reply_to
= $rfc822_header->parseAddress($reply_to,true);
1518 /* Receipt: On Read */
1519 if (isset($request_mdn) && $request_mdn) {
1520 $rfc822_header->dnt
= $rfc822_header->parseAddress($from_addr,true);
1521 } elseif (isset($rfc822_header->dnt
)) {
1522 unset($rfc822_header->dnt
);
1525 /* Receipt: On Delivery */
1526 if (!empty($request_dr)) {
1527 //FIXME: it would be better to fiddle with headers inside of the message object or possibly when delivering the message to its destination; is this possible?
1528 $rfc822_header->more_headers
['Return-Receipt-To'] = $from_addr;
1529 } elseif (isset($rfc822_header->more_headers
['Return-Receipt-To'])) {
1530 unset($rfc822_header->more_headers
['Return-Receipt-To']);
1533 /* multipart messages */
1534 if (count($composeMessage->entities
)) {
1535 $message_body = new Message();
1536 $message_body->body_part
= $composeMessage->body_part
;
1537 $composeMessage->body_part
= '';
1538 $mime_header = new MessageHeader
;
1539 $mime_header->type0
= 'text';
1540 $mime_header->type1
= 'plain';
1541 if ($special_encoding) {
1542 $mime_header->encoding
= $special_encoding;
1544 $mime_header->encoding
= '8bit';
1546 if ($default_charset) {
1547 $mime_header->parameters
['charset'] = $default_charset;
1549 $message_body->mime_header
= $mime_header;
1550 array_unshift($composeMessage->entities
, $message_body);
1551 $content_type = new ContentType('multipart/mixed');
1553 $content_type = new ContentType('text/plain');
1554 if ($special_encoding) {
1555 $rfc822_header->encoding
= $special_encoding;
1557 $rfc822_header->encoding
= '8bit';
1559 if ($default_charset) {
1560 $content_type->properties
['charset']=$default_charset;
1564 $rfc822_header->content_type
= $content_type;
1565 $composeMessage->rfc822_header
= $rfc822_header;
1566 if ($action == 'reply' ||
$action == 'reply_all') {
1567 global $passed_id, $passed_ent_id;
1568 $reply_id = $passed_id;
1569 $reply_ent_id = $passed_ent_id;
1575 /* Here you can modify the message structure just before we hand
1576 it over to deliver; plugin authors note that $composeMessage
1577 is sent and modified by reference since 1.5.2 */
1578 do_hook('compose_send', $composeMessage);
1580 if (!$useSendmail && !$draft) {
1581 require_once(SM_PATH
. 'class/deliver/Deliver_SMTP.class.php');
1582 $deliver = new Deliver_SMTP();
1583 global $smtpServerAddress, $smtpPort, $pop_before_smtp, $pop_before_smtp_host;
1585 $authPop = (isset($pop_before_smtp) && $pop_before_smtp) ?
true : false;
1586 if (empty($pop_before_smtp_host)) $pop_before_smtp_host = $smtpServerAddress;
1587 get_smtp_user($user, $pass);
1588 $stream = $deliver->initStream($composeMessage,$domain,0,
1589 $smtpServerAddress, $smtpPort, $user, $pass, $authPop, $pop_before_smtp_host);
1590 } elseif (!$draft) {
1591 require_once(SM_PATH
. 'class/deliver/Deliver_SendMail.class.php');
1592 global $sendmail_path, $sendmail_args;
1593 // Check for outdated configuration
1594 if (!isset($sendmail_args)) {
1595 if ($sendmail_path=='/var/qmail/bin/qmail-inject') {
1596 $sendmail_args = '';
1598 $sendmail_args = '-i -t';
1601 $deliver = new Deliver_SendMail(array('sendmail_args'=>$sendmail_args));
1602 $stream = $deliver->initStream($composeMessage,$sendmail_path);
1604 global $draft_folder;
1605 $imap_stream = sqimap_login($username, false, $imapServerAddress,
1607 if (sqimap_mailbox_exists ($imap_stream, $draft_folder)) {
1608 require_once(SM_PATH
. 'class/deliver/Deliver_IMAP.class.php');
1609 $imap_deliver = new Deliver_IMAP();
1610 $success = $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $draft_folder);
1611 sqimap_logout($imap_stream);
1612 unset ($imap_deliver);
1613 $composeMessage->purgeAttachments();
1616 $msg = '<br />'.sprintf(_("Error: Draft folder %s does not exist."), htmlspecialchars($draft_folder));
1617 plain_error_message($msg);
1623 $deliver->mail($composeMessage, $stream, $reply_id, $reply_ent_id);
1624 $success = $deliver->finalizeStream($stream);
1627 // $deliver->dlv_server_msg is not always server's reply
1628 $msg = _("Message not sent.") . "<br />\n" .
1630 if (!empty($deliver->dlv_server_msg
)) {
1631 // add 'server replied' part only when it is not empty.
1632 // Delivery error can be generated by delivery class itself
1634 _("Server replied:") . ' ' . $deliver->dlv_ret_nr
. ' ' .
1635 nl2br(htmlspecialchars($deliver->dlv_server_msg
));
1637 plain_error_message($msg);
1640 $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, 0);
1643 // mark as replied or forwarded if applicable
1645 global $what, $iAccount, $startMessage, $passed_id, $mailbox;
1647 if ($action=='reply' ||
$action=='reply_all' ||
$action=='forward' ||
$action=='forward_as_attachment') {
1648 require(SM_PATH
. 'functions/mailbox_display.php');
1649 $aMailbox = sqm_api_mailbox_select($imap_stream, $iAccount, $mailbox,array('setindex' => $what, 'offset' => $startMessage),array());
1653 // check if we are allowed to set the \\Answered flag
1654 if (in_array('\\answered',$aMailbox['PERMANENTFLAGS'], true)) {
1655 $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, array($passed_id), '\\Answered', true, false);
1656 if (isset($aUpdatedMsgs[$passed_id]['FLAGS'])) {
1658 * Only update the cached headers if the header is
1661 if (isset($aMailbox['MSG_HEADERS'][$passed_id])) {
1662 $aMailbox['MSG_HEADERS'][$passed_id]['FLAGS'] = $aMsg['FLAGS'];
1668 case 'forward_as_attachment':
1669 // check if we are allowed to set the $Forwarded flag (RFC 4550 paragraph 2.8)
1670 if (in_array('$forwarded',$aMailbox['PERMANENTFLAGS'], true) ||
1671 in_array('\\*',$aMailbox['PERMANENTFLAGS'])) {
1673 $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, array($passed_id), '$Forwarded', true, false);
1674 if (isset($aUpdatedMsgs[$passed_id]['FLAGS'])) {
1675 if (isset($aMailbox['MSG_HEADERS'][$passed_id])) {
1676 $aMailbox['MSG_HEADERS'][$passed_id]['FLAGS'] = $aMsg['FLAGS'];
1684 * Write mailbox with updated seen flag information back to cache.
1686 if(isset($aUpdatedMsgs[$passed_id])) {
1687 $mailbox_cache[$iAccount.'_'.$aMailbox['NAME']] = $aMailbox;
1688 sqsession_register($mailbox_cache,'mailbox_cache');
1694 // move to sent folder
1696 $move_to_sent = getPref($data_dir,$username,'move_to_sent');
1697 if (isset($default_move_to_sent) && ($default_move_to_sent != 0)) {
1698 $svr_allow_sent = true;
1700 $svr_allow_sent = false;
1703 if (isset($sent_folder) && (($sent_folder != '') ||
($sent_folder != 'none'))
1704 && sqimap_mailbox_exists( $imap_stream, $sent_folder)) {
1710 if ((isset($move_to_sent) && ($move_to_sent != 0)) ||
(!isset($move_to_sent))) {
1711 $lcl_allow_sent = true;
1713 $lcl_allow_sent = false;
1716 if (($fld_sent && $svr_allow_sent && !$lcl_allow_sent) ||
($fld_sent && $lcl_allow_sent)) {
1717 if ($action == 'reply' ||
$action == 'reply_all') {
1718 $save_reply_with_orig=getPref($data_dir,$username,'save_reply_with_orig');
1719 if ($save_reply_with_orig) {
1720 $sent_folder = $mailbox;
1723 require_once(SM_PATH
. 'class/deliver/Deliver_IMAP.class.php');
1724 $imap_deliver = new Deliver_IMAP();
1725 $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $sent_folder);
1726 unset ($imap_deliver);
1732 $composeMessage->purgeAttachments();
1733 sqimap_logout($imap_stream);