MFB: kolab/issue4257 (Always accept policy doesnt set atendee status to accepted)
authorGunnar Wrobel <p@rdus.de>
Mon, 19 Apr 2010 12:02:32 +0000 (14:02 +0200)
committerGunnar Wrobel <p@rdus.de>
Mon, 19 Apr 2010 12:02:32 +0000 (14:02 +0200)
framework/Kolab_Filter/lib/Horde/Kolab/Resource.php
framework/Kolab_Filter/lib/Horde/Kolab/Resource/Epoch.php [new file with mode: 0644]
framework/Kolab_Filter/lib/Horde/Kolab/Resource/Itip.php [new file with mode: 0644]
framework/Kolab_Filter/package.xml
framework/Kolab_Filter/test/Horde/Kolab/Filter/ResourceTest.php
framework/Kolab_Filter/test/Horde/Kolab/Filter/fixtures/allday_invitation.eml [new file with mode: 0644]
framework/Kolab_Filter/test/Horde/Kolab/Filter/phpunit.xml [new file with mode: 0644]

index 4d561db..1c918c8 100644 (file)
@@ -21,6 +21,12 @@ require_once 'Horde/MIME/Message.php';
 require_once 'Horde/MIME/Headers.php';
 require_once 'Horde/MIME/Part.php';
 require_once 'Horde/MIME/Structure.php';
+
+/** Load Kolab_Filter elements */
+require_once 'Horde/Kolab/Resource/Epoch.php';
+require_once 'Horde/Kolab/Resource/Itip.php';
+
+require_once 'Horde/String.php';
 Horde_String::setDefaultCharset('utf-8');
 
 // What actions we can take when receiving an event request
@@ -379,28 +385,35 @@ class Kolab_Resource
             Horde::logMessage(sprintf('No VEVENT found in iCalendar data, passing through to %s', $id), 'INFO');
             return true;
         }
+        $itip = new Horde_Kolab_Resource_Itip($itip);
 
         // What is the request's method? i.e. should we create a new event/cancel an
         // existing event, etc.
-        $method = strtoupper($iCalendar->getAttributeDefault('METHOD',
-                                                             $itip->getAttributeDefault('METHOD', 'REQUEST')));
+        $method = strtoupper(
+            $iCalendar->getAttributeDefault(
+                'METHOD',
+                $itip->getMethod()
+            )
+        );
 
         // What resource are we managing?
         Horde::logMessage(sprintf('Processing %s method for %s', $method, $id), 'DEBUG');
 
         // This is assumed to be constant across event creation/modification/deletipn
-        $uid = $itip->getAttributeDefault('UID', '');
+        $uid = $itip->getUid();
         Horde::logMessage(sprintf('Event has UID %s', $uid), 'DEBUG');
 
         // Who is the organiser?
-        $organiser = preg_replace('/^mailto:\s*/i', '', $itip->getAttributeDefault('ORGANIZER', ''));
+        $organiser = $itip->getOrganizer();
         Horde::logMessage(sprintf('Request made by %s', $organiser), 'DEBUG');
 
         // What is the events summary?
-        $summary = $itip->getAttributeDefault('SUMMARY', '');
-
-        $dtstart = $this->convert2epoch($itip->getAttributeDefault('DTSTART', 0));
-        $dtend = $this->convert2epoch($itip->getAttributeDefault('DTEND', 0));
+        $summary = $itip->getSummary();
+  
+        $estart = new Horde_Kolab_Resource_Epoch($itip->getStart());
+        $dtstart = $estart->getEpoch();
+        $eend = new Horde_Kolab_Resource_Epoch($itip->getEnd());
+        $dtend = $eend->getEpoch();
 
         Horde::logMessage(sprintf('Event starts on <%s> %s and ends on <%s> %s.',
                                   $dtstart, $this->iCalDate2Kolab($dtstart), $dtend, $this->iCalDate2Kolab($dtend)), 'DEBUG');
@@ -461,7 +474,7 @@ class Kolab_Resource
             }
 
             /** Generate the Kolab object */
-            $object = $this->_objectFromItip($itip);
+            $object = $itip->getKolabObject();
 
             $outofperiod=0;
 
