From 08aa031871b030811c4305e5d73b8034315f7c5f Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Tue, 28 Sep 2010 09:30:41 -0400
Subject: [PATCH] - Fix wrong parameter count in fetchHeader() call

---
 program/include/rcube_imap.php |  183 +++++++++++++++++++++++++++------------------
 1 files changed, 111 insertions(+), 72 deletions(-)

diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 55b0820..c32d682 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -4,8 +4,8 @@
  +-----------------------------------------------------------------------+
  | program/include/rcube_imap.php                                        |
  |                                                                       |
- | This file is part of the RoundCube Webmail client                     |
- | Copyright (C) 2005-2010, RoundCube Dev. - Switzerland                 |
+ | This file is part of the Roundcube Webmail client                     |
+ | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -138,9 +138,10 @@
         // write error log
         else if ($this->conn->error) {
             $this->error_code = $this->conn->errornum;
-            raise_error(array('code' => 403, 'type' => 'imap',
-                'file' => __FILE__, 'line' => __LINE__,
-                'message' => $this->conn->error), true, false);
+            if ($pass && $user)
+                raise_error(array('code' => 403, 'type' => 'imap',
+                    'file' => __FILE__, 'line' => __LINE__,
+                    'message' => $this->conn->error), true, false);
         }
 
         return false;
@@ -155,8 +156,7 @@
      */
     function close()
     {
-        if ($this->conn && $this->conn->connected())
-            $this->conn->close();
+        $this->conn->close();
         $this->write_cache();
     }
 
@@ -1295,8 +1295,10 @@
         $all_ids = array();
         foreach($msg_index as $root) {
             $all_ids[] = $root;
-            if (!empty($thread_tree[$root]))
-                $all_ids = array_merge($all_ids, array_keys_recursive($thread_tree[$root]));
+            if (!empty($thread_tree[$root])) {
+                foreach (array_keys_recursive($thread_tree[$root]) as $val)
+                    $all_ids[] = $val;
+            }
         }
 
         return $all_ids;
