Changeset View
Changeset View
Standalone View
Standalone View
plugins/libkolab/lib/kolab_storage.php
Show All 19 Lines | |||||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | ||||
* | * | ||||
* You should have received a copy of the GNU Affero General Public License | * You should have received a copy of the GNU Affero General Public License | ||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
class kolab_storage | class kolab_storage | ||||
{ | { | ||||
const CTYPE_KEY = '/shared/vendor/kolab/folder-type'; | const CTYPE_KEY = '/shared/vendor/kolab/folder-type'; | ||||
const CTYPE_KEY_PRIVATE = '/private/vendor/kolab/folder-type'; | const CTYPE_KEY_PRIVATE = '/private/vendor/kolab/folder-type'; | ||||
const COLOR_KEY_SHARED = '/shared/vendor/kolab/color'; | const COLOR_KEY_SHARED = '/shared/vendor/kolab/color'; | ||||
const COLOR_KEY_PRIVATE = '/private/vendor/kolab/color'; | const COLOR_KEY_PRIVATE = '/private/vendor/kolab/color'; | ||||
const NAME_KEY_SHARED = '/shared/vendor/kolab/displayname'; | const NAME_KEY_SHARED = '/shared/vendor/kolab/displayname'; | ||||
const NAME_KEY_PRIVATE = '/private/vendor/kolab/displayname'; | const NAME_KEY_PRIVATE = '/private/vendor/kolab/displayname'; | ||||
const UID_KEY_SHARED = '/shared/vendor/kolab/uniqueid'; | const UID_KEY_SHARED = '/shared/vendor/kolab/uniqueid'; | ||||
const UID_KEY_CYRUS = '/shared/vendor/cmu/cyrus-imapd/uniqueid'; | const UID_KEY_CYRUS = '/shared/vendor/cmu/cyrus-imapd/uniqueid'; | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | public static function get_object($uid, $type) | ||||
return false; | return false; | ||||
} | } | ||||
/** | /** | ||||
* Execute cross-folder searches with the given query. | * Execute cross-folder searches with the given query. | ||||
* | * | ||||
* @param array Pseudo-SQL query as list of filter parameter triplets | * @param array Pseudo-SQL query as list of filter parameter triplets | ||||
* @param string Object type (contact,event,task,journal,file,note,configuration) | * @param string Object type (contact,event,task,journal,file,note,configuration) | ||||
* @param int Expected number of records or limit (for performance reasons) | |||||
* | |||||
* @return array List of Kolab data objects (each represented as hash array) | * @return array List of Kolab data objects (each represented as hash array) | ||||
* @see kolab_storage_format::select() | * @see kolab_storage_format::select() | ||||
*/ | */ | ||||
public static function select($query, $type) | public static function select($query, $type, $limit = null) | ||||
{ | { | ||||
self::setup(); | self::setup(); | ||||
$folder = null; | $folder = null; | ||||
$result = array(); | $result = array(); | ||||
foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) { | foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) { | ||||
if (!$folder) | |||||
$folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]); | $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]); | ||||
else | |||||
$folder->set_folder($foldername, $type, $folderdata[$foldername]); | if ($limit) { | ||||
$folder->set_order_and_limit(null, $limit); | |||||
} | |||||
foreach ($folder->select($query, '*') as $object) { | foreach ($folder->select($query, '*') as $object) { | ||||
$result[] = $object; | $result[] = $object; | ||||
} | } | ||||
} | } | ||||
return $result; | return $result; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 288 Lines • ▼ Show 20 Lines | public static function folder_update(&$prop) | ||||
} | } | ||||
return $result ? $folder : false; | return $result ? $folder : false; | ||||
} | } | ||||
/** | /** | ||||
* Getter for human-readable name of Kolab object (folder) | * Getter for human-readable name of Kolab object (folder) | ||||
* with kolab_custom_display_names support. | |||||
* See http://wiki.kolab.org/UI-Concepts/Folder-Listing for reference | * See http://wiki.kolab.org/UI-Concepts/Folder-Listing for reference | ||||
* | * | ||||
* @param string $folder IMAP folder name (UTF7-IMAP) | * @param string $folder IMAP folder name (UTF7-IMAP) | ||||
* @param string $folder_ns Will be set to namespace name of the folder | * @param string $folder_ns Will be set to namespace name of the folder | ||||
* | * | ||||
* @return string Name of the folder-object | * @return string Name of the folder-object | ||||
*/ | */ | ||||
public static function object_name($folder, &$folder_ns=null) | public static function object_name($folder, &$folder_ns=null) | ||||
{ | { | ||||
self::setup(); | |||||
// find custom display name in folder METADATA | // find custom display name in folder METADATA | ||||
if ($name = self::custom_displayname($folder)) { | if ($name = self::custom_displayname($folder)) { | ||||
return $name; | return $name; | ||||
} | } | ||||
return self::object_prettyname($folder, $folder_ns); | |||||
} | |||||
/** | |||||
* Get custom display name (saved in metadata) for the given folder | |||||
*/ | |||||
public static function custom_displayname($folder) | |||||
{ | |||||
// find custom display name in folder METADATA | |||||
if (self::$config->get('kolab_custom_display_names', true) && self::setup()) { | |||||
// For performance reasons ask for all folders, it will be cached as one cache entry | |||||
$metadata = self::$imap->get_metadata("*", array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED)); | |||||
if ($data = $metadata[$folder]) { | |||||
if (($name = $data[self::NAME_KEY_PRIVATE]) || ($name = $data[self::NAME_KEY_SHARED])) { | |||||
return $name; | |||||
} | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* Getter for human-readable name of Kolab object (folder) | |||||
* See http://wiki.kolab.org/UI-Concepts/Folder-Listing for reference | |||||
* | |||||
* @param string $folder IMAP folder name (UTF7-IMAP) | |||||
* @param string $folder_ns Will be set to namespace name of the folder | |||||
* | |||||
* @return string Name of the folder-object | |||||
*/ | |||||
public static function object_prettyname($folder, &$folder_ns=null) | |||||
{ | |||||
self::setup(); | |||||
$found = false; | $found = false; | ||||
$namespace = self::$imap->get_namespace(); | $namespace = self::$imap->get_namespace(); | ||||
if (!empty($namespace['shared'])) { | if (!empty($namespace['shared'])) { | ||||
foreach ($namespace['shared'] as $ns) { | foreach ($namespace['shared'] as $ns) { | ||||
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) { | if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) { | ||||
$prefix = ''; | $prefix = ''; | ||||
$folder = substr($folder, strlen($ns[0])); | $folder = substr($folder, strlen($ns[0])); | ||||
$delim = $ns[1]; | $delim = $ns[1]; | ||||
$found = true; | $found = true; | ||||
$folder_ns = 'shared'; | $folder_ns = 'shared'; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!$found && !empty($namespace['other'])) { | if (!$found && !empty($namespace['other'])) { | ||||
foreach ($namespace['other'] as $ns) { | foreach ($namespace['other'] as $ns) { | ||||
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) { | if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) { | ||||
// remove namespace prefix | // remove namespace prefix | ||||
$folder = substr($folder, strlen($ns[0])); | $folder = substr($folder, strlen($ns[0])); | ||||
$delim = $ns[1]; | $delim = $ns[1]; | ||||
// get username | // get username | ||||
$pos = strpos($folder, $delim); | $pos = strpos($folder, $delim); | ||||
if ($pos) { | if ($pos) { | ||||
$prefix = '('.substr($folder, 0, $pos).')'; | $prefix = '('.substr($folder, 0, $pos).')'; | ||||
$folder = substr($folder, $pos+1); | $folder = substr($folder, $pos+1); | ||||
} | } | ||||
else { | else { | ||||
$prefix = '('.$folder.')'; | $prefix = '('.$folder.')'; | ||||
$folder = ''; | $folder = ''; | ||||
} | } | ||||
$found = true; | $found = true; | ||||
$folder_ns = 'other'; | $folder_ns = 'other'; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!$found && !empty($namespace['personal'])) { | if (!$found && !empty($namespace['personal'])) { | ||||
foreach ($namespace['personal'] as $ns) { | foreach ($namespace['personal'] as $ns) { | ||||
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) { | if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) { | ||||
// remove namespace prefix | // remove namespace prefix | ||||
$folder = substr($folder, strlen($ns[0])); | $folder = substr($folder, strlen($ns[0])); | ||||
$prefix = ''; | $prefix = ''; | ||||
$delim = $ns[1]; | $delim = $ns[1]; | ||||
$found = true; | $found = true; | ||||
Show All 14 Lines | public static function object_prettyname($folder, &$folder_ns=null) | ||||
if (!$folder_ns) | if (!$folder_ns) | ||||
$folder_ns = 'personal'; | $folder_ns = 'personal'; | ||||
return $folder; | return $folder; | ||||
} | } | ||||
/** | /** | ||||
* Get custom display name (saved in metadata) for the given folder | |||||
*/ | |||||
public static function custom_displayname($folder) | |||||
{ | |||||
// find custom display name in folder METADATA | |||||
if (self::$config->get('kolab_custom_display_names', true)) { | |||||
$metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED)); | |||||
if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) { | |||||
return $name; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* Helper method to generate a truncated folder name to display. | * Helper method to generate a truncated folder name to display. | ||||
* Note: $origname is a string returned by self::object_name() | * Note: $origname is a string returned by self::object_name() | ||||
*/ | */ | ||||
public static function folder_displayname($origname, &$names) | public static function folder_displayname($origname, &$names) | ||||
{ | { | ||||
$name = $origname; | $name = $origname; | ||||
// find folder prefix to truncate | // find folder prefix to truncate | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | public static function folder_selector($type, $attrs, $current = '') | ||||
// skip folders where user have no rights to create subfolders | // skip folders where user have no rights to create subfolders | ||||
else if ($c_folder->get_owner() != $_SESSION['username']) { | else if ($c_folder->get_owner() != $_SESSION['username']) { | ||||
$rights = $c_folder->get_myrights(); | $rights = $c_folder->get_myrights(); | ||||
if (!preg_match('/[ck]/', $rights)) { | if (!preg_match('/[ck]/', $rights)) { | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
$names[$name] = self::object_name($name); | $names[$name] = $c_folder->get_name(); | ||||
} | } | ||||
// Build SELECT field of parent folder | // Build SELECT field of parent folder | ||||
$attrs['is_escaped'] = true; | $attrs['is_escaped'] = true; | ||||
$select = new html_select($attrs); | $select = new html_select($attrs); | ||||
$select->add('---', ''); | $select->add('---', ''); | ||||
$listnames = array(); | $listnames = array(); | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | class kolab_storage | ||||
*/ | */ | ||||
public static function sort_folders($folders) | public static function sort_folders($folders) | ||||
{ | { | ||||
$pad = ' '; | $pad = ' '; | ||||
$out = array(); | $out = array(); | ||||
$nsnames = array('personal' => array(), 'shared' => array(), 'other' => array()); | $nsnames = array('personal' => array(), 'shared' => array(), 'other' => array()); | ||||
foreach ($folders as $folder) { | foreach ($folders as $folder) { | ||||
$folders[$folder->name] = $folder; | $_folders[$folder->name] = $folder; | ||||
$ns = $folder->get_namespace(); | $ns = $folder->get_namespace(); | ||||
$nsnames[$ns][$folder->name] = strtolower(html_entity_decode(self::object_name($folder->name, $ns), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode » | $nsnames[$ns][$folder->name] = strtolower(html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode » | ||||
} | } | ||||
// $folders is a result of get_folders() we can assume folders were already sorted | // $folders is a result of get_folders() we can assume folders were already sorted | ||||
foreach (array_keys($nsnames) as $ns) { | foreach (array_keys($nsnames) as $ns) { | ||||
asort($nsnames[$ns], SORT_LOCALE_STRING); | asort($nsnames[$ns], SORT_LOCALE_STRING); | ||||
foreach (array_keys($nsnames[$ns]) as $utf7name) { | foreach (array_keys($nsnames[$ns]) as $utf7name) { | ||||
$out[] = $folders[$utf7name]; | $out[] = $_folders[$utf7name]; | ||||
} | } | ||||
} | } | ||||
return $out; | return $out; | ||||
} | } | ||||
/** | /** | ||||
Show All 24 Lines | public static function folder_hierarchy($folders, &$tree = null) | ||||
} | } | ||||
else { | else { | ||||
$parents = array(); | $parents = array(); | ||||
$depth = $folder->get_namespace() == 'personal' ? 1 : 2; | $depth = $folder->get_namespace() == 'personal' ? 1 : 2; | ||||
while (count($path) >= $depth && ($parent = join($delim, $path))) { | while (count($path) >= $depth && ($parent = join($delim, $path))) { | ||||
array_pop($path); | array_pop($path); | ||||
$parent_parent = join($delim, $path); | $parent_parent = join($delim, $path); | ||||
if (!$refs[$parent]) { | if (!$refs[$parent]) { | ||||
if ($folder->type && self::folder_type($parent) == $folder->type) { | if ($folder->type && self::folder_type($parent) == $folder->type) { | ||||
$refs[$parent] = new kolab_storage_folder($parent, $folder->type, $folder->type); | $refs[$parent] = new kolab_storage_folder($parent, $folder->type, $folder->type); | ||||
$refs[$parent]->parent = $parent_parent; | $refs[$parent]->parent = $parent_parent; | ||||
} | } | ||||
else if ($parent_parent == $other_ns) { | else if ($parent_parent == $other_ns) { | ||||
$refs[$parent] = new kolab_storage_folder_user($parent, $parent_parent); | $refs[$parent] = new kolab_storage_folder_user($parent, $parent_parent); | ||||
} | } | ||||
else { | else { | ||||
$name = kolab_storage::object_name($parent, $folder->get_namespace()); | $name = kolab_storage::object_name($parent); | ||||
$refs[$parent] = new kolab_storage_folder_virtual($parent, $name, $folder->get_namespace(), $parent_parent); | $refs[$parent] = new kolab_storage_folder_virtual($parent, $name, $folder->get_namespace(), $parent_parent); | ||||
} | } | ||||
$parents[] = $refs[$parent]; | $parents[] = $refs[$parent]; | ||||
} | } | ||||
} | } | ||||
if (!empty($parents)) { | if (!empty($parents)) { | ||||
$parents = array_reverse($parents); | $parents = array_reverse($parents); | ||||
▲ Show 20 Lines • Show All 565 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* Remove all cache data from the local database related to the given user. | * Remove all cache data from the local database related to the given user. | ||||
*/ | */ | ||||
public static function delete_user_folders($args) | public static function delete_user_folders($args) | ||||
{ | { | ||||
$db = rcmail::get_instance()->get_dbh(); | $db = rcmail::get_instance()->get_dbh(); | ||||
$prefix = 'imap://' . urlencode($args['username']) . '@' . $args['host'] . '/%'; | $prefix = 'imap://' . urlencode($args['username']) . '@' . $args['host'] . '/%'; | ||||
$db->query("DELETE FROM " . $db->table_name('kolab_folders', true) . " WHERE `resource` LIKE ?", $prefix); | $db->query("DELETE FROM " . $db->table_name('kolab_folders', true) . " WHERE `resource` LIKE ?", $prefix); | ||||
} | |||||
/** | |||||
* Get folder METADATA for all supported keys | |||||
* Do this in one go for better caching performance | |||||
*/ | |||||
public static function folder_metadata($folder) | |||||
{ | |||||
if (self::setup()) { | |||||
$keys = array( | |||||
// For better performance we skip displayname here, see (self::custom_displayname()) | |||||
// self::NAME_KEY_PRIVATE, | |||||
// self::NAME_KEY_SHARED, | |||||
self::CTYPE_KEY, | |||||
self::CTYPE_KEY_PRIVATE, | |||||
self::COLOR_KEY_PRIVATE, | |||||
self::COLOR_KEY_SHARED, | |||||
self::UID_KEY_SHARED, | |||||
self::UID_KEY_CYRUS, | |||||
); | |||||
$metadata = self::$imap->get_metadata($folder, $keys); | |||||
return $metadata[$folder]; | |||||
} | |||||
} | } | ||||
} | } |