Branch 'roundcubemail-plugins-kolab-3.1' - plugins/libkolab

Thomas Brüderli bruederli at kolabsys.com
Tue Feb 3 17:23:58 CET 2015


 plugins/libkolab/lib/kolab_storage.php        |   15 ++--
 plugins/libkolab/lib/kolab_storage_cache.php  |   81 ++++++++++++++++++----
 plugins/libkolab/lib/kolab_storage_folder.php |   92 ++++++++++++++++++++++----
 3 files changed, 157 insertions(+), 31 deletions(-)

New commits:
commit 467da5defb99fe0ca19914b68dfb12aa48bc7908
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Tue Feb 3 17:23:51 2015 +0100

    Backported folder type and error checks for kolab_storage access (#4378)

diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index 29479c4..d02ad57 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -35,6 +35,11 @@ class kolab_storage
     const UID_KEY_PRIVATE   = '/private/vendor/kolab/uniqueid';
     const UID_KEY_CYRUS     = '/shared/vendor/cmu/cyrus-imapd/uniqueid';
 
+    const ERROR_IMAP_CONN      = 1;
+    const ERROR_CACHE_DB       = 2;
+    const ERROR_NO_PERMISSION  = 3;
+    const ERROR_INVALID_FOLDER = 4;
+
     public static $version = '3.0';
     public static $last_error;
 
@@ -116,7 +121,7 @@ class kolab_storage
 
         if (self::setup()) {
             foreach ((array)self::list_folders('', '*', $type, $subscribed, $folderdata) as $foldername) {
-                $folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
+                $folders[$foldername] = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
             }
         }
 
@@ -133,7 +138,7 @@ class kolab_storage
     {
         if (self::setup()) {
             foreach ((array)self::list_folders('', '*', $type . '.default', false, $folderdata) as $foldername) {
-                return new kolab_storage_folder($foldername, $folderdata[$foldername]);
+                return new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
             }
         }
 
@@ -165,11 +170,11 @@ class kolab_storage
     {
         self::setup();
         $folder = null;
-        foreach ((array)self::list_folders('', '*', $type) as $foldername) {
+        foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
             if (!$folder)
-                $folder = new kolab_storage_folder($foldername);
+                $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
             else
-                $folder->set_folder($foldername);
+                $folder->set_folder($foldername, $type, $folderdata[$foldername]);
 
             if ($object = $folder->get_object($uid, '*'))
                 return $object;
diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php
index fbb9322..b31cd74 100644
--- a/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_cache.php
@@ -45,6 +45,7 @@ class kolab_storage_cache
     protected $extra_cols = array();
     protected $order_by = null;
     protected $limit = null;
+    protected $error = 0;
 
 
     /**
@@ -77,6 +78,7 @@ class kolab_storage_cache
         $this->db = $rcmail->get_dbh();
         $this->imap = $rcmail->get_storage();
         $this->enabled = $rcmail->config->get('kolab_cache', false);
+        $this->folders_table = $this->db->table_name('kolab_folders');
 
         if ($this->enabled) {
             // always read folder cache and lock state from DB master
@@ -95,8 +97,7 @@ class kolab_storage_cache
      */
     public function select_by_id($folder_id)
     {
-        $folders_table = $this->db->table_name('kolab_folders');
-        $sql_arr = $this->db->fetch_assoc($this->db->query("SELECT * FROM $folders_table WHERE folder_id=?", $folder_id));
+        $sql_arr = $this->db->fetch_assoc($this->db->query("SELECT * FROM {$this->folders_table} WHERE folder_id=?", $folder_id));
         if ($sql_arr) {
             $this->metadata = $sql_arr;
             $this->folder_id = $sql_arr['folder_id'];
@@ -117,14 +118,13 @@ class kolab_storage_cache
     {
         $this->folder = $storage_folder;
 
-        if (empty($this->folder->name)) {
+        if (empty($this->folder->name) || !$this->folder->valid) {
             $this->ready = false;
             return;
         }
 
         // compose fully qualified ressource uri for this instance
         $this->resource_uri = $this->folder->get_resource_uri();
-        $this->folders_table = $this->db->table_name('kolab_folders');
         $this->cache_table = $this->db->table_name('kolab_cache_' . $this->folder->type);
         $this->ready = $this->enabled && !empty($this->folder->type);
         $this->folder_id = null;
@@ -148,6 +148,16 @@ class kolab_storage_cache
     }
 
     /**
+     * Returns code of last error
+     *
+     * @return int Error code
+     */
+    public function get_error()
+    {
+        return $this->error;
+    }
+
+    /**
      * Synchronize local cache data with remote
      */
     public function synchronize()
@@ -219,6 +229,7 @@ class kolab_storage_cache
             $this->_sync_unlock();
         }
 
+        $this->check_error();
         $this->synched = time();
     }
 
@@ -235,7 +246,12 @@ class kolab_storage_cache
     {
         // delegate to another cache instance
         if ($foldername && $foldername != $this->folder->name) {
-            return kolab_storage::get_folder($foldername)->cache->get($msguid, $type);
+            $success = false;
+            if ($targetfolder = kolab_storage::get_folder($foldername)) {
+                $success = $targetfolder->cache->get($msguid, $type);
+                $this->error = $targetfolder->cache->get_error();
+            }
+            return $success;
         }
 
         // load object if not in memory
@@ -262,6 +278,7 @@ class kolab_storage_cache
             }
         }
 
+        $this->check_error();
         return $this->objects[$msguid];
     }
 
@@ -281,8 +298,11 @@ class kolab_storage_cache
 
         // delegate to another cache instance
         if ($foldername && $foldername != $this->folder->name) {
-            kolab_storage::get_folder($foldername)->cache->set($msguid, $object);
-            return;
+          if ($targetfolder = kolab_storage::get_folder($foldername)) {
+              $targetfolder->cache->set($msguid, $object);
+              $this->error = $targetfolder->cache->get_error();
+          }
+          return;
         }
 
         // remove old entry
@@ -300,6 +320,8 @@ class kolab_storage_cache
             // ...or set in-memory cache to false
             $this->objects[$msguid] = $object;
         }
+
+        $this->check_error();
     }
 
 
@@ -351,6 +373,8 @@ class kolab_storage_cache
         // keep a copy in memory for fast access
         $this->objects = array($msguid => $object);
         $this->uid2msg = array($object['uid'] => $msguid);
+
+        $this->check_error();
     }
 
 
