From d7a5dfa26abe21aa9216fe862225baa2b5caca3e Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Sat, 19 Jun 2010 14:04:48 -0400
Subject: [PATCH] - Fix dot-atom  expression in e-mail validation regexp (#1486808)

---
 program/include/rcube_imap.php |  645 +++++++++++++++++++++++++++++++--------------------------
 1 files changed, 349 insertions(+), 296 deletions(-)

diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 9facb32..6f3b402 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -26,7 +26,7 @@
  *
  * @package    Mail
  * @author     Thomas Bruederli <roundcube@gmail.com>
- * @author     Aleksander Machniak <alec@alec.pl> 
+ * @author     Aleksander Machniak <alec@alec.pl>
  * @version    2.0
  */
 class rcube_imap
@@ -53,7 +53,7 @@
     private $default_folders = array('INBOX');
     private $icache = array();
     private $cache = array();
-    private $cache_keys = array();  
+    private $cache_keys = array();
     private $cache_changes = array();
     private $uid_id_map = array();
     private $msg_headers = array();
@@ -92,7 +92,7 @@
      */
     function connect($host, $user, $pass, $port=143, $use_ssl=null)
     {
-        // check for Open-SSL support in PHP build
+        // check for OpenSSL support in PHP build
         if ($use_ssl && extension_loaded('openssl'))
             $this->options['ssl_mode'] = $use_ssl == 'imaps' ? 'ssl' : $use_ssl;
         else if ($use_ssl) {
@@ -108,7 +108,7 @@
         do {
             $data = rcmail::get_instance()->plugins->exec_hook('imap_connect',
                 array('host' => $host, 'user' => $user, 'attempt' => ++$attempt));
-            
+
             if (!empty($data['pass']))
                 $pass = $data['pass'];
 
@@ -154,7 +154,7 @@
      * @access public
      */
     function close()
-    {    
+    {
         if ($this->conn && $this->conn->connected())
             $this->conn->close();
         $this->write_cache();
@@ -171,7 +171,7 @@
     {
         $this->close();
         $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl);
-    
+
         // issue SELECT command to restore connection status
         if ($this->mailbox)
             $this->conn->select($this->mailbox);
@@ -201,7 +201,7 @@
 
         $this->root_dir = $root;
         $this->options['rootdir'] = $root;
-    
+
         if (empty($this->delimiter))
             $this->get_hierarchy_delimiter();
     }
@@ -283,7 +283,7 @@
     {
         $this->page_size = (int)$size;
     }
-    
+
 
     /**
      * Save a set of message ids for future message listing methods
@@ -297,7 +297,9 @@
     {
         if (is_array($str) && $msgs == null)
             list($str, $msgs, $charset, $sort_field, $threads) = $str;
-        if ($msgs != null && !is_array($msgs))
+        if ($msgs === false)
+            $msgs = array();
+        else if ($msgs != null && !is_array($msgs))
             $msgs = explode(',', $msgs);
 
         $this->search_string     = $str;
@@ -358,7 +360,7 @@
     function set_threading($enable=false)
     {
         $this->threading = false;
-    
+
         if ($enable) {
             if ($this->get_capability('THREAD=REFS'))
                 $this->threading = 'REFS';
@@ -412,14 +414,15 @@
      * @param  string  Mailbox/folder name
      * @param  string  Mode for count [ALL|THREADS|UNSEEN|RECENT]
      * @param  boolean Force reading from server and update cache
-     * @param  boolean Enables MAXUIDs checking
+     * @param  boolean Enables storing folder status info (max UID/count),
+     *                 required for mailbox_status()
      * @return int     Number of messages
      * @access public
      */
-    function messagecount($mbox_name='', $mode='ALL', $force=false, $maxuid=true)
+    function messagecount($mbox_name='', $mode='ALL', $force=false, $status=true)
     {
         $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox;
-        return $this->_messagecount($mailbox, $mode, $force, $maxuid);
+        return $this->_messagecount($mailbox, $mode, $force, $status);
     }
 
 
@@ -429,7 +432,7 @@
      * @access  private
      * @see     rcube_imap::messagecount()
      */
-    private function _messagecount($mailbox='', $mode='ALL', $force=false, $maxuid=true)
+    private function _messagecount($mailbox='', $mode='ALL', $force=false, $status=true)
     {
         $mode = strtoupper($mode);
 
@@ -443,9 +446,9 @@
             else
                 return count((array)$this->search_set);
         }
-    
+
         $a_mailbox_cache = $this->get_cache('messagecount');
-    
+
         // return cached value
         if (!$force && is_array($a_mailbox_cache[$mailbox]) && isset($a_mailbox_cache[$mailbox][$mode]))
             return $a_mailbox_cache[$mailbox][$mode];
@@ -455,8 +458,10 @@
 
         if ($mode == 'THREADS') {
             $count = $this->_threadcount($mailbox, $msg_count);
-            if ($maxuid)
-                $_SESSION['maxuid'][$mailbox] = $msg_count ? $this->_id2uid($msg_count, $mailbox) : 0;
+            if ($status) {
+                $this->set_folder_stats($mailbox, 'cnt', $msg_count);
+                $this->set_folder_stats($mailbox, 'maxuid', $msg_count ? $this->_id2uid($msg_count, $mailbox) : 0);
+            }
         }
         // RECENT count is fetched a bit different
         else if ($mode == 'RECENT') {
@@ -469,27 +474,26 @@
             // get message count and store in cache
             if ($mode == 'UNSEEN')
                 $search_str .= " UNSEEN";
-
             // get message count using SEARCH
             // not very performant but more precise (using UNDELETED)
-            // disable THREADS for this request
-            $threads = $this->threading;
-            $this->threading = false;
-            $index = $this->_search_index($mailbox, $search_str);
-            $this->threading = $threads;
-      
+            $index = $this->conn->search($mailbox, $search_str);
+
             $count = is_array($index) ? count($index) : 0;
 
-            if ($mode == 'ALL' && $maxuid)
-                $_SESSION['maxuid'][$mailbox] = $index ? $this->_id2uid(max($index), $mailbox) : 0;
+            if ($mode == 'ALL' && $status) {
+                $this->set_folder_stats($mailbox, 'cnt', $count);
+                $this->set_folder_stats($mailbox, 'maxuid', $index ? $this->_id2uid(max($index), $mailbox) : 0);
+            }
         }
         else {
             if ($mode == 'UNSEEN')
                 $count = $this->conn->countUnseen($mailbox);
             else {
                 $count = $this->conn->countMessages($mailbox);
-                if ($maxuid)
-                    $_SESSION['maxuid'][$mailbox] = $count ? $this->_id2uid($count, $mailbox) : 0;
+                if ($status) {
+                    $this->set_folder_stats($mailbox,'cnt', $count);
+                    $this->set_folder_stats($mailbox, 'maxuid', $count ? $this->_id2uid($count, $mailbox) : 0);
+                }
             }
         }
 
@@ -512,13 +516,13 @@
     {
         if (!empty($this->icache['threads']))
             return count($this->icache['threads']['tree']);
-    
+
         list ($thread_tree, $msg_depth, $has_children) = $this->_fetch_threads($mailbox);
-    
+
         $msg_count = count($msg_depth);
 
 //    $this->update_thread_cache($mailbox, $thread_tree, $msg_depth, $has_children);
-        return count($thread_tree);  
+        return count($thread_tree);
     }
 
 
@@ -532,7 +536,7 @@
      * @param   string   Sort order [ASC|DESC]
      * @param   boolean  Number of slice items to extract from result array
      * @return  array    Indexed array with message header objects
-     * @access  public   
+     * @access  public
      */
     function list_headers($mbox_name='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0)
     {
@@ -601,7 +605,7 @@
             else
                 $msg_index = array();
 
-            if ($slice)
+            if ($slice && $msg_index)
                 $msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice);
 
             // fetch reqested headers from server
@@ -647,14 +651,14 @@
         // return empty array if no messages found
         if (!is_array($a_msg_headers) || empty($a_msg_headers))
             return array();
-    
+
         // use this class for message sorting
         $sorter = new rcube_header_sorter();
         $sorter->set_sequence_numbers($msg_index);
         $sorter->sort_headers($a_msg_headers);
 
         if ($this->sort_order == 'DESC')
-            $a_msg_headers = array_reverse($a_msg_headers);	    
+            $a_msg_headers = array_reverse($a_msg_headers);
 
         return array_values($a_msg_headers);
     }
@@ -700,7 +704,7 @@
             // get all threads
             list ($thread_tree, $msg_depth, $has_children) = $this->conn->thread(
                 $mailbox, $this->threading, $this->skip_deleted ? 'UNDELETED' : '');
-   
+
             // add to internal (fast) cache
             $this->icache['threads'] = array();
             $this->icache['threads']['tree'] = $thread_tree;
@@ -749,7 +753,7 @@
         // return empty array if no messages found
         if (!is_array($a_msg_headers) || empty($a_msg_headers))
             return array();
-    
+
         // use this class for message sorting
         $sorter = new rcube_header_sorter();
         $sorter->set_sequence_numbers($all_ids);
@@ -816,9 +820,12 @@
             return $this->_list_thread_header_set($mailbox, $page, $sort_field, $sort_order, $slice);
 
         // search set is threaded, we need a new one
-        if ($this->search_threads)
+        if ($this->search_threads) {
+            if (empty($this->search_set['tree']))
+                return array();
             $this->search('', $this->search_string, $this->search_charset, $sort_field);
-    
+        }
+
         $msgs = $this->search_set;
         $a_msg_headers = array();
         $page = $page ? $page : $this->list_page;
@@ -902,7 +909,7 @@
             else {
                 // for small result set we can fetch all messages headers
                 $this->_fetch_headers($mailbox, join(',', $msgs), $a_msg_headers, NULL);
-    
+
                 // return empty array if no messages found
                 if (!is_array($a_msg_headers) || empty($a_msg_headers))
                     return array();
@@ -939,8 +946,15 @@
     private function _list_thread_header_set($mailbox, $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0)
     {
         // update search_set if previous data was fetched with disabled threading
-        if (!$this->search_threads)
+        if (!$this->search_threads) {
+            if (empty($this->search_set))
+                return array();
             $this->search('', $this->search_string, $this->search_charset, $sort_field);
+        }
+
+        // empty result
+        if (empty($this->search_set['tree']))
+            return array();
 
         $thread_tree = $this->search_set['tree'];
         $msg_depth = $this->search_set['depth'];
@@ -970,7 +984,7 @@
     private function _get_message_range($max, $page)
     {
         $start_msg = ($page-1) * $this->page_size;
-    
+
         if ($page=='all') {
             $begin  = 0;
             $end    = $max;
@@ -987,10 +1001,10 @@
         if ($begin < 0) $begin = 0;
         if ($end < 0) $end = $max;
         if ($end > $max) $end = $max;
-    
+
         return array($begin, $end);
     }
-    
+
 
     /**
      * Fetches message headers
@@ -1032,33 +1046,71 @@
 
         return count($a_msg_headers);
     }
-  
+
+
     /**
-     * Fetches IDS of pseudo recent messages.
+     * Returns current status of mailbox
      *
      * We compare the maximum UID to determine the number of
      * new messages because the RECENT flag is not reliable.
      *
-     * @param string  Mailbox/folder name
-     * @return array  List of recent message UIDs
+     * @param string Mailbox/folder name
+     * @return int   Folder status
      */
-    function recent_uids($mbox_name = null, $nofetch = false)
+    function mailbox_status($mbox_name = null)
     {
         $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox;
-        $old_maxuid = intval($_SESSION['maxuid'][$mailbox]);
-    
-        // refresh message count -> will update $_SESSION['maxuid'][$mailbox]
+        $old = $this->get_folder_stats($mailbox);
+
+        // refresh message count -> will update
         $this->_messagecount($mailbox, 'ALL', true);
-    
-        if ($_SESSION['maxuid'][$mailbox] > $old_maxuid) {
-            $maxuid = max(1, $old_maxuid+1);
-            return array_values((array)$this->conn->fetchHeaderIndex(
-                $mailbox, "$maxuid:*", 'UID', $this->skip_deleted, true));
-        }
-    
-        return array();
+
+        $result = 0;
+        $new = $this->get_folder_stats($mailbox);
+
+        // got new messages
+        if ($new['maxuid'] > $old['maxuid'])
+            $result += 1;
+        // some messages has been deleted
+        if ($new['cnt'] < $old['cnt'])
+            $result += 2;
+
+        // @TODO: optional checking for messages flags changes (?)
+        // @TODO: UIDVALIDITY checking
+
+        return $result;
     }
-  
+
+
+    /**
+     * Stores folder statistic data in session
+     * @TODO: move to separate DB table (cache?)
+     *
+     * @param string Mailbox name
+     * @param string Data name
+     * @param mixed  Data value
+     */
+    private function set_folder_stats($mbox_name, $name, $data)
+    {
+        $_SESSION['folders'][$mbox_name][$name] = $data;
+    }
+
+
+    /**
+     * Gets folder statistic data
+     *
+     * @param string Mailbox name
+     * @return array Stats data
+     */
+    private function get_folder_stats($mbox_name)
+    {
+        if ($_SESSION['folders'][$mbox_name])
+            return (array) $_SESSION['folders'][$mbox_name];
+        else
+            return array();
+    }
+
+
     /**
      * Return sorted array of message IDs (not UIDs)
      *
@@ -1105,7 +1157,7 @@
             else {
                 $a_index = $this->conn->fetchHeaderIndex($mailbox,
 	                join(',', $this->search_set), $this->sort_field, $this->skip_deleted);
-                
+
                 if (is_array($a_index)) {
                     if ($this->sort_order=="ASC")
                         asort($a_index);
@@ -1143,20 +1195,20 @@
                 $a_index = range(1, $max);
             }
 
-            if ($this->sort_order == 'DESC')
+            if ($a_index !== false && $this->sort_order == 'DESC')
                 $a_index = array_reverse($a_index);
 
             $this->cache[$key] = $a_index;
         }
         // fetch complete message index
         else if ($this->get_capability('SORT')) {
-            if ($a_index = $this->conn->sort($mailbox,
-                $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')) {
-                if ($this->sort_order == 'DESC')
-                    $a_index = array_reverse($a_index);
-	
-                $this->cache[$key] = $a_index;
-	        }
+            $a_index = $this->conn->sort($mailbox,
+                $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '');
+
+            if ($a_index !== false && $this->sort_order == 'DESC')
+                $a_index = array_reverse($a_index);
+
+            $this->cache[$key] = $a_index;
         }
         else if ($a_index = $this->conn->fetchHeaderIndex(
             $mailbox, "1:*", $this->sort_field, $this->skip_deleted)) {
@@ -1164,11 +1216,11 @@
                 asort($a_index);
             else if ($this->sort_order=="DESC")
                 arsort($a_index);
-        
+
             $this->cache[$key] = array_keys($a_index);
         }
 
-        return $this->cache[$key];
+        return $this->cache[$key] !== false ? $this->cache[$key] : array();
     }
 
 
@@ -1213,7 +1265,7 @@
         list ($thread_tree) = $this->_fetch_threads($mailbox);
 
         $this->cache[$key] = $this->_flatten_threads($mailbox, $thread_tree);
-    
+
         return $this->cache[$key];
     }
 
@@ -1238,7 +1290,7 @@
 
         if ($this->sort_order == 'DESC')
             $msg_index = array_reverse($msg_index);
-	  
+
         // flatten threads array
         $all_ids = array();
         foreach($msg_index as $root) {
@@ -1261,10 +1313,10 @@
 
         // fetch complete message index
         $a_message_index = $this->conn->fetchHeaderIndex($mailbox, "1:*", 'UID', $this->skip_deleted);
-    
+
         if ($a_message_index === false)
             return false;
-        
+
         foreach ($a_message_index as $id => $uid) {
             // message in cache at correct position
             if ($cache_index[$id] == $uid) {
@@ -1276,20 +1328,20 @@
             if (in_array((string)$uid, $cache_index, true)) {
                 unset($cache_index[$id]);
             }
-      
+
             // other message at this position
             if (isset($cache_index[$id])) {
                 $for_remove[] = $cache_index[$id];
                 unset($cache_index[$id]);
             }
-        
+
             $for_update[] = $id;
         }
 
-        // clear messages at wrong positions and those deleted that are still in cache_index      
+        // clear messages at wrong positions and those deleted that are still in cache_index
         if (!empty($for_remove))
             $cache_index = array_merge($cache_index, $for_remove);
-    
+
         if (!empty($cache_index))
             $this->remove_message_cache($cache_key, $cache_index);
 
@@ -1320,36 +1372,10 @@
     {
         if (!$str)
             return false;
-    
+
         $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox;
 
         $results = $this->_search_index($mailbox, $str, $charset, $sort_field);
-
-        // try search with US-ASCII charset (should be supported by server)
-        // only if UTF-8 search is not supported
-        if (empty($results) && !is_array($results) && !empty($charset) && $charset != 'US-ASCII')
-        {
-            // convert strings to US_ASCII
-            if(preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) {
-                $last = 0; $res = '';
-                foreach($matches[1] as $m)
-                {
-                    $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
-                    $string = substr($str, $string_offset - 1, $m[0]);
-                    $string = rcube_charset_convert($string, $charset, 'US-ASCII');
-                    if (!$string)
-                        continue;
-                    $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
-                    $last = $m[0] + $string_offset - 1;
-                }
-                if ($last < strlen($str))
-                    $res .= substr($str, $last, strlen($str)-$last);
-            }
-            else // strings for conversion not found
-                $res = $str;
-
-            $results = $this->search($mbox_name, $res, NULL, $sort_field);
-        }
 
         $this->set_search_set($str, $results, $charset, $sort_field, (bool)$this->threading);
 
@@ -1372,21 +1398,32 @@
             $criteria = 'UNDELETED '.$criteria;
 
         if ($this->threading) {
-            list ($thread_tree, $msg_depth, $has_children) = $this->conn->thread(
-                $mailbox, $this->threading, $criteria, $charset);
+            $a_messages = $this->conn->thread($mailbox, $this->threading, $criteria, $charset);
 
-            $a_messages = array(
-                'tree' 	=> $thread_tree,
-	            'depth'	=> $msg_depth,
-	            'children' => $has_children
-            );
+            // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
+            // but I've seen that Courier doesn't support UTF-8)
+            if ($a_messages === false && $charset && $charset != 'US-ASCII')
+                $a_messages = $this->conn->thread($mailbox, $this->threading,
+                    $this->convert_criteria($criteria, $charset), 'US-ASCII');
+
+            if ($a_messages !== false) {
+                list ($thread_tree, $msg_depth, $has_children) = $a_messages;
+                $a_messages = array(
+                    'tree' 	=> $thread_tree,
+	                'depth'	=> $msg_depth,
+	                'children' => $has_children
+                );
+            }
         }
         else if ($sort_field && $this->get_capability('SORT')) {
             $charset = $charset ? $charset : $this->default_charset;
             $a_messages = $this->conn->sort($mailbox, $sort_field, $criteria, false, $charset);
 
-            if (!$a_messages)
-	            return array();
+            // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
+            // but I've seen that Courier doesn't support UTF-8)
+            if ($a_messages === false && $charset && $charset != 'US-ASCII')
+                $a_messages = $this->conn->sort($mailbox, $sort_field,
+                    $this->convert_criteria($criteria, $charset), false, 'US-ASCII');
         }
         else {
             if ($orig_criteria == 'ALL') {
@@ -1395,14 +1432,16 @@
             }
             else {
                 $a_messages = $this->conn->search($mailbox,
-                        ($charset ? "CHARSET $charset " : '') . $criteria);
+                    ($charset ? "CHARSET $charset " : '') . $criteria);
 
-	        if (!$a_messages)
-	            return array();
+                // Error, try with US-ASCII (some servers may support only US-ASCII)
+                if ($a_messages === false && $charset && $charset != 'US-ASCII')
+                    $a_messages = $this->conn->search($mailbox,
+                        'CHARSET US-ASCII ' . $this->convert_criteria($criteria, $charset));
 
-            // I didn't found that SEARCH always returns sorted IDs
-            if (!$this->sort_field)
-                sort($a_messages);
+                // I didn't found that SEARCH should return sorted IDs
+	            if (is_array($a_messages) && !$this->sort_field)
+                    sort($a_messages);
             }
         }
 
@@ -1410,10 +1449,10 @@
 //      $a_mailbox_cache = get_cache('messagecount');
 //      $a_mailbox_cache[$mailbox][$criteria] = sizeof($a_messages);
 //      $this->update_cache('messagecount', $a_mailbox_cache);
-        
+
         return $a_messages;
     }
-    
+
 
     /**
      * Direct (real and simple) SEARCH request to IMAP server,
@@ -1429,13 +1468,46 @@
     {
         if (!$str)
             return false;
-    
+
         $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox;
 
         return $this->conn->search($mailbox, $str, $ret_uid);
     }
 
-  
+
+    /**
+     * Converts charset of search criteria string
+     *
+     * @param  string  Search string
+     * @param  string  Original charset
+     * @param  string  Destination charset (default US-ASCII)
+     * @return string  Search string
+     * @access private
+     */
+    private function convert_criteria($str, $charset, $dest_charset='US-ASCII')
+    {
+        // convert strings to US_ASCII
+        if (preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) {
+            $last = 0; $res = '';
+            foreach ($matches[1] as $m) {
+                $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
+                $string = substr($str, $string_offset - 1, $m[0]);
+                $string = rcube_charset_convert($string, $charset, $dest_charset);
+                if (!$string)
+                    continue;
+                $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
+                $last = $m[0] + $string_offset - 1;
+            }
+            if ($last < strlen($str))
+                $res .= substr($str, $last, strlen($str)-$last);
+        }
+        else // strings for conversion not found
+            $res = $str;
+
+        return $res;
+    }
+
+
     /**
      * Sort thread
      *
@@ -1495,7 +1567,7 @@
     {
         if (empty($tree))
             return array();
-    
+
         $index = array_combine(array_values($index), $index);
 
         // assign roots
@@ -1508,7 +1580,7 @@
             }
         }
 
-        $index = array_values($index);  
+        $index = array_values($index);
 
         // create sorted array of roots
         $msg_index = array();
@@ -1538,13 +1610,12 @@
     {
         if (!empty($this->search_string))
             $this->search_set = $this->search('', $this->search_string, $this->search_charset,
+    	        $this->search_sort_field, $this->search_threads);
 
-    	$this->search_sort_field, $this->search_threads);
-      
         return $this->get_search_set();
     }
-  
-  
+
+
     /**
      * Check if the given message ID is part of the current search set
      *
@@ -1567,7 +1638,7 @@
      * Return message headers object of a specific message
      *
      * @param int     Message ID
-     * @param string  Mailbox to read from 
+     * @param string  Mailbox to read from
      * @param boolean True if $id is the message UID
      * @param boolean True if we need also BODYSTRUCTURE in headers
      * @return object Message headers representation
@@ -1589,7 +1660,7 @@
             if ($headers->uid && $headers->id)
                 $this->uid_id_map[$mailbox][$headers->uid] = $headers->id;
 
-            $this->add_message_cache($mailbox.'.msg', $headers->id, $headers, NULL, true);
+            $this->add_message_cache($mailbox.'.msg', $headers->id, $headers, NULL);
         }
 
         return $headers;
@@ -1631,7 +1702,7 @@
         else
             $this->struct_charset = $this->_structure_charset($structure);
 
-        // Here we can recognize malformed BODYSTRUCTURE and 
+        // 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:
@@ -1659,7 +1730,7 @@
         return $struct;
     }
 
-  
+
     /**
      * Build message part object
      *
@@ -1673,7 +1744,7 @@
         // multipart
         if (is_array($part[0])) {
             $struct->ctype_primary = 'multipart';
-      
+
             // find first non-array entry
             for ($i=1; $i<count($part); $i++) {
                 if (!is_array($part[$i])) {
@@ -1681,12 +1752,12 @@
                     break;
                 }
             }
-            
+
             $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) {
+                if (is_array($part[$i]) && count($part[$i]) > 4) {
                     // fetch message headers if message/rfc822
                     // or named part (could contain Content-Location header)
                     if (!is_array($part[$i][0])) {
@@ -1701,7 +1772,7 @@
                     }
                 }
             }
-        
+
             // pre-fetch headers of all parts (in one command for better performance)
             // @TODO: we could do this before _structure_part() call, to fetch
             // headers for parts on all levels
@@ -1716,7 +1787,7 @@
             }
             $struct->parts = array();
             for ($i=0, $count=0; $i<count($part); $i++) {
-                if (is_array($part[$i]) && count($part[$i]) > 3) {
+                if (is_array($part[$i]) && count($part[$i]) > 4) {
                     $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]);
@@ -1736,17 +1807,17 @@
             $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]);
@@ -1761,7 +1832,7 @@
                 for ($n=0; $n<count($part[$di][1]); $n+=2)
                     $struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n+1];
         }
-      
+
         // get child parts
         if (is_array($part[8]) && $di != 8) {
             $struct->parts = array();
@@ -1774,11 +1845,11 @@
         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 or named part (could contain Content-Location header)
         if ($struct->ctype_primary == 'message' || ($struct->ctype_parameters['name'] && !$struct->content_id)) {
             if (empty($mime_headers)) {
@@ -1798,7 +1869,7 @@
                 // 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]);
-                }                                                    
+                }
             }
         }
 
@@ -1812,10 +1883,10 @@
 
         return $struct;
     }
-    
+
 
     /**
-     * Set attachment filename from message part structure 
+     * Set attachment filename from message part structure
      *
      * @access private
      * @param  object rcube_message_part Part object
@@ -1920,10 +1991,10 @@
 
         // decode filename
         if (!empty($filename_mime)) {
-            $part->filename = rcube_imap::decode_mime_string($filename_mime, 
+            $part->filename = rcube_imap::decode_mime_string($filename_mime,
                 $part->charset ? $part->charset : ($this->struct_charset ? $this->struct_charset :
                 rc_detect_encoding($filename_mime, $this->default_charset)));
-        } 
+        }
         else if (!empty($filename_encoded)) {
             // decode filename according to RFC 2231, Section 4
             if (preg_match("/^([^']*)'[^']*'(.*)$/", $filename_encoded, $fmatches)) {
@@ -1949,7 +2020,7 @@
                 return $structure[2][1];
             $structure = $structure[0];
         }
-    } 
+    }
 
 
     /**
@@ -1966,7 +2037,7 @@
     {
         // get part encoding if not provided
         if (!is_object($o_part)) {
-            $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true); 
+            $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true);
             $structure = new rcube_mime_struct();
             // error or message not found
             if (!$structure->loadStructure($structure_str)) {
@@ -1978,7 +2049,7 @@
             $o_part->encoding      = strtolower($structure->getPartEncoding($part));
             $o_part->charset       = $structure->getPartCharset($part);
         }
-      
+
         // TODO: Add caching for message parts
 
         if (!$part) $part = 'TEXT';
@@ -1990,14 +2061,14 @@
             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;
 
             $body = rcube_charset_convert($body, $o_part->charset);
         }
-    
+
         return $body;
     }
 
@@ -2039,13 +2110,13 @@
     {
         return $this->conn->fetchPartHeader($this->mailbox, $uid, true);
     }
-    
+
 
     /**
      * Sends the whole message source to stdout
      *
      * @param int  Message UID
-     */ 
+     */
     function print_raw_body($uid)
     {
         $this->conn->handlePartBody($this->mailbox, $uid, true, NULL, NULL, true);
@@ -2294,7 +2365,7 @@
 
             // unset threads internal cache
             unset($this->icache['threads']);
-      
+
             // remove message ids from search set
             if ($this->search_set && $mailbox == $this->mailbox) {
                 // threads are too complicated to just remove messages from set
@@ -2330,21 +2401,21 @@
     {
         $mailbox = !empty($mbox_name) ? $this->mod_mailbox($mbox_name) : $this->mailbox;
         $msg_count = $this->_messagecount($mailbox, 'ALL');
-    
+
         if (!$msg_count) {
             return 0;
         }
-        
+
         $cleared = $this->conn->clearFolder($mailbox);
-      
+
         // make sure the message count cache is cleared as well
         if ($cleared) {
-            $this->clear_message_cache($mailbox.'.msg');      
+            $this->clear_message_cache($mailbox.'.msg');
             $a_mailbox_cache = $this->get_cache('messagecount');
             unset($a_mailbox_cache[$mailbox]);
             $this->update_cache('messagecount', $a_mailbox_cache);
         }
-        
+
         return $cleared;
     }
 
@@ -2375,7 +2446,7 @@
      */
     private function _expunge($mailbox, $clear_cache=true, $uids=NULL)
     {
-        if ($uids && $this->get_capability('UIDPLUS')) 
+        if ($uids && $this->get_capability('UIDPLUS'))
             $a_uids = is_array($uids) ? join(',', $uids) : $uids;
         else
             $a_uids = NULL;
@@ -2386,7 +2457,7 @@
             $this->clear_message_cache($mailbox.'.msg');
             $this->_clear_messagecount($mailbox);
         }
-      
+
         return $result;
     }
 
@@ -2396,7 +2467,7 @@
      *
      * @param mixed  UIDs array or comma-separated list or '*' or '1:*'
      * @param string Mailbox name
-     * @return array Two elements array with UIDs converted to list and ALL flag 
+     * @return array Two elements array with UIDs converted to list and ALL flag
      * @access private
      */
     private function _parse_uids($uids, $mailbox)
@@ -2413,7 +2484,7 @@
                     $uids = $this->conn->fetchUIDs($mailbox, array_keys($this->search_set['depth']));
                 else
                     $uids = $this->conn->fetchUIDs($mailbox, $this->search_set);
-      
+
                 // save ID-to-UID mapping in local cache
                 if (is_array($uids))
                     foreach ($uids as $id => $uid)
@@ -2441,7 +2512,7 @@
      * @param string Mailbox name
      * @return int   Message ID
      */
-    function get_id($uid, $mbox_name=NULL) 
+    function get_id($uid, $mbox_name=NULL)
     {
         $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox;
         return $this->_uid2id($uid, $mailbox);
@@ -2468,7 +2539,7 @@
      * --------------------------------*/
 
     /**
-     * Public method for mailbox listing.
+     * Public method for listing subscribed folders
      *
      * Converts mailbox name with root dir first
      *
@@ -2482,10 +2553,10 @@
         $a_out = array();
         $a_mboxes = $this->_list_mailboxes($root, $filter);
 
-        foreach ($a_mboxes as $mbox_row) {
-            $name = $this->mod_mailbox($mbox_row, 'out');
-            if (strlen($name))
+        foreach ($a_mboxes as $idx => $mbox_row) {
+            if ($name = $this->mod_mailbox($mbox_row, 'out'))
                 $a_out[] = $name;
+            unset($a_mboxes[$idx]);
         }
 
         // INBOX should always be available
@@ -2508,17 +2579,17 @@
      */
     private function _list_mailboxes($root='', $filter='*')
     {
-        $a_defaults = $a_out = array();
-    
-        // get cached folder list    
+        // get cached folder list
         $a_mboxes = $this->get_cache('mailboxes');
         if (is_array($a_mboxes))
             return $a_mboxes;
 
+        $a_defaults = $a_out = array();
+
         // Give plugins a chance to provide a list of mailboxes
         $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',
-            array('root'=>$root,'filter'=>$filter));
-    
+            array('root' => $root, 'filter' => $filter, 'mode' => 'LSUB'));
+
         if (isset($data['folders'])) {
             $a_folders = $data['folders'];
         }
@@ -2526,38 +2597,52 @@
             // retrieve list of folders from IMAP server
             $a_folders = $this->conn->listSubscribed($this->mod_mailbox($root), $filter);
         }
-    
+
         if (!is_array($a_folders) || !sizeof($a_folders))
             $a_folders = array();
 
         // write mailboxlist to cache
         $this->update_cache('mailboxes', $a_folders);
-    
+
         return $a_folders;
     }
 
 
     /**
      * Get a list of all folders available on the IMAP server
-     * 
+     *
      * @param string IMAP root dir
+     * @param string Optional filter for mailbox listing
      * @return array Indexed array with folder names
      */
-    function list_unsubscribed($root='')
+    function list_unsubscribed($root='', $filter='*')
     {
-        static $a_folders;
-    
-        if (is_array($a_folders))
-            return $a_folders;
-      
-        // retrieve list of folders from IMAP server
-        $a_mboxes = $this->conn->listMailboxes($this->mod_mailbox($root), '*');
+        // Give plugins a chance to provide a list of mailboxes
+        $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',
+            array('root' => $root, 'filter' => $filter, 'mode' => 'LIST'));
+
+        if (isset($data['folders'])) {
+            $a_mboxes = $data['folders'];
+        }
+        else {
+            // 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();
 
         // modify names with root dir
-        foreach ($a_mboxes as $mbox_name) {
+        foreach ($a_mboxes as $idx => $mbox_name) {
             if ($name = $this->mod_mailbox($mbox_name, 'out'))
                 $a_folders[] = $name;
+            unset($a_mboxes[$idx]);
         }
+
+        // INBOX should always be available
+        if (!in_array('INBOX', $a_folders))
+            array_unshift($a_folders, 'INBOX');
 
         // filter folders and sort them
         $a_folders = $this->_sort_mailbox_list($a_folders);
@@ -2568,14 +2653,14 @@
     /**
      * Get mailbox quota information
      * added by Nuny
-     * 
+     *
      * @return mixed Quota info or False if not supported
      */
     function get_quota()
     {
         if ($this->get_capability('QUOTA'))
             return $this->conn->getQuota();
-	
+
         return false;
     }
 
@@ -2585,7 +2670,7 @@
      *
      * @param array Mailbox name(s)
      * @return boolean True on success
-     */ 
+     */
     function subscribe($a_mboxes)
     {
         if (!is_array($a_mboxes))
@@ -2622,7 +2707,7 @@
     function create_mailbox($name, $subscribe=false)
     {
         $result = false;
-    
+
         // reduce mailbox name to 100 chars
         $name = substr($name, 0, 100);
         $abs_name = $this->mod_mailbox($name);
@@ -2653,11 +2738,11 @@
         // make absolute path
         $mailbox = $this->mod_mailbox($mbox_name);
         $abs_name = $this->mod_mailbox($name);
-    
+
         // check if mailbox is subscribed
         $a_subscribed = $this->_list_mailboxes();
         $subscribed = in_array($mailbox, $a_subscribed);
-    
+
         // unsubscribe folder
         if ($subscribed)
             $this->conn->unsubscribe($mailbox);
@@ -2667,7 +2752,7 @@
 
         if ($result) {
             $delm = $this->get_hierarchy_delimiter();
-      
+
             // check if mailbox children are subscribed
             foreach ($a_subscribed as $c_subscribed)
                 if (preg_match('/^'.preg_quote($mailbox.$delm, '/').'/', $c_subscribed)) {
@@ -2678,7 +2763,7 @@
 
             // clear cache
             $this->clear_message_cache($mailbox.'.msg');
-            $this->clear_cache('mailboxes');      
+            $this->clear_cache('mailboxes');
         }
 
         // try to subscribe it
@@ -2708,23 +2793,23 @@
             foreach ($a_mboxes as $mbox_name) {
                 $mailbox = $this->mod_mailbox($mbox_name);
                 $sub_mboxes = $this->conn->listMailboxes($this->mod_mailbox(''),
-	            $mbox_name . $this->delimiter . '*');
+	                $mbox_name . $this->delimiter . '*');
 
                 // unsubscribe mailbox before deleting
                 $this->conn->unsubscribe($mailbox);
 
                 // send delete command to server
                 $result = $this->conn->deleteFolder($mailbox);
-                if ($result >= 0) {
+                if ($result) {
                     $deleted = true;
                     $this->clear_message_cache($mailbox.'.msg');
 	            }
-	  
+
                 foreach ($sub_mboxes as $c_mbox) {
                     if ($c_mbox != 'INBOX') {
                         $this->conn->unsubscribe($c_mbox);
                         $result = $this->conn->deleteFolder($c_mbox);
-                        if ($result >= 0) {
+                        if ($result) {
                             $deleted = true;
     	                    $this->clear_message_cache($c_mbox.'.msg');
                         }
@@ -2769,14 +2854,19 @@
             if ($mbox_name == 'INBOX')
                 return true;
 
+            $key = $subscription ? 'subscribed' : 'existing';
+            if (is_array($this->icache[$key]) && in_array($mbox_name, $this->icache[$key]))
+                return true;
+
             if ($subscription) {
-                if ($a_folders = $this->conn->listSubscribed($this->mod_mailbox(''), $mbox_name))
-                    return true;
+                $a_folders = $this->conn->listSubscribed($this->mod_mailbox(''), $mbox_name);
             }
             else {
                 $a_folders = $this->conn->listMailboxes($this->mod_mailbox(''), $mbox_name);
-	
-	        if (is_array($a_folders) && in_array($this->mod_mailbox($mbox_name), $a_folders))
+	        }
+
+            if (is_array($a_folders) && in_array($this->mod_mailbox($mbox_name), $a_folders)) {
+                $this->icache[$key][] = $mbox_name;
                 return true;
             }
         }
@@ -2803,7 +2893,7 @@
             else if (!empty($mbox_name)) // $mode=='out'
                 $mbox_name = substr($mbox_name, strlen($this->root_dir)+1);
         }
-    
+
         return $mbox_name;
     }
 
@@ -2832,7 +2922,7 @@
         if (!count($this->cache) && $this->caching_enabled) {
             return $this->_read_cache_record($key);
         }
-    
+
         return $this->cache[$key];
     }
 
@@ -2866,7 +2956,7 @@
     {
         if (!$this->caching_enabled)
             return;
-    
+
         if ($key===NULL) {
             foreach ($this->cache as $key => $data)
                 $this->_clear_cache_record($key);
@@ -2961,7 +3051,7 @@
             "AND cache_key=?",
             $_SESSION['user_id'],
             'IMAP.'.$key);
-      
+
         unset($this->cache_keys[$key]);
     }
 
@@ -2970,7 +3060,7 @@
     /* --------------------------------
      *   message caching methods
      * --------------------------------*/
-   
+
     /**
      * Checks if the cache is up-to-date
      *
@@ -3017,7 +3107,7 @@
                 // get UID of message with highest index
                 $uid = $this->conn->ID2UID($mailbox, $msg_count);
                 $cache_uid = array_pop($cache_index);
-      
+
                 // uids of highest message matches -> cache seems OK
                 if ($cache_uid == $uid)
                     return 1;
@@ -3038,12 +3128,12 @@
     private function get_message_cache($key, $from, $to, $sort_field, $sort_order)
     {
         $cache_key = "$key:$from:$to:$sort_field:$sort_order";
-    
+
         // use idx sort as default sorting
         if (!$sort_field || !in_array($sort_field, $this->db_header_fields)) {
             $sort_field = 'idx';
         }
-    
+
         if ($this->caching_enabled && !isset($this->cache[$cache_key])) {
             $this->cache[$cache_key] = array();
             $sql_result = $this->db->limitquery(
@@ -3077,7 +3167,7 @@
     private function &get_cached_message($key, $uid)
     {
         $internal_key = 'message';
-    
+
         if ($this->caching_enabled && !isset($this->icache[$internal_key][$uid])) {
             $sql_result = $this->db->query(
                 "SELECT idx, headers, structure".
@@ -3102,22 +3192,22 @@
 
     /**
      * @access private
-     */  
+     */
     private function get_message_cache_index($key, $force=false, $sort_field='idx', $sort_order='ASC')
     {
         static $sa_message_index = array();
-    
+
         // empty key -> empty array
         if (!$this->caching_enabled || empty($key))
             return array();
-    
+
         if (!empty($sa_message_index[$key]) && !$force)
             return $sa_message_index[$key];
 
         // use idx sort as default
         if (!$sort_field || !in_array($sort_field, $this->db_header_fields))
             $sort_field = 'idx';
-    
+
         $sa_message_index[$key] = array();
         $sql_result = $this->db->query(
             "SELECT idx, uid".
@@ -3130,7 +3220,7 @@
 
         while ($sql_arr = $this->db->fetch_assoc($sql_result))
             $sa_message_index[$key][$sql_arr['idx']] = $sql_arr['uid'];
-      
+
         return $sa_message_index[$key];
     }
 
@@ -3149,8 +3239,8 @@
         // no further caching
         if (!$this->caching_enabled)
             return;
-    
-        // check for an existing record (probly headers are cached but structure not)
+
+        // check for an existing record (probably headers are cached but structure not)
         if (!$force) {
             $sql_result = $this->db->query(
                 "SELECT message_id".
@@ -3201,7 +3291,7 @@
             );
         }
     }
-    
+
     /**
      * @access private
      */
@@ -3209,7 +3299,7 @@
     {
         if (!$this->caching_enabled)
             return;
-    
+
         $this->db->query(
             "DELETE FROM ".get_table_name('messages').
             " WHERE user_id=?".
@@ -3226,7 +3316,7 @@
     {
         if (!$this->caching_enabled)
             return;
-    
+
         $this->db->query(
             "DELETE FROM ".get_table_name('messages').
             " WHERE user_id=?".
@@ -3242,7 +3332,7 @@
     {
         if (!$this->caching_enabled)
             return;
-    
+
         if (!empty($uids) && !is_array($uids)) {
             if ($uids == '*' || $uids == '1:*')
                 $uids = NULL;
@@ -3262,7 +3352,7 @@
         if ($sql_arr = $this->db->fetch_assoc($sql_result))
             return $sql_arr['minidx'];
         else
-            return 0;  
+            return 0;
     }
 
 
@@ -3284,7 +3374,7 @@
         $out = array();
         // Special chars as defined by RFC 822 need to in quoted string (or escaped).
         $special_chars = '[\(\)\<\>\\\.\[\]@,;:"]';
-    
+
         if (!is_array($a))
             return $out;
 
@@ -3305,7 +3395,7 @@
                 $string = $address;
             else if ($name)
                 $string = $name;
-      
+
             $out[$j] = array('name' => $name,
                 'mailto' => $address,
                 'string' => $string
@@ -3314,45 +3404,8 @@
             if ($max && $j==$max)
                 break;
         }
-    
+
         return $out;
-    }
-  
-  
-    /**
-     * Decode a Microsoft Outlook TNEF part (winmail.dat)
-     *
-     * @param object rcube_message_part Message part to decode
-     * @param string UID of the message
-     * @return array List of rcube_message_parts extracted from windmail.dat
-     */
-    function tnef_decode(&$part, $uid)
-    {
-        if (!isset($part->body))
-            $part->body = $this->get_message_part($uid, $part->mime_id, $part);
-
-        require_once('lib/tnef_decoder.inc');
-
-        $pid = 0;
-        $tnef_parts = array();
-        $tnef_arr = tnef_decode($part->body);
-    
-        foreach ($tnef_arr as $winatt) {
-            $tpart = new rcube_message_part;
-            $tpart->filename = $winatt["name"];
-            $tpart->encoding = 'stream';
-            $tpart->ctype_primary = $winatt["type0"];
-            $tpart->ctype_secondary = $winatt["type1"];
-            $tpart->mimetype = strtolower($winatt["type0"] . "/" . $winatt["type1"]);
-            $tpart->mime_id = "winmail." . $part->mime_id . ".$pid";
-            $tpart->size = $winatt["size"];
-            $tpart->body = $winatt['stream'];
-
-            $tnef_parts[] = $tpart;
-            $pid++;
-        }
-
-        return $tnef_parts;
     }
 
 
@@ -3368,7 +3421,7 @@
         $str = rcube_imap::decode_mime_string((string)$input, $this->default_charset);
         if ($str{0}=='"' && $remove_quotes)
             $str = str_replace('"', '', $str);
-    
+
         return $str;
     }
 
@@ -3388,15 +3441,15 @@
         $out = '';
 
         // Iterate instead of recursing, this way if there are too many values we don't have stack overflows
-        // rfc: all line breaks or other characters not found 
+        // rfc: all line breaks or other characters not found
         // in the Base64 Alphabet must be ignored by decoding software
-        // delete all blanks between MIME-lines, differently we can 
+        // delete all blanks between MIME-lines, differently we can
         // receive unnecessary blanks and broken utf-8 symbols
         $input = preg_replace("/\?=\s+=\?/", '?==?', $input);
 
         // Check if there is stuff to decode
         if (strpos($input, '=?') !== false) {
-            // Loop through the string to decode all occurences of =? ?= into the variable $out 
+            // Loop through the string to decode all occurences of =? ?= into the variable $out
             while(($pos = strpos($input, '=?')) !== false) {
                 // Append everything that is before the text to be decoded
                 $out .= substr($input, 0, $pos);
@@ -3424,7 +3477,7 @@
         }
 
         // no encoding information, use fallback
-        return rcube_charset_convert($input, 
+        return rcube_charset_convert($input,
             !empty($fallback) ? $fallback : rcmail::get_instance()->config->get('default_charset', 'ISO-8859-1'));
     }
 
@@ -3454,7 +3507,7 @@
             return rcube_charset_convert($rest, $a[0]);
         }
 
-        // we dont' know what to do with this  
+        // we dont' know what to do with this
         return $str;
     }
 
@@ -3544,15 +3597,15 @@
         ksort($a_defaults);
         $folders = array_merge($a_defaults, array_keys($folders));
 
-        // finally we must rebuild the list to move 
+        // finally we must rebuild the list to move
         // subfolders of default folders to their place...
         // ...also do this for the rest of folders because
         // asort() is not properly sorting case sensitive names
         while (list($key, $folder) = each($folders)) {
-            // set the type of folder name variable (#1485527) 
+            // set the type of folder name variable (#1485527)
             $a_out[] = (string) $folder;
             unset($folders[$key]);
-            $this->_rsort($folder, $delimiter, $folders, $a_out);	
+            $this->_rsort($folder, $delimiter, $folders, $a_out);
         }
 
         return $a_out;
@@ -3566,13 +3619,13 @@
     {
         while (list($key, $name) = each($list)) {
 	        if (strpos($name, $folder.$delimiter) === 0) {
-	            // set the type of folder name variable (#1485527) 
+	            // set the type of folder name variable (#1485527)
     	        $out[] = (string) $name;
 	            unset($list[$key]);
 	            $this->_rsort($name, $delimiter, $list, $out);
 	        }
         }
-        reset($list);	
+        reset($list);
     }
 
 
@@ -3583,7 +3636,7 @@
     {
         if (!$mbox_name)
             $mbox_name = $this->mailbox;
-      
+
         if (!isset($this->uid_id_map[$mbox_name][$uid]))
             $this->uid_id_map[$mbox_name][$uid] = $this->conn->UID2ID($mbox_name, $uid);
 
@@ -3603,7 +3656,7 @@
 
         $uid = $this->conn->ID2UID($mbox_name, $id);
         $this->uid_id_map[$mbox_name][$uid] = $id;
-    
+
         return $uid;
     }
 
@@ -3658,20 +3711,20 @@
         $mode = strtoupper($mode);
 
         $a_mailbox_cache = $this->get_cache('messagecount');
-    
+
         if (!is_array($a_mailbox_cache[$mailbox]) || !isset($a_mailbox_cache[$mailbox][$mode]) || !is_numeric($increment))
             return false;
-    
+
         // add incremental value to messagecount
         $a_mailbox_cache[$mailbox][$mode] += $increment;
-    
+
         // there's something wrong, delete from cache
         if ($a_mailbox_cache[$mailbox][$mode] < 0)
             unset($a_mailbox_cache[$mailbox][$mode]);
 
         // write back to cache
         $this->update_cache('messagecount', $a_mailbox_cache);
-    
+
         return true;
     }
 
@@ -3713,7 +3766,7 @@
                     $a_headers[$field] = $value;
             }
         }
-    
+
         return $a_headers;
     }
 
@@ -3739,13 +3792,13 @@
                 else
                     $result[$key]['name'] .= (empty($result[$key]['name'])?'':' ').str_replace("\"",'',stripslashes($v));
             }
-        
+
             if (empty($result[$key]['name']))
-                $result[$key]['name'] = $result[$key]['address'];        
+                $result[$key]['name'] = $result[$key]['address'];
             elseif (empty($result[$key]['address']))
                 $result[$key]['address'] = $result[$key]['name'];
         }
-    
+
         return $result;
     }
 
@@ -3791,7 +3844,7 @@
 class rcube_header_sorter
 {
     var $sequence_numbers = array();
-   
+
     /**
      * Set the predetermined sort order.
      *
@@ -3813,12 +3866,12 @@
         * uksort would work if the keys were the sequence number, but unfortunately
         * the keys are the UIDs.  We'll use uasort instead and dereference the value
         * to get the sequence number (in the "id" field).
-        * 
-        * uksort($headers, array($this, "compare_seqnums")); 
+        *
+        * uksort($headers, array($this, "compare_seqnums"));
         */
         uasort($headers, array($this, "compare_seqnums"));
     }
- 
+
     /**
      * Sort method called by uasort()
      */
@@ -3827,11 +3880,11 @@
         // First get the sequence number from the header object (the 'id' field).
         $seqa = $a->id;
         $seqb = $b->id;
-      
+
         // then find each sequence number in my ordered list
         $posa = isset($this->sequence_numbers[$seqa]) ? intval($this->sequence_numbers[$seqa]) : -1;
         $posb = isset($this->sequence_numbers[$seqb]) ? intval($this->sequence_numbers[$seqb]) : -1;
-      
+
         // return the relative position as the comparison value
         return $posa - $posb;
     }

--
Gitblit v1.9.1