@@ -483,7 +496,8 @@ class Kolab_Resource
                 Horde::logMessage(sprintf('Free/busy info starts on <%s> %s and ends on <%s> %s',
                                           $vfbstart, $this->iCalDate2Kolab($vfbstart), $vfbend, $this->iCalDate2Kolab($vfbend)), 'DEBUG');
 
-                if ($vfbstart && $dtstart > $this->convert2epoch ($vfbend)) {
+                $evfbend = new Horde_Kolab_Resource_Epoch($vfbend);
+                if ($vfbstart && $dtstart > $evfbend->getEpoch()) {
                     $outofperiod=1;
                 } else {
                     // Check whether we are busy or not
@@ -608,39 +622,14 @@ class Kolab_Resource
                 }
             }
 
-            $result = $data->save($object, $old_uid);
+            $itip->setAccepted($resource);
+
+            $result = $data->save($itip->getKolabObject(), $old_uid);
             if (is_a($result, 'PEAR_Error')) {
                 $result->code = OUT_LOG | EX_UNAVAILABLE;
                 return $result;
             }
 
-            // Update our status within the iTip request and send the reply
-            $itip->setAttribute('STATUS', 'CONFIRMED', array(), false);
-            $attendees = $itip->getAttribute('ATTENDEE');
-            if (!is_array($attendees)) {
-                $attendees = array($attendees);
-            }
-            $attparams = $itip->getAttribute('ATTENDEE', true);
-            foreach ($attendees as $i => $attendee) {
-                $attendee = preg_replace('/^mailto:\s*/i', '', $attendee);
-                if ($attendee != $resource) {
-                    continue;
-                }
-
-                $attparams[$i]['PARTSTAT'] = 'ACCEPTED';
-                if (array_key_exists('RSVP', $attparams[$i])) {
-                    unset($attparams[$i]['RSVP']);
-                }
-            }
-
-            // Re-add all the attendees to the event, using our updates status info
-            $firstatt = array_pop($attendees);
-            $firstattparams = array_pop($attparams);
-            $itip->setAttribute('ATTENDEE', $firstatt, $firstattparams, false);
-            foreach ($attendees as $i => $attendee) {
-                $itip->setAttribute('ATTENDEE', $attendee, $attparams[$i]);
-            }
-
             if ($outofperiod) {
                 $this->sendITipReply($cn, $resource, $itip, RM_ITIP_TENTATIVE,
                                      $organiser, $uid, $is_update);
@@ -952,8 +941,9 @@ class Kolab_Resource
             $temp = $this->cleanArray($ical_date);
             if (array_key_exists('DATE', $temp)) {
                 if ($type == 'ENDDATE') {
+                    $etemp = new Horde_Kolab_Resource_Epoch($temp);
                     // substract a day (86400 seconds) using epochs to take number of days per month into account
-                    $epoch= $this->convert2epoch($temp) - 86400;
+                    $epoch= $etemp->getEpoch() - 86400;
                     $date = gmstrftime('%Y-%m-%d', $epoch);
                 } else {
                     $date= sprintf('%04d-%02d-%02d', $temp['year'], $temp['month'], $temp['mday']);
@@ -971,28 +961,4 @@ class Kolab_Resource
         Horde::logMessage(sprintf('To <%s>', $date), 'DEBUG');
         return $date;
     }
-
-    /**
-     * Convert a date to an epoch.
-     *
-     * @param array  $values  The array to convert.
-     *
-     * @return int Time.
-     */
-    function convert2epoch($values)
-    {
-        Horde::logMessage(sprintf('Converting to epoch %s',
-                                  print_r($values, true)), 'DEBUG');
-
-        if (is_array($values)) {
-            $temp = $this->cleanArray($values);
-            $epoch = gmmktime($temp['hour'], $temp['minute'], $temp['second'],
-                              $temp['month'], $temp['mday'], $temp['year']);
-        } else {
-            $epoch = $values;
-        }
-
-        Horde::logMessage(sprintf('Converted <%s>', $epoch), 'DEBUG');
-        return $epoch;
-    }
 }
diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Resource/Epoch.php b/framework/Kolab_Filter/lib/Horde/Kolab/Resource/Epoch.php
new file mode 100644 (file)
index 0000000..6178dba
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Handles Date conversion for the resource handler.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Kolab_Filter
+ * @author   Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Handles Date conversion for the resource handler.
+ *
+ * Copyright 2004-2010 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did not
+ * receive this file, see
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package  Kolab_Filter
+ * @author   Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Kolab_Server
+ */
+class Horde_Kolab_Resource_Epoch
+{
+
+    /**
+     * The date to be converted.
+     *
+     * @var mixed
+     */
+    private $_date;
+
+    /**
+     * Constructor.
+     *
+     * @param mixed $date The date to be converted.
+     */
+    public function __construct($date)
+    {
+        $this->_date = $date;
+    }
+
+    /**
+     * Clear information from a date array.
+     *
+     * @param array $ical_date  The array to clear.
+     *
+     * @return array The cleaned array.
+     */
+    function cleanArray($ical_date)
+    {
+        if (!array_key_exists('hour', $ical_date)) {
+            $temp['DATE'] = '1';
+        }
+        $temp['hour']   = array_key_exists('hour', $ical_date) ? $ical_date['hour'] :  '00';
+        $temp['minute']   = array_key_exists('minute', $ical_date) ? $ical_date['minute'] :  '00';
+        $temp['second']   = array_key_exists('second', $ical_date) ? $ical_date['second'] :  '00';
+        $temp['year']   = array_key_exists('year', $ical_date) ? $ical_date['year'] :  '0000';
+        $temp['month']   = array_key_exists('month', $ical_date) ? $ical_date['month'] :  '00';
+        $temp['mday']   = array_key_exists('mday', $ical_date) ? $ical_date['mday'] :  '00';
+        $temp['zone']   = array_key_exists('zone', $ical_date) ? $ical_date['zone'] :  'UTC';
+
+        return $temp;
+    }
+
+    /**
+     * Convert a date to an epoch.
+     *
+     * @param array  $values  The array to convert.
+     *
+     * @return int Time.
+     */
+    private function convert2epoch($values)
+    {
+        Horde::logMessage(sprintf('Converting to epoch %s',
+                                  print_r($values, true)), 'DEBUG');
+
+        if (is_array($values)) {
+            $temp = $this->cleanArray($values);
+            $epoch = gmmktime($temp['hour'], $temp['minute'], $temp['second'],
+                              $temp['month'], $temp['mday'], $temp['year']);
+        } else {
+            $epoch=$values;
+        }
+
+        Horde::logMessage(sprintf('Converted <%s>', $epoch), 'DEBUG');
+        return $epoch;
+    }
+
+    public function getEpoch()
+    {
+        return $this->convert2Epoch($this->_date);
+    }
+}
\ No newline at end of file
diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Resource/Itip.php b/framework/Kolab_Filter/lib/Horde/Kolab/Resource/Itip.php
new file mode 100644 (file)
index 0000000..fea3697
--- /dev/null
@@ -0,0 +1,257 @@
+<?php
+/**
+ * Handles Itip data.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Kolab_Filter
+ * @author   Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Handles Itip data.
+ *
+ * Copyright 2004-2010 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did not
+ * receive this file, see
+ * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package  Kolab_Filter
+ * @author   Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Kolab_Server
+ */
+class Horde_Kolab_Resource_Itip
+{
+
+    /**
+     * Reference to the iCalendar iTip object.
+     *
+     * @var Horde_iCalendar_vevent
+     */
+    private $_itip;
+
+    /**
+     * Constructor.
+     *
+     * @param Horde_iCalendar_vevent $itip Reference to the iCalendar iTip object.
+     */
+    public function __construct($itip)
+    {
+        $this->_itip = $itip;
+    }
+
+    public function __call($method, $args)
+    {
+        return call_user_func_array(array($this->_itip, $method), $args);
+    }
+
+    /**
+     * Return the method of the iTip request.
+     *
+     * @return string The method of the request.
+     */
+    public function getMethod()
+    {
+        return $this->_itip->getAttributeDefault('METHOD', 'REQUEST');
+    }
+
+    /**
+     * Return the uid of the iTip event.
+     *
+     * @return string The uid of the event.
+     */
+    public function getUid()
+    {
+        return $this->_itip->getAttributeDefault('UID', '');
+    }
+
+    /**
+     * Return the organizer of the iTip event.
+     *
+     * @return string The organizer of the event.
+     */
+    public function getOrganizer()
+    {
+        return preg_replace('/^mailto:\s*/i', '', $this->_itip->getAttributeDefault('ORGANIZER', ''));
+    }
+
+    /**
+     * Return the summary of the iTip event.
+     *
+     * @return string The summary of the event.
+     */
+    public function getSummary()
+    {
+        return $this->_itip->getAttributeDefault('SUMMARY', '');
+    }
+
+    /**
+     * Return the start of the iTip event.
+     *
+     * @return string The start of the event.
+     */
+    public function getStart()
+    {
+        return $this->_itip->getAttributeDefault('DTSTART', 0);
+    }
+
+    /**
+     * Return the end of the iTip event.
+     *
+     * @return string The end of the event.
+     */
+    public function getEnd()
+    {
+        return $this->_itip->getAttributeDefault('DTEND', 0);
+    }
+
+    public function getKolabObject()
+    {
+        $object = array();
+        $object['uid'] = $this->_itip->getAttributeDefault('UID', '');
+
+        $org_params = $this->_itip->getAttribute('ORGANIZER', true);
+        if (!is_a( $org_params, 'PEAR_Error')) {
+            if (!empty($org_params[0]['CN'])) {
+                $object['organizer']['display-name'] = $org_params[0]['CN'];
+            }
+            $orgemail = $this->_itip->getAttributeDefault('ORGANIZER', '');
+            if (preg_match('/mailto:(.*)/i', $orgemail, $regs )) {
+                $orgemail = $regs[1];
+            }
+            $object['organizer']['smtp-address'] = $orgemail;
+        }
+        $object['summary'] = $this->_itip->getAttributeDefault('SUMMARY', '');
+        $object['location'] = $this->_itip->getAttributeDefault('LOCATION', '');
+        $object['body'] = $this->_itip->getAttributeDefault('DESCRIPTION', '');
+        $dtend = $this->_itip->getAttributeDefault('DTEND', '');
+        if (is_array($dtend)) {
+            $object['_is_all_day'] = true;
+        }
+        $start = new Horde_Kolab_Resource_Epoch($this->getStart());
+        $object['start-date'] = $start->getEpoch();
+        $end = new Horde_Kolab_Resource_Epoch($dtend);
+        $object['end-date'] = $end->getEpoch();
+
+        $attendees = $this->_itip->getAttribute('ATTENDEE');
+        if (!is_a( $attendees, 'PEAR_Error')) {
+            $attendees_params = $this->_itip->getAttribute('ATTENDEE', true);
+            if (!is_array($attendees)) {
+                $attendees = array($attendees);
+            }
+            if (!is_array($attendees_params)) {
+                $attendees_params = array($attendees_params);
+            }
+
+            $object['attendee'] = array();
+            for ($i = 0; $i < count($attendees); $i++) {
+                $attendee = array();
+                if (isset($attendees_params[$i]['CN'])) {
+                    $attendee['display-name'] = $attendees_params[$i]['CN'];
+                }
+
+                $attendeeemail = $attendees[$i];
+                if (preg_match('/mailto:(.*)/i', $attendeeemail, $regs)) {
+                    $attendeeemail = $regs[1];
+                }
+                $attendee['smtp-address'] = $attendeeemail;
+
+                if (!isset($attendees_params[$i]['RSVP'])
+                    || $attendees_params[$i]['RSVP'] == 'FALSE') {
+                    $attendee['request-response'] = false;
+                } else {
+                    $attendee['request-response'] = true;
+                }
+
+                if (isset($attendees_params[$i]['ROLE'])) {
+                    $attendee['role'] = $attendees_params[$i]['ROLE'];
+                }
+
+                if (isset($attendees_params[$i]['PARTSTAT'])) {
+                    $status = strtolower($attendees_params[$i]['PARTSTAT']);
+                    switch ($status) {
+                    case 'needs-action':
+                    case 'delegated':
+                        $attendee['status'] = 'none';
+                        break;
+                    default:
+                        $attendee['status'] = $status;
+                        break;
+                    }
+                }
+
+                $object['attendee'][] = $attendee;
+            }
+        }
+
+        // Alarm
+        $valarm = $this->_itip->findComponent('VALARM');
+        if ($valarm) {
+            $trigger = $valarm->getAttribute('TRIGGER');
+            if (!is_a($trigger, 'PEAR_Error')) {
+                $p = $valarm->getAttribute('TRIGGER', true);
+                if ($trigger < 0) {
+                    // All OK, enter the alarm into the XML
+                    // NOTE: The Kolab XML format seems underspecified
+                    // wrt. alarms currently...
+                    $object['alarm'] = -$trigger / 60;
+                }
+            } else {
+                Horde::logMessage('No TRIGGER in VALARM. ' . $trigger->getMessage(), 'ERR');
+            }
+        }
+
+        // Recurrence
+        $rrule_str = $this->_itip->getAttribute('RRULE');
+        if (!is_a($rrule_str, 'PEAR_Error')) {
+            require_once 'Horde/Date/Recurrence.php';
+            $recurrence = new Horde_Date_Recurrence(time());
+            $recurrence->fromRRule20($rrule_str);
+            $object['recurrence'] = $recurrence->toHash();
+        }
+
+        Horde::logMessage(sprintf('Assembled event object: %s',
+                                  print_r($object, true)), 'DEBUG');
+
+        return $object;
+    }
+
+    public function setAccepted($resource)
+    {
+        // Update our status within the iTip request and send the reply
+        $this->_itip->setAttribute('STATUS', 'CONFIRMED', array(), false);
+        $attendees = $this->_itip->getAttribute('ATTENDEE');
+        if (!is_array($attendees)) {
+            $attendees = array($attendees);
+        }
+        $attparams = $this->_itip->getAttribute('ATTENDEE', true);
+        foreach ($attendees as $i => $attendee) {
+            $attendee = preg_replace('/^mailto:\s*/i', '', $attendee);
+            if ($attendee != $resource) {
+                continue;
+            }
+
+            $attparams[$i]['PARTSTAT'] = 'ACCEPTED';
+            if (array_key_exists('RSVP', $attparams[$i])) {
+                unset($attparams[$i]['RSVP']);
+            }
+        }
+
+        // Re-add all the attendees to the event, using our updates status info
+        $firstatt = array_pop($attendees);
+        $firstattparams = array_pop($attparams);
+        $this->_itip->setAttribute('ATTENDEE', $firstatt, $firstattparams, false);
+        foreach ($attendees as $i => $attendee) {
+            $this->_itip->setAttribute('ATTENDEE', $attendee, $attparams[$i]);
+        }
+    }
+
+}
\ No newline at end of file
index 7101090..7146a15 100644 (file)
@@ -28,7 +28,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
   <email>jan@horde.org</email>
   <active>yes</active>
  </lead>
- <date>2009-11-16</date>
+ <date>2010-04-19</date>
  <version>
   <release>0.2.0</release>
   <api>0.1.0</api>
@@ -43,6 +43,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
   * Fixed handling of whole day invitations.
   * Extended iTip reply delivery to support different transport mechanisms.
   * Splitted Free/Busy functionality in a separate driver class.
+  * kolab/issue4257 ("Always accept" policy doesn't set atendee status to
+    "accepted") 
   * kolab/issue3962 (Names of config variables for "untrusted" text missleading)
   * kolab/issue3967 (UNTRUSTED vs. UNAUTHENTICATED, distinction considered
     harmful)
@@ -67,6 +69,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
        <file name="Filter.php" role="php" />
       </dir> <!-- /lib/Horde/Kolab/Test -->
       <file name="Resource.php" role="php" />
+      <dir name="Resource">
+       <file name="Epoch.php" role="php" />
+       <file name="Itip.php" role="php" />
+      </dir> <!-- /lib/Horde/Kolab/Resource -->
       <dir name="Filter">
        <file name="Content.php" role="php" />
        <file name="Base.php" role="php" />
@@ -143,6 +149,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
        <file name="LoadTest.php" role="test" />
        <file name="ResourceTest.php" role="test" />
        <dir name="fixtures">
+        <file name="allday_invitation.eml" role="test" />
         <file name="attendee_status_invitation.eml" role="test" />
         <file name="empty.eml" role="test" />
         <file name="empty2.ret" role="test" />
@@ -229,6 +236,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
   <filelist>
    <install name="doc/Horde/Kolab/Filter/kolabfilter.1" as="man/man1/kolabfilter.1" />
    <install name="lib/Horde/Kolab/Resource.php" as="Horde/Kolab/Resource.php" />
+   <install name="lib/Horde/Kolab/Resource/Epoch.php" as="Horde/Kolab/Resource/Epoch.php" />
+   <install name="lib/Horde/Kolab/Resource/Itip.php" as="Horde/Kolab/Resource/Itip.php" />
    <install name="lib/Horde/Kolab/Resource/Freebusy.php" as="Horde/Kolab/Resource/Freebusy.php" />
    <install name="lib/Horde/Kolab/Resource/Freebusy/Kolab.php" as="Horde/Kolab/Resource/Freebusy/Kolab.php" />
    <install name="lib/Horde/Kolab/Resource/Freebusy/Mock.php" as="Horde/Kolab/Resource/Freebusy/Mock.php" />
@@ -255,6 +264,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
    <install name="test/Horde/Kolab/Filter/IncomingTest.php" as="Horde/Kolab/Filter/IncomingTest.php" />
    <install name="test/Horde/Kolab/Filter/LoadTest.php" as="Horde/Kolab/Filter/LoadTest.php" />
    <install name="test/Horde/Kolab/Filter/ResourceTest.php" as="Horde/Kolab/Filter/ResourceTest.php" />
+   <install name="test/Horde/Kolab/Filter/fixtures/allday_invitation.eml" as="Horde/Kolab/Filter/fixtures/allday_invitation.eml" />
    <install name="test/Horde/Kolab/Filter/fixtures/attendee_status_invitation.eml" as="Horde/Kolab/Filter/fixtures/attendee_status_invitation.eml" />
    <install name="test/Horde/Kolab/Filter/fixtures/empty.eml" as="Horde/Kolab/Filter/fixtures/empty.eml" />
    <install name="test/Horde/Kolab/Filter/fixtures/empty2.ret" as="Horde/Kolab/Filter/fixtures/empty2.ret" />
index cd6338f..5fa0fbd 100644 (file)
@@ -283,6 +283,37 @@ class Horde_Kolab_Filter_ResourceTest extends Horde_Kolab_Test_Filter
     }
 
     /**
+     * Test all day events
+     */
+    public function testAllDay()
+    {
+        $GLOBALS['KOLAB_FILTER_TESTING'] = &new Horde_iCalendar_vfreebusy();
+        $GLOBALS['KOLAB_FILTER_TESTING']->setAttribute('DTSTART', Horde_iCalendar::_parseDateTime('20090901T000000Z'));
+        $GLOBALS['KOLAB_FILTER_TESTING']->setAttribute('DTEND', Horde_iCalendar::_parseDateTime('20091101T000000Z'));
+
+        $params = array('unmodified_content' => true,
+                        'incoming' => true);
+
+        $this->sendFixture(dirname(__FILE__) . '/fixtures/allday_invitation.eml',
+                           dirname(__FILE__) . '/fixtures/null.ret',
+                           '', '', 'test@example.org', 'wrobel@example.org',
+                           'home.example.org', $params);
+
+        $result = $this->auth->authenticate('wrobel', array('password' => 'none'));
+        $this->assertNoError($result);
+
+        $folder = $this->storage->getFolder('INBOX/Kalender');
+        $data = $folder->getData();
+        $events = $data->getObjects();
+
+        $this->assertEquals(1251928800, $events[0]['start-date']);
+        $this->assertEquals(1252015200, $events[0]['end-date']);
+
+        $result = $data->deleteAll();
+        $this->assertNoError($result);
+    }
+
+    /**
      * Test that the attendee status gets transferred.
      */
     public function testAttendeeStatusInvitation()
