Correctly parse message/rfc822; fixed html2text conversion; code cleanup

release-0.6
thomascube 18 years ago
parent 86958f70d2
commit 5cc4b13a0c

@ -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)

@ -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;

@ -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);

@ -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
);
}

@ -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>";

@ -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);
}

@ -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

Loading…
Cancel
Save