From 48ba4414b33c8982f8232b06f06d68f3213aa986 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 22 Oct 2014 14:29:44 +0200 Subject: Fix download of attachments that are part of TNEF message (#1490091) Rcube_message_part::body content should never be modified by code out of the rcube_message. Added convenient rcube_message::get_part_body() method, making rcube_message::get_part_content() deprecated. --- program/steps/mail/compose.inc | 16 ++++------------ program/steps/mail/func.inc | 32 +++++++++++++++----------------- program/steps/mail/get.inc | 40 +++++++++++++++++----------------------- 3 files changed, 36 insertions(+), 52 deletions(-) (limited to 'program/steps') diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 1770a1bcb..2b1ca4de6 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -802,22 +802,14 @@ function rcmail_compose_part_body($part, $isHtml = false) return ''; } - if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) { - $part->ctype_parameters['charset'] = $MESSAGE->headers->charset; - } - // fetch part if not available - if (!isset($part->body)) { - $part->body = $MESSAGE->get_part_content($part->mime_id); - } + $body = $MESSAGE->get_part_body($part->mime_id, true); // message is cached but not exists (#1485443), or other error - if ($part->body === false) { + if ($body === false) { return ''; } - $body = $part->body; - if ($isHtml) { if ($part->ctype_secondary == 'html') { } @@ -1363,7 +1355,7 @@ function rcmail_save_attachment(&$message, $pid) $path = tempnam($temp_dir, 'rcmAttmnt'); if ($fp = fopen($path, 'w')) { - $message->get_part_content($pid, $fp, true, 0, false); + $message->get_part_body($pid, false, 0, $fp); fclose($fp); } else { @@ -1371,7 +1363,7 @@ function rcmail_save_attachment(&$message, $pid) } } else { - $data = $message->get_part_content($pid, null, true, 0, false); + $data = $message->get_part_body($pid); } $mimetype = $part->ctype_primary . '/' . $part->ctype_secondary; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index cbeeb05fb..8dced9b18 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -864,17 +864,19 @@ function rcmail_wash_html($html, $p, $cid_replaces) * Convert the given message part to proper HTML * which can be displayed the message view * - * @param object rcube_message_part Message part - * @param array Display parameters array + * @param string Message part body + * @param rcube_message_part Message part + * @param array Display parameters array + * * @return string Formatted HTML string */ -function rcmail_print_body($part, $p = array()) +function rcmail_print_body($body, $part, $p = array()) { global $RCMAIL; // trigger plugin hook $data = $RCMAIL->plugins->exec_hook('message_part_before', - array('type' => $part->ctype_secondary, 'body' => $part->body, 'id' => $part->mime_id) + array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); // convert html to text/plain @@ -900,7 +902,7 @@ function rcmail_print_body($part, $p = array()) } else { // assert plaintext - $body = $part->body; + $body = $data['body']; $part->ctype_secondary = $data['type'] = 'plain'; } @@ -1072,8 +1074,10 @@ function rcmail_message_headers($attrib, $headers=null) } else if ($hkey == 'subject' && empty($value)) $header_value = $RCMAIL->gettext('nosubject'); - else + else { + $value = is_array($value) ? implode(' ', $value) : $value; $header_value = trim(rcube_mime::decode_header($value, $headers['charset'])); + } $output_headers[$hkey] = array( 'title' => $header_title, @@ -1204,18 +1208,12 @@ function rcmail_message_body($attrib) continue; } - if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) { - $part->ctype_parameters['charset'] = $MESSAGE->headers->charset; - } - - // fetch part if not available - if (!isset($part->body)) { - $part->body = $MESSAGE->get_part_content($part->mime_id); - } + // fetch part body + $body = $MESSAGE->get_part_body($part->mime_id, true); // extract headers from message/rfc822 parts if ($part->mimetype == 'message/rfc822') { - $msgpart = rcube_mime::parse_message($part->body); + $msgpart = rcube_mime::parse_message($body); if (!empty($msgpart->headers)) { $part = $msgpart; $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); @@ -1223,14 +1221,14 @@ function rcmail_message_body($attrib) } // message is cached but not exists (#1485443), or other error - if ($part->body === false) { + if ($body === false) { rcmail_message_error($MESSAGE->uid); } $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array('part' => $part, 'prefix' => '')); - $body = rcmail_print_body($part, array('safe' => $safe_mode, 'plain' => !$RCMAIL->config->get('prefer_html'))); + $body = rcmail_print_body($body, $part, array('safe' => $safe_mode, 'plain' => !$RCMAIL->config->get('prefer_html'))); if ($part->ctype_secondary == 'html') { $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode); diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index b260d2c85..948465604 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -130,7 +130,7 @@ else if (strlen($part_id)) { $extensions = rcube_mime::get_mime_extensions($mimetype); if ($plugin['body']) { - $part->body = $plugin['body']; + $body = $plugin['body']; } // compare file mimetype with the stated content-type headers and file extension to avoid malicious operations @@ -142,15 +142,10 @@ else if (strlen($part_id)) { // 2. detect the real mimetype of the attachment part and compare it with the stated mimetype and filename extension if ($valid || !$file_extension || $mimetype == 'application/octet-stream' || stripos($mimetype, 'text/') === 0) { - if ($part->body) // part body is already loaded - $body = $part->body; - else if ($part->size && $part->size < 1024*1024) // load the entire part if it's small enough - $body = $part->body = $MESSAGE->get_part_content($part->mime_id); - else // fetch the first 2K of the message part - $body = $MESSAGE->get_part_content($part->mime_id, null, true, 2048); + $tmp_body = $body ?: $MESSAGE->get_part_body($part->mime_id, false, 2048); // detect message part mimetype - $real_mimetype = rcube_mime::file_content_type($body, $part->filename, $mimetype, true, true); + $real_mimetype = rcube_mime::file_content_type($tmp_body, $part->filename, $mimetype, true, true); list($real_ctype_primary, $real_ctype_secondary) = explode('/', $real_mimetype); // accept text/plain with any extension @@ -251,15 +246,15 @@ else if (strlen($part_id)) { } else { // get part body if not available - if (!$part->body) { - $part->body = $MESSAGE->get_part_content($part->mime_id); + if (!isset($body)) { + $body = $MESSAGE->get_part_body($part->mime_id, true); } // show images? rcmail_check_safe($MESSAGE); // render HTML body - $out = rcmail_print_body($part, array('safe' => $MESSAGE->is_safe, 'inline_html' => false)); + $out = rcmail_print_body($body, $part, array('safe' => $MESSAGE->is_safe, 'inline_html' => false)); // insert remote objects warning into HTML body if ($REMOTE_OBJECTS) { @@ -280,7 +275,7 @@ else if (strlen($part_id)) { } // check connection status - if ($part->size && empty($part->body)) { + if ($part->size && empty($body)) { check_storage_status(); } @@ -320,12 +315,12 @@ else if (strlen($part_id)) { $file_path = tempnam($temp_dir, 'rcmAttmnt'); // write content to temp file - if ($part->body) { - $saved = file_put_contents($file_path, $part->body); + if ($body) { + $saved = file_put_contents($file_path, $body); } else if ($part->size) { $fd = fopen($file_path, 'w'); - $saved = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $fd); + $saved = $MESSAGE->get_part_body($part->mime_id, false, 0, $fd); fclose($fd); } @@ -341,22 +336,22 @@ else if (strlen($part_id)) { } // do content filtering to avoid XSS through fake images else if (!empty($_REQUEST['_embed']) && $browser->ie && $browser->ver <= 8) { - if ($part->body) { - echo preg_match('/<(script|iframe|object)/i', $part->body) ? '' : $part->body; + if ($body) { + echo preg_match('/<(script|iframe|object)/i', $body) ? '' : $body; $sent = true; } else if ($part->size) { $stdout = fopen('php://output', 'w'); stream_filter_register('rcube_content', 'rcube_content_filter') or die('Failed to register content filter'); stream_filter_append($stdout, 'rcube_content'); - $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $stdout); + $sent = $MESSAGE->get_part_body($part->mime_id, true, 0, $stdout); } } // send part as-it-is else { - if ($part->body && empty($plugin['download'])) { - header("Content-Length: " . strlen($part->body)); - echo $part->body; + if ($body && empty($plugin['download'])) { + header("Content-Length: " . strlen($body)); + echo $body; $sent = true; } else if ($part->size) { @@ -364,8 +359,7 @@ else if (strlen($part_id)) { header("Content-Length: $size"); } - // 8th argument disables re-formatting of text/* parts (#1489267) - $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, true, null, false, 0, false); + $sent = $MESSAGE->get_part_body($part->mime_id, false, 0, -1); } } -- cgit v1.2.3