From 58993ffcbbfb8b362ebf9d088125fb73d7f6cbed Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Wed, 13 Mar 2013 06:04:09 -0400
Subject: [PATCH] Fix HTML part detection for some specific message structures (#1488992)

---
 program/lib/Roundcube/rcube_message.php |   67 ++++++++++++++++-----------------
 1 files changed, 33 insertions(+), 34 deletions(-)

diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php
index 08b94d8..6160c65 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);
@@ -211,18 +210,20 @@
                 if (!$recursive) {
                     $level = explode('.', $part->mime_id);
 
-                    // Skip if level too deep or part has a file name
-                    if (count($level) > 2 || $part->filename) {
+                    // Skip if part is an attachment
+                    if ($this->is_attachment($part)) {
                         continue;
                     }
 
-                    // HTML part can be on the lower level, if not...
-                    if (count($level) > 1) {
-                        array_pop($level);
+                    // 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)];
-                        // ... parent isn't multipart/alternative or related
                         if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') {
-                            continue;
+                            continue 2;
                         }
                     }
                 }
@@ -272,7 +273,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();
             }
         }
@@ -323,7 +324,7 @@
 
             // 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));
+                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);
             }
         }
@@ -351,15 +352,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 +387,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 +467,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 +573,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,7 +612,7 @@
             }
 
             // 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)/';
 
@@ -639,26 +658,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