From 5579ef662197029afbf90d7bc2bfb5ba594475ac Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Thu, 17 Dec 2015 03:29:30 -0500
Subject: [PATCH] Fix handling of message/rfc822 attachments on replies and forwards (#1490607)
---
CHANGELOG | 1
program/steps/mail/compose.inc | 50 ++++++++--------
program/steps/mail/func.inc | 26 +-------
program/lib/Roundcube/rcube_message.php | 50 +++++-----------
4 files changed, 47 insertions(+), 80 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 6053494..545d339 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@
- Add workaround for https://bugs.php.net/bug.php?id=70757 (#1490582)
- Fix HTML sanitizer to skip <!-- node type X --> in output (#1490583)
- Fix charset encoding of message/rfc822 part bodies (#1490606)
+- Fix handling of message/rfc822 attachments on replies and forwards (#1490607)
RELEASE 1.0.7
-------------
diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php
index 30f6b56..6268228 100644
--- a/program/lib/Roundcube/rcube_message.php
+++ b/program/lib/Roundcube/rcube_message.php
@@ -525,24 +525,16 @@
$mail_part = &$structure->parts[$i];
$primary_type = $mail_part->ctype_primary;
$secondary_type = $mail_part->ctype_secondary;
+ $part_mimetype = $mail_part->mimetype;
- // real content-type of message/rfc822
- if ($mail_part->real_mimetype) {
- $part_orig_mimetype = $mail_part->mimetype;
- $part_mimetype = $mail_part->real_mimetype;
- list($primary_type, $secondary_type) = explode('/', $part_mimetype);
- }
- else {
- $part_mimetype = $part_orig_mimetype = $mail_part->mimetype;
- }
-
- // multipart/alternative
- if ($primary_type == 'multipart') {
+ // multipart/alternative or message/rfc822
+ if ($primary_type == 'multipart' || $part_mimetype == 'message/rfc822') {
$this->parse_structure($mail_part, true);
// list message/rfc822 as attachment as well (mostly .eml)
- if ($part_orig_mimetype == 'message/rfc822' && !empty($mail_part->filename))
+ if ($primary_type == 'message' && !empty($mail_part->filename)) {
$this->attachments[] = $mail_part;
+ }
}
// part text/[plain|html] or delivery status
else if ((($part_mimetype == 'text/plain' || $part_mimetype == 'text/html') && $mail_part->disposition != 'attachment') ||
@@ -553,8 +545,9 @@
array('object' => $this, 'structure' => $mail_part,
'mimetype' => $part_mimetype, 'recursive' => true));
- if ($plugin['abort'])
+ if ($plugin['abort']) {
continue;
+ }
if ($part_mimetype == 'text/html' && $mail_part->size) {
$got_html_part = true;
@@ -576,14 +569,6 @@
if (!empty($mail_part->filename)) {
$this->attachments[] = $mail_part;
}
- }
- // part message/*
- else if ($primary_type == 'message') {
- $this->parse_structure($mail_part, true);
-
- // list as attachment as well (mostly .eml)
- if (!empty($mail_part->filename))
- $this->attachments[] = $mail_part;
}
// ignore "virtual" protocol parts
else if ($primary_type == 'protocol') {
@@ -608,21 +593,14 @@
// part belongs to a related message and is linked
if (preg_match('/^multipart\/(related|relative)/', $mimetype)
- && ($mail_part->headers['content-id'] || $mail_part->headers['content-location'])) {
+ && ($mail_part->headers['content-id'] || $mail_part->headers['content-location'])
+ ) {
if ($mail_part->headers['content-id'])
$mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']);
if ($mail_part->headers['content-location'])
$mail_part->content_location = $mail_part->headers['content-base'] . $mail_part->headers['content-location'];
$this->inline_parts[] = $mail_part;
- }
- // attachment encapsulated within message/rfc822 part needs further decoding (#1486743)
- else if ($part_orig_mimetype == 'message/rfc822') {
- $this->parse_structure($mail_part, true);
-
- // list as attachment as well (mostly .eml)
- if (!empty($mail_part->filename))
- $this->attachments[] = $mail_part;
}
// regular attachment with valid content type
// (content-type name regexp according to RFC4288.4.2)
@@ -639,9 +617,13 @@
$this->attachments[] = $mail_part;
}
}
- // attachment part as message/rfc822 (#1488026)
- else if ($mail_part->mimetype == 'message/rfc822') {
- $this->parse_structure($mail_part);
+ // calendar part not marked as attachment (#1490325)
+ else if ($part_mimetype == 'text/calendar') {
+ if (!$mail_part->filename) {
+ $mail_part->filename = 'calendar.ics';
+ }
+
+ $this->attachments[] = $mail_part;
}
}
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index bd0b11a..0dab641 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -716,11 +716,9 @@
if (!empty($MESSAGE->parts)) {
// collect IDs of message/rfc822 parts
- if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) {
- foreach ($MESSAGE->attachments as $part) {
- if ($part->mimetype == 'message/rfc822') {
- $messages[] = $part->mime_id;
- }
+ foreach ($MESSAGE->mime_parts as $part) {
+ if ($part->mimetype == 'message/rfc822') {
+ $messages[] = $part->mime_id;
}
}
@@ -730,7 +728,7 @@
continue;
}
- // skip all content parts inside the message/rfc822 part in DRAFT/EDIT mode
+ // skip all content parts inside the message/rfc822 part
foreach ($messages as $mimeid) {
if (strpos($part->mime_id, $mimeid . '.') === 0) {
continue 2;
@@ -1163,6 +1161,10 @@
$messages = array();
foreach ((array)$message->mime_parts as $pid => $part) {
+ if ($part->mimetype == 'message/rfc822') {
+ $messages[] = $part->mime_id;
+ }
+
if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) {
// skip parts that aren't valid attachments
if ($part->ctype_primary == 'multipart' || $part->mimetype == 'application/ms-tnef') {
@@ -1179,23 +1181,10 @@
continue;
}
- // skip message/rfc822 attachments on forwards (#1489214)
- // Thunderbird when forwarding in inline mode displays such attachments
- // and skips any attachments from inside of such part, this however
- // skipped e.g. images used in HTML body or other attachments. So,
- // better to skip .eml attachments but not their content (included files).
- if ($part->mimetype == 'message/rfc822') {
- if ($compose_mode == RCUBE_COMPOSE_FORWARD) {
- continue;
- }
- $messages[] = $part->mime_id;
- }
- else if ($compose_mode != RCUBE_COMPOSE_FORWARD) {
- // skip attachments included in message/rfc822 attachment (#1486487)
- foreach ($messages as $mimeid) {
- if (strpos($part->mime_id, $mimeid . '.') === 0) {
- continue 2;
- }
+ // skip attachments included in message/rfc822 attachment (#1486487, #1490607)
+ foreach ($messages as $mimeid) {
+ if (strpos($part->mime_id, $mimeid . '.') === 0) {
+ continue 2;
}
}
@@ -1227,9 +1216,22 @@
{
global $RCMAIL, $COMPOSE;
- $cid_map = array();
+ $cid_map = array();
+ $messages = array();
+
foreach ((array)$message->mime_parts as $pid => $part) {
+ if ($part->mimetype == 'message/rfc822') {
+ $messages[] = $part->mime_id;
+ }
+
if (($part->content_id || $part->content_location) && $part->filename) {
+ // skip attachments included in message/rfc822 attachment (#1486487, #1490607)
+ foreach ($messages as $mimeid) {
+ if (strpos($part->mime_id, $mimeid . '.') === 0) {
+ continue 2;
+ }
+ }
+
if ($attachment = rcmail_save_attachment($message, $pid)) {
$COMPOSE['attachments'][$attachment['id']] = $attachment;
$url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s',
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 7a96356..3eee82d 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -789,20 +789,15 @@
*
* @param rcube_message_part Message part
* @param array Display parameters array
- * @param string Part body
* @return string Formatted HTML string
*/
-function rcmail_print_body($part, $p = array(), $body = null)
+function rcmail_print_body($part, $p = array())
{
global $RCMAIL;
- if ($body === null) {
- $body = $part->body;
- }
-
// trigger plugin hook
$data = $RCMAIL->plugins->exec_hook('message_part_before',
- array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id)
+ array('type' => $part->ctype_secondary, 'body' => $part->body, 'id' => $part->mime_id)
+ $p + array('safe' => false, 'plain' => false, 'inline_html' => true));
// convert html to text/plain
@@ -1205,28 +1200,15 @@
$part->body = $MESSAGE->get_part_content($part->mime_id);
}
- $body = $part->body;
-
- // extract headers from message/rfc822 parts
- if ($part->mimetype == 'message/rfc822') {
- $msgpart = rcube_mime::parse_message($part->body);
- $body = rcube_charset::convert($msgpart->body, $msgpart->charset);
-
- if (!empty($msgpart->headers)) {
- $part = $msgpart;
- $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers));
- }
- }
-
// message is cached but not exists (#1485443), or other error
- if ($body === false) {
+ if ($part->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);
+ $body = rcmail_print_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);
--
Gitblit v1.9.1