From 26bc46d9b671ea069fc779ecb8b4ac90323c2291 Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Wed, 07 Sep 2011 02:59:48 -0400
Subject: [PATCH] - Move two entries from 0.6-rc to trunk's changelog part

---
 program/include/rcube_imap.php |  203 ++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 153 insertions(+), 50 deletions(-)

diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 413a672..97b080a 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -5,7 +5,8 @@
  | program/include/rcube_imap.php                                        |
  |                                                                       |
  | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2005-2010, The Roundcube Dev Team                       |
+ | Copyright (C) 2005-2011, The Roundcube Dev Team                       |
+ | Copyright (C) 2011, Kolab Systems AG                                  |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -80,24 +81,22 @@
     private $db_header_fields = array('idx', 'uid', 'subject', 'from', 'to', 'cc', 'date', 'size');
     private $options = array('auth_method' => 'check');
     private $host, $user, $pass, $port, $ssl;
+    private $caching = false;
 
     /**
      * All (additional) headers used (in any way) by Roundcube
-     * Not listed here: DATE, FROM, TO, SUBJECT, CONTENT-TYPE, LIST-POST
+     * Not listed here: DATE, FROM, TO, CC, REPLY-TO, SUBJECT, CONTENT-TYPE, LIST-POST
      * (used for messages listing) are hardcoded in rcube_imap_generic::fetchHeaders()
      *
      * @var array
      * @see rcube_imap::fetch_add_headers
      */
     private $all_headers = array(
-        'REPLY-TO',
         'IN-REPLY-TO',
-        'CC',
         'BCC',
         'MESSAGE-ID',
         'CONTENT-TRANSFER-ENCODING',
         'REFERENCES',
-        'X-PRIORITY',
         'X-DRAFT-INFO',
         'MAIL-FOLLOWUP-TO',
         'MAIL-REPLY-TO',
@@ -121,6 +120,13 @@
     function __construct()
     {
         $this->conn = new rcube_imap_generic();
+
+        // Set namespace and delimiter from session,
+        // so some methods would work before connection
+        if (isset($_SESSION['imap_namespace']))
+            $this->namespace = $_SESSION['imap_namespace'];
+        if (isset($_SESSION['imap_delimiter']))
+            $this->delimiter = $_SESSION['imap_delimiter'];
     }
 
 
@@ -549,12 +555,6 @@
     private function set_env()
     {
         if ($this->delimiter !== null && $this->namespace !== null) {
-            return;
-        }
-
-        if (isset($_SESSION['imap_namespace']) && isset($_SESSION['imap_delimiter'])) {
-            $this->namespace = $_SESSION['imap_namespace'];
-            $this->delimiter = $_SESSION['imap_delimiter'];
             return;
         }
 
@@ -2163,7 +2163,7 @@
                     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')) {
+                    else if (in_array('name', (array)$part[$i][2]) && empty($part[$i][3])) {
                         $mime_part_headers[] = $tmp_part_id;
                     }
                 }
@@ -2231,13 +2231,13 @@
         }
 
         // read content encoding
-        if (!empty($part[5]) && $part[5]!='NIL') {
+        if (!empty($part[5])) {
             $struct->encoding = strtolower($part[5]);
             $struct->headers['content-transfer-encoding'] = $struct->encoding;
         }
 
         // get part size
-        if (!empty($part[6]) && $part[6]!='NIL')
+        if (!empty($part[6]))
             $struct->size = intval($part[6]);
 
         // read part disposition
@@ -2264,7 +2264,7 @@
         }
 
         // get part ID
