Search in LDAP and collect accessible folders (#3041)

- Add LDAP user search capabilities to kolab_storage class (using kolab_auth plugin classes)
- Introduce virtual 'user' folder objects and add methods to list them
- New 'user calendar' class in calendar (kolab driver)
- Render folder search results as hierarchical list
This commit is contained in:
Thomas Bruederli 2014-05-14 20:37:06 +02:00
parent 8a47c676d5
commit 701c3391fe
11 changed files with 726 additions and 109 deletions

View file

@ -2739,7 +2739,9 @@ function rcube_calendar_ui(settings)
selectable: true,
save_state: true,
searchbox: '#calendarlistsearch',
search_action: 'calendar/calendar'
search_action: 'calendar/calendar',
search_sources: [ 'folders', 'users' ],
search_title: rcmail.gettext('calsearchresults','calendar')
});
calendars_list.addEventListener('select', function(node) {
me.select_calendar(node.id);

View file

@ -7,7 +7,7 @@
* @author Thomas Bruederli <bruederli@kolabsys.com>
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
* Copyright (C) 2012-2014, 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
@ -35,11 +35,30 @@ class kolab_calendar
public $storage;
public $name;
private $cal;
private $events = array();
private $imap_folder = 'INBOX/Calendar';
private $search_fields = array('title', 'description', 'location', 'attendees');
protected $cal;
protected $events = array();
protected $imap_folder = 'INBOX/Calendar';
protected $search_fields = array('title', 'description', 'location', 'attendees');
/**
* Factory method to instantiate a kolab_calendar object
*
* @param string Calendar ID (encoded IMAP folder name)
* @param object calendar plugin object
* @return object kolab_calendar instance
*/
public static function factory($id, $calendar)
{
$imap = $calendar->rc->get_storage();
$imap_folder = kolab_storage::id_decode($id);
$info = $imap->folder_info($imap_folder, true);
if (empty($info) || $info['noselect'] || kolab_storage::folder_type($imap_folder) != 'event') {
return new kolab_user_calendar($imap_folder, $calendar);
}
else {
return new kolab_calendar($imap_folder, $calendar);
}
}
/**
* Default constructor
@ -177,14 +196,6 @@ class kolab_calendar
return false;
}
/**
* Return the corresponding kolab_storage_folder instance
*/
public function get_folder()
{
return $this->storage;
}
/**
* Getter for a single event object

View file

@ -24,6 +24,7 @@
*/
require_once(dirname(__FILE__) . '/kolab_calendar.php');
require_once(dirname(__FILE__) . '/kolab_user_calendar.php');
class kolab_driver extends calendar_driver
{
@ -78,14 +79,20 @@ class kolab_driver extends calendar_driver
return $this->calendars;
// get all folders that have "event" type, sorted by namespace/name
$folders = kolab_storage::sort_folders(kolab_storage::get_folders('event'));
$folders = kolab_storage::sort_folders(kolab_storage::get_folders('event') + kolab_storage::get_user_folders(true));
$this->calendars = array();
foreach ($folders as $folder) {
$calendar = new kolab_calendar($folder->name, $this->cal);
$this->calendars[$calendar->id] = $calendar;
if (!$calendar->readonly)
$this->has_writeable = true;
if ($folder instanceof kolab_storage_user_folder)
$calendar = new kolab_user_calendar($folder->name, $this->cal);
else
$calendar = new kolab_calendar($folder->name, $this->cal);
if ($calendar->ready) {
$this->calendars[$calendar->id] = $calendar;
if (!$calendar->readonly)
$this->has_writeable = true;
}
}
return $this->calendars;
@ -114,18 +121,32 @@ class kolab_driver extends calendar_driver
$calendars = $names = array();
// include virtual folders for a full folder tree
if (!$active && !$personal && !$this->rc->output->ajax_call && in_array($this->rc->action, array('index','')))
if (!is_null($tree))
$folders = kolab_storage::folder_hierarchy($folders, $tree);
foreach ($folders as $id => $cal) {
$fullname = $cal->get_name();
$listname = kolab_storage::folder_displayname($fullname, $names);
$listname = $cal->get_foldername();
$imap_path = explode('/', $cal->name);
$topname = array_pop($imap_path);
$parent_id = kolab_storage::folder_id(join('/', $imap_path), true);
// special handling for virtual folders
if ($cal->virtual) {
// special handling for user or virtual folders
if ($cal instanceof kolab_storage_user_folder) {
$calendars[$cal->id] = array(
'id' => $cal->id,
'name' => kolab_storage::object_name($fullname),
'listname' => $listname,
'editname' => $cal->get_foldername(),
'color' => $cal->get_color(),
'active' => $cal->is_active(),
'owner' => $cal->get_owner(),
'virtual' => false,
'readonly' => true,
'class_name' => 'user',
);
}
else if ($cal->virtual) {
$calendars[$cal->id] = array(
'id' => $cal->id,
'name' => $fullname,
@ -230,8 +251,8 @@ class kolab_driver extends calendar_driver
{
// create calendar object if necesary
if (!$this->calendars[$id] && $id !== self::BIRTHDAY_CALENDAR_ID) {
$foldername = kolab_storage::id_decode($id);
$calendar = new kolab_calendar($foldername, $this->cal);
$calendar = kolab_calendar::factory($id, $this->cal);
console($id, $calendar->id, $calendar->ready);
if ($calendar->ready)
$this->calendars[$calendar->id] = $calendar;
}
@ -389,8 +410,20 @@ class kolab_driver extends calendar_driver
$this->calendars[$calendar->id] = $calendar;
}
}
// find other user's virtual calendars
else if ($source == 'users') {
// TODO: implement this
foreach (kolab_storage::search_users($query, 0) as $user) {
$calendar = new kolab_user_calendar($user, $this->cal);
$this->calendars[$calendar->id] = $calendar;
// search for calendar folders shared by this user
foreach (kolab_storage::list_user_folders($user, 'event', false) as $foldername) {
if (1 || !kolab_storage::folder_is_subscribed($foldername, true)) {
$cal = new kolab_calendar($foldername, $this->cal);
$this->calendars[$cal->id] = $cal;
}
}
}
}
// don't list the birthday calendar

View file

@ -0,0 +1,219 @@
<?php
/**
* Kolab calendar storage class simulating a virtual user calendar
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2014, 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_user_calendar extends kolab_calendar
{
public $id = 'unknown';
public $ready = false;
public $readonly = true;
public $attachments = false;
public $name;
protected $userdata = array();
/**
* Default constructor
*/
public function __construct($user_or_folder, $calendar)
{
$this->cal = $calendar;
// full user record is provided
if (is_array($user_or_folder)) {
$this->userdata = $user_or_folder;
$this->storage = new kolab_storage_user_folder($this->userdata['kolabtargetfolder'], '', $this->userdata);
}
else { // get user record from LDAP
$this->storage = new kolab_storage_user_folder($user_or_folder);
$this->userdata = $this->storage->ldaprec;
}
$this->ready = !empty($this->userdata['kolabtargetfolder']);
if ($this->ready) {
// ID is derrived from the user's kolabtargetfolder attribute
$this->id = kolab_storage::folder_id($this->userdata['kolabtargetfolder'], true);
$this->imap_folder = $this->userdata['kolabtargetfolder'];
$this->name = $this->storage->get_name();
// user-specific alarms settings win
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
if (isset($prefs[$this->id]['showalarms']))
$this->alarms = $prefs[$this->id]['showalarms'];
}
}
/**
* Getter for a nice and human readable name for this calendar
*
* @return string Name of this calendar
*/
public function get_name()
{
return $this->userdata['name'] ?: $this->userdata['mail'];
}
/**
* Getter for the IMAP folder owner
*
* @return string Name of the folder owner
*/
public function get_owner()
{
return $this->userdata['mail'];
}
/**
* Getter for the name of the namespace to which the IMAP folder belongs
*
* @return string Name of the namespace (personal, other, shared)
*/
public function get_namespace()
{
return 'user';
}
/**
* Getter for the top-end calendar folder name (not the entire path)
*
* @return string Name of this calendar
*/
public function get_foldername()
{
return $this->get_name();
}
/**
* Return color to display this calendar
*/
public function get_color()
{
// calendar color is stored in local user prefs
$prefs = $this->cal->rc->config->get('kolab_calendars', array());
if (!empty($prefs[$this->id]) && !empty($prefs[$this->id]['color']))
return $prefs[$this->id]['color'];
return 'cc0000';
}
/**
* Compose an URL for CalDAV access to this calendar (if configured)
*/
public function get_caldav_url()
{
return false;
}
/**
* Getter for a single event object
*/
public function get_event($id)
{
// TODO: implement this
return $this->events[$id];
}
/**
* @param integer Event's new start (unix timestamp)
* @param integer Event's new end (unix timestamp)
* @param string Search query (optional)
* @param boolean Include virtual events (optional)
* @param array Additional parameters to query storage
* @return array A list of event records
*/
public function list_events($start, $end, $search = null, $virtual = 1, $query = array())
{
// TODO: implement this
console('kolab_user_calendar::list_events()');
return array();
}
/**
* Create a new event record
*
* @see calendar_driver::new_event()
*
* @return mixed The created record ID on success, False on error
*/
public function insert_event($event)
{
return false;
}
/**
* Update a specific event record
*
* @see calendar_driver::new_event()
* @return boolean True on success, False on error
*/
public function update_event($event, $exception_id = null)
{
return false;
}
/**
* Delete an event record
*
* @see calendar_driver::remove_event()
* @return boolean True on success, False on error
*/
public function delete_event($event, $force = true)
{
return false;
}
/**
* Restore deleted event record
*
* @see calendar_driver::undelete_event()
* @return boolean True on success, False on error
*/
public function restore_event($event)
{
return false;
}
/**
* Convert from Kolab_Format to internal representation
*/
private function _to_rcube_event($record)
{
$record['id'] = $record['uid'];
$record['calendar'] = $this->id;
// TODO: implement this
return $record;
}
}

View file

@ -205,6 +205,7 @@ class calendar_ui
{
$html = '';
$jsenv = array();
$tree = true;
$calendars = $this->cal->driver->list_calendars(false, false, $tree);
// walk folder tree
@ -273,19 +274,22 @@ class calendar_ui
*/
public function calendar_list_item($id, $prop, &$jsenv)
{
unset($prop['user_id']);
$prop['alarms'] = $this->cal->driver->alarms;
$prop['attendees'] = $this->cal->driver->attendees;
$prop['freebusy'] = $this->cal->driver->freebusy;
$prop['attachments'] = $this->cal->driver->attachments;
$prop['undelete'] = $this->cal->driver->undelete;
$prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed'));
// enrich calendar properties with settings from the driver
if (!$prop['virtual']) {
unset($prop['user_id']);
$prop['alarms'] = $this->cal->driver->alarms;
$prop['attendees'] = $this->cal->driver->attendees;
$prop['freebusy'] = $this->cal->driver->freebusy;
$prop['attachments'] = $this->cal->driver->attachments;
$prop['undelete'] = $this->cal->driver->undelete;
$prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed'));
if (!$prop['virtual'])
$jsenv[$id] = $prop;
}
$class = 'calendar cal-' . asciiwords($id, true);
$title = $prop['name'] != $prop['listname'] ? html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : '';
$title = $prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : '';
$is_collapsed = false; // TODO: determine this somehow?
if ($prop['virtual'])

View file

@ -269,12 +269,12 @@ pre {
#calendars .treelist div.readonly span.calname {
background-position: right -20px;
}
/*
#calendars .treelist div.other span.calname {
#calendars .treelist div.user span.calname {
background-position: right -38px;
}
#calendars .treelist div.other.readonly span.calname {
/*
#calendars .treelist div.user.readonly span.calname {
background-position: right -56px;
}

View file

@ -213,7 +213,6 @@ class kolab_auth_ldap extends rcube_ldap_generic
* 0 - partial (*abc*),
* 1 - strict (=),
* 2 - prefix (abc*)
* @param boolean $select True if results are requested, False if count only
* @param array $required List of fields that cannot be empty
* @param int $limit Number of records
*

View file

@ -46,7 +46,7 @@ function kolab_folderlist(node, p)
// create treelist widget to present the search results
if (!search_results_widget) {
search_results_container = $('<div class="searchresults"></div>')
.html('<h2 class="boxtitle">' + rcmail.gettext('calsearchresults','calendar') + '</h2>')
.html(p.search_title ? '<h2 class="boxtitle">' + p.search_title + '</h2>' : '')
.insertAfter(me.container);
search_results_widget = new rcube_treelist_widget('<ul class="treelist listing"></ul>', {
@ -63,36 +63,64 @@ function kolab_folderlist(node, p)
var li = $(this).closest('li'),
id = li.attr('id').replace(new RegExp('^'+p.id_prefix), ''),
node = search_results_widget.get_node(id),
prop = search_results[id],
parent_id = prop.parent || null;
parent_id = prop.parent || null,
has_children = node.children && node.children.length,
dom_node = has_children ? li.children().first().clone(true, true) : li.children().first();
// find parent node and insert at the right place
if (parent_id && $('#' + p.id_prefix + parent_id, me.container).length) {
prop.listname = prop.editname;
li.children().first().children('span,a').first().html(Q(prop.listname));
dom_node.children('span,a').first().html(Q(prop.listname));
}
// move this result item to the main list widget
me.insert({
id: id,
classes: [],
html: li.children().first()
}, parent_id, parent_id ? true : false);
// TODO: copy parent tree too
// replace virtual node with a real one
if (me.get_node(id)) {
$(me.get_item(id, true)).children().first()
.replaceWith(dom_node)
.removeClass('virtual');
}
else {
// move this result item to the main list widget
me.insert({
id: id,
classes: [],
virtual: prop.virtual,
html: dom_node,
}, parent_id, parent_id ? true : false);
}
delete prop.html;
me.triggerEvent('insert-item', { id: id, data: prop, item: li });
li.remove();
if (has_children) {
li.find('input[type=checkbox]').first().prop('disabled', true).get(0).checked = true;
}
else {
li.remove();
}
});
}
// add results to list
for (var prop, i=0; i < results.length; i++) {
for (var prop, item, i=0; i < results.length; i++) {
prop = results[i];
item = $(prop.html);
search_results[prop.id] = prop;
$('<li>')
.attr('id', p.id_prefix + prop.id)
.html(prop.html)
.appendTo(search_results_widget.container);
search_results_widget.insert({
id: prop.id,
classes: prop.class_name ? String(prop.class_name).split(' ') : [],
html: item,
collapsed: true
}, prop.parent);
// disable checkbox if item already exists in main list
if (me.get_node(prop.id) && !me.get_node(prop.id).virtual) {
item.find('input[type=checkbox]').first().prop('disabled', true).get(0).checked = true;
}
}
search_results_container.show();
@ -110,7 +138,7 @@ function kolab_folderlist(node, p)
// send search request(s) to server
if (search.query && search.execute) {
var sources = [ 'folders' /*, 'users'*/ ];
var sources = p.search_sources || [ 'folders' ];
var reqid = rcmail.multi_thread_http_request({
items: sources,
threads: rcmail.env.autocomplete_threads || 1,

View file

@ -44,6 +44,7 @@ class kolab_storage
private static $states;
private static $config;
private static $imap;
private static $ldap;
// Default folder names
private static $default_folders = array(
@ -101,6 +102,40 @@ class kolab_storage
return self::$ready;
}
/**
* Initializes LDAP object to resolve Kolab users
*/
public static function ldap()
{
if (self::$ldap) {
return self::$ldap;
}
$rcmail = rcube::get_instance();
$config = $rcmail->config->get('kolab_users_directory', $rcmail->config->get('kolab_auth_addressbook'));
if (!is_array($config)) {
$ldap_config = (array)$rcmail->config->get('ldap_public');
$config = $ldap_config[$config];
}
if (empty($config)) {
return null;
}
// overwrite filter option
if ($filter = $rcmail->config->get('kolab_users_filter')) {
$rcmail->config->set('kolab_auth_filter', $filter);
}
// re-use the LDAP wrapper class from kolab_auth plugin
require_once rtrim(RCUBE_PLUGINS_DIR, '/') . '/kolab_auth/kolab_auth_ldap.php';
self::$ldap = new kolab_auth_ldap($config);
return self::$ldap;
}
/**
* Get a list of storage folders for the given data type
@ -490,7 +525,7 @@ class kolab_storage
$folder = substr($folder, $pos+1);
}
else {
$prefix = $folder;
$prefix = '('.$folder.')';
$folder = '';
}
@ -811,7 +846,7 @@ class kolab_storage
// $folders is a result of get_folders() we can assume folders were already sorted
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) {
$out[] = $folders[$utf7name];
}
@ -829,13 +864,18 @@ class kolab_storage
*
* @return array Flat folders list
*/
public static function folder_hierarchy($folders, &$tree)
public static function folder_hierarchy($folders, &$tree = null)
{
$_folders = array();
$delim = rcube::get_instance()->get_storage()->get_hierarchy_delimiter();
$tree = new virtual_kolab_storage_folder('', '<root>', ''); // create tree root
$delim = self::$imap->get_hierarchy_delimiter();
$other_ns = self::$imap->get_namespace('other');
$tree = new kolab_storage_virtual_folder('', '<root>', ''); // create tree root
$refs = array('' => $tree);
if (is_array($other_ns)) {
$other_ns = rtrim($other_ns[0][0], '/');
}
foreach ($folders as $idx => $folder) {
$path = explode($delim, $folder->name);
array_pop($path);
@ -852,9 +892,15 @@ class kolab_storage
while (count($path) >= $depth && ($parent = join($delim, $path))) {
array_pop($path);
$name = kolab_storage::object_name($parent, $folder->get_namespace());
$parent_parent = join($delim, $path);
if (!$refs[$parent]) {
$refs[$parent] = new virtual_kolab_storage_folder($parent, $name, $folder->get_namespace(), join($delim, $path));
if ($parent_parent == $other_ns) {
$refs[$parent] = new kolab_storage_user_folder($parent, $parent_parent);
}
else {
$name = kolab_storage::object_name($parent, $folder->get_namespace());
$refs[$parent] = new kolab_storage_virtual_folder($parent, $name, $folder->get_namespace(), $parent_parent);
}
$parents[] = $refs[$parent];
}
}
@ -1023,14 +1069,22 @@ class kolab_storage
* Change subscription status of this folder
*
* @param string $folder Folder name
* @param boolean $temp Only remove temporary subscription
*
* @return True on success, false on error
*/
public static function folder_unsubscribe($folder)
public static function folder_unsubscribe($folder, $temp = false)
{
self::setup();
if (self::$imap->unsubscribe($folder)) {
// temporary/session subscription
if ($temp) {
if (is_array($_SESSION['kolab_subscribed_folders']) && ($i = array_search($folder, $_SESSION['kolab_subscribed_folders'])) !== false) {
unset($_SESSION['kolab_subscribed_folders'][$i]);
}
return true;
}
else if (self::$imap->unsubscribe($folder)) {
self::$subscriptions === null;
return true;
}
@ -1078,10 +1132,8 @@ class kolab_storage
*/
public static function folder_deactivate($folder)
{
// remove from temp subscriptions
if (is_array($_SESSION['kolab_subscribed_folders']) && ($i = array_search($folder, $_SESSION['kolab_subscribed_folders'])) !== false) {
unset($_SESSION['kolab_subscribed_folders'][$i]);
}
// remove from temp subscriptions, really?
self::folder_unsubscribe($folder, true);
return self::set_state($folder, false);
}
@ -1241,6 +1293,106 @@ class kolab_storage
}
}
/**
*
* @param mixed $query Search value (or array of field => value pairs)
* @param int $mode Matching mode: 0 - partial (*abc*), 1 - strict (=), 2 - prefix (abc*)
* @param array $required List of fields that shall ot be empty
* @param int $limit Number of records
*
* @return array List or false on error
*/
public static function search_users($query, $mode = 1, $required = array(), $limit = 0)
{
// requires a working LDAP setup
if (!self::ldap()) {
return array();
}
// FIXME: make search attributes configurable
$results = self::$ldap->search(array('cn','mail','alias'), $query, $mode, $required, $limit);
// resolve to IMAP folder name
$other_ns = self::$imap->get_namespace('other');
$user_attrib = rcube::get_instance()->config->get('kolab_auth_login', 'mail');
array_walk($results, function(&$user, $dn) use ($other_ns, $user_attrib) {
list($localpart, $domain) = explode('@', $user[$user_attrib]);
$root = $other_ns[0][0];
$user['kolabtargetfolder'] = $root . $localpart;
});
return $results;
}
/**
* Returns a list of IMAP folders shared by the given user
*
* @param array User entry from LDAP
* @param string Data type to list folders for (contact,event,task,journal,file,note,mail,configuration)
* @param boolean Return subscribed folders only (null to use configured subscription mode)
* @param array Will be filled with folder-types data
*
* @return array List of folders
*/
public static function list_user_folders($user, $type, $subscribed = null, &$folderdata = array())
{
$folders = array();
// use localpart of user attribute as root for folder listing
$user_attrib = rcube::get_instance()->config->get('kolab_auth_login', 'mail');
if (!empty($user[$user_attrib])) {
list($mbox) = explode('@', $user[$user_attrib]);
$other_ns = self::$imap->get_namespace('other');
if (is_array($other_ns)) {
$other_ns = $other_ns[0][0];
}
$folders = self::list_folders($other_ns . $mbox, '*', $type, $subscribed, $folderdata);
}
return $folders;
}
/**
* Get a list of (virtual) top-level folders from the other users namespace
*
* @param boolean Enable to return subscribed folders only (null to use configured subscription mode)
*
* @return array List of Kolab_Folder objects (folder names in UTF7-IMAP)
*/
public static function get_user_folders($subscribed)
{
$folders = $folderdata = array();
if (self::setup()) {
$delimiter = self::$imap->get_hierarchy_delimiter();
$other_ns = self::$imap->get_namespace('other');
if (is_array($other_ns)) {
$other_ns = rtrim($other_ns[0][0], $delimiter);
$other_depth = count(explode($delimiter, $other_ns));
}
foreach ((array)self::list_folders($other_ns, '*', '', $subscribed) as $foldername) {
$path = explode($delimiter, $foldername);
$depth = count($path) - $other_depth;
array_pop($path);
// only list top-level folders of the 'other' namespace
if ($depth == 1) {
$folders[$foldername] = new kolab_storage_user_folder($foldername, $other_ns);
}
}
}
return $folders;
}
/**
* Handler for user_delete plugin hooks
*
@ -1255,43 +1407,3 @@ class kolab_storage
}
/**
* Helper class that represents a virtual IMAP folder
* with a subset of the kolab_storage_folder API.
*/
class virtual_kolab_storage_folder
{
public $id;
public $name;
public $namespace;
public $parent = '';
public $children = array();
public $virtual = true;
protected $displayname;
public function __construct($name, $dispname, $ns, $parent = '')
{
$this->id = kolab_storage::folder_id($name);
$this->name = $name;
$this->namespace = $ns;
$this->parent = $parent;
$this->displayname = $dispname;
}
public function get_namespace()
{
return $this->namespace;
}
public function get_name()
{
// this is already kolab_storage::object_name() result
return $this->displayname;
}
public function get_foldername()
{
$parts = explode('/', $this->name);
return rcube_charset::convert(end($parts), 'UTF7-IMAP');
}
}

View file

@ -0,0 +1,123 @@
<?php
/**
* Class that represents a (virtual) folder in the 'other' namespace
* implementing a subset of the kolab_storage_folder API.
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2014, 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_user_folder extends kolab_storage_virtual_folder
{
protected static $ldapcache = array();
public $ldaprec;
/**
* Default constructor
*/
public function __construct($name, $parent = '', $ldaprec = null)
{
parent::__construct($name, $name, 'other', $parent);
if (!empty($ldaprec)) {
self::$ldapcache[$name] = $this->ldaprec = $ldaprec;
}
// use value cached in memory for repeated lookups
else if (array_key_exists($name, self::$ldapcache)) {
$this->ldaprec = self::$ldapcache[$name];
}
// lookup user in LDAP and set $this->ldaprec
else if ($ldap = kolab_storage::ldap()) {
// get domain from current user
list(,$domain) = explode('@', rcube::get_instance()->get_user_name());
$this->ldaprec = $ldap->get_user_record(parent::get_foldername($this->name) . '@' . $domain, $_SESSION['imap_host']);
if (!empty($this->ldaprec)) {
$this->ldaprec['kolabtargetfolder'] = $name;
}
self::$ldapcache[$name] = $this->ldaprec;
}
}
/**
* Getter for the top-end folder name to be displayed
*
* @return string Name of this folder
*/
public function get_foldername()
{
return $this->ldaprec ? ($this->ldaprec['displayname'] ?: $this->ldaprec['name']) :
parent::get_foldername();
}
/**
* Returns the owner of the folder.
*
* @return string The owner of this folder.
*/
public function get_owner()
{
return $this->ldaprec['mail'];
}
/**
* 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
*
* @return boolean True if subscribed, false if not
*/
public function is_subscribed()
{
return kolab_storage::folder_is_subscribed($this->name, true);
}
/**
* Change subscription status of this folder
*
* @param boolean The desired subscription status: true = subscribed, false = not subscribed
*
* @return True on success, false on error
*/
public function subscribe($subscribed)
{
return $subscribed ?
kolab_storage::folder_subscribe($this->name, true) :
kolab_storage::folder_unsubscribe($this->name, true);
}
}

View file

@ -0,0 +1,86 @@
<?php
/**
* Helper class that represents a virtual IMAP folder
* with a subset of the kolab_storage_folder API.
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2014, 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_virtual_folder
{
public $id;
public $name;
public $namespace;
public $parent = '';
public $children = array();
public $virtual = true;
protected $displayname;
public function __construct($name, $dispname, $ns, $parent = '')
{
$this->id = kolab_storage::folder_id($name);
$this->name = $name;
$this->namespace = $ns;
$this->parent = $parent;
$this->displayname = $dispname;
}
/**
* Getter for the name of the namespace to which the IMAP folder belongs
*
* @return string Name of the namespace (personal, other, shared)
*/
public function get_namespace()
{
return $this->namespace;
}
/**
* Get the display name value of this folder
*
* @return string Folder name
*/
public function get_name()
{
// this is already kolab_storage::object_name() result
return $this->displayname;
}
/**
* Getter for the top-end folder name (not the entire path)
*
* @return string Name of this folder
*/
public function get_foldername()
{
$parts = explode('/', $this->name);
return rcube_charset::convert(end($parts), 'UTF7-IMAP');
}
/**
* Get the color value stored in metadata
*
* @param string Default color value to return if not set
* @return mixed Color value from IMAP metadata or $default is not set
*/
public function get_color($default = null)
{
return $default;
}
}