Branch 'roundcubemail-plugins-kolab-3.0' - 13 commits - plugins/calendar plugins/kolab_addressbook plugins/libcalendaring plugins/libkolab plugins/tasklist

Aleksander Machniak machniak at kolabsys.com
Fri Jun 21 11:02:27 CEST 2013


 plugins/calendar/drivers/database/database_driver.php  |    4 -
 plugins/calendar/drivers/kolab/kolab_calendar.php      |   60 ++++++++++++++---
 plugins/calendar/drivers/kolab/kolab_driver.php        |   35 ++++++---
 plugins/calendar/lib/calendar_ical.php                 |    3 
 plugins/calendar/lib/calendar_recurrence.php           |   31 +++++++-
 plugins/kolab_addressbook/lib/rcube_kolab_contacts.php |    4 -
 plugins/libcalendaring/libcalendaring.php              |   14 ++-
 plugins/libkolab/lib/kolab_format.php                  |   15 ++--
 plugins/libkolab/lib/kolab_storage.php                 |    2 
 plugins/libkolab/lib/kolab_storage_cache.php           |    1 
 plugins/libkolab/lib/kolab_storage_folder.php          |   19 ++++-
 plugins/tasklist/tasklist.js                           |    2 
 12 files changed, 142 insertions(+), 48 deletions(-)

New commits:
commit a1f14a3f8fde16f4bea094b309c3072eb4443f31
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Feb 21 13:04:00 2013 +0100

    Allow libcalendaring to work without output

diff --git a/plugins/libcalendaring/libcalendaring.php b/plugins/libcalendaring/libcalendaring.php
index 24f98cb..c78173b 100644
--- a/plugins/libcalendaring/libcalendaring.php
+++ b/plugins/libcalendaring/libcalendaring.php
@@ -84,14 +84,16 @@ class libcalendaring extends rcube_plugin
         $this->add_texts('localization/', false);
 
         // include client scripts and styles
-        $this->include_script('libcalendaring.js');
-        $this->rc->output->set_env('libcal_settings', $this->load_settings());
+        if ($this->rc->output) {
+            $this->include_script('libcalendaring.js');
+            $this->rc->output->set_env('libcal_settings', $this->load_settings());
 
-        $this->include_stylesheet($this->local_skin_path() . '/libcal.css');
+            $this->include_stylesheet($this->local_skin_path() . '/libcal.css');
 
-        // add hook to display alarms
-        $this->add_hook('refresh', array($this, 'refresh'));
-        $this->register_action('plugin.alarms', array($this, 'alarms_action'));
+            // add hook to display alarms
+            $this->add_hook('refresh', array($this, 'refresh'));
+            $this->register_action('plugin.alarms', array($this, 'alarms_action'));
+        }
     }
 
 


commit c6eb05eaa7af29a0cec0141ab48716185874a189
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Feb 21 11:18:59 2013 +0100

    Make some metadata from the Kolab storage backend available to the library user

diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php
index 6f6e16e..ef4dd22 100644
--- a/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_cache.php
@@ -591,6 +591,7 @@ class kolab_storage_cache
         $object['_type'] = $sql_arr['type'];
         $object['_msguid'] = $sql_arr['msguid'];
         $object['_mailbox'] = $this->folder->name;
+        $object['_size'] = strlen($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 23ea4e3..2811886 100644
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -51,6 +51,7 @@ class kolab_storage_folder
     private $type_annotation;
     private $imap;
     private $info;
+    private $idata;
     private $owner;
     private $resource_uri;
     private $uid2msg = array();
@@ -99,6 +100,16 @@ class kolab_storage_folder
         return $this->info;
     }
 