@@ -385,6 +409,7 @@ class kolab_storage_cache
         }
 
         unset($this->uid2msg[$uid]);
+        $this->check_error();
     }
 
 
@@ -410,15 +435,20 @@ class kolab_storage_cache
      */
     public function rename($new_folder)
     {
-        $target = kolab_storage::get_folder($new_folder);
+        if ($target = kolab_storage::get_folder($new_folder)) {
+            // resolve new message UID in target folder
+            $this->db->query(
+                "UPDATE $this->folders_table SET resource=? ".
+                "WHERE resource=?",
+                $target->get_resource_uri(),
+                $this->resource_uri
+            );
 
-        // resolve new message UID in target folder
-        $this->db->query(
-            "UPDATE $this->folders_table SET resource=? ".
-            "WHERE resource=?",
-            $target->get_resource_uri(),
-            $this->resource_uri
-        );
+            $this->check_error();
+        }
+        else {
+            $this->error = kolab_storage::ERROR_IMAP_CONN;
+        }
     }
 
     /**
@@ -498,6 +528,8 @@ class kolab_storage_cache
             }
         }
 
+        $this->check_error();
+
         return $result;
     }
 
@@ -534,12 +566,14 @@ class kolab_storage_cache
             $index  = $this->imap->search_once($this->folder->name, 'UNDELETED HEADER X-Kolab-Type ' . $ctype);
 
             if ($index->is_error()) {
+                $this->check_error();
                 return null;
             }
 
             $count = $index->count();
         }
 
+        $this->check_error();
         return $count;
     }
 
@@ -867,6 +901,7 @@ class kolab_storage_cache
 
         // abort if database is not set-up
         if ($this->db->is_error()) {
+            $this->check_error();
             $this->ready = false;
             return;
         }
@@ -901,6 +936,22 @@ class kolab_storage_cache
     }
 
     /**
+     * Check IMAP connection error state
+     */
+    protected function check_error()
+    {
+        if (($err_code = $this->imap->get_error_code()) < 0) {
+            $this->error = kolab_storage::ERROR_IMAP_CONN;
+            if (($res_code = $this->imap->get_response_code()) !== 0 && in_array($res_code, array(rcube_storage::NOPERM, rcube_storage::READONLY))) {
+                $this->error = kolab_storage::ERROR_NO_PERMISSION;
+            }
+        }
+        else if ($this->db->is_error()) {
+            $this->error = kolab_storage::ERROR_CACHE_DB;
+        }
+    }
+
+    /**
      * Resolve an object UID into an IMAP message UID
      *
      * @param string  Kolab object UID
diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
index 11ad287..0610325 100644
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -48,7 +48,13 @@ class kolab_storage_folder
      */
     public $cache;
 
