Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117947539
D91.1775485802.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
64 KB
Referenced Files
None
Subscribers
None
D91.1775485802.diff
View Options
diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -1746,11 +1746,11 @@
// convert link URIs references into structs
if (array_key_exists('links', $event)) {
- foreach ((array)$event['links'] as $i => $link) {
- if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link))) {
- $event['links'][$i] = $msgref;
+ foreach ((array) $event['links'] as $i => $link) {
+ if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link))) {
+ $event['links'][$i] = $msgref;
+ }
}
- }
}
// check for organizer in attendees list
diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -188,29 +188,35 @@
*/
public function get_event($id)
{
+ // remove our occurrence identifier if it's there
+ $master_id = preg_replace('/-\d{8}(T\d{6})?$/', '', $id);
+
// directly access storage object
- if (!$this->events[$id] && ($record = $this->storage->get_object($id)))
- $this->events[$id] = $this->_to_driver_event($record, true);
+ if (!$this->events[$id] && $master_id == $id && ($record = $this->storage->get_object($id))) {
+ $this->events[$id] = $this->_to_driver_event($record, true);
+ }
- // event not found, maybe a recurring instance is requested
- if (!$this->events[$id]) {
- $master_id = preg_replace('/-\d+(T\d{6})?$/', '', $id);
+ // maybe a recurring instance is requested
+ if (!$this->events[$id] && $master_id != $id) {
$instance_id = substr($id, strlen($master_id) + 1);
- if ($master_id != $id && ($record = $this->storage->get_object($master_id))) {
- $master = $this->_to_driver_event($record);
+ if ($record = $this->storage->get_object($master_id)) {
+ $master = $this->_to_driver_event($record, true);
+ $this->events[$master_id] = $master;
}
- // check for match in top-level exceptions (aka loose single occurrences)
- if ($master && $master['_formatobj'] && ($instance = $master['_formatobj']->get_instance($instance_id))) {
- $this->events[$id] = $this->_to_driver_event($instance);
- }
- // check for match on the first instance already
- else if ($master['_instance'] && $master['_instance'] == $instance_id) {
- $this->events[$id] = $master;
- }
- else if ($master && is_array($master['recurrence'])) {
- $this->get_recurring_events($record, $master['start'], null, $id);
+ if ($master) {
+ // check for match in top-level exceptions (aka loose single occurrences)
+ if ($master['_formatobj'] && ($instance = $master['_formatobj']->get_instance($instance_id))) {
+ $this->events[$id] = $this->_to_driver_event($instance);
+ }
+ // check for match on the first instance already
+ else if ($master['_instance'] && $master['_instance'] == $instance_id) {
+ $this->events[$id] = $master;
+ }
+ else if (is_array($master['recurrence'])) {
+ $this->get_recurring_events($record, $master['start'], null, $id);
+ }
}
}
@@ -298,13 +304,13 @@
$events = array();
foreach ($this->storage->select($query) as $record) {
- $event = $this->_to_driver_event($record, !$virtual);
+ $event = $this->_to_driver_event($record, !$virtual, false);
// remember seen categories
if ($event['categories']) {
$cat = is_array($event['categories']) ? $event['categories'][0] : $event['categories'];
$this->categories[$cat]++;
- }
+ }
// list events in requested time window
if ($event['start'] <= $end && $event['end'] >= $start) {
@@ -347,7 +353,7 @@
// add top-level exceptions (aka loose single occurrences)
else if (is_array($record['exceptions'])) {
foreach ($record['exceptions'] as $ex) {
- $component = $this->_to_driver_event($ex);
+ $component = $this->_to_driver_event($ex, false, false);
if ($component['start'] <= $end && $component['end'] >= $start) {
$events[] = $component;
}
@@ -381,6 +387,10 @@
return true;
});
+ // Apply event-to-mail relations
+ $config = kolab_storage_config::get_instance();
+ $config->apply_links($events);
+
// avoid session race conditions that will loose temporary subscriptions
$this->cal->rc->session->nowrite = true;
@@ -451,8 +461,8 @@
//generate new event from RC input
$object = $this->_from_driver_event($event);
- $saved = $this->storage->save($object, 'event');
-
+ $saved = $this->storage->save($object, 'event');
+
if (!$saved) {
rcube::raise_error(array(
'code' => 600, 'type' => 'php',
@@ -463,11 +473,13 @@
}
else {
// save links in configuration.relation object
- $this->save_links($event['uid'], $links);
+ if ($this->save_links($event['uid'], $links)) {
+ $object['links'] = $links;
+ }
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
}
-
+
return $saved;
}
@@ -490,7 +502,7 @@
unset($event['links']);
$object = $this->_from_driver_event($event, $old);
- $saved = $this->storage->save($object, 'event', $old['uid']);
+ $saved = $this->storage->save($object, 'event', $old['uid']);
if (!$saved) {
rcube::raise_error(array(
@@ -501,7 +513,9 @@
}
else {
// save links in configuration.relation object
- $this->save_links($event['uid'], $links);
+ if ($this->save_links($event['uid'], $links)) {
+ $object['links'] = $links;
+ }
$updated = true;
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
@@ -572,14 +586,8 @@
*/
protected function save_links($uid, $links)
{
- // make sure we have a valid array
- if (empty($links)) {
- $links = array();
- }
-
$storage = kolab_storage_config::get_instance();
- $remove = array_diff($storage->get_object_links($uid), $links);
- return $storage->save_object_links($uid, $links, $remove);
+ return $storage->save_object_links($uid, (array) $links);
}
/**
@@ -628,7 +636,7 @@
if (!$exception['_instance'])
$exception['_instance'] = libcalendaring::recurrence_instance_identifier($exception);
- $rec_event = $this->_to_driver_event($exception);
+ $rec_event = $this->_to_driver_event($exception, false, false);
$rec_event['id'] = $event['uid'] . '-' . $exception['_instance'];
$rec_event['isexception'] = 1;
@@ -677,7 +685,7 @@
// add to output if in range
$rec_id = $event['uid'] . '-' . $instance_id;
if (($next_event['start'] <= $end && $next_event['end'] >= $start) || ($event_id && $rec_id == $event_id)) {
- $rec_event = $this->_to_driver_event($next_event);
+ $rec_event = $this->_to_driver_event($next_event, false, false);
$rec_event['_instance'] = $instance_id;
$rec_event['_count'] = $i + 1;
@@ -709,10 +717,13 @@
/**
* Convert from Kolab_Format to internal representation
*/
- private function _to_driver_event($record, $noinst = false)
+ private function _to_driver_event($record, $noinst = false, $links = true)
{
$record['calendar'] = $this->id;
- $record['links'] = $this->get_links($record['uid']);
+
+ if ($links && !array_key_exists('links', $record)) {
+ $record['links'] = $this->get_links($record['uid']);
+ }
if ($this->get_namespace() == 'other') {
$record['className'] = 'fc-event-ns-other';
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -57,12 +57,11 @@
require_once(dirname(__FILE__) . '/kolab_invitation_calendar.php');
$this->cal = $cal;
- $this->rc = $cal->rc;
- $this->_read_calendars();
-
+ $this->rc = $cal->rc;
+
$this->cal->register_action('push-freebusy', array($this, 'push_freebusy'));
$this->cal->register_action('calendar-acl', array($this, 'calendar_acl'));
-
+
$this->freebusy_trigger = $this->rc->config->get('calendar_freebusy_trigger', false);
if (kolab_storage::$version == '2.0') {
@@ -89,11 +88,11 @@
// get all folders that have "event" type, sorted by namespace/name
$folders = kolab_storage::sort_folders(kolab_storage::get_folders('event') + kolab_storage::get_user_folders('event', true));
- $this->calendars = array();
+ $this->calendars = array();
foreach ($folders as $folder) {
if ($folder instanceof kolab_storage_folder_user) {
- $calendar = new kolab_user_calendar($folder->name, $this->cal);
+ $calendar = new kolab_user_calendar($folder, $this->cal);
$calendar->subscriptions = count($folder->children) > 0;
}
else {
@@ -120,10 +119,12 @@
*/
public function list_calendars($filter = 0, &$tree = null)
{
+ $this->_read_calendars();
+
// attempt to create a default calendar for this user
if (!$this->has_writeable) {
if ($this->create_calendar(array('name' => 'Calendar', 'color' => 'cc0000'))) {
- unset($this->calendars);
+ unset($this->calendars);
$this->_read_calendars();
}
}
@@ -162,8 +163,8 @@
// special handling for user or virtual folders
if ($cal instanceof kolab_storage_folder_user) {
$calendars[$cal->id] = array(
- 'id' => $cal->id,
- 'name' => kolab_storage::object_name($fullname),
+ 'id' => $cal->id,
+ 'name' => $fullname,
'listname' => $listname,
'editname' => $cal->get_foldername(),
'color' => $cal->get_color(),
@@ -287,6 +288,8 @@
*/
protected function filter_calendars($filter)
{
+ $this->_read_calendars();
+
$calendars = array();
$plugin = $this->rc->plugins->exec_hook('calendar_list_filter', array(
@@ -340,14 +343,19 @@
*/
public function get_calendar($id)
{
+ $this->_read_calendars();
+
// create calendar object if necesary
- if (!$this->calendars[$id] && in_array($id, array(self::INVITATIONS_CALENDAR_PENDING, self::INVITATIONS_CALENDAR_DECLINED))) {
- $this->calendars[$id] = new kolab_invitation_calendar($id, $this->cal);
- }
- else if (!$this->calendars[$id] && $id !== self::BIRTHDAY_CALENDAR_ID) {
- $calendar = kolab_calendar::factory($id, $this->cal);
- if ($calendar->ready)
- $this->calendars[$calendar->id] = $calendar;
+ if (!$this->calendars[$id]) {
+ if (in_array($id, array(self::INVITATIONS_CALENDAR_PENDING, self::INVITATIONS_CALENDAR_DECLINED))) {
+ $this->calendars[$id] = new kolab_invitation_calendar($id, $this->cal);
+ }
+ else if ($id !== self::BIRTHDAY_CALENDAR_ID) {
+ $calendar = kolab_calendar::factory($id, $this->cal);
+ if ($calendar->ready) {
+ $this->calendars[$calendar->id] = $calendar;
+ }
+ }
}
return $this->calendars[$id];
@@ -592,8 +600,12 @@
$event = self::from_rcube_event($event);
- $cid = $event['calendar'] ? $event['calendar'] : reset(array_keys($this->calendars));
- if ($storage = $this->get_calendar($cid)) {
+ if (!$event['calendar']) {
+ $this->_read_calendars();
+ $event['calendar'] = reset(array_keys($this->calendars));
+ }
+
+ if ($storage = $this->get_calendar($event['calendar'])) {
// if this is a recurrence instance, append as exception to an already existing object for this UID
if (!empty($event['recurrence_date']) && ($master = $storage->get_event($event['uid']))) {
self::add_exception($master, $event);
@@ -1012,7 +1024,7 @@
// copy attachment metadata to new event
$event = self::from_rcube_event($event, $master);
-
+
// remove recurrence exceptions on re-scheduling
if ($reschedule) {
unset($event['recurrence']['EXCEPTIONS'], $event['exceptions'], $master['recurrence']['EXDATE']);
@@ -1436,8 +1448,10 @@
{
if ($calendars && is_string($calendars))
$calendars = explode(',', $calendars);
- else if (!$calendars)
+ else if (!$calendars) {
+ $this->_read_calendars();
$calendars = array_keys($this->calendars);
+ }
$query = array();
if ($modifiedsince)
@@ -1482,8 +1496,10 @@
if ($calendars && is_string($calendars))
$calendars = explode(',', $calendars);
- else if (!$calendars)
+ else if (!$calendars) {
+ $this->_read_calendars();
$calendars = array_keys($this->calendars);
+ }
foreach ($calendars as $cid) {
if ($storage = $this->get_calendar($cid)) {
@@ -1521,6 +1537,9 @@
$candidates = array();
$query = array(array('tags', '=', 'x-has-alarms'));
+
+ $this->_read_calendars();
+
foreach ($this->calendars as $cid => $calendar) {
// skip calendars with alarms disabled
if (!$calendar->alarms || ($calendars && !in_array($cid, $calendars)))
@@ -2317,6 +2336,8 @@
return parent::calendar_form($action, $calendar, $formfields);
}
+ $this->_read_calendars();
+
if ($calendar['id'] && ($cal = $this->calendars[$calendar['id']])) {
$folder = $cal->get_realname(); // UTF7
$color = $cal->get_color();
diff --git a/plugins/calendar/drivers/kolab/kolab_invitation_calendar.php b/plugins/calendar/drivers/kolab/kolab_invitation_calendar.php
--- a/plugins/calendar/drivers/kolab/kolab_invitation_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_invitation_calendar.php
@@ -34,6 +34,7 @@
public $categories = array();
public $name = 'Invitations';
+
/**
* Default constructor
*/
@@ -62,7 +63,6 @@
$this->alarms = $prefs[$this->id]['showalarms'];
}
-
/**
* Getter for a nice and human readable name for this calendar
*
@@ -73,7 +73,6 @@
return $this->name;
}
-
/**
* Getter for the IMAP folder owner
*
@@ -84,7 +83,6 @@
return $this->cal->rc->get_user_name();
}
-
/**
*
*/
@@ -93,7 +91,6 @@
return $this->get_name();
}
-
/**
* Getter for the name of the namespace to which the IMAP folder belongs
*
@@ -104,7 +101,6 @@
return 'x-special';
}
-
/**
* Getter for the top-end calendar folder name (not the entire path)
*
@@ -171,7 +167,6 @@
return $prop['id'];
}
-
/**
* Getter for a single event object
*/
@@ -202,7 +197,7 @@
else {
$cal = null;
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
- $cal = new kolab_calendar($foldername, $this->cal);
+ $cal = $this->_get_calendar($foldername);
if ($cal->ready && $cal->storage && $cal->get_event($event['id'])) {
break;
}
@@ -216,7 +211,6 @@
return false;
}
-
/**
* @param integer Event's new start (unix timestamp)
* @param integer Event's new end (unix timestamp)
@@ -239,7 +233,7 @@
// aggregate events from all calendar folders
$events = array();
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
- $cal = new kolab_calendar($foldername, $this->cal);
+ $cal = $this->_get_calendar($foldername);
if ($cal->get_namespace() == 'other')
continue;
@@ -293,7 +287,7 @@
// aggregate counts from all calendar folders
$count = 0;
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
- $cal = new kolab_calendar($foldername, $this->cal);
+ $cal = $this->_get_calendar($foldername);
if ($cal->get_namespace() == 'other')
continue;
@@ -304,6 +298,15 @@
}
/**
+ * Get calendar object instance (that maybe already initialized)
+ */
+ private function _get_calendar($folder_name)
+ {
+ $id = kolab_storage::folder_id($folder_name, true);
+ return $this->cal->driver->get_calendar($id);
+ }
+
+ /**
* Helper method to modify some event properties
*/
private function _mod_event($event)
@@ -318,7 +321,6 @@
return $event;
}
-
/**
* Create a new event record
*
@@ -337,7 +339,6 @@
* @see calendar_driver::new_event()
* @return boolean True on success, False on error
*/
-
public function update_event($event, $exception_id = null)
{
// forward call to the actual storage folder
@@ -372,6 +373,4 @@
{
return false;
}
-
-
}
diff --git a/plugins/calendar/drivers/kolab/kolab_user_calendar.php b/plugins/calendar/drivers/kolab/kolab_user_calendar.php
--- a/plugins/calendar/drivers/kolab/kolab_user_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_user_calendar.php
@@ -5,7 +5,7 @@
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
- * Copyright (C) 2014-2015, Kolab Systems AG <contact@kolabsys.com>
+ * Copyright (C) 2014-2016, 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
@@ -45,8 +45,12 @@
$this->userdata = $user_or_folder;
$this->storage = new kolab_storage_folder_user($this->userdata['kolabtargetfolder'], '', $this->userdata);
}
+ else if ($user_or_folder instanceof kolab_storage_folder_user) {
+ $this->storage = $user_or_folder;
+ $this->userdata = $this->storage->ldaprec;
+ }
else { // get user record from LDAP
- $this->storage = new kolab_storage_folder_user($user_or_folder);
+ $this->storage = new kolab_storage_folder_user($user_or_folder);
$this->userdata = $this->storage->ldaprec;
}
@@ -57,7 +61,7 @@
// 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();
+ $this->name = $this->storage->name;
$this->parent = ''; // user calendars are top level
// user-specific alarms settings win
@@ -67,7 +71,6 @@
}
}
-
/**
* Getter for a nice and human readable name for this calendar
*
@@ -78,7 +81,6 @@
return $this->userdata['displayname'] ?: ($this->userdata['name'] ?: $this->userdata['mail']);
}
-
/**
* Getter for the IMAP folder owner
*
@@ -89,7 +91,6 @@
return $this->userdata['mail'];
}
-
/**
*
*/
@@ -98,7 +99,6 @@
return trim($this->userdata['displayname'] . '; ' . $this->userdata['mail'], '; ');
}
-
/**
* Getter for the name of the namespace to which the IMAP folder belongs
*
@@ -109,7 +109,6 @@
return 'other user';
}
-
/**
* Getter for the top-end calendar folder name (not the entire path)
*
@@ -164,7 +163,6 @@
return $prop['id'];
}
-
/**
* Getter for a single event object
*/
@@ -370,7 +368,6 @@
return sprintf('%s/%s', $event['start']->format('U'), is_object($event['end']->format('U')) ?: '0');
}
-
/**
* Create a new event record
*
@@ -389,7 +386,6 @@
* @see calendar_driver::new_event()
* @return boolean True on success, False on error
*/
-
public function update_event($event, $exception_id = null)
{
return false;
@@ -417,7 +413,6 @@
return false;
}
-
/**
* Convert from Kolab_Format to internal representation
*/
@@ -428,5 +423,4 @@
return kolab_driver::to_rcube_event($record);
}
-
}
diff --git a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
--- a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
+++ b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
@@ -166,7 +166,6 @@
$this->action = rcube::get_instance()->action;
}
-
/**
* Getter for the address book name to be displayed
*
@@ -174,8 +173,7 @@
*/
public function get_name()
{
- $folder = kolab_storage::object_name($this->imap_folder, $this->namespace);
- return $folder;
+ return $this->storagefolder->get_name();
}
/**
@@ -186,7 +184,6 @@
return $this->storagefolder->get_foldername();
}
-
/**
* Getter for the IMAP folder name
*
@@ -197,7 +194,6 @@
return $this->imap_folder;
}
-
/**
* Getter for the name of the namespace to which the IMAP folder belongs
*
diff --git a/plugins/kolab_notes/kolab_notes.php b/plugins/kolab_notes/kolab_notes.php
--- a/plugins/kolab_notes/kolab_notes.php
+++ b/plugins/kolab_notes/kolab_notes.php
@@ -239,7 +239,7 @@
else if ($folder->virtual) {
$lists[$list_id] = array(
'id' => $list_id,
- 'name' => kolab_storage::object_name($fullname),
+ 'name' => $fullname,
'listname' => $listname,
'virtual' => true,
'editable' => false,
@@ -441,6 +441,7 @@
{
$config = kolab_storage_config::get_instance();
$tags = $config->apply_tags($records);
+ $config->apply_links($records);
foreach ($records as $i => $rec) {
unset($records[$i]['description']);
@@ -557,6 +558,8 @@
if ($result) {
// get note tags
$result['tags'] = $this->get_tags($result['uid']);
+ // get note links
+ $result['links'] = $this->get_links($result['uid']);
}
return $result;
@@ -565,7 +568,7 @@
/**
* Helper method to encode the given note record for use in the client
*/
- private function _client_encode(&$note, $resolve = false)
+ private function _client_encode(&$note)
{
foreach ($note as $key => $prop) {
if ($key[0] == '_' || $key == 'x-custom') {
@@ -585,10 +588,14 @@
$note['html'] = $this->_wash_html($note['description']);
}
- // resolve message links
- $note['links'] = array_map(function($link) {
- return kolab_storage_config::get_message_reference($link, 'note') ?: array('uri' => $link);
- }, $this->get_links($note['uid']));
+ // convert link URIs references into structs
+ if (array_key_exists('links', $note)) {
+ foreach ((array)$note['links'] as $i => $link) {
+ if (strpos($link, 'imap://') === 0 && ($msgref = kolab_storage_config::get_message_reference($link, 'note'))) {
+ $note['links'][$i] = $msgref;
+ }
+ }
+ }
return $note;
}
@@ -1045,7 +1052,7 @@
$newfolder = kolab_storage::folder_update($list);
if ($newfolder === false) {
- $save_error = $this->gettext(kolab_storage::$last_error);
+ $save_error = $this->gettext(kolab_storage::$last_error);
}
else {
$success = true;
@@ -1056,7 +1063,7 @@
// compose the new display name
$delim = $this->rc->get_storage()->get_hierarchy_delimiter();
$path_imap = explode($delim, $newfolder);
- $list['name'] = kolab_storage::object_name($newfolder);
+ $list['name'] = kolab_storage::object_name($newfolder);
$list['editname'] = rcube_charset::convert(array_pop($path_imap), 'UTF7-IMAP');
$list['listname'] = str_repeat(' ', count($path_imap)) . '» ' . $list['editname'];
}
@@ -1247,12 +1254,8 @@
private function save_links($uid, $links)
{
- if (empty($links)) {
- $links = array();
- }
$config = kolab_storage_config::get_instance();
- $remove = array_diff($config->get_object_links($uid), $links);
- return $config->save_object_links($uid, $links, $remove);
+ return $config->save_object_links($uid, (array) $links);
}
/**
diff --git a/plugins/kolab_tags/kolab_tags.php b/plugins/kolab_tags/kolab_tags.php
--- a/plugins/kolab_tags/kolab_tags.php
+++ b/plugins/kolab_tags/kolab_tags.php
@@ -120,6 +120,10 @@
return $args;
}
+ if ($this->rc->action == 'print') {
+ return;
+ }
+
$this->mail_headers_done = true;
if ($engine = $this->engine()) {
diff --git a/plugins/kolab_tags/lib/kolab_tags_engine.php b/plugins/kolab_tags/lib/kolab_tags_engine.php
--- a/plugins/kolab_tags/lib/kolab_tags_engine.php
+++ b/plugins/kolab_tags/lib/kolab_tags_engine.php
@@ -278,6 +278,12 @@
public function taglist($attrib)
{
$taglist = $this->backend->list_tags();
+
+ // Performance: Save the list for later
+ if ($this->rc->action == 'show' || $this->rc->action == 'preview') {
+ $this->taglist = $taglist;
+ }
+
$taglist = array_map(array($this, 'parse_tag'), $taglist);
$this->rc->output->set_env('tags', $taglist);
@@ -329,7 +335,7 @@
*/
public function message_headers_handler($args)
{
- $taglist = $this->backend->list_tags();
+ $taglist = $this->taglist ?: $this->backend->list_tags();
$uid = $args['uid'];
$folder = $args['folder'];
$tags = array();
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -25,7 +25,7 @@
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 COLOR_KEY_SHARED = '/shared/vendor/kolab/color';
const COLOR_KEY_PRIVATE = '/private/vendor/kolab/color';
@@ -233,20 +233,23 @@
*
* @param array Pseudo-SQL query as list of filter parameter triplets
* @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)
* @see kolab_storage_format::select()
*/
- public static function select($query, $type)
+ public static function select($query, $type, $limit = null)
{
self::setup();
$folder = null;
$result = array();
foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
- if (!$folder)
- $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
- else
- $folder->set_folder($foldername, $type, $folderdata[$foldername]);
+ $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
+
+ if ($limit) {
+ $folder->set_order_and_limit(null, $limit);
+ }
foreach ($folder->select($query, '*') as $object) {
$result[] = $object;
@@ -551,6 +554,7 @@
/**
* 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
*
* @param string $folder IMAP folder name (UTF7-IMAP)
@@ -560,13 +564,47 @@
*/
public static function object_name($folder, &$folder_ns=null)
{
- self::setup();
-
// find custom display name in folder METADATA
if ($name = self::custom_displayname($folder)) {
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;
$namespace = self::$imap->get_namespace();
@@ -582,6 +620,7 @@
}
}
}
+
if (!$found && !empty($namespace['other'])) {
foreach ($namespace['other'] as $ns) {
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
@@ -605,6 +644,7 @@
}
}
}
+
if (!$found && !empty($namespace['personal'])) {
foreach ($namespace['personal'] as $ns) {
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
@@ -635,22 +675,6 @@
}
/**
- * 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.
* Note: $origname is a string returned by self::object_name()
*/
@@ -745,7 +769,7 @@
}
}
- $names[$name] = self::object_name($name);
+ $names[$name] = $c_folder->get_name();
}
// Build SELECT field of parent folder
@@ -958,16 +982,16 @@
$nsnames = array('personal' => array(), 'shared' => array(), 'other' => array());
foreach ($folders as $folder) {
- $folders[$folder->name] = $folder;
+ $_folders[$folder->name] = $folder;
$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
foreach (array_keys($nsnames) as $ns) {
asort($nsnames[$ns], SORT_LOCALE_STRING);
foreach (array_keys($nsnames[$ns]) as $utf7name) {
- $out[] = $folders[$utf7name];
+ $out[] = $_folders[$utf7name];
}
}
@@ -1008,6 +1032,7 @@
while (count($path) >= $depth && ($parent = join($delim, $path))) {
array_pop($path);
$parent_parent = join($delim, $path);
+
if (!$refs[$parent]) {
if ($folder->type && self::folder_type($parent) == $folder->type) {
$refs[$parent] = new kolab_storage_folder($parent, $folder->type, $folder->type);
@@ -1017,7 +1042,7 @@
$refs[$parent] = new kolab_storage_folder_user($parent, $parent_parent);
}
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);
}
$parents[] = $refs[$parent];
@@ -1599,5 +1624,31 @@
$db = rcmail::get_instance()->get_dbh();
$prefix = 'imap://' . urlencode($args['username']) . '@' . $args['host'] . '/%';
$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];
+ }
}
}
diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php
--- a/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_cache.php
@@ -25,6 +25,7 @@
class kolab_storage_cache
{
const DB_DATE_FORMAT = 'Y-m-d H:i:s';
+ const MAX_RECORDS = 500;
public $sync_complete = false;
@@ -428,18 +429,23 @@
/**
* Move an existing cache entry to a new resource
*
- * @param string Entry's IMAP message UID
- * @param string Entry's Object UID
- * @param object kolab_storage_folder Target storage folder instance
+ * @param string Entry's IMAP message UID
+ * @param string Entry's Object UID
+ * @param kolab_storage_folder Target storage folder instance
+ * @param string Target entry's IMAP message UID
*/
- public function move($msguid, $uid, $target)
+ public function move($msguid, $uid, $target, $new_msguid = null)
{
- if ($this->ready) {
+ if ($this->ready && $target) {
// clear cached uid mapping and force new lookup
unset($target->cache->uid2msg[$uid]);
// resolve new message UID in target folder
- if ($new_msguid = $target->cache->uid2msguid($uid)) {
+ if (!$new_msguid) {
+ $new_msguid = $target->cache->uid2msguid($uid);
+ }
+
+ if ($new_msguid) {
$this->_read_folder_data();
$this->db->query(
@@ -528,7 +534,7 @@
$this->_read_folder_data();
// fetch full object data on one query if a small result set is expected
- $fetchall = !$uids && ($this->limit ? $this->limit[0] : ($count = $this->count($query))) < 500;
+ $fetchall = !$uids && ($this->limit ? $this->limit[0] : ($count = $this->count($query))) < self::MAX_RECORDS;
// skip SELECT if we know it will return nothing
if ($count === 0) {
@@ -665,7 +671,12 @@
public function set_order_by($sortcols)
{
if (!empty($sortcols)) {
- $this->order_by = '`' . join('`, `', (array)$sortcols) . '`';
+ $sortcols = array_map(function($v) {
+ list($column, $order) = explode(' ', $v, 2);
+ return "`$column`" . ($order ? " $order" : '');
+ }, (array) $sortcols);
+
+ $this->order_by = join(', ', $sortcols);
}
else {
$this->order_by = null;
diff --git a/plugins/libkolab/lib/kolab_storage_config.php b/plugins/libkolab/lib/kolab_storage_config.php
--- a/plugins/libkolab/lib/kolab_storage_config.php
+++ b/plugins/libkolab/lib/kolab_storage_config.php
@@ -25,8 +25,8 @@
class kolab_storage_config
{
- const FOLDER_TYPE = 'configuration';
-
+ const FOLDER_TYPE = 'configuration';
+ const MAX_RELATIONS = 499; // should be less than kolab_storage_cache::MAX_RECORDS
/**
* Singleton instace of kolab_storage_config
@@ -58,8 +58,12 @@
/**
* Private constructor (finds default configuration folder as a config source)
*/
- private function __construct()
+ private function _init()
{
+ if ($this->enabled !== null) {
+ return $this->enabled;
+ }
+
// get all configuration folders
$this->folders = kolab_storage::get_folders(self::FOLDER_TYPE, false);
@@ -86,9 +90,7 @@
}
// check if configuration folder exist
- if ($this->default && $this->default->name) {
- $this->enabled = true;
- }
+ return $this->enabled = $this->default && $this->default->name;
}
/**
@@ -98,7 +100,7 @@
*/
public function is_enabled()
{
- return $this->enabled;
+ return $this->_init();
}
/**
@@ -114,6 +116,10 @@
{
$list = array();
+ if (!$this->is_enabled()) {
+ return $list;
+ }
+
foreach ($this->folders as $folder) {
// we only want to read from default folder
if ($default && !$folder->default) {
@@ -144,6 +150,10 @@
*/
public function get_object($uid, $default = false)
{
+ if (!$this->is_enabled()) {
+ return;
+ }
+
foreach ($this->folders as $folder) {
// we only want to read from default folder
if ($default && !$folder->default) {
@@ -166,7 +176,7 @@
*/
public function save(&$object, $type)
{
- if (!$this->enabled) {
+ if (!$this->is_enabled()) {
return false;
}
@@ -201,25 +211,27 @@
/**
* Remove configuration object
*
- * @param string $uid Object UID
+ * @param string|array $object Object array or its UID
*
* @return bool True on success, False on failure
*/
- public function delete($uid)
+ public function delete($object)
{
- if (!$this->enabled) {
+ if (!$this->is_enabled()) {
return false;
}
// fetch the object to find folder
- $object = $this->get_object($uid);
+ if (!is_array($object)) {
+ $object = $this->get_object($object);
+ }
if (!$object) {
return false;
}
$folder = $this->find_folder($object);
- $status = $folder->delete($uid);
+ $status = $folder->delete($object);
// on success, update cached tags list
if ($status && is_array($this->tags)) {
@@ -239,6 +251,10 @@
*/
public function find_folder($object = array())
{
+ if (!$this->is_enabled()) {
+ return;
+ }
+
// find folder object
if ($object['_mailbox']) {
foreach ($this->folders as $folder) {
@@ -551,12 +567,17 @@
/**
* Assign tags to kolab objects
*
- * @param array $records List of kolab objects
+ * @param array $records List of kolab objects
+ * @param bool $no_return Don't return anything
*
* @return array List of tags
*/
- public function apply_tags(&$records)
+ public function apply_tags(&$records, $no_return = false)
{
+ if (empty($records) && $no_return) {
+ return;
+ }
+
// first convert categories into tags
foreach ($records as $i => $rec) {
if (!empty($rec['categories'])) {
@@ -587,12 +608,84 @@
$tags[] = $tag['name'];
}
- $tags = array_unique($tags);
+ $tags = $no_return ? null : array_unique($tags);
return $tags;
}
/**
+ * Assign links (relations) to kolab objects
+ *
+ * @param array $records List of kolab objects
+ */
+ public function apply_links(&$records)
+ {
+ $links = array();
+ $uids = array();
+ $ids = array();
+ $limit = 25;
+
+ // get list of object UIDs and UIRs map
+ foreach ($records as $i => $rec) {
+ $uids[] = $rec['uid'];
+ // there can be many objects with the same uid (recurring events)
+ $ids[self::build_member_url($rec['uid'])][] = $i;
+ $records[$i]['links'] = array();
+ }
+
+ if (!empty($uids)) {
+ $uids = array_unique($uids);
+ }
+
+ // The whole story here is to not do SELECT for every object.
+ // We'll build one SELECT for many (limit above) objects at once
+
+ while (!empty($uids)) {
+ $chunk = array_splice($uids, 0, $limit);
+ $chunk = array_map(function($v) { return array('member', '=', $v); }, $chunk);
+
+ $filter = array(
+ array('type', '=', 'relation'),
+ array('category', '=', 'generic'),
+ array($chunk, 'OR'),
+ );
+
+ $relations = $this->get_objects($filter, true, self::MAX_RELATIONS);
+
+ foreach ($relations as $relation) {
+ $links[$relation['uid']] = $relation;
+ }
+ }
+
+ if (empty($links)) {
+ return;
+ }
+
+ // assign links of related messages
+ foreach ($links as $relation) {
+ // make relation members up-to-date
+ kolab_storage_config::resolve_members($relation);
+
+ $members = array();
+ foreach ((array) $relation['members'] as $member) {
+ if (strpos($member, 'imap://') === 0) {
+ $members[$member] = $member;
+ }
+ }
+ $members = array_values($members);
+
+ // assign links to objects
+ foreach ((array) $relation['members'] as $member) {
+ if (($id = $ids[$member]) !== null) {
+ foreach ($id as $i) {
+ $records[$i]['links'] = array_unique(array_merge($records[$i]['links'], $members));
+ }
+ }
+ }
+ }
+ }
+
+ /**
* Update object tags
*
* @param string $uid Kolab object UID
@@ -650,12 +743,10 @@
* Get tags (all or referring to specified object)
*
* @param string $member Optional object UID or mail message-id
- * @param int $limit Max. number of records (per-folder)
- * Used when searching by member
*
* @return array List of Relation objects
*/
- public function get_tags($member = '*', $limit = 0)
+ public function get_tags($member = '*')
{
if (!isset($this->tags)) {
$default = true;
@@ -667,10 +758,10 @@
// use faster method
if ($member && $member != '*') {
$filter[] = array('member', '=', $member);
- $tags = $this->get_objects($filter, $default, $limit);
+ $tags = $this->get_objects($filter, $default, self::MAX_RELATIONS);
}
else {
- $this->tags = $tags = $this->get_objects($filter, $default);
+ $this->tags = $tags = $this->get_objects($filter, $default, self::MAX_RELATIONS);
}
}
else {
@@ -711,7 +802,8 @@
* Find objects linked with the given groupware object through a relation
*
* @param string Object UUID
- * @param array List of related URIs
+ *
+ * @return array List of related URIs
*/
public function get_object_links($uid)
{
@@ -735,30 +827,33 @@
}
/**
+ * Save relations of an object.
+ * Note, that we already support only one-to-one relations.
+ * So, all relations to the object that are not provided in $links
+ * argument will be removed.
+ *
+ * @param string $uid Object UUID
+ * @param array $links List of related-object URIs
*
+ * @return bool True on success, False on failure
*/
- public function save_object_links($uid, $links, $remove = array())
+ public function save_object_links($uid, $links)
{
$object_uri = self::build_member_url($uid);
- $relations = $this->get_relations_for_member($uid);
- $done = false;
+ $relations = $this->get_relations_for_member($uid);
+ $done = false;
foreach ($relations as $relation) {
// make relation members up-to-date
kolab_storage_config::resolve_members($relation);
// remove and add links
- $members = array_diff($relation['members'], (array)$remove);
+ $members = array($object_uri);
$members = array_unique(array_merge($members, $links));
- // make sure the object_uri is still a member
- if (!in_array($object_uri, $members)) {
- $members[$object_uri];
- }
-
// remove relation if no other members remain
if (count($members) <= 1) {
- $done = $this->delete($relation['uid']);
+ $done = $this->delete($relation);
}
// update relation object if members changed
else if (count(array_diff($members, $relation['members'])) || count(array_diff($relation['members'], $members))) {
@@ -768,7 +863,7 @@
}
// no changes, we're happy
else {
- $done = true;
+ $done = true;
$links = array();
}
}
@@ -780,10 +875,10 @@
'category' => 'generic',
);
- $ret = $this->save($relation, 'relation');
+ $done = $this->save($relation, 'relation');
}
- return $ret;
+ return $done;
}
/**
@@ -798,7 +893,7 @@
array('member', '=', $uid),
);
- return $this->get_objects($filter, $default, 100);
+ return $this->get_objects($filter, $default, self::MAX_RELATIONS);
}
/**
@@ -862,7 +957,7 @@
// get kolab objects of specified type
if (!empty($uids)) {
$query = array(array('uid', '=', array_unique($uids)));
- $result = kolab_storage::select($query, $type);
+ $result = kolab_storage::select($query, $type, count($uids));
}
return $result;
@@ -893,7 +988,7 @@
/**
* Resolve the email message reference from the given URI
*/
- public function get_message_reference($uri, $rel = null)
+ public static function get_message_reference($uri, $rel = null)
{
if ($linkref = self::parse_member_url($uri)) {
$linkref['subject'] = $linkref['params']['subject'];
diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -64,15 +64,16 @@
*/
public function set_folder($name, $type = null, $type_annotation = null)
{
+ $this->name = $name;
+
if (empty($type_annotation)) {
- $type_annotation = kolab_storage::folder_type($name);
+ $type_annotation = $this->get_type();
}
$oldtype = $this->type;
list($this->type, $suffix) = explode('.', $type_annotation);
$this->default = $suffix == 'default';
$this->subtype = $this->default ? '' : $suffix;
- $this->name = $name;
$this->id = kolab_storage::folder_id($name);
$this->valid = !empty($this->type) && $this->type != 'mail' && (!$type || $this->type == $type);
@@ -155,7 +156,7 @@
{
// UID is defined in folder METADATA
$metakeys = array(kolab_storage::UID_KEY_SHARED, kolab_storage::UID_KEY_CYRUS);
- $metadata = $this->get_metadata($metakeys);
+ $metadata = $this->get_metadata();
if ($metadata !== null) {
foreach ($metakeys as $key) {
@@ -347,6 +348,12 @@
if ($length !== null) {
$this->cache->set_limit($length, $offset);
}
+
+ $this->order_and_limit = array(
+ 'cols' => $sortcols,
+ 'limit' => $length,
+ 'offset' => $offset,
+ );
}
/**
@@ -375,7 +382,6 @@
return $query;
}
-
/**
* Getter for a single Kolab object, identified by its UID
*
@@ -387,17 +393,35 @@
*/
public function get_object($uid, $type = null)
{
- if (!$this->valid) {
+ if (!$this->valid || !$uid) {
return false;
}
+ $query = array(array('uid', '=', $uid));
+
+ if ($type) {
+ $query[] = array('type', '=', $type);
+ }
+
// synchronize caches
$this->cache->synchronize();
- $msguid = $this->cache->uid2msguid($uid);
+ // we don't use cache->get() here because we don't have msguid
+ // yet, using select() is faster
- if ($msguid && ($object = $this->cache->get($msguid, $type))) {
- return $object;
+ // set order to make sure we get most recent object version
+ // set limit to skip count query
+ $this->cache->set_order_by('msguid DESC');
+ $this->cache->set_limit(1);
+
+ $list = $this->cache->select($this->_prepare_query($query));
+
+ // set the order/limit back to defined value
+ $this->cache->set_order_by($this->order_and_limit['order']);
+ $this->cache->set_limit($this->order_and_limit['limit'], $this->order_and_limit['offset']);
+
+ if (!empty($list) && !empty($list[0])) {
+ return $list[0];
}
return false;
@@ -906,7 +930,8 @@
$this->cache->bypass(false);
if ($result) {
- $this->cache->move($msguid, $uid, $target_folder);
+ $new_uid = ($copyuid = $this->imap->conn->data['COPYUID']) ? $copyuid[1] : null;
+ $this->cache->move($msguid, $uid, $target_folder, $new_uid);
return true;
}
else {
@@ -1168,6 +1193,4 @@
return true;
}
-
}
-
diff --git a/plugins/libkolab/lib/kolab_storage_folder_api.php b/plugins/libkolab/lib/kolab_storage_folder_api.php
--- a/plugins/libkolab/lib/kolab_storage_folder_api.php
+++ b/plugins/libkolab/lib/kolab_storage_folder_api.php
@@ -57,7 +57,7 @@
* @var array
*/
public $children = array();
-
+
/**
* Name of the parent folder
* @var string
@@ -69,6 +69,7 @@
protected $info;
protected $idata;
protected $namespace;
+ protected $metadata;
/**
@@ -135,10 +136,10 @@
{
if (!isset($this->namespace))
$this->namespace = $this->imap->folder_namespace($this->name);
+
return $this->namespace;
}
-
/**
* Get the display name value of this folder
*
@@ -146,10 +147,9 @@
*/
public function get_name()
{
- return kolab_storage::object_name($this->name, $this->get_namespace());
+ return kolab_storage::object_name($this->name);
}
-
/**
* Getter for the top-end folder name (not the entire path)
*
@@ -221,7 +221,7 @@
public function get_color($default = null)
{
// color is defined in folder METADATA
- $metadata = $this->get_metadata(array(kolab_storage::COLOR_KEY_PRIVATE, kolab_storage::COLOR_KEY_SHARED));
+ $metadata = $this->get_metadata();
if (($color = $metadata[kolab_storage::COLOR_KEY_PRIVATE]) || ($color = $metadata[kolab_storage::COLOR_KEY_SHARED])) {
return $color;
}
@@ -229,19 +229,20 @@
return $default;
}
-
/**
* Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION)
+ * supported by kolab_storage
*
- * @param array List of metadata keys to read
* @return array Metadata entry-value hash array on success, NULL on error
*/
- public function get_metadata($keys)
+ public function get_metadata()
{
- $metadata = rcube::get_instance()->get_storage()->get_metadata($this->name, (array)$keys);
- return $metadata[$this->name];
- }
+ if ($this->metadata === null) {
+ $this->metadata = kolab_storage::folder_metadata($this->name);
+ }
+ return $this->metadata;
+ }
/**
* Sets IMAP metadata/annotations (SETMETADATA/SETANNOTATION)
@@ -251,10 +252,10 @@
*/
public function set_metadata($entries)
{
+ $this->metadata = null;
return $this->imap->set_metadata($this->name, $entries);
}
-
/**
*
*/
@@ -277,6 +278,21 @@
return $this->idata;
}
+ /**
+ * Returns (full) type of IMAP folder
+ *
+ * @return string Folder type
+ */
+ public function get_type()
+ {
+ $metadata = $this->get_metadata();
+
+ if (!empty($metadata)) {
+ return kolab_storage::folder_select_metadata($metadata);
+ }
+
+ return $this->type;
+ }
/**
* Get IMAP ACL information for this folder
@@ -358,4 +374,3 @@
return $this->name;
}
}
-
diff --git a/plugins/libkolab/lib/kolab_storage_folder_user.php b/plugins/libkolab/lib/kolab_storage_folder_user.php
--- a/plugins/libkolab/lib/kolab_storage_folder_user.php
+++ b/plugins/libkolab/lib/kolab_storage_folder_user.php
@@ -33,7 +33,7 @@
*/
public function __construct($name, $parent = '', $ldaprec = null)
{
- parent::__construct($name, $name, 'other', $parent);
+ parent::__construct($name, kolab_storage::object_prettyname($name), 'other', $parent);
if (!empty($ldaprec)) {
self::$ldapcache[$name] = $this->ldaprec = $ldaprec;
@@ -72,7 +72,7 @@
*/
public function get_title()
{
- return trim($this->ldaprec['displayname'] . '; ' . $this->ldaprec['mail'], '; ');
+ return trim($this->ldaprec['displayname'] . '; ' . $this->ldaprec['mail'], '; ');
}
/**
@@ -131,5 +131,4 @@
return $success;
}
-
-}
\ No newline at end of file
+}
diff --git a/plugins/libkolab/lib/kolab_storage_folder_virtual.php b/plugins/libkolab/lib/kolab_storage_folder_virtual.php
--- a/plugins/libkolab/lib/kolab_storage_folder_virtual.php
+++ b/plugins/libkolab/lib/kolab_storage_folder_virtual.php
@@ -56,4 +56,4 @@
{
return $default;
}
-}
\ No newline at end of file
+}
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -46,7 +46,7 @@
*/
public function __construct($plugin)
{
- $this->rc = $plugin->rc;
+ $this->rc = $plugin->rc;
$this->plugin = $plugin;
if (kolab_storage::$version == '2.0') {
@@ -59,8 +59,6 @@
// get configuration for the Bonnie API
$this->bonnie_api = libkolab::get_bonnie_api();
- $this->_read_lists();
-
$this->plugin->register_action('folder-acl', array($this, 'folder_acl'));
}
@@ -70,8 +68,9 @@
private function _read_lists($force = false)
{
// already read sources
- if (isset($this->lists) && !$force)
+ if (isset($this->lists) && !$force) {
return $this->lists;
+ }
// get all folders that have type "task"
$folders = kolab_storage::sort_folders(kolab_storage::get_folders('task'));
@@ -102,6 +101,8 @@
$this->folders[$tasklist['id']] = $folder;
$this->folders[$folder->name] = $folder;
}
+
+ return $this->lists;
}
/**
@@ -165,6 +166,8 @@
*/
public function get_lists(&$tree = null)
{
+ $this->_read_lists();
+
// attempt to create a default list for this user
if (empty($this->lists) && !isset($this->search_more_results)) {
$prop = array('name' => 'Tasks', 'color' => '0000CC', 'default' => true);
@@ -211,7 +214,7 @@
if ($folder instanceof kolab_storage_folder_user) {
$lists[$list_id] = array(
'id' => $list_id,
- 'name' => $folder->get_name(),
+ 'name' => $fullname,
'listname' => $listname,
'title' => $folder->get_title(),
'virtual' => true,
@@ -225,7 +228,7 @@
else if ($folder->virtual) {
$lists[$list_id] = array(
'id' => $list_id,
- 'name' => kolab_storage::object_name($fullname),
+ 'name' => $fullname,
'listname' => $listname,
'virtual' => true,
'editable' => false,
@@ -256,6 +259,8 @@
*/
protected function get_folder($id)
{
+ $this->_read_lists();
+
// create list and folder instance if necesary
if (!$this->lists[$id]) {
$folder = kolab_storage::get_folder(kolab_storage::id_decode($id));
@@ -385,8 +390,10 @@
($prop['active'] ? kolab_storage::folder_activate($subfolder) : kolab_storage::folder_deactivate($subfolder));
}
}
+
return $ret;
}
+
return false;
}
@@ -400,10 +407,11 @@
public function delete_list($prop)
{
if ($prop['id'] && ($folder = $this->get_folder($prop['id']))) {
- if (kolab_storage::folder_delete($folder->name))
- return true;
- else
- $this->last_error = kolab_storage::$last_error;
+ if (kolab_storage::folder_delete($folder->name)) {
+ return true;
+ }
+
+ $this->last_error = kolab_storage::$last_error;
}
return false;
@@ -486,21 +494,26 @@
*/
public function count_tasks($lists = null)
{
- if (empty($lists))
- $lists = array_keys($this->lists);
- else if (is_string($lists))
+ if (empty($lists)) {
+ $lists = $this->_read_lists();
+ $lists = array_keys($lists);
+ }
+ else if (is_string($lists)) {
$lists = explode(',', $lists);
+ }
- $today_date = new DateTime('now', $this->plugin->timezone);
- $today = $today_date->format('Y-m-d');
+ $today_date = new DateTime('now', $this->plugin->timezone);
+ $today = $today_date->format('Y-m-d');
$tomorrow_date = new DateTime('now + 1 day', $this->plugin->timezone);
- $tomorrow = $tomorrow_date->format('Y-m-d');
+ $tomorrow = $tomorrow_date->format('Y-m-d');
$counts = array('all' => 0, 'flagged' => 0, 'today' => 0, 'tomorrow' => 0, 'overdue' => 0, 'nodate' => 0, 'mytasks' => 0);
+
foreach ($lists as $list_id) {
if (!$folder = $this->get_folder($list_id)) {
continue;
}
+
foreach ($folder->select(array(array('tags','!~','x-complete'))) as $record) {
$rec = $this->_to_rcube_task($record, $list_id, false);
@@ -542,11 +555,15 @@
*/
public function list_tasks($filter, $lists = null)
{
- if (empty($lists))
- $lists = array_keys($this->lists);
- else if (is_string($lists))
+ if (empty($lists)) {
+ $lists = $this->_read_lists();
+ $lists = array_keys($lists);
+ }
+ else if (is_string($lists)) {
$lists = explode(',', $lists);
+ }
+ $config = kolab_storage_config::get_instance();
$results = array();
// query Kolab storage
@@ -568,23 +585,25 @@
$query[] = array('changed', '>=', $filter['since']);
}
- // load all tags into memory first
- kolab_storage_config::get_instance()->get_tags();
-
foreach ($lists as $list_id) {
if (!$folder = $this->get_folder($list_id)) {
continue;
}
- foreach ($folder->select($query) as $record) {
- $this->load_tags($record);
- $task = $this->_to_rcube_task($record, $list_id);
+ foreach ($folder->select($query) as $record) {
// TODO: post-filter tasks returned from storage
-
- $results[] = $task;
+ $record['list_id'] = $list_id;
+ $results[] = $record;
}
}
+ $config->apply_tags($results, true);
+ $config->apply_links($results);
+
+ foreach (array_keys($results) as $idx) {
+ $results[$idx] = $this->_to_rcube_task($results[$idx], $results[$idx]['list_id']);
+ }
+
// avoid session race conditions that will loose temporary subscriptions
$this->plugin->rc->session->nowrite = true;
@@ -599,7 +618,9 @@
*/
public function get_task($prop)
{
+ $this->_read_lists();
$this->_parse_id($prop);
+
$id = $prop['uid'];
$list_id = $prop['list'];
$folders = $list_id ? array($list_id => $this->get_folder($list_id)) : $this->folders;
@@ -745,7 +766,7 @@
$list_id = $prop['list'];
list($uid, $mailbox, $msguid) = $this->_resolve_task_identity($prop);
- $folder = $this->get_folder($list_id);
+ $folder = $this->get_folder($list_id);
$success = false;
if ($folder && ($raw_msg = $this->bonnie_api->rawdata('task', $uid, $rev, $mailbox))) {
@@ -908,7 +929,6 @@
return array($uid, $mailbox, $msguid);
}
-
/**
* Get a list of pending alarms to be displayed to the user
*
@@ -938,7 +958,13 @@
$time = $slot + $interval;
$candidates = array();
- $query = array(array('tags', '=', 'x-has-alarms'), array('tags', '!=', 'x-complete'));
+ $query = array(
+ array('tags', '=', 'x-has-alarms'),
+ array('tags', '!=', 'x-complete')
+ );
+
+ $this->_read_lists();
+
foreach ($this->lists as $lid => $list) {
// skip lists with alarms disabled
if (!$list['showalarms'] || ($lists && !in_array($lid, $lists)))
@@ -1091,14 +1117,8 @@
*/
private function save_links($uid, $links)
{
- // make sure we have a valid array
- if (empty($links)) {
- $links = array();
- }
-
$config = kolab_storage_config::get_instance();
- $remove = array_diff($config->get_object_links($uid), $links);
- return $config->save_object_links($uid, $links, $remove);
+ return $config->save_object_links($uid, (array) $links);
}
/**
@@ -1171,10 +1191,11 @@
'sequence' => $record['sequence'],
'tags' => $record['tags'],
'list' => $list_id,
+ 'links' => $record['links'],
);
// we can sometimes skip this expensive operation
- if ($all) {
+ if ($all && !array_key_exists('links', $task)) {
$task['links'] = $this->get_links($task['uid']);
}
@@ -1238,7 +1259,7 @@
*/
private function _from_rcube_task($task, $old = array())
{
- $object = $task;
+ $object = $task;
$id_prefix = $task['list'] . ':';
if (!empty($task['date'])) {
@@ -1372,7 +1393,7 @@
// email links and tags are stored separately
$links = $task['links'];
- $tags = $task['tags'];
+ $tags = $task['tags'];
unset($task['tags'], $task['links']);
// moved from another folder
@@ -1603,6 +1624,8 @@
*/
public function tasklist_edit_form($action, $list, $fieldprop)
{
+ $this->_read_lists();
+
if ($list['id'] && ($list = $this->lists[$list['id']])) {
$folder_name = $this->get_folder($list['id'])->name; // UTF7
}
diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php
--- a/plugins/tasklist/tasklist.php
+++ b/plugins/tasklist/tasklist.php
@@ -1256,8 +1256,8 @@
// convert link URIs references into structs
if (array_key_exists('links', $rec)) {
- foreach ((array)$rec['links'] as $i => $link) {
- if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link))) {
+ foreach ((array) $rec['links'] as $i => $link) {
+ if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link, 'task'))) {
$rec['links'][$i] = $msgref;
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 6, 2:30 PM (5 d, 7 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18828376
Default Alt Text
D91.1775485802.diff (64 KB)
Attached To
Mode
D91: A set of performance improvements
Attached
Detach File
Event Timeline