A set of performance improvements
Summary: Performance: Consolidate metadata requests (#3989) This changes number of cache requests from 4 to 2 for each groupware folder. Performance: Don't initialize all folders in driver constructor (#3971) Fix regression in last optimisations Performance: Optimize kolab_storage_folder::get_object() to use one sql query instead of two Before the change to get an object by UID we first resolve UID to IMAP-UID and then fetch the object data by IMAP-UID - two select queries. Now we directly select the data by UID. Performance: Limit number of SQL queries needed for "object relations update" operation Performance: Limit number of SQL queries when "attaching" relations/tags to list of tasks/notes (#3969) Performance: Optimize get_message_relations() to use one query per-folder less Fix bug where in kolab_storage::select() could not initialize/reset folder cache properly Performance: Skip another few cache selects Performance: Get event-to-mail relations once per events list, instead of doing SELECT for every event (including recurrences) Unify mail-relations handling across plugins Performance: Use initialized calendars if available, skipping redundant folder cache synchronization Performance: Don't initialize configuration folders until they are needed Performance: Skip redundant SELECTs on mail preview and print pages Performance: Skip some redundant SELECT queries on event update Performance: Skip one SELECT query when deleting relations Performance: Better displayname annotation handling Performance: SKip some SQL queries on "empty" tasklist refresh Performance: Make objects moving faster (less SQL and less IMAP operations) using COPYUID Merge remote-tracking branch 'remotes/origin/dev/perf' Differential Revision: https://git.kolab.org/D91
This commit is contained in:
commit
1e2ea3c0e6
18 changed files with 506 additions and 255 deletions
|
@ -1746,11 +1746,11 @@ class calendar extends rcube_plugin
|
|||
|
||||
// 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
|
||||
|
|
|
@ -188,29 +188,35 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
*/
|
||||
public function get_event($id)
|
||||
{
|
||||
// directly access storage object
|
||||
if (!$this->events[$id] && ($record = $this->storage->get_object($id)))
|
||||
$this->events[$id] = $this->_to_driver_event($record, true);
|
||||
// remove our occurrence identifier if it's there
|
||||
$master_id = preg_replace('/-\d{8}(T\d{6})?$/', '', $id);
|
||||
|
||||
// event not found, maybe a recurring instance is requested
|
||||
if (!$this->events[$id]) {
|
||||
$master_id = preg_replace('/-\d+(T\d{6})?$/', '', $id);
|
||||
// directly access storage object
|
||||
if (!$this->events[$id] && $master_id == $id && ($record = $this->storage->get_object($id))) {
|
||||
$this->events[$id] = $this->_to_driver_event($record, true);
|
||||
}
|
||||
|
||||
// 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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
$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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
// 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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
//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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
}
|
||||
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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
}
|
||||
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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
*/
|
||||
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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
// 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 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
/**
|
||||
* 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';
|
||||
|
|
|
@ -57,12 +57,11 @@ class kolab_driver extends calendar_driver
|
|||
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 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
// 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 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
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 @@ class kolab_driver extends calendar_driver
|
|||
// 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 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
protected function filter_calendars($filter)
|
||||
{
|
||||
$this->_read_calendars();
|
||||
|
||||
$calendars = array();
|
||||
|
||||
$plugin = $this->rc->plugins->exec_hook('calendar_list_filter', array(
|
||||
|
@ -340,14 +343,19 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
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 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
$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 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
// 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 @@ class kolab_driver extends calendar_driver
|
|||
{
|
||||
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 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
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 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
$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 @@ class kolab_driver extends calendar_driver
|
|||
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();
|
||||
|
|
|
@ -34,6 +34,7 @@ class kolab_invitation_calendar
|
|||
public $categories = array();
|
||||
public $name = 'Invitations';
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
|
@ -62,7 +63,6 @@ class kolab_invitation_calendar
|
|||
$this->alarms = $prefs[$this->id]['showalarms'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a nice and human readable name for this calendar
|
||||
*
|
||||
|
@ -73,7 +73,6 @@ class kolab_invitation_calendar
|
|||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the IMAP folder owner
|
||||
*
|
||||
|
@ -84,7 +83,6 @@ class kolab_invitation_calendar
|
|||
return $this->cal->rc->get_user_name();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -93,7 +91,6 @@ class kolab_invitation_calendar
|
|||
return $this->get_name();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the name of the namespace to which the IMAP folder belongs
|
||||
*
|
||||
|
@ -104,7 +101,6 @@ class kolab_invitation_calendar
|
|||
return 'x-special';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the top-end calendar folder name (not the entire path)
|
||||
*
|
||||
|
@ -171,7 +167,6 @@ class kolab_invitation_calendar
|
|||
return $prop['id'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a single event object
|
||||
*/
|
||||
|
@ -202,7 +197,7 @@ class kolab_invitation_calendar
|
|||
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 @@ class kolab_invitation_calendar
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param integer Event's new start (unix timestamp)
|
||||
* @param integer Event's new end (unix timestamp)
|
||||
|
@ -239,7 +233,7 @@ class kolab_invitation_calendar
|
|||
// 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 @@ class kolab_invitation_calendar
|
|||
// 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;
|
||||
|
||||
|
@ -303,6 +297,15 @@ class kolab_invitation_calendar
|
|||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -318,7 +321,6 @@ class kolab_invitation_calendar
|
|||
return $event;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new event record
|
||||
*
|
||||
|
@ -337,7 +339,6 @@ class kolab_invitation_calendar
|
|||
* @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 @@ class kolab_invitation_calendar
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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 @@ class kolab_user_calendar extends kolab_calendar
|
|||
$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 @@ class kolab_user_calendar extends kolab_calendar
|
|||
// 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 @@ class kolab_user_calendar extends kolab_calendar
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a nice and human readable name for this calendar
|
||||
*
|
||||
|
@ -78,7 +81,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return $this->userdata['displayname'] ?: ($this->userdata['name'] ?: $this->userdata['mail']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the IMAP folder owner
|
||||
*
|
||||
|
@ -89,7 +91,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return $this->userdata['mail'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -98,7 +99,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
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 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return 'other user';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the top-end calendar folder name (not the entire path)
|
||||
*
|
||||
|
@ -164,7 +163,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return $prop['id'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a single event object
|
||||
*/
|
||||
|
@ -370,7 +368,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return sprintf('%s/%s', $event['start']->format('U'), is_object($event['end']->format('U')) ?: '0');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new event record
|
||||
*
|
||||
|
@ -389,7 +386,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
* @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 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert from Kolab_Format to internal representation
|
||||
*/
|
||||
|
@ -428,5 +423,4 @@ class kolab_user_calendar extends kolab_calendar
|
|||
|
||||
return kolab_driver::to_rcube_event($record);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -166,7 +166,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
$this->action = rcube::get_instance()->action;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the address book name to be displayed
|
||||
*
|
||||
|
@ -174,8 +173,7 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
*/
|
||||
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 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
return $this->storagefolder->get_foldername();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the IMAP folder name
|
||||
*
|
||||
|
@ -197,7 +194,6 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
return $this->imap_folder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the name of the namespace to which the IMAP folder belongs
|
||||
*
|
||||
|
|
|
@ -239,7 +239,7 @@ class kolab_notes extends rcube_plugin
|
|||
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 @@ class kolab_notes extends rcube_plugin
|
|||
{
|
||||
$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 @@ class kolab_notes extends rcube_plugin
|
|||
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 @@ class kolab_notes extends rcube_plugin
|
|||
/**
|
||||
* 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 @@ class kolab_notes extends rcube_plugin
|
|||
$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 @@ class kolab_notes extends rcube_plugin
|
|||
$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 @@ class kolab_notes extends rcube_plugin
|
|||
// 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 @@ class kolab_notes extends rcube_plugin
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -120,6 +120,10 @@ class kolab_tags extends rcube_plugin
|
|||
return $args;
|
||||
}
|
||||
|
||||
if ($this->rc->action == 'print') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->mail_headers_done = true;
|
||||
|
||||
if ($engine = $this->engine()) {
|
||||
|
|
|
@ -278,6 +278,12 @@ class kolab_tags_engine
|
|||
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 @@ class kolab_tags_engine
|
|||
*/
|
||||
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();
|
||||
|
|
|
@ -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 @@ class kolab_storage
|
|||
*
|
||||
* @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 @@ class kolab_storage
|
|||
|
||||
/**
|
||||
* 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 @@ class kolab_storage
|
|||
*/
|
||||
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 @@ class kolab_storage
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found && !empty($namespace['other'])) {
|
||||
foreach ($namespace['other'] as $ns) {
|
||||
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
|
||||
|
@ -605,6 +644,7 @@ class kolab_storage
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found && !empty($namespace['personal'])) {
|
||||
foreach ($namespace['personal'] as $ns) {
|
||||
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
|
||||
|
@ -634,22 +674,6 @@ class kolab_storage
|
|||
return $folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom display name (saved in metadata) for the given folder
|
||||
*/
|
||||
public static function custom_displayname($folder)
|
||||
{
|
||||
// find custom display name in folder METADATA
|
||||
if (self::$config->get('kolab_custom_display_names', true)) {
|
||||
$metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED));
|
||||
if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to generate a truncated folder name to display.
|
||||
* Note: $origname is a string returned by self::object_name()
|
||||
|
@ -745,7 +769,7 @@ class kolab_storage
|
|||
}
|
||||
}
|
||||
|
||||
$names[$name] = self::object_name($name);
|
||||
$names[$name] = $c_folder->get_name();
|
||||
}
|
||||
|
||||
// Build SELECT field of parent folder
|
||||
|
@ -958,16 +982,16 @@ class kolab_storage
|
|||
$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 @@ class kolab_storage
|
|||
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 @@ class kolab_storage
|
|||
$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 @@ class kolab_storage
|
|||
$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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 @@ class kolab_storage_cache
|
|||
/**
|
||||
* 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 @@ class kolab_storage_cache
|
|||
$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 @@ class kolab_storage_cache
|
|||
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;
|
||||
|
|
|
@ -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 @@ class kolab_storage_config
|
|||
/**
|
||||
* 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 @@ class kolab_storage_config
|
|||
}
|
||||
|
||||
// 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 @@ class kolab_storage_config
|
|||
*/
|
||||
public function is_enabled()
|
||||
{
|
||||
return $this->enabled;
|
||||
return $this->_init();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,6 +116,10 @@ class kolab_storage_config
|
|||
{
|
||||
$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 @@ class kolab_storage_config
|
|||
*/
|
||||
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 @@ class kolab_storage_config
|
|||
*/
|
||||
public function save(&$object, $type)
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
if (!$this->is_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -201,25 +211,27 @@ class kolab_storage_config
|
|||
/**
|
||||
* 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 @@ class kolab_storage_config
|
|||
*/
|
||||
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 @@ class kolab_storage_config
|
|||
/**
|
||||
* 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,11 +608,83 @@ class kolab_storage_config
|
|||
$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
|
||||
*
|
||||
|
@ -650,12 +743,10 @@ class kolab_storage_config
|
|||
* 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 @@ class kolab_storage_config
|
|||
// 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 @@ class kolab_storage_config
|
|||
* 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 @@ class kolab_storage_config
|
|||
}
|
||||
|
||||
/**
|
||||
* 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 @@ class kolab_storage_config
|
|||
}
|
||||
// no changes, we're happy
|
||||
else {
|
||||
$done = true;
|
||||
$done = true;
|
||||
$links = array();
|
||||
}
|
||||
}
|
||||
|
@ -780,10 +875,10 @@ class kolab_storage_config
|
|||
'category' => 'generic',
|
||||
);
|
||||
|
||||
$ret = $this->save($relation, 'relation');
|
||||
$done = $this->save($relation, 'relation');
|
||||
}
|
||||
|
||||
return $ret;
|
||||
return $done;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -798,7 +893,7 @@ class kolab_storage_config
|
|||
array('member', '=', $uid),
|
||||
);
|
||||
|
||||
return $this->get_objects($filter, $default, 100);
|
||||
return $this->get_objects($filter, $default, self::MAX_RELATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -862,7 +957,7 @@ class kolab_storage_config
|
|||
// 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 @@ class kolab_storage_config
|
|||
/**
|
||||
* 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'];
|
||||
|
|
|
@ -64,15 +64,16 @@ class kolab_storage_folder extends kolab_storage_folder_api
|
|||
*/
|
||||
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 @@ class kolab_storage_folder extends kolab_storage_folder_api
|
|||
{
|
||||
// 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 @@ class kolab_storage_folder extends kolab_storage_folder_api
|
|||
if ($length !== null) {
|
||||
$this->cache->set_limit($length, $offset);
|
||||
}
|
||||
|
||||
$this->order_and_limit = array(
|
||||
'cols' => $sortcols,
|
||||
'limit' => $length,
|
||||
'offset' => $offset,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -375,7 +382,6 @@ class kolab_storage_folder extends kolab_storage_folder_api
|
|||
return $query;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a single Kolab object, identified by its UID
|
||||
*
|
||||
|
@ -387,17 +393,35 @@ class kolab_storage_folder extends kolab_storage_folder_api
|
|||
*/
|
||||
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 @@ class kolab_storage_folder extends kolab_storage_folder_api
|
|||
$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 @@ class kolab_storage_folder extends kolab_storage_folder_api
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ abstract class kolab_storage_folder_api
|
|||
* @var array
|
||||
*/
|
||||
public $children = array();
|
||||
|
||||
|
||||
/**
|
||||
* Name of the parent folder
|
||||
* @var string
|
||||
|
@ -69,6 +69,7 @@ abstract class kolab_storage_folder_api
|
|||
protected $info;
|
||||
protected $idata;
|
||||
protected $namespace;
|
||||
protected $metadata;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -135,10 +136,10 @@ abstract class kolab_storage_folder_api
|
|||
{
|
||||
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 @@ abstract class kolab_storage_folder_api
|
|||
*/
|
||||
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 @@ abstract class kolab_storage_folder_api
|
|||
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 @@ abstract class kolab_storage_folder_api
|
|||
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 @@ abstract class kolab_storage_folder_api
|
|||
*/
|
||||
public function set_metadata($entries)
|
||||
{
|
||||
$this->metadata = null;
|
||||
return $this->imap->set_metadata($this->name, $entries);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -277,6 +278,21 @@ abstract class kolab_storage_folder_api
|
|||
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 @@ abstract class kolab_storage_folder_api
|
|||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual
|
|||
*/
|
||||
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 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual
|
|||
*/
|
||||
public function get_title()
|
||||
{
|
||||
return trim($this->ldaprec['displayname'] . '; ' . $this->ldaprec['mail'], '; ');
|
||||
return trim($this->ldaprec['displayname'] . '; ' . $this->ldaprec['mail'], '; ');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,5 +131,4 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual
|
|||
|
||||
return $success;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,4 +56,4 @@ class kolab_storage_folder_virtual extends kolab_storage_folder_api
|
|||
{
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
// 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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
$this->folders[$tasklist['id']] = $folder;
|
||||
$this->folders[$folder->name] = $folder;
|
||||
}
|
||||
|
||||
return $this->lists;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,6 +166,8 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
($prop['active'] ? kolab_storage::folder_activate($subfolder) : kolab_storage::folder_deactivate($subfolder));
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -400,10 +407,11 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
$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);
|
||||
|
||||
// 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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
$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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
return array($uid, $mailbox, $msguid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of pending alarms to be displayed to the user
|
||||
*
|
||||
|
@ -938,7 +958,13 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
$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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
'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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
private function _from_rcube_task($task, $old = array())
|
||||
{
|
||||
$object = $task;
|
||||
$object = $task;
|
||||
$id_prefix = $task['list'] . ':';
|
||||
|
||||
if (!empty($task['date'])) {
|
||||
|
@ -1372,7 +1393,7 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
|
||||
// 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 @@ class tasklist_kolab_driver extends tasklist_driver
|
|||
*/
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1256,8 +1256,8 @@ class tasklist extends rcube_plugin
|
|||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue