From: Gunnar Wrobel Date: Mon, 7 Sep 2009 18:53:30 +0000 (+0200) Subject: Converted Kolab_Storage to Horde4. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=82567e60442765bacc2eff9333b023dedb901c35;p=horde.git Converted Kolab_Storage to Horde4. The major change is the use of the new Imap_Client library. Some PHP5 corrections have been done but conversion is not complete yet. --- diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server.php b/framework/Kolab_Server/lib/Horde/Kolab/Server.php index 29763eb65..d1da1c15e 100644 --- a/framework/Kolab_Server/lib/Horde/Kolab/Server.php +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server.php @@ -17,6 +17,11 @@ require_once 'Horde/Autoloader.php'; /** + * We need Log.php for the Log constants + */ +require_once 'Log.php'; + +/** * This class provides methods to deal with Kolab objects stored in * the Kolab object db. * @@ -149,8 +154,9 @@ abstract class Horde_Kolab_Server static $instances = array(); - $sparam = $params; - $sparam['pass'] = isset($sparam['pass']) ? hash('sha256', $sparam['pass']) : ''; + $sparam = $params; + $sparam['pass'] = isset($sparam['pass']) + ? hash('sha256', $sparam['pass']) : ''; ksort($sparam); $signature = serialize($sparam); @@ -226,7 +232,7 @@ abstract class Horde_Kolab_Server || $this->params['host_master'] == $this->params['host']) { return $this; } - $params = $this->params; + $params = $this->params; $params['write'] = true; return Horde_Kolab_Server::singleton($params); } @@ -423,7 +429,7 @@ abstract class Horde_Kolab_Server if (!isset($this->attributes)) { if (!empty($GLOBALS['conf']['kolab']['server']['cache']['driver']) - && class_exists('Horde_Cache')) { + && class_exists('Horde_Cache')) { $params = isset($GLOBALS['conf']['kolab']['server']['cache']['params']) ? $GLOBALS['conf']['kolab']['server']['cache']['params'] : null; $cache = Horde_Cache::singleton($GLOBALS['conf']['kolab']['server']['cache']['driver'], diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage.php index 83f7cc678..694d568f1 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Storage.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage.php @@ -1,29 +1,37 @@ + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ -/** Load the handler for the folder list management. */ -require_once 'Horde/Kolab/Storage/List.php'; +/** + * The Autoloader allows us to omit "require/include" statements. + */ +require_once 'Horde/Autoloader.php'; /** - * The Kolab_Storage class provides the means to access the Kolab server - * storage for groupware objects. + * The Horde_Kolab_Storage class provides the means to access the + * Kolab server storage for groupware objects. * * To get access to the folder handling you would do the following: * * * require_once 'Horde/Kolab/Storage.php'; - * $folder = Kolab_Storage::getFolder('INBOX/Calendar'); + * $folder = Horde_Kolab_Storage::getFolder('INBOX/Calendar'); * * * or (in case you are dealing with share identifications): * * * require_once 'Horde/Kolab/Storage.php'; - * $folder = Kolab_Storage::getShare(Auth::getAuth(), 'event'); + * $folder = Horde_Kolab_Storage::getShare(Auth::getAuth(), 'event'); * * * To access data in a share (or folder) you need to retrieve the @@ -31,49 +39,538 @@ require_once 'Horde/Kolab/Storage/List.php'; * * * require_once 'Horde/Kolab/Storage.php'; - * $folder = Kolab_Storage::getShareData(Auth::getAuth(), 'event'); + * $folder = Horde_Kolab_Storage::getShareData(Auth::getAuth(), 'event'); * * - * $Horde: framework/Kolab_Storage/lib/Horde/Kolab/Storage.php,v 1.4 2009/01/06 17:49:27 jan Exp $ - * * Copyright 2004-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Gunnar Wrobel - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ -class Kolab_Storage { +class Horde_Kolab_Storage +{ + /** + * Singleton instance. + * + * @var Horde_Kolab_Storage + */ + static protected $instances = array(); /** - * Return the folder object corresponding to the share of the - * specified type (e.g. "contact", "event" etc.). + * An array of Horde_Kolab_Storage_Driver connections to Kolab + * storage systems. + * + * @var array + */ + protected $connections = array(); + + /** + * The driver type for the base connection. + * + * @var string + */ + private $_driver; + + /** + * The parameters for the base connection. + * + * @var array + */ + private $_params; + + /** + * A connection to the cache object. + * + * @var Horde_Cache + */ + private $_cache; + + /** + * The list of existing folders on this server. + * + * @var array + */ + private $_list; + + /** + * A cache for folder objects (these do not necessarily exist). + * + * @var array + */ + private $_folders; + + /** + * A cache array listing a default folder for each folder type. + * + * @var array + */ + private $_defaults; + + /** + * A cache array listing a the folders for each folder type. * - * @param string $share The id of the share. - * @param string $type The share type. + * @var array + */ + private $_types; + + /** + * Constructor. * - * @return Kolab_Folder|PEAR_Error The folder object representing - * the share. + * @param string $driver The driver used for the primary storage connection. + * @param array $params Additional connection parameters. */ - function &getShare($share, $type) + public function __construct($driver, $params = array()) { - $list = &Kolab_List::singleton(); - $share = $list->getByShare($share, $type); - return $share; + $this->_driver = $driver; + $this->_params = $params; + + if (isset($this->_params['owner'])) { + $this->_owner = $this->_params['owner']; + } else if (class_exists('Horde_Auth')) { + $this->_owner = Horde_Auth::getAuth(); + } else { + $this->_owner = ''; + } + + $this->__wakeup(); + } + + /** + * Factory. + * + * @param string $driver The driver used for the primary storage connection. + * @param array $params Additional connection parameters. + * + * @return Horde_Kolab_Storage_List A concrete list instance. + */ + static public function &factory($driver, $params = array()) + { + if (!empty($GLOBALS['conf']['kolab']['storage']['cache']['folders'])) { + $signature = hash('md5', serialize(array($driver, $params))) . '|list'; + + $this->_cache = &Horde_Cache::singleton($GLOBALS['conf']['kolab']['storage']['cache']['folders']['driver'], + $GLOBALS['conf']['kolab']['storage']['cache']['folders']['params']); + + $data = $this->_cache->get($signature, + $GLOBALS['conf']['kolab']['storage']['cache']['folders']['lifetime']); + if ($data) { + $list = @unserialize($data); + if ($list instanceOf Horde_Kolab_Storage) { + register_shutdown_function(array($list, 'shutdown')); + return $list; + } + } + } + $list = new Horde_Kolab_Storage($driver, $params); + if (!empty($GLOBALS['conf']['kolab']['storage']['cache']['folders'])) { + register_shutdown_function(array($list, 'shutdown')); + } + return $list; } /** - * Return the folder object. + * Attempts to return a reference to a concrete Horde_Kolab_Storage_List + * instance based on $driver and $params. It will only create a new instance + * if no Horde_Kolab_Storage_List instance with the same parameters currently + * exists. + * + * This method must be invoked as: + * $var = &Horde_Kolab_Storage_List::singleton() * - * @param string $folder The name of the folder. + * @param string $driver The driver used for the primary storage connection. + * @param array $params Additional connection parameters. * - * @return Kolab_Folder|PEAR_Error The folder object. + * @return Horde_Kolab_Storage_List The concrete Horde_Kolab_Storage reference. + */ + static public function singleton($driver, $params = array()) + { + ksort($params); + $signature = hash('md5', serialize(array($driver, $params))); + + if (!isset(self::$instances[$signature])) { + self::$instances[$signature] = Horde_Kolab_Storage::factory($driver, + $params); + } + + return self::$instances[$signature]; + } + + /** + * Clean the simulated IMAP store. + * + * @return NULL + */ + public function clean() + { + $this->_list = null; + $this->_folders = null; + $this->_defaults = null; + $this->_types = null; + } + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + $properties = get_object_vars($this); + unset($properties['connections']); + $properties = array_keys($properties); + return $properties; + } + + /** + * Initializes the object. + * + * @return NULL + */ + public function __wakeup() + { + if (!isset($this->_folders)) { + $this->_folders = array(); + } + + foreach ($this->_folders as $key => $folder) { + $result = $this->getConnection($key); + $folder->restore($this, $result->connection); + } + $this->connect(); + } + + /** + * Stores the object in the session cache. + * + * @return NULL + */ + protected function shutdown() + { + $data = @serialize($this); + return $this->_cache->set($signature, $data, + $GLOBALS['conf']['kolab']['storage']['cache']['folders']['lifetime']); + } + + /** + * Return the connection driver and the folder name for the given key. + * + * @param string $key The key specifying a connection (may be a folder name) + * + * @return stdClass An object with the parameter "connection" set to the + * connection identified by the given key and the parameter + * "name" set to the folder name if the given key contained + * a folder name. + */ + public function &getConnection($key = null) + { + $result = new stdClass; + if (strpos('@', $key)) { + list($connection, $result->name) = explode('@', $folder, 2); + } else { + $connection = null; + $result->name = $key; + } + + if (empty($connection) || !isset($this->connections[$connection])) { + $result->connection = &$this->connections['BASE']; + } else { + $result->connection = &$this->connections[$connection]; + } + return $result; + } + + /** + * Initializes the connection to the Kolab Storage system. + * + * @return NULL + */ + protected function connect() + { + $this->connections['BASE'] = &Horde_Kolab_Storage_Driver::factory($this->_driver, + $this->_params); + } + + /** + * Returns the list of folders visible to the current user. + * + * @return array The list of IMAP folders, represented as + * Horde_Kolab_Storage_Folder objects. + */ + public function &listFolders() + { + $this->initiateCache(); + $result = array_keys($this->_list); + return $result; + } + + /** + * Get several or all Folder objects. + * + * @param array $folders Several folder names or unset to retrieve + * all folders. + * + * @return array An array of Horde_Kolab_Storage_Folder objects. + */ + function getFolders($folders = null) + { + if (!isset($folders)) { + $folders = $this->listFolders(); + } + + $result = array(); + foreach ($folders as $folder) { + $result[] = $this->getFolder($folder); + } + return $result; + } + + /** + * Get a Folder object. + * + * @param string $folder The folder name. + * + * @return Horde_Kolab_Storage_Folder The Kolab folder object. */ function &getFolder($folder) { - $list = &Kolab_List::singleton(); - $share = $list->getFolder($folder); + if (!isset($this->_folders[$folder])) { + $result = $this->getConnection($folder); + + $kf = new Horde_Kolab_Storage_Folder($result->name); + $kf->restore($this, $result->connection); + $this->_folders[$folder] = &$kf; + } + return $this->_folders[$folder]; + } + + /** + * Get a new Folder object. + * + * @param string $connection The name of the connection for the folder. + * + * @return Horde_Kolab_Storage_Folder The new Kolab folder object. + */ + function getNewFolder($connection = null) + { + if (empty($connection) || !isset($this->connections[$connection])) { + $connection = &$this->connections['BASE']; + } else { + $connection = &$this->connections[$connection]; + } + $folder = new Horde_Kolab_Storage_Folder(null); + $folder->restore($this, $connection); + return $folder; + } + + /** + * Get a Folder object based on a share ID. + * + * @param string $share The share ID. + * @param string $type The type of the share/folder. + * + * @return Horde_Kolab_Storage_Folder The Kolab folder object. + */ + function getByShare($share, $type) + { + $folder = $this->parseShare($share, $type); + return $this->getFolder($folder); + } + + /** + * Get a list of folders based on the type. + * + * @param string $type The type of the share/folder. + * + * @return Horde_Kolab_Storage_Folder The list of Kolab folder objects. + */ + function getByType($type) + { + $this->initiateCache(); + if (isset($this->_types[$type])) { + return $this->getFolders($this->_types[$type]); + } else { + return array(); + } + } + + /** + * Get the default folder for a certain type. + * + * @param string $type The type of the share/folder. + * + * @return mixed The default folder, false if there is no default. + */ + function getDefault($type) + { + $this->initiateCache(); + if (isset($this->_defaults[$this->_owner][$type])) { + return $this->getFolder($this->_defaults[$this->_owner][$type]); + } else { + return false; + } + } + + /** + * Get the default folder for a certain type from a different owner. + * + * @param string $owner The folder owner. + * @param string $type The type of the share/folder. + * + * @return mixed The default folder, false if there is no default. + */ + function getForeignDefault($owner, $type) + { + $this->initiateCache(); + if (isset($this->_defaults[$owner][$type])) { + return $this->getFolder($this->_defaults[$owner][$type]); + } else { + return false; + } + } + + /** + * Converts the horde syntax for shares to storage identifiers. + * + * @param string $share The share ID that should be parsed. + * @param string $type The type of the share/folder. + * + * @return string The corrected folder name. + */ + function parseShare($share, $type) + { + // Handle default shares + if (class_exists('Horde_Auth') + && $share == Horde_Auth::getAuth()) { + $result = $this->getDefault($type); + if (!empty($result)) { + return $result->name; + } + } + return rawurldecode($share); + } + + /** + * Start the cache for the type specific and the default folders. + * + * @return NULL + */ + function initiateCache() + { + if (isset($this->_list) && isset($this->_types) && isset($this->_defaults)) { + return; + } + + $this->_list = array(); + $this->_types = array(); + $this->_defaults = array(); + + foreach ($this->connections as $key => $connection) { + if ($key == 'BASE') { + // Obtain a list of all folders the current user has access to + $folders = array_merge($this->_list, $connection->getMailboxes()); + } else { + $list = $connection->getMailboxes(); + foreach ($list as $item) { + $folders[] = $key . '@' . $item; + } + } + } + + foreach ($folders as $folder) { + $fo = $this->getFolder($folder); + $type = $fo->getType(); + $default = $fo->isDefault(); + $owner = $fo->getOwner(); + + $this->_list[$folder] = array($type, $default, $owner); + if (!isset($this->_types[$type])) { + $this->_types[$type] = array(); + } + $this->_types[$type][] = $folder; + if ($default) { + $this->_defaults[$owner][$type] = $folder; + } + } + } + + /** + * Update the cache variables. + * + * @param Horde_Kolab_Storage_Folder &$folder The folder that was added. + * + * @return NULL + */ + function addToCache(&$folder) + { + $this->initiateCache(); + + try { + $type = $folder->getType(); + $default = $folder->isDefault(); + $owner = $folder->getOwner(); + } catch (Exception $e) { + Horde::logMessage(sprintf("Error while updating the Kolab folder list cache: %s.", + $e->getMessage()), __FILE__, __LINE__, PEAR_LOG_ERR); + return; + } + + $this->_folders[$folder->name] = &$folder; + $this->_list[$folder->name] = array($type, $default, $owner); + $this->_types[$type][] = $folder->name; + + if ($default) { + $this->_defaults[$owner][$type] = $folder->name; + } + } + + /** + * Update the cache variables. + * + * @param Horde_Kolab_Storage_Folder &$folder The folder that was removed. + * + * @return NULL + */ + function removeFromCache(&$folder) + { + $this->initiateCache(); + + unset($this->_folders[$folder->name]); + if (isset($this->_list)) { + if (in_array($folder->name, array_keys($this->_list))) { + list($type, $default, $owner) = $this->_list[$folder->name]; + unset($this->_list[$folder->name]); + } + } + if (isset($this->_types[$type])) { + $idx = array_search($folder->name, $this->_types[$type]); + if ($idx !== false) { + unset($this->_types[$type][$idx]); + } + } + if ($default && isset($this->_defaults[$owner][$type])) { + unset($this->_defaults[$owner][$type]); + } + } + + /** + * Return the folder object corresponding to the share of the + * specified type (e.g. "contact", "event" etc.). + * + * @param string $share The id of the share. + * @param string $type The share type. + * + * @return Horde_Kolab_Folder The folder object representing + * the share. + */ + public function &getShare($share, $type) + { + $share = $this->getByShare($share, $type); return $share; } @@ -81,15 +578,17 @@ class Kolab_Storage { * Return a data object for accessing data in the specified * folder. * - * @param Kolab_Folder $folder The folder object. - * @param string $data_type The type of data we want to - * access in the folder. - * @param int $data_format The version of the data format - * we want to access in the folder. + * @param Horde_Kolab_Storage_Folder &$folder The folder object. + * @param string $data_type The type of data we want + * to access in the folder. + * @param int $data_format The version of the data + * format we want to access + * in the folder. * - * @return Kolab_Data|PEAR_Error The data object. + * @return Horde_Kolab_Data The data object. */ - function &getData(&$folder, $data_type = null, $data_format = 1) + public function &getData(Horde_Kolab_Storage_Folder &$folder, + $data_type = null, $data_format = 1) { if (empty($data_type)) { $data_type = $folder->getType(); @@ -102,22 +601,19 @@ class Kolab_Storage { * Return a data object for accessing data in the specified * share. * - * @param string $share The id of the share. - * @param string $type The share type. - * @param string $data_type The type of data we want to - * access in the folder. - * @param int $data_format The version of the data format - * we want to access in the folder. + * @param string $share The id of the share. + * @param string $type The share type. + * @param string $data_type The type of data we want to + * access in the folder. + * @param int $data_format The version of the data format + * we want to access in the folder. * - * @return Kolab_Data|PEAR_Error The data object. + * @return Horde_Kolab_Data The data object. */ - function &getShareData($share, $type, $data_type = null, $data_format = 1) + public function &getShareData($share, $type, $data_type = null, $data_format = 1) { - $folder = Kolab_Storage::getShare($share, $type); - if (is_a($folder, 'PEAR_Error')) { - return $folder; - } - $data = Kolab_Storage::getData($folder, $data_type, $data_format); + $folder = $this->getShare($share, $type); + $data = $this->getData($folder, $data_type, $data_format); return $data; } @@ -125,21 +621,18 @@ class Kolab_Storage { * Return a data object for accessing data in the specified * folder. * - * @param string $folder The name of the folder. - * @param string $data_type The type of data we want to - * access in the folder. - * @param int $data_format The version of the data format - * we want to access in the folder. + * @param string $folder The name of the folder. + * @param string $data_type The type of data we want to + * access in the folder. + * @param int $data_format The version of the data format + * we want to access in the folder. * - * @return Kolab_Data|PEAR_Error The data object. + * @return Horde_Kolab_Data The data object. */ - function &getFolderData($folder, $data_type = null, $data_format = 1) + public function &getFolderData($folder, $data_type = null, $data_format = 1) { - $folder = Kolab_Storage::getFolder($folder); - if (is_a($folder, 'PEAR_Error')) { - return $folder; - } - $data = Kolab_Storage::getData($folder, $data_type, $data_format); + $folder = $this->getFolder($folder); + $data = $this->getData($folder, $data_type, $data_format); return $data; } } diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Cache.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Cache.php index 24f19f1fb..a52e7c3b6 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Cache.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Cache.php @@ -1,36 +1,60 @@ + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ -/** We need the Horde Cache system for caching */ -require_once 'Horde/Cache.php'; +/** + * The Autoloader allows us to omit "require/include" statements. + */ +require_once 'Horde/Autoloader.php'; /** - * The Kolab_Cache class provides a cache for the Kolab - * storage for groupware objects + * The Kolab_Cache class provides a cache for Kolab groupware objects. + * + * The Horde_Kolab_Storage_Cache singleton instance provides caching for all + * storage folders. So before operating on the cache data it is necessary to + * load the desired folder data. Before switching the folder the cache data + * should be saved. * - * $Horde: framework/Kolab_Storage/lib/Horde/Kolab/Storage/Cache.php,v 1.5 2009/01/06 17:49:27 jan Exp $ + * This class does not offer a lot of safeties and is primarily intended to be + * used within the Horde_Kolab_Storage_Data class. * * Copyright 2007-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Gunnar Wrobel - * @author Thomas Jarosch - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Thomas Jarosch + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ -class Kolab_Cache { +class Horde_Kolab_Storage_Cache +{ + /** + * Singleton instance. + * + * @var array + */ + static protected $instance; /** * The version of the cache we loaded. * * @var int */ - var $_version; + protected $version; /** * The internal version of the cache format represented by the @@ -38,21 +62,21 @@ class Kolab_Cache { * * @var int */ - var $_base_version = 1; + protected $base_version = 1; /** * The version of the data format provided by the storage handler. * * @var int */ - var $_data_version; + protected $data_version; /** * The version of the cache format that includes the data version. * * @var int */ - var $_cache_version = -1; + protected $cache_version = -1; /** * A validity marker for a share in the cache. This allows the @@ -60,7 +84,7 @@ class Kolab_Cache { * * @var int */ - var $validity; + public $validity; /** * A nextid marker for a share in the cache. This allows the @@ -68,7 +92,7 @@ class Kolab_Cache { * * @var int */ - var $nextid; + public $nextid; /** * The objects of the current share. @@ -80,7 +104,7 @@ class Kolab_Cache { * * @var array */ - var $objects; + public $objects; /** * The uid<->object mapping of the current share. @@ -91,57 +115,65 @@ class Kolab_Cache { * * @var array */ - var $uids; + public $uids; /** * The unique key for the currently loaded data. * * @var string */ - var $_key; + protected $key; /** * The link to the horde cache. * * @var Horde_Cache */ - var $_horde_cache; + protected $horde_cache; /** * Constructor. + * + * @todo Improve the cache setup and allow different cache types. + * + * @throws Horde_Exception */ - function Kolab_Cache() + public function __construct() { - /** - * We explicitly select the file based cache to ensure - * that different users have access to the same cache - * data. I am not certain this is guaranteed for the other - * possible cache drivers. - */ - $this->_horde_cache = &Horde_Cache::singleton('file', - array('prefix' => 'kolab_cache', - 'dir' => Horde::getTempDir())); + if (!isset($GLOBALS['conf']['kolab']['storage']['cache']['data']['driver'])) { + $driver = 'file'; + $params = array('prefix' => 'kolab_cache', 'dir' => Horde::getTempDir()); + } else { + $driver = $GLOBALS['conf']['kolab']['storage']['cache']['data']['driver']; + if (!isset($GLOBALS['conf']['kolab']['storage']['cache']['data']['params'])) { + + $params = array(); + } else { + $params = $GLOBALS['conf']['kolab']['storage']['cache']['data']['params']; + } + } + $this->horde_cache = &Horde_Cache::singleton($driver, $params); } /** - * Attempts to return a reference to a concrete - * Kolab_Cache instance. It will only create a new - * instance if no Kolab_Cache instance currently exists. + * Attempts to return a reference to a concrete Horde_Kolab_Storage_Cache + * instance. It will only create a new instance if no + * Horde_Kolab_Storage_Cache instance currently exists. + * + * This method must be invoked as: * - * This method must be invoked as: $var = &Kolab_Cache::singleton() + * $var = &Horde_Kolab_Storage_Cache::singleton() * - * @return Kolab_Cache The concrete Kolab_Cache - * reference, or false on error. + * @return Horde_Kolab_Storage_Cache The concrete Horde_Kolab_Storage_Cache + * reference, or false on error. */ - function &singleton() + static public function &singleton() { - static $kolab_cache; - - if (!isset($kolab_cache)) { - $kolab_cache = new Kolab_Cache(); + if (!isset(self::$instance)) { + self::$instance = new Horde_Kolab_Storage_Cache(); } - return $kolab_cache; + return self::$instance; } /** @@ -151,21 +183,23 @@ class Kolab_Cache { * @param int $data_version A version identifier provided by * the storage manager. * @param bool $force Force loading the cache. + * + * @return NULL */ - function load($key, $data_version, $force = false) + public function load($key, $data_version, $force = false) { - if (!$force && $this->_key == $key - && $this->_data_version == $data_version) { + if (!$force && $this->key == $key + && $this->data_version == $data_version) { return; } - $this->_key = $key; - $this->_data_version = $data_version; - $this->_cache_version = ($data_version << 8) | $this->_base_version; + $this->key = $key; + $this->data_version = $data_version; + $this->cache_version = ($data_version << 8) | $this->base_version; $this->reset(); - $cache = $this->_horde_cache->get($this->_key, 0); + $cache = $this->horde_cache->get($this->key, 0); if (!$cache) { return; @@ -174,28 +208,28 @@ class Kolab_Cache { $data = unserialize($cache); // Delete disc cache if it's from an old version - if ($data['version'] != $this->_cache_version) { - $this->_horde_cache->expire($this->_key); + if ($data['version'] != $this->cache_version) { + $this->horde_cache->expire($this->key); $this->reset(); } else { - $this->_version = $data['version']; + $this->version = $data['version']; $this->validity = $data['uidvalidity']; - $this->nextid = $data['uidnext']; - $this->objects = $data['objects']; - $this->uids = $data['uids']; + $this->nextid = $data['uidnext']; + $this->objects = $data['objects']; + $this->uids = $data['uids']; } } /** * Load a cached attachment. * - * @param string $key Access key to the cached data. + * @param string $key Access key to the cached data. * * @return mixed The data of the object. */ - function loadAttachment($key) + public function loadAttachment($key) { - return $this->_horde_cache->get($key, 0); + return $this->horde_cache->get($key, 0); } /** @@ -206,21 +240,23 @@ class Kolab_Cache { * * @return boolean True if successfull. */ - function storeAttachment($key, $data) + public function storeAttachment($key, $data) { - return $this->_horde_cache->set($key, $data); + return $this->horde_cache->set($key, $data); } /** * Initialize the cache structure. + * + * @return NULL */ - function reset() + public function reset() { - $this->_version = $this->_cache_version; + $this->version = $this->cache_version; $this->validity = -1; - $this->nextid = -1; - $this->objects = array(); - $this->uids = array(); + $this->nextid = -1; + $this->objects = array(); + $this->uids = array(); } /** @@ -228,59 +264,54 @@ class Kolab_Cache { * * @return boolean True on success. */ - function save() + public function save() { - if (!isset($this->_key)) { - return PEAR::raiseError('The cache has not been loaded yet!'); - } - - $data = array('version' => $this->_version, + $data = array('version' => $this->version, 'uidvalidity' => $this->validity, 'uidnext' => $this->nextid, 'objects' => $this->objects, 'uids' => $this->uids); - return $this->_horde_cache->set($this->_key, - serialize($data)); + return $this->horde_cache->set($this->key, + serialize($data)); } /** * Store an object in the cache. * - * @param int $id The storage ID. - * @param string $object_id The object ID. - * @param array $object The object data. + * @param int $id The storage ID. + * @param string $object_id The object ID. + * @param array &$object The object data. + * + * @return NULL */ - function store($id, $object_id, &$object) + public function store($id, $object_id, &$object) { - $this->uids[$id] = $object_id; + $this->uids[$id] = $object_id; $this->objects[$object_id] = $object; } /** * Mark the ID as invalid (cannot be correctly parsed). * - * @param int $id The ID of the storage item to ignore. + * @param int $id The ID of the storage item to ignore. + * + * @return NULL */ - function ignore($id) + public function ignore($id) { $this->uids[$id] = false; } /** * Deliberately expire a cache. + * + * @return NULL */ - function expire() + public function expire() { - if (!isset($this->_key)) { - return PEAR::raiseError('The cache has not been loaded yet!'); - } - - $this->_version = -1; + $this->version = -1; $this->save(); - $this->load($this->_key, $this->_data_version, true); + $this->load($this->key, $this->data_version, true); } - } - - diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Data.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Data.php index a46d4108b..287a88175 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Data.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Data.php @@ -1,72 +1,83 @@ + * @author Thomas Jarosch + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ -/** Data caching for Kolab **/ -require_once 'Horde/Kolab/Storage/Cache.php'; +/** + * The Autoloader allows us to omit "require/include" statements. + */ +require_once 'Horde/Autoloader.php'; /** - * The Kolab_Data class represents a data type in an IMAP folder on the Kolab - * server. + * The Kolab_Data class represents a data type in a Kolab storage + * folder on the Kolab server. * - * $Horde: framework/Kolab_Storage/lib/Horde/Kolab/Storage/Data.php,v 1.9 2009/01/14 23:39:12 wrobel Exp $ - * - * Copyright 2004-2009 The Horde Project (http://www.horde.org/) + * Copyright 2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Stuart Binge - * @author Gunnar Wrobel - * @author Thomas Jarosch - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Stuart Binge + * @author Thomas Jarosch + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ -class Kolab_Data { - +class Horde_Kolab_Storage_Data +{ /** - * The link to the folder object. + * The link to the parent folder object. * * @var Kolab_Folder */ - var $_folder; + private $_folder; /** * The folder type. * * @var string */ - var $_type; + private $_type; /** * The object type of the data. * * @var string */ - var $_object_type; + private $_object_type; /** * The version of the data. * * @var int */ - var $_data_version; + private $_data_version; /** * The data cache. * * @var Kolab_Cache */ - var $_cache; + private $_cache; /** * The Id of this data object in the cache. * * @var string */ - var $_cache_key; + private $_cache_key; /** * An addition to the cache key in case we are operating on @@ -74,29 +85,29 @@ class Kolab_Data { * * @var string */ - var $_type_key; + private $_type_key; /** * Do we optimize for cyrus IMAPD? * * @var boolean */ - var $_cache_cyrus_optimize = true; + private $_cache_cyrus_optimize = true; /** * Creates a Kolab Folder Data representation. * - * @param string $type Type of the folder. - * @param string $object_type Type of the objects we want to read. - * @param int $data_version Format version of the object data. + * @param string $type Type of the folder. + * @param string $object_type Type of the objects we want to read. + * @param int $data_version Format version of the object data. */ - function Kolab_Data($type, $object_type = null, $data_version = 1) + public function __construct($type, $object_type = null, $data_version = 1) { $this->_type = $type; if (!empty($object_type)) { - $this->_object_type = $object_type; + $this->_object_type = $object_type; } else { - $this->_object_type = $type; + $this->_object_type = $type; } $this->_data_version = $data_version; @@ -110,18 +121,20 @@ class Kolab_Data { /** * Initializes the object. + * + * @return NULL */ - function __wakeup() + public function __wakeup() { - $this->_cache = &Kolab_Cache::singleton(); + $this->_cache = &Horde_Kolab_Storage_Cache::singleton(); } /** * Returns the properties that need to be serialized. * - * @return array List of serializable properties. + * @return array List of serializable properties. */ - function __sleep() + public function __sleep() { $properties = get_object_vars($this); unset($properties['_cache'], $properties['_folder']); @@ -130,14 +143,27 @@ class Kolab_Data { } /** - * Set the folder handler. + * Set the folder handler for this data instance. * - * @param Kolab_Folder $folder The handler for the folder of folders. + * @param Kolab_Folder &$folder The handler for the folder. + * + * @return NULL */ - function setFolder(&$folder) + public function setFolder(&$folder) { - $this->_folder = &$folder; - $this->_cache_key = $this->_getCacheKey(); + $this->_folder = &$folder; + $this->_cache_key = $this->getCacheKey(); + } + + /** + * Expire the cache. + * + * @return NULL + */ + public function expireCache() + { + $this->_cache->load($this->_cache_key, $this->_data_version); + $this->_cache->expire(); } /** @@ -145,14 +171,14 @@ class Kolab_Data { * * @return string A key that represents the current folder. */ - function _getCacheKey() + public function getCacheKey() { if ($this->_cache_cyrus_optimize) { $search_prefix = 'INBOX/'; $pos = strpos($this->_folder->name, $search_prefix); if ($pos !== false && $pos == 0) { - $key = 'user/' . Auth::getBareAuth() . '/' + $key = 'user/' . Horde_Auth::getBareAuth() . '/' . substr($this->_folder->name, strlen($search_prefix)) . $this->_type_key; @@ -168,19 +194,19 @@ class Kolab_Data { /** * Delete the specified message from this folder. * - * @param string $object_uid Id of the message to be deleted. + * @param string $object_uid Id of the message to be deleted. * * @return boolean|PEAR_Error True is successful, false if the * message does not exist. */ - function delete($object_uid) + public function delete($object_uid) { if (!$this->objectUidExists($object_uid)) { return false; } // Find the storage ID - $id = $this->_getStorageId($object_uid); + $id = $this->getStorageId($object_uid); if ($id === false) { return false; } @@ -190,8 +216,6 @@ class Kolab_Data { return $result; } - $this->_cache->load($this->_cache_key, $this->_data_version); - unset($this->_cache->objects[$object_uid]); unset($this->_cache->uids[$id]); $this->_cache->save(); @@ -203,18 +227,15 @@ class Kolab_Data { * * @return boolean|PEAR_Error True if successful. */ - function deleteAll() + public function deleteAll() { + $this->_cache->load($this->_cache_key, $this->_data_version); + if (empty($this->_cache->uids)) { return true; } foreach ($this->_cache->uids as $id => $object_uid) { - $result = $this->_folder->deleteMessage($id, false); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $this->_cache->load($this->_cache_key, $this->_data_version); + $this->_folder->deleteMessage($id, false); unset($this->_cache->objects[$object_uid]); unset($this->_cache->uids[$id]); @@ -235,30 +256,25 @@ class Kolab_Data { * Move the specified message from the current folder into a new * folder. * - * @param string $object_uid ID of the message to be deleted. - * @param string $new_share ID of the target share. + * @param string $object_uid ID of the message to be deleted. + * @param string $new_share ID of the target share. * * @return boolean|PEAR_Error True is successful, false if the * object does not exist. */ - function move($object_uid, $new_share) + public function move($object_uid, $new_share) { if (!$this->objectUidExists($object_uid)) { return false; } // Find the storage ID - $id = $this->_getStorageId($object_uid); + $id = $this->getStorageId($object_uid); if ($id === false) { return false; } $result = $this->_folder->moveMessageToShare($id, $new_share); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $this->_cache->load($this->_cache_key, $this->_data_version); unset($this->_cache->objects[$object_uid]); unset($this->_cache->uids[$id]); @@ -269,44 +285,42 @@ class Kolab_Data { /** * Save an object. * - * @param array $object The array that holds the data object. - * @param string $old_object_id The id of the object if it existed before. + * @param array $object The array that holds the data object. + * @param string $old_object_id The id of the object if it existed before. + * + * @return boolean True on success. * - * @return boolean|PEAR_Error True on success. + * @throws Horde_Kolab_Storage_Exception In case the given old object id + * is invalid or an error occured + * while saving the data. */ - function save($object, $old_object_id = null) + public function save($object, $old_object_id = null) { // update existing kolab object if ($old_object_id != null) { // check if object really exists if (!$this->objectUidExists($old_object_id)) { - return PEAR::raiseError(sprintf(_("Old object %s does not exist."), - $old_object_id)); + throw new Horde_Kolab_Storage_Exception(sprintf(_("Old object %s does not exist."), + $old_object_id)); } // get the storage ID - $id = $this->_getStorageId($old_object_id); + $id = $this->getStorageId($old_object_id); if ($id === false) { - return PEAR::raiseError(sprintf(_("Old object %s does not map to a uid."), - $old_object_id)); + throw new Horde_Kolab_Storage_Exception(sprintf(_("Old object %s does not map to a uid."), + $old_object_id)); } $old_object = $this->getObject($old_object_id); } else { - $id = null; + $id = null; $old_object = null; } - $result = $this->_folder->saveObject($object, $this->_data_version, - $this->_object_type, $id, $old_object); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_folder->saveObject($object, $this->_data_version, + $this->_object_type, $id, $old_object); - $result = $this->synchronize($old_object_id); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->synchronize($old_object_id); return true; } @@ -315,19 +329,19 @@ class Kolab_Data { * * @param string $history_ignore Object uid that should not be * updated in the History + * + * @return NULL */ - function synchronize($history_ignore = null) + public function synchronize($history_ignore = null) { $this->_cache->load($this->_cache_key, $this->_data_version); $result = $this->_folder->getStatus(); - if (is_a($result, 'PEAR_Error')) { - return $result; - } list($validity, $nextid, $ids) = $result; - $changes = $this->_folderChanged($validity, $nextid, array_keys($this->_cache->uids), $ids); + $changes = $this->_folderChanged($validity, $nextid, + array_keys($this->_cache->uids), $ids); if ($changes) { $modified = array(); @@ -335,10 +349,8 @@ class Kolab_Data { $formats = $this->_folder->getFormats(); - $handler = Horde_Kolab_Format::factory('XML', $this->_object_type, $this->_data_version); - if (is_a($handler, 'PEAR_Error')) { - return $handler; - } + $handler = Horde_Kolab_Format::factory('Xml', $this->_object_type, + $this->_data_version); $count = 0; foreach ($recent_uids as $id) { @@ -347,12 +359,14 @@ class Kolab_Data { continue; } - $mime = $this->_folder->parseMessage($id, $handler->getMimeType(), false); - if (is_a($mime, 'PEAR_Error')) { + try { + $mime = $this->_folder->parseMessage($id, + $handler->getMimeType(), + false); + $text = $mime[0]; + } catch (Horde_Kolab_Storage_Exception $e) { Horde::logMessage($mime, __FILE__, __LINE__, PEAR_LOG_WARNING); $text = false; - } else { - $text = $mime[0]; } if ($text) { @@ -360,7 +374,8 @@ class Kolab_Data { if (is_a($object, 'PEAR_Error')) { $this->_cache->ignore($id); $object->addUserInfo('STORAGE ID: ' . $id); - Horde::logMessage($object, __FILE__, __LINE__, PEAR_LOG_WARNING); + Horde::logMessage($object, __FILE__, __LINE__, + PEAR_LOG_WARNING); continue; } } else { @@ -368,7 +383,7 @@ class Kolab_Data { } if ($object !== false) { - $message = &$mime[2]; + $message = &$mime[2]; $handler_type = $handler->getMimeType(); foreach ($message->getParts() as $part) { $name = $part->getName(); @@ -377,13 +392,15 @@ class Kolab_Data { if (!empty($name) && $type != $handler_type || (!empty($dp) && in_array($dp, $formats))) { $object['_attachments'][$name]['type'] = $type; - $object['_attachments'][$name]['key'] = $this->_cache_key . '/' . $object['uid'] . ':' . $name; - $part->transferDecodeContents(); + $object['_attachments'][$name]['key'] = $this->_cache_key . '/' . $object['uid'] . ':' . $name; + //@todo: Check what to do with this call + //$part->transferDecodeContents(); $result = $this->_cache->storeAttachment($object['_attachments'][$name]['key'], $part->getContents()); if (is_a($result, 'PEAR_Error')) { Horde::logMessage(sprintf('Failed storing attachment of object %s: %s', - $id, $result->getMessage()), + $id, + $result->getMessage()), __FILE__, __LINE__, PEAR_LOG_ERR); $object = false; break; @@ -435,8 +452,10 @@ class Kolab_Data { * @param string $object_uid Object uid that should be updated. * @param int $mod_ts Timestamp of the modification. * @param string $action The action that was performed. + * + * @return NULL */ - function _updateHistory($object_uid, $mod_ts, $action) + private function _updateHistory($object_uid, $mod_ts, $action) { global $registry; @@ -453,28 +472,33 @@ class Kolab_Data { return $app; } + if (!class_exists('Horde_History')) { + return; + } + /* Log the action on this item in the history log. */ $history = &Horde_History::singleton(); $history_id = $app . ':' . $this->_folder->getShareId() . ':' . $object_uid; - $history->log($history_id, array('action' => $action, 'ts' => $mod_ts), true); + $history->log($history_id, array('action' => $action, 'ts' => $mod_ts), + true); } /** * Check if the folder has changed and the cache needs to be updated. * - * @param string $validity ID validity of the folder. - * @param string $nextid next ID for the folder. - * @param array $old_ids Old list of IDs in the folder. - * @param array $new_ids New list of IDs in the folder. + * @param string $validity ID validity of the folder. + * @param string $nextid next ID for the folder. + * @param array &$old_ids Old list of IDs in the folder. + * @param array &$new_ids New list of IDs in the folder. * * @return mixed True or an array of deleted IDs if the * folder changed and false otherwise. */ - function _folderChanged($validity, $nextid, &$old_ids, &$new_ids) + private function _folderChanged($validity, $nextid, &$old_ids, &$new_ids) { - $changed = false; + $changed = false; $reset_done = false; // uidvalidity changed? @@ -489,7 +513,7 @@ class Kolab_Data { } $this->_cache->validity = $validity; - $this->_cache->nextid = $nextid; + $this->_cache->nextid = $nextid; if ($reset_done) { return true; @@ -497,9 +521,9 @@ class Kolab_Data { // Speed optimization: if nextid and validity didn't change // and count(old_ids) == count(new_ids), the folder didn't change. - if ($changed || count($old_ids) != count ($new_ids)) { + if ($changed || count($old_ids) != count($new_ids)) { // remove deleted messages from cache - $delete_ids = array_diff($old_ids, $new_ids); + $delete_ids = array_diff($old_ids, $new_ids); $deleted_oids = array(); foreach ($delete_ids as $delete_id) { $object_id = $this->_cache->uids[$delete_id]; @@ -521,11 +545,11 @@ class Kolab_Data { /** * Return the IMAP ID for the given object ID. * - * @param string $object_id The object ID. + * @param string $object_uid The object ID. * - * @return int The IMAP ID. + * @return int The IMAP ID. */ - function _getStorageId($object_uid) + public function getStorageId($object_uid) { $this->_cache->load($this->_cache_key, $this->_data_version); @@ -540,11 +564,11 @@ class Kolab_Data { /** * Test if the storage ID exists. * - * @param int $uid The storage ID. + * @param int $uid The storage ID. * - * @return boolean True if the ID exists. + * @return boolean True if the ID exists. */ - function _storageIdExists($uid) + public function storageIdExists($uid) { $this->_cache->load($this->_cache_key, $this->_data_version); @@ -556,11 +580,11 @@ class Kolab_Data { * * @return string The unique id. */ - function generateUID() + public function generateUID() { do { $key = md5(uniqid(mt_rand(), true)); - } while($this->objectUidExists($key)); + } while ($this->objectUidExists($key)); return $key; } @@ -568,11 +592,11 @@ class Kolab_Data { /** * Check if the given id exists. * - * @param string $uid The object id. + * @param string $uid The object id. * - * @return boolean True if the id was found, false otherwise. + * @return boolean True if the id was found, false otherwise. */ - function objectUidExists($uid) + public function objectUidExists($uid) { $this->_cache->load($this->_cache_key, $this->_data_version); @@ -582,16 +606,16 @@ class Kolab_Data { /** * Return the specified object. * - * @param string $object_id The object id. + * @param string $object_id The object id. * - * @return array|PEAR_Error The object data as an array. + * @return array|PEAR_Error The object data as an array. */ - function getObject($object_id) + public function getObject($object_id) { $this->_cache->load($this->_cache_key, $this->_data_version); - if (!$this->objectUidExists($object_id)) { - return PEAR::raiseError(sprintf(_("Kolab cache: Object uid %s does not exist in the cache!"), $object_id)); + if (!isset($this->_cache->objects[$object_id])) { + throw new Horde_Kolab_Storage_Exception(sprintf(_("Kolab cache: Object uid %s does not exist in the cache!"), $object_id)); } return $this->_cache->objects[$object_id]; } @@ -599,12 +623,14 @@ class Kolab_Data { /** * Return the specified attachment. * - * @param string $attachment_id The attachment id. + * @param string $attachment_id The attachment id. * * @return string|PEAR_Error The attachment data as a string. */ - function getAttachment($attachment_id) + public function getAttachment($attachment_id) { + $this->_cache->load($this->_cache_key, $this->_data_version); + return $this->_cache->loadAttachment($attachment_id); } @@ -613,7 +639,7 @@ class Kolab_Data { * * @return array The object ids. */ - function getObjectIds() + public function getObjectIds() { $this->_cache->load($this->_cache_key, $this->_data_version); @@ -625,7 +651,7 @@ class Kolab_Data { * * @return array All object data arrays. */ - function getObjects() + public function getObjects() { $this->_cache->load($this->_cache_key, $this->_data_version); @@ -637,7 +663,7 @@ class Kolab_Data { * * @return array The object data array. */ - function getObjectArray() + public function getObjectArray() { $this->_cache->load($this->_cache_key, $this->_data_version); diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Driver.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Driver.php new file mode 100644 index 000000000..8d09ad737 --- /dev/null +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Driver.php @@ -0,0 +1,50 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ + +/** + * The driver class for accessing Kolab storage. + * + * Copyright 2004-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ +class Horde_Kolab_Storage_Driver +{ + + /** + * Factory. + * + * @param string $driver The driver type used for the storage connection. + * @param array $params Additional connection parameters. + * + * @return Horde_Kolab_Storage_List A concrete list instance. + */ + static public function &factory($driver, $params = array()) + { + $class = 'Horde_Kolab_Storage_Driver_' . ucfirst(basename($driver)); + if (class_exists($class)) { + $driver = new $class($params); + return $driver; + } + throw new Horde_Kolab_Storage_Exception( + 'Driver type definition "' . $class . '" missing.'); + + } +} \ No newline at end of file diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Driver/Imap.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Driver/Imap.php new file mode 100644 index 000000000..3b74f52b3 --- /dev/null +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Driver/Imap.php @@ -0,0 +1,315 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ + +/** + * The IMAP driver class for accessing Kolab storage. + * + * Copyright 2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ +class Horde_Kolab_Storage_Driver_Imap extends Horde_Kolab_Storage_Driver +{ + /** + * The IMAP connection + * + * @var Horde_Imap_Client + */ + private $_imap; + + /** + * Constructor. + * + * @param array $params Connection parameters. + */ + public function __construct($params = array()) + { + if (isset($params['driver'])) { + $driver = $params['driver']; + unset($params['driver']); + } else { + $driver = 'socket'; + } + $this->_imap = Horde_Imap_Client::factory($driver, $params); + } + + /** + * Retrieves a list of mailboxes on the server. + * + * @return array The list of mailboxes. + */ + public function getMailboxes() + { + return $this->_imap->listMailboxes('', Horde_Imap_Client::MBOX_ALL, array('flat' => true)); + } + + /** + * Opens the given folder. + * + * @param string $folder The folder to open + * + * @return mixed True in case the folder was opened successfully, a PEAR + * error otherwise. + */ + public function select($folder) + { + $this->_imap->openMailbox($folder, Horde_Imap_Client::OPEN_AUTO); + return true; + } + + /** + * Does the given folder exist? + * + * @param string $folder The folder to check. + * + * @return boolean True in case the folder exists, false otherwise. + */ + public function exists($folder) + { + $folders = $this->getMailboxes(); + if (in_array($folder, $folders)) { + return true; + } + return false; + } + + /** + * Returns the status of the current folder. + * + * @param string $folder Check the status of this folder. + * + * @return array An array that contains 'uidvalidity' and 'uidnext'. + */ + function status($folder) + { + return $this->_imap->status($folder, + Horde_Imap_Client::STATUS_UIDNEXT + | Horde_Imap_Client::STATUS_UIDVALIDITY); + } + + /** + * Returns the message ids of the messages in this folder. + * + * @param string $folder Check the status of this folder. + * + * @return array The message ids. + */ + function getUids($folder) + { + $search_query = new Horde_Imap_Client_Search_Query(); + $search_query->flag('DELETED', false); + $uidsearch = $this->_imap->search($folder, $search_query); + $uids = $uidsearch['match']; + return $uids; + } + + /** + * Create the specified folder. + * + * @param string $folder The folder to create. + * + * @return mixed True in case the operation was successfull, a + * PEAR error otherwise. + */ + public function create($folder) + { + return $this->_imap->createMailbox($folder); + } + + /** + * Delete the specified folder. + * + * @param string $folder The folder to delete. + * + * @return mixed True in case the operation was successfull, a + * PEAR error otherwise. + */ + function delete($folder) + { + return $this->_imap->deleteMailbox($folder); + } + + /** + * Rename the specified folder. + * + * @param string $old The folder to rename. + * @param string $new The new name of the folder. + * + * @return mixed True in case the operation was successfull, a + * PEAR error otherwise. + */ + function rename($old, $new) + { + return $this->_imap->renameMailbox($old, $new); + } + + /** + * Appends a message to the current folder. + * + * @param string $mailbox The mailbox to append the message(s) to. Either + * in UTF7-IMAP or UTF-8. + * @param string $msg The message to append. + * + * @return mixed True or a PEAR error in case of an error. + */ + function appendMessage($mailbox, $msg) + { + return $this->_imap->append($mailbox, array(array('data' => $msg))); + } + + /** + * Deletes messages from the current folder. + * + * @param integer $uids IMAP message ids. + * + * @return mixed True or a PEAR error in case of an error. + */ + function deleteMessages($mailbox, $uids) + { + if (!is_array($uids)) { + $uids = array($uids); + } + return $this->_imap->store($mailbox, array('add' => array('\\deleted'), 'ids' => $uids)); + } + + /** + * Moves a message to a new folder. + * + * @param integer $uid IMAP message id. + * @param string $new_folder Target folder. + * + * @return mixed True or a PEAR error in case of an error. + */ + function moveMessage($old_folder, $uid, $new_folder) + { + $options = array('ids' => array($uid), 'move' => true); + return $this->_imap->copy($old_folder, $new_folder, $options); + } + + /** + * Expunges messages in the current folder. + * + * @param string $mailbox The mailbox to append the message(s) to. Either + * in UTF7-IMAP or UTF-8. + * + * @return mixed True or a PEAR error in case of an error. + */ + function expunge($mailbox) + { + return $this->_imap->expunge($mailbox); + } + + /** + * Retrieves the message headers for a given message id. + * + * @param string $mailbox The mailbox to append the message(s) to. Either + * in UTF7-IMAP or UTF-8. + * @param int $uid The message id. + * @param boolean $peek_for_body Prefetch the body. + * + * @return mixed The message header or a PEAR error in case of an error. + */ + function getMessageHeader($mailbox, $uid, $peek_for_body = true) + { + $options = array('ids' => array($uid)); + $criteria = array(Horde_Imap_Client::FETCH_HEADERTEXT => array()); + $result = $this->_imap->fetch($mailbox, $criteria, $options); + return $result['headertext'][$uid]; + } + + /** + * Retrieves the message body for a given message id. + * + * @param string $mailbox The mailbox to append the message(s) to. Either + * in UTF7-IMAP or UTF-8. + * @param integet $uid The message id. + * + * @return mixed The message body or a PEAR error in case of an error. + */ + function getMessageBody($mailbox, $uid) + { + $options = array('ids' => array($uid)); + $criteria = array(Horde_Imap_Client::FETCH_BODYTEXT => array()); + $result = $this->_imap->fetch($mailbox, $criteria, $options); + return $result['bodytext'][$uid]; + } + + /** + * Retrieve the access rights from a folder + * + * @param string $folder The folder to retrieve the ACLs from. + * + * @return mixed An array of rights if successfull, a PEAR error + * otherwise. + */ + function getACL($folder) + { + if (!$this->_imap->queryCapability('ACL')) { + $acl = array(); + $acl[Horde_Auth::getAuth()] = 'lrid'; + return $acl; + } + + return $this->_imap->getACL($folder); + } + + /** + * Set the access rights for a folder + * + * @param string $folder The folder to retrieve the ACLs from. + * @param string $user The user to set the ACLs for + * @param string $acl The ACLs + * + * @return mixed True if successfull, a PEAR error otherwise. + */ + function setACL($folder, $user, $acl) + { + return $this->_imap->setACL($folder, $user, array('rights' => $acl)); + } + + /** + * Fetches the annotation on a folder. + * + * @param string $entry The entry to fetch. + * @param string $mailbox_name The name of the folder. + * + * @return mixed The annotation value or a PEAR error in case of an error. + */ + function getAnnotation($entry, $mailbox_name) + { + $result = $this->_imap->getMetadata($mailbox_name, $entry); + return $result[$entry]; + } + + /** + * Sets the annotation on a folder. + * + * @param string $entry The entry to set. + * @param array $value The values to set + * @param string $mailbox_name The name of the folder. + * + * @return mixed True if successfull, a PEAR error otherwise. + */ + public function setAnnotation($entry, $value, $mailbox_name) + { + return $this->_imap->setMetadata($mailbox_name, + array($entry => $value)); + } +} \ No newline at end of file diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Exception.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Exception.php new file mode 100644 index 000000000..8b6b2c68e --- /dev/null +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Exception.php @@ -0,0 +1,44 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ + +/** + * This class provides the standard error class for Kolab Storage exceptions. + * + * Copyright 2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ +class Horde_Kolab_Storage_Exception extends Horde_Exception +{ + /** + * Constants to define the error type. + */ + + /** + * The specified folder already exists. + */ + const FOLDER_EXISTS = 10; + + /** + * The name of the folder has not been specified. + */ + const FOLDER_NAME_UNSET = 50; + +} diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php index a6f6485af..7e402ed38 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php @@ -5,53 +5,10 @@ * $Horde: framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php,v 1.30 2009/06/09 23:23:39 slusarz Exp $ */ -/** We need the current user session. */ -require_once 'Horde/Kolab/Session.php'; - -/** Data handling for Kolab **/ -require_once 'Horde/Kolab/Storage/Data.php'; - -/** Permission library for Kolab **/ -require_once 'Horde/Kolab/Storage/Perms.php'; - -/** We need the Kolab XML library for xml handling. */ -require_once 'Horde/Kolab/Format.php'; - -/** We need the Horde History System for logging */ -require_once 'Horde/History.php'; - -/** We need the Horde Mime library to deal with Mime messages. */ -require_once 'Horde/Mime.php'; -require_once 'Horde/Mime/Part.php'; -require_once 'Horde/Mime/Address.php'; -require_once 'Horde/Mime/Headers.php'; - -/** We need the String & NLS libraries for character set conversions, etc. */ -require_once 'Horde/NLS.php'; - -/** - * The root of the Kolab annotation hierarchy, used on the various IMAP folder - * that are used by Kolab clients. - */ -define('KOLAB_ANNOT_ROOT', '/vendor/kolab/'); - /** - * The annotation, as defined by the Kolab format spec, that is used to store - * information about what groupware format the folder contains. + * The Autoloader allows us to omit "require/include" statements. */ -define('KOLAB_ANNOT_FOLDER_TYPE', KOLAB_ANNOT_ROOT . 'folder-type'); - -/** - * Kolab specific free/busy relevance - */ -define('KOLAB_FBRELEVANCE_ADMINS', 0); -define('KOLAB_FBRELEVANCE_READERS', 1); -define('KOLAB_FBRELEVANCE_NOBODY', 2); - -/** - * Horde-specific annotations on the imap folder have this prefix. - */ -define('HORDE_ANNOT_SHARE_ATTR', '/vendor/horde/share-'); +require_once 'Horde/Autoloader.php'; /** * The Kolab_Folder class represents an IMAP folder on the Kolab @@ -69,7 +26,39 @@ define('HORDE_ANNOT_SHARE_ATTR', '/vendor/horde/share-'); * @author Thomas Jarosch * @package Kolab_Storage */ -class Kolab_Folder { +class Horde_Kolab_Storage_Folder +{ + + /** + * The root of the Kolab annotation hierarchy, used on the various IMAP + * folder that are used by Kolab clients. + */ + const ANNOT_ROOT = '/vendor/kolab/'; + + /** + * The annotation, as defined by the Kolab format spec, that is used to store + * information about what groupware format the folder contains. + */ + const ANNOT_FOLDER_TYPE = '/vendor/kolab/folder-type'; + + /** + * Horde-specific annotations on the imap folder have this prefix. + */ + const ANNOT_SHARE_ATTR = '/vendor/horde/share-'; + + /** + * Kolab specific free/busy relevance + */ + const FBRELEVANCE_ADMINS = 0; + const FBRELEVANCE_READERS = 1; + const FBRELEVANCE_NOBODY = 2; + + /** + * The connection specific for this folder. + * + * @var Horde_Kolab_Storage_Driver + */ + private $_connection; /** * The folder name. @@ -89,9 +78,9 @@ class Kolab_Folder { /** * The handler for the list of Kolab folders. * - * @var Kolab_List + * @var Kolab_storage */ - var $_list; + var $_storage; /** * The type of this folder. @@ -181,11 +170,11 @@ class Kolab_Folder { /** * Creates a Kolab Folder representation. * - * @param string $name Name of the folder + * @param string $name Name of the folder */ - function Kolab_Folder($name = null) + function __construct($name = null) { - $this->name = $name; + $this->name = $name; $this->__wakeup(); } @@ -215,19 +204,24 @@ class Kolab_Folder { function __sleep() { $properties = get_object_vars($this); - unset($properties['_list']); + unset($properties['_storage']); + unset($properties['connection']); $properties = array_keys($properties); return $properties; } /** - * Set the list handler. + * Restore the object after a deserialization. * - * @param Kolab_List $list The handler for the list of folders. + * @param Horde_Kolab_Storage $storage The handler for the list of + * folders. + * @param Horde_Kolab_Storage_Driver $connection The storage connection. */ - function setList(&$list) + function restore(Horde_Kolab_Storage &$storage, + Horde_Kolab_Storage_Driver &$connection) { - $this->_list = &$list; + $this->_storage = $storage; + $this->_connection = $connection; } /** @@ -242,7 +236,7 @@ class Kolab_Folder { if (substr($name, 0, 5) != 'user/' && substr($name, 0, 7) != 'shared.') { $name = 'INBOX/' . $name; } - $this->new_name = Horde_String::convertCharset($name, NLS::getCharset(), 'UTF7-IMAP'); + $this->new_name = Horde_String::convertCharset($name, Horde_Nls::getCharset(), 'UTF7-IMAP'); } /** @@ -263,7 +257,7 @@ class Kolab_Folder { */ function getShareId() { - $current_user = Auth::getAuth(); + $current_user = Horde_Auth::getAuth(); if ($this->isDefault() && $this->getOwner() == $current_user) { return $current_user; } @@ -285,7 +279,8 @@ class Kolab_Folder { if (!isset($this->name)) { /* A new folder needs to be created */ if (!isset($this->new_name)) { - return PEAR::raiseError(_("Cannot create this folder! The name has not yet been set.")); + throw new Horde_Kolab_Storage_Exception('Cannot create this folder! The name has not yet been set.', + Horde_Kolab_Storage_Exception::FOLDER_NAME_UNSET); } if (isset($attributes['type'])) { @@ -302,10 +297,15 @@ class Kolab_Folder { $this->_default = false; } - $result = $this->_list->create($this); - if (is_a($result, 'PEAR_Error')) { - return $result; + $result = $this->_connection->exists($this->new_name); + if ($result) { + throw new Horde_Kolab_Storage_Exception(sprintf("Unable to add %s: destination folder already exists", + $this->new_name), + Horde_Kolab_Storage_Exception::FOLDER_EXISTS); } + + $this->_connection->create($this->new_name); + $this->name = $this->new_name; $this->new_name = null; @@ -313,7 +313,6 @@ class Kolab_Folder { if (empty($this->_perms)) { $this->getPermission(); } - } else { $type = $this->getType(); @@ -337,39 +336,29 @@ class Kolab_Folder { if (isset($this->new_name) && $this->new_name != $this->name) { /** The folder needs to be renamed */ - $result = $this->_list->rename($this); - if (is_a($result, 'PEAR_Error')) { - return $result; + $result = $this->_connection->exists($this->new_name); + if ($result) { + throw new Horde_Kolab_Storage_Exception(sprintf(_("Unable to rename %s to %s: destination folder already exists"), + $name, $new_name)); } + $result = $this->_connection->rename($this->name, $this->new_name); + $this->_storage->removeFromCache($this); + /** * Trigger the old folder on an empty IMAP folder. */ - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (!is_a($imap, 'PEAR_Error')) { - $result = $imap->create($this->name); - if (is_a($result, 'PEAR_Error')) { - Horde::logMessage(sprintf('Failed creating dummy folder: %s!', - $result->getMessage()), - __FILE__, __LINE__, PEAR_LOG_ERR); - } - $imap->setAnnotation(KOLAB_ANNOT_FOLDER_TYPE, - array('value.shared' => $this->_type), - $this->name); - - $result = $this->trigger($this->name); - if (is_a($result, 'PEAR_Error')) { - Horde::logMessage(sprintf('Failed triggering dummy folder: %s!', - $result->getMessage()), - __FILE__, __LINE__, PEAR_LOG_ERR); - } - $result = $imap->delete($this->name); - if (is_a($result, 'PEAR_Error')) { - Horde::logMessage(sprintf('Failed deleting dummy folder: %s!', - $result->getMessage()), - __FILE__, __LINE__, PEAR_LOG_ERR); - } + try { + $this->_connection->create($this->name); + $this->_connection->setAnnotation(self::ANNOT_FOLDER_TYPE, + array('value.shared' => $this->_type), + $this->name); + $this->trigger($this->name); + $this->_connection->delete($this->name); + } catch (Exception $e) { + Horde::logMessage(sprintf('Failed handling the dummy folder: %s!', + $e->getMessage()), + __FILE__, __LINE__, PEAR_LOG_ERR); } $this->name = $this->new_name; @@ -391,12 +380,13 @@ class Kolab_Folder { /** Handle the folder type */ $folder_type = $this->_type . ($this->_default ? '.default' : ''); if ($this->_type_annotation != $folder_type) { - $result = $this->_setAnnotation(KOLAB_ANNOT_FOLDER_TYPE, $folder_type); - if (is_a($result, 'PEAR_Error')) { + try { + $result = $this->_setAnnotation(self::ANNOT_FOLDER_TYPE, $folder_type); + } catch (Exception $e) { $this->_type = null; $this->_default = false; $this->_type_annotation = null; - return $result; + throw $e; } } @@ -426,7 +416,7 @@ class Kolab_Folder { if ($key == 'desc') { $entry = '/comment'; } else { - $entry = HORDE_ANNOT_SHARE_ATTR . $key; + $entry = self::ANNOT_SHARE_ATTR . $key; } $result = $this->_setAnnotation($entry, $store); if (is_a($result, 'PEAR_Error')) { @@ -438,16 +428,16 @@ class Kolab_Folder { /** Now save the folder permissions */ if (isset($this->_perms)) { - $result = $this->_perms->save(); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_perms->save(); } - $result = $this->trigger(); - if (is_a($result, 'PEAR_Error')) { + $this->_storage->addToCache($this); + + try { + $this->trigger(); + } catch (Horde_Kolab_Storage_Exception $e) { Horde::logMessage(sprintf('Failed triggering folder %s! Error was: %s', - $this->name, $result->getMessage()), + $this->name, $e->getMessage()), __FILE__, __LINE__, PEAR_LOG_ERR); } @@ -461,11 +451,8 @@ class Kolab_Folder { */ function delete() { - $result = $this->_list->remove($this); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - + $this->_connection->delete($this->name); + $this->_storage->removeFromCache($this); return true; } @@ -490,9 +477,9 @@ class Kolab_Folder { $this->_subpath = $matches[3]; if (substr($matches[1], 0, 6) == 'INBOX/') { - $this->_owner = Auth::getAuth(); + $this->_owner = Horde_Auth::getAuth(); } elseif (substr($matches[1], 0, 5) == 'user/') { - $domain = strstr(Auth::getAuth(), '@'); + $domain = strstr(Horde_Auth::getAuth(), '@'); $user_domain = isset($matches[4]) ? $matches[4] : $domain; $this->_owner = $matches[2] . $user_domain; } elseif ($matches[1] == 'shared.') { @@ -556,12 +543,14 @@ class Kolab_Folder { function getType() { if (!isset($this->_type)) { - $type_annotation = $this->_getAnnotation(KOLAB_ANNOT_FOLDER_TYPE, - $this->name); - if (is_a($type_annotation, 'PEAR_Error')) { + try { + $type_annotation = $this->_getAnnotation(self::ANNOT_FOLDER_TYPE, + $this->name); + } catch (Exception $e) { $this->_default = false; - return $type_annotation; - } else if (empty($type_annotation)) { + throw $e; + } + if (empty($type_annotation)) { $this->_default = false; $this->_type = ''; } else { @@ -652,17 +641,11 @@ class Kolab_Folder { */ function exists() { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - - $result = $imap->exists($this->name); - if (is_a($result, 'PEAR_Error')) { + try { + return $this->_connection->exists($this->name); + } catch (Horde_Imap_Client_Exception $e) { return false; } - return $result; } /** @@ -672,17 +655,11 @@ class Kolab_Folder { */ function accessible() { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - - $result = $imap->select($this->name); - if (is_a($result, 'PEAR_Error')) { + try { + return $this->_connection->select($this->name); + } catch (Horde_Imap_Client_Exception $e) { return false; } - return $result; } /** @@ -733,31 +710,14 @@ class Kolab_Folder { */ function deleteMessage($id, $trigger = true) { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - // Select folder - $result = $imap->select($this->name); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $result = $imap->deleteMessages($id); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $result = $imap->expunge(); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_connection->deleteMessages($this->name, $id); + $this->_connection->expunge($this->name); if ($trigger) { - $result = $this->trigger(); - if (is_a($result, 'PEAR_Error')) { + try { + $result = $this->trigger(); + } catch (Horde_Kolab_Storage_Exception $e) { Horde::logMessage(sprintf('Failed triggering folder %s! Error was: %s', $this->name, $result->getMessage()), __FILE__, __LINE__, PEAR_LOG_ERR); @@ -777,24 +737,18 @@ class Kolab_Folder { */ function moveMessage($id, $folder) { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - // Select folder - $result = $imap->select($this->name); + $result = $this->_connection->select($this->name); if (is_a($result, 'PEAR_Error')) { return $result; } - $result = $imap->moveMessage($id, $folder); + $result = $this->_connection->moveMessage($this->name, $id, $folder); if (is_a($result, 'PEAR_Error')) { return $result; } - $result = $imap->expunge(); + $result = $this->_connection->expunge($this->name); if (is_a($result, 'PEAR_Error')) { return $result; } @@ -819,7 +773,7 @@ class Kolab_Folder { */ function moveMessageToShare($id, $share) { - $folder = $this->_list->getByShare($share, $this->getType()); + $folder = $this->_storage->getByShare($share, $this->getType()); if (is_a($folder, 'PEAR_Error')) { return $folder; } @@ -862,30 +816,21 @@ class Kolab_Folder { /** * Save an object in this folder. * - * @param array $object The array that holds the data of the object. - * @param int $data_version The format handler version. - * @param string $object_type The type of the kolab object. - * @param string $id The IMAP id of the old object if it - * existed before - * @param array $old_object The array that holds the current data of the - * object. + * @param array $object The array that holds the data of the object. + * @param int $data_version The format handler version. + * @param string $object_type The type of the kolab object. + * @param string $id The IMAP id of the old object if it + * existed before + * @param array $old_object The array that holds the current data of the + * object. * - * @return boolean|PEAR_Error True on success. + * @return boolean True on success. */ function saveObject(&$object, $data_version, $object_type, $id = null, &$old_object = null) { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - // Select folder - $result = $imap->select($this->name); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_connection->select($this->name); $new_headers = new Horde_Mime_Headers(); $new_headers->setEOL("\r\n"); @@ -909,13 +854,7 @@ class Kolab_Folder { if ($id != null) { /** Update an existing kolab object */ - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - - if (!in_array($id, $imap->getUids())) { + if (!in_array($id, $this->_connection->getUids($this->name))) { return PEAR::raiseError(sprintf(_("The message with ID %s does not exist. This probably means that the Kolab object has been modified by somebody else while you were editing it. Your edits have been lost."), $id)); } @@ -989,7 +928,7 @@ class Kolab_Folder { $part = new Horde_Mime_Part(); $part->setType(isset($data['type']) ? $data['type'] : null); $part->setContents(isset($data['content']) ? $data['content'] : file_get_contents($data['path'])); - $part->setCharset(NLS::getCharset()); + $part->setCharset(Horde_Nls::getCharset()); $part->setTransferEncoding('quoted-printable'); $part->setDisposition('attachment'); $part->setName($attachment); @@ -1012,7 +951,7 @@ class Kolab_Folder { $part = new Horde_Mime_Part(); $part->setType($handlers[$type]->getMimeType()); $part->setContents($new_content); - $part->setCharset(NLS::getCharset()); + $part->setCharset(Horde_Nls::getCharset()); $part->setTransferEncoding('quoted-printable'); $part->setDisposition($handlers[$type]->getDisposition()); $part->setDispositionParameter('x-kolab-type', $type); @@ -1034,40 +973,34 @@ class Kolab_Folder { $new_headers->addHeader('X-Kolab-Type', $handlers['XML']->getMimeType()); $new_headers->addHeader('Subject', $object['uid']); $new_headers->addHeader('User-Agent', 'Horde::Kolab::Storage v0.2'); - $mime_message->addMimeHeaders($new_headers); + $new_headers->addHeader('MIME-Version', '1.0'); + $mime_message->addMimeHeaders(array('headers' => $new_headers)); - $msg = $new_headers->toString() . $mime_message->toCanonicalString(false); + $msg = $new_headers->toString() . $mime_message->toString(array('canonical' => true, + 'headers' => false)); // delete old email? if ($id != null) { - $result = $imap->deleteMessages($id); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_connection->deleteMessages($this->name, $id); } // store new email - $result = $imap->appendMessage($msg); - if (is_a($result, 'PEAR_Error')) { + try { + $result = $this->_connection->appendMessage($this->name, $msg); + } catch (Horde_Kolab_Storage_Exception $e) { if ($id != null) { - $result = $imap->undeleteMessages($id); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_connection->undeleteMessages($id); } - return $result; } // remove deleted object if ($id != null) { - $result = $imap->expunge(); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_connection->expunge($this->name); } - $result = $this->trigger(); - if (is_a($result, 'PEAR_Error')) { + try { + $this->trigger(); + } catch (Horde_Kolab_Storage_Exception $e) { Horde::logMessage(sprintf('Failed triggering folder %s! Error was: %s', $this->name, $result->getMessage()), __FILE__, __LINE__, PEAR_LOG_ERR); @@ -1093,25 +1026,20 @@ class Kolab_Folder { function parseMessage($id, $mime_type, $parse_headers = true, $formats = array('XML')) { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - - $raw_headers = $imap->getMessageHeader($id); + $raw_headers = $this->_connection->getMessageHeader($this->name, $id); if (is_a($raw_headers, 'PEAR_Error')) { return PEAR::raiseError(sprintf(_("Failed retrieving the message with ID %s. Original error: %s."), $id, $raw_headers->getMessage())); } - $body = $imap->getMessageBody($id); + $body = $this->_connection->getMessageBody($this->name, $id); if (is_a($body, 'PEAR_Error')) { return PEAR::raiseError(sprintf(_("Failed retrieving the message with ID %s. Original error: %s."), $id, $body->getMessage())); } - $mime_message = Horde_Mime_Part::parseMessage($raw_headers . $body); + //@todo: not setting "forcemime" means the subparts get checked too. Seems incorrect. + $mime_message = Horde_Mime_Part::parseMessage($raw_headers . "\r" . $body, array('forcemime' => true)); $parts = $mime_message->contentTypeMap(); $mime_headers = false; @@ -1126,7 +1054,8 @@ class Kolab_Folder { } $part = $mime_message->getPart($part_ids['XML']); - $part->transferDecodeContents(); + //@todo: Check what happened to this call + //$part->transferDecodeContents(); $xml = $part->getContents(); } @@ -1165,8 +1094,8 @@ class Kolab_Folder { $part = new Horde_Mime_Part(); $part->setType('text/plain'); $part->setName('Kolab Groupware Information'); - $part->setContents(Horde_String::wrap($kolab_text, 76, "\r\n", NLS::getCharset())); - $part->setCharset(NLS::getCharset()); + $part->setContents(Horde_String::wrap($kolab_text, 76, "\r\n", Horde_Nls::getCharset())); + $part->setCharset(Horde_Nls::getCharset()); $part->setTransferEncoding('quoted-printable'); $mime_message->addPart($part); @@ -1181,27 +1110,11 @@ class Kolab_Folder { */ function getStatus() { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - // Select the folder to update uidnext - $result = $imap->select($this->name); - if (is_a($result, 'PEAR_Error')) { - return $result; - } + $this->_connection->select($this->name); - $status = $imap->status(); - if (is_a($status, 'PEAR_Error')) { - return $status; - } - - $uids = $imap->getUids(); - if (is_a($uids, 'PEAR_Error')) { - return $uids; - } + $status = $this->_connection->status($this->name); + $uids = $this->_connection->getUids($this->name); return array($status['uidvalidity'], $status['uidnext'], $uids); } @@ -1274,7 +1187,7 @@ class Kolab_Folder { require_once 'HTTP/Request.php'; $http = new HTTP_Request($url, $options); - $http->setBasicAuth(Auth::getAuth(), Auth::getCredential('password')); + $http->setBasicAuth(Horde_Auth::getAuth(), Horde_Auth::getCredential('password')); @$http->sendRequest(); if ($http->getResponseCode() != 200) { return PEAR::raiseError(sprintf(_("Unable to trigger URL %s. Response: %s"), @@ -1320,10 +1233,10 @@ class Kolab_Folder { } else { $perms = array( 'users' => array( - Auth::getAuth() => PERMS_SHOW | PERMS_READ | + Horde_Auth::getAuth() => PERMS_SHOW | PERMS_READ | PERMS_EDIT | PERMS_DELETE)); } - $this->_perms = &new Horde_Permission_Kolab($this, $perms); + $this->_perms = &new Horde_Kolab_Storage_Permission($this, $perms); } return $this->_perms; } @@ -1364,41 +1277,27 @@ class Kolab_Folder { */ function getACL() { - global $conf; - - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - - if (!empty($conf['kolab']['imap']['no_acl'])) { - $acl = array(); - $acl[Auth::getAuth()] = 'lrid'; - return $acl; - } - - $acl = $imap->getACL($this->name); + $acl = $this->_connection->getACL($this->name); /* * Check if the getPerm comes from the owner in this case we * can use getACL to have all the right of the share Otherwise * we just ask for the right of the current user for a folder */ - if ($this->getOwner() == Auth::getAuth()) { + if ($this->getOwner() == Horde_Auth::getAuth()) { return $acl; } else { if (!is_a($acl, 'PEAR_Error')) { return $acl; } - $my_rights = $imap->getMyrights($this->name); + $my_rights = $this->_connection->getMyrights($this->name); if (is_a($my_rights, 'PEAR_Error')) { return $my_rights; } $acl = array(); - $acl[Auth::getAuth()] = $my_rights; + $acl[Horde_Auth::getAuth()] = $my_rights; return $acl; } } @@ -1413,22 +1312,7 @@ class Kolab_Folder { */ function setACL($user, $acl) { - global $conf; - - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - - if (!empty($conf['kolab']['imap']['no_acl'])) { - return true; - } - - $iresult = $imap->setACL($this->name, $user, $acl); - if (is_a($iresult, 'PEAR_Error')) { - return $iresult; - } + $this->_connection->setACL($this->name, $user, $acl); if (!empty($this->_perms)) { /** Refresh the cache after changing the permissions */ @@ -1442,7 +1326,7 @@ class Kolab_Folder { __FILE__, __LINE__, PEAR_LOG_ERR); } - return $iresult; + return $result; } /** @@ -1456,20 +1340,11 @@ class Kolab_Folder { { global $conf; - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - if (!empty($conf['kolab']['imap']['no_acl'])) { return true; } - $iresult = $imap->deleteACL($this->name, $user); - if (is_a($iresult, 'PEAR_Error')) { - return $iresult; - } + $this->_connection->deleteACL($this->name, $user); $result = $this->trigger(); if (is_a($result, 'PEAR_Error')) { @@ -1506,13 +1381,7 @@ class Kolab_Folder { global $conf; if (empty($conf['kolab']['imap']['no_annotations'])) { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - return $imap->getAnnotation($key, 'value.shared', - $this->name); + return $this->_connection->getAnnotation($key, $this->name); } if (!isset($this->_annotation_data)) { @@ -1543,14 +1412,7 @@ class Kolab_Folder { function _setAnnotation($key, $value) { if (empty($conf['kolab']['imap']['no_annotations'])) { - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - if (is_a($imap, 'PEAR_Error')) { - return $imap; - } - return $imap->setAnnotation($key, - array('value.shared' => $value), - $this->name); + return $this->_connection->setAnnotation($key, $value, $this->name); } if (!isset($this->_annotation_data)) { diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Permission.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Permission.php new file mode 100644 index 000000000..cc0ca2d74 --- /dev/null +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Permission.php @@ -0,0 +1,408 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ + +/** + * The Autoloader allows us to omit "require/include" statements. + */ +require_once 'Horde/Autoloader.php'; + +/** + * The Horde_Perms package does not work with Horde_Autoloader yet. + * + * @todo Fix once Horde_Perms has been converted to H4 + */ +require_once 'Horde/Perms.php'; + +/** + * The Horde_Kolab_Storage_Permission provides a bridge between Horde Permission + * handling and the IMAP permission system used on the Kolab server. + * + * Copyright 2006-2009 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage + */ +class Horde_Kolab_Storage_Permission extends Horde_Permission { + + /** + * The folder name. + * + * @var string + */ + protected $_folder; + + /** + * A cache for the folder acl settings. The cache holds the permissions + * in horde compatible format, not in the IMAP permission format. + * + * @var string + */ + protected $data; + + /** + * A cache for the raw IMAP folder acl settings. + * + * @var string + */ + protected $acl; + + /** + * Constructor. + * + * @param Horde_Kolab_Storage_Folder $folder The Kolab Folder these + * permissions belong to. + * @param array $perms A set of initial + * permissions. + */ + public function __construct(&$folder, $perms = null) + { + $this->setFolder($folder); + if (!isset($perms)) { + $result = $this->getPerm(); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage(sprintf("Failed parsing permission information. Error was: %s", + $result->getMessage()), __FILE__, __LINE__); + } else { + $perms = $result; + } + } + $this->data = $perms; + + } + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + $properties = get_object_vars($this); + unset($properties['_folder']); + $properties = array_keys($properties); + return $properties; + } + + /** + * Sets the folder object for this permission object. + * + * @param Horde_Kolab_Storage_Folder $folder Kolab Folder object. + */ + public function setFolder(Horde_Kolab_Storage_Folder &$folder) + { + $this->_folder = $folder; + } + + /** + * Gets one of the attributes of the object, or null if it isn't defined. + * + * @param string $attribute The attribute to get. + * + * @return mixed The value of the attribute, or null. + */ + public function get($attribute) + { + // This object only handles permissions. So only return these + switch ($attribute) { + case 'perm': + return $this->data; + case 'type': + return 'matrix'; + default: + // User requested something other than permissions: return null + return null; + } + } + + /** + * Gets the current permission of the folder and stores the values in the + * cache. + * + * @return array|PEAR_Error The data array representing the permissions. + */ + public function getPerm() + { + try { + $acl = $this->_folder->getACL(); + } catch (Horde_Kolab_Storage_Exception $e) { + Horde::logMessage($acl, __FILE__, __LINE__); + return array(); + } + if (empty($acl)) { + return array(); + } + $this->acl = &$acl; + + // Loop through the returned users + $data = array(); + foreach ($acl as $user => $rights) { + // Convert the user rights to horde format + $result = 0; + for ($i = 0, $j = strlen($rights); $i < $j; $i++) { + switch ($rights[$i]) { + case 'l': + $result |= PERMS_SHOW; + break; + case 'r': + $result |= PERMS_READ; + break; + case 'i': + $result |= PERMS_EDIT; + break; + case 'd': + $result |= PERMS_DELETE; + break; + } + } + + // Check for special users + $name = ''; + switch ($user) { + case 'anyone': + $name = 'default'; + break; + case 'anonymous': + $name = 'guest'; + break; + } + + // Did we have a special user? + if ($name) { + // Store the converted acl in the cache + $data[$name] = $result; + continue; + } + + // Is it a group? + if (substr($user, 0, 6) == 'group:') { + if (!isset($groups)) { + require_once 'Horde/Group.php'; + $groups = &Group::singleton(); + } + $group_id = $groups->getGroupId(substr($user, 6)); + if (!is_a($group_id, 'PEAR_Error')) { + // Store the converted acl in the cache + $data['groups'][$group_id] = $result; + } + + continue; + } + + // Standard user + // Store the converted acl in the cache + $data['users'][$user] = $result; + } + + return $data; + } + + /** + * Saves the current permission values from the cache to the IMAP folder. + * + * @return boolean|PEAR_Error True on success, false if there is + * nothing to save. + */ + public function save() + { + if (!isset($this->data)) { + return false; + } + + // FIXME: If somebody else accessed the folder before us, we will overwrite + // the change here. + $current = $this->getPerm(); + + foreach ($this->data as $user => $user_perms) { + if (is_array($user_perms)) { + foreach ($user_perms as $userentry => $perms) { + if ($user == 'groups') { + if (!isset($groups)) { + require_once 'Horde/Group.php'; + $groups = &Group::singleton(); + } + // Convert group id back to name + $group_name = $groups->getGroupName($userentry); + $name = 'group:' . $group_name; + } else if ($user == 'users') { + $name = $userentry; + } else { + continue; + } + $this->savePermission($name, $perms); + unset($current[$user][$userentry]); + } + } else { + if ($user == 'default') { + $name = 'anyone'; + } else if ($user == 'guest') { + $name = 'anonymous'; + } else { + continue; + } + $this->savePermission($name, $user_perms); + unset($current[$user]); + } + } + + // Delete ACLs that have been removed + foreach ($current as $user => $user_perms) { + if (is_array($user_perms)) { + foreach ($user_perms as $userentry => $perms) { + if ($user == 'groups') { + if (!isset($groups)) { + require_once 'Horde/Group.php'; + $groups = &Group::singleton(); + } + // Convert group id back to name + $group_name = $groups->getGroupName($userentry); + $name = 'group:' . $group_name; + } else { + $name = $userentry; + } + + $this->_folder->deleteACL($name); + } + } else { + if ($user == 'default') { + $name = 'anyone'; + } else if ($user == 'guest') { + $name = 'anonymous'; + } else { + continue; + } + $this->_folder->deleteACL($name); + } + } + + // Load the permission from the folder again + $this->data = $this->getPerm(); + + return true; + } + + /** + * Saves the specified permission values for the given user on the + * IMAP folder. + * + * @return boolean|PEAR_Error True on success. + */ + public function savePermission($user, $perms) + { + // Convert the horde permission style to IMAP permissions + $result = $user == $this->_folder->getOwner() ? 'a' : ''; + if ($perms & PERMS_SHOW) { + $result .= 'l'; + } + if ($perms & PERMS_READ) { + $result .= 'r'; + } + if ($perms & PERMS_EDIT) { + $result .= 'iswc'; + } + if ($perms & PERMS_DELETE) { + $result .= 'd'; + } + + return $this->_folder->setACL($user, $result); + } + + /** + * Finds out what rights the given user has to this object. + * + * @param string $user The user to check for. Defaults to the current + * user. + * @param string $creator The user who created the object. + * + * @return mixed A bitmask of permissions, a permission value, or + * an array of permission values the user has, + * depending on the permission type and whether the + * permission value is ambiguous. False if there is + * no such permsission. + */ + public function getPermissions($user = null, $creator = null) + { + if ($user === null) { + $user = Auth::getAuth(); + } + // If $creator was specified, check creator permissions. + if ($creator !== null) { + // If the user is the creator see if there are creator + // permissions. + if (strlen($user) && $user === $creator && + ($perms = $this->getCreatorPermissions()) !== null) { + return $perms; + } + } + + // Check user-level permissions. + $userperms = $this->getUserPermissions(); + if (isset($userperms[$user])) { + return $userperms[$user]; + } + + // If no user permissions are found, try group permissions. + $groupperms = $this->getGroupPermissions(); + if (!empty($groupperms)) { + require_once 'Horde/Group.php'; + $groups = &Group::singleton(); + + $composite_perm = null; + foreach ($this->data['groups'] as $group => $perm) { + $result = $groups->userIsInGroup($user, $group); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + if ($result) { + if ($composite_perm === null) { + $composite_perm = 0; + } + $composite_perm |= $perm; + } + } + + if ($composite_perm !== null) { + return $composite_perm; + } + } + + // If there are default permissions, return them. + if (($perms = $this->getDefaultPermissions()) !== null) { + return $perms; + } + + // Otherwise, deny all permissions to the object. + return false; + } + + /** + * Finds out if the user has the specified rights to the given object. + * + * @param string $user The user to check for. + * @param integer $perm The permission level that needs to be checked + * for. + * @param string $creator The creator of the shared object. + * + * @return boolean True if the user has the specified permissions. + */ + public function hasPermission($user, $perm, $creator = null) + { + return ($this->getPermissions($user, $creator) & $perm); + } +} diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Test/Storage.php b/framework/Kolab_Storage/lib/Horde/Kolab/Test/Storage.php index 28240b940..d913510f6 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Test/Storage.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Test/Storage.php @@ -14,14 +14,9 @@ */ /** - * We need the unit test framework + * The Autoloader allows us to omit "require/include" statements. */ -require_once 'Horde/Kolab/Test/Server.php'; - -/** - * We need the classes to be tested - */ -require_once 'Horde/Kolab/Storage/List.php'; +require_once 'Horde/Autoloader.php'; /** * Base for PHPUnit scenarios. @@ -99,8 +94,6 @@ class Horde_Kolab_Test_Storage extends Horde_Kolab_Test_Server $folder->setACL($arguments[0], 'alrid'); break; case 'retrieving the list of shares for the application': - require_once 'Horde/Share.php'; - $shares = Horde_Share::singleton($arguments[0], 'kolab'); $world['list'] = $shares->listShares(Auth::getAuth()); @@ -155,15 +148,17 @@ class Horde_Kolab_Test_Storage extends Horde_Kolab_Test_Server /** * Prepare an empty Kolab storage. * - * @return Kolab_List The empty storage. + * @return Horde_Kolab_Storage_List The empty storage. */ - public function &prepareEmptyKolabStorage() + public function &prepareEmptyKolabStorage($params = null) { - /** Ensure that IMAP runs in testing mode and is empty */ - $GLOBALS['KOLAB_TESTING'] = array(); - /** Prepare a Kolab test storage */ - $storage = Kolab_List::singleton(true); + if(empty($params)) { + $params = array('driver' => 'Mock', + 'username' => 'test', + 'password' => 'test'); + } + $storage = Horde_Kolab_Storage::singleton('imap', $params); return $storage; } @@ -175,7 +170,6 @@ class Horde_Kolab_Test_Storage extends Horde_Kolab_Test_Server public function prepareBrowser() { /** Provide a browser setup */ - include_once 'Horde/Browser.php'; $GLOBALS['browser'] = new Horde_Browser(); } @@ -204,7 +198,7 @@ class Horde_Kolab_Test_Storage extends Horde_Kolab_Test_Server \$conf['cookie']['path'] = '/'; \$conf['cookie']['domain'] = \$_SERVER['SERVER_NAME']; \$conf['use_ssl'] = false; -\$conf['session']['cache_limiter'] = 'nocache'; +\$conf['session']['cache_limiter'] = null; \$conf['session']['name'] = 'Horde'; \$conf['log']['enabled'] = false; \$conf['prefs']['driver'] = 'session'; @@ -285,12 +279,22 @@ EOD; * * @return NULL */ - public function &prepareKolabSetup() + public function &prepareKolabSetup($username = 'test', $password = 'test') { + /** + * Ensure we have a session array. Otherwise the Auth handler will try + * to unset the session and issue a notice. + */ + $_SESSION = array(); + $world = array(); + $params = array('driver' => 'Mock', + 'username' => $username, + 'password' => $password); + $world['server'] = &$this->prepareEmptyKolabServer(); - $world['storage'] = &$this->prepareEmptyKolabStorage(); + $world['storage'] = &$this->prepareEmptyKolabStorage($params); $world['auth'] = &$this->prepareKolabAuthDriver(); $this->prepareBasicConfiguration(); @@ -303,18 +307,21 @@ EOD; $result = mkdir(HORDE_BASE . '/config', 0755, true); } + /* Ensure that we send no heders when the session is started */ + ini_set('session.use_cookies', 0); + ini_set('session.use_only_cookies', 0); + $this->prepareConfiguration(); $this->prepareRegistry(); $this->prepareNotification(); if (!isset($GLOBALS['perms'])) { + include_once 'Horde/Perms.php'; $GLOBALS['perms'] = &Perms::singleton(); } /** Provide the horde registry */ - include_once 'Horde/Registry.php'; - - $GLOBALS['registry'] = &Registry::singleton(); + $GLOBALS['registry'] = &Horde_Registry::singleton(); $GLOBALS['notification'] = &Horde_Notification::singleton(); $this->prepareFixedConfiguration(); @@ -376,4 +383,16 @@ EOD; function provideHordeBase() { return Horde::getTempDir() . '/test_config'; } + + public function &authenticate(Horde_Auth_Base $auth, $username = 'test', $password = 'test') + { + $this->assertTrue($auth->authenticate($username, + array('password' => $password))); + + $params = array('driver' => 'Mock', + 'username' => $username, + 'password' => $password); + + return $this->prepareEmptyKolabStorage($params); + } } diff --git a/framework/Kolab_Storage/package.xml b/framework/Kolab_Storage/package.xml index 287563739..99bd63756 100644 --- a/framework/Kolab_Storage/package.xml +++ b/framework/Kolab_Storage/package.xml @@ -73,14 +73,17 @@ http://pear.php.net/dtd/package-2.0.xsd"> - + + + + + - - + @@ -97,7 +100,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> - + @@ -181,20 +184,21 @@ http://pear.php.net/dtd/package-2.0.xsd"> - + + + - - + - + diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/AttachmentTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/AttachmentTest.php index 88535be89..b4dd752ef 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/AttachmentTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/AttachmentTest.php @@ -53,10 +53,20 @@ class Horde_Kolab_Storage_AttachmentTest extends Horde_Kolab_Test_Storage { $world = $this->prepareBasicSetup(); - $this->assertTrue($world['auth']->authenticate('wrobel@example.org', - array('password' => 'none'))); + $this->storage = $this->authenticate($world['auth'], + 'wrobel@example.org', + 'none'); - $this->prepareNewFolder($world['storage'], 'Contacts', 'contact', true); + $this->folder = $this->prepareNewFolder($this->storage, 'Contacts', 'contact', true); + } + + /** + * Test destruction. + */ + public function tearDown() + { + Horde_Imap_Client_Mock::clean(); + $this->storage->clean(); } /** @@ -66,9 +76,8 @@ class Horde_Kolab_Storage_AttachmentTest extends Horde_Kolab_Test_Storage */ public function testCacheAttachmentInFile() { - $data = &new Kolab_Data('contact'); - $folder = &new Kolab_Folder('INBOX/Contacts'); - $data->setFolder($folder); + $data = &new Horde_Kolab_Storage_Data('contact'); + $data->setFolder($this->folder); $atc1 = Horde_Util::getTempFile(); $fh = fopen($atc1, 'w'); @@ -88,7 +97,8 @@ class Horde_Kolab_Storage_AttachmentTest extends Horde_Kolab_Test_Storage $result = $data->getObject(1); $this->assertNoError($result); $this->assertTrue(isset($result['_attachments']['test.txt'])); - $this->assertEquals("test\n", $data->getAttachment($result['_attachments']['test.txt']['key'])); + // @todo: what introduces the \r? + $this->assertEquals("test\r", $data->getAttachment($result['_attachments']['test.txt']['key'])); } /** @@ -98,9 +108,8 @@ class Horde_Kolab_Storage_AttachmentTest extends Horde_Kolab_Test_Storage */ public function testCacheAttachmentAsContent() { - $data = &new Kolab_Data('contact'); - $folder = &new Kolab_Folder('INBOX/Contacts'); - $data->setFolder($folder); + $data = &new Horde_Kolab_Storage_Data('contact'); + $data->setFolder($this->folder); $object = array('uid' => '1', 'full-name' => 'User Name', @@ -115,6 +124,6 @@ class Horde_Kolab_Storage_AttachmentTest extends Horde_Kolab_Test_Storage $result = $data->getObject(1); $this->assertNoError($result); $this->assertTrue(isset($result['_attachments']['test.txt'])); - $this->assertEquals("test\n", $data->getAttachment($result['_attachments']['test.txt']['key'])); + $this->assertEquals("test\r", $data->getAttachment($result['_attachments']['test.txt']['key'])); } } diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/CacheTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/CacheTest.php index d9ecd7d44..f83d79f94 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/CacheTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/CacheTest.php @@ -2,50 +2,44 @@ /** * Test the Kolab cache. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/CacheTest.php,v 1.4 2009/03/20 23:44:38 wrobel Exp $ + * PHP version 5 * - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ /** - * We need the unit test framework + * The Autoloader allows us to omit "require/include" statements. */ -require_once 'PHPUnit/Framework.php'; - -require_once 'Horde.php'; -require_once 'Horde/Kolab/Storage/Cache.php'; +require_once 'Horde/Autoloader.php'; /** * Test the Kolab cache. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/CacheTest.php,v 1.4 2009/03/20 23:44:38 wrobel Exp $ - * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Gunnar Wrobel - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ class Horde_Kolab_Storage_CacheTest extends PHPUnit_Framework_TestCase { - - /** - * Test cache construction. - */ - public function testConstruct() - { - $cache = &new Kolab_Cache(); - $this->assertEquals('Horde_Cache_File', get_class($cache->_horde_cache)); - } - /** * Test cleaning the cache. + * + * @return NULL */ public function testReset() { - $cache = &new Kolab_Cache(); + $cache = new Horde_Kolab_Storage_Cache(); $cache->reset(); $this->assertEquals(-1, $cache->validity); $this->assertEquals(-1, $cache->nextid); @@ -55,10 +49,12 @@ class Horde_Kolab_Storage_CacheTest extends PHPUnit_Framework_TestCase /** * Test storing data. + * + * @return NULL */ public function testStore() { - $cache = &new Kolab_Cache(); + $cache = new Horde_Kolab_Storage_Cache(); $cache->reset(); $item = array(1); $cache->store(10, 1, $item); @@ -70,25 +66,80 @@ class Horde_Kolab_Storage_CacheTest extends PHPUnit_Framework_TestCase /** * Test ignoring objects. + * + * @return NULL */ public function testIgnore() { - $cache = &new Kolab_Cache(); + $cache = new Horde_Kolab_Storage_Cache(); $cache->reset(); $cache->ignore(11); $this->assertEquals(false, $cache->uids[11]); } /** + * Test storing/loading attachments. + * + * @return NULL + */ + public function testAttachments() + { + $cache = new Horde_Kolab_Storage_Cache(); + $cache->storeAttachment('a', 'attachment'); + $this->assertEquals('attachment', $cache->loadAttachment('a')); + $cache->storeAttachment('b', 'b'); + $this->assertEquals('b', $cache->loadAttachment('b')); + $cache->storeAttachment('a', 'a'); + $this->assertEquals('a', $cache->loadAttachment('a')); + } + + /** + * Test configration. + * + * @return NULL + */ + public function testConfigruation() + { + $cache = new Horde_Kolab_Storage_Cache(); + + $GLOBALS['conf']['kolab']['storage']['cache']['data']['driver'] = 'file'; + + $cache2 = new Horde_Kolab_Storage_Cache(); + + $GLOBALS['conf']['kolab']['storage']['cache']['data']['params'] = array('prefix' => 'kolab_cache', + 'dir' => Horde::getTempDir()); + + $cache3 = new Horde_Kolab_Storage_Cache(); + } + /** + * Test creating the cache singleton. + * + * @return NULL + */ + public function testSingleton() + { + $cache = Horde_Kolab_Storage_Cache::singleton(); + $cache2 = new Horde_Kolab_Storage_Cache(); + $this->assertTrue($cache !== $cache2); + $cache3 = Horde_Kolab_Storage_Cache::singleton(); + $this->assertTrue($cache === $cache3); + } + + /** * Test loading/saving the cache. + * + * @return NULL */ public function testLoadSave() { - $cache = &new Kolab_Cache(); + $cache = new Horde_Kolab_Storage_Cache(); + $cache->load('test', 1); + /** + * Loading a second time should return immediately (see code + * coverage) + */ $cache->load('test', 1); $cache->expire(); - $this->assertEquals(1, $cache->_data_version); - $this->assertEquals('test', $cache->_key); $this->assertEquals(-1, $cache->validity); $this->assertEquals(-1, $cache->nextid); $this->assertTrue(empty($cache->objects)); @@ -109,17 +160,12 @@ class Horde_Kolab_Storage_CacheTest extends PHPUnit_Framework_TestCase $this->assertEquals(false, $cache->uids[10]); $this->assertEquals(false, $cache->uids[12]); /** Allow us to reload the cache */ - $cache->_key = null; - $cache->load('test', 1); - $this->assertEquals((1 << 8) | 1, $cache->_cache_version); + $cache->load('test', 1, true); $this->assertTrue(isset($cache->objects[1])); $this->assertTrue(isset($cache->uids[10])); $this->assertEquals(1, $cache->uids[10]); $this->assertEquals($item1, $cache->objects[1]); $cache->expire(); - $this->assertEquals((1 << 8) | 1, $cache->_cache_version); - $this->assertEquals(1, $cache->_data_version); - $this->assertEquals('test', $cache->_key); $this->assertEquals(-1, $cache->validity); $this->assertEquals(-1, $cache->nextid); $this->assertTrue(empty($cache->objects)); diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/DataTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/DataTest.php index c8504c3b4..b09b91fdc 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/DataTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/DataTest.php @@ -2,33 +2,33 @@ /** * Test the Kolab data handler. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/DataTest.php,v 1.10 2009/01/14 23:39:14 wrobel Exp $ + * PHP version 5 * - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ /** - * We need the base class + * The Autoloader allows us to omit "require/include" statements. */ -require_once 'Horde/Kolab/Test/Storage.php'; - -require_once 'Horde.php'; -require_once 'Horde/Kolab/Storage/Data.php'; -require_once 'Horde/Kolab/IMAP.php'; -require_once 'Horde/Kolab/IMAP/test.php'; +require_once 'Horde/Autoloader.php'; /** * Test the Kolab data handler. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/DataTest.php,v 1.10 2009/01/14 23:39:14 wrobel Exp $ - * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Gunnar Wrobel - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage { @@ -40,20 +40,21 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage { $world = $this->prepareBasicSetup(); - $this->assertTrue($world['auth']->authenticate('wrobel@example.org', - array('password' => 'none'))); + $this->storage = $this->authenticate($world['auth'], + 'wrobel@example.org', + 'none'); - $this->prepareNewFolder($world['storage'], 'Contacts', 'contact', true); - $this->prepareNewFolder($world['storage'], 'NewContacts', 'contact'); + $this->folder = $this->prepareNewFolder($this->storage, 'Contacts', 'contact', true); + $this->prepareNewFolder($this->storage, 'NewContacts', 'contact'); } /** - * Test class constructor. + * Test destruction. */ - public function testConstruct() + public function tearDown() { - $data = &new Kolab_Data('test'); - $this->assertEquals('test', $data->_object_type); + Horde_Imap_Client_Mock::clean(); + $this->storage->clean(); } /** @@ -61,16 +62,11 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage */ public function testGetCacheKey() { - $data = &new Kolab_Data('test'); - $this->assertTrue($data->_cache_cyrus_optimize); - $session = &Horde_Kolab_Session::singleton(); - $imap = &$session->getImap(); - $this->assertEquals('Horde_Kolab_IMAP_test', get_class($imap)); - - $folder = &new Kolab_Folder('INBOX/Test'); + $data = &new Horde_Kolab_Storage_Data('test'); + + $folder = &new Horde_Kolab_Storage_Folder('INBOX/Test'); $data->setFolder($folder); - $this->assertEquals('INBOX/Test', $data->_folder->name); - $this->assertEquals('user/wrobel/Test', $data->_getCacheKey()); + $this->assertEquals('user/wrobel/Test', $data->getCacheKey()); } /** @@ -78,22 +74,18 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage */ public function testDelete() { - $data = &new Kolab_Data('contact'); - $folder = &new Kolab_Folder('INBOX/Contacts'); - $data->setFolder($folder); + $data = &new Horde_Kolab_Storage_Data('contact'); + $data->setFolder($this->folder); - /** + /** * During testing we want to ensure that we do not access any * old, cached data. The cache gets loaded when calling * getObjectIds and is manually expired afterwards. */ $result = $data->getObjectIds(); - $data->_cache->expire(); + $data->expireCache(); $result = $data->delete('1'); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertFalse($result); $object = array( 'uid' => '1', @@ -102,22 +94,14 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage 'email' => 'p@rdus.de' ); $result = $data->save($object); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } - $this->assertTrue($result); - $result = $data->delete('1'); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); $ids = $data->getObjectIds(); - if (is_a($ids, 'PEAR_Error')) { - $this->assertEquals('', $ids->message); + foreach ($ids as $id) { + $uid = $data->getStorageId($id); + $result = $data->delete($uid); + $this->assertTrue($result); } + $ids = $data->getObjectIds(); $this->assertTrue(empty($ids)); } @@ -126,37 +110,29 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage */ public function testMove() { - $list = &new Kolab_List(); - $list->_imap = &new Horde_Kolab_IMAP_test('', 0); - - $data = &new Kolab_Data('contact'); - $folder = &new Kolab_Folder('INBOX/Contacts'); - $folder->setList($list); + $data = &new Horde_Kolab_Storage_Data('contact'); + $folder = $this->storage->getFolder('INBOX/Contacts'); $data->setFolder($folder); - /** + /** * During testing we want to ensure that we do not access any * old, cached data. The cache gets loaded when calling * getObjectIds and is manually expired afterwards. */ $result = $data->getObjectIds(); - $data->_cache->expire(); + $data->expireCache(); - $data2 = &new Kolab_Data('contact'); - $folder2 = &new Kolab_Folder('INBOX/NewContacts'); - $folder2->setList($list); + $data2 = &new Horde_Kolab_Storage_Data('contact'); + $folder2 = $this->storage->getFolder('INBOX/NewContacts'); $data2->setFolder($folder2); - /** + /** * During testing we want to ensure that we do not access any * old, cached data. The cache gets loaded when calling * getObjectIds and is manually expired afterwards. */ $result = $data2->getObjectIds(); - $data2->_cache->expire(); + $data2->expireCache(); $result = $data->move('1', 'INBOX%20NewContacts'); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertFalse($result); $object = array( 'uid' => '1', @@ -165,37 +141,19 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage 'email' => 'p@rdus.de' ); $result = $data->save($object); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); $result = $data->move('1', rawurlencode('INBOX/NewContacts')); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); $ids = $data->getObjectIds(); - if (is_a($ids, 'PEAR_Error')) { - $this->assertEquals('', $ids->message); - } $this->assertTrue(empty($ids)); $data2->synchronize(); $ids = $data2->getObjectIds(); - if (is_a($ids, 'PEAR_Error')) { - $this->assertEquals('', $ids->message); - } $this->assertEquals(1, count($ids)); $result = $data2->delete('1'); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); } @@ -204,16 +162,15 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage */ public function testSave() { - $data = &new Kolab_Data('contact'); - $folder = &new Kolab_Folder('INBOX/Contacts'); - $data->setFolder($folder); - /** + $data = &new Horde_Kolab_Storage_Data('contact'); + $data->setFolder($this->folder); + /** * During testing we want to ensure that we do not access any * old, cached data. The cache gets loaded when calling * getObjectIds and is manually expired afterwards. */ $result = $data->getObjectIds(); - $data->_cache->expire(); + $data->expireCache(); $object = array( 'uid' => '1', 'given-name' => 'Gunnar', @@ -221,26 +178,22 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage 'email' => 'p@rdus.de' ); - $result = $data->save($object, '1000'); - $this->assertEquals("Old object 1000 does not exist.", $result->message); - - $result = $data->save($object); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); + try { + $result = $data->save($object, '1000'); + } catch (Exception $e) { + $this->assertEquals("Old object 1000 does not exist.", $e->getMessage()); } + $result = $data->save($object); $this->assertTrue($result); - $id = $data->_getStorageId('1'); - $this->assertTrue($data->_storageIdExists($id)); + $id = $data->getStorageId('1'); + $this->assertTrue($data->storageIdExists($id)); $this->assertTrue($data->objectUidExists('1')); $object = $data->getObject('1'); $this->assertEquals('Gunnar', $object['given-name']); $objects = $data->getObjects(); - if (is_a($objects, 'PEAR_Error')) { - $this->assertEquals('', $objects->message); - } $this->assertEquals(1, count($objects)); $object = array( @@ -251,27 +204,21 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage ); $result = $data->save($object, '1'); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); - $this->assertNotEquals($id, $data->_getStorageId('1')); + $this->assertNotEquals($id, $data->getStorageId('1')); $result = $data->delete('1'); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); - $this->assertFalse($data->_getStorageId('1')); - $this->assertFalse($data->_storageIdExists($id)); + $this->assertFalse($data->getStorageId('1')); + $this->assertFalse($data->storageIdExists($id)); $this->assertFalse($data->objectUidExists('1')); + try { $object = $data->getObject('1'); - $this->assertEquals("Kolab cache: Object uid 1 does not exist in the cache!", $object->message); + } catch (Exception $e) { + $this->assertEquals("Kolab cache: Object uid 1 does not exist in the cache!", $e->getMessage()); + } $objects = $data->getObjects(); - if (is_a($objects, 'PEAR_Error')) { - $this->assertEquals('', $objects->message); - } $this->assertEquals(0, count($objects)); } @@ -280,16 +227,15 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage */ public function testObjectDeleteAll() { - $data = &new Kolab_Data('contact'); - $folder = &new Kolab_Folder('INBOX/Contacts'); - $data->setFolder($folder); - /** + $data = &new Horde_Kolab_Storage_Data('contact'); + $data->setFolder($this->folder); + /** * During testing we want to ensure that we do not access any * old, cached data. The cache gets loaded when calling * getObjectIds and is manually expired afterwards. */ $result = $data->getObjectIds(); - $data->_cache->expire(); + $data->expireCache(); $result = $data->deleteAll(); $this->assertTrue($result); @@ -300,24 +246,12 @@ class Horde_Kolab_Storage_DataTest extends Horde_Kolab_Test_Storage 'email' => 'p@rdus.de' ); $result = $data->save($object); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); $result = $data->deleteAll(); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); $ids = $data->getObjectIds(); - if (is_a($ids, 'PEAR_Error')) { - $this->assertEquals('', $ids->message); - } $this->assertTrue(empty($ids)); } diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/FolderTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/FolderTest.php index 97227c4ee..990082fc8 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/FolderTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/FolderTest.php @@ -2,34 +2,33 @@ /** * Test the Kolab folder handler. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/FolderTest.php,v 1.11 2009/06/09 23:23:39 slusarz Exp $ + * PHP version 5 * - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ /** - * We need the unit test framework + * The Autoloader allows us to omit "require/include" statements. */ -require_once 'Horde/Kolab/Test/Storage.php'; - -require_once 'Horde.php'; -require_once 'Horde/Kolab/Storage/Folder.php'; -require_once 'Horde/Kolab/Storage/List.php'; -require_once 'Horde/Kolab/IMAP.php'; -require_once 'Horde/Kolab/IMAP/test.php'; +require_once 'Horde/Autoloader.php'; /** * Test the Kolab folder handler. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/FolderTest.php,v 1.11 2009/06/09 23:23:39 slusarz Exp $ - * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Gunnar Wrobel - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ class Horde_Kolab_Storage_FolderTest extends Horde_Kolab_Test_Storage { @@ -41,13 +40,12 @@ class Horde_Kolab_Storage_FolderTest extends Horde_Kolab_Test_Storage { $world = $this->prepareBasicSetup(); - $this->assertTrue($world['auth']->authenticate('wrobel@example.org', - array('password' => 'none'))); - - $this->prepareNewFolder($world['storage'], 'Contacts', 'contact', true); - $this->prepareNewFolder($world['storage'], 'NewContacts', 'contact'); + $this->storage = $this->authenticate($world['auth'], + 'wrobel@example.org', + 'none'); - $this->list = &new Kolab_List(); + $this->prepareNewFolder($this->storage, 'Contacts', 'contact', true); + $this->prepareNewFolder($this->storage, 'NewContacts', 'contact'); } /** @@ -55,7 +53,7 @@ class Horde_Kolab_Storage_FolderTest extends Horde_Kolab_Test_Storage */ public function testConstruct() { - $folder = &new Kolab_Folder('INBOX/Contacts'); + $folder = &new Horde_Kolab_Storage_Folder('INBOX/Contacts'); $this->assertEquals('INBOX/Contacts', $folder->name); $this->assertTrue(is_array($folder->_data)); $this->assertTrue(empty($folder->_data)); @@ -63,13 +61,22 @@ class Horde_Kolab_Storage_FolderTest extends Horde_Kolab_Test_Storage } /** + * Test destruction. + */ + public function tearDown() + { + Horde_Imap_Client_Mock::clean(); + $this->storage->clean(); + } + + /** * Test renaming. */ public function testSetName() { - $folder = &new Kolab_Folder('INBOX/Contacts'); + $folder = &new Horde_Kolab_Storage_Folder('INBOX/Contacts'); $folder->setName('TestAÖÜ'); - $this->assertEquals(Horde_String::convertCharset('INBOX/TestAÖÜ', NLS::getCharset(), 'UTF7-IMAP'), $folder->new_name); + $this->assertEquals(Horde_String::convertCharset('INBOX/TestAÖÜ', Horde_Nls::getCharset(), 'UTF7-IMAP'), $folder->new_name); } /** @@ -77,12 +84,12 @@ class Horde_Kolab_Storage_FolderTest extends Horde_Kolab_Test_Storage */ public function testSave() { - $folder = &new Kolab_Folder(); - $folder->setList($this->list); + $folder = $this->storage->getNewFolder(); - $result = $folder->save(); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals("Cannot create this folder! The name has not yet been set.", $result->message); + try { + $result = $folder->save(); + } catch (Exception $e) { + $this->assertEquals(Horde_Kolab_Storage_Exception::FOLDER_NAME_UNSET , $e->getCode()); } $folder->setName('TestÄÖÜ'); $result = $folder->exists(); @@ -108,17 +115,13 @@ class Horde_Kolab_Storage_FolderTest extends Horde_Kolab_Test_Storage $this->assertTrue($folder->exists()); $this->assertTrue($folder->accessible()); - $folder2 = &new Kolab_Folder(); - $folder2->setList($this->list); + $folder2 = $this->storage->getNewFolder(); $folder2->setName('TestEvents'); $attributes = array( 'type' => 'event', 'default' => true, ); $result = $folder2->save($attributes); - if (is_a($result, 'PEAR_Error')) { - $this->assertEquals('', $result->message); - } $this->assertTrue($result); $this->assertEquals("wrobel@example.org", $folder2->getOwner()); $this->assertEquals("TestEvents", $folder2->getTitle()); @@ -170,25 +173,32 @@ class Horde_Kolab_Storage_FolderTest extends Horde_Kolab_Test_Storage /** * Test triggering. */ - public function testTrigger() + public function testTriggerOwn() { - $folder = $this->getMock('Kolab_Folder', array('triggerUrl')); + $folder = $this->getMock('Horde_Kolab_Storage_Folder', array('triggerUrl')); $folder->expects($this->once()) ->method('triggerUrl') ->with($this->equalTo('https://fb.example.org/freebusy/trigger/wrobel@example.org/Kalender.pfb')); - $folder->setList(&$this->list); + $connection = $this->storage->getConnection(); + $folder->restore($this->storage, $connection->connection); $folder->setName('Kalender'); $folder->save(array('type' => 'event')); - - $folder = $this->getMock('Kolab_Folder', array('triggerUrl')); - $folder->expects($this->once()) + } + + /** + * Test triggering. + */ + public function testTriggerForeign() + { + $folder = $this->getMock('Horde_Kolab_Storage_Folder', array('triggerUrl')); + $folder->expects($this->exactly(2)) ->method('triggerUrl') ->with($this->equalTo('https://fb.example.org/freebusy/trigger/test@example.org/Kalender.pfb')); - $folder->setList(&$this->list); + $connection = $this->storage->getConnection(); + $folder->restore($this->storage, $connection->connection); $folder->setName('user/test/Kalender'); $folder->save(array('type' => 'event')); - } } diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/ListTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/ListTest.php index e587db82f..ada5635e7 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/ListTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/ListTest.php @@ -8,12 +8,9 @@ */ /** - * We need the base class + * The Autoloader allows us to omit "require/include" statements. */ -require_once 'Horde/Kolab/Test/Storage.php'; - -require_once 'Horde.php'; -require_once 'Horde/Kolab/Storage/List.php'; +require_once 'Horde/Autoloader.php'; /** * Test the Kolab list handler. @@ -38,21 +35,42 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage { $world = $this->prepareBasicSetup(); - $this->assertTrue($world['auth']->authenticate('wrobel@example.org', - array('password' => 'none'))); + /** Prepare a Kolab test storage */ + $params = array('driver' => 'Mock', + 'username' => 'wrobel@example.org', + 'password' => 'none'); + $storage1 = Horde_Kolab_Storage::singleton('imap', $params); + + $folder = $this->prepareNewFolder($storage1, 'Contacts', 'contact', true); + $perms = $folder->getPermission(); + $perms->addUserPermission('test@example.org', PERMS_SHOW); + $perms->save(); - $this->prepareNewFolder($world['storage'], 'Contacts', 'contact', true); - $this->prepareNewFolder($world['storage'], 'Calendar', 'event', true); + $folder = $this->prepareNewFolder($storage1, 'Calendar', 'event', true); + $perms = $folder->getPermission(); + $perms->addUserPermission('test@example.org', PERMS_SHOW); + $perms->save(); - $this->assertTrue($world['auth']->authenticate('test@example.org', - array('password' => 'test'))); + /** Prepare a Kolab test storage */ + $storage2 = $this->authenticate($world['auth'], + 'test@example.org', + 'test'); - $this->prepareNewFolder($world['storage'], 'Contacts', 'contact', true); - $this->prepareNewFolder($world['storage'], 'TestContacts', 'contact'); - $this->prepareNewFolder($world['storage'], 'Calendar', 'event', true); - $this->prepareNewFolder($world['storage'], 'TestCalendar', 'event'); + $this->prepareNewFolder($storage2, 'Contacts', 'contact', true); + $this->prepareNewFolder($storage2, 'TestContacts', 'contact'); + $this->prepareNewFolder($storage2, 'Calendar', 'event', true); + $this->prepareNewFolder($storage2, 'TestCalendar', 'event'); + + $this->list = &$storage2; + } - $this->list = &new Kolab_List(); + /** + * Test destruction. + */ + public function tearDown() + { + Horde_Imap_Client_Mock::clean(); + $this->list->clean(); } /** @@ -60,11 +78,7 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage */ public function testConstruct() { - $this->assertEquals(0, $this->list->validity); - $this->assertTrue(is_array($this->list->_folders)); - $this->assertTrue(empty($this->list->_folders)); - $this->assertTrue(empty($this->list->_defaults)); - $this->assertTrue(empty($this->list->_types)); + $this->assertTrue($this->list instanceOf Horde_Kolab_Storage); } /** @@ -73,7 +87,6 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage public function testListFolders() { $folders = $this->list->listFolders(); - $this->assertFalse(is_a($folders, 'PEAR_Error')); $this->assertContains('INBOX/Contacts', $folders); } @@ -84,7 +97,11 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage { $folders = $this->list->getFolders(); $this->assertEquals(6, count($folders)); - $this->assertContains('INBOX/Contacts', array_keys($this->list->_folders)); + $folder_names = array(); + foreach ($folders as $folder) { + $folder_names[] = $folder->name; + } + $this->assertContains('INBOX/Contacts', $folder_names); } /** @@ -93,9 +110,6 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage public function testGetByShare() { $folder = $this->list->getByShare('test@example.org', 'event'); - if (is_a($folder, 'PEAR_Error')) { - $this->assertEquals('', $folder->message); - } $this->assertEquals('INBOX/Calendar', $folder->name); } @@ -152,34 +166,50 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage */ public function testCreate() { - $folder = &new Kolab_Folder(null); - $folder->setList($this->list); + $folder = $this->list->getNewFolder(); $folder->setName('Notes'); $folder->save(array()); - $this->assertContains('INBOX/Notes', array_keys($this->list->_folders)); - $this->assertEquals(1, $this->list->validity); + $result = $this->list->getFolder('INBOX/Notes'); + $this->assertTrue($result instanceOf Horde_Kolab_Storage_Folder); } /** * Test cache update. */ - public function testCacheUpdate() + public function testCacheAdd() { - $this->list = $this->getMock('Kolab_List', array('updateCache')); - $this->list->expects($this->once()) - ->method('updateCache'); + $params = array('driver' => 'Mock', + 'username' => 'cacheadd@example.org', + 'password' => 'none'); + $storage4 = $this->getMock('Horde_Kolab_Storage', + array('addToCache', 'removeFromCache'), + array('imap', $params)); + $storage4->expects($this->once()) + ->method('addToCache'); - $folder = &new Kolab_Folder(null); - $folder->setList($this->list); + $folder = $storage4->getNewFolder(); $folder->setName('Notes'); - $this->assertEquals('INBOX/Notes', $folder->new_name); $folder->save(array()); - $type = $folder->getType(); - if (is_a($type, 'PEAR_Error')) { - $this->assertEquals('', $type->getMessage()); - } - $this->assertEquals('mail', $type); - $this->assertEquals('INBOX/Notes', $folder->name); + } + + /** + * Test cache update. + */ + public function testCacheDelete() + { + $params = array('driver' => 'Mock', + 'username' => 'cachedel@example.org', + 'password' => 'none'); + $storage4 = $this->getMock('Horde_Kolab_Storage', + array('addToCache', 'removeFromCache'), + array('imap', $params)); + $storage4->expects($this->once()) + ->method('removeFromCache'); + + $folder = $storage4->getNewFolder(); + $folder->setName('Notes'); + $folder->save(array()); + $folder->delete(); } @@ -188,13 +218,11 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage */ public function testRename() { - $folder = &new Kolab_Folder('INBOX/TestContacts'); - $folder->setList($this->list); + $folder = &$this->list->getFolder('INBOX/TestContacts'); $folder->setName('TestNotes'); $folder->save(array()); - $this->assertNotContains('INBOX/TestContacts', array_keys($this->list->_folders)); - $this->assertContains('INBOX/TestNotes', array_keys($this->list->_folders)); - $this->assertEquals(1, $this->list->validity); + $this->assertNotContains('INBOX/TestContacts', $this->list->listFolders()); + $this->assertContains('INBOX/TestNotes', $this->list->listFolders()); } /** @@ -202,13 +230,11 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage */ public function testRemove() { - $folder = &new Kolab_Folder('INBOX/Calendar'); - $folder->setList($this->list); + $folder = &$this->list->getFolder('INBOX/Calendar'); $this->assertTrue($folder->exists()); $this->assertTrue($folder->isDefault()); $folder->delete(); - $this->assertNotContains('INBOX/Calendar', array_keys($this->list->_folders)); - $this->assertEquals(1, $this->list->validity); + $this->assertNotContains('INBOX/Calendar', $this->list->listFolders()); } /** @@ -216,57 +242,60 @@ class Horde_Kolab_Storage_ListTest extends Horde_Kolab_Test_Storage */ public function testCaching() { - $GLOBALS['KOLAB_TESTING'] = array(); - $this->list = &new Kolab_List(); - $folders = $this->list->getFolders(); - $this->assertTrue(empty($folders)); - $folders = $this->list->getByType('event'); + $params = array('driver' => 'Mock', + 'username' => 'cache@example.org', + 'password' => 'none'); + $storage3 = Horde_Kolab_Storage::singleton('imap', $params); + $folders = $storage3->getFolders(); + $this->assertTrue(count($folders) == 1); + $folders = $storage3->getByType('event'); $this->assertTrue(empty($folders)); - $default = $this->list->getDefault('event'); + $default = $storage3->getDefault('event'); $this->assertTrue(empty($default)); - $addfolder = &new Kolab_Folder(null); + $connection = $storage3->getConnection(); + $addfolder = new Horde_Kolab_Storage_Folder(null); + $addfolder->restore($storage3, $connection->connection); $addfolder->setName('TestFolder'); - $addfolder->setList($this->list); $addfolder->save(array('type' => 'event', 'default' => true)); - $this->assertContains('INBOX/TestFolder', array_keys($this->list->_folders)); + $this->assertContains('INBOX/TestFolder', $storage3->listFolders()); $this->assertEquals('test@example.org', $addfolder->getOwner()); - $folders = $this->list->getFolders(); + $folders = $storage3->getFolders(); $names = array(); foreach ($folders as $folder) { $names[] = $folder->name; } $this->assertContains('INBOX/TestFolder', $names); - $folders = $this->list->getByType('event'); + $folders = $storage3->getByType('event'); $names = array(); foreach ($folders as $folder) { $names[] = $folder->name; } $this->assertContains('INBOX/TestFolder', $names); - $default = $this->list->getDefault('event'); + $default = $storage3->getDefault('event'); $this->assertTrue($default !== false); $this->assertEquals('INBOX/TestFolder', $default->name); $addfolder->setName('NewCal'); $addfolder->save(); - $folders = $this->list->getFolders(); + $folders = $storage3->getFolders(); $names = array(); foreach ($folders as $folder) { $names[] = $folder->name; } $this->assertContains('INBOX/NewCal', $names); - $folders = $this->list->getByType('event'); + $folders = $storage3->getByType('event'); $names = array(); foreach ($folders as $folder) { $names[] = $folder->name; } $this->assertContains('INBOX/NewCal', $names); - $default = $this->list->getDefault('event'); + $default = $storage3->getDefault('event'); $this->assertEquals('INBOX/NewCal', $default->name); $addfolder->delete(); - $folders = $this->list->getFolders(); - $this->assertTrue(empty($folders)); - $folders = $this->list->getByType('event'); + $folders = $storage3->getFolders(); + $this->assertTrue(count($folders) == 1); + $folders = $storage3->getByType('event'); $this->assertTrue(empty($folders)); - $default = $this->list->getDefault('event'); + $default = $storage3->getDefault('event'); $this->assertTrue(empty($default)); } } diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php index 6b1787a7c..e75a3b424 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php @@ -2,31 +2,33 @@ /** * Test the Kolab permission handler. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php,v 1.4 2009/01/06 17:49:28 jan Exp $ + * PHP version 5 * - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ /** - * We need the unit test framework + * The Autoloader allows us to omit "require/include" statements. */ -require_once 'PHPUnit/Framework.php'; - -require_once 'Horde.php'; -require_once 'Horde/Kolab/Storage/Perms.php'; +require_once 'Horde/Autoloader.php'; /** * Test the Kolab permission handler. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php,v 1.4 2009/01/06 17:49:28 jan Exp $ - * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Gunnar Wrobel - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase { @@ -37,14 +39,18 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase public function testConstruct() { $folder = &new DummyFolder(null); - $perms = &new Horde_Permission_Kolab($folder); - $this->assertEquals('DummyFolder', get_class($perms->_folder)); - $this->assertEquals(array(), $perms->data); - $perms = &new Horde_Permission_Kolab($folder, array('users' => array( - 'wrobel' => PERMS_SHOW | PERMS_READ | - PERMS_EDIT | PERMS_DELETE) - )); - $this->assertTrue(is_array($perms->data)); + $perms = &new Horde_Kolab_Storage_Permission($folder); + $this->assertEquals(array(), $perms->get('perm')); + $permissions = array('users' => + array( + 'wrobel' => + PERMS_SHOW | + PERMS_READ | + PERMS_EDIT | + PERMS_DELETE + )); + $perms = &new Horde_Kolab_Storage_Permission($folder, $permissions); + $this->assertTrue(is_array($perms->get('perm'))); } /** @@ -66,13 +72,14 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase 'group:editors' => 'lre' ) ); - $perms = &new Horde_Permission_Kolab($folder); - $this->assertContains('users', array_keys($perms->data)); - $this->assertContains('wrobel', array_keys($perms->data['users'])); - $this->assertContains('reader', array_keys($perms->data['users'])); - $this->assertContains('groups', array_keys($perms->data)); - $this->assertContains('default', array_keys($perms->data)); - $this->assertContains('guest', array_keys($perms->data)); + $perms = &new Horde_Kolab_Storage_Permission($folder); + $data = $perms->getData(); + $this->assertContains('users', array_keys($data)); + $this->assertContains('wrobel', array_keys($data['users'])); + $this->assertContains('reader', array_keys($data['users'])); + $this->assertContains('groups', array_keys($data)); + $this->assertContains('default', array_keys($data)); + $this->assertContains('guest', array_keys($data)); } /** @@ -95,13 +102,15 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase ), 'wrobel' ); - $perms = &new Horde_Permission_Kolab($folder); - unset($perms->data['guest']); - unset($perms->data['default']); - unset($perms->data['users']['viewer']); - $perms->data['users']['editor'] = PERMS_SHOW | PERMS_READ | PERMS_EDIT | PERMS_DELETE; - $perms->data['users']['test'] = PERMS_SHOW | PERMS_READ; - $perms->data['groups']['group'] = PERMS_SHOW | PERMS_READ; + $perms = &new Horde_Kolab_Storage_Permission($folder); + $data = $perms->getData(); + unset($data['guest']); + unset($data['default']); + unset($data['users']['viewer']); + $data['users']['editor'] = PERMS_SHOW | PERMS_READ | PERMS_EDIT | PERMS_DELETE; + $data['users']['test'] = PERMS_SHOW | PERMS_READ; + $data['groups']['group'] = PERMS_SHOW | PERMS_READ; + $perms->setData($data); $perms->save(); $this->assertNotContains('anyone', array_keys($folder->acl)); $this->assertNotContains('anonymous', array_keys($folder->acl)); @@ -121,7 +130,7 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase $folder = &new DummyFolder(array(), 'wrobel'); $hperms = &new Horde_Permission('test'); $hperms->addUserPermission('wrobel', PERMS_SHOW, false); - $perms = &new Horde_Permission_Kolab($folder, $hperms->data); + $perms = &new Horde_Kolab_Storage_Permission($folder, $hperms->data); $perms->save(); $this->assertEquals('al', $folder->acl['wrobel']); } @@ -130,17 +139,18 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase /** * A dummy folder representation to test the Kolab permission handler. * - * $Horde: framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php,v 1.4 2009/01/06 17:49:28 jan Exp $ - * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Gunnar Wrobel - * @package Kolab_Storage + * @category Kolab + * @package Kolab_Storage + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Storage */ -class DummyFolder +class DummyFolder extends Horde_Kolab_Storage_Folder { var $acl; var $_owner;