@@ -1347,8 +1349,8 @@
 
         // fetch complete headers and add to cache
         if (!empty($for_update)) {
-            if ($headers = $this->conn->fetchHeader($mailbox,
-                    join(',', $for_update), false, $this->fetch_add_headers)) {
+            if ($headers = $this->conn->fetchHeaders($mailbox,
+                    join(',', $for_update), false, false, $this->fetch_add_headers)) {
                 foreach ($headers as $header) {
                     $this->add_message_cache($cache_key, $header->id, $header, NULL,
                         in_array($header->uid, (array)$for_remove));
@@ -1702,14 +1704,22 @@
         else
             $this->struct_charset = $this->_structure_charset($structure);
 
+        $headers->ctype = strtolower($headers->ctype);
+
         // Here we can recognize malformed BODYSTRUCTURE and
         // 1. [@TODO] parse the message in other way to create our own message structure
         // 2. or just show the raw message body.
         // Example of structure for malformed MIME message:
-        // ("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 2154 70 NIL NIL NIL)
-        if ($headers->ctype && $headers->ctype != 'text/plain'
-            && $structure[0] == 'text' && $structure[1] == 'plain') {
-            return false;
+        // ("text" "plain" NIL NIL NIL "7bit" 2154 70 NIL NIL NIL)
+        if ($headers->ctype && !is_array($structure[0]) && $headers->ctype != 'text/plain'
+            && strtolower($structure[0].'/'.$structure[1]) == 'text/plain') {
+            // we can handle single-part messages, by simple fix in structure (#1486898)
+            if (preg_match('/^(text|application)\/(.*)/', $headers->ctype, $m)) {
+                $structure[0] = $m[1];
+                $structure[1] = $m[2];
+            }
+            else
+                return false;
         }
 
         $struct = &$this->_structure_part($structure);
@@ -1736,7 +1746,7 @@
      *
      * @access private
      */
-    function &_structure_part($part, $count=0, $parent='', $mime_headers=null, $raw_headers=null)
+    function &_structure_part($part, $count=0, $parent='', $mime_headers=null)
     {
         $struct = new rcube_message_part;
         $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count";
@@ -1744,6 +1754,18 @@
         // multipart
         if (is_array($part[0])) {
             $struct->ctype_primary = 'multipart';
+
+        /* RFC3501: BODYSTRUCTURE fields of multipart part
+            part1 array
+            part2 array
+            part3 array
+            ....
+            1. subtype
+            2. parameters (optional)
+            3. description (optional)
+            4. language (optional)
+            5. location (optional)
+        */
 
             // find first non-array entry
             for ($i=1; $i<count($part); $i++) {
@@ -1756,19 +1778,18 @@
             $struct->mimetype = 'multipart/'.$struct->ctype_secondary;
 
             // build parts list for headers pre-fetching
-            for ($i=0, $count=0; $i<count($part); $i++) {
-                if (is_array($part[$i]) && count($part[$i]) > 3) {
-                    // fetch message headers if message/rfc822
-                    // or named part (could contain Content-Location header)
-                    if (!is_array($part[$i][0])) {
-                        $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
-                        if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
-                            $raw_part_headers[] = $tmp_part_id;
-                            $mime_part_headers[] = $tmp_part_id;
-                        }
-                        else if (in_array('name', (array)$part[$i][2]) && (empty($part[$i][3]) || $part[$i][3]=='NIL')) {
-                            $mime_part_headers[] = $tmp_part_id;
-                        }
+            for ($i=0; $i<count($part); $i++) {
+                if (!is_array($part[$i]))
+                    break;
+                // fetch message headers if message/rfc822
+                // or named part (could contain Content-Location header)
+                if (!is_array($part[$i][0])) {
+                    $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
+                    if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
+                        $mime_part_headers[] = $tmp_part_id;
+                    }
+                    else if (in_array('name', (array)$part[$i][2]) && (empty($part[$i][3]) || $part[$i][3]=='NIL')) {
+                        $mime_part_headers[] = $tmp_part_id;
                     }
                 }
             }
@@ -1780,22 +1801,39 @@
                 $mime_part_headers = $this->conn->fetchMIMEHeaders($this->mailbox,
                     $this->_msg_id, $mime_part_headers);
             }
-            // we'll need a real content-type of message/rfc822 part
-            if ($raw_part_headers) {
-                $raw_part_headers = $this->conn->fetchMIMEHeaders($this->mailbox,
-                    $this->_msg_id, $raw_part_headers, false);
-            }
+
             $struct->parts = array();
             for ($i=0, $count=0; $i<count($part); $i++) {
-                if (is_array($part[$i]) && count($part[$i]) > 3) {
-                    $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
-                    $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id,
-                    $mime_part_headers[$tmp_part_id], $raw_part_headers[$tmp_part_id]);
-                }
+                if (!is_array($part[$i]))
+                    break;
+                $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
+                $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id,
+                    $mime_part_headers[$tmp_part_id]);
             }
 
             return $struct;
         }
+
+        /* RFC3501: BODYSTRUCTURE fields of non-multipart part
+            0. type
+            1. subtype
+            2. parameters
+            3. id
+            4. description
+            5. encoding
+            6. size
+          -- text
+            7. lines
+          -- message/rfc822
+            7. envelope structure
+            8. body structure
+            9. lines
+          --
+            x. md5 (optional)
+            x. disposition (optional)
+            x. language (optional)
+            x. location (optional)
+        */
 
         // regular part
         $struct->ctype_primary = strtolower($part[0]);
@@ -1823,9 +1861,11 @@
             $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)) {
+        $di = 8;
+        if ($struct->ctype_primary == 'text') $di += 1;
+        else if ($struct->mimetype == 'message/rfc822') $di += 3;
+
+        if (is_array($part[$di]) && count($part[$di]) == 2) {
             $struct->disposition = strtolower($part[$di][0]);
 
             if (is_array($part[$di][1]))
@@ -1833,12 +1873,14 @@
                     $struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n+1];
         }
 
-        // get child parts
+        // get message/rfc822's child-parts
         if (is_array($part[8]) && $di != 8) {
             $struct->parts = array();
-            for ($i=0, $count=0; $i<count($part[8]); $i++)
-                if (is_array($part[8][$i]) && count($part[8][$i]) > 5)
-                    $struct->parts[] = $this->_structure_part($part[8][$i], ++$count, $struct->mime_id);
+            for ($i=0, $count=0; $i<count($part[8]); $i++) {
+                if (!is_array($part[8][$i]))
+                    break;
+                $struct->parts[] = $this->_structure_part($part[8][$i], ++$count, $struct->mime_id);
+            }
         }
 
         // get part ID
@@ -1858,24 +1900,24 @@
             }
             $struct->headers = $this->_parse_headers($mime_headers) + $struct->headers;
 
-            // get real headers for message of type 'message/rfc822'
+            // get real content-type of message/rfc822
             if ($struct->mimetype == 'message/rfc822') {
-                if (empty($raw_headers)) {
-                    $raw_headers = $this->conn->fetchMIMEHeaders(
-                        $this->mailbox, $this->_msg_id, (array)$struct->mime_id, false);
-                }
-                $struct->real_headers = $this->_parse_headers($raw_headers);
-
-                // get real content-type of message/rfc822
-                if (preg_match('/^([a-z0-9_\/-]+)/i', $struct->real_headers['content-type'], $matches)) {
-                    $struct->real_mimetype = strtolower($matches[1]);
+                // single-part
+                if (!is_array($part[8][0]))
+                    $struct->real_mimetype = strtolower($part[8][0] . '/' . $part[8][1]);
+                // multi-part
+                else {
+                    for ($n=0; $n<count($part[8]); $n++)
+                        if (!is_array($part[8][$n]))
+                            break;
+                    $struct->real_mimetype = 'multipart/' . strtolower($part[8][$n]);
                 }
             }
-        }
 
-        if ($struct->ctype_primary=='message') {
-            if (is_array($part[8]) && $di != 8 && empty($struct->parts))
-                $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id);
+            if ($struct->ctype_primary == 'message' && empty($struct->parts)) {
+                if (is_array($part[8]) && $di != 8)
+                    $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id);
+            }
         }
 
         // normalize filename property
