Happy New Year
[squirrelmail.git] / src / compose.php
CommitLineData
59177427 1<?php
35586184 2/**
3 * compose.php
4 *
35586184 5 * This code sends a mail.
6 *
7 * There are 4 modes of operation:
8 * - Start new mail
9 * - Add an attachment
10 * - Send mail
11 * - Save As Draft
12 *
353d074a 13 * @copyright 1999-2018 The SquirrelMail Project Team
4b4abf93 14 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
30967a1e 15 * @version $Id$
8f6f9ba5 16 * @package squirrelmail
35586184 17 */
f7fb20fe 18
ebd2391c 19/** This is the compose page */
20define('PAGE_NAME', 'compose');
21
30967a1e 22/**
202bcbcc 23 * Include the SquirrelMail initialization file.
30967a1e 24 */
202bcbcc 25require('../include/init.php');
86725763 26
c90271cb 27/* If email_address not set and admin wants us to ask user for it,
28 * redirect to options page. */
29if ( $ask_user_info && getPref($data_dir, $username,'email_address') == "" ) {
30 header("Location: " . get_location() . "/options.php?optpage=personal");
31 exit;
32}
33
86725763 34/* SquirrelMail required files. */
202bcbcc 35require_once(SM_PATH . 'functions/imap_general.php');
36require_once(SM_PATH . 'functions/imap_messages.php');
86725763 37require_once(SM_PATH . 'functions/date.php');
38require_once(SM_PATH . 'functions/mime.php');
628bce99 39require_once(SM_PATH . 'functions/compose.php');
86725763 40require_once(SM_PATH . 'class/deliver/Deliver.class.php');
24192f77 41require_once(SM_PATH . 'functions/addressbook.php');
df96b37a 42require_once(SM_PATH . 'functions/forms.php');
a2b193bc 43require_once(SM_PATH . 'functions/identity.php');
a9805897 44global $imap_stream_options; // in case not defined in config
91f2085b 45
0b97a708 46/* --------------------- Get globals ------------------------------------- */
0b97a708 47
953fa718 48/** SESSION VARS */
953fa718 49sqgetGlobalVar('delimiter', $delimiter, SQ_SESSION);
50
f8eb968d 51sqgetGlobalVar('delayed_errors', $delayed_errors, SQ_SESSION);
953fa718 52sqgetGlobalVar('composesession', $composesession, SQ_SESSION);
53sqgetGlobalVar('compose_messages', $compose_messages, SQ_SESSION);
f8eb968d 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
58sqsession_unregister('compose_messages');
762853f4 59
60// Turn on delayed error handling in case we wind up redirecting below
61$oErrorHandler->setDelayedErrors(true);
953fa718 62
63/** SESSION/POST/GET VARS */
61bd57f5 64sqgetGlobalVar('send_button_count', $send_button_count, SQ_POST, 1, SQ_TYPE_INT);
65for ($i = 1; $i <= $send_button_count; $i++)
66 if (sqgetGlobalVar('send' . $i, $send, SQ_POST)) break;
567dc524 67// Send can only be achieved by setting $_POST var. If Send = true then
68// retrieve other form fields from $_POST
69if (isset($send) && $send) {
70 $SQ_GLOBAL = SQ_POST;
71} else {
72 $SQ_GLOBAL = SQ_FORM;
73}
74sqgetGlobalVar('session',$session, $SQ_GLOBAL);
75sqgetGlobalVar('mailbox',$mailbox, $SQ_GLOBAL);
79cecc00 76sqgetGlobalVar('identity',$orig_identity, $SQ_GLOBAL);
567dc524 77if(!sqgetGlobalVar('identity',$identity, $SQ_GLOBAL)) {
1e2a6ff6 78 $identity=0;
79}
567dc524 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_GLOBAL);
89sqgetGlobalVar('mail_sent',$mail_sent, $SQ_GLOBAL);
51bbe8fa 90sqgetGlobalVar('passed_id',$passed_id, $SQ_GLOBAL, NULL, SQ_TYPE_BIGINT);
567dc524 91sqgetGlobalVar('passed_ent_id',$passed_ent_id, $SQ_GLOBAL);
e506b6e5 92sqgetGlobalVar('fwduid',$fwduid, $SQ_GLOBAL, '');
12a0ed01 93
567dc524 94sqgetGlobalVar('attach',$attach, SQ_POST);
95sqgetGlobalVar('draft',$draft, SQ_POST);
96sqgetGlobalVar('draft_id',$draft_id, $SQ_GLOBAL);
97sqgetGlobalVar('ent_num',$ent_num, $SQ_GLOBAL);
98sqgetGlobalVar('saved_draft',$saved_draft, SQ_FORM);
7e2ff844 99
100if ( sqgetGlobalVar('delete_draft',$delete_draft) ) {
101 $delete_draft = (int)$delete_draft;
102}
103
a6d3eff6 104if ( sqgetGlobalVar('startMessage',$startMessage) ) {
105 $startMessage = (int)$startMessage;
106} else {
107 $startMessage = 1;
108}
953fa718 109
8780308f 110
953fa718 111/** POST VARS */
167c6996 112sqgetGlobalVar('sigappend', $sigappend, SQ_POST);
113sqgetGlobalVar('from_htmladdr_search', $from_htmladdr_search, SQ_POST);
114sqgetGlobalVar('addr_search_done', $html_addr_search_done, SQ_POST);
115sqgetGlobalVar('addr_search_cancel', $html_addr_search_cancel, SQ_POST);
116sqgetGlobalVar('send_to_search', $send_to_search, SQ_POST);
117sqgetGlobalVar('do_delete', $do_delete, SQ_POST);
118sqgetGlobalVar('delete', $delete, SQ_POST);
f8eb968d 119sqgetGlobalVar('attachments', $attachments, SQ_POST);
953fa718 120if ( sqgetGlobalVar('return', $temp, SQ_POST) ) {
73ad81bf 121 $html_addr_search_done = 'Use Addresses';
953fa718 122}
123
124/** GET VARS */
8780308f 125if ( sqgetGlobalVar('account', $temp, SQ_GET) ) {
126 $iAccount = (int) $temp;
127} else {
128 $iAccount = 0;
129}
130
0b97a708 131
98a9cc03 132/** get smaction */
133if ( !sqgetGlobalVar('smaction',$action) )
134{
73ad81bf 135 if ( sqgetGlobalVar('smaction_reply',$tmp) ) $action = 'reply';
136 if ( sqgetGlobalVar('smaction_reply_all',$tmp) ) $action = 'reply_all';
137 if ( sqgetGlobalVar('smaction_forward',$tmp) ) $action = 'forward';
138 if ( sqgetGlobalVar('smaction_attache',$tmp) ) $action = 'forward_as_attachment';
139 if ( sqgetGlobalVar('smaction_draft',$tmp) ) $action = 'draft';
140 if ( sqgetGlobalVar('smaction_edit_new',$tmp) ) $action = 'edit_as_new';
98a9cc03 141}
142
199a9ab8 143sqgetGlobalVar('smtoken', $submitted_token, $SQ_GLOBAL, '');
144
7e2ff844 145/**
146 * Here we decode the data passed in from mailto.php.
147 */
148if ( sqgetGlobalVar('mailtodata', $mailtodata, SQ_GET) ) {
149 $trtable = array('to' => 'send_to',
150 'cc' => 'send_to_cc',
151 'bcc' => 'send_to_bcc',
152 'body' => 'body',
153 'subject' => 'subject');
154 $mtdata = unserialize($mailtodata);
1638beb6 155
7e2ff844 156 foreach ($trtable as $f => $t) {
157 if ( !empty($mtdata[$f]) ) {
158 $$t = $mtdata[$f];
159 }
160 }
161 unset($mailtodata,$mtdata, $trtable);
162}
163
39cf816f 164/* Location (For HTTP 1.1 header("Location: ...") redirects) */
3461167c 165$location = get_location();
1e2a6ff6 166/* Identities (fetch only once) */
167$idents = get_identities();
3461167c 168
09044055 169/* --------------------- Specific Functions ------------------------------ */
0b97a708 170
41b94d65 171function replyAllString($header) {
73ad81bf 172 global $include_self_reply_all, $idents;
173 $excl_ar = array();
174 /**
175 * 1) Remove the addresses we'll be sending the message 'to'
176 */
af084f6e 177 if (isset($header->reply_to)) {
178 $excl_ar = $header->getAddr_a('reply_to');
73ad81bf 179 }
180 /**
181 * 2) Remove our identities from the CC list (they still can be in the
182 * TO list) only if $include_self_reply_all is turned off
183 */
184 if (!$include_self_reply_all) {
185 foreach($idents as $id) {
186 $excl_ar[strtolower(trim($id['email_address']))] = '';
187 }
188 }
189
190 /**
191 * 3) get the addresses.
192 */
193 $url_replytoall_ar = $header->getAddr_a(array('to','cc'), $excl_ar);
194
195 /**
196 * 4) generate the string.
197 */
198 $url_replytoallcc = '';
199 foreach( $url_replytoall_ar as $email => $personal) {
200 if ($personal) {
a9b9e5d3 201 // always quote personal name (can't just quote it if
202 // it contains a comma separator, since it might still
203 // be encoded)
204 $url_replytoallcc .= ", \"$personal\" <$email>";
73ad81bf 205 } else {
206 $url_replytoallcc .= ', '. $email;
1e2a6ff6 207 }
73ad81bf 208 }
209 $url_replytoallcc = substr($url_replytoallcc,2);
210
211 return $url_replytoallcc;
09044055 212}
213
50706f77 214/**
215 * creates top line in reply citations
216 *
217 * Line style depends on user preferences.
218 * $orig_date argument is available only from 1.4.3 and 1.5.1 version.
219 * @param object $orig_from From: header object.
220 * @param integer $orig_date email's timestamp
221 * @return string reply citation
222 */
b0323712 223function getReplyCitation($orig_from, $orig_date) {
12a0ed01 224 global $reply_citation_style, $reply_citation_start, $reply_citation_end;
50706f77 225
05f7db7a 226 if (!is_object($orig_from)) {
d1205176 227 $sOrig_from = '';
05f7db7a 228 } else {
d1205176 229 $sOrig_from = decodeHeader($orig_from->getAddress(false),false,false,true);
05f7db7a 230 }
91c27aee 231
12a0ed01 232 /* First, return an empty string when no citation style selected. */
233 if (($reply_citation_style == '') || ($reply_citation_style == 'none')) {
234 return '';
235 }
236
237 /* Make sure our final value isn't an empty string. */
d1205176 238 if ($sOrig_from == '') {
12a0ed01 239 return '';
240 }
241
242 /* Otherwise, try to select the desired citation style. */
243 switch ($reply_citation_style) {
50706f77 244 case 'author_said':
b986936a 245 // i18n: %s is for author's name
d1205176 246 $full_reply_citation = sprintf(_("%s wrote:"),$sOrig_from);
50706f77 247 break;
248 case 'quote_who':
a42c236f 249 $start = '<quote who="';
50706f77 250 $end = '">';
d1205176 251 $full_reply_citation = $start . $sOrig_from . $end;
50706f77 252 break;
253 case 'date_time_author':
b986936a 254 // i18n:
255 // The first %s is for date string, the second %s is for author's name.
256 // The date uses formating from "D, F j, Y g:i a" and "D, F j, Y H:i"
257 // translations.
258 // Example string:
259 // "On Sat, December 24, 2004 23:59, Santa wrote:"
260 // If you have to put author's name in front of date string, check comments about
261 // argument swapping at http://php.net/sprintf
d1205176 262 $full_reply_citation = sprintf(_("On %s, %s wrote:"), getLongDateString($orig_date), $sOrig_from);
50706f77 263 break;
264 case 'user-defined':
265 $start = $reply_citation_start .
266 ($reply_citation_start == '' ? '' : ' ');
267 $end = $reply_citation_end;
d1205176 268 $full_reply_citation = $start . $sOrig_from . $end;
50706f77 269 break;
270 default:
271 return '';
272 }
273
274 /* Add line feed and return the citation string. */
275 return ($full_reply_citation . "\n");
12a0ed01 276}
277
50706f77 278/**
279 * Creates header fields in forwarded email body
280 *
91c27aee 281 * $default_charset global must be set correctly before you call this function.
50706f77 282 * @param object $orig_header
91c27aee 283 * @return $string
50706f77 284 */
41b94d65 285function getforwardHeader($orig_header) {
50706f77 286 global $editor_size, $default_charset;
287
288 // using own strlen function in order to detect correct string length
289 $display = array( _("Subject") => sq_strlen(_("Subject"),$default_charset),
290 _("From") => sq_strlen(_("From"),$default_charset),
291 _("Date") => sq_strlen(_("Date"),$default_charset),
292 _("To") => sq_strlen(_("To"),$default_charset),
293 _("Cc") => sq_strlen(_("Cc"),$default_charset) );
73ad81bf 294 $maxsize = max($display);
295 $indent = str_pad('',$maxsize+2);
296 foreach($display as $key => $val) {
297 $display[$key] = $key .': '. str_pad('', $maxsize - $val);
298 }
299 $from = decodeHeader($orig_header->getAddr_s('from',"\n$indent"),false,false,true);
300 $from = str_replace('&nbsp;',' ',$from);
301 $to = decodeHeader($orig_header->getAddr_s('to',"\n$indent"),false,false,true);
302 $to = str_replace('&nbsp;',' ',$to);
303 $subject = decodeHeader($orig_header->subject,false,false,true);
304 $subject = str_replace('&nbsp;',' ',$subject);
50706f77 305
306 // using own str_pad function in order to create correct string pad
307 $bodyTop = sq_str_pad(' '._("Original Message").' ',$editor_size -2,'-',STR_PAD_BOTH,$default_charset) .
73ad81bf 308 "\n". $display[_("Subject")] . $subject . "\n" .
309 $display[_("From")] . $from . "\n" .
3aaa3214 310 $display[_("Date")] . getLongDateString( $orig_header->date, $orig_header->date_unparsed ). "\n" .
73ad81bf 311 $display[_("To")] . $to . "\n";
312 if ($orig_header->cc != array() && $orig_header->cc !='') {
313 $cc = decodeHeader($orig_header->getAddr_s('cc',"\n$indent"),false,false,true);
314 $cc = str_replace('&nbsp;',' ',$cc);
315 $bodyTop .= $display[_("Cc")] .$cc . "\n";
316 }
317 $bodyTop .= str_pad('', $editor_size -2 , '-') .
318 "\n\n";
319 return $bodyTop;
41b94d65 320}
09044055 321/* ----------------------------------------------------------------------- */
322
44560457 323/*
1c044820 324 * If the session is expired during a post this restores the compose session
44560457 325 * vars.
326 */
f8eb968d 327$session_expired = false;
5da08ef7 328if (sqsession_is_registered('session_expired_post')) {
953fa718 329 sqgetGlobalVar('session_expired_post', $session_expired_post, SQ_SESSION);
1c044820 330 /*
40934000 331 * extra check for username so we don't display previous post data from
332 * another user during this session.
333 */
c7ebdfcf 334 if (!empty($session_expired_post['username'])
335 && $session_expired_post['username'] == $username) {
1638beb6 336 // these are the vars that we can set from the expired composed session
f8eb968d 337 $compo_var_list = array ('send_to', 'send_to_cc', 'body',
338 'startMessage', 'passed_body', 'use_signature', 'signature',
339 'subject', 'newmail', 'send_to_bcc', 'passed_id', 'mailbox',
340 'from_htmladdr_search', 'identity', 'draft_id', 'delete_draft',
341 'mailprio', 'edit_as_new', 'attachments', 'composesession',
e506b6e5 342 'request_mdn', 'request_dr', 'fwduid');
c6f28eb1 343
344 foreach ($compo_var_list as $var) {
345 if ( isset($session_expired_post[$var]) && !isset($$var) ) {
774d79cc 346 $$var = $session_expired_post[$var];
61e96f7e 347 }
40934000 348 }
c6f28eb1 349
f8eb968d 350 if (!empty($attachments))
177cb345 351 $attachments = unserialize(urldecode($attachments));
f8eb968d 352
0ec1a14b 353 sqsession_register($composesession,'composesession');
f8eb968d 354
40934000 355 if (isset($send)) {
356 unset($send);
357 }
358 $session_expired = true;
359 }
5da08ef7 360 unset($session_expired_post);
0b97a708 361 sqsession_unregister('session_expired_post');
5da08ef7 362 session_write_close();
40934000 363 if (!isset($mailbox)) {
364 $mailbox = '';
365 }
366 if ($compose_new_win == '1') {
367 compose_Header($color, $mailbox);
368 } else {
91c27aee 369 $sHeaderJs = (isset($sHeaderJs)) ? $sHeaderJs : '';
370 if (strpos($action, 'reply') !== false && $reply_focus) {
ca14ebb7 371 $sOnload = 'checkForm(\''.$replyfocus.'\');';
91c27aee 372 } else {
ca14ebb7 373 $sOnload = 'checkForm();';
91c27aee 374 }
ca14ebb7 375 displayPageHeader($color, $mailbox,$sHeaderJs,$sOnload);
40934000 376 }
377 showInputForm($session, false);
378 exit();
44560457 379}
f8eb968d 380
da95c4b6 381if (!isset($composesession)) {
382 $composesession = 0;
a43e4b90 383 sqsession_register(0,'composesession');
7e2ff844 384} else {
385 $composesession = (int)$composesession;
da95c4b6 386}
387
d7f8e6e6 388if (!isset($session) || (isset($newmessage) && $newmessage)) {
0b97a708 389 sqsession_unregister('composesession');
1c044820 390 $session = "$composesession" +1;
91f2085b 391 $composesession = $session;
a43e4b90 392 sqsession_register($composesession,'composesession');
1c044820 393}
b4e7df34 394if (!empty($compose_messages[$session])) {
395 $composeMessage = $compose_messages[$session];
396} else {
73ad81bf 397 $composeMessage = new Message();
398 $rfc822_header = new Rfc822Header();
399 $composeMessage->rfc822_header = $rfc822_header;
400 $composeMessage->reply_rfc822_header = '';
a43e4b90 401}
a43e4b90 402
f8eb968d 403// re-add attachments that were already in this message
404// FIXME: note that technically this is very bad form -
405// should never directly manipulate an object like this
406if (!empty($attachments)) {
177cb345 407 $attachments = unserialize(urldecode($attachments));
f8eb968d 408 if (!empty($attachments) && is_array($attachments))
409 $composeMessage->entities = $attachments;
410}
411
876fdb60 412if (empty($mailbox)) {
00793a25 413 $mailbox = 'INBOX';
414}
415
4dfb9db7 416if ($draft) {
199a9ab8 417
418 // validate security token
419 //
2cefa62a 420 sm_validate_security_token($submitted_token, -1, TRUE);
199a9ab8 421
4dfb9db7 422 /*
423 * Set $default_charset to correspond with the user's selection
424 * of language interface.
425 */
426 set_my_charset();
b7ff469f 427 if (! deliverMessage($composeMessage, true)) {
da95c4b6 428 showInputForm($session);
00793a25 429 exit();
734f4ee6 430 } else {
00793a25 431 $draft_message = _("Draft Email Saved");
432 /* If this is a resumed draft, then delete the original */
433 if(isset($delete_draft)) {
a9805897 434 $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false, $imap_stream_options);
b034bca2 435 sqimap_mailbox_select($imap_stream, $draft_folder);
436 // force bypass_trash=true because message should be saved when deliverMessage() returns true.
91c27aee 437 // in current implementation of sqimap_msgs_list_flag() single message id can
b034bca2 438 // be submitted as string. docs state that it should be array.
439 sqimap_msgs_list_delete($imap_stream, $draft_folder, $delete_draft, true);
440 if ($auto_expunge) {
441 sqimap_mailbox_expunge($imap_stream, $draft_folder, true);
9c3e6cd4 442 }
b034bca2 443 sqimap_logout($imap_stream);
444 }
1638beb6 445
762853f4 446 $oErrorHandler->saveDelayedErrors();
c077ffeb 447 session_write_close();
762853f4 448
b034bca2 449 if ($compose_new_win == '1') {
09047d19 450 if ( !isset($pageheader_sent) || !$pageheader_sent ) {
39cf816f 451 header("Location: $location/compose.php?saved_draft=yes&session=$composesession");
09047d19 452 } else {
c8dc86c9 453//FIXME: DON'T ECHO HTML FROM CORE!
f265009a 454 echo ' <br><br><div style="text-align: center;"><a href="' . $location
09047d19 455 . '/compose.php?saved_sent=yes&amp;session=' . $composesession . '">'
f265009a 456 . _("Return") . '</a></div>';
a6d3eff6 457 }
b034bca2 458 exit();
459 } else {
09047d19 460 if ( !isset($pageheader_sent) || !$pageheader_sent ) {
39cf816f 461 header("Location: $location/right_main.php?mailbox=" . urlencode($draft_folder) .
b034bca2 462 "&startMessage=1&note=".urlencode($draft_message));
09047d19 463 } else {
c8dc86c9 464//FIXME: DON'T ECHO HTML FROM CORE!
f265009a 465 echo ' <br><br><div style="text-align: center;"><a href="' . $location
09047d19 466 . '/right_main.php?mailbox=' . urlencode($draft_folder)
467 . '&amp;startMessage=1&amp;note=' . urlencode($draft_message) .'">'
f265009a 468 . _("Return") . '</a></div>';
a6d3eff6 469 }
b034bca2 470 exit();
00793a25 471 }
472 }
473}
474
4dfb9db7 475if ($send) {
199a9ab8 476
477 // validate security token
478 //
2cefa62a 479 sm_validate_security_token($submitted_token, -1, TRUE);
199a9ab8 480
0b97a708 481 if (isset($_FILES['attachfile']) &&
73ad81bf 482 $_FILES['attachfile']['tmp_name'] &&
483 $_FILES['attachfile']['tmp_name'] != 'none') {
da95c4b6 484 $AttachFailure = saveAttachedFiles($session);
00793a25 485 }
d887e067 486
00793a25 487 if (checkInput(false) && !isset($AttachFailure)) {
73ad81bf 488 if ($mailbox == "All Folders") {
489 /* We entered compose via the search results page */
a42c236f 490 $mailbox = 'INBOX'; /* Send 'em to INBOX, that's safe enough */
73ad81bf 491 }
9a19cc66 492 $urlMailbox = urlencode($mailbox);
3f6b1b6f 493 if (! isset($passed_id)) {
494 $passed_id = 0;
00793a25 495 }
d4c5c50c 496 /**
00793a25 497 * Set $default_charset to correspond with the user's selection
7058a2a9 498 * of language interface.
00793a25 499 */
500 set_my_charset();
d4c5c50c 501 /**
00793a25 502 * This is to change all newlines to \n
7058a2a9 503 * We'll change them to \r\n later (in the sendMessage function)
00793a25 504 */
505 $body = str_replace("\r\n", "\n", $body);
506 $body = str_replace("\r", "\n", $body);
507
d4c5c50c 508 /**
18c9998a 509 * Rewrap $body so that no line is bigger than $editor_size
00793a25 510 */
18c9998a 511 $body = explode("\n", $body);
512 $newBody = '';
513 foreach ($body as $line) {
514 if( $line <> '-- ' ) {
73ad81bf 515 $line = rtrim($line);
18c9998a 516 }
774d79cc 517 if (sq_strlen($line, $default_charset) <= $editor_size + 1) {
18c9998a 518 $newBody .= $line . "\n";
519 } else {
774d79cc 520 sqWordWrap($line, $editor_size, $default_charset);
18c9998a 521 $newBody .= $line . "\n";
522
523 }
524
525 }
526 $body = $newBody;
1c044820 527
a91189d6 528 $Result = deliverMessage($composeMessage);
81de00c0 529
64793f9a 530 if ($Result)
531 $mail_sent = 'yes';
532 else
533 $mail_sent = 'no';
534
1638beb6 535 // NOTE: this hook changed in 1.5.2 from sending $Result and
6e515418 536 // $composeMessage as args #2 and #3 to being in an array
537 // under arg #2
802e7490 538 $temp = array(&$Result, &$composeMessage, &$mail_sent);
539 do_hook('compose_send_after', $temp);
00793a25 540 if (! $Result) {
da95c4b6 541 showInputForm($session);
00793a25 542 exit();
543 }
5c4ff7bf 544
b034bca2 545 /* if it is resumed draft, delete draft message */
00793a25 546 if ( isset($delete_draft)) {
a9805897 547 $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false, $imap_stream_options);
b034bca2 548 sqimap_mailbox_select($imap_stream, $draft_folder);
549 // bypass_trash=true because message should be saved when deliverMessage() returns true.
91c27aee 550 // in current implementation of sqimap_msgs_list_flag() single message id can
b034bca2 551 // be submitted as string. docs state that it should be array.
552 sqimap_msgs_list_delete($imap_stream, $draft_folder, $delete_draft, true);
553 if ($auto_expunge) {
554 sqimap_mailbox_expunge($imap_stream, $draft_folder, true);
555 }
556 sqimap_logout($imap_stream);
00793a25 557 }
81de00c0 558 /*
559 * Store the error array in the session because they will be lost on a redirect
560 */
762853f4 561 $oErrorHandler->saveDelayedErrors();
c077ffeb 562 session_write_close();
762853f4 563
9c3e6cd4 564 if ($compose_new_win == '1') {
09047d19 565 if ( !isset($pageheader_sent) || !$pageheader_sent ) {
39cf816f 566 header("Location: $location/compose.php?mail_sent=$mail_sent");
09047d19 567 } else {
c8dc86c9 568//FIXME: DON'T ECHO HTML FROM CORE!
f265009a 569 echo ' <br><br><div style="text-align: center;"><a href="' . $location
64793f9a 570 . '/compose.php?mail_sent=$mail_sent">'
f265009a 571 . _("Return") . '</a></div>';
09047d19 572 }
573 exit();
574 } else {
575 if ( !isset($pageheader_sent) || !$pageheader_sent ) {
5594db7a 576 global $return_to_message_after_reply;
aa1340eb 577 if (($action === 'reply' || $action === 'reply_all' || $action === 'forward' || $action === 'forward_as_attachment')
578 && $return_to_message_after_reply && $passed_id)
5594db7a 579 header("Location: $location/read_body.php?passed_id=$passed_id&mailbox=$urlMailbox".
580 "&startMessage=$startMessage&mail_sent=$mail_sent");
581 else
582 header("Location: $location/right_main.php?mailbox=$urlMailbox".
583 "&startMessage=$startMessage&mail_sent=$mail_sent");
09047d19 584 } else {
c8dc86c9 585//FIXME: DON'T ECHO HTML FROM CORE!
f265009a 586 echo ' <br><br><div style="text-align: center;"><a href="' . $location
09047d19 587 . "/right_main.php?mailbox=$urlMailbox"
64793f9a 588 . "&amp;startMessage=$startMessage&amp;mail_sent=$mail_sent\">"
f265009a 589 . _("Return") . '</a></div>';
09047d19 590 }
591 exit();
9c3e6cd4 592 }
734f4ee6 593 } else {
9c3e6cd4 594 if ($compose_new_win == '1') {
595 compose_Header($color, $mailbox);
596 }
597 else {
598 displayPageHeader($color, $mailbox);
599 }
00793a25 600 if (isset($AttachFailure)) {
73ad81bf 601 plain_error_message(_("Could not move/copy file. File not attached"),
602 $color);
00793a25 603 }
00793a25 604 checkInput(true);
da95c4b6 605 showInputForm($session);
00793a25 606 /* sqimap_logout($imapConnection); */
607 }
e02775fe 608} elseif (isset($html_addr_search_done)) {
199a9ab8 609
610 // validate security token
611 //
2cefa62a 612 sm_validate_security_token($submitted_token, -1, TRUE);
199a9ab8 613
73ad81bf 614 if ($compose_new_win == '1') {
615 compose_Header($color, $mailbox);
616 }
617 else {
618 displayPageHeader($color, $mailbox);
619 }
00793a25 620
621 if (isset($send_to_search) && is_array($send_to_search)) {
622 foreach ($send_to_search as $k => $v) {
623 if (substr($k, 0, 1) == 'T') {
624 if ($send_to) {
625 $send_to .= ', ';
626 }
627 $send_to .= $v;
628 }
629 elseif (substr($k, 0, 1) == 'C') {
630 if ($send_to_cc) {
631 $send_to_cc .= ', ';
632 }
633 $send_to_cc .= $v;
634 }
635 elseif (substr($k, 0, 1) == 'B') {
636 if ($send_to_bcc) {
637 $send_to_bcc .= ', ';
638 }
639 $send_to_bcc .= $v;
640 }
641 }
642 }
da95c4b6 643 showInputForm($session);
167c6996 644} elseif (isset($html_addr_search) && !isset($html_addr_search_cancel)) {
0b97a708 645 if (isset($_FILES['attachfile']) &&
73ad81bf 646 $_FILES['attachfile']['tmp_name'] &&
647 $_FILES['attachfile']['tmp_name'] != 'none') {
0b97a708 648 if(saveAttachedFiles($session)) {
cb34dbd0 649 plain_error_message(_("Could not move/copy file. File not attached"));
00793a25 650 }
651 }
652 /*
653 * I am using an include so as to elminiate an extra unnecessary
654 * click. If you can think of a better way, please implement it.
655 */
656 include_once('./addrbook_search_html.php');
e02775fe 657} elseif (isset($attach)) {
199a9ab8 658
659 // validate security token
660 //
2cefa62a 661 sm_validate_security_token($submitted_token, -1, TRUE);
199a9ab8 662
73ad81bf 663 if ($compose_new_win == '1') {
664 compose_Header($color, $mailbox);
665 } else {
666 displayPageHeader($color, $mailbox);
667 }
5a3e52f3 668 if (saveAttachedFiles($session)) {
cb34dbd0 669 plain_error_message(_("Could not move/copy file. File not attached"));
5a3e52f3 670 }
da95c4b6 671 showInputForm($session);
01265fba 672}
673elseif (isset($sigappend)) {
199a9ab8 674
675 // validate security token
676 //
2cefa62a 677 sm_validate_security_token($submitted_token, -1, TRUE);
199a9ab8 678
1e2a6ff6 679 $signature = $idents[$identity]['signature'];
680
01265fba 681 $body .= "\n\n".($prefix_sig==true? "-- \n":'').$signature;
682 if ($compose_new_win == '1') {
73ad81bf 683 compose_Header($color, $mailbox);
01265fba 684 } else {
685 displayPageHeader($color, $mailbox);
686 }
da95c4b6 687 showInputForm($session);
e02775fe 688} elseif (isset($do_delete)) {
199a9ab8 689
690 // validate security token
691 //
2cefa62a 692 sm_validate_security_token($submitted_token, -1, TRUE);
199a9ab8 693
73ad81bf 694 if ($compose_new_win == '1') {
695 compose_Header($color, $mailbox);
696 } else {
697 displayPageHeader($color, $mailbox);
698 }
00793a25 699
00793a25 700 if (isset($delete) && is_array($delete)) {
701 foreach($delete as $index) {
a58b05b4 702 if (!empty($composeMessage->entities) && isset($composeMessage->entities[$index])) {
c077ffeb 703 $composeMessage->entities[$index]->purgeAttachments();
16449d84 704 // 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
705 //$composeMessage->entities[$index] = NULL;
a58b05b4 706 unset ($composeMessage->entities[$index]);
707 }
a91189d6 708 }
709 $new_entities = array();
710 foreach ($composeMessage->entities as $entity) {
711 $new_entities[] = $entity;
00793a25 712 }
a91189d6 713 $composeMessage->entities = $new_entities;
00793a25 714 }
da95c4b6 715 showInputForm($session);
734f4ee6 716} else {
00793a25 717 /*
718 * This handles the default case as well as the error case
1c044820 719 * (they had the same code) --> if (isset($smtpErrors))
00793a25 720 */
44560457 721
722 if ($compose_new_win == '1') {
73ad81bf 723 compose_Header($color, $mailbox);
44560457 724 } else {
73ad81bf 725 displayPageHeader($color, $mailbox);
44560457 726 }
00793a25 727
728 $newmail = true;
729
a61878d0 730 if (!isset($passed_ent_id)) {
731 $passed_ent_id = '';
732 }
733 if (!isset($passed_id)) {
1c044820 734 $passed_id = '';
a61878d0 735 }
736 if (!isset($mailbox)) {
737 $mailbox = '';
1c044820 738 }
a61878d0 739 if (!isset($action)) {
740 $action = '';
741 }
1c044820 742
44560457 743 $values = newMail($mailbox,$passed_id,$passed_ent_id, $action, $session);
b9928adc 744
f2ad47f1 745 // forward as attachment - subject is in the message in session
746 //
747 if ($action == 'forward_as_attachment' && empty($values['subject']))
748 $subject = $composeMessage->rfc822_header->subject;
749
b9928adc 750 /* in case the origin is not read_body.php */
751 if (isset($send_to)) {
73ad81bf 752 $values['send_to'] = $send_to;
b9928adc 753 }
754 if (isset($send_to_cc)) {
73ad81bf 755 $values['send_to_cc'] = $send_to_cc;
b9928adc 756 }
757 if (isset($send_to_bcc)) {
73ad81bf 758 $values['send_to_bcc'] = $send_to_bcc;
b9928adc 759 }
2a2f2185 760 if (isset($subject)) {
73ad81bf 761 $values['subject'] = $subject;
2a2f2185 762 }
79cecc00 763 if (isset($mailprio)) {
764 $values['mailprio'] = $mailprio;
765 }
766 if (isset($orig_identity)) {
767 $values['identity'] = $orig_identity;
768 }
41b94d65 769 showInputForm($session, $values);
00793a25 770}
771
772exit();
773
00793a25 774/**************** Only function definitions go below *************/
775
92c6f757 776function getforwardSubject($subject)
777{
778 if ((substr(strtolower($subject), 0, 4) != 'fwd:') &&
73ad81bf 779 (substr(strtolower($subject), 0, 5) != '[fwd:') &&
780 (substr(strtolower($subject), 0, 6) != '[ fwd:')) {
92c6f757 781 $subject = '[Fwd: ' . $subject . ']';
782 }
783 return $subject;
784}
00793a25 785
48985d59 786/* This function is used when not sending or adding attachments */
44560457 787function newMail ($mailbox='', $passed_id='', $passed_ent_id='', $action='', $session='') {
1e2a6ff6 788 global $editor_size, $default_use_priority, $body, $idents,
ce68b76b 789 $use_signature, $data_dir, $username,
a9805897 790 $key, $imapServerAddress, $imapPort, $imap_stream_options,
74f66d27 791 $composeMessage, $body_quote, $request_mdn, $request_dr,
856e58ef 792 $mdn_user_support, $languages, $squirrelmail_language,
ace75dcb 793 $default_charset, $do_not_reply_to_self;
e7f1a81d 794
d4f20027 795 /*
796 * Set $default_charset to correspond with the user's selection
797 * of language interface. $default_charset global is not correct,
798 * if message is composed in new window.
799 */
800 set_my_charset();
801
91f2085b 802 $send_to = $send_to_cc = $send_to_bcc = $subject = $identity = '';
bdb92db3 803 $mailprio = 3;
44560457 804
41b94d65 805 if ($passed_id) {
906f7e9f 806 $imapConnection = sqimap_login($username, false, $imapServerAddress,
a9805897 807 $imapPort, 0, $imap_stream_options);
a61878d0 808
48985d59 809 sqimap_mailbox_select($imapConnection, $mailbox);
41b94d65 810 $message = sqimap_get_message($imapConnection, $passed_id, $mailbox);
1c044820 811
a61878d0 812 $body = '';
813 if ($passed_ent_id) {
814 /* redefine the messsage in case of message/rfc822 */
815 $message = $message->getEntity($passed_ent_id);
816 /* message is an entity which contains the envelope and type0=message
73ad81bf 817 * and type1=rfc822. The actual entities are childs from
818 * $message->entities[0]. That's where the encoding and is located
819 */
a61878d0 820
821 $entities = $message->entities[0]->findDisplayEntity
73ad81bf 822 (array(), $alt_order = array('text/plain'));
a61878d0 823 if (!count($entities)) {
824 $entities = $message->entities[0]->findDisplayEntity
9c462f8b 825 (array(), $alt_order = array('text/plain','text/html'));
a61878d0 826 }
827 $orig_header = $message->rfc822_header; /* here is the envelope located */
828 /* redefine the message for picking up the attachments */
829 $message = $message->entities[0];
830
831 } else {
832 $entities = $message->findDisplayEntity (array(), $alt_order = array('text/plain'));
833 if (!count($entities)) {
9c462f8b 834 $entities = $message->findDisplayEntity (array(), $alt_order = array('text/plain','text/html'));
a61878d0 835 }
836 $orig_header = $message->rfc822_header;
837 }
1c044820 838
a61878d0 839 $type0 = $message->type0;
840 $type1 = $message->type1;
41b94d65 841 foreach ($entities as $ent) {
b455e47b 842 $msg = $message->getEntity($ent);
843 $type0 = $msg->type0;
844 $type1 = $msg->type1;
a61878d0 845 $unencoded_bodypart = mime_fetch_body($imapConnection, $passed_id, $ent);
846 $body_part_entity = $message->getEntity($ent);
1638beb6 847 $bodypart = decodeBody($unencoded_bodypart,
73ad81bf 848 $body_part_entity->header->encoding);
a61878d0 849 if ($type1 == 'html') {
5b755d9f 850 $bodypart = str_replace("\n", ' ', $bodypart);
bb977394 851 $bodypart = preg_replace(array('/<\/?p>/i','/<div><\/div>/i','/<br\s*(\/)*>/i','/<\/?div>/i'), "\n", $bodypart);
5b755d9f 852 $bodypart = str_replace(array('&nbsp;','&gt;','&lt;'),array(' ','>','<'),$bodypart);
a61878d0 853 $bodypart = strip_tags($bodypart);
854 }
e842b215 855 if (isset($languages[$squirrelmail_language]['XTRA_CODE']) &&
73ad81bf 856 function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode')) {
e842b215 857 if (mb_detect_encoding($bodypart) != 'ASCII') {
f4bb5d22 858 $bodypart = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode', $bodypart);
e842b215 859 }
860 }
eceefdfe 861
bfa54da7 862 // charset encoding in compose form stuff
73ad81bf 863 if (isset($body_part_entity->header->parameters['charset'])) {
864 $actual = $body_part_entity->header->parameters['charset'];
865 } else {
866 $actual = 'us-ascii';
867 }
beca818e 868
73ad81bf 869 if ( $actual && is_conversion_safe($actual) && $actual != $default_charset){
870 $bodypart = charset_convert($actual,$bodypart,$default_charset,false);
871 }
bfa54da7 872 // end of charset encoding in compose
eceefdfe 873
a61878d0 874 $body .= $bodypart;
875 }
876 if ($default_use_priority) {
877 $mailprio = substr($orig_header->priority,0,1);
878 if (!$mailprio) {
879 $mailprio = 3;
880 }
881 } else {
882 $mailprio = '';
883 }
bdb92db3 884
a45887d7 885 $from_o = $orig_header->from;
fe868193 886 if (is_array($from_o)) {
887 if (isset($from_o[0])) {
888 $from_o = $from_o[0];
889 }
890 }
bdb92db3 891 if (is_object($from_o)) {
892 $orig_from = $from_o->getAddress();
893 } else {
894 $orig_from = '';
a61878d0 895 }
1e2a6ff6 896
a91189d6 897 $identities = array();
1e2a6ff6 898 if (count($idents) > 1) {
899 foreach($idents as $nr=>$data) {
900 $enc_from_name = '"'.$data['full_name'].'" <'. $data['email_address'].'>';
a91189d6 901 $identities[] = $enc_from_name;
902 }
1e2a6ff6 903
a91189d6 904 $identity_match = $orig_header->findAddress($identities);
ea721316 905 if ($identity_match !== FALSE) {
a91189d6 906 $identity = $identity_match;
a61878d0 907 }
bdb92db3 908 }
a61878d0 909
910 switch ($action) {
73ad81bf 911 case ('draft'):
912 $use_signature = FALSE;
913 $composeMessage->rfc822_header = $orig_header;
914 $send_to = decodeHeader($orig_header->getAddr_s('to'),false,false,true);
915 $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'),false,false,true);
916 $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'),false,false,true);
917 $send_from = $orig_header->getAddr_s('from');
918 $send_from_parts = new AddressStructure();
919 $send_from_parts = $orig_header->parseAddress($send_from);
920 $send_from_add = $send_from_parts->mailbox . '@' . $send_from_parts->host;
40e07136 921 $identity = find_identity(array($send_from_add));
73ad81bf 922 $subject = decodeHeader($orig_header->subject,false,false,true);
1638beb6 923
762853f4 924 // Remember the receipt settings
925 $request_mdn = $mdn_user_support && !empty($orig_header->dnt) ? '1' : '0';
926 $request_dr = $mdn_user_support && !empty($orig_header->drnt) ? '1' : '0';
1638beb6 927
73ad81bf 928 /* remember the references and in-reply-to headers in case of an reply */
657fe1bd 929//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?
73ad81bf 930 $composeMessage->rfc822_header->more_headers['References'] = $orig_header->references;
931 $composeMessage->rfc822_header->more_headers['In-Reply-To'] = $orig_header->in_reply_to;
932 // rewrap the body to clean up quotations and line lengths
933 sqBodyWrap($body, $editor_size);
934 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
aff28a6d 935 if (!empty($orig_header->x_sm_flag_reply))
936 $composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply'] = $orig_header->x_sm_flag_reply;
041d360b 937//TODO: completely unclear if should be using $compose_session instead of $session below
938 $compose_messages[$session] = $composeMessage;
939 sqsession_register($compose_messages,'compose_messages');
73ad81bf 940 break;
941 case ('edit_as_new'):
942 $send_to = decodeHeader($orig_header->getAddr_s('to'),false,false,true);
943 $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'),false,false,true);
944 $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'),false,false,true);
945 $subject = decodeHeader($orig_header->subject,false,false,true);
946 $mailprio = $orig_header->priority;
947 $orig_from = '';
948 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
949 // rewrap the body to clean up quotations and line lengths
950 sqBodyWrap($body, $editor_size);
951 break;
952 case ('forward'):
953 $send_to = '';
954 $subject = getforwardSubject(decodeHeader($orig_header->subject,false,false,true));
955 $body = getforwardHeader($orig_header) . $body;
956 // the logic for calling sqUnWordWrap here would be to allow the browser to wrap the lines
957 // forwarded message text should be as undisturbed as possible, so commenting out this call
958 // sqUnWordWrap($body);
959 $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
91c27aee 960
73ad81bf 961 //add a blank line after the forward headers
962 $body = "\n" . $body;
963 break;
964 case ('forward_as_attachment'):
965 $subject = getforwardSubject(decodeHeader($orig_header->subject,false,false,true));
966 $composeMessage = getMessage_RFC822_Attachment($message, $composeMessage, $passed_id, $passed_ent_id, $imapConnection);
f2ad47f1 967 $subject = decodeHeader($orig_header->subject,false,false,true);
968 $subject = str_replace('"', "'", $subject);
969 $subject = trim($subject);
970 if (substr(strtolower($subject), 0, 4) != 'fwd:') {
971 $subject = 'Fwd: ' . $subject;
972 }
73ad81bf 973 $body = '';
974 break;
975 case ('reply_all'):
976 if(isset($orig_header->mail_followup_to) && $orig_header->mail_followup_to) {
977 $send_to = $orig_header->getAddr_s('mail_followup_to');
b268e66b 978 } else {
73ad81bf 979 $send_to_cc = replyAllString($orig_header);
980 $send_to_cc = decodeHeader($send_to_cc,false,false,true);
a9b9e5d3 981 $send_to_cc = str_replace('""', '"', $send_to_cc);
b268e66b 982 }
73ad81bf 983 case ('reply'):
984 // skip this if send_to was already set right above here
985 if(!$send_to) {
986 $send_to = $orig_header->reply_to;
987 if (is_array($send_to) && count($send_to)) {
a9b9e5d3 988 $send_to = $orig_header->getAddr_s('reply_to', ',', FALSE, TRUE);
73ad81bf 989 } else if (is_object($send_to)) { /* unneccesarry, just for failsafe purpose */
a9b9e5d3 990 $send_to = $orig_header->getAddr_s('reply_to', ',', FALSE, TRUE);
73ad81bf 991 } else {
a9b9e5d3 992 $send_to = $orig_header->getAddr_s('from', ',', FALSE, TRUE);
73ad81bf 993 }
dd4a44cd 994 }
73ad81bf 995 $send_to = decodeHeader($send_to,false,false,true);
a9b9e5d3 996 $send_to = str_replace('""', '"', $send_to);
ace75dcb 997
998
999 // If user doesn't want replies to her own messages
1000 // going back to herself (instead send again to the
1001 // original recipient of the message being replied to),
1002 // then iterate through identities, checking if the TO
1003 // field is one of them (if the reply is to ourselves)
1004 //
1005 // Note we don't bother if the original message doesn't
1006 // have anything in the TO field itself (because that's
1007 // what we use if we change the recipient to be that of
1008 // the previous message)
1009 //
1010 if ($do_not_reply_to_self && !empty($orig_header->to)) {
1011
1012 $orig_to = '';
1013
1014 foreach($idents as $id) {
1015
1016 if (!empty($id['email_address'])
1017 && strpos($send_to, $id['email_address']) !== FALSE) {
1018
1019 // if this is a reply-all, the original recipient
1020 // is already in the CC field, so we can just blank
1021 // the recipient (TO field) (as long as the CC field
a9b6e52d 1022 // isn't empty that is)... but then move the CC into
1023 // the TO, so TO isn't empty
ace75dcb 1024 //
6fac6196 1025 if ($action == 'reply_all' && !empty($send_to_cc)) {
a9b6e52d 1026 $orig_to = $send_to_cc;
1027 $send_to_cc = '';
ace75dcb 1028 break;
1029 }
1030
1031 $orig_to = $orig_header->to;
1032 if (is_array($orig_to) && count($orig_to)) {
1033 $orig_to = $orig_header->getAddr_s('to', ',', FALSE, TRUE);
1034 } else if (is_object($orig_to)) { /* unneccesarry, just for failsafe purpose */
1035 $orig_to = $orig_header->getAddr_s('to', ',', FALSE, TRUE);
1036 } else {
1037 $orig_to = '';
1038 }
1039 $orig_to = decodeHeader($orig_to,false,false,true);
1040 $orig_to = str_replace('""', '"', $orig_to);
1041
1042 break;
1043 }
1044 }
1045
1046 // if the reply was addressed back to ourselves,
5df2efa2 1047 // we will send it to the TO of the previous message
ace75dcb 1048 //
1049 if (!empty($orig_to)) {
1050
5df2efa2 1051 $send_to = $orig_to;
5777c73d 1052
1053 // in this case, we also want to reset the FROM
1054 // identity as well (it should match the original
1055 // *FROM* header instead of TO or CC)
1056 //
1057 if (count($idents) > 1) {
1058 $identity = '';
1059 foreach($idents as $i => $id) {
1060 if (!empty($id['email_address'])
1061 && strpos($orig_from, $id['email_address']) !== FALSE) {
1062 $identity = $i;
1063 break;
1064 }
1065 }
1066 }
1067
ace75dcb 1068 }
1069
1070 }
1071
1072
73ad81bf 1073 $subject = decodeHeader($orig_header->subject,false,false,true);
1074 $subject = str_replace('"', "'", $subject);
1075 $subject = trim($subject);
1076 if (substr(strtolower($subject), 0, 3) != 're:') {
1077 $subject = 'Re: ' . $subject;
1078 }
1079 /* this corrects some wrapping/quoting problems on replies */
1080 $rewrap_body = explode("\n", $body);
3aaa3214 1081 $from = (is_array($orig_header->from) && !empty($orig_header->from)) ? $orig_header->from[0] : $orig_header->from;
73ad81bf 1082 $body = '';
1083 $strip_sigs = getPref($data_dir, $username, 'strip_sigs');
1084 foreach ($rewrap_body as $line) {
3673a2de 1085 if ($strip_sigs && rtrim($line, "\r\n") == '-- ') {
73ad81bf 1086 break;
1087 }
1088 if (preg_match("/^(>+)/", $line, $matches)) {
1089 $gt = $matches[1];
1090 $body .= $body_quote . str_replace("\n", "\n$body_quote$gt ", rtrim($line)) ."\n";
1091 } else {
1092 $body .= $body_quote . (!empty($body_quote) ? ' ' : '') . str_replace("\n", "\n$body_quote" . (!empty($body_quote) ? ' ' : ''), rtrim($line)) . "\n";
1093 }
a61878d0 1094 }
c9d61baf 1095
73ad81bf 1096 //rewrap the body to clean up quotations and line lengths
1097 $body = sqBodyWrap ($body, $editor_size);
c9d61baf 1098
73ad81bf 1099 $body = getReplyCitation($from , $orig_header->date) . $body;
1100 $composeMessage->reply_rfc822_header = $orig_header;
12a0ed01 1101
73ad81bf 1102 break;
1103 default:
1104 break;
41b94d65 1105 }
b4e7df34 1106//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?
5da08ef7 1107 session_write_close();
a61878d0 1108 sqimap_logout($imapConnection);
41b94d65 1109 }
a61878d0 1110 $ret = array( 'send_to' => $send_to,
73ad81bf 1111 'send_to_cc' => $send_to_cc,
1112 'send_to_bcc' => $send_to_bcc,
1113 'subject' => $subject,
1114 'mailprio' => $mailprio,
1115 'body' => $body,
1116 'identity' => $identity );
a61878d0 1117
41b94d65 1118 return ($ret);
48985d59 1119} /* function newMail() */
1120
50706f77 1121/**
1122 * downloads attachments from original message, stores them in attachment directory and adds
1123 * them to composed message.
1124 * @param object $message
1125 * @param object $composeMessage
1126 * @param integer $passed_id
1127 * @param mixed $entities
1128 * @param mixed $imapConnection
91c27aee 1129 * @return object
50706f77 1130 */
a43e4b90 1131function getAttachments($message, &$composeMessage, $passed_id, $entities, $imapConnection) {
1f270d3c 1132 global $squirrelmail_language, $languages, $username, $attachment_dir;
628bce99 1133
1c044820 1134 if (!count($message->entities) ||
73ad81bf 1135 ($message->type0 == 'message' && $message->type1 == 'rfc822')) {
41b94d65 1136 if ( !in_array($message->entity_id, $entities) && $message->entity_id) {
73ad81bf 1137 switch ($message->type0) {
1138 case 'message':
1139 if ($message->type1 == 'rfc822') {
1140 $filename = $message->rfc822_header->subject;
1141 if ($filename == "") {
1142 $filename = "untitled-".$message->entity_id;
1143 }
6f71f6e6 1144 $filename .= '.eml';
73ad81bf 1145 } else {
1146 $filename = $message->getFilename();
181538ac 1147 }
73ad81bf 1148 break;
1149 default:
1150 if (!$message->mime_header) { /* temporary hack */
1151 $message->mime_header = $message->header;
1152 }
1153 $filename = $message->getFilename();
1154 break;
1155 }
117aa0c5 1156//FIXME: added three args to the following, so as to set the last one to TRUE, to mimick a fix in 1.4.21 (#2994865), but didn't test this (note that in 1.4.21, the 2nd and 3rd args are FALSE, but here in this code, they weren't being specified (thus defaulting to TRUE), so I don't know if that means this code is outdated and should have been changed to FALSE, FALSE or if this code is completely different and the addition of the TRUE for arg #4 is wrong
1157 $filename = str_replace('&#32;', ' ', decodeHeader($filename, true, true, true));
73ad81bf 1158 if (isset($languages[$squirrelmail_language]['XTRA_CODE']) &&
1159 function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode')) {
f4bb5d22 1160 $filename = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode', $filename);
73ad81bf 1161 }
1f270d3c 1162
1163 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
628bce99 1164 $localfilename = sq_get_attach_tempfile();
1165 $message->att_local_name = $localfilename;
73ad81bf 1166
1167 $composeMessage->initAttachment($message->type0.'/'.$message->type1,$filename,
628bce99 1168 $localfilename);
73ad81bf 1169
1170 /* Write Attachment to file */
1f270d3c 1171 $fp = fopen ($hashed_attachment_dir . '/' . $localfilename, 'wb');
91c27aee 1172 mime_print_body_lines ($imapConnection, $passed_id, $message->entity_id, $message->header->encoding, $fp);
73ad81bf 1173 fclose ($fp);
48985d59 1174 }
734f4ee6 1175 } else {
a43e4b90 1176 for ($i=0, $entCount=count($message->entities); $i<$entCount;$i++) {
1177 $composeMessage=getAttachments($message->entities[$i], $composeMessage, $passed_id, $entities, $imapConnection);
48985d59 1178 }
1179 }
a43e4b90 1180 return $composeMessage;
48985d59 1181}
1182
1c044820 1183function getMessage_RFC822_Attachment($message, $composeMessage, $passed_id,
73ad81bf 1184 $passed_ent_id='', $imapConnection) {
756406df 1185 if (!$passed_ent_id) {
1c044820 1186 $body_a = sqimap_run_command($imapConnection,
73ad81bf 1187 'FETCH '.$passed_id.' RFC822',
1188 TRUE, $response, $readmessage,
1189 TRUE);
756406df 1190 } else {
1c044820 1191 $body_a = sqimap_run_command($imapConnection,
73ad81bf 1192 'FETCH '.$passed_id.' BODY['.$passed_ent_id.']',
1193 TRUE, $response, $readmessage, TRUE);
a61878d0 1194 $message = $message->parent;
756406df 1195 }
d0519c03 1196 if ($response == 'OK') {
a61878d0 1197 $subject = encodeHeader($message->rfc822_header->subject);
1198 array_shift($body_a);
1c044820 1199 array_pop($body_a);
a61878d0 1200 $body = implode('', $body_a) . "\r\n";
1c044820 1201
1f270d3c 1202 global $username, $attachment_dir;
1203 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
628bce99 1204 $localfilename = sq_get_attach_tempfile();
1f270d3c 1205 $fp = fopen($hashed_attachment_dir . '/' . $localfilename, 'wb');
a61878d0 1206 fwrite ($fp, $body);
1207 fclose($fp);
6f71f6e6 1208 $composeMessage->initAttachment('message/rfc822',$subject.'.eml',
628bce99 1209 $localfilename);
a43e4b90 1210 }
1211 return $composeMessage;
a6ec592e 1212}
1213
41b94d65 1214function showInputForm ($session, $values=false) {
856e58ef 1215 global $send_to, $send_to_cc, $send_to_bcc,
f8eb968d 1216 $body, $startMessage, $action, $attachments,
b2b614bb 1217 $use_signature, $signature, $prefix_sig, $session_expired,
8d8da447 1218 $editor_size, $editor_height, $subject, $newmail,
e506b6e5 1219 $use_javascript_addr_book, $passed_id, $mailbox, $fwduid,
73ad81bf 1220 $from_htmladdr_search, $location_of_buttons, $attachment_dir,
ce68b76b 1221 $username, $data_dir, $identity, $idents, $delete_draft,
1222 $mailprio, $compose_new_win, $saved_draft, $mail_sent, $sig_first,
b4e7df34 1223 $composeMessage, $composesession, $default_charset,
762853f4 1224 $compose_onsubmit, $oTemplate, $oErrorHandler;
a43e4b90 1225
87745b9c 1226 if (checkForJavascript()) {
1227 $onfocus = ' onfocus="alreadyFocused=true;"';
1228 $onfocus_array = array('onfocus' => 'alreadyFocused=true;');
1229 }
1230 else {
1231 $onfocus = '';
1232 $onfocus_array = array();
1233 }
1234
41b94d65 1235 if ($values) {
73ad81bf 1236 $send_to = $values['send_to'];
1237 $send_to_cc = $values['send_to_cc'];
1238 $send_to_bcc = $values['send_to_bcc'];
1239 $subject = $values['subject'];
1240 $mailprio = $values['mailprio'];
1241 $body = $values['body'];
1242 $identity = (int) $values['identity'];
676bb189 1243 } else {
73ad81bf 1244 $send_to = decodeHeader($send_to, true, false);
1245 $send_to_cc = decodeHeader($send_to_cc, true, false);
1246 $send_to_bcc = decodeHeader($send_to_bcc, true, false);
41b94d65 1247 }
1c044820 1248
48985d59 1249 if ($use_javascript_addr_book) {
c8dc86c9 1250//FIXME: NO HTML IN CORE!
2c92ea9d 1251 echo "\n". '<script type="text/javascript">'."\n<!--\n" .
73ad81bf 1252 'function open_abook() { ' . "\n" .
1253 ' var nwin = window.open("addrbook_popup.php","abookpopup",' .
1254 '"width=670,height=300,resizable=yes,scrollbars=yes");' . "\n" .
1255 ' if((!nwin.opener) && (document.windows != null))' . "\n" .
1256 ' nwin.opener = document.windows;' . "\n" .
1257 "}\n" .
1258 "// -->\n</script>\n\n";
48985d59 1259 }
1260
c8dc86c9 1261//FIXME: NO HTML IN CORE!
4a1788b3 1262 echo "\n" . '<form name="compose" action="compose.php" method="post" ' .
73ad81bf 1263 'enctype="multipart/form-data"';
a34b07a5 1264
1265 $compose_onsubmit = array();
6e515418 1266 global $null;
1267 do_hook('compose_form', $null);
1c044820 1268
a34b07a5 1269 // Plugins that use compose_form hook can add an array entry
1270 // to the globally scoped $compose_onsubmit; we add them up
5c4ff7bf 1271 // here and format the form tag's full onsubmit handler.
1272 // Each plugin should use "return false" if they need to
a34b07a5 1273 // stop form submission but otherwise should NOT use "return
1274 // true" to give other plugins the chance to do what they need
1275 // to do; SquirrelMail itself will add the final "return true".
1276 // Onsubmit text is enclosed inside of double quotes, so plugins
1277 // need to quote accordingly.
395c3216 1278 //
1279 // Also, plugin authors should try to retain compatibility with
1280 // the Compose Extras plugin by resetting its compose submit
1281 // counter when preventing form submit. Use this code:
1282 // if (your-code-here) { submit_count = 0; return false; }
1283 //
a34b07a5 1284 if (checkForJavascript()) {
5c4ff7bf 1285 if (empty($compose_onsubmit))
a34b07a5 1286 $compose_onsubmit = array();
5c4ff7bf 1287 else if (!is_array($compose_onsubmit))
a34b07a5 1288 $compose_onsubmit = array($compose_onsubmit);
1289
82dcbb1e 1290 $onsubmit_text = '';
a34b07a5 1291 foreach ($compose_onsubmit as $text) {
1292 $text = trim($text);
82dcbb1e 1293 if (!empty($text)) {
1294 if (substr($text, -1) != ';' && substr($text, -1) != '}')
1295 $text .= '; ';
1296 $onsubmit_text .= $text;
1297 }
a34b07a5 1298 }
1299
82dcbb1e 1300 if (!empty($onsubmit_text))
c8dc86c9 1301//FIXME: DON'T ECHO HTML FROM CORE!
82dcbb1e 1302 echo ' onsubmit="' . $onsubmit_text . ' return true;"';
a34b07a5 1303 }
5c4ff7bf 1304
a34b07a5 1305
c8dc86c9 1306//FIXME: NO HTML IN CORE!
48985d59 1307 echo ">\n";
1308
c8dc86c9 1309//FIXME: DON'T ECHO HTML FROM CORE!
199a9ab8 1310 echo addHidden('smtoken', sm_generate_security_token());
1311
1312//FIXME: DON'T ECHO HTML FROM CORE!
df96b37a 1313 echo addHidden('startMessage', $startMessage);
4a1788b3 1314
41b94d65 1315 if ($action == 'draft') {
c8dc86c9 1316//FIXME: DON'T ECHO HTML FROM CORE!
df96b37a 1317 echo addHidden('delete_draft', $passed_id);
48985d59 1318 }
1319 if (isset($delete_draft)) {
c8dc86c9 1320//FIXME: DON'T ECHO HTML FROM CORE!
df96b37a 1321 echo addHidden('delete_draft', $delete_draft);
48985d59 1322 }
da95c4b6 1323 if (isset($session)) {
c8dc86c9 1324//FIXME: DON'T ECHO HTML FROM CORE!
df96b37a 1325 echo addHidden('session', $session);
da95c4b6 1326 }
1c044820 1327
08bad2b1 1328 if (isset($passed_id)) {
c8dc86c9 1329//FIXME: DON'T ECHO HTML FROM CORE!
df96b37a 1330 echo addHidden('passed_id', $passed_id);
08bad2b1 1331 }
44560457 1332
e506b6e5 1333 if (isset($fwduid)) {
1334//FIXME: DON'T ECHO HTML FROM CORE!
1335 echo addHidden('fwduid', $fwduid);
1336 }
1337
9c3e6cd4 1338 if ($saved_draft == 'yes') {
774d79cc 1339 $oTemplate->assign('note', _("Your draft has been saved."));
762853f4 1340 $oTemplate->display('note.tpl');
9c3e6cd4 1341 }
1342 if ($mail_sent == 'yes') {
774d79cc 1343 $oTemplate->assign('note', _("Your mail has been sent."));
762853f4 1344 $oTemplate->display('note.tpl');
9c3e6cd4 1345 }
9c3e6cd4 1346 if ($compose_new_win == '1') {
762853f4 1347 $oTemplate->display('compose_newwin_close.tpl');
9c3e6cd4 1348 }
1638beb6 1349
78a35fcd 1350 if ($location_of_buttons == 'top') {
c8dc86c9 1351//FIXME: DON'T ECHO HTML FROM CORE!
78a35fcd 1352 showComposeButtonRow();
1353 }
48985d59 1354
762853f4 1355 $identities = array();
1e2a6ff6 1356 if (count($idents) > 1) {
762853f4 1357 reset($idents);
73ad81bf 1358 foreach($idents as $id => $data) {
762853f4 1359 $identities[$id] = $data['full_name'].' &lt;'.$data['email_address'].'&gt;';
73ad81bf 1360 }
762853f4 1361 }
1638beb6 1362
762853f4 1363 $oTemplate->assign('identities', $identities);
1364 $oTemplate->assign('identity_def', $identity);
1365 $oTemplate->assign('input_onfocus', 'onfocus="'.join(' ', $onfocus_array).'"');
1638beb6 1366
3047e291 1367 $oTemplate->assign('to', sm_encode_html_special_chars($send_to));
1368 $oTemplate->assign('cc', sm_encode_html_special_chars($send_to_cc));
1369 $oTemplate->assign('bcc', sm_encode_html_special_chars($send_to_bcc));
1370 $oTemplate->assign('subject', sm_encode_html_special_chars($subject));
1638beb6 1371
8949acd6 1372 // access keys...
1373 //
1374 global $accesskey_compose_to, $accesskey_compose_cc,
5f20677e 1375 $accesskey_compose_identity, $accesskey_compose_bcc,
1376 $accesskey_compose_subject;
1377 $oTemplate->assign('accesskey_compose_identity', $accesskey_compose_identity);
8949acd6 1378 $oTemplate->assign('accesskey_compose_to', $accesskey_compose_to);
1379 $oTemplate->assign('accesskey_compose_cc', $accesskey_compose_cc);
1380 $oTemplate->assign('accesskey_compose_bcc', $accesskey_compose_bcc);
1381 $oTemplate->assign('accesskey_compose_subject', $accesskey_compose_subject);
1382
762853f4 1383 $oTemplate->display('compose_header.tpl');
48985d59 1384
78a35fcd 1385 if ($location_of_buttons == 'between') {
c8dc86c9 1386//FIXME: DON'T ECHO HTML FROM CORE!
78a35fcd 1387 showComposeButtonRow();
1388 }
4dfb9db7 1389
762853f4 1390 $body_str = '';
48985d59 1391 if ($use_signature == true && $newmail == true && !isset($from_htmladdr_search)) {
1e2a6ff6 1392 $signature = $idents[$identity]['signature'];
d3c13a51 1393
3b17e952 1394 if ($sig_first == '1') {
50706f77 1395 /*
1396 * FIXME: test is specific to ja_JP translation implementation.
1397 * This test might apply incorrect conversion to other translations, but
91c27aee 1398 * use of 7bit iso-2022-jp charset in other translations might have other
50706f77 1399 * issues too.
1400 */
ab4700c3 1401 if ($default_charset == 'iso-2022-jp') {
762853f4 1402 $body_str = "\n\n".($prefix_sig==true? "-- \n":'').mb_convert_encoding($signature, 'EUC-JP');
83be314a 1403 } else {
762853f4 1404 $body_str = "\n\n".($prefix_sig==true? "-- \n":'').decodeHeader($signature,false,false);
83be314a 1405 }
3047e291 1406 $body_str .= "\n\n".sm_encode_html_special_chars(decodeHeader($body,false,false));
762853f4 1407 } else {
3047e291 1408 $body_str = "\n\n".sm_encode_html_special_chars(decodeHeader($body,false,false));
50706f77 1409 // FIXME: test is specific to ja_JP translation implementation. See above comments.
ab4700c3 1410 if ($default_charset == 'iso-2022-jp') {
762853f4 1411 $body_str .= "\n\n".($prefix_sig==true? "-- \n":'').mb_convert_encoding($signature, 'EUC-JP');
1412 } else {
1413 $body_str .= "\n\n".($prefix_sig==true? "-- \n":'').decodeHeader($signature,false,false);
73ad81bf 1414 }
3b17e952 1415 }
73ad81bf 1416 } else {
3047e291 1417 $body_str = sm_encode_html_special_chars(decodeHeader($body,false,false));
48985d59 1418 }
12a0ed01 1419
762853f4 1420 $oTemplate->assign('editor_width', (int)$editor_size);
1421 $oTemplate->assign('editor_height', (int)$editor_height);
1422 $oTemplate->assign('input_onfocus', 'onfocus="'.join(' ', $onfocus_array).'"');
1423 $oTemplate->assign('body', $body_str);
1424 $oTemplate->assign('show_bottom_send', $location_of_buttons!='bottom');
1638beb6 1425
8949acd6 1426 // access keys...
1427 //
1428 global $accesskey_compose_body, $accesskey_compose_send;
1429 $oTemplate->assign('accesskey_compose_body', $accesskey_compose_body);
1430 $oTemplate->assign('accesskey_compose_send', $accesskey_compose_send);
1431
762853f4 1432 $oTemplate->display ('compose_body.tpl');
1638beb6 1433
48985d59 1434 if ($location_of_buttons == 'bottom') {
c8dc86c9 1435//FIXME: DON'T ECHO HTML FROM CORE!
48985d59 1436 showComposeButtonRow();
48985d59 1437 }
46bb8da8 1438
f8eb968d 1439 // composeMessage can be empty when coming from a restored session
1440 if (is_object($composeMessage) && $composeMessage->entities)
1441 $attach_array = $composeMessage->entities;
1442 if ($session_expired && !empty($attachments) && is_array($attachments))
1443 $attach_array = $attachments;
1444
48985d59 1445 /* This code is for attachments */
73ad81bf 1446 if ((bool) ini_get('file_uploads')) {
1447
1448 /* Calculate the max size for an uploaded file.
1449 * This is advisory for the user because we can't actually prevent
1450 * people to upload too large files. */
1451 $sizes = array();
1452 /* php.ini vars which influence the max for uploads */
1453 $configvars = array('post_max_size', 'memory_limit', 'upload_max_filesize');
1454 foreach($configvars as $var) {
4f21ba00 1455 /* skip 0 or empty values, and -1 which means 'unlimited' */
73ad81bf 1456 if( $size = getByteSize(ini_get($var)) ) {
4f21ba00 1457 if ( $size != '-1' ) {
1458 $sizes[] = $size;
1459 }
73ad81bf 1460 }
0a2c3218 1461 }
0a2c3218 1462
762853f4 1463 $attach = array();
1f270d3c 1464 global $username, $attachment_dir;
1465 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
f8eb968d 1466 if (!empty($attach_array)) {
1467 foreach ($attach_array as $key => $attachment) {
73ad81bf 1468 $attached_file = $attachment->att_local_name;
1469 if ($attachment->att_local_name || $attachment->body_part) {
1470 $attached_filename = decodeHeader($attachment->mime_header->getParameter('name'));
1471 $type = $attachment->mime_header->type0.'/'.
a91189d6 1472 $attachment->mime_header->type1;
1638beb6 1473
762853f4 1474 $a = array();
1475 $a['Key'] = $key;
1476 $a['FileName'] = $attached_filename;
1477 $a['ContentType'] = $type;
1f270d3c 1478 $a['Size'] = filesize($hashed_attachment_dir . '/' . $attached_file);
762853f4 1479 $attach[$key] = $a;
73ad81bf 1480 }
1481 }
4dfb9db7 1482 }
1638beb6 1483
762853f4 1484 $max = min($sizes);
1485 $oTemplate->assign('max_file_size', empty($max) ? -1 : $max);
1486 $oTemplate->assign('attachments', $attach);
1638beb6 1487
8949acd6 1488 // access keys...
1489 //
1490 global $accesskey_compose_attach_browse, $accesskey_compose_attach,
1491 $accesskey_compose_delete_attach;
1492 $oTemplate->assign('accesskey_compose_attach_browse', $accesskey_compose_attach_browse);
1493 $oTemplate->assign('accesskey_compose_attach', $accesskey_compose_attach);
1494 $oTemplate->assign('accesskey_compose_delete_attach', $accesskey_compose_delete_attach);
1495
762853f4 1496 $oTemplate->display('compose_attachments.tpl');
73ad81bf 1497 } // End of file_uploads if-block
41b94d65 1498 /* End of attachment code */
762853f4 1499
253ad942 1500 $oTemplate->assign('username', $username);
1501 $oTemplate->assign('smaction', $action);
1502 $oTemplate->assign('mailbox', $mailbox);
953fa718 1503 sqgetGlobalVar('QUERY_STRING', $queryString, SQ_SERVER);
253ad942 1504 $oTemplate->assign('querystring', $queryString);
1505 $oTemplate->assign('composesession', $composesession);
1506 $oTemplate->assign('send_button_count', unique_widget_name('send', TRUE));
1507 if (!empty($attach_array))
1508 $oTemplate->assign('attachments', urlencode(serialize($attach_array)));
1509
1510 $aUserNotices = array();
1511
1512 // File uploads are off, so we didn't show that part of the form.
1513 // To avoid bogus bug reports, tell the user why.
a64f47e7 1514 if (!(bool) ini_get('file_uploads')) {
253ad942 1515 $aUserNotices[] = _("Because PHP file uploads are turned off, you can not attach files to this message. Please see your system administrator for details.");
a64f47e7 1516 }
1517
253ad942 1518 $oTemplate->assign('user_notices', $aUserNotices);
1519
1520 $oTemplate->display('compose_form_close.tpl');
1521
762853f4 1522 if ($compose_new_win=='1') {
1523 $oTemplate->display('compose_newwin_close.tpl');
1524 }
1638beb6 1525
762853f4 1526 $oErrorHandler->setDelayedErrors(false);
5c4ff7bf 1527 $oTemplate->display('footer.tpl');
48985d59 1528}
1529
1530
70c4fd84 1531function showComposeButtonRow() {
78a35fcd 1532 global $use_javascript_addr_book, $save_as_draft,
73ad81bf 1533 $default_use_priority, $mailprio, $default_use_mdn,
1534 $request_mdn, $request_dr,
1535 $data_dir, $username;
70c4fd84 1536
762853f4 1537 global $oTemplate, $buffer_hook;
1638beb6 1538
1539 if ($default_use_priority) {
762853f4 1540 $priorities = array('1'=>_("High"), '3'=>_("Normal"), '5'=>_("Low"));
1541 $priority = isset($mailprio) ? $mailprio : 3;
1542 } else {
1543 $priorities = array();
1544 $priority = NULL;
ae25968c 1545 }
1638beb6 1546
ae25968c 1547 $mdn_user_support=getPref($data_dir, $username, 'mdn_user_support',$default_use_mdn);
48985d59 1548
8949acd6 1549 $address_book_button_attribs = array();
1550 global $accesskey_compose_addresses;
1551 if ($accesskey_compose_addresses != 'NONE')
1552 $address_book_button_attribs['accesskey'] = $accesskey_compose_addresses;
c40a269e 1553 if ($use_javascript_addr_book && checkForJavascript()) {
8949acd6 1554 $addr_book = addButton(_("Addresses"),
1555 null,
1556 array_merge($address_book_button_attribs, array('onclick' => 'javascript:open_abook();')));
734f4ee6 1557 } else {
8949acd6 1558 $addr_book = addSubmit(_("Addresses"), 'html_addr_search', $address_book_button_attribs);
78a35fcd 1559 }
48985d59 1560
762853f4 1561 $oTemplate->assign('allow_priority', $default_use_priority==1);
1562 $oTemplate->assign('priority_list', $priorities);
1563 $oTemplate->assign('current_priority', $priority);
1638beb6 1564
762853f4 1565 $oTemplate->assign('notifications_enabled', $mdn_user_support==1);
1566 $oTemplate->assign('read_receipt', $request_mdn=='1');
1567 $oTemplate->assign('delivery_receipt', $request_dr=='1');
1638beb6 1568
762853f4 1569 $oTemplate->assign('drafts_enabled', $save_as_draft);
1570 $oTemplate->assign('address_book_button', $addr_book);
441f2d33 1571
8949acd6 1572 // access keys...
1573 //
1574 global $accesskey_compose_priority, $accesskey_compose_on_read,
1575 $accesskey_compose_on_delivery, $accesskey_compose_signature,
1576 $accesskey_compose_save_draft, $accesskey_compose_send;
1577 $oTemplate->assign('accesskey_compose_priority', $accesskey_compose_priority);
1578 $oTemplate->assign('accesskey_compose_on_read', $accesskey_compose_on_read);
1579 $oTemplate->assign('accesskey_compose_on_delivery', $accesskey_compose_on_delivery);
1580 $oTemplate->assign('accesskey_compose_signature', $accesskey_compose_signature);
1581 $oTemplate->assign('accesskey_compose_save_draft', $accesskey_compose_save_draft);
1582 $oTemplate->assign('accesskey_compose_send', $accesskey_compose_send);
1583
762853f4 1584 $oTemplate->display('compose_buttons.tpl');
78a35fcd 1585}
b278172f 1586
70c4fd84 1587function checkInput ($show) {
78a35fcd 1588 /*
1589 * I implemented the $show variable because the error messages
1590 * were getting sent before the page header. So, I check once
1591 * using $show=false, and then when i'm ready to display the error
1592 * message, show=true
1593 */
1356041d 1594 global $send_to, $send_to_cc, $send_to_bcc;
78a35fcd 1595
1356041d 1596 $send_to = trim($send_to);
1597 $send_to_cc = trim($send_to_cc);
1598 $send_to_bcc = trim($send_to_bcc);
1599 if (empty($send_to) && empty($send_to_cc) && empty($send_to_bcc)) {
78a35fcd 1600 if ($show) {
cb34dbd0 1601 plain_error_message(_("You have not filled in the \"To:\" field."));
78a35fcd 1602 }
1603 return false;
1604 }
1605 return true;
1606} /* function checkInput() */
df15de21 1607
3806fa52 1608
00793a25 1609/* True if FAILURE */
da95c4b6 1610function saveAttachedFiles($session) {
b4e7df34 1611 global $composeMessage, $username, $attachment_dir;
bfa54da7 1612
45cdd1b5 1613 /* get out of here if no file was attached at all */
1614 if (! is_uploaded_file($_FILES['attachfile']['tmp_name']) ) {
1615 return true;
1616 }
1617
1f270d3c 1618 $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
628bce99 1619 $localfilename = sq_get_attach_tempfile();
1f270d3c 1620 $fullpath = $hashed_attachment_dir . '/' . $localfilename;
4c9d2242 1621
a42c236f 1622 // m_u_f works better with restricted PHP installs (safe_mode, open_basedir),
1623 // if that doesn't work, try a simple rename.
8442ecb9 1624 if (!sq_call_function_suppress_errors('move_uploaded_file', array($_FILES['attachfile']['tmp_name'], $fullpath))) {
1625 if (!sq_call_function_suppress_errors('rename', array($_FILES['attachfile']['tmp_name'], $fullpath))) {
73ad81bf 1626 return true;
1627 }
a61878d0 1628 }
0b97a708 1629 $type = strtolower($_FILES['attachfile']['type']);
1630 $name = $_FILES['attachfile']['name'];
b4e7df34 1631 $composeMessage->initAttachment($type, $name, $localfilename);
4c9d2242 1632}
1633
5fe7d683 1634/**
1635 * Parse strings such as "8M" and "2k" into their corresponding size in bytes
1636 *
1637 * NOTE: This function only recognizes the suffixes "K", "M" and "G"
1638 * and will probably break very easily if the given size is in
1639 * some completely different format.
1640 *
1641 * @param string $ini_size The input string to be converted
1642 *
1643 * @return mixed Boolean FALSE if something went wrong (the value passed in
1644 * was empty?, the suffix was not recognized?), otherwise, the
1645 * converted size in bytes (just the number (as an integer),
1646 * no unit identifier included)
1647 *
1648 */
0a2c3218 1649function getByteSize($ini_size) {
1650
4d30dc83 1651 if(!$ini_size) {
1652 return FALSE;
1653 }
da95c4b6 1654
0a2c3218 1655 $ini_size = trim($ini_size);
1656
5b9716de 1657 // if there's some kind of letter at the end of the string we need to multiply.
1658 if(!is_numeric(substr($ini_size, -1))) {
1659
1660 switch(strtoupper(substr($ini_size, -1))) {
1661 case 'G':
73ad81bf 1662 $bytesize = 1073741824;
1663 break;
5b9716de 1664 case 'M':
73ad81bf 1665 $bytesize = 1048576;
1666 break;
5b9716de 1667 case 'K':
73ad81bf 1668 $bytesize = 1024;
1669 break;
5fe7d683 1670 default:
1671 return FALSE;
5b9716de 1672 }
1673
4d30dc83 1674 return ($bytesize * (int)substr($ini_size, 0, -1));
0a2c3218 1675 }
1c044820 1676
4d30dc83 1677 return $ini_size;
0a2c3218 1678}
a43e4b90 1679
4c9d2242 1680
50706f77 1681/**
1682 * temporary function to make use of the deliver class.
a42c236f 1683 * In the future the responsible backend should be automaticly loaded
50706f77 1684 * and conf.pl should show a list of available backends.
1685 * The message also should be constructed by the message class.
b67d61ee 1686 *
10adeb76 1687 * @param object $composeMessage The message being sent. Please note
1688 * that it is passed by reference and
1689 * will be returned modified, with additional
1690 * headers, such as Message-ID, Date, In-Reply-To,
1691 * References, and so forth.
1692 *
b67d61ee 1693 * @return boolean FALSE if delivery failed, or some non-FALSE value
1694 * upon success.
1695 *
73ad81bf 1696 */
10adeb76 1697function deliverMessage(&$composeMessage, $draft=false) {
a43e4b90 1698 global $send_to, $send_to_cc, $send_to_bcc, $mailprio, $subject, $body,
10adeb76 1699 $username, $identity, $idents, $data_dir,
856e58ef 1700 $request_mdn, $request_dr, $default_charset, $useSendmail,
1701 $domain, $action, $default_move_to_sent, $move_to_sent,
a9805897 1702 $imapServerAddress, $imapPort, $imap_stream_options, $sent_folder, $key;
a43e4b90 1703
1704 $rfc822_header = $composeMessage->rfc822_header;
24192f77 1705
1706 $abook = addressbook_init(false, true);
310dfeb6 1707 $rfc822_header->to = $rfc822_header->parseAddress($send_to,true, array(), '', $domain, array(&$abook,'lookup'));
1708 $rfc822_header->cc = $rfc822_header->parseAddress($send_to_cc,true,array(), '',$domain, array(&$abook,'lookup'));
1709 $rfc822_header->bcc = $rfc822_header->parseAddress($send_to_bcc,true, array(), '',$domain, array(&$abook,'lookup'));
a43e4b90 1710 $rfc822_header->priority = $mailprio;
1711 $rfc822_header->subject = $subject;
310dfeb6 1712
a43e4b90 1713 $special_encoding='';
1714 if (strtolower($default_charset) == 'iso-2022-jp') {
1715 if (mb_detect_encoding($body) == 'ASCII') {
a91189d6 1716 $special_encoding = '8bit';
a43e4b90 1717 } else {
1718 $body = mb_convert_encoding($body, 'JIS');
1719 $special_encoding = '7bit';
1720 }
1721 }
1722 $composeMessage->setBody($body);
1723
a43e4b90 1724 $reply_to = '';
1e2a6ff6 1725 $reply_to = $idents[$identity]['reply_to'];
52ead32b 1726 if ($reply_to && strpos($reply_to, '@') === FALSE)
8b213268 1727 $reply_to .= '@' . $domain;
40e07136 1728
1729 $from_addr = build_from_header($identity);
1730 $rfc822_header->from = $rfc822_header->parseAddress($from_addr,true);
a43e4b90 1731 if ($reply_to) {
73ad81bf 1732 $rfc822_header->reply_to = $rfc822_header->parseAddress($reply_to,true);
a43e4b90 1733 }
1734 /* Receipt: On Read */
1735 if (isset($request_mdn) && $request_mdn) {
40e07136 1736 $rfc822_header->dnt = $rfc822_header->parseAddress($from_addr,true);
762853f4 1737 } elseif (isset($rfc822_header->dnt)) {
1738 unset($rfc822_header->dnt);
a43e4b90 1739 }
1638beb6 1740
a43e4b90 1741 /* Receipt: On Delivery */
657fe1bd 1742 if (!empty($request_dr)) {
1743//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?
cc51047f 1744 $rfc822_header->more_headers['Return-Receipt-To'] = $from_addr;
762853f4 1745 } elseif (isset($rfc822_header->more_headers['Return-Receipt-To'])) {
1746 unset($rfc822_header->more_headers['Return-Receipt-To']);
a43e4b90 1747 }
762853f4 1748
a43e4b90 1749 /* multipart messages */
1750 if (count($composeMessage->entities)) {
1751 $message_body = new Message();
a91189d6 1752 $message_body->body_part = $composeMessage->body_part;
1753 $composeMessage->body_part = '';
1754 $mime_header = new MessageHeader;
1755 $mime_header->type0 = 'text';
1756 $mime_header->type1 = 'plain';
1757 if ($special_encoding) {
1758 $mime_header->encoding = $special_encoding;
1c044820 1759 } else {
12a0ed01 1760 $mime_header->encoding = '8bit';
a91189d6 1761 }
1762 if ($default_charset) {
1763 $mime_header->parameters['charset'] = $default_charset;
1764 }
1c044820 1765 $message_body->mime_header = $mime_header;
a43e4b90 1766 array_unshift($composeMessage->entities, $message_body);
a91189d6 1767 $content_type = new ContentType('multipart/mixed');
a43e4b90 1768 } else {
1e2026df 1769 $content_type = new ContentType('text/plain');
1770 if ($special_encoding) {
1771 $rfc822_header->encoding = $special_encoding;
1c044820 1772 } else {
1e2026df 1773 $rfc822_header->encoding = '8bit';
1c044820 1774 }
426e0b72 1775 if ($default_charset) {
1776 $content_type->properties['charset']=$default_charset;
73ad81bf 1777 }
181538ac 1778 }
1c044820 1779
a43e4b90 1780 $rfc822_header->content_type = $content_type;
1781 $composeMessage->rfc822_header = $rfc822_header;
0fdb0aa1 1782 if ($action == 'reply' || $action == 'reply_all') {
1783 global $passed_id, $passed_ent_id;
1784 $reply_id = $passed_id;
1785 $reply_ent_id = $passed_ent_id;
1786 } else {
1787 $reply_id = '';
1788 $reply_ent_id = '';
1789 }
1638beb6 1790
1c044820 1791 /* Here you can modify the message structure just before we hand
6e515418 1792 it over to deliver; plugin authors note that $composeMessage
1793 is sent and modified by reference since 1.5.2 */
1794 do_hook('compose_send', $composeMessage);
66540988 1795//TODO: need to migrate to the following, but it neessitates changes in existing plugins, since the args are now an array
1796 //$temp = array(&$composeMessage, &$draft);
1797 //do_hook('compose_send', $temp);
a43e4b90 1798
aff28a6d 1799 // remove special header if present and prepare to mark
1800 // a message that a draft was composed in reply to
1801 if (!empty($composeMessage->rfc822_header->x_sm_flag_reply) && !$draft) {
1802 global $passed_id, $mailbox;
1803 // tricks the code below that marks the reply
1804 list($action, $passed_id, $mailbox) = explode('::', $rfc822_header->x_sm_flag_reply, 3);
1805 unset($composeMessage->rfc822_header->x_sm_flag_reply);
1806 unset($composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply']);
1807 }
1808
b48d3c53 1809 if (!$useSendmail && !$draft) {
a91189d6 1810 require_once(SM_PATH . 'class/deliver/Deliver_SMTP.class.php');
1811 $deliver = new Deliver_SMTP();
a9805897 1812 global $smtpServerAddress, $smtpPort, $smtp_stream_options, $pop_before_smtp, $pop_before_smtp_host;
a91189d6 1813
a91189d6 1814 $authPop = (isset($pop_before_smtp) && $pop_before_smtp) ? true : false;
783e926e 1815 if (empty($pop_before_smtp_host)) $pop_before_smtp_host = $smtpServerAddress;
9bd3b1e6 1816 get_smtp_user($user, $pass);
a91189d6 1817 $stream = $deliver->initStream($composeMessage,$domain,0,
a9805897 1818 $smtpServerAddress, $smtpPort, $user, $pass, $authPop, $pop_before_smtp_host, $smtp_stream_options);
b48d3c53 1819 } elseif (!$draft) {
73ad81bf 1820 require_once(SM_PATH . 'class/deliver/Deliver_SendMail.class.php');
fd7ab795 1821 global $sendmail_path, $sendmail_args;
f3dc9c62 1822 // Check for outdated configuration
1823 if (!isset($sendmail_args)) {
1824 if ($sendmail_path=='/var/qmail/bin/qmail-inject') {
1825 $sendmail_args = '';
1826 } else {
1827 $sendmail_args = '-i -t';
1828 }
1829 }
fd7ab795 1830 $deliver = new Deliver_SendMail(array('sendmail_args'=>$sendmail_args));
73ad81bf 1831 $stream = $deliver->initStream($composeMessage,$sendmail_path);
b48d3c53 1832 } elseif ($draft) {
73ad81bf 1833 global $draft_folder;
906f7e9f 1834 $imap_stream = sqimap_login($username, false, $imapServerAddress,
a9805897 1835 $imapPort, 0, $imap_stream_options);
73ad81bf 1836 if (sqimap_mailbox_exists ($imap_stream, $draft_folder)) {
aff28a6d 1837//TODO: this can leak private information about folders and message IDs if messages are accessed/sent from another client --- should this feature be optional?
1838 // make note of the message to mark as having been replied to
1839 global $passed_id, $mailbox;
1840 if ($action == 'reply' || $action == 'reply_all' || $action == 'forward' || $action == 'forward_as_attachment') {
1841 $composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply'] = $action . '::' . $passed_id . '::' . $mailbox;
1842 }
1843
73ad81bf 1844 require_once(SM_PATH . 'class/deliver/Deliver_IMAP.class.php');
1845 $imap_deliver = new Deliver_IMAP();
a90d951c 1846 $success = $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $draft_folder);
73ad81bf 1847 sqimap_logout($imap_stream);
1848 unset ($imap_deliver);
c077ffeb 1849 $composeMessage->purgeAttachments();
b67d61ee 1850 return $success;
4dfb9db7 1851 } else {
3047e291 1852 $msg = '<br />'.sprintf(_("Error: Draft folder %s does not exist."), sm_encode_html_special_chars($draft_folder));
cb34dbd0 1853 plain_error_message($msg);
73ad81bf 1854 return false;
a91189d6 1855 }
a43e4b90 1856 }
0c59bbe1 1857 $success = false;
a43e4b90 1858 if ($stream) {
10adeb76 1859 $deliver->mail($composeMessage, $stream, $reply_id, $reply_ent_id);
0c59bbe1 1860 $success = $deliver->finalizeStream($stream);
a43e4b90 1861 }
0c59bbe1 1862 if (!$success) {
fd7ab795 1863 // $deliver->dlv_server_msg is not always server's reply
32433689 1864 $msg = _("Message not sent.")
1865 . "<br />\n"
1866 . (isset($deliver->dlv_msg) ? $deliver->dlv_msg : '');
a15f9d93 1867 if (!empty($deliver->dlv_server_msg)) {
1868 // add 'server replied' part only when it is not empty.
1869 // Delivery error can be generated by delivery class itself
32433689 1870 $msg .= '<br />'
1871 . _("Server replied:") . ' '
1872 . (isset($deliver->dlv_ret_nr) ? $deliver->dlv_ret_nr . ' ' : '')
3047e291 1873 . nl2br(sm_encode_html_special_chars($deliver->dlv_server_msg));
a15f9d93 1874 }
cb34dbd0 1875 plain_error_message($msg);
a43e4b90 1876 } else {
1877 unset ($deliver);
a9805897 1878 $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, 0, $imap_stream_options);
e4a1f097 1879
8780308f 1880
414303b8 1881 // mark as replied or forwarded if applicable
1882 //
e506b6e5 1883 global $what, $iAccount, $startMessage, $passed_id, $fwduid, $mailbox;
8780308f 1884
bc29bf70 1885 if ($action=='reply' || $action=='reply_all' || $action=='forward' || $action=='forward_as_attachment') {
202bcbcc 1886 require(SM_PATH . 'functions/mailbox_display.php');
aff28a6d 1887 // select errors here could be due to a draft reply being sent
1888 // after the original message's mailbox is moved or deleted
1889 $aMailbox = sqm_api_mailbox_select($imap_stream, $iAccount, $mailbox,array('setindex' => $what, 'offset' => $startMessage),array(), false);
1890 // a non-empty return from above means we can proceed
1891 if (!empty($aMailbox)) {
1892 switch($action) {
1893 case 'reply':
1894 case 'reply_all':
1895 // check if we are allowed to set the \\Answered flag
1896 if (in_array('\\answered',$aMailbox['PERMANENTFLAGS'], true)) {
1897 $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, array($passed_id), '\\Answered', true, false);
1898 if (isset($aUpdatedMsgs[$passed_id]['FLAGS'])) {
1899 /**
1900 * Only update the cached headers if the header is
1901 * cached.
1902 */
1903 if (isset($aMailbox['MSG_HEADERS'][$passed_id])) {
1904 $aMailbox['MSG_HEADERS'][$passed_id]['FLAGS'] = $aMsg['FLAGS'];
1905 }
bc29bf70 1906 }
1907 }
aff28a6d 1908 break;
1909 case 'forward':
1910 case 'forward_as_attachment':
1911 // check if we are allowed to set the $Forwarded flag (RFC 4550 paragraph 2.8)
1912 if (in_array('$forwarded',$aMailbox['PERMANENTFLAGS'], true) ||
1913 in_array('\\*',$aMailbox['PERMANENTFLAGS'])) {
1914
1915 // when forwarding as an attachment from the message
1916 // list, passed_id is not used, need to get UID(s)
1917 // from the query string
1918 //
1919 if (empty($passed_id) && !empty($fwduid))
1920 $ids = explode('_', $fwduid);
1921 else
1922 $ids = array($passed_id);
e506b6e5 1923
aff28a6d 1924 $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, $ids, '$Forwarded', true, false);
e506b6e5 1925
aff28a6d 1926 foreach ($ids as $id) {
1927 if (isset($aUpdatedMsgs[$id]['FLAGS'])) {
1928 if (isset($aMailbox['MSG_HEADERS'][$id])) {
1929 $aMailbox['MSG_HEADERS'][$id]['FLAGS'] = $aMsg['FLAGS'];
1930 }
e506b6e5 1931 }
bc29bf70 1932 }
bda07b93 1933 }
aff28a6d 1934 break;
8780308f 1935 }
bc29bf70 1936
aff28a6d 1937 /**
1938 * Write mailbox with updated seen flag information back to cache.
1939 */
1940 if(isset($aUpdatedMsgs[$passed_id])) {
1941 $mailbox_cache[$iAccount.'_'.$aMailbox['NAME']] = $aMailbox;
1942 sqsession_register($mailbox_cache,'mailbox_cache');
1943 }
bc29bf70 1944 }
a91189d6 1945 }
414303b8 1946
1947
1948 // move to sent folder
1949 //
1950 $move_to_sent = getPref($data_dir,$username,'move_to_sent');
1951 if (isset($default_move_to_sent) && ($default_move_to_sent != 0)) {
1952 $svr_allow_sent = true;
1953 } else {
1954 $svr_allow_sent = false;
1955 }
1956
1957 if (isset($sent_folder) && (($sent_folder != '') || ($sent_folder != 'none'))
1958 && sqimap_mailbox_exists( $imap_stream, $sent_folder)) {
1959 $fld_sent = true;
1960 } else {
1961 $fld_sent = false;
1962 }
1963
1964 if ((isset($move_to_sent) && ($move_to_sent != 0)) || (!isset($move_to_sent))) {
1965 $lcl_allow_sent = true;
1966 } else {
1967 $lcl_allow_sent = false;
1968 }
1969
1970 if (($fld_sent && $svr_allow_sent && !$lcl_allow_sent) || ($fld_sent && $lcl_allow_sent)) {
1971 if ($action == 'reply' || $action == 'reply_all') {
1972 $save_reply_with_orig=getPref($data_dir,$username,'save_reply_with_orig');
1973 if ($save_reply_with_orig) {
1974 $sent_folder = $mailbox;
1975 }
1976 }
414303b8 1977 require_once(SM_PATH . 'class/deliver/Deliver_IMAP.class.php');
1978 $imap_deliver = new Deliver_IMAP();
33f0da43 1979 $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $sent_folder);
414303b8 1980 unset ($imap_deliver);
1981 }
1982
1983
1984 // final cleanup
1985 //
1986 $composeMessage->purgeAttachments();
1987 sqimap_logout($imap_stream);
1988
a43e4b90 1989 }
0c59bbe1 1990 return $success;
a43e4b90 1991}