From b4ced09d2e91a7be0649aa4c7866b4f817fcffbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Br=C3=BCderli?= Date: Tue, 23 Oct 2012 15:05:38 +0200 Subject: [PATCH 01/15] Make use of libkolab/libcalendaring PHP bindings for computing recurring events --- .../calendar/drivers/kolab/kolab_calendar.php | 10 +- .../libkolab/lib/kolab_date_recurrence.php | 107 ++++-------------- plugins/libkolab/lib/kolab_format_event.php | 10 ++ plugins/libkolab/lib/kolab_storage_cache.php | 4 +- 4 files changed, 46 insertions(+), 85 deletions(-) diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php index e20133e1..a62eb549 100644 --- a/plugins/calendar/drivers/kolab/kolab_calendar.php +++ b/plugins/calendar/drivers/kolab/kolab_calendar.php @@ -376,7 +376,15 @@ class kolab_calendar */ public function _get_recurring_events($event, $start, $end, $event_id = null) { - $recurrence = new kolab_date_recurrence($event); + $object = $event['_formatobj']; + if (!$object) { + $rec = $this->storage->get_object($event['id']); + $object = $rec['_formatobj']; + } + if (!is_object($object)) + return array(); + + $recurrence = new kolab_date_recurrence($object); $i = 0; $events = array(); diff --git a/plugins/libkolab/lib/kolab_date_recurrence.php b/plugins/libkolab/lib/kolab_date_recurrence.php index 427f62ac..2e883d08 100644 --- a/plugins/libkolab/lib/kolab_date_recurrence.php +++ b/plugins/libkolab/lib/kolab_date_recurrence.php @@ -3,7 +3,8 @@ /** * Recurrence computation class for xcal-based Kolab format objects * - * Uitility class to compute instances of recurring events. + * Utility class to compute instances of recurring events. + * It requires the libcalendaring PHP module to be installed and loaded. * * @version @package_version@ * @author Thomas Bruederli @@ -25,14 +26,11 @@ */ class kolab_date_recurrence { - private $engine; - private $object; - private $next; - private $duration; - private $tz_offset = 0; - private $dst_start = 0; - private $allday = false; - private $hour = 0; + private /* EventCal */ $engine; + private /* kolab_format_xcal */ $object; + private /* DateTime */ $start; + private /* DateTime */ $next; + private /* DateInterval */ $duration; /** * Default constructor @@ -41,27 +39,16 @@ class kolab_date_recurrence */ function __construct($object) { + $data = $object->to_array(); + $this->object = $object; - $this->next = new Horde_Date($object['start'], kolab_format::$timezone->getName()); + $this->engine = $object->to_libcal(); + $this->start = $this->next = $data['start']; - if (is_object($object['start']) && is_object($object['end'])) - $this->duration = $object['start']->diff($object['end']); + if (is_object($data['start']) && is_object($data['end'])) + $this->duration = $data['start']->diff($data['end']); else - $this->duration = new DateInterval('PT' . ($object['end'] - $object['start']) . 'S'); - - // use (copied) Horde classes to compute recurring instances - // TODO: replace with something that has less than 6'000 lines of code - $this->engine = new Horde_Date_Recurrence($this->next); - $this->engine->fromRRule20($this->to_rrule($object['recurrence'])); // TODO: get that string directly from libkolabxml - - foreach ((array)$object['recurrence']['EXDATE'] as $exdate) - $this->engine->addException($exdate->format('Y'), $exdate->format('n'), $exdate->format('j')); - - $now = new DateTime('now', kolab_format::$timezone); - $this->tz_offset = $object['allday'] ? $now->getOffset() - date('Z') : 0; - $this->dst_start = $this->next->format('I'); - $this->allday = $object['allday']; - $this->hour = $this->next->hour; + $this->duration = new DateInterval('PT' . ($data['end'] - $data['start']) . 'S'); } /** @@ -73,20 +60,13 @@ class kolab_date_recurrence public function next_start($timestamp = false) { $time = false; - if ($this->next && ($next = $this->engine->nextActiveRecurrence(array('year' => $this->next->year, 'month' => $this->next->month, 'mday' => $this->next->mday + 1, 'hour' => $this->next->hour, 'min' => $this->next->min, 'sec' => $this->next->sec)))) { - if ($this->allday) { - $next->hour = $this->hour; # fix time for all-day events - $next->min = 0; + + if ($this->engine && $this->next) { + $cstart = kolab_format::get_datetime($this->next); + if ($next = kolab_format::php_datetime(new cDateTime($this->engine->getNextOccurence($cstart)))) { + $time = $timestamp ? $next->format('U') : $next; + $this->next = $next; } - if ($timestamp) { - # consider difference in daylight saving between base event and recurring instance - $dst_diff = ($this->dst_start - $next->format('I')) * 3600; - $time = $next->timestamp() - $this->tz_offset - $dst_diff; - } - else { - $time = $next->toDateTime(); - } - $this->next = $next; } return $time; @@ -103,7 +83,7 @@ class kolab_date_recurrence $next_end = clone $next_start; $next_end->add($this->duration); - $next = $this->object; + $next = $this->object->to_array(); $next['recurrence_id'] = $next_start->format('Y-m-d'); $next['start'] = $next_start; $next['end'] = $next_end; @@ -123,49 +103,12 @@ class kolab_date_recurrence */ public function end($limit = 'now +1 year') { - if ($this->object['recurrence']['UNTIL']) - return $this->object['recurrence']['UNTIL']->format('U'); - - $limit_time = strtotime($limit); - while ($next_start = $this->next_start(true)) { - if ($next_start > $limit_time) - break; - } - - if ($this->next) { - $next_end = $this->next->toDateTime(); - $next_end->add($this->duration); - return $next_end->format('U'); + $limit_dt = new DateTime($limit); + $cstart = kolab_format::get_datetime($this->start); + if ($this->engine && ($cend = $this->engine->getOccurenceEndDate($cstart)) && ($end_dt = kolab_format::php_datetime(new cDateTime($cend))) && $end_dt < $limit_dt) { + return $end_dt->format('U'); } return false; } - - /** - * Convert the internal structured data into a vcalendar RRULE 2.0 string - */ - private function to_rrule($recurrence) - { - if (is_string($recurrence)) - return $recurrence; - - $rrule = ''; - foreach ((array)$recurrence as $k => $val) { - $k = strtoupper($k); - switch ($k) { - case 'UNTIL': - $val = $val->format('Ymd\THis'); - break; - case 'EXDATE': - foreach ((array)$val as $i => $ex) - $val[$i] = $ex->format('Ymd\THis'); - $val = join(',', (array)$val); - break; - } - $rrule .= $k . '=' . $val . ';'; - } - - return $rrule; - } - } diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php index 33ed5af3..4e790f2b 100644 --- a/plugins/libkolab/lib/kolab_format_event.php +++ b/plugins/libkolab/lib/kolab_format_event.php @@ -51,6 +51,16 @@ class kolab_format_event extends kolab_format_xcal $this->xmldata = $xmldata; } + /** + * Clones into an instance of libcalendaring's extended EventCal class + * + * @return mixed EventCal object or false on failure + */ + public function to_libcal() + { + return class_exists('kolabcalendaring') ? new EventCal($this->obj) : false; + } + /** * Set event properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php index c3e88da8..866a7950 100644 --- a/plugins/libkolab/lib/kolab_storage_cache.php +++ b/plugins/libkolab/lib/kolab_storage_cache.php @@ -517,8 +517,8 @@ class kolab_storage_cache $sql_data['dtend'] = date('Y-m-d H:i:s', is_object($object['end']) ? $object['end']->format('U') : $object['end']); // extend date range for recurring events - if ($object['recurrence']) { - $recurrence = new kolab_date_recurrence($object); + if ($object['recurrence'] && $object['_formatobj']) { + $recurrence = new kolab_date_recurrence($object['_formatobj']); $sql_data['dtend'] = date('Y-m-d 23:59:59', $recurrence->end() ?: strtotime('now +1 year')); } } From 06e6c43db027cb6539d5eb417322aff556a5f3a7 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 31 Oct 2012 14:01:54 +0100 Subject: [PATCH 02/15] Use the right library function to get the last occurence of a recurrence chain --- plugins/libkolab/lib/kolab_date_recurrence.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/libkolab/lib/kolab_date_recurrence.php b/plugins/libkolab/lib/kolab_date_recurrence.php index 2e883d08..0df96e0d 100644 --- a/plugins/libkolab/lib/kolab_date_recurrence.php +++ b/plugins/libkolab/lib/kolab_date_recurrence.php @@ -104,8 +104,7 @@ class kolab_date_recurrence public function end($limit = 'now +1 year') { $limit_dt = new DateTime($limit); - $cstart = kolab_format::get_datetime($this->start); - if ($this->engine && ($cend = $this->engine->getOccurenceEndDate($cstart)) && ($end_dt = kolab_format::php_datetime(new cDateTime($cend))) && $end_dt < $limit_dt) { + if ($this->engine && ($cend = $this->engine->getLastOccurrence()) && ($end_dt = kolab_format::php_datetime(new cDateTime($cend))) && $end_dt < $limit_dt) { return $end_dt->format('U'); } From d55e56c07ca04bbe642e9b60c095c7938a16d424 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 1 Nov 2012 20:06:09 +0100 Subject: [PATCH 03/15] Use new libkolab XML object reading/writing functions in preparation of adding Kolab format v2 capabilities --- plugins/libkolab/lib/kolab_format.php | 92 +++++++++++++++++-- .../lib/kolab_format_configuration.php | 7 +- plugins/libkolab/lib/kolab_format_contact.php | 10 +- .../lib/kolab_format_distributionlist.php | 11 +-- plugins/libkolab/lib/kolab_format_event.php | 24 ++--- plugins/libkolab/lib/kolab_format_journal.php | 11 +-- plugins/libkolab/lib/kolab_format_note.php | 11 +-- plugins/libkolab/lib/kolab_format_task.php | 11 +-- plugins/libkolab/lib/kolab_storage.php | 2 + plugins/libkolab/lib/kolab_storage_folder.php | 40 +++----- 10 files changed, 127 insertions(+), 92 deletions(-) diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index 23246d32..bedee440 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -31,38 +31,59 @@ abstract class kolab_format public /*abstract*/ $CTYPE; + protected /*abstract*/ $objclass; protected /*abstract*/ $read_func; protected /*abstract*/ $write_func; protected $obj; protected $data; protected $xmldata; + protected $xmlobject; protected $loaded = false; + protected $version = 3.0; - const VERSION = '3.0'; const KTYPE_PREFIX = 'application/x-vnd.kolab.'; + const PRODUCT_ID = 'Roundcube-libkolab-0.9'; /** - * Factory method to instantiate a kolab_format object of the given type + * Factory method to instantiate a kolab_format object of the given type and version * * @param string Object type to instantiate * @param string Cached xml data to initialize with + * @param float Format version * @return object kolab_format */ - public static function factory($type, $xmldata = null) + public static function factory($type, $xmldata = null, $version = 3.0) { if (!isset(self::$timezone)) self::$timezone = new DateTimeZone('UTC'); + if (!self::supports($version)) + return PEAR::raiseError("No support for Kolab format version " . $version); + $type = preg_replace('/configuration\.[a-z.]+$/', 'configuration', $type); $suffix = preg_replace('/[^a-z]+/', '', $type); $classname = 'kolab_format_' . $suffix; if (class_exists($classname)) - return new $classname($xmldata); + return new $classname($xmldata, $version); return PEAR::raiseError("Failed to load Kolab Format wrapper for type " . $type); } + /** + * Determine support for the given format version + * + * @param float Format version to check + * @return boolean True if supported, False otherwise + */ + public static function supports($version) + { + if ($version == 2.0) + return class_exists('kolabobject'); + // default is version 3 + return class_exists('kolabformat'); + } + /** * Convert the given date/time value into a cDateTime object * @@ -184,6 +205,23 @@ abstract class kolab_format return preg_replace('/dictionary.[a-z.]+$/', 'dictionary', substr($x_kolab_type, strlen(self::KTYPE_PREFIX))); } + + /** + * Default constructor of all kolab_format_* objects + */ + public function __construct($xmldata = null, $version = null) + { + $this->obj = new $this->objclass; + $this->xmldata = $xmldata; + + if ($version) + $this->version = $version; + + // use libkolab module if available + if (class_exists('kolabobject')) + $this->xmlobject = new XMLObject(); + } + /** * Check for format errors after calling kolabformat::write*() * @@ -245,6 +283,39 @@ abstract class kolab_format } } + /** + * Get constant value for libkolab's version parameter + * + * @param float Version value to convert + * @return int Constant value of either kolabobject::KolabV2 or kolabobject::KolabV3 or false if kolabobject module isn't available + */ + protected function libversion($v = null) + { + if (class_exists('kolabobject')) { + $version = $v ?: $this->version; + if ($version <= 2.0) + return kolabobject::KolabV2; + else + return kolabobject::KolabV3; + } + + return false; + } + + /** + * Determine the correct libkolab(xml) wrapper function for the given call + * depending on the available PHP modules + */ + protected function libfunc($func) + { + if (is_array($func) || strpos($func, '::')) + return $func; + else if (class_exists('kolabobject')) + return array($this->xmlobject, $func); + else + return 'kolabformat::' . $func; + } + /** * Direct getter for object properties */ @@ -257,22 +328,29 @@ abstract class kolab_format * Load Kolab object data from the given XML block * * @param string XML data + * @return boolean True on success, False on failure */ public function load($xml) { - $this->obj = call_user_func($this->read_func, $xml, false); + $r = call_user_func($this->libfunc($this->read_func), $xml, $this->libversion()); + if (is_resource($r)) + $this->obj = new $this->objclass($r); + else if (is_a($r, $this->objclass)) + $this->obj = $r; + $this->loaded = !$this->format_errors(); } /** * Write object data to XML format * + * @param float Format version to write * @return string XML data */ - public function write() + public function write($version = null) { $this->init(); - $this->xmldata = call_user_func($this->write_func, $this->obj); + $this->xmldata = call_user_func($this->libfunc($this->write_func), $this->obj, $this->libversion($version), self::PRODUCT_ID); if (!$this->format_errors()) $this->update_uid(); diff --git a/plugins/libkolab/lib/kolab_format_configuration.php b/plugins/libkolab/lib/kolab_format_configuration.php index 974fc453..1bb919d3 100644 --- a/plugins/libkolab/lib/kolab_format_configuration.php +++ b/plugins/libkolab/lib/kolab_format_configuration.php @@ -26,6 +26,7 @@ class kolab_format_configuration extends kolab_format { public $CTYPE = 'application/x-vnd.kolab.configuration'; + protected $objclass = 'Configuration'; protected $read_func = 'kolabformat::readConfiguration'; protected $write_func = 'kolabformat::writeConfiguration'; @@ -35,12 +36,6 @@ class kolab_format_configuration extends kolab_format ); - function __construct($xmldata = null) - { - $this->obj = new Configuration; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php index ffef059d..bae5fa33 100644 --- a/plugins/libkolab/lib/kolab_format_contact.php +++ b/plugins/libkolab/lib/kolab_format_contact.php @@ -26,8 +26,9 @@ class kolab_format_contact extends kolab_format { public $CTYPE = 'application/vcard+xml'; - protected $read_func = 'kolabformat::readContact'; - protected $write_func = 'kolabformat::writeContact'; + protected $objclass = 'Contact'; + protected $read_func = 'readContact'; + protected $write_func = 'writeContact'; public static $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'email'); @@ -106,10 +107,9 @@ class kolab_format_contact extends kolab_format /** * Default constructor */ - function __construct($xmldata = null) + function __construct($xmldata = null, $version = 3.0) { - $this->obj = new Contact; - $this->xmldata = $xmldata; + parent::__construct($xmldata, $version); // complete phone types $this->phonetypes['homefax'] |= Telephone::Home; diff --git a/plugins/libkolab/lib/kolab_format_distributionlist.php b/plugins/libkolab/lib/kolab_format_distributionlist.php index fcb94c14..6def48fd 100644 --- a/plugins/libkolab/lib/kolab_format_distributionlist.php +++ b/plugins/libkolab/lib/kolab_format_distributionlist.php @@ -26,16 +26,11 @@ class kolab_format_distributionlist extends kolab_format { public $CTYPE = 'application/vcard+xml'; - protected $read_func = 'kolabformat::readDistlist'; - protected $write_func = 'kolabformat::writeDistlist'; + protected $objclass = 'DistList'; + protected $read_func = 'readDistlist'; + protected $write_func = 'writeDistlist'; - function __construct($xmldata = null) - { - $this->obj = new DistList; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php index 4e790f2b..b2cb87b9 100644 --- a/plugins/libkolab/lib/kolab_format_event.php +++ b/plugins/libkolab/lib/kolab_format_event.php @@ -24,8 +24,9 @@ class kolab_format_event extends kolab_format_xcal { - protected $read_func = 'kolabformat::readEvent'; - protected $write_func = 'kolabformat::writeEvent'; + protected $objclass = 'Event'; + protected $read_func = 'readEvent'; + protected $write_func = 'writeEvent'; private $kolab2_rolemap = array( 'required' => 'REQ-PARTICIPANT', @@ -43,24 +44,15 @@ class kolab_format_event extends kolab_format_xcal /** - * Default constructor + * Clones into an instance of libcalendaring's extended EventCal class + * + * @return mixed EventCal object or false on failure */ - function __construct($xmldata = null) + public function to_libcal() { - $this->obj = new Event; - $this->xmldata = $xmldata; + return class_exists('kolabcalendaring') ? new EventCal($this->obj) : false; } - /** - * Clones into an instance of libcalendaring's extended EventCal class - * - * @return mixed EventCal object or false on failure - */ - public function to_libcal() - { - return class_exists('kolabcalendaring') ? new EventCal($this->obj) : false; - } - /** * Set event properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_journal.php b/plugins/libkolab/lib/kolab_format_journal.php index 5869af09..0e1b4743 100644 --- a/plugins/libkolab/lib/kolab_format_journal.php +++ b/plugins/libkolab/lib/kolab_format_journal.php @@ -26,16 +26,11 @@ class kolab_format_journal extends kolab_format { public $CTYPE = 'application/calendar+xml'; - protected $read_func = 'kolabformat::readJournal'; - protected $write_func = 'kolabformat::writeJournal'; + protected $objclass = 'Journal'; + protected $read_func = 'readJournal'; + protected $write_func = 'writeJournal'; - function __construct($xmldata = null) - { - $this->obj = new Journal; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_note.php b/plugins/libkolab/lib/kolab_format_note.php index 1c88a8bb..482a3e8f 100644 --- a/plugins/libkolab/lib/kolab_format_note.php +++ b/plugins/libkolab/lib/kolab_format_note.php @@ -26,16 +26,11 @@ class kolab_format_note extends kolab_format { public $CTYPE = 'application/x-vnd.kolab.note'; - protected $read_func = 'kolabformat::readNote'; - protected $write_func = 'kolabformat::writeNote'; + protected $objclass = 'Note'; + protected $read_func = 'readNote'; + protected $write_func = 'writeNote'; - function __construct($xmldata = null) - { - $this->obj = new Note; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_task.php b/plugins/libkolab/lib/kolab_format_task.php index 2a7a629f..425f5e06 100644 --- a/plugins/libkolab/lib/kolab_format_task.php +++ b/plugins/libkolab/lib/kolab_format_task.php @@ -24,16 +24,11 @@ class kolab_format_task extends kolab_format_xcal { - protected $read_func = 'kolabformat::readTodo'; - protected $write_func = 'kolabformat::writeTodo'; + protected $objclass = 'Todo'; + protected $read_func = 'readTodo'; + protected $write_func = 'writeTodo'; - function __construct($xmldata = null) - { - $this->obj = new Todo; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php index 12419340..ac7de34b 100644 --- a/plugins/libkolab/lib/kolab_storage.php +++ b/plugins/libkolab/lib/kolab_storage.php @@ -31,6 +31,7 @@ class kolab_storage const SERVERSIDE_SUBSCRIPTION = 0; const CLIENTSIDE_SUBSCRIPTION = 1; + public static $version = 3.0; public static $last_error; private static $ready = false; @@ -49,6 +50,7 @@ class kolab_storage $rcmail = rcube::get_instance(); self::$config = $rcmail->config; + self::$version = $rcmail->config->get('kolab_format_version', self::$version); self::$imap = $rcmail->get_storage(); self::$ready = class_exists('kolabformat') && (self::$imap->get_capability('METADATA') || self::$imap->get_capability('ANNOTATEMORE') || self::$imap->get_capability('ANNOTATEMORE2')); diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index 08bf6690..e92a6fae 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -466,39 +466,27 @@ class kolab_storage_folder return false; } - $format = kolab_format::factory($object_type); - - if (is_a($format, 'PEAR_Error')) - return false; - // check kolab format version - $mime_version = $headers->others['x-kolab-mime-version']; - if (empty($mime_version)) { + $format_version = $headers->others['x-kolab-mime-version']; + if (empty($format_version)) { list($xmltype, $subtype) = explode('.', $object_type); $xmlhead = substr($xml, 0, 512); // detect old Kolab 2.0 format if (strpos($xmlhead, '<' . $xmltype) !== false && strpos($xmlhead, 'xmlns=') === false) - $mime_version = 2.0; + $format_version = 2.0; else - $mime_version = 3.0; // assume 3.0 + $format_version = 3.0; // assume 3.0 } - if ($mime_version <= 2.0) { - // read Kolab 2.0 format - $handler = class_exists('Horde_Kolab_Format') ? Horde_Kolab_Format::factory('XML', $xmltype, array('subtype' => $subtype)) : null; - if (!is_object($handler) || is_a($handler, 'PEAR_Error')) { - return false; - } + // get Kolab format handler for the given type + $format = kolab_format::factory($object_type, $format_version); - // XML-to-array - $object = $handler->load($xml); - $format->fromkolab2($object); - } - else { - // load Kolab 3 format using libkolabxml - $format->load($xml); - } + if (is_a($format, 'PEAR_Error')) + return false; + + // load Kolab object from XML part + $format->load($xml); if ($format->is_valid()) { $object = $format->to_array(); @@ -696,13 +684,13 @@ class kolab_storage_folder // create new kolab_format instance if (!$format) - $format = kolab_format::factory($type); + $format = kolab_format::factory($type, kolab_storage::$version); if (PEAR::isError($format)) return false; $format->set($object); - $xml = $format->write(); + $xml = $format->write(kolab_storage::$version); $object['uid'] = $format->uid; // read UID from format $object['_formatobj'] = $format; @@ -721,7 +709,7 @@ class kolab_storage_folder } $headers['Date'] = date('r'); $headers['X-Kolab-Type'] = kolab_format::KTYPE_PREFIX . $type; - $headers['X-Kolab-Mime-Version'] = kolab_format::VERSION; + $headers['X-Kolab-Mime-Version'] = kolab_storage::$version; $headers['Subject'] = $object['uid']; // $headers['Message-ID'] = $rcmail->gen_message_id(); $headers['User-Agent'] = $rcmail->config->get('useragent'); From 50b3b8e766ca081f492521a4f502284e139c8915 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 2 Nov 2012 13:45:05 +0100 Subject: [PATCH 04/15] Use different signatures for libkolab/libkolabxml function calls --- plugins/libkolab/lib/kolab_format.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index bedee440..760133ba 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -350,7 +350,11 @@ abstract class kolab_format public function write($version = null) { $this->init(); - $this->xmldata = call_user_func($this->libfunc($this->write_func), $this->obj, $this->libversion($version), self::PRODUCT_ID); + $write_func = $this->libfunc($this->write_func); + if (is_array($write_func)) + $this->xmldata = call_user_func($write_func, $this->obj, $this->libversion($version), self::PRODUCT_ID); + else + $this->xmldata = call_user_func($write_func, $this->obj, self::PRODUCT_ID); if (!$this->format_errors()) $this->update_uid(); From dbe7352ce100eb6c8d6619d68fe9b6a81b029112 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 2 Nov 2012 13:46:00 +0100 Subject: [PATCH 05/15] Fix default config folder selection (list is not indexed anymore) --- plugins/kolab_config/kolab_config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kolab_config/kolab_config.php b/plugins/kolab_config/kolab_config.php index 4fe8a7f3..23188cf6 100644 --- a/plugins/kolab_config/kolab_config.php +++ b/plugins/kolab_config/kolab_config.php @@ -77,7 +77,7 @@ class kolab_config extends rcube_plugin // if no folder is set as default, choose the first one if (!$this->default) - $this->default = $this->folders[0]; + $this->default = reset($this->folders); // check if configuration folder exist if ($this->default && $this->default->name) { From dd2bf15adf7e39612df9548095ac1ed8cafb33a1 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 2 Nov 2012 15:04:59 +0100 Subject: [PATCH 06/15] Also use different signatures when calling libkolab(xml) read functions --- plugins/libkolab/lib/kolab_format.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index 760133ba..08dc9626 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -332,7 +332,12 @@ abstract class kolab_format */ public function load($xml) { - $r = call_user_func($this->libfunc($this->read_func), $xml, $this->libversion()); + $read_func = $this->libfunc($this->read_func); + if (is_array($read_func)) + $r = call_user_func($read_func, $xml, $this->libversion()); + else + $r = call_user_func($read_func, $xml, false); + if (is_resource($r)) $this->obj = new $this->objclass($r); else if (is_a($r, $this->objclass)) From d98e8787c6b74bf26e9eec8df807435d455af990 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Tue, 6 Nov 2012 19:03:12 +0100 Subject: [PATCH 07/15] Fix kolab_format_* classes to read v2 format; perpare kolab_storage to write out v2 format --- plugins/libkolab/config.inc.php.dist | 1 + plugins/libkolab/lib/kolab_format.php | 28 ++++++++++--------- .../lib/kolab_format_configuration.php | 9 +++--- plugins/libkolab/lib/kolab_format_contact.php | 1 + .../lib/kolab_format_distributionlist.php | 1 + plugins/libkolab/lib/kolab_format_event.php | 2 ++ plugins/libkolab/lib/kolab_format_journal.php | 1 + plugins/libkolab/lib/kolab_format_note.php | 1 + plugins/libkolab/lib/kolab_format_task.php | 2 ++ plugins/libkolab/lib/kolab_storage_cache.php | 2 +- plugins/libkolab/lib/kolab_storage_folder.php | 3 +- 11 files changed, 32 insertions(+), 19 deletions(-) diff --git a/plugins/libkolab/config.inc.php.dist b/plugins/libkolab/config.inc.php.dist index fedf7936..cb446523 100644 --- a/plugins/libkolab/config.inc.php.dist +++ b/plugins/libkolab/config.inc.php.dist @@ -2,6 +2,7 @@ /* Configuration for libkolab */ $rcmail_config['kolab_cache'] = true; + $rcmail_config['kolab_format_version'] = 3.0; $rcmail_config['kolab_freebusy_server'] = 'https://' . $_SESSION['imap_host'] . '/freebusy'; $rcmail_config['kolab_ssl_verify_peer'] = true; diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index 08dc9626..c54558eb 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -30,6 +30,7 @@ abstract class kolab_format public static $timezone; public /*abstract*/ $CTYPE; + public /*abstract*/ $CTYPEv2; protected /*abstract*/ $objclass; protected /*abstract*/ $read_func; @@ -49,11 +50,11 @@ abstract class kolab_format * Factory method to instantiate a kolab_format object of the given type and version * * @param string Object type to instantiate - * @param string Cached xml data to initialize with * @param float Format version + * @param string Cached xml data to initialize with * @return object kolab_format */ - public static function factory($type, $xmldata = null, $version = 3.0) + public static function factory($type, $version = 3.0, $xmldata = null) { if (!isset(self::$timezone)) self::$timezone = new DateTimeZone('UTC'); @@ -249,7 +250,7 @@ abstract class kolab_format 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, - 'message' => "kolabformat write $log: " . kolabformat::errorMessage(), + 'message' => "kolabformat $log: " . kolabformat::errorMessage(), ), true); } @@ -332,11 +333,12 @@ abstract class kolab_format */ public function load($xml) { - $read_func = $this->libfunc($this->read_func); - if (is_array($read_func)) - $r = call_user_func($read_func, $xml, $this->libversion()); - else - $r = call_user_func($read_func, $xml, false); + $read_func = $this->libfunc($this->read_func); + + if (is_array($read_func)) + $r = call_user_func($read_func, $xml, $this->libversion()); + else + $r = call_user_func($read_func, $xml, false); if (is_resource($r)) $this->obj = new $this->objclass($r); @@ -355,11 +357,11 @@ abstract class kolab_format public function write($version = null) { $this->init(); - $write_func = $this->libfunc($this->write_func); - if (is_array($write_func)) - $this->xmldata = call_user_func($write_func, $this->obj, $this->libversion($version), self::PRODUCT_ID); - else - $this->xmldata = call_user_func($write_func, $this->obj, self::PRODUCT_ID); + $write_func = $this->libfunc($this->write_func); + if (is_array($write_func)) + $this->xmldata = call_user_func($write_func, $this->obj, $this->libversion($version), self::PRODUCT_ID); + else + $this->xmldata = call_user_func($write_func, $this->obj, self::PRODUCT_ID); if (!$this->format_errors()) $this->update_uid(); diff --git a/plugins/libkolab/lib/kolab_format_configuration.php b/plugins/libkolab/lib/kolab_format_configuration.php index 1bb919d3..918928b2 100644 --- a/plugins/libkolab/lib/kolab_format_configuration.php +++ b/plugins/libkolab/lib/kolab_format_configuration.php @@ -25,10 +25,11 @@ class kolab_format_configuration extends kolab_format { public $CTYPE = 'application/x-vnd.kolab.configuration'; + public $CTYPEv2 = 'application/x-vnd.kolab.configuration'; protected $objclass = 'Configuration'; - protected $read_func = 'kolabformat::readConfiguration'; - protected $write_func = 'kolabformat::writeConfiguration'; + protected $read_func = 'readConfiguration'; + protected $write_func = 'writeConfiguration'; private $type_map = array( 'dictionary' => Configuration::TypeDictionary, @@ -69,7 +70,7 @@ class kolab_format_configuration extends kolab_format $this->obj->setCreated(self::get_datetime($object['created'])); // adjust content-type string - $this->CTYPE = 'application/x-vnd.kolab.configuration.' . $object['type']; + $this->CTYPE = $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type']; // cache this data $this->data = $object; @@ -121,7 +122,7 @@ class kolab_format_configuration extends kolab_format // adjust content-type string if ($object['type']) - $this->CTYPE = 'application/x-vnd.kolab.configuration.' . $object['type']; + $this->CTYPE = $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type']; $this->data = $object; return $this->data; diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php index bae5fa33..9dedcb1a 100644 --- a/plugins/libkolab/lib/kolab_format_contact.php +++ b/plugins/libkolab/lib/kolab_format_contact.php @@ -25,6 +25,7 @@ class kolab_format_contact extends kolab_format { public $CTYPE = 'application/vcard+xml'; + public $CTYPEv2 = 'application/x-vnd.kolab.contact'; protected $objclass = 'Contact'; protected $read_func = 'readContact'; diff --git a/plugins/libkolab/lib/kolab_format_distributionlist.php b/plugins/libkolab/lib/kolab_format_distributionlist.php index 6def48fd..ba54742b 100644 --- a/plugins/libkolab/lib/kolab_format_distributionlist.php +++ b/plugins/libkolab/lib/kolab_format_distributionlist.php @@ -25,6 +25,7 @@ class kolab_format_distributionlist extends kolab_format { public $CTYPE = 'application/vcard+xml'; + public $CTYPEv2 = 'application/x-vnd.kolab.distribution-list'; protected $objclass = 'DistList'; protected $read_func = 'readDistlist'; diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php index b2cb87b9..838f37df 100644 --- a/plugins/libkolab/lib/kolab_format_event.php +++ b/plugins/libkolab/lib/kolab_format_event.php @@ -24,6 +24,8 @@ class kolab_format_event extends kolab_format_xcal { + public $CTYPEv2 = 'application/x-vnd.kolab.event'; + protected $objclass = 'Event'; protected $read_func = 'readEvent'; protected $write_func = 'writeEvent'; diff --git a/plugins/libkolab/lib/kolab_format_journal.php b/plugins/libkolab/lib/kolab_format_journal.php index 0e1b4743..9144ea2d 100644 --- a/plugins/libkolab/lib/kolab_format_journal.php +++ b/plugins/libkolab/lib/kolab_format_journal.php @@ -25,6 +25,7 @@ class kolab_format_journal extends kolab_format { public $CTYPE = 'application/calendar+xml'; + public $CTYPEv2 = 'application/x-vnd.kolab.journal'; protected $objclass = 'Journal'; protected $read_func = 'readJournal'; diff --git a/plugins/libkolab/lib/kolab_format_note.php b/plugins/libkolab/lib/kolab_format_note.php index 482a3e8f..48e963e1 100644 --- a/plugins/libkolab/lib/kolab_format_note.php +++ b/plugins/libkolab/lib/kolab_format_note.php @@ -25,6 +25,7 @@ class kolab_format_note extends kolab_format { public $CTYPE = 'application/x-vnd.kolab.note'; + public $CTYPEv2 = 'application/x-vnd.kolab.note'; protected $objclass = 'Note'; protected $read_func = 'readNote'; diff --git a/plugins/libkolab/lib/kolab_format_task.php b/plugins/libkolab/lib/kolab_format_task.php index 425f5e06..0bfac3dd 100644 --- a/plugins/libkolab/lib/kolab_format_task.php +++ b/plugins/libkolab/lib/kolab_format_task.php @@ -24,6 +24,8 @@ class kolab_format_task extends kolab_format_xcal { + public $CTYPEv2 = 'application/x-vnd.kolab.task'; + protected $objclass = 'Todo'; protected $read_func = 'readTodo'; protected $write_func = 'writeTodo'; diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php index 866a7950..a800e58d 100644 --- a/plugins/libkolab/lib/kolab_storage_cache.php +++ b/plugins/libkolab/lib/kolab_storage_cache.php @@ -582,7 +582,7 @@ class kolab_storage_cache $object['_type'] = $sql_arr['type']; $object['_msguid'] = $sql_arr['msguid']; $object['_mailbox'] = $this->folder->name; - $object['_formatobj'] = kolab_format::factory($sql_arr['type'], $sql_arr['xml']); + $object['_formatobj'] = kolab_format::factory($sql_arr['type'], 3.0, $sql_arr['xml']); return $object; } diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index e92a6fae..54aed7a3 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -719,8 +719,9 @@ class kolab_storage_folder . 'To view this object you will need an email client that understands the Kolab Groupware format. ' . "For a list of such email clients please visit http://www.kolab.org/\n\n"); + $ctype = kolab_storage::$version == 2.0 ? $format->CTYPEv2 : $format->CTYPE; $mime->addAttachment($xml, // file - $format->CTYPE, // content-type + $ctype, // content-type 'kolab.xml', // filename false, // is_file '8bit', // encoding From 6d75fdd5f317d33d4f42208397de21e7fce47aed Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 8 Nov 2012 14:03:06 +0100 Subject: [PATCH 08/15] Quote object UID for IMAP SEARCH command; read generated UID from XMLObject if we're working with libkolab bindings --- plugins/libkolab/lib/kolab_format.php | 2 +- plugins/libkolab/lib/kolab_storage_cache.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index c54558eb..a4147812 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -265,7 +265,7 @@ abstract class kolab_format { // get generated UID if (!$this->data['uid']) { - $this->data['uid'] = kolabformat::getSerializedUID(); + $this->data['uid'] = $this->xmlobject ? $this->xmlobject->getSerializedUID() : kolabformat::getSerializedUID(); $this->obj->setUid($this->data['uid']); } } diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php index a800e58d..cdb373fd 100644 --- a/plugins/libkolab/lib/kolab_storage_cache.php +++ b/plugins/libkolab/lib/kolab_storage_cache.php @@ -717,7 +717,7 @@ class kolab_storage_cache { if (!isset($this->uid2msg[$uid])) { // use IMAP SEARCH to get the right message - $index = $this->imap->search_once($this->folder->name, ($deleted ? '' : 'UNDELETED ') . 'HEADER SUBJECT ' . $uid); + $index = $this->imap->search_once($this->folder->name, ($deleted ? '' : 'UNDELETED ') . 'HEADER SUBJECT "' . $uid. '"'); $results = $index->get(); $this->uid2msg[$uid] = $results[0]; } From dfb7fae98367bf59540aff43979539cfc1ff27d1 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 8 Nov 2012 14:07:01 +0100 Subject: [PATCH 09/15] Fix contact picture handling with Kolab format v2 --- plugins/libkolab/lib/kolab_format_contact.php | 2 ++ plugins/libkolab/lib/kolab_storage_folder.php | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php index 9dedcb1a..b147c384 100644 --- a/plugins/libkolab/lib/kolab_format_contact.php +++ b/plugins/libkolab/lib/kolab_format_contact.php @@ -379,6 +379,8 @@ class kolab_format_contact extends kolab_format if ($this->obj->photoMimetype()) $object['photo'] = $this->obj->photo(); + else if ($this->xmlobject && ($photo_name = $this->xmlobject->pictureAttachmentName())) + $object['photo'] = $photo_name; // relateds -> spouse, children $this->read_relateds($this->obj->relateds(), $object); diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index 54aed7a3..682ca7e8 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -540,13 +540,23 @@ class kolab_storage_folder unset($object['_attachments'][$key]); } // load photo.attachment from old Kolab2 format to be directly embedded in xcard block - else if ($key == 'photo.attachment' && !isset($object['photo']) && !$object['_attachments'][$key]['content'] && $att['id']) { - $object['photo'] = $this->get_attachment($object['_msguid'], $att['id'], $object['_mailbox']); + else if ($type == 'contact' && ($key == 'photo.attachment' || $key == 'kolab-picture.png') && $att['id']) { + if (!isset($object['photo'])) + $object['photo'] = $this->get_attachment($object['_msguid'], $att['id'], $object['_mailbox']); unset($object['_attachments'][$key]); } } } + // save contact photo to attachment for Kolab2 format + if (kolab_storage::$version == 2.0 && $object['photo'] && !$existing_photo) { + $attkey = 'kolab-picture.png'; // this file name is hard-coded in libkolab/kolabformatV2/contact.cpp + $object['_attachments'][$attkey] = array( + 'mimetype'=> rc_image_content_type($object['photo']), + 'content' => preg_match('![^a-z0-9/=+-]!i', $object['photo']) ? $object['photo'] : base64_decode($object['photo']), + ); + } + // generate unique keys (used as content-id) for attachments if (is_array($object['_attachments'])) { $numatt = count($object['_attachments']); From f91e6ed831da8cb1ac9c4d121ece42147b5ea87b Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 8 Nov 2012 14:41:37 +0100 Subject: [PATCH 10/15] Use generic escape() function to quote UIDs --- plugins/libkolab/lib/kolab_storage_cache.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php index cdb373fd..6d50bf9a 100644 --- a/plugins/libkolab/lib/kolab_storage_cache.php +++ b/plugins/libkolab/lib/kolab_storage_cache.php @@ -717,7 +717,8 @@ class kolab_storage_cache { if (!isset($this->uid2msg[$uid])) { // use IMAP SEARCH to get the right message - $index = $this->imap->search_once($this->folder->name, ($deleted ? '' : 'UNDELETED ') . 'HEADER SUBJECT "' . $uid. '"'); + $index = $this->imap->search_once($this->folder->name, ($deleted ? '' : 'UNDELETED ') . + 'HEADER SUBJECT ' . rcube_imap_generic::escape($uid)); $results = $index->get(); $this->uid2msg[$uid] = $results[0]; } From fa497d2dbbb4e87635c10651196f0a504e1a4f02 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 8 Nov 2012 15:41:23 +0100 Subject: [PATCH 11/15] Fix recurrence computation using libkolab bindings --- plugins/libkolab/lib/kolab_date_recurrence.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/libkolab/lib/kolab_date_recurrence.php b/plugins/libkolab/lib/kolab_date_recurrence.php index 0df96e0d..3aaa399f 100644 --- a/plugins/libkolab/lib/kolab_date_recurrence.php +++ b/plugins/libkolab/lib/kolab_date_recurrence.php @@ -30,6 +30,7 @@ class kolab_date_recurrence private /* kolab_format_xcal */ $object; private /* DateTime */ $start; private /* DateTime */ $next; + private /* cDateTime */ $cnext; private /* DateInterval */ $duration; /** @@ -44,6 +45,7 @@ class kolab_date_recurrence $this->object = $object; $this->engine = $object->to_libcal(); $this->start = $this->next = $data['start']; + $this->cnext = kolab_format::get_datetime($this->next); if (is_object($data['start']) && is_object($data['end'])) $this->duration = $data['start']->diff($data['end']); @@ -62,9 +64,10 @@ class kolab_date_recurrence $time = false; if ($this->engine && $this->next) { - $cstart = kolab_format::get_datetime($this->next); - if ($next = kolab_format::php_datetime(new cDateTime($this->engine->getNextOccurence($cstart)))) { + if (($cnext = new cDateTime($this->engine->getNextOccurence($this->cnext))) && $cnext->isValid()) { + $next = kolab_format::php_datetime($cnext); $time = $timestamp ? $next->format('U') : $next; + $this->cnext = $cnext; $this->next = $next; } } From 0c418da7908806a4ee89fad56a814fa7939c1175 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 8 Nov 2012 16:18:28 +0100 Subject: [PATCH 12/15] Don't set due time if dateonly --- plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php index 0f9d35d1..f6ebe14d 100644 --- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php +++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php @@ -548,7 +548,8 @@ class tasklist_kolab_driver extends tasklist_driver // convert from DateTime to internal date format if (is_a($record['due'], 'DateTime')) { $task['date'] = $record['due']->format('Y-m-d'); - $task['time'] = $record['due']->format('h:i'); + if (!$record['due']->_dateonly) + $task['time'] = $record['due']->format('h:i'); } // convert from DateTime to internal date format if (is_a($record['start'], 'DateTime')) { From 3cff4556329849bb8939c1c2de03362e42d13bad Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Thu, 8 Nov 2012 16:18:54 +0100 Subject: [PATCH 13/15] Ignore empty attachments from format v2 --- plugins/libkolab/lib/kolab_format_event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php index 838f37df..6094c6a3 100644 --- a/plugins/libkolab/lib/kolab_format_event.php +++ b/plugins/libkolab/lib/kolab_format_event.php @@ -147,7 +147,7 @@ class kolab_format_event extends kolab_format_xcal $attach = $vattach->get($i); // skip cid: attachments which are mime message parts handled by kolab_storage_folder - if (substr($attach->uri(), 0, 4) != 'cid') { + if (substr($attach->uri(), 0, 4) != 'cid' && $attach->label()) { $name = $attach->label(); $data = $attach->data(); $object['_attachments'][$name] = array( From 826f3f8ea39299a9c8e8cf105ec112ef32960c38 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 9 Nov 2012 13:55:57 +0100 Subject: [PATCH 14/15] Avoid endless loops in recurrence computation --- plugins/calendar/drivers/kolab/kolab_calendar.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php index a62eb549..c1c86268 100644 --- a/plugins/calendar/drivers/kolab/kolab_calendar.php +++ b/plugins/calendar/drivers/kolab/kolab_calendar.php @@ -409,6 +409,10 @@ class kolab_calendar } else if ($next_event['start'] > $end) // stop loop if out of range break; + + // avoid endless recursion loops + if ($i > 1000) + break; } return $events; From 79d71d07310fe88346cb22c33afebc04f336f33e Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 9 Nov 2012 13:57:54 +0100 Subject: [PATCH 15/15] Always use Kolab format v3 for caching --- plugins/libkolab/lib/kolab_storage_cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php index 6d50bf9a..9eac164e 100644 --- a/plugins/libkolab/lib/kolab_storage_cache.php +++ b/plugins/libkolab/lib/kolab_storage_cache.php @@ -534,7 +534,7 @@ class kolab_storage_cache } if ($object['_formatobj']) { - $sql_data['xml'] = preg_replace('!()[\n\r\t\s]+!ms', '$1', (string)$object['_formatobj']->write()); + $sql_data['xml'] = preg_replace('!()[\n\r\t\s]+!ms', '$1', (string)$object['_formatobj']->write(3.0)); $sql_data['tags'] = ' ' . join(' ', $object['_formatobj']->get_tags()) . ' '; // pad with spaces for strict/prefix search $sql_data['words'] = ' ' . join(' ', $object['_formatobj']->get_words()) . ' '; }