thomascube
2010-12-17 db1a87cd6c506f2afbd1a37c64cb56ae11120b49
commit | author | age
4e17e6 1 <?php
T 2
3 /*
4  +-----------------------------------------------------------------------+
5  | program/steps/mail/sendmail.inc                                       |
6  |                                                                       |
e019f2 7  | This file is part of the Roundcube Webmail client                     |
A 8  | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland                 |
30233b 9  | Licensed under the GNU GPL                                            |
4e17e6 10  |                                                                       |
T 11  | PURPOSE:                                                              |
12  |   Compose a new mail message with all headers and attachments         |
e8f8fe 13  |   and send it using the PEAR::Net_SMTP class or with PHP mail()       |
4e17e6 14  |                                                                       |
T 15  +-----------------------------------------------------------------------+
16  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
17  +-----------------------------------------------------------------------+
18
19  $Id$
20
21 */
22
0b6c1c 23 // remove all scripts and act as called in frame
T 24 $OUTPUT->reset();
25 $OUTPUT->framed = TRUE;
26
ad334a 27 $savedraft = !empty($_POST['_draft']) ? true : false;
acb08f 28
A 29 /****** checks ********/
0b6c1c 30
T 31 if (!isset($_SESSION['compose']['id'])) {
ae0040 32   raise_error(array('code' => 500, 'type' => 'php',
10eedb 33     'file' => __FILE__, 'line' => __LINE__,
A 34     'message' => "Invalid compose ID"), true, false);
35
ae0040 36   $OUTPUT->show_message('internalerror', 'error');
0b6c1c 37   $OUTPUT->send('iframe');
T 38 }
4e17e6 39
4b60fa 40 if (!$savedraft) {
A 41   if (empty($_POST['_to']) && empty($_POST['_cc']) && empty($_POST['_bcc'])
42     && empty($_POST['_subject']) && $_POST['_message']) {
43     $OUTPUT->show_message('sendingfailed', 'error');
acb08f 44     $OUTPUT->send('iframe');
4b60fa 45   }
A 46
47   if(!empty($CONFIG['sendmail_delay'])) {
48     $wait_sec = time() - intval($CONFIG['sendmail_delay']) - intval($CONFIG['last_message_time']);
49     if($wait_sec < 0) {
50       $OUTPUT->show_message('senttooquickly', 'error', array('sec' => $wait_sec * -1));
51       $OUTPUT->send('iframe');
acb08f 52     }
4b60fa 53   }
acb08f 54 }
A 55
4e17e6 56
T 57 /****** message sending functions ********/
58
2471d3 59 // encrypt parts of the header
A 60 function rcmail_encrypt_header($what)
61 {
62   global $CONFIG, $RCMAIL;
e99991 63   if (!$CONFIG['http_received_header_encrypt']) {
2471d3 64     return $what;
A 65   }
66   return $RCMAIL->encrypt($what);
67 }
68
fba1f5 69 // get identity record
4e17e6 70 function rcmail_get_identity($id)
e99991 71 {
fba1f5 72   global $USER, $OUTPUT;
db1a87 73
e99991 74   if ($sql_arr = $USER->get_identity($id)) {
4e17e6 75     $out = $sql_arr;
fba1f5 76     $out['mailto'] = $sql_arr['email'];
e99991 77     $out['string'] = format_email_recipient($sql_arr['email'],
A 78       rcube_charset_convert($sql_arr['name'], RCMAIL_CHARSET, $OUTPUT->get_charset()));
fd51e0 79
4e17e6 80     return $out;
T 81   }
e99991 82
A 83   return FALSE;
84 }
4e17e6 85
a0109c 86 /**
S 87  * go from this:
141eb8 88  * <img src="http[s]://.../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" />
a0109c 89  *
S 90  * to this:
91  *
141eb8 92  * <img src="/path/on/server/.../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" />
a0109c 93  * ...
S 94  */
141eb8 95 function rcmail_fix_emoticon_paths(&$mime_message)
a0109c 96 {
47124c 97   global $CONFIG;
a0109c 98
91790e 99   $body = $mime_message->getHTMLBody();
a0109c 100
S 101   // remove any null-byte characters before parsing
24ed41 102   $body = preg_replace('/\x00/', '', $body);
db1a87 103
33ca14 104   $searchstr = 'program/js/tiny_mce/plugins/emotions/img/';
24ed41 105   $offset = 0;
a0109c 106
ed6592 107   // keep track of added images, so they're only added once
S 108   $included_images = array();
109
24ed41 110   if (preg_match_all('# src=[\'"]([^\'"]+)#', $body, $matches, PREG_OFFSET_CAPTURE)) {
A 111     foreach ($matches[1] as $m) {
112       // find emoticon image tags
113       if (preg_match('#'.$searchstr.'(.*)$#', $m[0], $imatches)) {
114         $image_name = $imatches[1];
99f2b3 115
24ed41 116         // sanitize image name so resulting attachment doesn't leave images dir
A 117         $image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i', '', $image_name);
118         $img_file = INSTALL_PATH . '/' . $searchstr . $image_name;
99f2b3 119
24ed41 120         if (! in_array($image_name, $included_images)) {
A 121           // add the image to the MIME message
91790e 122           if (! $mime_message->addHTMLImage($img_file, 'image/gif', '', true, $image_name))
24ed41 123             $OUTPUT->show_message("emoticonerror", 'error');
A 124           array_push($included_images, $image_name);
125         }
4e6eb1 126
24ed41 127         $body = substr_replace($body, $img_file, $m[1] + $offset, strlen($m[0]));
A 128         $offset += strlen($img_file) - strlen($m[0]);
ed6592 129       }
a0109c 130     }
24ed41 131   }
99f2b3 132
a0109c 133   $mime_message->setHTMLBody($body);
24ed41 134
A 135   return $body;
a0109c 136 }
41fa0b 137
751b22 138 // parse email address input (and count addresses)
e99991 139 function rcmail_email_input_format($mailto, $count=false, $check=true)
c58c0a 140 {
751b22 141   global $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT;
e4acbb 142
c58c0a 143   $regexp = array('/[,;]\s*[\r\n]+/', '/[\r\n]+/', '/[,;]\s*$/m', '/;/', '/(\S{1})(<\S+@\S+>)/U');
A 144   $replace = array(', ', ', ', '', ',', '\\1 \\2');
145
050410 146   // replace new lines and strip ending ', ', make address input more valid
c58c0a 147   $mailto = trim(preg_replace($regexp, $replace, $mailto));
A 148
050410 149   $result = array();
A 150   $items = rcube_explode_quoted_string(',', $mailto);
c58c0a 151
050410 152   foreach($items as $item) {
A 153     $item = trim($item);
154     // address in brackets without name (do nothing)
155     if (preg_match('/^<\S+@\S+>$/', $item)) {
e99991 156       $item = idn_to_ascii($item);
050410 157       $result[] = $item;
A 158     // address without brackets and without name (add brackets)
159     } else if (preg_match('/^\S+@\S+$/', $item)) {
e99991 160       $item = idn_to_ascii($item);
050410 161       $result[] = '<'.$item.'>';
A 162     // address with name (handle name)
163     } else if (preg_match('/\S+@\S+>*$/', $item, $matches)) {
164       $address = $matches[0];
165       $name = str_replace($address, '', $item);
166       $name = trim($name);
167       if ($name && ($name[0] != '"' || $name[strlen($name)-1] != '"')
c58c0a 168           && preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name)) {
A 169       $name = '"'.addcslashes($name, '"').'"';
170       }
e99991 171       $address = idn_to_ascii($address);
050410 172       if (!preg_match('/^<\S+@\S+>$/', $address))
A 173         $address = '<'.$address.'>';
c58c0a 174
050410 175       $result[] = $name.' '.$address;
e4acbb 176       $item = $address;
050410 177     } else if (trim($item)) {
e4acbb 178       continue;
A 179     }
180
181     // check address format
182     $item = trim($item, '<>');
e99991 183     if ($item && $check && !check_email($item)) {
e4acbb 184       $EMAIL_FORMAT_ERROR = $item;
A 185       return;
050410 186     }
A 187   }
188
751b22 189   if ($count) {
A 190     $RECIPIENT_COUNT += count($result);
191   }
192
050410 193   return implode(', ', $result);
c58c0a 194 }
db1a87 195
acb08f 196
A 197 /****** compose message ********/
198
b068a0 199 if (strlen($_POST['_draft_saveid']) > 3)
T 200   $olddraftmessageid = get_input_value('_draft_saveid', RCUBE_INPUT_POST);
201
1d8cbc 202 $message_id = rcmail_gen_message_id();
4e17e6 203
5bc8cb 204 // set default charset
13c1af 205 $input_charset = $OUTPUT->get_charset();
c03095 206 $message_charset = isset($_POST['_charset']) ? $_POST['_charset'] : $input_charset;
T 207
e4acbb 208 $EMAIL_FORMAT_ERROR = NULL;
751b22 209 $RECIPIENT_COUNT = 0;
e4acbb 210
751b22 211 $mailto = rcmail_email_input_format(get_input_value('_to', RCUBE_INPUT_POST, TRUE, $message_charset), true);
A 212 $mailcc = rcmail_email_input_format(get_input_value('_cc', RCUBE_INPUT_POST, TRUE, $message_charset), true);
213 $mailbcc = rcmail_email_input_format(get_input_value('_bcc', RCUBE_INPUT_POST, TRUE, $message_charset), true);
4e17e6 214
e4acbb 215 if ($EMAIL_FORMAT_ERROR) {
d2b884 216   $OUTPUT->show_message('emailformaterror', 'error', array('email' => $EMAIL_FORMAT_ERROR));
e4acbb 217   $OUTPUT->send('iframe');
A 218 }
219
e8f8fe 220 if (empty($mailto) && !empty($mailcc)) {
T 221   $mailto = $mailcc;
222   $mailcc = null;
223 }
224 else if (empty($mailto))
225   $mailto = 'undisclosed-recipients:;';
226
d2b884 227 // Get sender name and address...
42b25a 228 $from = get_input_value('_from', RCUBE_INPUT_POST, true, $message_charset);
d2b884 229 // ... from identity...
A 230 if (is_numeric($from)) {
231   if (is_array($identity_arr = rcmail_get_identity($from))) {
232     if ($identity_arr['mailto'])
233       $from = $identity_arr['mailto'];
234     if ($identity_arr['string'])
235       $from_string = $identity_arr['string'];
236   }
237   else {
238     $from = null;
239   }
240 }
241 // ... if there is no identity record, this might be a custom from
242 else if ($from_string = rcmail_email_input_format($from)) {
243   if (preg_match('/(\S+@\S+)/', $from_string, $m))
244     $from = trim($m[1], '<>');
245   else
246     $from = null;
247 }
fd51e0 248
d2b884 249 if (!$from_string && $from)
A 250   $from_string = $from;
4e17e6 251
T 252 // compose headers array
2471d3 253 $headers = array();
A 254
255 // if configured, the Received headers goes to top, for good measure
256 if ($CONFIG['http_received_header'])
257 {
ac8edb 258   $nldlm = "\r\n\t";
ddc891 259   // FROM/VIA
2471d3 260   $http_header = 'from ';
A 261   if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
ddc891 262     $host = $_SERVER['HTTP_X_FORWARDED_FOR'];
A 263     $hostname = gethostbyaddr($host);
264     if ($CONFIG['http_received_header_encrypt']) {
265       $http_header .= rcmail_encrypt_header($hostname);
266       if ($host != $hostname)
267         $http_header .= ' ('. rcmail_encrypt_header($host) . ')';
268     } else {
269       $http_header .= (($host != $hostname) ? $hostname : '[' . $host . ']');
82c98e 270       if ($host != $hostname)
A 271         $http_header .= ' (['. $host .'])';
ddc891 272     }
2471d3 273     $http_header .= $nldlm . ' via ';
A 274   }
ddc891 275   $host = $_SERVER['REMOTE_ADDR'];
A 276   $hostname = gethostbyaddr($host);
277   if ($CONFIG['http_received_header_encrypt']) {
278     $http_header .= rcmail_encrypt_header($hostname);
279     if ($host != $hostname)
280       $http_header .= ' ('. rcmail_encrypt_header($host) . ')';
281   } else {
282     $http_header .= (($host != $hostname) ? $hostname : '[' . $host . ']');
82c98e 283     if ($host != $hostname)
A 284       $http_header .= ' (['. $host .'])';
ddc891 285   }
A 286   // BY
287   $http_header .= $nldlm . 'by ' . $_SERVER['HTTP_HOST'];
288   // WITH
82c98e 289   $http_header .= $nldlm . 'with HTTP (' . $_SERVER['SERVER_PROTOCOL'] .
A 290       ' '.$_SERVER['REQUEST_METHOD'] . '); ' . date('r');
2471d3 291   $http_header = wordwrap($http_header, 69, $nldlm);
ddc891 292
2471d3 293   $headers['Received'] = $http_header;
A 294 }
295
2bf3cc 296 $headers['Date'] = rcmail_user_date();
d2b884 297 $headers['From'] = rcube_charset_convert($from_string, RCMAIL_CHARSET, $message_charset);
2471d3 298 $headers['To'] = $mailto;
4e17e6 299
T 300 // additional recipients
db1a87 301 if (!empty($mailcc)) {
e8f8fe 302   $headers['Cc'] = $mailcc;
db1a87 303 }
T 304 if (!empty($mailbcc)) {
e8f8fe 305   $headers['Bcc'] = $mailbcc;
db1a87 306 }
751b22 307 if (!empty($identity_arr['bcc'])) {
4e17e6 308   $headers['Bcc'] = ($headers['Bcc'] ? $headers['Bcc'].', ' : '') . $identity_arr['bcc'];
751b22 309   $RECIPIENT_COUNT ++;
A 310 }
311
312 if (($max_recipients = (int) $RCMAIL->config->get('max_recipients')) > 0) {
313   if ($RECIPIENT_COUNT > $max_recipients) {
314     $OUTPUT->show_message('toomanyrecipients', 'error', array('max' => $max_recipients));
315     $OUTPUT->send('iframe');
316   }
317 }
4e17e6 318
T 319 // add subject
762a69 320 $headers['Subject'] = trim(get_input_value('_subject', RCUBE_INPUT_POST, TRUE, $message_charset));
4e17e6 321
db1a87 322 if (!empty($identity_arr['organization'])) {
4e17e6 323   $headers['Organization'] = $identity_arr['organization'];
db1a87 324 }
T 325 if (!empty($_POST['_replyto'])) {
8f9ab3 326   $headers['Reply-To'] = rcmail_email_input_format(get_input_value('_replyto', RCUBE_INPUT_POST, TRUE, $message_charset));
db1a87 327 }
T 328 else if (!empty($identity_arr['reply-to'])) {
e99991 329   $headers['Reply-To'] = rcmail_email_input_format($identity_arr['reply-to'], false, true);
db1a87 330 }
T 331 if (!empty($headers['Reply-To'])) {
332   $headers['Mail-Reply-To'] = $headers['Reply-To'];
333 }
334 if (!empty($_POST['_followupto'])) {
335   $headers['Mail-Followup-To'] = rcmail_email_input_format(get_input_value('_followupto', RCUBE_INPUT_POST, TRUE, $message_charset));
336 }
337 if (!empty($_SESSION['compose']['reply_msgid'])) {
4e17e6 338   $headers['In-Reply-To'] = $_SESSION['compose']['reply_msgid'];
db1a87 339 }
e99991 340
bbc856 341 // remember reply/forward UIDs in special headers
db1a87 342 if (!empty($_SESSION['compose']['reply_uid']) && $savedraft) {
bc404f 343   $headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $_SESSION['compose']['reply_uid']);
db1a87 344 }
T 345 else if (!empty($_SESSION['compose']['forward_uid']) && $savedraft) {
bc404f 346   $headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $_SESSION['compose']['forward_uid']);
db1a87 347 }
bbc856 348
db1a87 349 if (!empty($_SESSION['compose']['references'])) {
f88d41 350   $headers['References'] = $_SESSION['compose']['references'];
db1a87 351 }
4e17e6 352
d2b884 353 if (!empty($_POST['_priority'])) {
c57996 354   $priority = intval($_POST['_priority']);
3287e8 355   $a_priorities = array(1=>'highest', 2=>'high', 4=>'low', 5=>'lowest');
db1a87 356   if ($str_priority = $a_priorities[$priority]) {
4e17e6 357     $headers['X-Priority'] = sprintf("%d (%s)", $priority, ucfirst($str_priority));
db1a87 358   }
d2b884 359 }
4e17e6 360
d2b884 361 if (!empty($_POST['_receipt'])) {
A 362   $headers['Return-Receipt-To'] = $from_string;
363   $headers['Disposition-Notification-To'] = $from_string;
364 }
4e17e6 365
T 366 // additional headers
53e79d 367 $headers['Message-ID'] = $message_id;
A 368 $headers['X-Sender'] = $from;
369
db1a87 370 if (is_array($headers['X-Draft-Info'])) {
bc404f 371   $headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $_SESSION['compose']['mailbox']));
db1a87 372 }
T 373 if (!empty($CONFIG['useragent'])) {
4e17e6 374   $headers['User-Agent'] = $CONFIG['useragent'];
db1a87 375 }
4e17e6 376
b44b4d 377 // exec hook for header checking and manipulation
e6ce00 378 $data = $RCMAIL->plugins->exec_hook('message_outgoing_headers', array('headers' => $headers));
b44b4d 379
T 380 // sending aborted by plugin
381 if ($data['abort'] && !$savedraft) {
382   $OUTPUT->show_message($data['message'] ? $data['message'] : 'sendingfailed');
383   $OUTPUT->send('iframe');
384 }
385 else
386   $headers = $data['headers'];
387
388
751b22 389 $isHtml = (bool) get_input_value('_is_html', RCUBE_INPUT_POST);
940fc1 390
c03095 391 // fetch message body
ea7c46 392 $message_body = get_input_value('_message', RCUBE_INPUT_POST, TRUE, $message_charset);
940fc1 393
65605c 394 if (!$savedraft) {
7a48e5 395   if ($isHtml) {
A 396     // remove signature's div ID
65605c 397     $message_body = preg_replace('/\s*id="_rc_sig"/', '', $message_body);
4e17e6 398
7a48e5 399     // add inline css for blockquotes
A 400     $bstyle = 'padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px; width:100%';
401     $message_body = preg_replace('/<blockquote>/',
402     '<blockquote type="cite" style="'.$bstyle.'">', $message_body);
403   }
5852c1 404
65605c 405   // generic footer for all messages
5852c1 406   if ($isHtml && !empty($CONFIG['generic_message_footer_html'])) {
A 407       $footer = file_get_contents(realpath($CONFIG['generic_message_footer_html']));
408       $footer = rcube_charset_convert($footer, RCMAIL_CHARSET, $message_charset);
409   }
410   else if (!empty($CONFIG['generic_message_footer'])) {
65605c 411     $footer = file_get_contents(realpath($CONFIG['generic_message_footer']));
ecb9fb 412     $footer = rcube_charset_convert($footer, RCMAIL_CHARSET, $message_charset);
5852c1 413     if ($isHtml)
A 414       $footer = '<pre>'.$footer.'</pre>';
65605c 415   }
5852c1 416   if ($footer)
A 417     $message_body .= "\r\n" . $footer;
65605c 418 }
a0109c 419
b62049 420 // set line length for body wrapping
c769c6 421 $LINE_LENGTH = $RCMAIL->config->get('line_length', 72);
b62049 422
91790e 423 // Since we can handle big messages with disk usage, we need more time to work
A 424 @set_time_limit(0);
425
426 // create PEAR::Mail_mime instance
ac8edb 427 $MAIL_MIME = new Mail_mime("\r\n");
91790e 428
A 429 // Check if we have enough memory to handle the message in it
430 // It's faster than using files, so we'll do this if we only can
431 if (is_array($_SESSION['compose']['attachments']) && $CONFIG['smtp_server']
432   && ($mem_limit = parse_bytes(ini_get('memory_limit'))))
433 {
434   $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB
435
436   foreach ($_SESSION['compose']['attachments'] as $id => $attachment)
437     $memory += $attachment['size'];
438
439   // Yeah, Net_SMTP needs up to 12x more memory, 1.33 is for base64
440   if ($memory * 1.33 * 12 > $mem_limit)
441     $MAIL_MIME->setParam('delay_file_io', true);
442 }
a0109c 443
S 444 // For HTML-formatted messages, construct the MIME message with both
445 // the HTML part and the plain-text part
446
cc97ea 447 if ($isHtml) {
e6ce00 448   $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body',
ac8edb 449     array('body' => $message_body, 'type' => 'html', 'message' => $MAIL_MIME));
A 450
5852c1 451   $MAIL_MIME->setHTMLBody($plugin['body']);
a0109c 452
db1a87 453   // replace emoticons
T 454   $plugin['body'] = rcmail_replace_emoticons($plugin['body']);
455
a0109c 456   // add a plain text version of the e-mail as an alternative part.
cc97ea 457   $h2t = new html2text($plugin['body'], false, true, 0);
5852c1 458   $plainTextPart = rc_wordwrap($h2t->get_text(), $LINE_LENGTH, "\r\n");
65605c 459   $plainTextPart = wordwrap($plainTextPart, 998, "\r\n", true);
5852c1 460   if (!$plainTextPart) {
db1a87 461     // empty message body breaks attachment handling in drafts
T 462     $plainTextPart = "\r\n";
cc97ea 463   }
ac8edb 464   else {
A 465     // make sure all line endings are CRLF (#1486712)
466     $plainTextPart = preg_replace('/\r?\n/', "\r\n", $plainTextPart);
467   }
468
e6ce00 469   $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body',
ac8edb 470     array('body' => $plainTextPart, 'type' => 'alternative', 'message' => $MAIL_MIME));
A 471
cc97ea 472   $MAIL_MIME->setTXTBody($plugin['body']);
a0109c 473
141eb8 474   // look for "emoticon" images from TinyMCE and change their src paths to
S 475   // be file paths on the server instead of URL paths.
476   $message_body = rcmail_fix_emoticon_paths($MAIL_MIME);
cc97ea 477 }
6b6f2e 478 else {
e6ce00 479   $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body',
5852c1 480     array('body' => $message_body, 'type' => 'plain', 'message' => $MAIL_MIME));
A 481
482   $message_body = $plugin['body'];
483
99b8c1 484   // compose format=flowed content if enabled
A 485   if ($flowed = $RCMAIL->config->get('send_format_flowed', true))
486     $message_body = rcube_message::format_flowed($message_body, min($LINE_LENGTH+2, 79));
6b6f2e 487   else
dffcaa 488     $message_body = rc_wordwrap($message_body, $LINE_LENGTH, "\r\n");
5852c1 489
a23884 490   $message_body = wordwrap($message_body, 998, "\r\n", true);
cc97ea 491   if (!strlen($message_body)) { 
212352 492     // empty message body breaks attachment handling in drafts 
T 493     $message_body = "\r\n"; 
a0109c 494   }
ac8edb 495
5852c1 496   $MAIL_MIME->setTXTBody($message_body, false, true);
cc97ea 497 }
4e17e6 498
T 499 // add stored attachments, if any
91790e 500 if (is_array($_SESSION['compose']['attachments']))
A 501 {
cc97ea 502   foreach ($_SESSION['compose']['attachments'] as $id => $attachment) {
T 503     // This hook retrieves the attachment contents from the file storage backend
e6ce00 504     $attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment);
cc97ea 505
c973ab 506     $dispurl = '/\ssrc\s*=\s*[\'"]*\S+display-attachment\S+file=rcmfile' . preg_quote($attachment['id']) . '[\s\'"]*/';
cc97ea 507     $message_body = $MAIL_MIME->getHTMLBody();
T 508     if ($isHtml && (preg_match($dispurl, $message_body) > 0)) {
d519ef 509       $message_body = preg_replace($dispurl, ' src="'.$attachment['name'].'" ', $message_body);
7145e0 510       $MAIL_MIME->setHTMLBody($message_body);
dc9d75 511
cc97ea 512       if ($attachment['data'])
T 513         $MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false);
514       else
515         $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true);
4315b0 516     }
cc97ea 517     else {
6d5dba 518       $ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914
cc97ea 519       $file = $attachment['data'] ? $attachment['data'] : $attachment['path'];
33ca14 520
A 521       // .eml attachments send inline
cc97ea 522       $MAIL_MIME->addAttachment($file,
57388f 523         $ctype,
cc97ea 524         $attachment['name'],
T 525         ($attachment['data'] ? false : true),
dc9d75 526         ($ctype == 'message/rfc822' ? '8bit' : 'base64'),
33ca14 527         ($ctype == 'message/rfc822' ? 'inline' : 'attachment'),
db1a87 528         '', '', '',
cc97ea 529         $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL,
db1a87 530         $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL,
T 531         '', RCMAIL_CHARSET
cc97ea 532       );
4315b0 533     }
S 534   }
cc97ea 535 }
4e17e6 536
3d0ec7 537 // choose transfer encoding for plain/text body
A 538 if (preg_match('/[^\x00-\x7F]/', $MAIL_MIME->getTXTBody()))
47ad83 539   $transfer_encoding = $RCMAIL->config->get('force_7bit') ? 'quoted-printable' : '8bit';
3d0ec7 540 else
A 541   $transfer_encoding = '7bit';
542
a95e0e 543 // encoding settings for mail composing
91790e 544 $MAIL_MIME->setParam('text_encoding', $transfer_encoding);
A 545 $MAIL_MIME->setParam('html_encoding', 'quoted-printable');
546 $MAIL_MIME->setParam('head_encoding', 'quoted-printable');
547 $MAIL_MIME->setParam('head_charset', $message_charset);
548 $MAIL_MIME->setParam('html_charset', $message_charset);
6b6f2e 549 $MAIL_MIME->setParam('text_charset', $message_charset . ($flowed ? ";\r\n format=flowed" : ''));
cc97ea 550
5a6ad2 551 // encoding subject header with mb_encode provides better results with asian characters
d2b884 552 if (function_exists('mb_encode_mimeheader')) {
24fe97 553   mb_internal_encoding($message_charset);
34b659 554   $headers['Subject'] = mb_encode_mimeheader($headers['Subject'],
ac8edb 555     $message_charset, 'Q', "\r\n", 8);
f11541 556   mb_internal_encoding(RCMAIL_CHARSET);
b517af 557 }
4e17e6 558
fba1f5 559 // pass headers to message object
T 560 $MAIL_MIME->headers($headers);
4e17e6 561
d2b884 562 // Begin SMTP Delivery Block
fba1f5 563 if (!$savedraft)
T 564 {
d2b884 565   // check 'From' address (identity may be incomplete)
A 566   if (empty($from)) {
fd51e0 567     $OUTPUT->show_message('nofromaddress', 'error');
d2b884 568     $OUTPUT->send('iframe');
fd51e0 569   }
A 570
f22ea7 571   // Handle Delivery Status Notification request
A 572   if (!empty($_POST['_dsn'])) {
573     $smtp_opts['dsn'] = true;
574   }
575
576   $sent = rcmail_deliver_message($MAIL_MIME, $from, $mailto,
577     $smtp_error, $mailbody_file, $smtp_opts);
91790e 578
1966c5 579   // return to compose page if sending failed
968bdc 580   if (!$sent)
4e17e6 581     {
91790e 582     // remove temp file
A 583     if ($mailbody_file) {
584       unlink($mailbody_file);
585       }
586
2818f8 587     if ($smtp_error)
A 588       $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); 
589     else
590       $OUTPUT->show_message('sendingfailed', 'error'); 
f11541 591     $OUTPUT->send('iframe');
4e17e6 592     }
acb08f 593
A 594   // save message sent time
595   if (!empty($CONFIG['sendmail_delay']))
4b60fa 596     $RCMAIL->user->save_prefs(array('last_message_time' => time()));
1966c5 597   
4dae73 598   // set replied/forwarded flag
1966c5 599   if ($_SESSION['compose']['reply_uid'])
48958e 600     $IMAP->set_flag($_SESSION['compose']['reply_uid'], 'ANSWERED', $_SESSION['compose']['mailbox']);
4dae73 601   else if ($_SESSION['compose']['forward_uid'])
48958e 602     $IMAP->set_flag($_SESSION['compose']['forward_uid'], 'FORWARDED', $_SESSION['compose']['mailbox']);
c03095 603
4dae73 604 } // End of SMTP Delivery Block
41fa0b 605
T 606
1966c5 607 // Determine which folder to save message
b068a0 608 if ($savedraft)
faf876 609   $store_target = $CONFIG['drafts_mbox'];
d583bc 610 else    
faf876 611   $store_target = isset($_POST['_store_target']) ? get_input_value('_store_target', RCUBE_INPUT_POST) : $CONFIG['sent_mbox'];
c03095 612
faf876 613 if ($store_target)
4e17e6 614   {
16378f 615   // check if folder is subscribed
A 616   if ($IMAP->mailbox_exists($store_target, true))
617     $store_folder = true;
618   // folder may be existing but not subscribed (#1485241)
619   else if (!$IMAP->mailbox_exists($store_target))
620     $store_folder = $IMAP->create_mailbox($store_target, true);
621   else if ($IMAP->subscribe($store_target))
622     $store_folder = true;
520c36 623
91790e 624   // append message to sent box
A 625   if ($store_folder) {
626
627     // message body in file
628     if ($mailbody_file || $MAIL_MIME->getParam('delay_file_io')) {
629       $headers = $MAIL_MIME->txtHeaders();
630       
631       // file already created
632       if ($mailbody_file)
633         $msg = $mailbody_file;
634       else {
635         $temp_dir = $RCMAIL->config->get('temp_dir');
636         $mailbody_file = tempnam($temp_dir, 'rcmMsg');
637         if (!PEAR::isError($msg = $MAIL_MIME->saveMessageBody($mailbody_file)))
638           $msg = $mailbody_file;
639         }
640       }
641     else {
642       $msg = $MAIL_MIME->getMessage();
643       $headers = '';
644       }
645
646     if (PEAR::isError($msg))
647       raise_error(array('code' => 600, 'type' => 'php',
648         'file' => __FILE__, 'line' => __LINE__,
649             'message' => "Could not create message: ".$msg->getMessage()),
650             TRUE, FALSE);
651     else {
652       $saved = $IMAP->save_message($store_target, $msg, $headers, $mailbody_file ? true : false);
653       }
654
655     if ($mailbody_file) {
656       unlink($mailbody_file);
657       $mailbody_file = null;
658       }
659
660     // raise error if saving failed
661     if (!$saved) {
662       raise_error(array('code' => 800, 'type' => 'imap',
6d13ca 663         'file' => __FILE__, 'line' => __LINE__,
A 664             'message' => "Could not save message in $store_target"), TRUE, FALSE);
41fa0b 665     
91790e 666       if ($savedraft) {
A 667         $OUTPUT->show_message('errorsaving', 'error');
668         $OUTPUT->send('iframe');
669         }
9a5762 670       }
f0f98f 671     }
4e17e6 672
b068a0 673   if ($olddraftmessageid)
T 674     {
1966c5 675     // delete previous saved draft
6f31b3 676     $a_deleteid = $IMAP->search_once($CONFIG['drafts_mbox'],
A 677         'HEADER Message-ID '.$olddraftmessageid, true);
678     $deleted = $IMAP->delete_message($a_deleteid, $CONFIG['drafts_mbox']);
4e17e6 679
f0f98f 680     // raise error if deletion of old draft failed
1966c5 681     if (!$deleted)
6d13ca 682       raise_error(array('code' => 800, 'type' => 'imap',
A 683             'file' => __FILE__, 'line' => __LINE__,
684                 'message' => "Could not delete message from ".$CONFIG['drafts_mbox']), TRUE, FALSE);
4e17e6 685     }
T 686   }
91790e 687 // remove temp file
A 688 else if ($mailbody_file) {
689   unlink($mailbody_file);
690   }
691
4e17e6 692
1966c5 693 if ($savedraft)
S 694   {
c719f3 695   $msgid = strtr($message_id, array('>' => '', '<' => ''));
T 696   
697   // remember new draft-uid
6f31b3 698   $draftuids = $IMAP->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$msgid, true);
A 699   $_SESSION['compose']['param']['_draft_uid'] = $draftuids[0];
c719f3 700
f11541 701   // display success
T 702   $OUTPUT->show_message('messagesaved', 'confirmation');
f0f98f 703
f11541 704   // update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning
c719f3 705   $OUTPUT->command('set_draft_id', $msgid);
f11541 706   $OUTPUT->command('compose_field_hash', true);
41fa0b 707
f0f98f 708   // start the auto-save timer again
f11541 709   $OUTPUT->command('auto_save_start');
f0f98f 710
f11541 711   $OUTPUT->send('iframe');
1966c5 712   }
S 713 else
714   {
715   rcmail_compose_cleanup();
9a5762 716
A 717   if ($store_folder && !$saved)
718     $OUTPUT->command('sent_successfully', 'error', rcube_label('errorsavingsent'));
719   else
720     $OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent'));
f11541 721   $OUTPUT->send('iframe');
1966c5 722   }
4e17e6 723
b25dfd 724