summaryrefslogtreecommitdiff
path: root/plugins/libkolab
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2015-02-20 09:18:59 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2015-02-20 09:18:59 (GMT)
commit52bbf63a8e0c6a785facc395206d1a1f11ee7d05 (patch)
tree49a92853df52f22d341c1aac31a80af1b3ab9360 /plugins/libkolab
parent5966cff343a2c44c7160c7db56f0c563a1d5dcb0 (diff)
parentf972f4a511a7c3710ec5f5cee001133837797923 (diff)
downloadroundcubemail-plugins-kolab-52bbf63a8e0c6a785facc395206d1a1f11ee7d05.tar.gz
Merge branch 'dev/recurring-invitations'
Diffstat (limited to 'plugins/libkolab')
-rw-r--r--plugins/libkolab/config.inc.php.dist2
-rw-r--r--plugins/libkolab/lib/kolab_date_recurrence.php6
-rw-r--r--plugins/libkolab/lib/kolab_format_event.php25
-rw-r--r--plugins/libkolab/lib/kolab_format_task.php26
-rw-r--r--plugins/libkolab/lib/kolab_format_xcal.php74
-rw-r--r--plugins/libkolab/lib/kolab_storage_folder.php7
6 files changed, 98 insertions, 42 deletions
diff --git a/plugins/libkolab/config.inc.php.dist b/plugins/libkolab/config.inc.php.dist
index 6e4b613..3a8476c 100644
--- a/plugins/libkolab/config.inc.php.dist
+++ b/plugins/libkolab/config.inc.php.dist
@@ -41,7 +41,7 @@ $config['kolab_messages_cache_bypass'] = 0;
// These event properties contribute to a significant revision to the calendar component
// and if changed will increment the sequence number relevant for scheduling according to RFC 5545
-$config['kolab_event_scheduling_properties'] = array('start', 'end', 'allday', 'location', 'status', 'cancelled');
+$config['kolab_event_scheduling_properties'] = array('start', 'end', 'allday', 'recurrence', 'location', 'status', 'cancelled');
// These task properties contribute to a significant revision to the calendar component
// and if changed will increment the sequence number relevant for scheduling according to RFC 5545
diff --git a/plugins/libkolab/lib/kolab_date_recurrence.php b/plugins/libkolab/lib/kolab_date_recurrence.php
index 06dd331..b2511f2 100644
--- a/plugins/libkolab/lib/kolab_date_recurrence.php
+++ b/plugins/libkolab/lib/kolab_date_recurrence.php
@@ -87,9 +87,13 @@ class kolab_date_recurrence
$next_end->add($this->duration);
$next = $this->object->to_array();
- $next['recurrence_id'] = $next_start->format('Y-m-d');
$next['start'] = $next_start;
$next['end'] = $next_end;
+
+ $recurrence_id_format = $next['allday'] ? 'Ymd' : 'Ymd\THis';
+ $next['recurrence_date'] = clone $next_start;
+ $next['_instance'] = $next_start->format($recurrence_id_format);
+
unset($next['_formatobj']);
return $next;
diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php
index 075c517..91efb26 100644
--- a/plugins/libkolab/lib/kolab_format_event.php
+++ b/plugins/libkolab/lib/kolab_format_event.php
@@ -26,7 +26,7 @@ class kolab_format_event extends kolab_format_xcal
{
public $CTYPEv2 = 'application/x-vnd.kolab.event';
- public static $scheduling_properties = array('start', 'end', 'allday', 'location', 'status', 'cancelled');
+ public static $scheduling_properties = array('start', 'end', 'allday', 'recurrence', 'location', 'status', 'cancelled');
protected $objclass = 'Event';
protected $read_func = 'readEvent';
@@ -44,6 +44,9 @@ class kolab_format_event extends kolab_format_xcal
$this->obj = $data;
$this->loaded = true;
}
+
+ // copy static property overriden by this class
+ $this->_scheduling_properties = self::$scheduling_properties;
}
/**
@@ -115,10 +118,13 @@ class kolab_format_event extends kolab_format_xcal
$vexceptions->push($exevent->obj);
// write cleaned-up exception data back to memory/cache
- $object['recurrence']['EXCEPTIONS'][$i] = $this->expand_exception($compacted, $object);
+ $object['recurrence']['EXCEPTIONS'][$i] = $this->expand_exception($exevent->data, $object);
}
$this->obj->setExceptions($vexceptions);
}
+ else if ($object['recurrence_date'] && $object['recurrence_date'] instanceof DateTime) {
+ $this->obj->setRecurrenceID(self::get_datetime($object['recurrence_date'], null, $object['allday']), (bool)$object['thisandfuture']);
+ }
// cache this data
$this->data = $object;
@@ -220,15 +226,16 @@ class kolab_format_event extends kolab_format_xcal
*
* @return array List of tags to save in cache
*/
- public function get_tags()
+ public function get_tags($obj = null)
{
- $tags = parent::get_tags();
+ $tags = parent::get_tags($obj);
+ $object = $obj ?: $this->data;
- foreach ((array)$this->data['categories'] as $cat) {
+ foreach ((array)$object['categories'] as $cat) {
$tags[] = rcube_utils::normalize_string($cat);
}
- return $tags;
+ return array_unique($tags);
}
/**
@@ -244,12 +251,6 @@ class kolab_format_event extends kolab_format_xcal
}
}
- foreach ($master as $prop => $value) {
- if (isset($exception[$prop]) && gettype($exception[$prop]) == gettype($value) && $exception[$prop] == $value) {
- unset($exception[$prop]);
- }
- }
-
// preserve this property for date serialization
$exception['allday'] = $master['allday'];
diff --git a/plugins/libkolab/lib/kolab_format_task.php b/plugins/libkolab/lib/kolab_format_task.php
index ee0ca6a..4640875 100644
--- a/plugins/libkolab/lib/kolab_format_task.php
+++ b/plugins/libkolab/lib/kolab_format_task.php
@@ -32,6 +32,16 @@ class kolab_format_task extends kolab_format_xcal
protected $read_func = 'readTodo';
protected $write_func = 'writeTodo';
+ /**
+ * Default constructor
+ */
+ function __construct($data = null, $version = 3.0)
+ {
+ parent::__construct(is_string($data) ? $data : null, $version);
+
+ // copy static property overriden by this class
+ $this->_scheduling_properties = self::$scheduling_properties;
+ }
/**
* Set properties to the kolabformat object
@@ -111,19 +121,21 @@ class kolab_format_task extends kolab_format_xcal
*
* @return array List of tags to save in cache
*/
- public function get_tags()
+ public function get_tags($obj = null)
{
- $tags = parent::get_tags();
+ $tags = parent::get_tags($obj);
+ $object = $obj ?: $this->data;
- if ($this->data['status'] == 'COMPLETED' || ($this->data['complete'] == 100 && empty($this->data['status'])))
+ if ($object['status'] == 'COMPLETED' || ($object['complete'] == 100 && empty($object['status'])))
$tags[] = 'x-complete';
- if ($this->data['priority'] == 1)
+ if ($object['priority'] == 1)
$tags[] = 'x-flagged';
- if ($this->data['parent_id'])
- $tags[] = 'x-parent:' . $this->data['parent_id'];
+ if ($object['parent_id'])
+ $tags[] = 'x-parent:' . $object['parent_id'];
- return $tags;
+ return array_unique($tags);
}
+
}
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
index d0f89b6..4d3a758 100644
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -32,6 +32,8 @@ abstract class kolab_format_xcal extends kolab_format
public static $scheduling_properties = array('start', 'end', 'location');
+ protected $_scheduling_properties = null;
+
protected $sensitivity_map = array(
'public' => kolabformat::ClassPublic,
'private' => kolabformat::ClassPrivate,
@@ -317,21 +319,11 @@ abstract class kolab_format_xcal extends kolab_format
}
else {
$object['sequence'] = $old_sequence;
- $old = $this->data['uid'] ? $this->data : $this->to_array();
// increment sequence when updating properties relevant for scheduling.
// RFC 5545: "It is incremented [...] each time the Organizer makes a significant revision to the calendar component."
- foreach (self::$scheduling_properties as $prop) {
- $a = $old[$prop];
- $b = $object[$prop];
- if ($object['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
- $a = $a->format('Y-m-d');
- $b = $b->format('Y-m-d');
- }
- if ($a != $b) {
- $object['sequence']++;
- break;
- }
+ if ($this->check_rescheduling($object)) {
+ $object['sequence']++;
}
}
}
@@ -365,7 +357,7 @@ abstract class kolab_format_xcal extends kolab_format
// set attendee RSVP if missing
if (!isset($attendee['rsvp'])) {
- $object['attendees'][$i]['rsvp'] = $attendee['rsvp'] = true;
+ $object['attendees'][$i]['rsvp'] = $attendee['rsvp'] = $reschedule;
}
$att = new Attendee;
@@ -619,22 +611,68 @@ abstract class kolab_format_xcal extends kolab_format
*
* @return array List of tags to save in cache
*/
- public function get_tags()
+ public function get_tags($obj = null)
{
$tags = array();
+ $object = $obj ?: $this->data;
- if (!empty($this->data['valarms'])) {
+ if (!empty($object['valarms'])) {
$tags[] = 'x-has-alarms';
}
// create tags reflecting participant status
- if (is_array($this->data['attendees'])) {
- foreach ($this->data['attendees'] as $attendee) {
+ if (is_array($object['attendees'])) {
+ foreach ($object['attendees'] as $attendee) {
if (!empty($attendee['email']) && !empty($attendee['status']))
$tags[] = 'x-partstat:' . $attendee['email'] . ':' . strtolower($attendee['status']);
}
}
- return $tags;
+ // collect tags from recurrence exceptions
+ if (is_array($object['recurrence']) && $object['recurrence']['EXCEPTIONS']) {
+ foreach((array)$object['recurrence']['EXCEPTIONS'] as $exception) {
+ $tags = array_merge($tags, $this->get_tags($exception));
+ }
+ }
+
+ return array_unique($tags);
+ }
+
+ /**
+ * Identify changes considered relevant for scheduling
+ *
+ * @param array Hash array with NEW object properties
+ * @param array Hash array with OLD object properties
+ *
+ * @return boolean True if changes affect scheduling, False otherwise
+ */
+ public function check_rescheduling($object, $old = null)
+ {
+ $reschedule = false;
+
+ if (!is_array($old)) {
+ $old = $this->data['uid'] ? $this->data : $this->to_array();
+ }
+
+ foreach ($this->_scheduling_properties ?: self::$scheduling_properties as $prop) {
+ $a = $old[$prop];
+ $b = $object[$prop];
+ if ($object['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
+ $a = $a->format('Y-m-d');
+ $b = $b->format('Y-m-d');
+ }
+ if ($prop == 'recurrence' && is_array($a) && is_array($b)) {
+ unset($a['EXCEPTIONS']);
+ unset($b['EXCEPTIONS']);
+ $a = array_filter($a);
+ $b = array_filter($b);
+ }
+ if ($a != $b) {
+ $reschedule = true;
+ break;
+ }
+ }
+
+ return $reschedule;
}
} \ No newline at end of file
diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
index ab3c63f..e0bf52e 100644
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -616,7 +616,8 @@ class kolab_storage_folder extends kolab_storage_folder_api
$type = $this->type;
// copy attachments from old message
- if (!empty($object['_msguid']) && ($old = $this->cache->get($object['_msguid'], $type, $object['_mailbox']))) {
+ $copyfrom = $object['_copyfrom'] ?: $object['_msguid'];
+ if (!empty($copyfrom) && ($old = $this->cache->get($copyfrom, $type, $object['_mailbox']))) {
foreach ((array)$old['_attachments'] as $key => $att) {
if (!isset($object['_attachments'][$key])) {
$object['_attachments'][$key] = $old['_attachments'][$key];
@@ -628,7 +629,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
// load photo.attachment from old Kolab2 format to be directly embedded in xcard block
else if ($type == 'contact' && ($key == 'photo.attachment' || $key == 'kolab-picture.png') && $att['id']) {
if (!isset($object['photo']))
- $object['photo'] = $this->get_attachment($object['_msguid'], $att['id'], $object['_mailbox']);
+ $object['photo'] = $this->get_attachment($copyfrom, $att['id'], $object['_mailbox']);
unset($object['_attachments'][$key]);
}
}
@@ -1010,7 +1011,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
foreach ((array)$object['_attachments'] as $key => $att) {
if (empty($att['content']) && !empty($att['id'])) {
// @TODO: use IMAP CATENATE to skip attachment fetch+push operation
- $msguid = !empty($object['_msguid']) ? $object['_msguid'] : $object['uid'];
+ $msguid = $object['_copyfrom'] ?: ($object['_msguid'] ?: $object['uid']);
if ($is_file) {
$att['path'] = tempnam($temp_dir, 'rcmAttmnt');
if (($fp = fopen($att['path'], 'w')) && $this->get_attachment($msguid, $att['id'], $object['_mailbox'], false, $fp, true)) {