Finish up support for recurring events with exceptions.
authorMichael J. Rubinsky <mrubinsk@horde.org>
Sun, 4 Apr 2010 03:51:20 +0000 (23:51 -0400)
committerMichael J. Rubinsky <mrubinsk@horde.org>
Sun, 4 Apr 2010 03:51:20 +0000 (23:51 -0400)
Recurring events now support exceptions both from server->pim and from pim->server
This *should* complete support for calendar syncing :-)

framework/ActiveSync/lib/Horde/ActiveSync/Message/Appointment.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Exception.php
kronolith/lib/Event.php

index 8baed98..434558f 100644 (file)
@@ -161,6 +161,10 @@ class Horde_ActiveSync_Message_Appointment extends Horde_ActiveSync_Message_Base
             $this->_properties['alldayevent'] = self::IS_ALL_DAY;
         } elseif (!empty($datetime['allday'])) {
             $this->_properties['alldayevent'] = self::IS_ALL_DAY;
+            $end = new Horde_Date(
+                array('year'  => (int)$end->year,
+                      'month' => (int)$end->month,
+                      'mday'  => (int)$end->mday));
         }
         $this->_properties['starttime'] = $start;
         $this->_properties['endtime'] = $end;
@@ -385,11 +389,7 @@ class Horde_ActiveSync_Message_Appointment extends Horde_ActiveSync_Message_Base
      */
     public function addException(Horde_ActiveSync_Message_Exception $exception)
     {
-//        if (!isset($this->_properties['exceptions']) || !is_array($this->_properties['exceptions'])) {
-//            $this->_properties['exceptions'] = array();
-//        }
         $this->exceptions[] = $exception;
-        //$this->_properties['exceptions'][] = $exception;
     }
 
     /**
@@ -399,7 +399,6 @@ class Horde_ActiveSync_Message_Appointment extends Horde_ActiveSync_Message_Base
     public function getExceptions()
     {
         return $this->exceptions;
-        //return $this->_getAttribute('exceptions', array());
     }
 
     /**
index ea79df6..80ef6a2 100644 (file)
@@ -49,4 +49,8 @@ class Horde_ActiveSync_Message_Exception extends Horde_ActiveSync_Message_Appoin
         return $this->_getAttribute('exceptionstarttime');
     }
 
+    public function setExceptionStartTime($date)
+    {
+        $this->exceptionstarttime = $date;
+    }
 }
index 98a30dd..511b0b3 100644 (file)
@@ -277,6 +277,14 @@ abstract class Kronolith_Event
     public $baseid;
 
     /**
+     * For exceptions, the date of the original recurring event that this is an
+     * exception for.
+     * 
+     * @var Horde_Date
+     */
+    public $exceptionoriginaldate;
+
+    /**
      * Constructor.
      *
      * @param Kronolith_Driver $driver  The backend driver that this event is
@@ -1051,20 +1059,22 @@ abstract class Kronolith_Event
 
             $erules = $message->getExceptions();
             foreach ($erules as $rule){
-                $d = new Horde_Date($rule->getExceptionStartTime());
-                $this->recurrence->addException($d->format('Y'), $d->format('m'), $d->format('d'));
-
-                /* Readd the exception event */
-                $event = $kronolith_driver->getEvent();
-                $times = $rule->getDatetime();
-                $event->start = $times['start'];
-                $event->end = $times['end'];
-                $event->allday = $times['allday'];
-                $event->title = Horde_String::convertCharset($rule->getSubject(), 'utf-8', Horde_Nls::getCharset());
-                $event->description = Horde_String::convertCharset($rule->getBody(), 'utf-8', Horde_Nls::getCharset());
-                $event->baseid = $this->uid;
-                $event->initialized = true;
-                $event->save();
+                /* Readd the exception event, but only if not deleted */
+                if (!$rule->deleted) {
+                    $event = $kronolith_driver->getEvent();
+                    $times = $rule->getDatetime();
+                    $original = $rule->getExceptionStartTime();
+                    $this->recurrence->addException($original->format('Y'), $original->format('m'), $original->format('d'));
+                    $event->start = $times['start'];
+                    $event->end = $times['end'];
+                    $event->allday = $times['allday'];
+                    $event->title = Horde_String::convertCharset($rule->getSubject(), 'utf-8', Horde_Nls::getCharset());
+                    $event->description = Horde_String::convertCharset($rule->getBody(), 'utf-8', Horde_Nls::getCharset());
+                    $event->baseid = $this->uid;
+                    $event->exceptionoriginaldate = $original;
+                    $event->initialized = true;
+                    $event->save();
+                }
             }
         }
 
@@ -1126,11 +1136,44 @@ abstract class Kronolith_Event
         if ($this->recurs()) {
             $message->setRecurrence($this->recurrence);
 
-            /* Exceptions */
+            /* Exceptions are tricky. Exceptions, even those are that represent
+             * deleted instances of a recurring event, must be added. To do this
+             * we need query storage for all the events that represent exceptions
+             * (those with the baseid == $this->uid) and then remove the
+             * exceptionoriginaldate from the list of exceptions we know about.
+             * Any dates left in this list when we are done, must represent
+             * deleted instances of this recurring event.*/
             if (!empty($this->recurrence) && $exceptions = $this->recurrence->getExceptions()) {
-                foreach ($exceptions as $start) {
+                $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
+                $search = new StdClass();
+                $search->start = $this->recurrence->getRecurStart();
+                $search->end = $this->recurrence->getRecurEnd();
+                $search->baseid = $this->uid;
+                $results = $kronolith_driver->search($search);
+                foreach ($results as $days) {
+                    foreach ($days as $exception) {
+                        $e = new Horde_ActiveSync_Message_Exception();
+                        /* Times */
+                        $e->setDateTime(
+                            array('start' => $exception->start,
+                                  'end' => $exception->end,
+                                  'allday' => $exception->isAllDay()));
+                        /* The start time of the original recurring event */
+                        $e->setExceptionStartTime($exception->exceptionoriginaldate);
+                        $originaldate = $exception->exceptionoriginaldate->format('Ymd');
+                        $key = array_search($originaldate, $exceptions);
+                        if ($key !== false) {
+                            unset($exceptions[$key]);
+                        }
+                        $message->addexception($e);
+                    }
+                }
+
+                /* Any dates left in $exceptions must be deleted exceptions */
+                foreach ($exceptions as $deleted) {
                     $e = new Horde_ActiveSync_Message_Exception();
-                    $e->setDateTime(array('start' => new Horde_Date($start)));
+                    $e->setExceptionStartTime(new Horde_Date($deleted));
+                    $e->deleted = true;
                     $message->addException($e);
                 }
             }
@@ -1138,6 +1181,7 @@ abstract class Kronolith_Event
 
         /* Attendees */
 
+        /* Reminder */
         $message->setReminder($this->alarm);
 
         return $message;