summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2013-06-20 12:27:43 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2013-06-20 12:27:43 (GMT)
commit09f5b3009a0b94f1b284dfe8e3ac358e7c6a695b (patch)
tree5bf102a1cc9bf0eed0ab649713e6a07ff8066013
parentdcd7143bd9a2914bfa9dcf1af51915ef24d9b168 (diff)
downloadiRony-09f5b3009a0b94f1b284dfe8e3ac358e7c6a695b.tar.gz
Expose tasks folders through CalDAV
-rw-r--r--lib/Kolab/CalDAV/CalendarBackend.php93
-rw-r--r--lib/Kolab/CalDAV/Plugin.php8
2 files changed, 71 insertions, 30 deletions
diff --git a/lib/Kolab/CalDAV/CalendarBackend.php b/lib/Kolab/CalDAV/CalendarBackend.php
index 1ebc3ef..a60fd46 100644
--- a/lib/Kolab/CalDAV/CalendarBackend.php
+++ b/lib/Kolab/CalDAV/CalendarBackend.php
@@ -30,6 +30,7 @@ use \kolab_storage;
use \libcalendaring;
use Kolab\Utils\DAVBackend;
use Kolab\Utils\VObjectUtils;
+use Sabre\DAV;
use Sabre\CalDAV;
use Sabre\VObject;
@@ -45,6 +46,7 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
private $folders;
private $aliases;
private $useragent;
+ private $type_component_map = array('event' => 'VEVENT', 'task' => 'VTODO');
/**
* Read available calendar folders from server
@@ -56,7 +58,7 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
return $this->calendars;
// get all folders that have "event" type
- $folders = kolab_storage::get_folders('event');
+ $folders = array_merge(kolab_storage::get_folders('event'), kolab_storage::get_folders('task'));
$this->calendars = $this->folders = $this->aliases = array();
foreach (DAVBackend::sort_folders($folders) as $folder) {
@@ -69,7 +71,7 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
'{DAV:}displayname' => html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET),
'{http://apple.com/ns/ical/}calendar-color' => $folder->get_color(),
'{http://calendarserver.org/ns/}getctag' => sprintf('%d-%d-%d', $fdata['UIDVALIDITY'], $fdata['HIGHESTMODSEQ'], $fdata['UIDNEXT']),
- '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT')),
+ '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array($this->type_component_map[$folder->type])),
'{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp('opaque'),
);
$this->aliases[$folder->name] = $id;
@@ -373,15 +375,15 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
$object = $this->parse_calendar_data($calendarData, $uid);
if ($object['uid'] == $uid) {
- $success = $storage->save($object, 'event');
+ $success = $storage->save($object, $object['_type']);
if (!$success) {
rcube::raise_error(array(
'code' => 600, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Error saving event object to Kolab server"),
+ 'message' => "Error saving $object[_type] object to Kolab server"),
true, false);
- throw new DAV\Exception('Error saving event object to backend');
+ throw new DAV\Exception('Error saving calendar object to backend');
}
}
else {
@@ -443,7 +445,7 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
// TODO: remove attachments not listed anymore
// save object
- $saved = $storage->save($object, 'event', $uid);
+ $saved = $storage->save($object, $object['_type'], $uid);
if (!$saved) {
rcube::raise_error(array(
'code' => 600, 'type' => 'php',
@@ -581,15 +583,17 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
else {
$vobject = VObject\Reader::read($calendarData, VObject\Reader::OPTION_FORGIVING | VObject\Reader::OPTION_IGNORE_INVALID_LINES);
if ($vobject->name == 'VCALENDAR') {
- foreach ($vobject->getBaseComponents('VEVENT') as $ve) {
- $vevent = $ve;
- break;
+ foreach ($vobject->getBaseComponents() as $ve) {
+ if ($ve->name == 'VEVENT' || $ve->name == 'VTODO') {
+ $vevent = $ve;
+ break;
+ }
}
}
}
// convert the VEvent object into a hash array
- if ($vevent && $vevent->name == 'VEVENT') {
+ if ($vevent && $vevent->name == 'VEVENT' || $vevent->name == 'VTODO') {
$object = $this->_to_array($vevent);
if (!empty($object['uid'])) {
// parse recurrence exceptions
@@ -630,23 +634,13 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
'title' => strval($ve->SUMMARY),
'created' => $ve->CREATED ? $ve->CREATED->getDateTime() : null,
'changed' => $ve->DTSTAMP->getDateTime(),
- 'start' => VObjectUtils::convert_datetime($ve->DTSTART),
- 'end' => VObjectUtils::convert_datetime($ve->DTEND),
+ '_type' => $ve->name == 'VTODO' ? 'task' : 'event',
// set defaults
'free_busy' => 'busy',
'priority' => 0,
'attendees' => array(),
);
- // check for all-day dates
- if ($event['start']->_dateonly) {
- $event['allday'] = true;
- }
-
- if ($event['allday'] && is_object($event['end'])) {
- $event['end']->sub(new \DateInterval('PT23H'));
- }
-
// map other attributes to internal fields
$_attendees = array();
foreach ($ve->children as $prop) {
@@ -654,6 +648,13 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
continue;
switch ($prop->name) {
+ case 'DTSTART':
+ case 'DTEND':
+ case 'DUE':
+ $propmap = array('DTSTART' => 'start', 'DTEND' => 'end', 'DUE' => 'due');
+ $event[$propmap[$prop->name]] = VObjectUtils::convert_datetime($prop);
+ break;
+
case 'TRANSP':
$event['free_busy'] = $prop->value == 'TRANSPARENT' ? 'free' : 'busy';
break;
@@ -661,8 +662,10 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
case 'STATUS':
if ($prop->value == 'TENTATIVE')
$event['free_busy'] = 'tentative';
- else if ($prop->value == 'cancelled')
+ else if ($prop->value == 'CANCELLED')
$event['cancelled'] = true;
+ else if ($prop->value == 'COMPLETED')
+ $event['complete'] = 100;
break;
case 'PRIORITY':
@@ -693,10 +696,20 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
// $event['recurrence_id'] = VObjectUtils::convert_datetime($prop);
break;
+ case 'RELATED-TO':
+ if ($prop->offsetGet('RELTYPE') == 'PARENT') {
+ $event['parent_id'] = $prop->value;
+ }
+ break;
+
case 'SEQUENCE':
$event['sequence'] = intval($prop->value);
break;
+ case 'PERCENT-COMPLETE':
+ $event['complete'] = intval($prop->value);
+ break;
+
case 'DESCRIPTION':
case 'LOCATION':
case 'URL':
@@ -754,6 +767,15 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
}
}
+ // check for all-day dates
+ if ($event['start']->_dateonly) {
+ $event['allday'] = true;
+ }
+
+ if ($event['allday'] && is_object($event['end'])) {
+ $event['end']->sub(new \DateInterval('PT23H'));
+ }
+
// find alarms
if ($valarms = $ve->select('VALARM')) {
$action = 'DISPLAY';
@@ -790,7 +812,7 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
/**
* Build a valid iCal format block from the given event
*
- * @param array Hash array with event properties from libkolab
+ * @param array Hash array with event/task properties from libkolab
* @param string Absolute URI referenceing this event object
* @param object RECURRENCE-ID property when serializing a recurrence exception
* @return mixed VCALENDAR string containing the VEVENT data
@@ -799,16 +821,20 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
*/
private function _to_ical($event, $base_uri, $storage, $recurrence_id = null)
{
- $ve = VObject\Component::create('VEVENT');
+ $type = $event['_type'] ?: 'event';
+ $ve = VObject\Component::create($this->type_component_map[$type]);
$ve->add('UID', $event['uid']);
if (!empty($event['created']))
$ve->add(VObjectUtils::datetime_prop('CREATED', $event['created'], true));
if (!empty($event['changed']))
$ve->add(VObjectUtils::datetime_prop('DTSTAMP', $event['changed'], true));
-
- $ve->add(VObjectUtils::datetime_prop('DTSTART', $event['start'], false));
- $ve->add(VObjectUtils::datetime_prop('DTEND', $event['end'], false));
+ if (!empty($event['start']))
+ $ve->add(VObjectUtils::datetime_prop('DTSTART', $event['start'], false));
+ if (!empty($event['end']))
+ $ve->add(VObjectUtils::datetime_prop('DTEND', $event['end'], false));
+ if (!empty($event['due']))
+ $ve->add(VObjectUtils::datetime_prop('DUE', $event['due'], false));
if ($recurrence_id)
$ve->add($recurrence_id);
@@ -858,10 +884,19 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
$ve->add('STATUS', 'CANCELLED');
else if ($event['free_busy'] == 'tentative')
$ve->add('STATUS', 'TENTATIVE');
+ else if ($event['complete'] == 100)
+ $ve->add('STATUS', 'COMPLETED');
if (!empty($event['sensitivity']))
$ve->add('CLASS', strtoupper($event['sensitivity']));
+ if (isset($event['complete'])) {
+ $ve->add('PERCENT-COMPLETE', intval($event['complete']));
+ // Apple iCal required the COMPLETED date to be set in order to consider a task complete
+ if ($event['complete'] == 100)
+ $ve->add(VObjectUtils::datetime_prop('COMPLETED', $event['changed'] ?: new DateTime('now - 1 hour'), true));
+ }
+
if ($event['alarms']) {
$va = VObject\Component::create('VALARM');
list($trigger, $va->action) = explode(':', $event['alarms']);
@@ -906,6 +941,10 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
$ve->add('ATTACH', $uri);
}
+ if (!empty($event['parent_id'])) {
+ $ve->add('RELATED-TO', $event['parent_id'], array('RELTYPE' => 'PARENT'));
+ }
+
// add custom properties
foreach ((array)$event['x-custom'] as $prop) {
$ve->add($prop[0], $prop[1]);
diff --git a/lib/Kolab/CalDAV/Plugin.php b/lib/Kolab/CalDAV/Plugin.php
index 87ccacf..b3bc367 100644
--- a/lib/Kolab/CalDAV/Plugin.php
+++ b/lib/Kolab/CalDAV/Plugin.php
@@ -65,9 +65,11 @@ class Plugin extends CalDAV\Plugin
// keep the parsed object in memory for later processing
if ($vobj->name == 'VCALENDAR') {
self::$parsed_vcalendar = $vobj;
- foreach ($vobj->getBaseComponents('VEVENT') as $vevent) {
- self::$parsed_vevent = $vevent;
- break;
+ foreach ($vobj->getBaseComponents() as $vevent) {
+ if ($vevent->name == 'VEVENT' || $vevent->name == 'VTODO') {
+ self::$parsed_vevent = $vevent;
+ break;
+ }
}
}
}