-    private $type_annotation;
+     /**
+      * Indicate validity status
+      * @var boolean
+      */
+    public $valid = false;
+
+    private $error = 0;
     private $namespace;
     private $imap;
     private $info;
@@ -59,12 +65,15 @@ class kolab_storage_folder
 
     /**
      * Default constructor
+     *
+     * @param string The folder name/path
+     * @param string Expected folder type
      */
-    function __construct($name, $type = null)
+    function __construct($name, $type = null, $type_annotation = null)
     {
         $this->imap = rcube::get_instance()->get_storage();
         $this->imap->set_options(array('skip_deleted' => true));
-        $this->set_folder($name, $type);
+        $this->set_folder($name, $type, $type_annotation);
     }
 
 
@@ -74,14 +83,21 @@ class kolab_storage_folder
      * @param string The folder name/path
      * @param string Optional folder type if known
      */
-    public function set_folder($name, $ftype = null)
+    public function set_folder($name, $type = null, $type_annotation = null)
     {
-        $this->type_annotation = $ftype ? $ftype : kolab_storage::folder_type($name);
+        if (empty($type_annotation)) {
+            $type_annotation = kolab_storage::folder_type($name);
+        }
 
         $oldtype = $this->type;
-        list($this->type, $suffix) = explode('.', $this->type_annotation);
+        list($this->type, $suffix) = explode('.', $type_annotation);
         $this->default      = $suffix == 'default';
         $this->name         = $name;
+        $this->valid        = !empty($this->type) && $this->type != 'mail' && (!$type || $this->type == $type);
+
+        if (!$this->valid) {
+            $this->error = $this->imap->get_error_code() < 0 ? kolab_storage::ERROR_IMAP_CONN : kolab_storage::ERROR_INVALID_FOLDER;
+        }
 
         // reset cached object properties
         $this->owner = $this->namespace = $this->resource_uri = $this->info = $this->idata = null;
@@ -89,9 +105,20 @@ class kolab_storage_folder
         // get a new cache instance of folder type changed
         if (!$this->cache || $type != $oldtype)
             $this->cache = kolab_storage_cache::factory($this);
+        else
+            $this->cache->set_folder($this);
 
         $this->imap->set_folder($this->name);
-        $this->cache->set_folder($this);
+    }
+
+    /**
+     * Returns code of last error
+     *
+     * @return int Error code
+     */
+    public function get_error()
+    {
+        return $this->error ?: $this->cache->get_error();
     }
 
     /**
@@ -370,6 +397,10 @@ class kolab_storage_folder
      */
     public function count($query = null)
     {
+        if (!$this->valid) {
+            return 0;
+        }
+
         // synchronize cache first
         $this->cache->synchronize();
 
@@ -387,6 +418,10 @@ class kolab_storage_folder
     {
         if (!$type) $type = $this->type;
 
+        if (!$this->valid) {
+            return array();
+        }
+
         // synchronize caches
         $this->cache->synchronize();
 
@@ -404,9 +439,14 @@ class kolab_storage_folder
      */
     public function select($query = array())
     {
+        if (!$this->valid) {
+            return array();
+        }
+
         // check query argument
-        if (empty($query))
+        if (empty($query)) {
             return $this->get_objects();
+        }
 
         // synchronize caches
         $this->cache->synchronize();
@@ -424,6 +464,10 @@ class kolab_storage_folder
      */
     public function get_uids($query = array())
     {
+        if (!$this->valid) {
+            return array();
+        }
+
         // synchronize caches
         $this->cache->synchronize();
 
@@ -485,6 +529,10 @@ class kolab_storage_folder
      */
     public function get_object($uid, $type = null)
     {
+        if (!$this->valid) {
+            return false;
+        }
+
         // synchronize caches
         $this->cache->synchronize();
 
@@ -514,7 +562,7 @@ class kolab_storage_folder
      */
     public function get_attachment($uid, $part, $mailbox = null, $print = false, $fp = null, $skip_charset_conv = false)
     {
-        if ($msguid = ($mailbox ? $uid : $this->cache->uid2msguid($uid))) {
+        if ($this->valid && ($msguid = ($mailbox ? $uid : $this->cache->uid2msguid($uid)))) {
             $this->imap->set_folder($mailbox ? $mailbox : $this->name);
             return $this->imap->get_message_part($msguid, $part, null, $print, $fp, $skip_charset_conv);
         }
@@ -535,6 +583,10 @@ class kolab_storage_folder
      */
     public function read_object($msguid, $type = null, $folder = null)
     {
+        if (!$this->valid) {
+            return false;
+        }
+
         if (!$type) $type = $this->type;
         if (!$folder) $folder = $this->name;
 
@@ -680,6 +732,10 @@ class kolab_storage_folder
      */
     public function save(&$object, $type = null, $uid = null)
     {
+        if (!$this->valid) {
+            return false;
+        }
+
         if (!$type)
             $type = $this->type;
 
@@ -872,6 +928,10 @@ class kolab_storage_folder
      */
     public function delete($object, $expunge = true)
     {
+        if (!$this->valid) {
+            return false;
+        }
+
         $msguid = is_array($object) ? $object['_msguid'] : $this->cache->uid2msguid($object);
         $success = false;
 
@@ -899,6 +959,10 @@ class kolab_storage_folder
      */
     public function delete_all()
     {
+        if (!$this->valid) {
+            return false;
+        }
+
         $this->cache->purge();
         $this->cache->bypass(true);
         $result = $this->imap->clear_folder($this->name);
@@ -916,6 +980,10 @@ class kolab_storage_folder
      */
     public function undelete($uid)
     {
+        if (!$this->valid) {
+            return false;
+        }
+
         if ($msguid = $this->cache->uid2msguid($uid, true)) {
             $this->cache->bypass(true);
             $result = $this->imap->set_flag($msguid, 'UNDELETED', $this->name);
@@ -939,6 +1007,10 @@ class kolab_storage_folder
      */
     public function move($uid, $target_folder)
     {
+        if (!$this->valid) {
+            return false;
+        }
+
         if (is_string($target_folder))
             $target_folder = kolab_storage::get_folder($target_folder);
 
@@ -1194,8 +1266,6 @@ class kolab_storage_folder
      */
     private function trigger_url($url, $auth_user = null, $auth_passwd = null)
     {
-        require_once('HTTP/Request2.php');
-
         try {
             $request = libkolab::http_request($url);
 




More information about the commits mailing list