@@ -2061,7 +2103,7 @@
             return true;
 
         // convert charset (if text or message part)
-        if ($o_part->ctype_primary == 'text' || $o_part->ctype_primary == 'message') {
+        if ($body && ($o_part->ctype_primary == 'text' || $o_part->ctype_primary == 'message')) {
             // assume default if no charset specified
             if (empty($o_part->charset) || strtolower($o_part->charset) == 'us-ascii')
                 $o_part->charset = $this->default_charset;
@@ -2197,11 +2239,8 @@
 
         // make sure mailbox exists
         if ($this->mailbox_exists($mbox_name, true)) {
-            if ($is_file) {
-                $separator = rcmail::get_instance()->config->header_delimiter();
-                $saved = $this->conn->appendFromFile($mailbox, $message,
-                    $headers, $separator.$separator);
-            }
+            if ($is_file)
+                $saved = $this->conn->appendFromFile($mailbox, $message, $headers);
             else
                 $saved = $this->conn->append($mailbox, $message);
         }
@@ -2587,7 +2626,7 @@
         $a_defaults = $a_out = array();
 
         // Give plugins a chance to provide a list of mailboxes
-        $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',
+        $data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list',
             array('root' => $root, 'filter' => $filter, 'mode' => 'LSUB'));
 
         if (isset($data['folders'])) {
@@ -2618,7 +2657,7 @@
     function list_unsubscribed($root='', $filter='*')
     {
         // Give plugins a chance to provide a list of mailboxes
-        $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',
+        $data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list',
             array('root' => $root, 'filter' => $filter, 'mode' => 'LIST'));
 
         if (isset($data['folders'])) {
@@ -2628,7 +2667,7 @@
             // retrieve list of folders from IMAP server
             $a_mboxes = $this->conn->listMailboxes($this->mod_mailbox($root), $filter);
         }
-        
+
         $a_folders = array();
         if (!is_array($a_mboxes))
             $a_mboxes = array();
@@ -3154,7 +3193,7 @@
                 // featch headers if unserialize failed
                 if (empty($this->cache[$cache_key][$uid]))
                     $this->cache[$cache_key][$uid] = $this->conn->fetchHeader(
-                            preg_replace('/.msg$/', '', $key), $uid, true, $this->fetch_add_headers);
+                            preg_replace('/.msg$/', '', $key), $uid, true, false, $this->fetch_add_headers);
             }
         }
 
@@ -3387,7 +3426,7 @@
             $name = trim($val['name']);
 
             if (preg_match('/^[\'"]/', $name) && preg_match('/[\'"]$/', $name))
-                $name = preg_replace(array('/^[\'"]/', '/[\'"]$/'), '', $name);
+                $name = trim($name, '\'"');
 
             if ($name && $address && $name != $address)
                 $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address);
@@ -3419,7 +3458,7 @@
     function decode_header($input, $remove_quotes=false)
     {
         $str = rcube_imap::decode_mime_string((string)$input, $this->default_charset);
-        if ($str{0}=='"' && $remove_quotes)
+        if ($str[0] == '"' && $remove_quotes)
             $str = str_replace('"', '', $str);
 
         return $str;

--
Gitblit v1.9.1