-        if (!empty($part[3]) && $part[3]!='NIL') {
+        if (!empty($part[3])) {
             $struct->content_id = $part[3];
             $struct->headers['content-id'] = $part[3];
 
@@ -3074,6 +3074,9 @@
         if (isset($data['folders'])) {
             $a_folders = $data['folders'];
         }
+        else if (!$this->conn->connected()) {
+           return array();
+        }
         else {
             // Server supports LIST-EXTENDED, we can use selection options
             $config = rcmail::get_instance()->config;
@@ -3083,20 +3086,36 @@
                 $a_folders = $this->conn->listMailboxes($root, $name,
                     NULL, array('SUBSCRIBED'));
 
-                // remove non-existent folders
-                if (is_array($a_folders)) {
+                // unsubscribe non-existent folders, remove from the list
+                if (is_array($a_folders) && $name == '*') {
                     foreach ($a_folders as $idx => $folder) {
                         if ($this->conn->data['LIST'] && ($opts = $this->conn->data['LIST'][$folder])
                             && in_array('\\NonExistent', $opts)
                         ) {
+                            $this->conn->unsubscribe($folder);
                             unset($a_folders[$idx]);
-                        } 
+                        }
                     }
                 }
             }
             // retrieve list of folders from IMAP server using LSUB
             else {
                 $a_folders = $this->conn->listSubscribed($root, $name);
+
+                // unsubscribe non-existent folders, remove from the list
+                if (is_array($a_folders) && $name == '*') {
+                    foreach ($a_folders as $idx => $folder) {
+                        if ($this->conn->data['LIST'] && ($opts = $this->conn->data['LIST'][$folder])
+                            && in_array('\\Noselect', $opts)
+                        ) {
+                            // Some servers returns \Noselect for existing folders
+                            if (!$this->mailbox_exists($folder)) {
+                                $this->conn->unsubscribe($folder);
+                                unset($a_folders[$idx]);
+                            }
+                        }
+                    }
+                }
             }
         }
 
@@ -3232,7 +3251,7 @@
         // try to subscribe it
         if ($result) {
             // clear cache
-            $this->clear_cache('/^mailboxes.*/', true);
+            $this->clear_cache('mailboxes', true);
 
             if ($subscribe)
                 $this->subscribe($mailbox);
@@ -3288,7 +3307,7 @@
 
             // clear cache
             $this->clear_message_cache($mailbox.'.msg');
-            $this->clear_cache('/^mailboxes.*/', true);
+            $this->clear_cache('mailboxes', true);
         }
 
         return $result;
@@ -3330,7 +3349,7 @@
 
             // clear mailbox-related cache
             $this->clear_message_cache($mailbox.'.msg');
-            $this->clear_cache('/^mailboxes.*/', true);
+            $this->clear_cache('mailboxes', true);
         }
 
         return $result;
@@ -3485,6 +3504,86 @@
         $opts = $this->conn->data['LIST'][$mailbox];
 
         return is_array($opts) ? $opts : array();
