summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2015-02-03 16:23:51 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2015-02-03 16:23:51 (GMT)
commit467da5defb99fe0ca19914b68dfb12aa48bc7908 (patch)
tree3e150e4b22ee1d3f2f2e358dbc6532939047638c
parent902b59d0d591fef2c1c591ecb0af931763cbb3ab (diff)
downloadroundcubemail-plugins-kolab-467da5defb99fe0ca19914b68dfb12aa48bc7908.tar.gz
Backported folder type and error checks for kolab_storage access (#4378)
-rw-r--r--plugins/libkolab/lib/kolab_storage.php15
-rw-r--r--plugins/libkolab/lib/kolab_storage_cache.php81
-rw-r--r--plugins/libkolab/lib/kolab_storage_folder.php92
3 files changed, 157 insertions, 31 deletions
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);