+    /**
+     * Make IMAP folder data available for this folder
+     */
+    public function get_imap_data()
+    {
+        if (!isset($this->idata))
+            $this->idata = $this->imap->folder_data($this->name);
+
+        return $this->idata;
+    }
 
     /**
      * Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION)


commit d8511c0429db91d5a9ffb1ab3c7e9b1a3a509f95
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Feb 20 21:03:44 2013 +0100

    Use generic getter for current user's email; also works in framework without session and user database record

diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
index 27517cf..23ea4e3 100644
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -776,9 +776,9 @@ class kolab_storage_folder
         $part_id  = 1;
         $encoding = $binary ? 'binary' : 'base64';
 
-        if ($ident = $rcmail->user->get_identity()) {
-            $headers['From'] = $ident['email'];
-            $headers['To'] = $ident['email'];
+        if ($user_email = $rcmail->get_user_email()) {
+            $headers['From'] = $user_email;
+            $headers['To'] = $user_email;
         }
         $headers['Date'] = date('r');
         $headers['X-Kolab-Type'] = kolab_format::KTYPE_PREFIX . $type;
@@ -820,7 +820,7 @@ class kolab_storage_folder
             false,                  // is_file
             '8bit',                 // encoding
             'attachment',           // disposition
-            RCUBE_CHARSET          // charset
+            RCUBE_CHARSET           // charset
         );
         $part_id++;
 


commit 3bd67d91fc2304a7b71028df26cecbc5b1e086cb
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Feb 20 09:56:13 2013 +0100

    Backport changes from dev/version_compare branch

diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php
index c0fb986..ccc7e46 100644
--- a/plugins/libkolab/lib/kolab_format.php
+++ b/plugins/libkolab/lib/kolab_format.php
@@ -41,7 +41,7 @@ abstract class kolab_format
     protected $xmldata;
     protected $xmlobject;
     protected $loaded = false;
-    protected $version = 3.0;
+    protected $version = '3.0';
 
     const KTYPE_PREFIX = 'application/x-vnd.kolab.';
     const PRODUCT_ID = 'Roundcube-libkolab-0.9';
@@ -54,7 +54,7 @@ abstract class kolab_format
      * @param string Cached xml data to initialize with
      * @return object kolab_format
      */
