diff --git a/lib/kolab_api_folder.php b/lib/kolab_api_folder.php index e032d03..50052da 100644 --- a/lib/kolab_api_folder.php +++ b/lib/kolab_api_folder.php @@ -1,546 +1,546 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_folder { /** * List of default properties * * @var array */ public static $fields = array( 'uid', 'parent', 'name', 'fullpath', 'type', /* 'rights', 'namespace', 'size', 'exists', 'unseen', 'modseq', 'uidvalidity', 'children', 'deleted', 'unread', */ ); /** * Modified properties * * @var array */ protected $data = array(); /** * Writeable properties * * @var array */ protected $write_props = array( 'parent', 'name', 'type', 'subscribed', ); protected $_name; protected $_uid; protected $_parent; protected $_type; protected $_fullpath; protected $_subscribed; /** * Object constructor * * @param array $props Original folder properties (name, fullpath, uid, parent, * type, subscribed) */ public function __construct($props = null) { $fields = array('uid', 'fullpath'); $fields = array_merge($this->write_props, $fields); foreach ($fields as $i) { if (array_key_exists($i, (array) $props)) { $this->{'_' . $i} = $props[$i]; unset($props[$i]); } } $this->data = $props; } /** * Properties setter * * @param string $name Property name * @param mixed $value Property value */ public function __set($name, $value) { if (in_array($name, $this->write_props)) { switch ($name) { case 'subscribed': $value = (bool) $value; break; case 'uid': // ignore return; } } // make sure the value is utf-8 if ($value !== null && $value !== '' && (!is_array($value) || !empty($value))) { // make sure we have utf-8 here $value = rcube_charset::clean($value); } $this->data[$name] = $value; } /** * Properties getter * * @param string $name Property name * * @param mixed Property value */ public function __get($name) { if (array_key_exists($name, $this->data)) { return $this->data[$name]; } $value = null; switch ($name) { case 'name': case 'fullpath': case 'type': case 'parent': case 'uid': $value = $this->{'_' . $name}; break; case 'children': return (int) $this->children(); case 'deleted': return (int) $this->deleted(); case 'size': return (int) $this->size(); case 'unread': return (int) $this->unread(); case 'rights': // @TODO break; case 'namespace': // @TODO break; case 'exists': case 'unseen': case 'highestmodseq': case 'uidvalidity': // get IMAP folder data $api = kolab_api::get_instance(); $folder = rcube_charset::convert($this->_fullpath, RCUBE_CHARSET, 'UTF7-IMAP'); $data = $api->backend->storage->folder_data($folder); $data = array_change_key_case((array) $data); $this->data = array_merge($data, $this->data); - $value = $this->data[$name]; + $value = $this->data[$name] ?: 0; break; } // add the value to the result if ($value !== null && $value !== '' && (!is_array($value) || !empty($value))) { // make sure we have utf-8 here $value = rcube_charset::clean($value); } return $value; } /** * Return folder data as an array * * @param array $filter Optional properties filter * * @return array Folder information */ public function data($filter = array()) { $result = array(); $extra = array(); $fields = self::$fields; if (!empty($filter)) { $extra = array_diff($filter, $fields); $fields = array_intersect($fields, $filter); } foreach ($fields as $field) { $value = $this->{$field}; // add the value to the result if ($value !== null && $value !== '') { $result[$field] = $value; } } foreach ($extra as $field) { $result[$field] = $this->{$field}; } return $result; } /** * Check if the original folder has been modified * * @return bool True if the folder has been modified * since the object creation */ public function changed() { foreach ($this->write_props as $prop) { if ($this->data[$prop] !== $this->{'_' . $prop}) { return true; } } return false; } /** * Check object validity * * @return bool True if the object is valid */ public function valid() { if (!strlen($this->data['name']) && !strlen($this->_name)) { return false; } // @TODO: check validity of the folder name return true; } /** * Save the folder information * * @return string New folder UID * @throws kolab_api_exception */ public function save() { if (empty($this->data)) { // Assume success if folder exists and nothing changed if (!empty($this->_uid)) { return $this->_uid; } throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR, array( 'file' => __FILE__, 'line' => __LINE__, 'message' => 'Nothing to save. Did you use kolab_api_folder::changed()?' )); } $api = kolab_api::get_instance(); // create new folder if ($this->_name === null) { $folder = $this->data['name']; if ($parent = $this->parent) { $parent = $api->backend->folder_info($parent); $folder = $parent->fullpath . $api->backend->delimiter . $folder; } $uid = $this->folder_create($folder, $this->type, $this->subscribed); } // existing folder... else { // need rename? $name = $this->_name; $parent = $this->_parent; $parent_change = isset($this->data['parent']) && $this->data['parent'] != $parent; $name_change = isset($this->data['name']) && $this->data['name'] !== $name; if ($parent_change || $name_change) { if ($name_change) { if (!strlen($this->data['name'])) { throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST); } $path = explode($api->backend->delimiter, $fullpath); array_pop($path); $path = implode($api->backend->delimiter, $path); $name = $this->data['name']; $fullpath = (strlen($path) ? $path . $api->backend->delimiter : '') . $this->data['name']; } if ($parent_change) { if ($this->data['parent']) { $parent = $api->backend->folder_info($this->data['parent']); $fullpath = $parent->fullpath . $api->backend->delimiter . $name; $parent = $this->data['parent']; } else { $fullpath = $name; } } $this->folder_rename($this->_fullpath, $fullpath); $this->_fullpath = $fullpath; $this->_name = $name; $this->_parent = $parent; } // type change if (isset($this->data['type']) && $this->data['type'] != $this->_type) { $this->folder_set_type($this->_fullpath, $this->data['type']); $this->_type = $this->data['type']; } // subscribtion status change if (isset($this->data['subscribed']) && $this->data['subscribed'] !== $this->_subscribed) { $this->folder_subscribe($this->_fullpath, $this->data['subscribed']); $this->_subscribed = $this->data['subscribed']; } $uid = $this->_uid; } return $uid; } /** * Deletes folder * * @throws kolab_api_exception */ public function delete() { $api = kolab_api::get_instance(); $folder = rcube_charset::convert($this->fullpath, RCUBE_CHARSET, 'UTF7-IMAP'); // don't use kolab_storage for mail folders if ($this->type === 'mail') { $status = $api->backend->storage->delete_folder($folder); } else { $status = kolab_storage::folder_delete($folder); } if (!$status) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } /** * Renames a folder * * @param string $old_name Folder name (UTF-8) * @param string $new_name New folder name (UTF-8) * * @throws kolab_api_exception */ protected function folder_rename($old_name, $new_name) { $api = kolab_api::get_instance(); $old_name = rcube_charset::convert($old_name, RCUBE_CHARSET, 'UTF7-IMAP'); $new_name = rcube_charset::convert($new_name, RCUBE_CHARSET, 'UTF7-IMAP'); if (!strlen($old_name) || !strlen($new_name) || $old_name === $new_name) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } if ($api->backend->storage->folder_exists($new_name)) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } $type = kolab_storage::folder_type($old_name); if ($type === null) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } // don't use kolab_storage for moving mail folders if (preg_match('/^mail/', $type)) { $result = $api->backend->storage->rename_folder($old_name, $new_name); } else { $result = kolab_storage::folder_rename($old_name, $new_name); } if (!$result) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } /** * Creates a folder * * @param string $name Folder name (UTF-8) * @param string $type Folder type * @param bool $subscribe Subscription flag * * @throws kolab_api_exception */ protected function folder_create($name, $type, $subscribe) { $api = kolab_api::get_instance(); $folder = rcube_charset::convert($name, RCUBE_CHARSET, 'UTF7-IMAP'); if ($api->backend->storage->folder_exists($folder)) { // @FIXME: This is a hack for Mapistore, for some reason // it tries to create already existing folders return $api->backend->folder_name2uid($name); // throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } $created = kolab_storage::folder_create($folder, $type, $subscribe, false); if (!$created) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } return $api->backend->folder_name2uid($name); } /** * Change folder subscription * * @param string $name Folder name (UTF-8) * @param bool $subscribe Subscription flag * * @throws kolab_api_exception */ protected function folder_subscribe($name, $subscribe) { $api = kolab_api::get_instance(); $folder = rcube_charset::convert($name, RCUBE_CHARSET, 'UTF7-IMAP'); $result = $api->backend->storage->{$subscribe ? 'subscribe' : 'unsubscribe'}($folder); if (!$result) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } /** * Change folder type * * @param string $name Folder name (UTF-8) * @param string $type Folder type * * @throws kolab_api_exception */ protected function folder_set_type($name, $type) { $folder = rcube_charset::convert($name, RCUBE_CHARSET, 'UTF7-IMAP'); $result = kolab_storage::set_folder_type($folder, $type); if (!$result) { throw new kolab_api_exception(kolab_api_exception::SERVER_ERROR); } } /** * Returns number of subfolders in the current folder */ protected function children() { if ($this->_fullpath !== null) { $api = kolab_api::get_instance(); $folder = rcube_charset::convert($this->_fullpath, RCUBE_CHARSET, 'UTF7-IMAP'); $delim = $api->backend->storage->get_hierarchy_delimiter(); $list = $api->backend->storage->list_folders($folder . $delim, '%', null, null, true); $this->data['children'] = count($list); } return $this->data['children']; } /** * Returns number of deleted messages in the current folder */ protected function deleted() { if ($this->_fullpath !== null) { $api = kolab_api::get_instance(); $folder = rcube_charset::convert($this->_fullpath, RCUBE_CHARSET, 'UTF7-IMAP'); $search = $api->backend->storage->search_once($folder, 'DELETED'); return $search ? $search->count() : 0; } } /** * Returns number of unread messages in the current folder */ protected function unread() { if ($this->_fullpath !== null) { $api = kolab_api::get_instance(); $folder = rcube_charset::convert($this->_fullpath, RCUBE_CHARSET, 'UTF7-IMAP'); $search = $api->backend->storage->search_once($folder, 'UNSEEN'); return $search ? $search->count() : 0; } } /** * Returns size of all messages in the current folder */ protected function size() { if ($this->_fullpath !== null) { $api = kolab_api::get_instance(); $folder = rcube_charset::convert($this->_fullpath, RCUBE_CHARSET, 'UTF7-IMAP'); return $api->backend->storage->folder_size($folder); } } }