diff options
-rw-r--r-- | CHANGELOG | 8 | ||||
-rw-r--r-- | program/include/rcube_imap.inc | 90 | ||||
-rw-r--r-- | program/lib/html2text.inc | 10 | ||||
-rw-r--r-- | program/steps/mail/compose.inc | 17 | ||||
-rw-r--r-- | program/steps/mail/func.inc | 45 | ||||
-rw-r--r-- | program/steps/mail/get.inc | 8 | ||||
-rw-r--r-- | skins/default/mail.css | 7 |
7 files changed, 99 insertions, 86 deletions
@@ -1,6 +1,14 @@ CHANGELOG RoundCube Webmail --------------------------- +2007/03/19 (thomasb) +---------- +- Don't download HTML message parts +- Convert HTML parts to plaintext if 'prefer_html' is off +- Correctly parse message/rfc822 parts (closes #1484045) +- Code cleanup + + 2007/03/18 (thomasb) ---------- - Also use user_id for unique key in messages table (closes #1484074) diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc index f8e9e0a0a..3463ae21b 100644 --- a/program/include/rcube_imap.inc +++ b/program/include/rcube_imap.inc @@ -988,10 +988,10 @@ class rcube_imap if (!($msg_id = $this->_uid2id($uid))) return FALSE; - $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); - $structure = iml_GetRawStructureArray($structure_str); - $struct = false; - + $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); + $structure = iml_GetRawStructureArray($structure_str); + $struct = false; + // parse structure and add headers if (!empty($structure)) { @@ -1013,9 +1013,9 @@ class rcube_imap if ($this->caching_enabled) $this->add_message_cache($cache_key, $msg_id, $headers, $struct); } - - return $struct; - } + + return $struct; + } /** @@ -1047,8 +1047,8 @@ class rcube_imap for ($i=0, $count=0; $i<count($part); $i++) if (is_array($part[$i]) && count($part[$i]) > 5) $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id); - - return $struct; + + return $struct; } @@ -1056,30 +1056,30 @@ class rcube_imap $struct->ctype_primary = strtolower($part[0]); $struct->ctype_secondary = strtolower($part[1]); $struct->mimetype = $struct->ctype_primary.'/'.$struct->ctype_secondary; - + // read content type parameters - if (is_array($part[2])) - { - $struct->ctype_parameters = array(); + if (is_array($part[2])) + { + $struct->ctype_parameters = array(); for ($i=0; $i<count($part[2]); $i+=2) $struct->ctype_parameters[strtolower($part[2][$i])] = $part[2][$i+1]; if (isset($struct->ctype_parameters['charset'])) $struct->charset = $struct->ctype_parameters['charset']; - } - - // read content encoding - if (!empty($part[5]) && $part[5]!='NIL') - { - $struct->encoding = strtolower($part[5]); - $struct->headers['content-transfer-encoding'] = $struct->encoding; - } - - // get part size - if (!empty($part[6]) && $part[6]!='NIL') - $struct->size = intval($part[6]); - - // read part disposition + } + + // read content encoding + if (!empty($part[5]) && $part[5]!='NIL') + { + $struct->encoding = strtolower($part[5]); + $struct->headers['content-transfer-encoding'] = $struct->encoding; + } + + // get part size + if (!empty($part[6]) && $part[6]!='NIL') + $struct->size = intval($part[6]); + + // read part disposition $di = count($part) - 2; if ((is_array($part[$di]) && count($part[$di]) == 2 && is_array($part[$di][1])) || (is_array($part[--$di]) && count($part[$di]) == 2)) @@ -1099,25 +1099,36 @@ class rcube_imap if (is_array($part[8][$i]) && count($part[8][$i]) > 5) $struct->parts[] = $this->_structure_part($part[8][$i], ++$count, $struct->mime_id); } - - // get part ID - if (!empty($part[3]) && $part[3]!='NIL') - { - $struct->content_id = $part[3]; - $struct->headers['content-id'] = $part[3]; - - if (empty($struct->disposition)) - $struct->disposition = 'inline'; - } + + // get part ID + if (!empty($part[3]) && $part[3]!='NIL') + { + $struct->content_id = $part[3]; + $struct->headers['content-id'] = $part[3]; + + if (empty($struct->disposition)) + $struct->disposition = 'inline'; + } // fetch message headers if message/rfc822 if ($struct->ctype_primary=='message') { $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER'); $struct->headers = $this->_parse_headers($headers); + + if (is_array($part[8]) && empty($struct->parts)) + $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id); } - - return $struct; + + // normalize filename property + if (!empty($struct->d_parameters['filename'])) + $struct->filename = $this->decode_mime_string($struct->d_parameters['filename']); + else if (!empty($struct->ctype_parameters['name'])) + $struct->filename = $this->decode_mime_string($struct->ctype_parameters['name']); + else if (!empty($struct->headers['content-description'])) + $struct->filename = $this->decode_mime_string($struct->headers['content-description']); + + return $struct; } @@ -2510,6 +2521,7 @@ class rcube_message_part var $ctype_secondary = 'plain'; var $mimetype = 'text/plain'; var $disposition = ''; + var $filename = ''; var $encoding = '8bit'; var $charset = ''; var $size = 0; diff --git a/program/lib/html2text.inc b/program/lib/html2text.inc index eabe15c69..0ac72f7b3 100644 --- a/program/lib/html2text.inc +++ b/program/lib/html2text.inc @@ -112,7 +112,7 @@ class html2text "/[\n\t]+/", // Newlines and tabs '/<script[^>]*>.*?<\/script>/i', // <script>s -- which strip_tags supposedly has problems with //'/<!-- .* -->/', // Comments -- which strip_tags might have problem a with - '/<a href="([^"]+)"[^>]*>(.+?)<\/a>/ie', // <a href=""> + '/<a [^>]*href="([^"]+)"[^>]*>(.+?)<\/a>/ie', // <a href=""> '/<h[123][^>]*>(.+?)<\/h[123]>/ie', // H1 - H3 '/<h[456][^>]*>(.+?)<\/h[456]>/ie', // H4 - H6 '/<p[^>]*>/i', // <P> @@ -160,11 +160,11 @@ class html2text '', // Non-legal carriage return ' ', // Newlines and tabs '', // <script>s -- which strip_tags supposedly has problems with - //'', // Comments -- which strip_tags might have problem a with + //'', // Comments -- which strip_tags might have problem a with '$this->_build_link_list("\\1", "\\2")', // <a href=""> "strtoupper(\"\n\n\\1\n\n\")", // H1 - H3 - "ucwords(\"\n\n\\1\n\n\")", // H4 - H6 - "\n", // <P> + "ucwords(\"\n\n\\1\n\")", // H4 - H6 + "\n\n", // <P> "\n", // <br> 'strtoupper("\\1")', // <b> '_\\1_', // <i> @@ -255,7 +255,7 @@ class html2text * @access public * @return void */ - function html2text( $source = '', $from_file = false, $do_link_table = true ) + function html2text( $source = '', $from_file = false, $produce_link_table = true ) { if ( !empty($source) ) { $this->set_html($source, $from_file); diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 1c2639d9b..a794e9814 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -401,8 +401,8 @@ function rcmail_compose_body($attrib) $body = rcmail_first_text_part($MESSAGE); $isHtml = false; } - if (strlen($body)) - $body = rcmail_create_forward_body($body, $isHtml); + + $body = rcmail_create_forward_body($body, $isHtml); } else if ($compose_mode == RCUBE_COMPOSE_DRAFT) { @@ -564,10 +564,9 @@ function rcmail_create_forward_body($body, $bodyIsHtml) } // add attachments - if (!isset($_SESSION['compose']['forward_attachments']) && - is_array($MESSAGE['parts']) && sizeof($MESSAGE['parts'])>1) + if (!isset($_SESSION['compose']['forward_attachments']) && is_array($MESSAGE['parts'])) rcmail_write_compose_attachments($MESSAGE); - + return $prefix.$body; } @@ -598,7 +597,7 @@ function rcmail_write_compose_attachments(&$message) { if ($part->ctype_primary != 'message' && $part->ctype_primary != 'text' && ($part->disposition=='attachment' || $part->disposition=='inline' || $part->headers['content-id'] || - (empty($part->disposition) && ($part->d_parameters['filename'] || $part->ctype_parameters['name'])))) + (empty($part->disposition) && $part->filename))) { $tmp_path = tempnam($temp_dir, 'rcmAttmnt'); if ($fp = fopen($tmp_path, 'w')) @@ -606,13 +605,9 @@ function rcmail_write_compose_attachments(&$message) fwrite($fp, $IMAP->get_message_part($message['UID'], $pid, $part->encoding)); fclose($fp); - $filename = !empty($part->d_parameters['filename']) ? $part->d_parameters['filename'] : - (!empty($part->ctype_parameters['name']) ? $part->ctype_parameters['name'] : - (!empty($part->headers['content-description']) ? $part->headers['content-description'] : 'file')); - $_SESSION['compose']['attachments'][] = array( - 'name' => rcube_imap::decode_mime_string($filename), 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, + 'name' => $part->filename, 'path' => $tmp_path ); } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index be9558fe1..e5e4db837 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -727,6 +727,14 @@ function rcmail_print_body($part, $safe=FALSE, $plain=FALSE) $body = is_array($part->replaces) ? strtr($part->body, $part->replaces) : $part->body; + // convert html to text/plain + if ($part->ctype_secondary=='html' && $plain) + { + $txt = new html2text($body, false, true); + $body = $txt->get_text(); + $part->ctype_secondary = 'plain'; + } + // text/html if ($part->ctype_secondary=='html') { @@ -975,7 +983,7 @@ function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE) // part is file/attachment else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] || - (empty($mail_part->disposition) && ($mail_part->d_parameters['filename'] || $mail_part->ctype_parameters['name']))) + (empty($mail_part->disposition) && $mail_part->filename)) { // skip apple resource forks if ($message_ctype_secondary=='appledouble' && $secondary_type=='applefile') @@ -984,18 +992,12 @@ function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE) // part belongs to a related message if ($message_ctype_secondary=='related' && $mail_part->headers['content-id']) { - $mail_part->filename = rcube_imap::decode_mime_string($mail_part->d_parameters['filename']); $mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']); $sa_inline_objects[] = $mail_part; } // is regular attachment - else if (($fname = $mail_part->d_parameters['filename']) || - ($fname = $mail_part->ctype_parameters['name']) || - ($fname = $mail_part->headers['content-description'])) - { - $mail_part->filename = rcube_imap::decode_mime_string($fname); + else if ($mail_part->filename) $a_attachments[] = $mail_part; - } } } @@ -1018,16 +1020,8 @@ function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE) } // message is single part non-text - else - { - if (($fname = $structure->d_parameters['filename']) || - ($fname = $structure->ctype_parameters['name']) || - ($fname = $structure->headers['content-description'])) - { - $structure->filename = rcube_imap::decode_mime_string($fname); - $a_attachments[] = $structure; - } - } + else if ($structure->filename) + $a_attachments[] = $structure; return array($a_return_parts, $a_attachments); } @@ -1136,11 +1130,11 @@ function rcmail_message_body($attrib) if (!isset($part->body)) $part->body = $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part); - $body = rcmail_print_body($part, $safe_mode); + $body = rcmail_print_body($part, $safe_mode, !$CONFIG['prefer_html']); $out .= '<div class="message-part">'; if ($part->ctype_secondary != 'plain') - $out .= rcmail_mod_html_body($body, $attrib['id']); + $out .= rcmail_sanitize_html($body, $attrib['id']); else $out .= $body; @@ -1180,7 +1174,7 @@ function rcmail_message_body($attrib) // modify a HTML message that it can be displayed inside a HTML page -function rcmail_mod_html_body($body, $container_id) +function rcmail_sanitize_html($body, $container_id) { // remove any null-byte characters before parsing $body = preg_replace('/\x00/', '', $body); @@ -1452,22 +1446,19 @@ function rcmail_message_part_controls() $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary')); $out = '<table '. $attrib_str . ">\n"; - $filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name']; - $filesize = $part->size; - if ($filename) { $out .= sprintf('<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n", Q(rcube_label('filename')), - Q(rcube_imap::decode_mime_string($filename)), + Q($part->filename), str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), Q(rcube_label('download'))); } - if ($filesize) + if ($part->size) $out .= sprintf('<tr><td class="title">%s</td><td>%s</td></tr>'."\n", Q(rcube_label('filesize')), - show_bytes($filesize)); + show_bytes($part->size)); $out .= "\n</table>"; diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index 521f47735..11688f125 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -59,16 +59,12 @@ else if ($pid = get_input_value('_part', RCUBE_INPUT_GET)) { $ctype_primary = strtolower($part->ctype_primary); $ctype_secondary = strtolower($part->ctype_secondary); - $mimetype = sprintf('%s/%s', $ctype_primary, $ctype_secondary); - $filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name']; header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Cache-Control: private", false); header("Content-Transfer-Encoding: binary"); - header(sprintf('Content-Disposition: attachment; filename="%s";', - $filename ? rcube_imap::decode_mime_string($filename) : "roundcube.$ctype_secondary")); // send download headers if ($_GET['_download']) @@ -110,6 +106,10 @@ else if ($pid = get_input_value('_part', RCUBE_INPUT_GET)) } else { + header(sprintf('Content-Disposition: %s; filename="%s";', + $part->disposition ? $part->disposition : 'attachment', + $part->filename ? $part->filename : "roundcube.$ctype_secondary")); + // turn off output buffering and print part content $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part->encoding, true); } diff --git a/skins/default/mail.css b/skins/default/mail.css index 4e9c0d7b5..139994167 100644 --- a/skins/default/mail.css +++ b/skins/default/mail.css @@ -628,7 +628,14 @@ table.headers-table width: 100%; background-color: #EBEBEB; table-layout: fixed; +} +#messagebody table.headers-table +{ + width: auto; + margin: 6px 8px; + background-color: #F4F4F4; + border: 1px solid #ccc; } table.headers-table tr td |