+    }
+
+
+    /**
+     * Returns extended information about the folder
+     *
+     * @param string $mailbox Folder name
+     *
+     * @return array Data
+     */
+    function mailbox_info($mailbox)
+    {
+        if ($this->icache['options'] && $this->icache['options']['name'] == $mailbox) {
+            return $this->icache['options'];
+        }
+
+        $acl       = $this->get_capability('ACL');
+        $namespace = $this->get_namespace();
+        $options   = array();
+
+        // check if the folder is a namespace prefix
+        if (!empty($namespace)) {
+            $mbox = $mailbox . $this->delimiter;
+            foreach ($namespace as $ns) {
+                if (!empty($ns)) {
+                    foreach ($ns as $item) {
+                        if ($item[0] === $mbox) {
+                            $options['is_root'] = true;
+                            break 2;
+                        }
+                    }
+                }
+            }
+        }
+        // check if the folder is other user virtual-root
+        if (!$options['is_root'] && !empty($namespace) && !empty($namespace['other'])) {
+            $parts = explode($this->delimiter, $mailbox);
+            if (count($parts) == 2) {
+                $mbox = $parts[0] . $this->delimiter;
+                foreach ($namespace['other'] as $item) {
+                    if ($item[0] === $mbox) {
+                        $options['is_root'] = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        $options['name']      = $mailbox;
+        $options['options']   = $this->mailbox_options($mailbox, true);
+        $options['namespace'] = $this->mailbox_namespace($mailbox);
+        $options['rights']    = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array();
+        $options['special']   = in_array($mailbox, $this->default_folders);
+
+        // Set 'noselect' and 'norename' flags
+        if (is_array($options['options'])) {
+            foreach ($options['options'] as $opt) {
+                $opt = strtolower($opt);
+                if ($opt == '\noselect' || $opt == '\nonexistent') {
+                    $options['noselect'] = true;
+                }
+            }
+        }
+        else {
+            $options['noselect'] = true;
+        }
+
+        if (!empty($options['rights'])) {
+            $options['norename'] = !in_array('x', $options['rights']);
+            if (!$options['noselect']) {
+                $options['noselect'] = !in_array('r', $options['rights']);
+            }
+        }
+        else {
+            $options['norename'] = $options['is_root'] || $options['namespace'] != 'personal';
+        }
+
+        $this->icache['options'] = $options;
+
+        return $options;
     }
 
 
@@ -3738,22 +3837,34 @@
     /**
      * Enable or disable indexes caching
      *
-     * @param boolean $type Cache type (memcache' or 'db')
+     * @param string $type Cache type (@see rcmail::get_cache)
      * @access public
      */
     function set_caching($type)
     {
         if ($type) {
-            $rcmail = rcmail::get_instance();
-            $this->cache = $rcmail->get_cache('IMAP', $type);
+            $this->caching = $type;
         }
         else {
             if ($this->cache)
                 $this->cache->close();
             $this->cache = null;
+            $this->caching = false;
         }
     }
 
+    /**
+     * Getter for IMAP cache object
+     */
+    private function get_cache_engine()
+    {
+        if ($this->caching && !$this->cache) {
+            $rcmail = rcmail::get_instance();
+            $this->cache = $rcmail->get_cache('IMAP', $this->caching);
+        }
+
+        return $this->cache;
+    }
 
     /**
      * Returns cached value
@@ -3764,8 +3875,8 @@
      */
     function get_cache($key)
     {
-        if ($this->cache) {
-            return $this->cache->get($key);
+        if ($cache = $this->get_cache_engine()) {
+            return $cache->get($key);
         }
     }
 
@@ -3778,23 +3889,23 @@
      */
     function update_cache($key, $data)
     {
-        if ($this->cache) {
-            $this->cache->set($key, $data);
+        if ($cache = $this->get_cache_engine()) {
+            $cache->set($key, $data);
         }
     }
 
     /**
      * Clears the cache.
      *
-     * @param string  $key          Cache key name or pattern
-     * @param boolean $pattern_mode Enable it to clear all keys with name
-     *                              matching PREG pattern in $key
+     * @param string  $key         Cache key name or pattern
+     * @param boolean $prefix_mode Enable it to clear all keys starting
+     *                             with prefix specified in $key
      * @access public
      */
-    function clear_cache($key=null, $pattern_mode=false)
+    function clear_cache($key=null, $prefix_mode=false)
     {
-        if ($this->cache) {
-            $this->cache->remove($key, $pattern_mode);
+        if ($cache = $this->get_cache_engine()) {
+            $cache->remove($key, $prefix_mode);
         }
     }
 
@@ -4583,20 +4694,9 @@
                     $updated = $this->conn->unsubscribe($mailbox);
             }
 
-        // get cached mailbox list
+        // clear cached mailbox list(s)
         if ($updated) {
-            $a_mailbox_cache = $this->get_cache('mailboxes');
-            if (!is_array($a_mailbox_cache))
-                return $updated;
-
-            // modify cached list
-            if ($mode == 'subscribe')
-                $a_mailbox_cache = array_merge($a_mailbox_cache, $a_mboxes);
-            else if ($mode == 'unsubscribe')
-                $a_mailbox_cache = array_diff($a_mailbox_cache, $a_mboxes);
-
-            // write mailboxlist to cache
-            $this->update_cache('mailboxes', $this->_sort_mailbox_list($a_mailbox_cache));
+            $this->clear_cache('mailboxes', true);
         }
 
         return $updated;
@@ -4685,16 +4785,19 @@
         $str = self::explode_header_string(',;', $str, true);
         $result = array();
 
+        // simplified regexp, supporting quoted local part
+        $email_rx = '(\S+|("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+"))@\S+';
+
         foreach ($str as $key => $val) {
             $name    = '';
             $address = '';
             $val     = trim($val);
 
-            if (preg_match('/(.*)<(\S+@\S+)>$/', $val, $m)) {
+            if (preg_match('/(.*)<('.$email_rx.')>$/', $val, $m)) {
                 $address = $m[2];
                 $name    = trim($m[1]);
             }
-            else if (preg_match('/^(\S+@\S+)$/', $val, $m)) {
+            else if (preg_match('/^('.$email_rx.')$/', $val, $m)) {
                 $address = $m[1];
                 $name    = '';
             }
@@ -4704,7 +4807,7 @@
 
             // dequote and/or decode name
             if ($name) {
-                if ($name[0] == '"') {
+                if ($name[0] == '"' && $name[strlen($name)-1] == '"') {
                     $name = substr($name, 1, -1);
                     $name = stripslashes($name);
                 }

--
Gitblit v1.9.1