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