From 5c26bd49b10a2666df9e4853b0740038b0cc3b88 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 14 Mar 2013 07:10:40 -0400 Subject: [PATCH] Added rcube_message::has_text_part(), simplified has_html_part() so it always works in "recursive mode" - removed $recursive argument. --- program/lib/Roundcube/rcube_message.php | 138 +++++++++++++++++++++++++++++---------------- 1 files changed, 89 insertions(+), 49 deletions(-) diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index 08b94d8..7d58a8e 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -106,7 +106,6 @@ if (!empty($this->headers->structure)) { $this->get_mime_numbers($this->headers->structure); $this->parse_structure($this->headers->structure); - $this->parse_attachments(); } else { $this->body = $this->storage->get_body($uid); @@ -195,39 +194,82 @@ /** - * Determine if the message contains a HTML part + * Determine if the message contains a HTML part. This must to be + * a real part not an attachment (or its part) + * This must to be + * a real part not an attachment (or its part) * - * @param bool $recursive Enables checking in all levels of the structure - * @param bool $enriched Enables checking for text/enriched parts too + * @param bool $enriched Enables checking for text/enriched parts too * * @return bool True if a HTML is available, False if not */ - function has_html_part($recursive = true, $enriched = false) + function has_html_part($enriched = false) { // check all message parts foreach ($this->parts as $part) { if ($part->mimetype == 'text/html' || ($enriched && $part->mimetype == 'text/enriched')) { - // Level check, we'll skip e.g. HTML attachments - if (!$recursive) { - $level = explode('.', $part->mime_id); + // Skip if part is an attachment + if ($this->is_attachment($part)) { + continue; + } - // Skip if level too deep or part has a file name - if (count($level) > 2 || $part->filename) { - continue; + $level = explode('.', $part->mime_id); + + // Check if the part belongs to higher-level's alternative/related + while (array_pop($level) !== null) { + if (!count($level)) { + return true; } - // HTML part can be on the lower level, if not... - if (count($level) > 1) { - array_pop($level); - $parent = $this->mime_parts[join('.', $level)]; - // ... parent isn't multipart/alternative or related - if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') { - continue; - } + $parent = $this->mime_parts[join('.', $level)]; + if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') { + continue 2; } } - return true; + if ($part->size) { + return true; + } + } + } + + return false; + } + + + /** + * Determine if the message contains a text/plain part. This must to be + * a real part not an attachment (or its part) + * + * @return bool True if a plain text part is available, False if not + */ + function has_text_part() + { + // check all message parts + foreach ($this->parts as $part) { + if ($part->mimetype == 'text/plain') { + // Skip if part is an attachment + if ($this->is_attachment($part)) { + continue; + } + + $level = explode('.', $part->mime_id); + + // Check if the part belongs to higher-level's alternative/related + while (array_pop($level) !== null) { + if (!count($level)) { + return true; + } + + $parent = $this->mime_parts[join('.', $level)]; + if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') { + continue 2; + } + } + + if ($part->size) { + return true; + } } } @@ -272,7 +314,7 @@ $out = $this->get_part_content($mime_id); // create instance of html2text class - $txt = new html2text($out); + $txt = new rcube_html2text($out); return $txt->get_text(); } } @@ -322,8 +364,8 @@ $mimetype = $structure->real_mimetype; // parse headers from message/rfc822 part - if (!isset($structure->headers['subject'])) { - list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 4096)); + if (!isset($structure->headers['subject']) && !isset($structure->headers['from'])) { + list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 8192)); $structure->headers = rcube_mime::parse_headers($headers); } } @@ -331,7 +373,7 @@ $mimetype = $structure->mimetype; // show message headers - if ($recursive && is_array($structure->headers) && isset($structure->headers['subject'])) { + if ($recursive && is_array($structure->headers) && (isset($structure->headers['subject']) || isset($structure->headers['from']))) { $c = new stdClass; $c->type = 'headers'; $c->headers = $structure->headers; @@ -351,15 +393,22 @@ // print body if message doesn't have multiple parts if ($message_ctype_primary == 'text' && !$recursive) { + // parts with unsupported type add to attachments list + if (!in_array($message_ctype_secondary, array('plain', 'html', 'enriched'))) { + $this->attachments[] = $structure; + return; + } + $structure->type = 'content'; $this->parts[] = $structure; // Parse simple (plain text) message body - if ($message_ctype_secondary == 'plain') + if ($message_ctype_secondary == 'plain') { foreach ((array)$this->uu_decode($structure) as $uupart) { $this->mime_parts[$uupart->mime_id] = $uupart; $this->attachments[] = $uupart; } + } } // the same for pgp signed messages else if ($mimetype == 'application/pgp' && !$recursive) { @@ -379,7 +428,7 @@ // get html/plaintext parts, other add to attachments list foreach ($structure->parts as $p => $sub_part) { $sub_mimetype = $sub_part->mimetype; - $is_multipart = in_array($sub_mimetype, array('multipart/related', 'multipart/mixed', 'multipart/alternative')); + $is_multipart = preg_match('/^multipart\/(related|relative|mixed|alternative)/', $sub_mimetype); // skip empty text parts if (!$sub_part->size && !$is_multipart) { @@ -459,6 +508,17 @@ $p->ctype_secondary = 'plain'; $p->mimetype = 'text/plain'; $p->realtype = 'multipart/encrypted'; + + $this->parts[] = $p; + } + // this is an S/MIME ecrypted message -> create a plaintext body with the according message + else if ($mimetype == 'application/pkcs7-mime') { + $p = new stdClass; + $p->type = 'content'; + $p->ctype_primary = 'text'; + $p->ctype_secondary = 'plain'; + $p->mimetype = 'text/plain'; + $p->realtype = 'application/pkcs7-mime'; $this->parts[] = $p; } @@ -554,7 +614,7 @@ continue; // part belongs to a related message and is linked - if ($mimetype == 'multipart/related' + if (preg_match('/^multipart\/(related|relative)/', $mimetype) && ($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']); @@ -593,13 +653,13 @@ } // if this was a related part try to resolve references - if ($mimetype == 'multipart/related' && sizeof($this->inline_parts)) { + if (preg_match('/^multipart\/(related|relative)/', $mimetype) && sizeof($this->inline_parts)) { $a_replaces = array(); $img_regexp = '/^image\/(gif|jpe?g|png|tiff|bmp|svg)/'; foreach ($this->inline_parts as $inline_object) { $part_url = $this->get_part_url($inline_object->mime_id, true); - if ($inline_object->content_id) + if (isset($inline_object->content_id)) $a_replaces['cid:'.$inline_object->content_id] = $part_url; if ($inline_object->content_location) { $a_replaces[$inline_object->content_location] = $part_url; @@ -639,26 +699,6 @@ // message is a single part non-text (without filename) else if (preg_match('/application\//i', $mimetype)) { $this->attachments[] = $structure; - } - } - - - /** - * Parse attachment parts - */ - private function parse_attachments() - { - // Attachment must have a name - foreach ($this->attachments as $attachment) { - if (!$attachment->filename) { - $ext = rcube_mime::get_mime_extensions($attachment->mimetype); - $ext = array_shift($ext); - - $attachment->filename = 'Part_' . $attachment->mime_id; - if ($ext) { - $attachment->filename .= '.' . $ext; - } - } } } -- Gitblit v1.9.1