-    public static function factory($type, $version = 3.0, $xmldata = null)
+    public static function factory($type, $version = '3.0', $xmldata = null)
     {
         if (!isset(self::$timezone))
             self::$timezone = new DateTimeZone('UTC');
@@ -79,7 +79,7 @@ abstract class kolab_format
      */
     public static function supports($version)
     {
-        if ($version == 2.0)
+        if ($version == '2.0')
             return class_exists('kolabobject');
         // default is version 3
         return class_exists('kolabformat');
@@ -299,7 +299,7 @@ abstract class kolab_format
     {
         if (class_exists('kolabobject')) {
             $version = $v ?: $this->version;
-            if ($version <= 2.0)
+            if ($version <= '2.0')
                 return kolabobject::KolabV2;
             else
                 return kolabobject::KolabV3;
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
index ebbadf2..a569af7 100644
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -51,7 +51,7 @@ class kolab_storage
 
         $rcmail = rcube::get_instance();
         self::$config = $rcmail->config;
-        self::$version = $rcmail->config->get('kolab_format_version', self::$version);
+        self::$version = strval($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'));


commit 826118b4a6b7e0bd6f37369557d226845a7d1e27
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Wed Feb 20 09:36:04 2013 +0100

    Fix importing photo and notes fields (Bug #1635). Values of these fields
    were imported from vCard as one-element-arrays. Setting limit=1 on these
    fields makes that the array is converted to string as needed.

diff --git a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
index b34cc6c..6e32bc7 100644
--- a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
+++ b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
@@ -65,8 +65,8 @@ class rcube_kolab_contacts extends rcube_addressbook
                                 'label' => 'kolab_addressbook.pgppublickey'),
       'pkcs7publickey' => array('type' => 'textarea', 'size' => 70, 'rows' => 10, 'limit' => 1,
                                 'label' => 'kolab_addressbook.pkcs7publickey'),
-      'notes'        => array(),
-      'photo'        => array(),
+      'notes'        => array('limit' => 1),
+      'photo'        => array('limit' => 1),
       // TODO: define more Kolab-specific fields such as: language, latitude, longitude, crypto settings
     );
 


commit 0a3071bfcfc0a64e5c2ee66422e60f4c83ed2e85
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Jan 23 11:36:55 2013 +0100

    Add fallback for recurrence computation when the kolabcalendaring php module isn't available

diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index f2c106e..45db638 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -414,7 +414,14 @@ class kolab_calendar
     }
 
     // use libkolab to compute recurring events
-    $recurrence = new kolab_date_recurrence($object);
+    if (class_exists('kolabcalendaring')) {
+        $recurrence = new kolab_date_recurrence($object);
+    }
+    else {
+        // fallback to local recurrence implementation
+        require_once($this->cal->home . '/lib/calendar_recurrence.php');
+        $recurrence = new calendar_recurrence($this->cal, $event);
+    }
 
     $i = 0;
     $events = array();
diff --git a/plugins/calendar/lib/calendar_recurrence.php b/plugins/calendar/lib/calendar_recurrence.php
index 03831c1..bf534f5 100644
--- a/plugins/calendar/lib/calendar_recurrence.php
+++ b/plugins/calendar/lib/calendar_recurrence.php
@@ -41,6 +41,10 @@ class calendar_recurrence
    */
   function __construct($cal, $event)
   {
+    // use Horde classes to compute recurring instances
+    // TODO: replace with something that has less than 6'000 lines of code
+    require_once(__DIR__ . '/Horde_Date_Recurrence.php');
+
     $this->cal = $cal;
     $this->event = $event;
     $this->next = new Horde_Date($event['start'], $cal->timezone->getName());
@@ -49,10 +53,6 @@ class calendar_recurrence
     if (is_object($event['start']) && is_object($event['end']))
       $this->duration = $event['start']->diff($event['end']);
 
-    // use Horde classes to compute recurring instances
-    // TODO: replace with something that has less than 6'000 lines of code
-    require_once($this->cal->home . '/lib/Horde_Date_Recurrence.php');
-
     $this->engine = new Horde_Date_Recurrence($event['start']);
     $this->engine->fromRRule20(libcalendaring::to_rrule($event['recurrence']));
 
@@ -83,4 +83,27 @@ class calendar_recurrence
     return $time;
   }
 
+  /**
+   * Get the next recurring instance of this event
+   *
+   * @return mixed Array with event properties or False if recurrence ended
+   */
+  public function next_instance()
+  {
+    if ($next_start = $this->next_start()) {
+      $next_end = clone $next_start;
+      $next_end->add($this->duration);
+
+      $next = $this->event;
+      $next['recurrence_id'] = $next_start->format('Y-m-d');
+      $next['start'] = $next_start;
+      $next['end'] = $next_end;
+      unset($next['_formatobj']);
+
+      return $next;
+    }
+
+    return false;
+  }
+
 }


commit e5ab237c3bfc4c44e0ebedd2ef7879b137ac7528
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Jan 23 10:06:44 2013 +0100

    Fix ical export with (invalid) timezone +00:00

diff --git a/plugins/calendar/lib/calendar_ical.php b/plugins/calendar/lib/calendar_ical.php
index f77224d..cec2040 100644
--- a/plugins/calendar/lib/calendar_ical.php
+++ b/plugins/calendar/lib/calendar_ical.php
@@ -449,7 +449,8 @@ class calendar_ical
     else {
       // <ATTR>;TZID=Europe/Zurich:20120706T210000
       $tz = $dt->getTimezone();
-      $tzid = $tz && $tz->getName() != 'UTC' ? ';TZID=' . $tz->getName() : '';
+      $tzname = $tz ? $tz->getName() : null;
+      $tzid = $tzname && $tzname != 'UTC' && $tzname != '+00:00' ? ';TZID=' . $tzname : '';
       return $attr . $tzid . ':' . $dt->format('Ymd\THis' . ($tzid ? '' : '\Z'));
     }
   }


commit e886498390f7692aab882146f0691a7fab5876c2
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Sat Jan 19 17:36:32 2013 +0100

    Fix javascript error that prevents delete dialog from being closed (#1551)

diff --git a/plugins/tasklist/tasklist.js b/plugins/tasklist/tasklist.js
index f897d0d..daf157e 100644
--- a/plugins/tasklist/tasklist.js
+++ b/plugins/tasklist/tasklist.js
@@ -1319,7 +1319,7 @@ function rcube_tasklist_ui(settings)
         rcmail.http_post('task', { action:'delete', t:{ id:rec.id, list:rec.list }, mode:mode, filter:filtermask });
 
         // move childs to parent/root
-        if (mode != 1) {
+        if (mode != 1 && rec.children !== undefined) {
             var parent_node = rec.parent_id ? $('li[rel="'+rec.parent_id+'"] > .childtasks', rcmail.gui_objects.resultlist) : null;
             if (!parent_node || !parent_node.length)
                 parent_node = rcmail.gui_objects.resultlist;


commit cb0ceb0df20085fa1182013f21f6e677f767b006
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Thu Jan 17 15:16:10 2013 +0100

    More typos fixed

diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 3e5d05f..2b3694a 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -150,7 +150,7 @@ class kolab_driver extends calendar_driver
 
     $plugin = $this->rc->plugins->exec_hook('calendar_list_filter', array(
       'list' => $this->calendars, 'calendars' => $calendars,
-      'writable' => $writable, 'active' => $active, 'personal' => $personal,
+      'writeable' => $writeable, 'active' => $active, 'personal' => $personal,
     ));
 
     if ($plugin['abort']) {


commit 01850fc9ac9921797946dbeebb0ee6a327e9c3e2
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Thu Jan 17 09:37:48 2013 +0100

    Fix typo in calendar selection; fixes bug #140

diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 687e39d..3e5d05f 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -138,13 +138,13 @@ class kolab_driver extends calendar_driver
   /**
    * Get list of calendars according to specified filters
    *
-   * @param bool $writable Return only writeable calendars
+   * @param bool $writeable Return only writeable calendars
    * @param bool $active   Return only active calendars
    * @param bool $personal Return only personal calendars
    *
    * @return array List of calendars
    */
-  protected function filter_calendars($writable = false, $active = false, $personal = false)
+  protected function filter_calendars($writeable = false, $active = false, $personal = false)
   {
     $calendars = array();
 


commit 6fac09efe1b8dea8a6cf38af3f33adc6b921b2fa
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Wed Jan 16 10:06:59 2013 +0100

    Add workaround for situation when kolabobject doesn't generate UID but kolabformat does
    (it's the case for File objects unsupported by libkolab)

diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php
index c3c1b12..c0fb986 100644
--- a/plugins/libkolab/lib/kolab_format.php
+++ b/plugins/libkolab/lib/kolab_format.php
@@ -265,7 +265,12 @@ abstract class kolab_format
     {
         // get generated UID
         if (!$this->data['uid']) {
-            $this->data['uid'] = $this->xmlobject ? $this->xmlobject->getSerializedUID() : kolabformat::getSerializedUID();
+            if ($this->xmlobject) {
+                $this->data['uid'] = $this->xmlobject->getSerializedUID();
+            }
+            if (empty($this->data['uid'])) {
+                $this->data['uid'] = kolabformat::getSerializedUID();
+            }
             $this->obj->setUid($this->data['uid']);
         }
     }


commit 6fe22f10b68e5f7b8f3b1604a136b9f8338ad928
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Jan 9 11:49:12 2013 +0100

    Fix modification of recurring events (#1499)

diff --git a/plugins/calendar/drivers/database/database_driver.php b/plugins/calendar/drivers/database/database_driver.php
index d6a4483..5a518f7 100644
--- a/plugins/calendar/drivers/database/database_driver.php
+++ b/plugins/calendar/drivers/database/database_driver.php
@@ -363,11 +363,11 @@ class database_driver extends calendar_driver
             
             // use start date from master but try to be smart on time or duration changes
             $old_start_date = $old['start']->format('Y-m-d');
-            $old_start_time = $old['start']->format('H:i');
+            $old_start_time = $old['allday'] ? '' : $old['start']->format('H:i');
             $old_duration = $old['end']->format('U') - $old['start']->format('U');
             
             $new_start_date = $event['start']->format('Y-m-d');
-            $new_start_time = $event['start']->format('H:i');
+            $new_start_time = $event['allday'] ? '' : $event['start']->format('H:i');
             $new_duration = $event['end']->format('U') - $event['start']->format('U');
             
             $diff = $old_start_date != $new_start_date || $old_start_time != $new_start_time || $old_duration != $new_duration;
diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index 5200cff..f2c106e 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -181,9 +181,7 @@ class kolab_calendar
         $this->events[$master_id] = $this->_to_rcube_event($record);
 
       if (($master = $this->events[$master_id]) && $master['recurrence']) {
-        $limit = clone $master['start'];
-        $limit->add(new DateInterval('P10Y'));
-        $this->_get_recurring_events($record, $master['start'], $limit, $id);
+        $this->_get_recurring_events($record, $master['start'], null, $id);
       }
     }
 
@@ -386,8 +384,14 @@ class kolab_calendar
 
   /**
    * Create instances of a recurring event
+   *
+   * @param array  Hash array with event properties
+   * @param object DateTime Start date of the recurrence window
+   * @param object DateTime End date of the recurrence window
+   * @param string ID of a specific recurring event instance
+   * @return array List of recurring event instances
    */
-  public function _get_recurring_events($event, $start, $end, $event_id = null)
+  public function _get_recurring_events($event, $start, $end = null, $event_id = null)
   {
     $object = $event['_formatobj'];
     if (!$object) {
@@ -397,6 +401,19 @@ class kolab_calendar
     if (!is_object($object))
       return array();
 
+    // determine a reasonable end date if none given
+    if (!$end) {
+      switch ($event['recurrence']['FREQ']) {
+        case 'YEARLY':  $intvl = 'P100Y'; break;
+        case 'MONTHLY': $intvl = 'P20Y';  break;
+        default:        $intvl = 'P10Y';  break;
+      }
+
+      $end = clone $event['start'];
+      $end->add(new DateInterval($intvl));
+    }
+
+    // use libkolab to compute recurring events
     $recurrence = new kolab_date_recurrence($object);
 
     $i = 0;
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index c701077..687e39d 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -429,9 +429,7 @@ class kolab_driver extends calendar_driver
 
           // removing the first instance => just move to next occurence
           if ($master['id'] == $event['id']) {
-            $limit = clone $event['end'];
-            $limit->add(new DateInterval('P370D'));
-            $recurring = reset($storage->_get_recurring_events($event, $event['start'], $limit, $event['id'].'-1'));
+            $recurring = reset($storage->_get_recurring_events($event, $event['start'], null, $event['id'].'-1'));
             $master['start'] = $recurring['start'];
             $master['end'] = $recurring['end'];
             if ($master['recurrence']['COUNT'])
@@ -588,9 +586,7 @@ class kolab_driver extends calendar_driver
       case 'current':
         // modifying the first instance => just move to next occurence
         if ($master['id'] == $event['id']) {
-          $limit = clone $old['end'];
-          $limit->add(new DateInterval('P370D'));
-          $recurring = reset($storage->_get_recurring_events($event, $event['start'], $limit, $event['id'].'-1'));
+          $recurring = reset($storage->_get_recurring_events($event, $event['start'], null, $event['id'].'-1'));
           $master['start'] = $recurring['start'];
           $master['end'] = $recurring['end'];
           if ($master['recurrence']['COUNT'])
@@ -643,11 +639,11 @@ class kolab_driver extends calendar_driver
 
         // use start date from master but try to be smart on time or duration changes
         $old_start_date = $old['start']->format('Y-m-d');
-        $old_start_time = $old['start']->format('H:i');
+        $old_start_time = $old['allday'] ? '' : $old['start']->format('H:i');
         $old_duration = $old['end']->format('U') - $old['start']->format('U');
         
         $new_start_date = $event['start']->format('Y-m-d');
-        $new_start_time = $event['start']->format('H:i');
+        $new_start_time = $event['allday'] ? '' : $event['start']->format('H:i');
         $new_duration = $event['end']->format('U') - $event['start']->format('U');
         
         $diff = $old_start_date != $new_start_date || $old_start_time != $new_start_time || $old_duration != $new_duration;


commit 7daf2b001c15cac0d77089b2088a8e4cc46d5a24
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date:   Wed Jan 9 11:12:19 2013 +0100

    Fix recurring event handling when first instance is modified and excluded (#1505)

diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index 0a3d273..5200cff 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -248,7 +248,21 @@ class kolab_calendar
       // list events in requested time window
       if ($event['start'] <= $end && $event['end'] >= $start) {
         unset($event['_attendees']);
-        $events[] = $event;
+        $add = true;
+
+        // skip the first instance of a recurring event if listed in exdate
+        if ($virtual && !empty($event['recurrence']['EXDATE'])) {
+          $event_date = $event['start']->format('Ymd');
+          foreach ($event['recurrence']['EXDATE'] as $exdate) {
+            if ($exdate->format('Ymd') == $event_date) {
+              $add = false;
+              break;
+            }
+          }
+        }
+
+        if ($add)
+          $events[] = $event;
       }
       
       // resolve recurring events
@@ -409,9 +423,9 @@ class kolab_calendar
       else if ($next_event['start'] > $end)  // stop loop if out of range
         break;
 
-	  // avoid endless recursion loops
-	  if ($i > 1000)
-		  break;
+      // avoid endless recursion loops
+      if ($i > 1000)
+          break;
     }
     
     return $events;
@@ -458,6 +472,10 @@ class kolab_calendar
     if (is_array($record['categories']))
       $record['categories'] = $record['categories'][0];
 
+    // remove empty recurrence array
+    if (empty($record['recurrence']))
+      unset($record['recurrence']);
+
     // remove internals
     unset($record['_mailbox'], $record['_msguid'], $record['_formatobj'], $record['_attachments']);
 
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index fcf05aa..c701077 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -408,10 +408,10 @@ class kolab_driver extends calendar_driver
   public function remove_event($event, $force = true)
   {
     $success = false;
-    $_savemode = $event['_savemode'];
+    $savemode = $event['_savemode'];
 
     if (($storage = $this->calendars[$event['calendar']]) && ($event = $storage->get_event($event['id']))) {
-      $event['_savemode'] = $_savemode;
+      $event['_savemode'] = $savemode;
       $savemode = 'all';
       $master = $event;
 
@@ -426,7 +426,7 @@ class kolab_driver extends calendar_driver
       switch ($savemode) {
         case 'current':
           $_SESSION['calendar_restore_event_data'] = $master;
-          
+
           // removing the first instance => just move to next occurence
           if ($master['id'] == $event['id']) {
             $limit = clone $event['end'];
@@ -586,13 +586,26 @@ class kolab_driver extends calendar_driver
         break;
         
       case 'current':
-        // add exception to master event
-        $master['recurrence']['EXDATE'][] = $old['start'];
+        // modifying the first instance => just move to next occurence
+        if ($master['id'] == $event['id']) {
+          $limit = clone $old['end'];
+          $limit->add(new DateInterval('P370D'));
+          $recurring = reset($storage->_get_recurring_events($event, $event['start'], $limit, $event['id'].'-1'));
+          $master['start'] = $recurring['start'];
+          $master['end'] = $recurring['end'];
+          if ($master['recurrence']['COUNT'])
+            $master['recurrence']['COUNT']--;
+        }
+        else {  // add exception to master event
+          $master['recurrence']['EXDATE'][] = $old['start'];
+		}
+
         $storage->update_event($master);
         
         // insert new event for this occurence
         $event += $old;
         $event['recurrence'] = array();
+        unset($event['recurrence_id']);
         $event['uid'] = $this->cal->generate_uid();
         $success = $storage->insert_event($event);
         break;





More information about the commits mailing list