From cb1715cd165b5f0883d96e6350239f74fdb76a58 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 04 Jul 2013 07:37:45 -0400 Subject: [PATCH] Fix handling of message/rfc822 attachments on message forward and edit (#1489214) --- program/steps/mail/compose.inc | 118 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 87 insertions(+), 31 deletions(-) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 36c6d96..329f63e 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -143,7 +143,7 @@ $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); // default font for HTML editor -$font = rcube_fontdefs($RCMAIL->config->get('default_font', 'Verdana')); +$font = rcube_fontdefs($RCMAIL->config->get('default_font')); if ($font && !is_array($font)) { $OUTPUT->set_env('default_font', $font); } @@ -219,10 +219,10 @@ $COMPOSE['param']['sent_mbox'] = $sent_folder; } } - else if ($compose_mode == RCUBE_COMPOSE_DRAFT) { - if ($MESSAGE->headers->others['x-draft-info']) { + else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { + if ($compose_mode == RCUBE_COMPOSE_DRAFT && ($draft_info = $MESSAGE->headers->get('x-draft-info'))) { // get reply_uid/forward_uid to flag the original message when sending - $info = rcmail_draftinfo_decode($MESSAGE->headers->others['x-draft-info']); + $info = rcmail_draftinfo_decode($draft_info); if ($info['type'] == 'reply') $COMPOSE['reply_uid'] = $info['uid']; @@ -239,10 +239,10 @@ } } - if ($MESSAGE->headers->in_reply_to) - $COMPOSE['reply_msgid'] = '<'.$MESSAGE->headers->in_reply_to.'>'; + if ($in_reply_to = $MESSAGE->headers->get('in-reply-to')) + $COMPOSE['reply_msgid'] = '<' . $in_reply_to . '>'; - $COMPOSE['references'] = $MESSAGE->headers->references; + $COMPOSE['references'] = $MESSAGE->headers->references; } } else { @@ -327,6 +327,20 @@ $fvalue .= $v; if ($v = $MESSAGE->headers->cc) $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + // Use Sender header (#1489011) + if (($v = $MESSAGE->headers->get('Sender', false)) && strpos($v, '-bounces@') === false) + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + + // When To: and Reply-To: are the same we add From: address to the list (#1489037) + if ($v = $MESSAGE->headers->from) { + $from = rcube_mime::decode_address_list($v, null, false, $MESSAGE->headers->charset, true); + $to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $MESSAGE->headers->charset, true); + $replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $MESSAGE->headers->charset, true); + + if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) { + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + } + } } } else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { @@ -386,7 +400,7 @@ { global $MESSAGE; - list($form_start, $form_end) = get_form_tags($attrib); + list($form_start,) = get_form_tags($attrib); $out = ''; $part = strtolower($attrib['part']); @@ -450,7 +464,7 @@ function rcmail_compose_header_from($attrib) { - global $MESSAGE, $OUTPUT, $RCMAIL, $compose_mode; + global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode; // pass the following attributes to the form class $field_attrib = array('name' => '_from'); @@ -461,6 +475,7 @@ if (count($MESSAGE->identities)) { $a_signatures = array(); + $identities = array(); $separator = intval($RCMAIL->config->get('reply_mode')) > 0 && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; @@ -498,12 +513,21 @@ $a_signatures[$identity_id]['text'] = $text; $a_signatures[$identity_id]['html'] = $html; } + + // add bcc and reply-to + if (!empty($sql_arr['reply-to'])) { + $identities[$identity_id]['replyto'] = $sql_arr['reply-to']; + } + if (!empty($sql_arr['bcc'])) { + $identities[$identity_id]['bcc'] = $sql_arr['bcc']; + } } $out = $select_from->show($MESSAGE->compose['from']); // add signatures to client $OUTPUT->set_env('signatures', $a_signatures); + $OUTPUT->set_env('identities', $identities); } // no identities, display text input field else { @@ -553,7 +577,7 @@ function rcmail_prepare_message_body() { - global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $LINE_LENGTH, $HTML_MODE; + global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE; // use posted message body if (!empty($_POST['_message'])) { @@ -571,14 +595,31 @@ rcmail_write_forward_attachments(); } // reply/edit/draft/forward - else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || $RCMAIL->config->get('reply_mode') != -1)) { - $isHtml = rcmail_compose_editor_mode(); + else if ($compose_mode && ($compose_mode != RCUBE_COMPOSE_REPLY || intval($RCMAIL->config->get('reply_mode')) != -1)) { + $isHtml = rcmail_compose_editor_mode(); + $messages = array(); 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->parts as $part) { // skip no-content and attachment parts (#1488557) if ($part->type != 'content' || !$part->size || $MESSAGE->is_attachment($part)) { continue; + } + + // skip all content parts inside the message/rfc822 part in DRAFT/EDIT mode + foreach ($messages as $mimeid) { + if (strpos($part->mime_id, $mimeid . '.') === 0) { + continue 2; + } } if ($part_body = rcmail_compose_part_body($part, $isHtml)) { @@ -626,7 +667,7 @@ function rcmail_compose_part_body($part, $isHtml = false) { - global $RCMAIL, $MESSAGE, $compose_mode; + global $RCMAIL, $MESSAGE, $LINE_LENGTH, $compose_mode; // Check if we have enough memory to handle the message in it // #1487424: we need up to 10x more memory than the body @@ -663,6 +704,11 @@ $body = rcmail_remove_signature($body); } } + + if ($part->ctype_parameters['format'] == 'flowed') { + $body = rcube_mime::unfold_flowed($body); + } + // add HTML formatting $body = rcmail_plain_body($body); if ($body) { @@ -702,7 +748,7 @@ function rcmail_compose_body($attrib) { - global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $LINE_LENGTH, $HTML_MODE, $MESSAGE_BODY; + global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $HTML_MODE, $MESSAGE_BODY; list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); @@ -886,8 +932,7 @@ if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); - $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); - $charset = $RCMAIL->output->get_charset(); + $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); if (!$bodyIsHtml) { $prefix = "\n\n\n-------- " . rcube_label('originalmessage') . " --------\n"; @@ -941,7 +986,7 @@ function rcmail_create_draft_body($body, $bodyIsHtml) { - global $MESSAGE, $OUTPUT, $COMPOSE; + global $MESSAGE, $COMPOSE; /** * add attachments @@ -989,11 +1034,13 @@ global $RCMAIL, $COMPOSE, $compose_mode; $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $id => $attachment) { + foreach ((array)$COMPOSE['attachments'] as $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; } - $cid_map = $messages = array(); + $cid_map = array(); + $messages = array(); + foreach ((array)$message->mime_parts as $pid => $part) { if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) { @@ -1005,25 +1052,32 @@ if ($part->ctype_primary == 'message' && $compose_mode == RCUBE_COMPOSE_REPLY) { continue; } - // skip inline images when forwarding in plain text - if ($part->content_id && !$bodyIsHtml && $compose_mode == RCUBE_COMPOSE_FORWARD) { + // skip inline images when forwarding in text mode + if ($part->content_id && $part->disposition == 'inline' && !$bodyIsHtml && $compose_mode == RCUBE_COMPOSE_FORWARD) { continue; } - $skip = false; + // 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 ($messages) { + } + 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) { - $skip = true; - break; + if (strpos($part->mime_id, $mimeid . '.') === 0) { + continue 2; } } - if (!$skip && (($attachment = $loaded_attachments[rcmail_attachment_name($part) . $part->mimetype]) - || ($attachment = rcmail_save_attachment($message, $pid)))) { + if (($attachment = $loaded_attachments[rcmail_attachment_name($part) . $part->mimetype]) + || ($attachment = rcmail_save_attachment($message, $pid))) { $COMPOSE['attachments'][$attachment['id']] = $attachment; if ($bodyIsHtml && ($part->content_id || $part->content_location)) { $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', @@ -1076,7 +1130,7 @@ $names = array(); $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $id => $attachment) { + foreach ((array)$COMPOSE['attachments'] as $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; } @@ -1211,10 +1265,11 @@ // handle attachments in memory $data = file_get_contents($path); + $name = rcmail_basename($path); $attachment = array( 'group' => $COMPOSE['id'], - 'name' => rcmail_basename($path), + 'name' => $name, 'mimetype' => $mimetype ? $mimetype : rc_mime_content_type($path, $name), 'data' => $data, 'size' => strlen($data), @@ -1484,7 +1539,7 @@ $select->add(Q(rcube_label('plaintoggle')), 'plain'); return $select->show($useHtml ? 'html' : 'plain'); - +/* foreach ($choices as $value => $text) { $attrib['id'] = '_' . $value; $attrib['value'] = $value; @@ -1492,6 +1547,7 @@ } return $selector; +*/ } -- Gitblit v1.9.1