diff --git a/framework/Kolab_Filter/test/Horde/Kolab/Filter/fixtures/allday_invitation.eml b/framework/Kolab_Filter/test/Horde/Kolab/Filter/fixtures/allday_invitation.eml
new file mode 100644 (file)
index 0000000..efb6c8c
--- /dev/null
@@ -0,0 +1,86 @@
+Received: from localhost (example.com [127.0.0.1])
+       (Authenticated sender: 1@example.com)
+       by example.com (Postfix) with ESMTP id D47689B1C0
+       for <3@example.com>; Tue, 22 Sep 2009 15:36:22 +0200 (CEST)
+Message-ID:    <20090922153619.71582t7kl56avveo@example.com>
+Date: Tue, 22 Sep 2009 15:36:19 +0200
+From: 1 1 <1@example.com>
+To: 3@example.com
+Subject: 5
+User-Agent: Kronolith H3 (2.3)
+MIME-Version: 1.0
+Content-Type: multipart/alternative;
+       boundary="=_2qehldvr5f40"
+Content-Transfer-Encoding: 7bit
+
+This message is in MIME format.
+
+--=_2qehldvr5f40
+Content-Type: text/plain;
+       charset=UTF-8
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+5 (am 03.09.2009 um 06:00)
+
+Ort: 5
+
+Teilnehmer: 3@example.com
+
+Im Anhang befindet sich eine iCalendar-Datei mit mehr Informationen zu diese=
+m Termin. Wenn Ihr E-Mail-Programm iTip-Anfragen beherrscht, k=C3=B6nnen Sie=
+ diese Datei dazu benutzen, Ihre lokale Version des Termins zu aktualisieren=
+.
+
+Falls Ihr E-Mail-Programm keine iTip-Anfragen unterst=C3=BCtzt, k=C3=B6nnen =
+Sie einen der folgenden Links verwenden, um den Termin zu best=C3=A4tigen od=
+er abzulehnen.
+
+Um den Termin zu best=C3=A4tigen:
+https://example.com/client/kronolith/attend.php=
+?c=3D1%40example.com&e=3Dcee9e56161efb8b8831059=
+b2bc506e4e&u=3D3%40example.com&a=3Daccept
+
+Um den Termin unter Vorbehalt zu best=C3=A4tigen:
+https://example.com/client/kronolith/attend.php=
+?c=3D1%40example.com&e=3Dcee9e56161efb8b8831059=
+b2bc506e4e&u=3D3%40example.com&a=3Dtentative
+
+Um den Termin abzulehnen:
+https://example.com/client/kronolith/attend.php=
+?c=3D1%40example.com&e=3Dcee9e56161efb8b8831059=
+b2bc506e4e&u=3D3%40example.com&a=3Ddecline
+--=_2qehldvr5f40
+Content-Type: text/calendar;
+       charset=UTF-8;
+       name="event-invitation.ics";
+       METHOD="REQUEST"
+Content-Disposition: inline;
+       filename="event-invitation.ics"
+Content-Transfer-Encoding: 7bit
+
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:REQUEST
+X-WR-CALNAME:Kalender
+PRODID:-//The Horde Project//Horde_iCalendar Library//EN
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20090903
+DTEND;VALUE=DATE:20090904
+DTSTAMP:20090922T133615Z
+UID:cee9e56161efb8b8831059b2bc506e4e
+CREATED:20090922T133619Z
+LAST-MODIFIED:20090922T133619Z
+SUMMARY:5
+ORGANIZER;CN=1 1:mailto:1@example.com
+LOCATION:5
+CLASS:PUBLIC
+STATUS:CONFIRMED
+TRANSP:OPAQUE
+ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:3@exam
+ ple.com
+RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=1TH
+END:VEVENT
+END:VCALENDAR
+
+--=_2qehldvr5f40--
diff --git a/framework/Kolab_Filter/test/Horde/Kolab/Filter/phpunit.xml b/framework/Kolab_Filter/test/Horde/Kolab/Filter/phpunit.xml
new file mode 100644 (file)
index 0000000..0148736
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit>
+  <filter>
+    <whitelist>
+      <directory suffix=".php">../../../../lib</directory>
+    </whitelist>
+  </filter>
+</phpunit>