Branch 'roundcubemail-plugins-kolab-3.1' - 4 commits - plugins/calendar plugins/libcalendaring plugins/libkolab plugins/tasklist
Thomas Brüderli
bruederli at kolabsys.com
Thu May 1 17:15:12 CEST 2014
plugins/calendar/drivers/calendar_driver.php | 13 +
plugins/calendar/drivers/kolab/kolab_driver.php | 2
plugins/libcalendaring/libcalendaring.php | 18 +-
plugins/libcalendaring/libvcalendar.php | 71 +++++++-
plugins/libcalendaring/localization/en_US.inc | 1
plugins/libcalendaring/tests/libvcalendar.php | 63 ++++++-
plugins/libcalendaring/tests/resources/alarms.ics | 51 ++++++
plugins/libkolab/lib/kolab_format_xcal.php | 127 +++++++++++++--
plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php | 2
9 files changed, 318 insertions(+), 30 deletions(-)
New commits:
commit a42e9947797b7a0da6e5bb2020cc6202944fc815
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu May 1 17:13:10 2014 +0200
Fix legacy support for storing alarms: legacy option sets first entry, additional entries shall be preserved (#2972)
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 611d9c5..f7612f5 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -33,7 +33,7 @@ class kolab_driver extends calendar_driver
public $freebusy = true;
public $attachments = true;
public $undelete = true;
- public $alarm_types = array('DISPLAY');
+ public $alarm_types = array('DISPLAY','AUDIO');
public $categoriesimmutable = true;
private $rc;
diff --git a/plugins/libcalendaring/localization/en_US.inc b/plugins/libcalendaring/localization/en_US.inc
index 702aac5..ea5a18e 100644
--- a/plugins/libcalendaring/localization/en_US.inc
+++ b/plugins/libcalendaring/localization/en_US.inc
@@ -6,6 +6,7 @@ $labels['alarmemail'] = 'Send Email';
$labels['alarmdisplay'] = 'Show message';
$labels['alarmdisplayoption'] = 'Message';
$labels['alarmemailoption'] = 'Email';
+$labels['alarmaudiooption'] = 'Sound';
$labels['alarmat'] = 'at $datetime';
$labels['trigger@'] = 'on date';
$labels['trigger-M'] = 'minutes before';
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
index b3bf10e..76b7b3c 100644
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -227,7 +227,7 @@ abstract class kolab_format_xcal extends kolab_format
}
if ($start = self::php_datetime($alarm->start())) {
- $object['alarms'] = '@' . $start->format('U');
+ $trigger = '@' . $start->format('U');
$valarm['trigger'] = $start;
}
else if ($offset = $alarm->relativeStart()) {
@@ -245,7 +245,7 @@ abstract class kolab_format_xcal extends kolab_format
$time = '0S';
}
- $object['alarms'] = $prefix . $value . $time;
+ $trigger = $prefix . $value . $time;
$valarm['trigger'] = $prefix . 'P' . $value . ($time ? 'T' . $time : '');
}
@@ -261,8 +261,11 @@ abstract class kolab_format_xcal extends kolab_format
$valarm['repeat'] = $alarm->numrepeat();
}
- $object['alarms'] .= ':' . $type; // legacy property
$object['valarms'][] = array_filter($valarm);
+
+ if (!$object['alarms']) {
+ $object['alarms'] = $trigger . ':' . $type; // legacy property
+ }
}
}
@@ -508,6 +511,19 @@ abstract class kolab_format_xcal extends kolab_format
}
$valarms->push($alarm);
+
+ // preserve additional alarm entries
+ $oldvalarms = $this->obj->alarms();
+ for ($i=1; $i < $oldvalarms->size(); $i++) {
+ $valarms->push($oldvalarms->get($i));
+ }
+
+ // HACK: set and read back alarms to store the correct 'valarms' value in cache
+ if ($i > 1) {
+ $this->obj->setAlarms($valarms);
+ $update = $this->to_array();
+ $object['valarms'] = $update['valarms'];
+ }
}
$this->obj->setAlarms($valarms);
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
index 0cf31fb..92d0aff 100644
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -28,7 +28,7 @@ class tasklist_kolab_driver extends tasklist_driver
public $alarms = false;
public $attachments = true;
public $undelete = false; // task undelete action
- public $alarm_types = array('DISPLAY');
+ public $alarm_types = array('DISPLAY','AUDIO');
private $rc;
private $plugin;
commit 7f887e0a4e003a77a2eb2b3277d2296957099f9a
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu May 1 16:47:57 2014 +0200
Improve libcalendaring::parse_alaram_value() to parse iCal alarm values with zero values
diff --git a/plugins/libcalendaring/libcalendaring.php b/plugins/libcalendaring/libcalendaring.php
index 415a15c..c96807f 100644
--- a/plugins/libcalendaring/libcalendaring.php
+++ b/plugins/libcalendaring/libcalendaring.php
@@ -313,10 +313,22 @@ class libcalendaring extends rcube_plugin
*/
public static function parse_alaram_value($val)
{
- if ($val[0] == '@')
+ if ($val[0] == '@') {
return array(substr($val, 1));
- else if (preg_match('/([+-])P?T?(\d+)([HMSDW])/', $val, $m))
- return array($m[2], $m[1].$m[3]);
+ }
+ else if (preg_match('/([+-]?)P?(T?\d+[HMSDW])+/', $val, $m) && preg_match_all('/T?(\d+)([HMSDW])/', $val, $m2, PREG_SET_ORDER)) {
+ if ($m[1] == '')
+ $m[1] = '+';
+ foreach ($m2 as $seg) {
+ $prefix = $seg[2] == 'D' || $seg[2] == 'W' ? 'P' : 'PT';
+ if ($seg[1] > 0) { // ignore zero values
+ return array($seg[1], $m[1].$seg[2], $m[1].$seg[1].$seg[2], $m[1].$prefix.$seg[1].$seg[2]);
+ }
+ }
+
+ // return zero value nevertheless
+ return array($seg[1], $m[1].$seg[2], $m[1].$seg[1].$seg[2], $m[1].$prefix.$seg[1].$seg[2]);
+ }
return false;
}
diff --git a/plugins/libcalendaring/tests/libvcalendar.php b/plugins/libcalendaring/tests/libvcalendar.php
index b6b713f..f0fe704 100644
--- a/plugins/libcalendaring/tests/libvcalendar.php
+++ b/plugins/libcalendaring/tests/libvcalendar.php
@@ -186,6 +186,10 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
// alarm trigger with 0 values
$events = $ical->import_from_file(__DIR__ . '/resources/alarms.ics', 'UTF-8');
+ $event = $events[0];
+
+ $this->assertEquals('-30M:DISPLAY', $event['alarms'], "Stripped alarm string");
+ $alarm = libcalendaring::parse_alaram_value($event['alarms']);
$this->assertEquals('-30M', $alarm[2], "Alarm string");
$this->assertEquals('DISPLAY', $event['valarms'][0]['action'], "First alarm action");
commit 32a3b432b1d97a06993d35a72994fd411744806a
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Apr 3 18:38:26 2014 +0200
Fix storing of (multiple) event alarms
diff --git a/plugins/libcalendaring/libvcalendar.php b/plugins/libcalendaring/libvcalendar.php
index aef62c2..87adbab 100644
--- a/plugins/libcalendaring/libvcalendar.php
+++ b/plugins/libcalendaring/libvcalendar.php
@@ -580,7 +580,13 @@ class libvcalendar implements Iterator
if (!$trigger && ($values = libcalendaring::parse_alaram_value($prop->value))) {
$trigger = $values[2];
+ }
+
+ if (!$alarm['trigger']) {
$alarm['trigger'] = rtrim(preg_replace('/([A-Z])0[WDHMS]/', '\\1', $prop->value), 'T');
+ // if all 0-values have been stripped, assume 'at time'
+ if ($alarm['trigger'] == 'P')
+ $alarm['trigger'] = 'PT0S';
}
break;
@@ -604,10 +610,12 @@ class libvcalendar implements Iterator
}
}
- if ($trigger && strtoupper($action) != 'NONE') {
- if (!$event['alarms']) // store first alarm in legacy property
+ if ($action != 'NONE') {
+ if ($trigger && !$event['alarms']) // store first alarm in legacy property
$event['alarms'] = $trigger . ':' . $action;
- $event['valarms'][] = $alarm;
+
+ if ($alarm['trigger'])
+ $event['valarms'][] = $alarm;
}
}
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
index 9c5bed9..b3bf10e 100644
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -238,7 +238,12 @@ abstract class kolab_format_xcal extends kolab_format
else if ($h = $offset->hours()) $time .= $h . 'H';
else if ($m = $offset->minutes()) $time .= $m . 'M';
else if ($s = $offset->seconds()) $time .= $s . 'S';
- else continue;
+
+ // assume 'at event time'
+ if (empty($value) && empty($time)) {
+ $prefix = '';
+ $time = '0S';
+ }
$object['alarms'] = $prefix . $value . $time;
$valarm['trigger'] = $prefix . 'P' . $value . ($time ? 'T' . $time : '');
@@ -423,11 +428,11 @@ abstract class kolab_format_xcal extends kolab_format
$valarms = new vectoralarm;
if ($object['valarms']) {
foreach ($object['valarms'] as $valarm) {
- if (!array_key_exists($valarm['type'], $this->alarm_type_map)) {
+ if (!array_key_exists($valarm['action'], $this->alarm_type_map)) {
continue; // skip unknown alarm types
}
- if ($valarm['type'] == 'EMAIL') {
+ if ($valarm['action'] == 'EMAIL') {
$recipients = new vectorcontactref;
foreach (($valarm['attendees'] ?: array($object['_owner'])) as $email) {
$recipients->push(new ContactReference(ContactReference::EmailReference, $email));
@@ -448,11 +453,12 @@ abstract class kolab_format_xcal extends kolab_format
else {
try {
$prefix = $valarm['trigger'][0];
- $period = new DateInterval(preg_replace('/[0-9PTWDHMS]/', '', $valarm['trigger']));
+ $period = new DateInterval(preg_replace('/[^0-9PTWDHMS]/', '', $valarm['trigger']));
$duration = new Duration($period->d, $period->h, $period->i, $period->s, $prefix == '-');
}
catch (Exception $e) {
// skip alarm with invalid trigger values
+ rcube::raise_error($e, true);
continue;
}
commit a595454bdddea0c5ebeec910553455588f63c91d
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Apr 3 17:39:26 2014 +0200
Improve libs to support multiple VALARM items according to iCal standards, including action-specific properties
Conflicts:
plugins/libcalendaring/libvcalendar.php
plugins/libcalendaring/tests/libvcalendar.php
plugins/libcalendaring/tests/resources/alarms.ics
diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php
index c09d8b9..02e1e68 100644
--- a/plugins/calendar/drivers/calendar_driver.php
+++ b/plugins/calendar/drivers/calendar_driver.php
@@ -54,7 +54,18 @@
* 'free_busy' => 'free|busy|outofoffice|tentative', // Show time as
* 'priority' => 0-9, // Event priority (0=undefined, 1=highest, 9=lowest)
* 'sensitivity' => 'public|private|confidential', // Event sensitivity
- * 'alarms' => '-15M:DISPLAY', // Reminder settings inspired by valarm definition (e.g. display alert 15 minutes before event)
+ * 'alarms' => '-15M:DISPLAY', // DEPRECATED Reminder settings inspired by valarm definition (e.g. display alert 15 minutes before event)
+ * 'valarms' => array( // List of reminders (new format), each represented as a hash array:
+ * array(
+ * 'trigger' => '-PT90M', // ISO 8601 period string prefixed with '+' or '-', or DateTime object
+ * 'action' => 'DISPLAY|EMAIL|AUDIO',
+ * 'duration' => 'PT15M', // ISO 8601 period string
+ * 'repeat' => 0, // number of repetitions
+ * 'description' => '', // text to display for DISPLAY actions
+ * 'summary' => '', // message text for EMAIL actions
+ * 'attendees' => array(), // list of email addresses to receive alarm messages
+ * ),
+ * ),
* 'attachments' => array( // List of attachments
* 'name' => 'File name',
* 'mimetype' => 'Content type',
diff --git a/plugins/libcalendaring/libvcalendar.php b/plugins/libcalendaring/libvcalendar.php
index 19ef12d..aef62c2 100644
--- a/plugins/libcalendaring/libvcalendar.php
+++ b/plugins/libcalendaring/libvcalendar.php
@@ -566,6 +566,7 @@ class libvcalendar implements Iterator
foreach ($ve->select('VALARM') as $valarm) {
$action = 'DISPLAY';
$trigger = null;
+ $alarm = array();
foreach ($valarm->children as $prop) {
switch ($prop->name) {
@@ -573,22 +574,40 @@ class libvcalendar implements Iterator
foreach ($prop->parameters as $param) {
if ($param->name == 'VALUE' && $param->value == 'DATE-TIME') {
$trigger = '@' . $prop->getDateTime()->format('U');
+ $alarm['trigger'] = $prop->getDateTime();
}
}
- if (!$trigger) {
- $trigger = preg_replace('/PT?/', '', $prop->value);
+
+ if (!$trigger && ($values = libcalendaring::parse_alaram_value($prop->value))) {
+ $trigger = $values[2];
+ $alarm['trigger'] = rtrim(preg_replace('/([A-Z])0[WDHMS]/', '\\1', $prop->value), 'T');
}
break;
case 'ACTION':
- $action = $prop->value;
+ $action = $alarm['action'] = strtoupper($prop->value);
+ break;
+
+ case 'SUMMARY':
+ case 'DESCRIPTION':
+ case 'DURATION':
+ $alarm[strtolower($prop->name)] = self::convert_string($prop);
+ break;
+
+ case 'REPEAT':
+ $alarm['repeat'] = intval($prop->value);
+ break;
+
+ case 'ATTENDEE':
+ $alarm['attendees'][] = preg_replace('/^mailto:/i', '', $prop->value);
break;
}
}
if ($trigger && strtoupper($action) != 'NONE') {
- $event['alarms'] = $trigger . ':' . $action;
- break;
+ if (!$event['alarms']) // store first alarm in legacy property
+ $event['alarms'] = $trigger . ':' . $action;
+ $event['valarms'][] = $alarm;
}
}
@@ -945,7 +964,37 @@ class libvcalendar implements Iterator
$ve->add(self::datetime_prop('COMPLETED', $event['changed'] ?: new DateTime('now - 1 hour'), true));
}
- if ($event['alarms']) {
+ if ($event['valarms']) {
+ foreach ($event['valarms'] as $alarm) {
+ $va = VObject\Component::create('VALARM');
+ $va->action = $alarm['action'];
+ if ($alarm['trigger'] instanceof DateTime) {
+ $va->add(self::datetime_prop('TRIGGER', $alarm['trigger'], true));
+ }
+ else {
+ $va->add('TRIGGER', $alarm['trigger']);
+ }
+
+ if ($alarm['action'] == 'EMAIL') {
+ foreach ((array)$alarm['attendees'] as $attendee) {
+ $va->add('ATTENDEE', 'mailto:' . $attendee);
+ }
+ }
+ if ($alarm['description']) {
+ $va->add('DESCRIPTION', $alarm['description'] ?: $event['title']);
+ }
+ if ($alarm['summary']) {
+ $va->add('SUMMARY', $alarm['summary']);
+ }
+ if ($alarm['duration']) {
+ $va->add('DURATION', $alarm['duration']);
+ $va->add('REPEAT', intval($alarm['repeat']));
+ }
+ $ve->add($va);
+ }
+ }
+ // legacy support
+ else if ($event['alarms']) {
$va = VObject\Component::create('VALARM');
list($trigger, $va->action) = explode(':', $event['alarms']);
$val = libcalendaring::parse_alaram_value($trigger);
diff --git a/plugins/libcalendaring/tests/libvcalendar.php b/plugins/libcalendaring/tests/libvcalendar.php
index 88a244f..b6b713f 100644
--- a/plugins/libcalendaring/tests/libvcalendar.php
+++ b/plugins/libcalendaring/tests/libvcalendar.php
@@ -168,19 +168,44 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
}
/**
- * @depends test_import
+ *
*/
- function test_apple_alarms()
+ function test_alarms()
{
$ical = new libvcalendar();
- $events = $ical->import_from_file(__DIR__ . '/resources/apple-alarms.ics', 'UTF-8');
+ $events = $ical->import_from_file(__DIR__ . '/resources/recurring.ics', 'UTF-8');
$event = $events[0];
- // alarms
- $this->assertEquals('-45M:AUDIO', $event['alarms'], "Relative alarm string");
+ $this->assertEquals('-12H:DISPLAY', $event['alarms'], "Serialized alarms string");
$alarm = libcalendaring::parse_alaram_value($event['alarms']);
- $this->assertEquals('45', $alarm[0], "Alarm value");
- $this->assertEquals('-M', $alarm[1], "Alarm unit");
+ $this->assertEquals('12', $alarm[0], "Alarm value");
+ $this->assertEquals('-H', $alarm[1], "Alarm unit");
+
+ $this->assertEquals('DISPLAY', $event['valarms'][0]['action'], "Full alarm item (action)");
+ $this->assertEquals('-PT12H', $event['valarms'][0]['trigger'], "Full alarm item (trigger)");
+
+ // alarm trigger with 0 values
+ $events = $ical->import_from_file(__DIR__ . '/resources/alarms.ics', 'UTF-8');
+ $this->assertEquals('-30M', $alarm[2], "Alarm string");
+
+ $this->assertEquals('DISPLAY', $event['valarms'][0]['action'], "First alarm action");
+ $this->assertEquals('This is the first event reminder', $event['valarms'][0]['description'], "First alarm text");
+
+ $this->assertEquals(2, count($event['valarms']), "List all VALARM blocks");
+
+ $valarm = $event['valarms'][1];
+ $this->assertEquals(1, count($valarm['attendees']), "Email alarm attendees");
+ $this->assertEquals('EMAIL', $valarm['action'], "Second alarm item (action)");
+ $this->assertEquals('-P1D', $valarm['trigger'], "Second alarm item (trigger)");
+ $this->assertEquals('This is the reminder message', $valarm['summary'], "Email alarm text");
+
+ // test alarms export
+ $ics = $ical->export(array($event));
+ $this->assertContains('ACTION:DISPLAY', $ics, "Display alarm block");
+ $this->assertContains('ACTION:EMAIL', $ics, "Email alarm block");
+ $this->assertContains('DESCRIPTION:This is the first event reminder', $ics, "Alarm description");
+ $this->assertContains('SUMMARY:This is the reminder message', $ics, "Email alarm summary");
+ $this->assertContains('ATTENDEE:mailto:reminder-recipient at example.org', $ics, "Email alarm recipient");
}
/**
@@ -200,6 +225,26 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
}
/**
+ * @depends test_import
+ */
+ function test_apple_alarms()
+ {
+ $ical = new libvcalendar();
+ $events = $ical->import_from_file(__DIR__ . '/resources/apple-alarms.ics', 'UTF-8');
+ $event = $events[0];
+
+ // alarms
+ $this->assertEquals('-45M:AUDIO', $event['alarms'], "Relative alarm string");
+ $alarm = libcalendaring::parse_alaram_value($event['alarms']);
+ $this->assertEquals('45', $alarm[0], "Alarm value");
+ $this->assertEquals('-M', $alarm[1], "Alarm unit");
+
+ $this->assertEquals(1, count($event['valarms']), "Ignore invalid alarm blocks");
+ $this->assertEquals('AUDIO', $event['valarms'][0]['action'], "Full alarm item (action)");
+ $this->assertEquals('-PT45M', $event['valarms'][0]['trigger'], "Full alarm item (trigger)");
+ }
+
+ /**
*
*/
function test_escaped_values()
diff --git a/plugins/libcalendaring/tests/resources/alarms.ics b/plugins/libcalendaring/tests/resources/alarms.ics
new file mode 100644
index 0000000..d6f9d54
--- /dev/null
+++ b/plugins/libcalendaring/tests/resources/alarms.ics
@@ -0,0 +1,51 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 5.0.3//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Europe/Zurich
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+DTSTART:19810329T020000
+TZNAME:CEST
+TZOFFSETTO:+0200
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+DTSTART:19961027T030000
+TZNAME:CET
+TZOFFSETTO:+0100
+END:STANDARD
+END:VTIMEZONE
+
+BEGIN:VEVENT
+UID:1dq52u617gkfqrr4uo1i2uh70
+CREATED:20130924T221822Z
+DESCRIPTION:
+DTSTART:20130818T230000Z
+DTEND:20130819T010000Z
+DTSTAMP:20130824T235608Z
+LAST-MODIFIED:20130924T222118Z
+LOCATION:
+SEQUENCE:2
+STATUS:CONFIRMED
+SUMMARY:Alarms test
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:This is the first event reminder
+TRIGGER:-P0DT0H30M0S
+END:VALARM
+BEGIN:VALARM
+ACTION:EMAIL
+DESCRIPTION:This is an event reminder
+TRIGGER:-P1D
+ATTENDEE:mailto:reminder-recipient at example.org
+SUMMARY:This is the reminder message
+DESCRIPTION:This is the second event reminder
+END:VALARM
+END:VEVENT
+
+END:VCALENDAR
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
index 5de82e0..9c5bed9 100644
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -205,27 +205,59 @@ abstract class kolab_format_xcal extends kolab_format
// read alarm
$valarms = $this->obj->alarms();
$alarm_types = array_flip($this->alarm_type_map);
+ $object['valarms'] = array();
for ($i=0; $i < $valarms->size(); $i++) {
$alarm = $valarms->get($i);
$type = $alarm_types[$alarm->type()];
if ($type == 'DISPLAY' || $type == 'EMAIL') { // only DISPLAY and EMAIL alarms are supported
+ $valarm = array(
+ 'action' => $type,
+ 'summary' => $alarm->summary(),
+ 'description' => $alarm->description(),
+ );
+
+ if ($type == 'EMAIL') {
+ $valarm['attendees'] = array();
+ $attvec = $this->obj->attendees();
+ for ($j=0; $j < $attvec->size(); $j++) {
+ $cr = $attvec->get($j);
+ $valarm['attendees'][] = $cr->email();
+ }
+ }
+
if ($start = self::php_datetime($alarm->start())) {
$object['alarms'] = '@' . $start->format('U');
+ $valarm['trigger'] = $start;
}
else if ($offset = $alarm->relativeStart()) {
- $value = $alarm->relativeTo() == kolabformat::End ? '+' : '-';
+ $prefix = $alarm->relativeTo() == kolabformat::End ? '+' : '-';
+ $value = $time = '';
if ($w = $offset->weeks()) $value .= $w . 'W';
else if ($d = $offset->days()) $value .= $d . 'D';
- else if ($h = $offset->hours()) $value .= $h . 'H';
- else if ($m = $offset->minutes()) $value .= $m . 'M';
- else if ($s = $offset->seconds()) $value .= $s . 'S';
+ else if ($h = $offset->hours()) $time .= $h . 'H';
+ else if ($m = $offset->minutes()) $time .= $m . 'M';
+ else if ($s = $offset->seconds()) $time .= $s . 'S';
else continue;
- $object['alarms'] = $value;
+ $object['alarms'] = $prefix . $value . $time;
+ $valarm['trigger'] = $prefix . 'P' . $value . ($time ? 'T' . $time : '');
+ }
+
+ // read alarm duration and repeat properties
+ if (($duration = $alarm->duration()) && $duration->isValid()) {
+ $value = $time = '';
+ if ($w = $duration->weeks()) $value .= $w . 'W';
+ else if ($d = $duration->days()) $value .= $d . 'D';
+ else if ($h = $duration->hours()) $time .= $h . 'H';
+ else if ($m = $duration->minutes()) $time .= $m . 'M';
+ else if ($s = $duration->seconds()) $time .= $s . 'S';
+ $valarm['duration'] = 'P' . $value . ($time ? 'T' . $time : '');
+ $valarm['repeat'] = $alarm->numrepeat();
}
- $object['alarms'] .= ':' . $type;
- break;
+
+ $object['alarms'] .= ':' . $type; // legacy property
+ $object['valarms'][] = array_filter($valarm);
}
}
@@ -389,7 +421,60 @@ abstract class kolab_format_xcal extends kolab_format
// save alarm
$valarms = new vectoralarm;
- if ($object['alarms']) {
+ if ($object['valarms']) {
+ foreach ($object['valarms'] as $valarm) {
+ if (!array_key_exists($valarm['type'], $this->alarm_type_map)) {
+ continue; // skip unknown alarm types
+ }
+
+ if ($valarm['type'] == 'EMAIL') {
+ $recipients = new vectorcontactref;
+ foreach (($valarm['attendees'] ?: array($object['_owner'])) as $email) {
+ $recipients->push(new ContactReference(ContactReference::EmailReference, $email));
+ }
+ $alarm = new Alarm(
+ strval($valarm['summary'] ?: $object['title']),
+ strval($valarm['description'] ?: $object['description']),
+ $recipients
+ );
+ }
+ else {
+ $alarm = new Alarm(strval($valarm['summary'] ?: $object['title']));
+ }
+
+ if (is_object($valarm['trigger']) && $valarm['trigger'] instanceof DateTime) {
+ $alarm->setStart(self::get_datetime($valarm['trigger'], new DateTimeZone('UTC')));
+ }
+ else {
+ try {
+ $prefix = $valarm['trigger'][0];
+ $period = new DateInterval(preg_replace('/[0-9PTWDHMS]/', '', $valarm['trigger']));
+ $duration = new Duration($period->d, $period->h, $period->i, $period->s, $prefix == '-');
+ }
+ catch (Exception $e) {
+ // skip alarm with invalid trigger values
+ continue;
+ }
+
+ $alarm->setRelativeStart($duration, $prefix == '-' ? kolabformat::Start : kolabformat::End);
+ }
+
+ if ($valarm['duration']) {
+ try {
+ $d = new DateInterval($valarm['duration']);
+ $duration = new Duration($d->d, $d->h, $d->i, $d->s);
+ $alarm->setDuration($duration, intval($valarm['repeat']));
+ }
+ catch (Exception $e) {
+ // ignore
+ }
+ }
+
+ $valarms->push($alarm);
+ }
+ }
+ // legacy support
+ else if ($object['alarms']) {
list($offset, $type) = explode(":", $object['alarms']);
if ($type == 'EMAIL' && !empty($object['_owner'])) { // email alarms implicitly go to event owner
More information about the commits
mailing list