Branch 'dev/kolab3' - 3 commits - plugins/kolab_folders plugins/libkolab

Aleksander Machniak machniak at kolabsys.com
Mon May 14 13:42:43 CEST 2012


 plugins/kolab_folders/kolab_folders.php       |  227 ++++----------------------
 plugins/kolab_folders/package.xml             |    6 
 plugins/libkolab/lib/kolab_storage.php        |   91 +++++++++-
 plugins/libkolab/lib/kolab_storage_folder.php |   26 +-
 4 files changed, 141 insertions(+), 209 deletions(-)

New commits:
commit a2e191d631a7d018db6e5d9cea777e8eb18afc69
Author: Aleksander Machniak <alec at alec.pl>
Date:   Mon May 14 13:41:33 2012 +0200

    Improve performance of kolab_storage_folder object creation when
    folder type is already known (e.g. in kolab_storage::get_folders())

diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index 43f9c72..62b7796 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -72,11 +72,11 @@ class kolab_storage
      */
     public static function get_folders($type)
     {
-        $folders = array();
+        $folders = $folderdata = array();
 
         if (self::setup()) {
-            foreach ((array)self::list_folders('', '*', $type) as $foldername) {
-                $folders[$foldername] = new kolab_storage_folder($foldername, self::$imap);
+            foreach ((array)self::list_folders('', '*', $type, false, $folderdata) as $foldername) {
+                $folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
             }
         }
 
@@ -92,7 +92,7 @@ class kolab_storage
      */
     public static function get_folder($folder)
     {
-        return self::setup() ? new kolab_storage_folder($folder, self::$imap) : null;
+        return self::setup() ? new kolab_storage_folder($folder) : null;
     }
 
 
@@ -110,7 +110,7 @@ class kolab_storage
         $folder = null;
         foreach ((array)self::list_folders('', '*', $type) as $foldername) {
             if (!$folder)
-                $folder = new kolab_storage_folder($foldername, self::$imap);
+                $folder = new kolab_storage_folder($foldername);
             else
                 $folder->set_folder($foldername);
 
@@ -384,10 +384,11 @@ class kolab_storage
      * @param string  Optional name pattern
      * @param string  Data type to list folders for (contact,distribution-list,event,task,note,mail)
      * @param string  Enable to return subscribed folders only
+     * @param array   Will be filled with folder-types data
      *
      * @return array List of folders
      */
-    public static function list_folders($root = '', $mbox = '*', $filter = null, $subscribed = false)
+    public static function list_folders($root = '', $mbox = '*', $filter = null, $subscribed = false, &$folderdata = array())
     {
         if (!self::setup()) {
             return null;
@@ -412,14 +413,14 @@ class kolab_storage
             return array();
         }
 
-        $regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
+        $folderdata = array_map('implode', $folderdata);
+        $regexp     = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
 
         // In some conditions we can skip LIST command (?)
         if ($subscribed == false && $filter != 'mail' && $prefix == '*') {
-            foreach ($folderdata as $idx => $folder) {
-                $type = $folder[self::CTYPE_KEY];
+            foreach ($folderdata as $folder => $type) {
                 if (!preg_match($regexp, $type)) {
-                    unset($folderdata[$idx]);
+                    unset($folderdata[$folder]);
                 }
             }
             return array_keys($folderdata);
@@ -440,7 +441,7 @@ class kolab_storage
 
         // Filter folders list
         foreach ($folders as $idx => $folder) {
-            $type = !empty($folderdata[$folder]) ? $folderdata[$folder][self::CTYPE_KEY] : null;
+            $type = $folderdata[$folder];
 
             if ($filter == 'mail' && empty($type)) {
                 continue;
diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
index d691906..ffbbb5d 100644
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -54,30 +54,34 @@ class kolab_storage_folder
     /**
      * Default constructor
      */
-    function __construct($name, $imap = null)
+    function __construct($name, $type = null)
     {
-        $this->imap = is_object($imap) ? $imap : rcube::get_instance()->get_storage();
+        $this->imap = rcube::get_instance()->get_storage();
         $this->imap->set_options(array('skip_deleted' => true));
         $this->cache = new kolab_storage_cache($this);
-        $this->set_folder($name);
+        $this->set_folder($name, $type);
     }
 
 
     /**
-     * Set the IMAP folder name this instance connects to
+     * Set the IMAP folder this instance connects to
      *
      * @param string The folder name/path
+     * @param string Optional folder type if known
      */
-    public function set_folder($name)
+    public function set_folder($name, $type = null)
     {
-        $this->name = $name;
-        $this->imap->set_folder($this->name);
+        if (!$type) {
+            $metadata = $this->imap->get_metadata($name, array(kolab_storage::CTYPE_KEY));
+            $type     = $metadata[$this->name][kolab_storage::CTYPE_KEY];
+        }
 
-        $metadata = $this->imap->get_metadata($this->name, array(kolab_storage::CTYPE_KEY));
-        $this->type_annotation = $metadata[$this->name][kolab_storage::CTYPE_KEY];
-        $this->type = reset(explode('.', $this->type_annotation));
-        $this->resource_uri = null;
+        $this->name            = $name;
+        $this->type_annotation = $type;
+        $this->type            = reset(explode('.', $type));
+        $this->resource_uri    = null;
 
+        $this->imap->set_folder($this->name);
         $this->cache->set_folder($this);
     }
 


commit 4ed6758112fdab4a6696b33b25fe87ebb16ce421
Author: Aleksander Machniak <alec at alec.pl>
Date:   Mon May 14 13:04:24 2012 +0200

    Integrate folders listing functionality from kolab_folders plugin
    into kolab_storage class - added public list_folders() method.
    Now we can use kolab_storage out of Roundcube application.

diff --git a/plugins/kolab_folders/kolab_folders.php b/plugins/kolab_folders/kolab_folders.php
index 29bcd2f..3e01061 100644
--- a/plugins/kolab_folders/kolab_folders.php
+++ b/plugins/kolab_folders/kolab_folders.php
@@ -30,8 +30,6 @@ class kolab_folders extends rcube_plugin
     public $mail_types = array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail');
     private $rc;
 
-    const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
-
 
     /**
      * Plugin initialization.
@@ -40,6 +38,9 @@ class kolab_folders extends rcube_plugin
     {
         $this->rc = rcmail::get_instance();
 
+        // load required plugin
+        $this->require_plugin('libkolab');
+
         // Folder listing hooks
         $this->add_hook('storage_folders', array($this, 'mailboxes_list'));
 
@@ -57,68 +58,32 @@ class kolab_folders extends rcube_plugin
      */
     function mailboxes_list($args)
     {
-        if (!$this->metadata_support()) {
+        // infinite loop prevention
+        if ($this->is_processing) {
             return $args;
         }
 
-        $filter = $args['filter'];
-
-        // all-folders request, use core method
-        if (!$filter) {
+        if (!$this->metadata_support()) {
             return $args;
         }
 
-        // get folders types
-        $folderdata = $this->get_folder_type_list($args['root'].$args['name'], true);
+        $this->is_processing = true;
 
-        if (!is_array($folderdata)) {
-            return $args;
-        }
+        // get folders
+        $folders = kolab_storage::list_folders($args['root'], $args['name'], $args['filter'], $args['mode'] == 'LSUB');
 
-        $regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
+        $this->is_processing = false;
 
-        // In some conditions we can skip LIST command (?)
-        if ($args['mode'] == 'LIST' && $filter != 'mail'
-            && $args['root'] == '' && $args['name'] == '*'
-        ) {
-            foreach ($folderdata as $folder => $type) {
-                if (!preg_match($regexp, $type)) {
-                    unset($folderdata[$folder]);
-                }
-            }
-            $args['folders'] = array_keys($folderdata);
+        if (!is_array($folders)) {
             return $args;
         }
 
-        $storage = $this->rc->get_storage();
-
-        // Get folders list
-        if ($args['mode'] == 'LIST') {
-            if (!$storage->check_connection()) {
-                return $args;        
-            }
-            $args['folders'] = $storage->conn->listMailboxes($args['root'], $args['name']);
-        }
-        else {
-            $args['folders'] = $this->list_subscribed($args['root'], $args['name']);
+        // Create default folders
+        if ($args['root'] == '' && $args['name'] = '*') {
+            $this->create_default_folders($folders, $args['filter']);
         }
 
-        // In case of an error, return empty list
-        if (!is_array($args['folders'])) {
-            $args['folders'] = array();
-            return $args;
-        }
-
-        // Filter folders list
-        foreach ($args['folders'] as $idx => $folder) {
-            $type = $folderdata[$folder];
-            if ($filter == 'mail' && empty($type)) {
-                continue;
-            }
-            if (empty($type) || !preg_match($regexp, $type)) {
-                unset($args['folders'][$idx]);
-            }
-        }
+        $args['folders'] = $folders;
 
         return $args;
     }
@@ -132,10 +97,11 @@ class kolab_folders extends rcube_plugin
             return $args;
         }
 
-        $table = $args['table'];
+        $table   = $args['table'];
+        $storage = $this->rc->get_storage();
 
         // get folders types
-        $folderdata = $this->get_folder_type_list('*');
+        $folderdata = $storage->get_metadata('*', kolab_storage::CTYPE_KEY);
 
         if (!is_array($folderdata)) {
             return $args;
@@ -146,7 +112,7 @@ class kolab_folders extends rcube_plugin
         for ($i=1, $cnt=$table->size(); $i<=$cnt; $i++) {
             $attrib = $table->get_row_attribs($i);
             $folder = $attrib['foldername']; // UTF7-IMAP
-            $type   = $folderdata[$folder];
+            $type   = !empty($folderdata[$folder]) ? $folderdata[$folder][kolab_storage::CTYPE_KEY] : null;
 
             if (!$type)
                 $type = 'mail';
@@ -266,8 +232,6 @@ class kolab_folders extends rcube_plugin
     {
         // Folder actions from folders list
         if (empty($args['record'])) {
-            // Just clear Horde folders cache and return
-            $this->clear_folders_cache();
             return $args;
         }
 
@@ -340,11 +304,6 @@ class kolab_folders extends rcube_plugin
             }
         }
 
-        // Clear Horde folders cache
-        if ($result) {
-            $this->clear_folders_cache();
-        }
-
         $args['record']['class'] = self::folder_class_name($ctype);
         $args['record']['subscribe'] = $subscribe;
         $args['result'] = $result;
@@ -355,7 +314,7 @@ class kolab_folders extends rcube_plugin
     /**
      * Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
      *
-     * @return boolean 
+     * @return boolean
      */
     function metadata_support()
     {
@@ -376,9 +335,9 @@ class kolab_folders extends rcube_plugin
     function get_folder_type($folder)
     {
         $storage    = $this->rc->get_storage();
-        $folderdata = $storage->get_metadata($folder, array(kolab_folders::CTYPE_KEY));
+        $folderdata = $storage->get_metadata($folder, kolab_storage::CTYPE_KEY);
 
-        return explode('.', $folderdata[$folder][kolab_folders::CTYPE_KEY]);
+        return explode('.', $folderdata[$folder][kolab_storage::CTYPE_KEY]);
     }
 
     /**
@@ -393,112 +352,7 @@ class kolab_folders extends rcube_plugin
     {
         $storage = $this->rc->get_storage();
 
-        return $storage->set_metadata($folder, array(kolab_folders::CTYPE_KEY => $type));
-    }
-
-    /**
-     * Returns list of subscribed folders (directly from IMAP server)
-     *
-     * @param string $root Optional root folder
-     * @param string $name Optional name pattern
-     *
-     * @return array List of mailboxes/folders
-     */
-    private function list_subscribed($root='', $name='*')
-    {
-        $storage = $this->rc->get_storage();
-
-        if (!$storage->check_connection()) {
-            return null;
-        }
-
-        // Code copied from rcube_imap::_list_mailboxes()
-        // Server supports LIST-EXTENDED, we can use selection options
-        // #1486225: Some dovecot versions returns wrong result using LIST-EXTENDED
-        if (!$this->rc->config->get('imap_force_lsub') && $storage->get_capability('LIST-EXTENDED')) {
-            // This will also set mailbox options, LSUB doesn't do that
-            $a_folders = $storage->conn->listMailboxes($root, $name,
-                NULL, array('SUBSCRIBED'));
-
-            // remove non-existent folders
-            if (is_array($a_folders) && $name = '*' && !empty($storage->conn->data['LIST'])) {
-                foreach ($a_folders as $idx => $folder) {
-                    if (($opts = $storage->conn->data['LIST'][$folder])
-                        && in_array('\\NonExistent', $opts)
-                    ) {
-                        $storage->conn->unsubscribe($folder);
-                        unset($a_folders[$idx]);
-                    }
-                }
-            }
-        }
-        // retrieve list of folders from IMAP server using LSUB
-        else {
-            $a_folders = $storage->conn->listSubscribed($root, $name);
-
-            // unsubscribe non-existent folders, remove from the list
-            if (is_array($a_folders) && $name == '*' && !empty($storage->conn->data['LIST'])) {
-                foreach ($a_folders as $idx => $folder) {
-                    if (!isset($storage->conn->data['LIST'][$folder])
-                        || in_array('\\Noselect', $storage->conn->data['LIST'][$folder])
-                    ) {
-                        // Some servers returns \Noselect for existing folders
-                        if (!$storage->folder_exists($folder)) {
-                            $storage->conn->unsubscribe($folder);
-                            unset($a_folders[$idx]);
-                        }
-                    }
-                }
-            }
-        }
-
-        return $a_folders;
-    }
-
-    /**
-     * Returns list of folder(s) type(s)
-     *
-     * @param string $mbox     Folder name or pattern
-     * @param bool   $defaults Enables creation of configured default folders
-     *
-     * @return array List of folders data, indexed by folder name
-     */
-    function get_folder_type_list($mbox, $create_defaults = false)
-    {
-        $storage = $this->rc->get_storage();
-
-        // Use mailboxes. prefix so the cache will be cleared by core
-        // together with other mailboxes-related cache data
-        $cache_key = 'mailboxes.folder-type.'.$mbox;
-
-        // get cached metadata
-        $metadata = $storage->get_cache($cache_key);
-
-        if (!is_array($metadata)) {
-            $metadata = $storage->get_metadata($mbox, kolab_folders::CTYPE_KEY);
-            $need_update = true;
-        }
-
-        if (!is_array($metadata)) {
-            return false;
-        }
-
-        // make the result more flat
-        if ($need_update) {
-            $metadata = array_map('implode', $metadata);
-        }
-
-        // create default folders if needed
-        if ($create_defaults) {
-            $this->create_default_folders($metadata, $cache_key);
-        }
-
-        // write mailboxlist to cache
-        if ($need_update) {
-            $storage->update_cache($cache_key, $metadata);
-        }
-
-        return $metadata;
+        return $storage->set_metadata($folder, array(kolab_storage::CTYPE_KEY => $type));
     }
 
     /**
@@ -511,7 +365,7 @@ class kolab_folders extends rcube_plugin
     function get_default_folder($type)
     {
         $storage    = $this->rc->get_storage();
-        $folderdata = $this->get_folder_type_list('*');
+        $folderdata = $storage->get_metadata('*', kolab_storage::CTYPE_KEY);
 
         if (!is_array($folderdata)) {
             return null;
@@ -521,7 +375,8 @@ class kolab_folders extends rcube_plugin
         $namespace = $storage->get_namespace();
 
         // get all folders of specified type
-        $folderdata = array_intersect($folderdata, array($type)); 
+        $folderdata = array_map('implode', $folderdata);
+        $folderdata = array_intersect($folderdata, array($type));
         unset($folders[0]);
 
         foreach ($folderdata as $folder => $data) {
@@ -563,23 +418,23 @@ class kolab_folders extends rcube_plugin
     }
 
     /**
-     * Clear Horde's folder cache. See Kolab_List::singleton().
-     */
-    private function clear_folders_cache()
-    {
-        unset($_SESSION['horde_session_objects']['kolab_folderlist']);
-    }
-
-    /**
      * Creates default folders if they doesn't exist
      */
-    private function create_default_folders(&$folderdata, $cache_key = null)
+    private function create_default_folders(&$folders, $filter)
     {
         $storage     = $this->rc->get_storage();
         $namespace   = $storage->get_namespace();
+        $folderdata  = $storage->get_metadata('*', kolab_storage::CTYPE_KEY);
         $defaults    = array();
         $need_update = false;
 
+        if (!is_array($folderdata)) {
+            return;
+        }
+
+        // "Flattenize" metadata array to become a name->type hash
+        $folderdata = array_map('implode', $folderdata);
+
         // Find personal namespace prefix
         if (is_array($namespace['personal']) && count($namespace['personal']) == 1) {
             $prefix = $namespace['personal'][0][0];
@@ -621,7 +476,7 @@ class kolab_folders extends rcube_plugin
             }
 
             // get all folders of specified type
-            $folders = array_intersect($folderdata, array($type)); 
+            $folders = array_intersect($folderdata, array($type));
             unset($folders[0]);
 
             // find folders in personal namespace
@@ -653,16 +508,10 @@ class kolab_folders extends rcube_plugin
             $result = $this->set_folder_type($foldername, $type);
 
             // add new folder to the result
-            if ($result) {
-                $folderdata[$foldername] = $type;
-                $need_update = true;
+            if ($result && (!$filter || $filter == $type1)) {
+                $folders[] = $foldername;
             }
         }
-
-        // update cache
-        if ($need_update && $cache_key) {
-            $storage->update_cache($cache_key, $folderdata);
-        }
     }
 
 }
diff --git a/plugins/kolab_folders/package.xml b/plugins/kolab_folders/package.xml
index 8042ba2..875d614 100644
--- a/plugins/kolab_folders/package.xml
+++ b/plugins/kolab_folders/package.xml
@@ -21,10 +21,10 @@
 		<email>machniak at kolabsys.com</email>
 		<active>yes</active>
 	</lead>
-	<date>2011-11-01</date>
+	<date>2012-05-14</date>
 	<version>
-		<release>1.0</release>
-		<api>1.0</api>
+		<release>2.0</release>
+		<api>2.0</api>
 	</version>
 	<stability>
 		<release>stable</release>
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index 175bb02..43f9c72 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -75,7 +75,7 @@ class kolab_storage
         $folders = array();
 
         if (self::setup()) {
-            foreach ((array)self::$imap->list_folders('', '*', $type) as $foldername) {
+            foreach ((array)self::list_folders('', '*', $type) as $foldername) {
                 $folders[$foldername] = new kolab_storage_folder($foldername, self::$imap);
             }
         }
@@ -108,7 +108,7 @@ class kolab_storage
     {
         self::setup();
         $folder = null;
-        foreach ((array)self::$imap->list_folders('', '*', $type) as $foldername) {
+        foreach ((array)self::list_folders('', '*', $type) as $foldername) {
             if (!$folder)
                 $folder = new kolab_storage_folder($foldername, self::$imap);
             else
@@ -375,4 +375,82 @@ class kolab_storage
 
         return $select;
     }
+
+
+    /**
+     * Returns a list of folder names
+     *
+     * @param string  Optional root folder
+     * @param string  Optional name pattern
+     * @param string  Data type to list folders for (contact,distribution-list,event,task,note,mail)
+     * @param string  Enable to return subscribed folders only
+     *
+     * @return array List of folders
+     */
+    public static function list_folders($root = '', $mbox = '*', $filter = null, $subscribed = false)
+    {
+        if (!self::setup()) {
+            return null;
+        }
+
+        if (!$filter) {
+            // Get ALL folders list, standard way
+            if ($subscribed) {
+                return self::$imap->list_folders_subscribed($root, $mbox);
+            }
+            else {
+                return self::$imap->list_folders($root, $mbox);
+            }
+        }
+
+        $prefix = $root . $mbox;
+
+        // get folders types
+        $folderdata = self::$imap->get_metadata($prefix, self::CTYPE_KEY);
+
+        if (!is_array($folderdata)) {
+            return array();
+        }
+
+        $regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
+
+        // In some conditions we can skip LIST command (?)
+        if ($subscribed == false && $filter != 'mail' && $prefix == '*') {
+            foreach ($folderdata as $idx => $folder) {
+                $type = $folder[self::CTYPE_KEY];
+                if (!preg_match($regexp, $type)) {
+                    unset($folderdata[$idx]);
+                }
+            }
+            return array_keys($folderdata);
+        }
+
+        // Get folders list
+        if ($subscribed) {
+            $folders = self::$imap->list_folders_subscribed_direct($root, $mbox);
+        }
+        else {
+            $folders = self::$imap->list_folders_direct($root, $mbox);
+        }
+
+        // In case of an error, return empty list (?)
+        if (!is_array($folders)) {
+            return array();
+        }
+
+        // Filter folders list
+        foreach ($folders as $idx => $folder) {
+            $type = !empty($folderdata[$folder]) ? $folderdata[$folder][self::CTYPE_KEY] : null;
+
+            if ($filter == 'mail' && empty($type)) {
+                continue;
+            }
+            if (empty($type) || !preg_match($regexp, $type)) {
+                unset($folders[$idx]);
+            }
+        }
+
+        return $folders;
+    }
+
 }


commit dd516006db8b662dac24bded8bd5c129358d6f6c
Author: Aleksander Machniak <machniak at hosted05.klab.cc>
Date:   Mon May 14 10:04:59 2012 +0200

    Fix argument count for kolab_storage_folder constructor

diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index 983a268..175bb02 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -92,7 +92,7 @@ class kolab_storage
      */
     public static function get_folder($folder)
     {
-        return self::setup() ? new kolab_storage_folder($folder, null, self::$imap) : null;
+        return self::setup() ? new kolab_storage_folder($folder, self::$imap) : null;
     }
 
 





More information about the commits mailing list