Page MenuHomePhorge

No OneTemporary

Size
41 KB
Referenced Files
None
Subscribers
None
diff --git a/plugins/kolab_folders/kolab_folders.php b/plugins/kolab_folders/kolab_folders.php
index 29bcd2f9..3e010611 100644
--- a/plugins/kolab_folders/kolab_folders.php
+++ b/plugins/kolab_folders/kolab_folders.php
@@ -1,668 +1,517 @@
<?php
/**
* Type-aware folder management/listing for Kolab
*
* @version @package_version@
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2011, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*/
class kolab_folders extends rcube_plugin
{
public $task = '?(?!login).*';
public $types = array('mail', 'event', 'journal', 'task', 'note', 'contact', 'configuration');
public $mail_types = array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail');
private $rc;
- const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
-
/**
* Plugin initialization.
*/
function init()
{
$this->rc = rcmail::get_instance();
+ // load required plugin
+ $this->require_plugin('libkolab');
+
// Folder listing hooks
$this->add_hook('storage_folders', array($this, 'mailboxes_list'));
// Folder manager hooks
$this->add_hook('folder_form', array($this, 'folder_form'));
$this->add_hook('folder_update', array($this, 'folder_save'));
$this->add_hook('folder_create', array($this, 'folder_save'));
$this->add_hook('folder_delete', array($this, 'folder_save'));
$this->add_hook('folder_rename', array($this, 'folder_save'));
$this->add_hook('folders_list', array($this, 'folders_list'));
}
/**
* Handler for mailboxes_list hook. Enables type-aware lists filtering.
*/
function mailboxes_list($args)
{
- if (!$this->metadata_support()) {
+ // infinite loop prevention
+ if ($this->is_processing) {
return $args;
}
- $filter = $args['filter'];
-
- // all-folders request, use core method
- if (!$filter) {
+ if (!$this->metadata_support()) {
return $args;
}
- // get folders types
- $folderdata = $this->get_folder_type_list($args['root'].$args['name'], true);
+ $this->is_processing = true;
- if (!is_array($folderdata)) {
- return $args;
- }
+ // get folders
+ $folders = kolab_storage::list_folders($args['root'], $args['name'], $args['filter'], $args['mode'] == 'LSUB');
- $regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
+ $this->is_processing = false;
- // In some conditions we can skip LIST command (?)
- if ($args['mode'] == 'LIST' && $filter != 'mail'
- && $args['root'] == '' && $args['name'] == '*'
- ) {
- foreach ($folderdata as $folder => $type) {
- if (!preg_match($regexp, $type)) {
- unset($folderdata[$folder]);
- }
- }
- $args['folders'] = array_keys($folderdata);
+ if (!is_array($folders)) {
return $args;
}
- $storage = $this->rc->get_storage();
-
- // Get folders list
- if ($args['mode'] == 'LIST') {
- if (!$storage->check_connection()) {
- return $args;
- }
- $args['folders'] = $storage->conn->listMailboxes($args['root'], $args['name']);
- }
- else {
- $args['folders'] = $this->list_subscribed($args['root'], $args['name']);
+ // Create default folders
+ if ($args['root'] == '' && $args['name'] = '*') {
+ $this->create_default_folders($folders, $args['filter']);
}
- // In case of an error, return empty list
- if (!is_array($args['folders'])) {
- $args['folders'] = array();
- return $args;
- }
-
- // Filter folders list
- foreach ($args['folders'] as $idx => $folder) {
- $type = $folderdata[$folder];
- if ($filter == 'mail' && empty($type)) {
- continue;
- }
- if (empty($type) || !preg_match($regexp, $type)) {
- unset($args['folders'][$idx]);
- }
- }
+ $args['folders'] = $folders;
return $args;
}
/**
* Handler for folders_list hook. Add css classes to folder rows.
*/
function folders_list($args)
{
if (!$this->metadata_support()) {
return $args;
}
- $table = $args['table'];
+ $table = $args['table'];
+ $storage = $this->rc->get_storage();
// get folders types
- $folderdata = $this->get_folder_type_list('*');
+ $folderdata = $storage->get_metadata('*', kolab_storage::CTYPE_KEY);
if (!is_array($folderdata)) {
return $args;
}
// Add type-based style for table rows
// See kolab_folders::folder_class_name()
for ($i=1, $cnt=$table->size(); $i<=$cnt; $i++) {
$attrib = $table->get_row_attribs($i);
$folder = $attrib['foldername']; // UTF7-IMAP
- $type = $folderdata[$folder];
+ $type = !empty($folderdata[$folder]) ? $folderdata[$folder][kolab_storage::CTYPE_KEY] : null;
if (!$type)
$type = 'mail';
$class_name = self::folder_class_name($type);
$attrib['class'] = trim($attrib['class'] . ' ' . $class_name);
$table->set_row_attribs($attrib, $i);
}
return $args;
}
/**
* Handler for folder info/edit form (folder_form hook).
* Adds folder type selector.
*/
function folder_form($args)
{
if (!$this->metadata_support()) {
return $args;
}
// load translations
$this->add_texts('localization/', false);
// INBOX folder is of type mail.inbox and this cannot be changed
if ($args['name'] == 'INBOX') {
$args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
'label' => $this->gettext('folderctype'),
'value' => sprintf('%s (%s)', $this->gettext('foldertypemail'), $this->gettext('inbox')),
);
return $args;
}
if ($args['options']['is_root']) {
return $args;
}
$mbox = strlen($args['name']) ? $args['name'] : $args['parent_name'];
if (isset($_POST['_ctype'])) {
$new_ctype = trim(get_input_value('_ctype', RCUBE_INPUT_POST));
$new_subtype = trim(get_input_value('_subtype', RCUBE_INPUT_POST));
}
// Get type of the folder or the parent
if (strlen($mbox)) {
list($ctype, $subtype) = $this->get_folder_type($mbox);
if (strlen($args['parent_name']) && $subtype == 'default')
$subtype = ''; // there can be only one
}
if (!$ctype) {
$ctype = 'mail';
}
$storage = $this->rc->get_storage();
// Don't allow changing type of shared folder, according to ACL
if (strlen($mbox)) {
$options = $storage->folder_info($mbox);
if ($options['namespace'] != 'personal' && !in_array('a', $options['rights'])) {
if (in_array($ctype, $this->types)) {
$value = $this->gettext('foldertype'.$ctype);
}
else {
$value = $ctype;
}
if ($subtype) {
$value .= ' ('. ($subtype == 'default' ? $this->gettext('default') : $subtype) .')';
}
$args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
'label' => $this->gettext('folderctype'),
'value' => $value,
);
return $args;
}
}
// Add javascript script to the client
$this->include_script('kolab_folders.js');
// build type SELECT fields
$type_select = new html_select(array('name' => '_ctype', 'id' => '_ctype'));
$sub_select = new html_select(array('name' => '_subtype', 'id' => '_subtype'));
foreach ($this->types as $type) {
$type_select->add($this->gettext('foldertype'.$type), $type);
}
// add non-supported type
if (!in_array($ctype, $this->types)) {
$type_select->add($ctype, $ctype);
}
$sub_select->add('', '');
$sub_select->add($this->gettext('default'), 'default');
foreach ($this->mail_types as $type) {
$sub_select->add($this->gettext($type), $type);
}
$args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
'label' => $this->gettext('folderctype'),
'value' => $type_select->show(isset($new_ctype) ? $new_ctype : $ctype)
. $sub_select->show(isset($new_subtype) ? $new_subtype : $subtype),
);
return $args;
}
/**
* Handler for folder update/create action (folder_update/folder_create hook).
*/
function folder_save($args)
{
// Folder actions from folders list
if (empty($args['record'])) {
- // Just clear Horde folders cache and return
- $this->clear_folders_cache();
return $args;
}
// Folder create/update with form
$ctype = trim(get_input_value('_ctype', RCUBE_INPUT_POST));
$subtype = trim(get_input_value('_subtype', RCUBE_INPUT_POST));
$mbox = $args['record']['name'];
$old_mbox = $args['record']['oldname'];
$subscribe = $args['record']['subscribe'];
if (empty($ctype)) {
return $args;
}
// load translations
$this->add_texts('localization/', false);
// Skip folder creation/rename in core
// @TODO: Maybe we should provide folder_create_after and folder_update_after hooks?
// Using create_mailbox/rename_mailbox here looks bad
$args['abort'] = true;
// There can be only one default folder of specified type
if ($subtype == 'default') {
$default = $this->get_default_folder($ctype);
if ($default !== null && $old_mbox != $default) {
$args['result'] = false;
$args['message'] = $this->gettext('defaultfolderexists');
return $args;
}
}
// Subtype sanity-checks
else if ($subtype && ($ctype != 'mail' || !in_array($subtype, $this->mail_types))) {
$subtype = '';
}
$ctype .= $subtype ? '.'.$subtype : '';
$storage = $this->rc->get_storage();
// Create folder
if (!strlen($old_mbox)) {
// By default don't subscribe to non-mail folders
if ($subscribe)
$subscribe = (bool) preg_match('/^mail/', $ctype);
$result = $storage->create_folder($mbox, $subscribe);
// Set folder type
if ($result) {
$this->set_folder_type($mbox, $ctype);
}
}
// Rename folder
else {
if ($old_mbox != $mbox) {
$result = $storage->rename_folder($old_mbox, $mbox);
}
else {
$result = true;
}
if ($result) {
list($oldtype, $oldsubtype) = $this->get_folder_type($mbox);
$oldtype .= $oldsubtype ? '.'.$oldsubtype : '';
if ($ctype != $oldtype) {
$this->set_folder_type($mbox, $ctype);
}
}
}
- // Clear Horde folders cache
- if ($result) {
- $this->clear_folders_cache();
- }
-
$args['record']['class'] = self::folder_class_name($ctype);
$args['record']['subscribe'] = $subscribe;
$args['result'] = $result;
return $args;
}
/**
* Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
*
- * @return boolean
+ * @return boolean
*/
function metadata_support()
{
$storage = $this->rc->get_storage();
return $storage->get_capability('METADATA') ||
$storage->get_capability('ANNOTATEMORE') ||
$storage->get_capability('ANNOTATEMORE2');
}
/**
* Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
*
* @param string $folder Folder name
*
* @return array Folder content-type
*/
function get_folder_type($folder)
{
$storage = $this->rc->get_storage();
- $folderdata = $storage->get_metadata($folder, array(kolab_folders::CTYPE_KEY));
+ $folderdata = $storage->get_metadata($folder, kolab_storage::CTYPE_KEY);
- return explode('.', $folderdata[$folder][kolab_folders::CTYPE_KEY]);
+ return explode('.', $folderdata[$folder][kolab_storage::CTYPE_KEY]);
}
/**
* Sets folder content-type.
*
* @param string $folder Folder name
* @param string $type Content type
*
* @return boolean True on success
*/
function set_folder_type($folder, $type='mail')
{
$storage = $this->rc->get_storage();
- return $storage->set_metadata($folder, array(kolab_folders::CTYPE_KEY => $type));
- }
-
- /**
- * Returns list of subscribed folders (directly from IMAP server)
- *
- * @param string $root Optional root folder
- * @param string $name Optional name pattern
- *
- * @return array List of mailboxes/folders
- */
- private function list_subscribed($root='', $name='*')
- {
- $storage = $this->rc->get_storage();
-
- if (!$storage->check_connection()) {
- return null;
- }
-
- // Code copied from rcube_imap::_list_mailboxes()
- // Server supports LIST-EXTENDED, we can use selection options
- // #1486225: Some dovecot versions returns wrong result using LIST-EXTENDED
- if (!$this->rc->config->get('imap_force_lsub') && $storage->get_capability('LIST-EXTENDED')) {
- // This will also set mailbox options, LSUB doesn't do that
- $a_folders = $storage->conn->listMailboxes($root, $name,
- NULL, array('SUBSCRIBED'));
-
- // remove non-existent folders
- if (is_array($a_folders) && $name = '*' && !empty($storage->conn->data['LIST'])) {
- foreach ($a_folders as $idx => $folder) {
- if (($opts = $storage->conn->data['LIST'][$folder])
- && in_array('\\NonExistent', $opts)
- ) {
- $storage->conn->unsubscribe($folder);
- unset($a_folders[$idx]);
- }
- }
- }
- }
- // retrieve list of folders from IMAP server using LSUB
- else {
- $a_folders = $storage->conn->listSubscribed($root, $name);
-
- // unsubscribe non-existent folders, remove from the list
- if (is_array($a_folders) && $name == '*' && !empty($storage->conn->data['LIST'])) {
- foreach ($a_folders as $idx => $folder) {
- if (!isset($storage->conn->data['LIST'][$folder])
- || in_array('\\Noselect', $storage->conn->data['LIST'][$folder])
- ) {
- // Some servers returns \Noselect for existing folders
- if (!$storage->folder_exists($folder)) {
- $storage->conn->unsubscribe($folder);
- unset($a_folders[$idx]);
- }
- }
- }
- }
- }
-
- return $a_folders;
- }
-
- /**
- * Returns list of folder(s) type(s)
- *
- * @param string $mbox Folder name or pattern
- * @param bool $defaults Enables creation of configured default folders
- *
- * @return array List of folders data, indexed by folder name
- */
- function get_folder_type_list($mbox, $create_defaults = false)
- {
- $storage = $this->rc->get_storage();
-
- // Use mailboxes. prefix so the cache will be cleared by core
- // together with other mailboxes-related cache data
- $cache_key = 'mailboxes.folder-type.'.$mbox;
-
- // get cached metadata
- $metadata = $storage->get_cache($cache_key);
-
- if (!is_array($metadata)) {
- $metadata = $storage->get_metadata($mbox, kolab_folders::CTYPE_KEY);
- $need_update = true;
- }
-
- if (!is_array($metadata)) {
- return false;
- }
-
- // make the result more flat
- if ($need_update) {
- $metadata = array_map('implode', $metadata);
- }
-
- // create default folders if needed
- if ($create_defaults) {
- $this->create_default_folders($metadata, $cache_key);
- }
-
- // write mailboxlist to cache
- if ($need_update) {
- $storage->update_cache($cache_key, $metadata);
- }
-
- return $metadata;
+ return $storage->set_metadata($folder, array(kolab_storage::CTYPE_KEY => $type));
}
/**
* Returns the name of default folder
*
* @param string $type Folder type
*
* @return string Folder name
*/
function get_default_folder($type)
{
$storage = $this->rc->get_storage();
- $folderdata = $this->get_folder_type_list('*');
+ $folderdata = $storage->get_metadata('*', kolab_storage::CTYPE_KEY);
if (!is_array($folderdata)) {
return null;
}
$type .= '.default';
$namespace = $storage->get_namespace();
// get all folders of specified type
- $folderdata = array_intersect($folderdata, array($type));
+ $folderdata = array_map('implode', $folderdata);
+ $folderdata = array_intersect($folderdata, array($type));
unset($folders[0]);
foreach ($folderdata as $folder => $data) {
// check if folder is in personal namespace
foreach (array('shared', 'other') as $nskey) {
if (!empty($namespace[$nskey])) {
foreach ($namespace[$nskey] as $ns) {
if ($ns[0] && substr($folder, 0, strlen($ns[0])) == $ns[0]) {
continue 3;
}
}
}
}
// There can be only one default folder of specified type
return $folder;
}
return null;
}
/**
* Returns CSS class name for specified folder type
*
* @param string $type Folder type
*
* @return string Class name
*/
static function folder_class_name($type)
{
list($ctype, $subtype) = explode('.', $type);
$class[] = 'type-' . ($ctype ? $ctype : 'mail');
if ($subtype)
$class[] = 'subtype-' . $subtype;
return implode(' ', $class);
}
- /**
- * Clear Horde's folder cache. See Kolab_List::singleton().
- */
- private function clear_folders_cache()
- {
- unset($_SESSION['horde_session_objects']['kolab_folderlist']);
- }
-
/**
* Creates default folders if they doesn't exist
*/
- private function create_default_folders(&$folderdata, $cache_key = null)
+ private function create_default_folders(&$folders, $filter)
{
$storage = $this->rc->get_storage();
$namespace = $storage->get_namespace();
+ $folderdata = $storage->get_metadata('*', kolab_storage::CTYPE_KEY);
$defaults = array();
$need_update = false;
+ if (!is_array($folderdata)) {
+ return;
+ }
+
+ // "Flattenize" metadata array to become a name->type hash
+ $folderdata = array_map('implode', $folderdata);
+
// Find personal namespace prefix
if (is_array($namespace['personal']) && count($namespace['personal']) == 1) {
$prefix = $namespace['personal'][0][0];
}
else {
$prefix = '';
}
$this->load_config();
// get configured defaults
foreach ($this->types as $type) {
$subtypes = $type == 'mail' ? $this->mail_types : array('default');
foreach ($subtypes as $subtype) {
$opt_name = 'kolab_folders_' . $type . '_' . $subtype;
if ($folder = $this->rc->config->get($opt_name)) {
// convert configuration value to UTF7-IMAP charset
$folder = rcube_charset::convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');
// and namespace prefix if needed
if ($prefix && strpos($folder, $prefix) === false && $folder != 'INBOX') {
$folder = $prefix . $folder;
}
$defaults[$type . '.' . $subtype] = $folder;
}
}
}
// find default folders
foreach ($defaults as $type => $foldername) {
// folder exists, do nothing
if (!empty($folderdata[$foldername])) {
continue;
}
// special case, need to set type only
if ($foldername == 'INBOX' || $type == 'mail.inbox') {
$this->set_folder_type($foldername, 'mail.inbox');
continue;
}
// get all folders of specified type
- $folders = array_intersect($folderdata, array($type));
+ $folders = array_intersect($folderdata, array($type));
unset($folders[0]);
// find folders in personal namespace
foreach ($folders as $folder) {
if ($folder) {
foreach (array('shared', 'other') as $nskey) {
if (!empty($namespace[$nskey])) {
foreach ($namespace[$nskey] as $ns) {
if ($ns[0] && substr($folder, 0, strlen($ns[0])) == $ns[0]) {
continue 3;
}
}
}
}
}
// got folder in personal namespace
continue 2;
}
list($type1, $type2) = explode('.', $type);
// create folder
if ($type1 != 'mail' || !$storage->folder_exists($foldername)) {
$storage->create_folder($foldername, $type1 == 'mail');
}
// set type
$result = $this->set_folder_type($foldername, $type);
// add new folder to the result
- if ($result) {
- $folderdata[$foldername] = $type;
- $need_update = true;
+ if ($result && (!$filter || $filter == $type1)) {
+ $folders[] = $foldername;
}
}
-
- // update cache
- if ($need_update && $cache_key) {
- $storage->update_cache($cache_key, $folderdata);
- }
}
}
diff --git a/plugins/kolab_folders/package.xml b/plugins/kolab_folders/package.xml
index 8042ba25..875d6140 100644
--- a/plugins/kolab_folders/package.xml
+++ b/plugins/kolab_folders/package.xml
@@ -1,63 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
http://pear.php.net/dtd/tasks-1.0.xsd
http://pear.php.net/dtd/package-2.0
http://pear.php.net/dtd/package-2.0.xsd">
<name>kolab_folders</name>
<uri>http://git.kolab.org/roundcubemail-plugins-kolab/</uri>
<summary>Type-aware folder management/listing for Kolab</summary>
<description>
The plugin extends folders handling with features of the Kolab Suite
according to specified format (http://www.kolab.org/doc/kolabformat-2.0-html).
With this plugin enabled it is possible to:
- set/get/change folder's type,
- filter folders list by folder type,
- style folders list rows (in folder manager),
- create default folders with specified type.
</description>
<lead>
<name>Aleksander Machniak</name>
<user>machniak</user>
<email>machniak@kolabsys.com</email>
<active>yes</active>
</lead>
- <date>2011-11-01</date>
+ <date>2012-05-14</date>
<version>
- <release>1.0</release>
- <api>1.0</api>
+ <release>2.0</release>
+ <api>2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://www.gnu.org/licenses/agpl.html">GNU AGPLv3</license>
<notes>-</notes>
<contents>
<dir baseinstalldir="/" name="/">
<file name="kolab_folders.php" role="php">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="kolab_folders.js" role="data">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="config.inc.php.dist" role="data"></file>
<file name="localization/en_US.inc" role="data"></file>
<file name="localization/pl_PL.inc" role="data"></file>
<file name="LICENSE" role="data"></file>
</dir>
<!-- / -->
</contents>
<dependencies>
<required>
<php>
<min>5.2.1</min>
</php>
<pearinstaller>
<min>1.7.0</min>
</pearinstaller>
</required>
</dependencies>
<phprelease />
</package>
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index 175bb027..43f9c720 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -1,378 +1,456 @@
<?php
/**
* Kolab storage class providing static methods to access groupware objects on a Kolab server.
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*/
class kolab_storage
{
const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
const SERVERSIDE_SUBSCRIPTION = 0;
const CLIENTSIDE_SUBSCRIPTION = 1;
public static $last_error;
private static $ready = false;
private static $config;
private static $cache;
private static $imap;
/**
* Setup the environment needed by the libs
*/
public static function setup()
{
if (self::$ready)
return true;
$rcmail = rcube::get_instance();
self::$config = $rcmail->config;
self::$imap = $rcmail->get_storage();
self::$ready = class_exists('kolabformat') &&
(self::$imap->get_capability('METADATA') || self::$imap->get_capability('ANNOTATEMORE') || self::$imap->get_capability('ANNOTATEMORE2'));
if (self::$ready) {
// set imap options
self::$imap->set_options(array(
'skip_deleted' => true,
'threading' => false,
));
self::$imap->set_pagesize(9999);
}
return self::$ready;
}
/**
* Get a list of storage folders for the given data type
*
* @param string Data type to list folders for (contact,distribution-list,event,task,note)
*
* @return array List of Kolab_Folder objects (folder names in UTF7-IMAP)
*/
public static function get_folders($type)
{
$folders = array();
if (self::setup()) {
- foreach ((array)self::$imap->list_folders('', '*', $type) as $foldername) {
+ foreach ((array)self::list_folders('', '*', $type) as $foldername) {
$folders[$foldername] = new kolab_storage_folder($foldername, self::$imap);
}
}
return $folders;
}
/**
* Getter for a specific storage folder
*
* @param string IMAP folder to access (UTF7-IMAP)
* @return object kolab_storage_folder The folder object
*/
public static function get_folder($folder)
{
return self::setup() ? new kolab_storage_folder($folder, self::$imap) : null;
}
/**
* Getter for a single Kolab object, identified by its UID.
* This will search all folders storing objects of the given type.
*
* @param string Object UID
* @param string Object type (contact,distribution-list,event,task,note)
* @return array The Kolab object represented as hash array or false if not found
*/
public static function get_object($uid, $type)
{
self::setup();
$folder = null;
- foreach ((array)self::$imap->list_folders('', '*', $type) as $foldername) {
+ foreach ((array)self::list_folders('', '*', $type) as $foldername) {
if (!$folder)
$folder = new kolab_storage_folder($foldername, self::$imap);
else
$folder->set_folder($foldername);
if ($object = $folder->get_object($uid))
return $object;
}
return false;
}
/**
*
*/
public static function get_freebusy_server()
{
return unslashify(self::$config->get('kolab_freebusy_server', 'https://' . $_SESSION['imap_host'] . '/freebusy'));
}
/**
* Compose an URL to query the free/busy status for the given user
*/
public static function get_freebusy_url($email)
{
return self::get_freebusy_server() . '/' . $email . '.ifb';
}
/**
* Creates folder ID from folder name
*
* @param string $folder Folder name (UTF7-IMAP)
*
* @return string Folder ID string
*/
public static function folder_id($folder)
{
return asciiwords(strtr($folder, '/.-', '___'));
}
/**
* Deletes IMAP folder
*
* @param string $name Folder name (UTF7-IMAP)
*
* @return bool True on success, false on failure
*/
public static function folder_delete($name)
{
self::setup();
$success = self::$imap->delete_folder($name);
self::$last_error = self::$imap->get_error_str();
return $success;
}
/**
* Creates IMAP folder
*
* @param string $name Folder name (UTF7-IMAP)
* @param string $type Folder type
* @param bool $default True if older is default (for specified type)
*
* @return bool True on success, false on failure
*/
public static function folder_create($name, $type=null, $default=false)
{
self::setup();
if (self::$imap->create_folder($name)) {
// set metadata for folder type
$ctype = $type . ($default ? '.default' : '');
$saved = self::$imap->set_metadata($name, array(self::CTYPE_KEY => $ctype));
if ($saved)
return true;
else // revert if metadata could not be set
self::$imap->delete_folder($name);
}
self::$last_error = self::$imap->get_error_str();
return false;
}
/**
* Renames IMAP folder
*
* @param string $oldname Old folder name (UTF7-IMAP)
* @param string $newname New folder name (UTF7-IMAP)
*
* @return bool True on success, false on failure
*/
public static function folder_rename($oldname, $newname)
{
self::setup();
$success = self::$imap->rename_folder($oldname, $newname);
self::$last_error = self::$imap->get_error_str();
return $success;
}
/**
* 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_name($folder, &$folder_ns=null)
{
self::setup();
$found = false;
$namespace = self::$imap->get_namespace();
if (!empty($namespace['shared'])) {
foreach ($namespace['shared'] as $ns) {
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
$prefix = '';
$folder = substr($folder, strlen($ns[0]));
$delim = $ns[1];
$found = true;
$folder_ns = 'shared';
break;
}
}
}
if (!$found && !empty($namespace['other'])) {
foreach ($namespace['other'] as $ns) {
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
// remove namespace prefix
$folder = substr($folder, strlen($ns[0]));
$delim = $ns[1];
// get username
$pos = strpos($folder, $delim);
if ($pos) {
$prefix = '('.substr($folder, 0, $pos).') ';
$folder = substr($folder, $pos+1);
}
else {
$prefix = '('.$folder.')';
$folder = '';
}
$found = true;
$folder_ns = 'other';
break;
}
}
}
if (!$found && !empty($namespace['personal'])) {
foreach ($namespace['personal'] as $ns) {
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
// remove namespace prefix
$folder = substr($folder, strlen($ns[0]));
$prefix = '';
$delim = $ns[1];
$found = true;
break;
}
}
}
if (empty($delim))
$delim = self::$imap->get_hierarchy_delimiter();
$folder = rcube_charset::convert($folder, 'UTF7-IMAP');
$folder = str_replace($delim, ' &raquo; ', $folder);
if ($prefix)
$folder = $prefix . ' ' . $folder;
if (!$folder_ns)
$folder_ns = 'personal';
return $folder;
}
/**
* Creates a SELECT field with folders list
*
* @param string $type Folder type
* @param array $attrs SELECT field attributes (e.g. name)
* @param string $current The name of current folder (to skip it)
*
* @return html_select SELECT object
*/
public static function folder_selector($type, $attrs, $current = '')
{
// get all folders of specified type
$folders = self::get_folders($type);
$delim = self::$imap->get_hierarchy_delimiter();
$names = array();
$len = strlen($current);
if ($len && ($rpos = strrpos($current, $delim))) {
$parent = substr($current, 0, $rpos);
$p_len = strlen($parent);
}
// Filter folders list
foreach ($folders as $c_folder) {
$name = $c_folder->name;
// skip current folder and it's subfolders
if ($len && ($name == $current || strpos($name, $current.$delim) === 0)) {
continue;
}
// always show the parent of current folder
if ($p_len && $name == $parent) { }
// skip folders where user have no rights to create subfolders
else if ($c_folder->get_owner() != $_SESSION['username']) {
$rights = $c_folder->get_myrights();
if (!preg_match('/[ck]/', $rights)) {
continue;
}
}
$names[$name] = rcube_charset::convert($name, 'UTF7-IMAP');
}
// Make sure parent folder is listed (might be skipped e.g. if it's namespace root)
if ($p_len && !isset($names[$parent])) {
$names[$parent] = rcube_charset::convert($parent, 'UTF7-IMAP');
}
// Sort folders list
asort($names, SORT_LOCALE_STRING);
$folders = array_keys($names);
$names = array();
// Build SELECT field of parent folder
$select = new html_select($attrs);
$select->add('---', '');
foreach ($folders as $name) {
$imap_name = $name;
$name = $origname = self::object_name($name);
// find folder prefix to truncate
for ($i = count($names)-1; $i >= 0; $i--) {
if (strpos($name, $names[$i].' &raquo; ') === 0) {
$length = strlen($names[$i].' &raquo; ');
$prefix = substr($name, 0, $length);
$count = count(explode(' &raquo; ', $prefix));
$name = str_repeat('&nbsp;&nbsp;', $count-1) . '&raquo; ' . substr($name, $length);
break;
}
}
$names[] = $origname;
$select->add($name, $imap_name);
}
return $select;
}
+
+
+ /**
+ * Returns a list of folder names
+ *
+ * @param string Optional root folder
+ * @param string Optional name pattern
+ * @param string Data type to list folders for (contact,distribution-list,event,task,note,mail)
+ * @param string Enable to return subscribed folders only
+ *
+ * @return array List of folders
+ */
+ public static function list_folders($root = '', $mbox = '*', $filter = null, $subscribed = false)
+ {
+ if (!self::setup()) {
+ return null;
+ }
+
+ if (!$filter) {
+ // Get ALL folders list, standard way
+ if ($subscribed) {
+ return self::$imap->list_folders_subscribed($root, $mbox);
+ }
+ else {
+ return self::$imap->list_folders($root, $mbox);
+ }
+ }
+
+ $prefix = $root . $mbox;
+
+ // get folders types
+ $folderdata = self::$imap->get_metadata($prefix, self::CTYPE_KEY);
+
+ if (!is_array($folderdata)) {
+ return array();
+ }
+
+ $regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
+
+ // In some conditions we can skip LIST command (?)
+ if ($subscribed == false && $filter != 'mail' && $prefix == '*') {
+ foreach ($folderdata as $idx => $folder) {
+ $type = $folder[self::CTYPE_KEY];
+ if (!preg_match($regexp, $type)) {
+ unset($folderdata[$idx]);
+ }
+ }
+ return array_keys($folderdata);
+ }
+
+ // Get folders list
+ if ($subscribed) {
+ $folders = self::$imap->list_folders_subscribed_direct($root, $mbox);
+ }
+ else {
+ $folders = self::$imap->list_folders_direct($root, $mbox);
+ }
+
+ // In case of an error, return empty list (?)
+ if (!is_array($folders)) {
+ return array();
+ }
+
+ // Filter folders list
+ foreach ($folders as $idx => $folder) {
+ $type = !empty($folderdata[$folder]) ? $folderdata[$folder][self::CTYPE_KEY] : null;
+
+ if ($filter == 'mail' && empty($type)) {
+ continue;
+ }
+ if (empty($type) || !preg_match($regexp, $type)) {
+ unset($folders[$idx]);
+ }
+ }
+
+ return $folders;
+ }
+
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Aug 17, 6:12 PM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1257459
Default Alt Text
(41 KB)

Event Timeline