Use client-side subscriptions for folders activation state (calendar, tasklist)

Add kolab_use_subscriptions option to limit folders visibility in Kolab plugins (#1314)
This commit is contained in:
Aleksander Machniak 2012-12-10 12:17:41 +01:00
parent 89de2f226e
commit 56abf7e5f3
8 changed files with 246 additions and 72 deletions

View file

@ -127,7 +127,7 @@ class kolab_driver extends calendar_driver
'showalarms' => $cal->alarms, 'showalarms' => $cal->alarms,
'class_name' => $cal->get_namespace(), 'class_name' => $cal->get_namespace(),
'default' => $cal->storage->default, 'default' => $cal->storage->default,
'active' => $cal->storage->is_subscribed(), 'active' => $cal->storage->is_active(),
); );
} }
@ -154,7 +154,7 @@ class kolab_driver extends calendar_driver
if ($writeable && $cal->readonly) { if ($writeable && $cal->readonly) {
continue; continue;
} }
if ($active && !$cal->storage->is_subscribed()) { if ($active && !$cal->storage->is_active()) {
continue; continue;
} }
if ($personal && $cal->get_namespace() != 'personal') { if ($personal && $cal->get_namespace() != 'personal') {
@ -177,7 +177,6 @@ class kolab_driver extends calendar_driver
public function create_calendar($prop) public function create_calendar($prop)
{ {
$prop['type'] = 'event'; $prop['type'] = 'event';
$prop['subscribed'] = $prop['active'] ? kolab_storage::SERVERSIDE_SUBSCRIPTION : null;
$folder = kolab_storage::folder_update($prop); $folder = kolab_storage::folder_update($prop);
if ($folder === false) { if ($folder === false) {
@ -249,7 +248,7 @@ class kolab_driver extends calendar_driver
public function subscribe_calendar($prop) public function subscribe_calendar($prop)
{ {
if ($prop['id'] && ($cal = $this->calendars[$prop['id']])) { if ($prop['id'] && ($cal = $this->calendars[$prop['id']])) {
return $cal->storage->subscribe($prop['active'], kolab_storage::SERVERSIDE_SUBSCRIPTION); return $cal->storage->activate($prop['active']);
} }
return false; return false;

View file

@ -92,6 +92,7 @@ class kolab_delegation extends rcube_plugin
$delegators = $engine->list_delegators(); $delegators = $engine->list_delegators();
$other_ns = $storage->get_namespace('other'); $other_ns = $storage->get_namespace('other');
$folders = $storage->list_folders(); $folders = $storage->list_folders();
$use_subs = $this->rc->config->get('kolab_use_subscriptions');
$identities = $this->rc->user->list_identities(); $identities = $this->rc->user->list_identities();
$emails = array(); $emails = array();
$uids = array(); $uids = array();
@ -139,7 +140,16 @@ class kolab_delegation extends rcube_plugin
$prefix = $ns[0] . $delegator['imap_uid']; $prefix = $ns[0] . $delegator['imap_uid'];
// subscribe delegator's folder // subscribe delegator's folder
if ($folder === $prefix || strpos($folder, $prefix . substr($ns[0], -1)) === 0) { if ($folder === $prefix || strpos($folder, $prefix . substr($ns[0], -1)) === 0) {
$storage->subscribe($folder); // Event/Task folders need client-side activation
$type = kolab_storage::folder_type($folder);
if (preg_match('/^(event|task)/i', $type)) {
kolab_storage::folder_activate($folder);
}
// Subscribe to mail folders and (if system is configured
// to display only subscribed folders) to other
if ($use_subs || preg_match('/^mail/i', $type)) {
$storage->subscribe($folder);
}
} }
} }
} }

View file

@ -28,19 +28,5 @@ To do so, execute the SQL commands in SQL/<yourdatabase>.sql
CONFIGURATION CONFIGURATION
------------- -------------
The following options can be configured in Roundcube's main config file Rename config.inc.php.dist to config.inc.php in the plugin folder.
or a local config file (config.inc.php) located in the plugin folder. For available configuration options see config.inc.php.dist file.
// Enable caching of Kolab objects in local database
$rcmail_config['kolab_cache'] = true;
// Specify format version to write Kolab objects (must be a string value!)
$rcmail_config['kolab_format_version'] = '3.0';
// Optional override of the URL to read and trigger Free/Busy information of Kolab users
// Defaults to https://<imap-server->/freebusy
$rcmail_config['kolab_freebusy_server'] = 'https://<some-host>/<freebusy-path>';
// Set this option to disable SSL certificate checks when triggering Free/Busy (enabled by default)
$rcmail_config['kolab_ssl_verify_peer'] = false;

View file

@ -1,10 +1,22 @@
<?php <?php
/* Configuration for libkolab */
$rcmail_config['kolab_cache'] = true; /* Configuration for libkolab */
$rcmail_config['kolab_format_version'] = '3.0';
$rcmail_config['kolab_freebusy_server'] = 'https://' . $_SESSION['imap_host'] . '/freebusy'; // Enable caching of Kolab objects in local database
$rcmail_config['kolab_ssl_verify_peer'] = true; $rcmail_config['kolab_cache'] = true;
// Specify format version to write Kolab objects (must be a string value!)
$rcmail_config['kolab_format_version'] = '3.0';
// Optional override of the URL to read and trigger Free/Busy information of Kolab users
// Defaults to https://<imap-server->/freebusy
$rcmail_config['kolab_freebusy_server'] = 'https://<some-host>/<freebusy-path>';
// Set this option to disable SSL certificate checks when triggering Free/Busy (enabled by default)
$rcmail_config['kolab_ssl_verify_peer'] = false;
// Enables listing of only subscribed folders. This e.g. will limit
// folders in calendar view or available addressbooks
$rcmail_config['kolab_use_subscriptions'] = false;
?> ?>

View file

@ -5,6 +5,7 @@
* *
* @version @package_version@ * @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com> * @author Thomas Bruederli <bruederli@kolabsys.com>
* @author Aleksander Machniak <machniak@kolabsys.com>
* *
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com> * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
* *
@ -28,13 +29,13 @@ class kolab_storage
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 SERVERSIDE_SUBSCRIPTION = 0;
const CLIENTSIDE_SUBSCRIPTION = 1;
public static $version = '3.0'; public static $version = '3.0';
public static $last_error; public static $last_error;
private static $ready = false; private static $ready = false;
private static $subscriptions;
private static $states;
private static $config; private static $config;
private static $cache; private static $cache;
private static $imap; private static $imap;
@ -92,7 +93,7 @@ class kolab_storage
$folders = $folderdata = array(); $folders = $folderdata = array();
if (self::setup()) { if (self::setup()) {
foreach ((array)self::list_folders('', '*', $type, false, $folderdata) as $foldername) { foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
$folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]); $folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
} }
} }
@ -192,13 +193,14 @@ class kolab_storage
/** /**
* Creates IMAP folder * Creates IMAP folder
* *
* @param string $name Folder name (UTF7-IMAP) * @param string $name Folder name (UTF7-IMAP)
* @param string $type Folder type * @param string $type Folder type
* @param bool $subscribed Sets folder subscription * @param bool $subscribed Sets folder subscription
* @param bool $active Sets folder state (client-side subscription)
* *
* @return bool True on success, false on failure * @return bool True on success, false on failure
*/ */
public static function folder_create($name, $type = null, $subscribed = false) public static function folder_create($name, $type = null, $subscribed = false, $active = false)
{ {
self::setup(); self::setup();
@ -211,6 +213,10 @@ class kolab_storage
if (!$saved) { if (!$saved) {
self::$imap->delete_folder($name); self::$imap->delete_folder($name);
} }
// activate folder
else if ($active) {
self::set_state($name, true);
}
} }
} }
@ -222,6 +228,7 @@ class kolab_storage
return false; return false;
} }
/** /**
* Renames IMAP folder * Renames IMAP folder
* *
@ -247,10 +254,12 @@ class kolab_storage
* Does additional checks for permissions and folder name restrictions * Does additional checks for permissions and folder name restrictions
* *
* @param array Hash array with folder properties and metadata * @param array Hash array with folder properties and metadata
* - name: Folder name * - name: Folder name
* - oldname: Old folder name when changed * - oldname: Old folder name when changed
* - parent: Parent folder to create the new one in * - parent: Parent folder to create the new one in
* - type: Folder type to create * - type: Folder type to create
* - subscribed: Subscribed flag (IMAP subscription)
* - active: Activation flag (client-side subscription)
* @return mixed New folder name or False on failure * @return mixed New folder name or False on failure
*/ */
public static function folder_update(&$prop) public static function folder_update(&$prop)
@ -319,7 +328,7 @@ class kolab_storage
} }
// create new folder // create new folder
else { else {
$result = self::folder_create($folder, $prop['type'], $prop['subscribed'] === self::SERVERSIDE_SUBSCRIPTION); $result = self::folder_create($folder, $prop['type'], $prop['subscribed'], $prop['active']);
} }
// save color in METADATA // save color in METADATA
@ -532,17 +541,22 @@ class kolab_storage
* @param string Optional root folder * @param string Optional root folder
* @param string Optional name pattern * @param string Optional name pattern
* @param string Data type to list folders for (contact,distribution-list,event,task,note,mail) * @param string Data type to list folders for (contact,distribution-list,event,task,note,mail)
* @param string Enable to return subscribed folders only * @param boolean Enable to return subscribed folders only (null to use configured subscription mode)
* @param array Will be filled with folder-types data * @param array Will be filled with folder-types data
* *
* @return array List of folders * @return array List of folders
*/ */
public static function list_folders($root = '', $mbox = '*', $filter = null, $subscribed = false, &$folderdata = array()) public static function list_folders($root = '', $mbox = '*', $filter = null, $subscribed = null, &$folderdata = array())
{ {
if (!self::setup()) { if (!self::setup()) {
return null; return null;
} }
// use IMAP subscriptions
if ($subscribed === null && self::$config->get('kolab_use_subscriptions')) {
$subscribed = true;
}
if (!$filter) { if (!$filter) {
// Get ALL folders list, standard way // Get ALL folders list, standard way
if ($subscribed) { if ($subscribed) {
@ -566,7 +580,7 @@ class kolab_storage
$regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/'; $regexp = '/^' . preg_quote($filter, '/') . '(\..+)?$/';
// In some conditions we can skip LIST command (?) // In some conditions we can skip LIST command (?)
if ($subscribed == false && $filter != 'mail' && $prefix == '*') { if (!$subscribed && $filter != 'mail' && $prefix == '*') {
foreach ($folderdata as $folder => $type) { foreach ($folderdata as $folder => $type) {
if (!preg_match($regexp, $type)) { if (!preg_match($regexp, $type)) {
unset($folderdata[$folder]); unset($folderdata[$folder]);
@ -644,6 +658,7 @@ class kolab_storage
return 'mail'; return 'mail';
} }
/** /**
* Sets folder content-type. * Sets folder content-type.
* *
@ -665,4 +680,156 @@ class kolab_storage
return $success; return $success;
} }
/**
* Check subscription status of this folder
*
* @param string $folder Folder name
*
* @return boolean True if subscribed, false if not
*/
public static function folder_is_subscribed($folder)
{
if (self::$subscriptions === null) {
self::setup();
self::$subscriptions = self::$imap->list_folders_subscribed();
}
return in_array($folder, self::$subscriptions);
}
/**
* Change subscription status of this folder
*
* @param string $folder Folder name
*
* @return True on success, false on error
*/
public static function folder_subscribe($folder)
{
self::setup();
if (self::$imap->subscribe($folder)) {
self::$subscriptions === null;
return true;
}
return false;
}
/**
* Change subscription status of this folder
*
* @param string $folder Folder name
*
* @return True on success, false on error
*/
public static function folder_unsubscribe($folder)
{
self::setup();
if (self::$imap->unsubscribe($folder)) {
self::$subscriptions === null;
return true;
}
return false;
}
/**
* Check activation status of this folder
*
* @param string $folder Folder name
*
* @return boolean True if active, false if not
*/
public static function folder_is_active($folder)
{
$active_folders = self::get_states();
return in_array($folder, $active_folders);
}
/**
* Change activation status of this folder
*
* @param string $folder Folder name
*
* @return True on success, false on error
*/
public static function folder_activate($folder)
{
return self::set_state($folder, true);
}
/**
* Change activation status of this folder
*
* @param string $folder Folder name
*
* @return True on success, false on error
*/
public static function folder_deactivate($folder)
{
return self::set_state($folder, false);
}
/**
* Return list of active folders
*/
private static function get_states()
{
if (self::$states !== null) {
return self::$states;
}
$rcube = rcube::get_instance();
$folders = $rcube->config->get('kolab_active_folders');
if ($folders !== null) {
self::$states = !empty($folders) ? explode('**', $folders) : array();
}
// for backward-compatibility copy server-side subscriptions to activation states
else {
self::setup();
if (self::$subscriptions === null) {
self::$subscriptions = self::$imap->list_folders_subscribed();
}
self::$states = self::$subscriptions;
$folders = implode(self::$states, '**');
$rcube->user->save_prefs(array('kolab_active_folders' => $folders));
}
return self::$states;
}
/**
* Update list of active folders
*/
private static function set_state($folder, $state)
{
self::get_states();
// update in-memory list
$idx = array_search($folder, self::$states);
if ($state && $idx === false) {
self::$states[] = $folder;
}
else if (!$state && $idx !== false) {
unset(self::$states[$idx]);
}
// update user preferences
$folders = implode(self::$states, '**');
$rcube = rcube::get_instance();
return $rcube->user->save_prefs(array('kolab_active_folders' => $folders));
}
} }

View file

@ -5,6 +5,7 @@
* *
* @version @package_version@ * @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com> * @author Thomas Bruederli <bruederli@kolabsys.com>
* @author Aleksander Machniak <machniak@kolabsys.com>
* *
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com> * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
* *
@ -235,47 +236,48 @@ class kolab_storage_folder
return $this->resource_uri; return $this->resource_uri;
} }
/**
* Check activation status of this folder
*
* @return boolean True if enabled, false if not
*/
public function is_active()
{
return kolab_storage::folder_is_active($this->name);
}
/**
* Change activation status of this folder
*
* @param boolean The desired subscription status: true = active, false = not active
*
* @return True on success, false on error
*/
public function activate($active)
{
return $active ? kolab_storage::folder_activate($this->name) : kolab_storage::folder_deactivate($this->name);
}
/** /**
* Check subscription status of this folder * Check subscription status of this folder
* *
* @param string Subscription type (kolab_storage::SERVERSIDE_SUBSCRIPTION or kolab_storage::CLIENTSIDE_SUBSCRIPTION)
* @return boolean True if subscribed, false if not * @return boolean True if subscribed, false if not
*/ */
public function is_subscribed($type = 0) public function is_subscribed()
{ {
static $subscribed; // local cache return kolab_storage::folder_is_subscribed($this->name);
if ($type == kolab_storage::SERVERSIDE_SUBSCRIPTION) {
if (!$subscribed)
$subscribed = $this->imap->list_folders_subscribed();
return in_array($this->name, $subscribed);
}
else if (kolab_storage::CLIENTSIDE_SUBSCRIPTION) {
// TODO: implement this
return true;
}
return false;
} }
/** /**
* Change subscription status of this folder * Change subscription status of this folder
* *
* @param boolean The desired subscription status: true = subscribed, false = not subscribed * @param boolean The desired subscription status: true = subscribed, false = not subscribed
* @param string Subscription type (kolab_storage::SERVERSIDE_SUBSCRIPTION or kolab_storage::CLIENTSIDE_SUBSCRIPTION) *
* @return True on success, false on error * @return True on success, false on error
*/ */
public function subscribe($subscribed, $type = 0) public function subscribe($subscribed)
{ {
if ($type == kolab_storage::SERVERSIDE_SUBSCRIPTION) { return $subscribed ? kolab_storage::folder_subscribe($this->name) : kolab_storage::folder_unsubscribe($this->name);
return $subscribed ? $this->imap->subscribe($this->name) : $this->imap->unsubscribe($this->name);
}
else {
// TODO: implement this
}
return false;
} }

View file

@ -59,6 +59,4 @@ class libkolab extends rcube_plugin
$p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE X-KOLAB-MIME-VERSION'); $p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE X-KOLAB-MIME-VERSION');
return $p; return $p;
} }
} }

View file

@ -119,7 +119,7 @@ class tasklist_kolab_driver extends tasklist_driver
'color' => $folder->get_color('0000CC'), 'color' => $folder->get_color('0000CC'),
'showalarms' => isset($prefs[$list_id]['showalarms']) ? $prefs[$list_id]['showalarms'] : $alarms, 'showalarms' => isset($prefs[$list_id]['showalarms']) ? $prefs[$list_id]['showalarms'] : $alarms,
'editable' => !$readonly, 'editable' => !$readonly,
'active' => $folder->is_subscribed(kolab_storage::SERVERSIDE_SUBSCRIPTION), 'active' => $folder->is_active(),
'parentfolder' => $path_imap, 'parentfolder' => $path_imap,
'default' => $folder->default, 'default' => $folder->default,
'class_name' => trim($folder->get_namespace() . ($folder->default ? ' default' : '')), 'class_name' => trim($folder->get_namespace() . ($folder->default ? ' default' : '')),
@ -155,7 +155,7 @@ class tasklist_kolab_driver extends tasklist_driver
public function create_list($prop) public function create_list($prop)
{ {
$prop['type'] = 'task' . ($prop['default'] ? '.default' : ''); $prop['type'] = 'task' . ($prop['default'] ? '.default' : '');
$prop['subscribed'] = kolab_storage::SERVERSIDE_SUBSCRIPTION; // subscribe to folder by default $prop['active'] = true; // activate folder by default
$folder = kolab_storage::folder_update($prop); $folder = kolab_storage::folder_update($prop);
if ($folder === false) { if ($folder === false) {
@ -229,7 +229,7 @@ class tasklist_kolab_driver extends tasklist_driver
public function subscribe_list($prop) public function subscribe_list($prop)
{ {
if ($prop['id'] && ($folder = $this->folders[$prop['id']])) { if ($prop['id'] && ($folder = $this->folders[$prop['id']])) {
return $folder->subscribe($prop['active'], kolab_storage::SERVERSIDE_SUBSCRIPTION); return $folder->activate($prop['active']);
} }
return false; return false;
} }