From ea2809369b54816ce22191231f025a2b0dfe44cd Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 27 Feb 2013 14:36:13 +0000 Subject: [PATCH] * Calendar/CalDAV: fixed iCal parser calculating recurrence-enddate from COUNT parameter, taking into account BY* rules (RRULE:FREQ=WEEKLY;COUNT=4;BYDAY=Mo,Mi runs just 2 weeks!) --- calendar/inc/class.calendar_ical.inc.php | 103 ++++------------------ calendar/inc/class.calendar_rrule.inc.php | 26 ++++++ 2 files changed, 41 insertions(+), 88 deletions(-) diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 4c3c579342..2e73b5b91f 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -2493,34 +2493,13 @@ class calendar_ical extends calendar_boupdate } $vcardData['recur_type'] = MCAL_RECUR_WEEKLY; } - - if (!empty($vcardData['recur_count'])) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['start']), - date('d', $vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1)*7), - date('Y', $vcardData['start'])); - } break; case 'D': // 1.0 if (preg_match('/D(\d+) #(\d+)/', $recurence, $recurenceMatches)) { $vcardData['recur_interval'] = $recurenceMatches[1]; - if ($recurenceMatches[2] > 0 && $vcardData['end']) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['end']), - date('d', $vcardData['end']) + ($vcardData['recur_interval']*($recurenceMatches[2]-1)), - date('Y', $vcardData['end']) - ); - } + $vcardData['recur_count'] = $recurenceMatches[2]; } elseif (preg_match('/D(\d+) (.*)/', $recurence, $recurenceMatches)) { @@ -2532,17 +2511,6 @@ class calendar_ical extends calendar_boupdate // fall-through case 'DAILY': // 2.0 $vcardData['recur_type'] = MCAL_RECUR_DAILY; - - if (!empty($vcardData['recur_count'])) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['start']), - date('d', $vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1)), - date('Y', $vcardData['start'])); - } break; case 'M': @@ -2550,17 +2518,7 @@ class calendar_ical extends calendar_boupdate { $vcardData['recur_type'] = MCAL_RECUR_MONTHLY_MDAY; $vcardData['recur_interval'] = $recurenceMatches[1]; - if ($recurenceMatches[2] > 0 && $vcardData['end']) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['end']) + ($vcardData['recur_interval']*($recurenceMatches[2]-1)), - date('d', $vcardData['end']), - date('Y', $vcardData['end']) - ); - } + $vcardData['recur_count'] = $recurenceMatches[2]; } elseif (preg_match('/MD(\d+)(?: [^ ]+)? ([0-9TZ]+)/',$recurence, $recurenceMatches)) { @@ -2574,16 +2532,7 @@ class calendar_ical extends calendar_boupdate $vcardData['recur_interval'] = $recurenceMatches[1]; if (preg_match('/#(\d+)/',$recurenceMatches[4],$recurenceMatches)) { - if ($recurenceMatches[1]) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['start']) + ($vcardData['recur_interval']*($recurenceMatches[1]-1)), - date('d', $vcardData['start']), - date('Y', $vcardData['start'])); - } + $vcardData['recur_count'] = $recurenceMatches[1]; } else { @@ -2594,34 +2543,13 @@ class calendar_ical extends calendar_boupdate case 'MONTHLY': $vcardData['recur_type'] = strpos($recurence,'BYDAY') !== false ? MCAL_RECUR_MONTHLY_WDAY : MCAL_RECUR_MONTHLY_MDAY; - - if (!empty($vcardData['recur_count'])) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1)), - date('d', $vcardData['start']), - date('Y', $vcardData['start'])); - } break; case 'Y': // 1.0 if (preg_match('/YM(\d+)(?: [^ ]+)? #(\d+)/', $recurence, $recurenceMatches)) { $vcardData['recur_interval'] = $recurenceMatches[1]; - if ($recurenceMatches[2] > 0 && $vcardData['end']) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['end']), - date('d', $vcardData['end']), - date('Y', $vcardData['end']) + ($recurenceMatches[2] * $vcardData['recur_interval']) - ); - } + $vcardData['recur_count'] = $recurenceMatches[2]; } elseif (preg_match('/YM(\d+)(?: [^ ]+)? ([0-9TZ]+)/',$recurence, $recurenceMatches)) { @@ -2632,17 +2560,6 @@ class calendar_ical extends calendar_boupdate // fall-through case 'YEARLY': // 2.0 $vcardData['recur_type'] = MCAL_RECUR_YEARLY; - - if (!empty($vcardData['recur_count'])) - { - $vcardData['recur_enddate'] = mktime( - date('H', $vcardData['end']), - date('i', $vcardData['end']), - date('s', $vcardData['end']), - date('m', $vcardData['start']), - date('d', $vcardData['start']), - date('Y', $vcardData['start']) + ($vcardData['recur_interval']*($vcardData['recur_count']-1))); - } break; } break; @@ -2981,6 +2898,7 @@ class calendar_ical extends calendar_boupdate case 'recur_enddate': case 'recur_data': case 'recur_exception': + case 'recur_count': // not handled here break; @@ -2989,7 +2907,7 @@ class calendar_ical extends calendar_boupdate if ($event['recur_type'] != MCAL_RECUR_NONE) { $event['reference'] = 0; - foreach (array('recur_interval','recur_enddate','recur_data','recur_exception') as $r) + foreach (array('recur_interval','recur_enddate','recur_data','recur_exception','recur_count') as $r) { if (isset($vcardData[$r])) { @@ -3023,6 +2941,15 @@ class calendar_ical extends calendar_boupdate $last->setTime(0, 0, 0); $event['recur_enddate'] = egw_time::to($last, 'server'); } + // translate COUNT into an enddate, as we only store enddates + elseif($event['recur_count']) + { + $rriter = calendar_rrule::event2rrule($event, false); + $last = $rriter->count2date($event['recur_count']); + $last->setTime(0, 0, 0); + $event['recur_enddate'] = egw_time::to($last, 'server'); + unset($event['recur_count']); + } // Apple iCal on OS X uses X-CALENDARSERVER-ACCESS: CONFIDENTIAL on VCALANDAR (not VEVENT!) if (($x_calendarserver_access = $component->_container->getAttribute('X-CALENDARSERVER-ACCESS')) && diff --git a/calendar/inc/class.calendar_rrule.inc.php b/calendar/inc/class.calendar_rrule.inc.php index 788e9d2866..c0345d4939 100644 --- a/calendar/inc/class.calendar_rrule.inc.php +++ b/calendar/inc/class.calendar_rrule.inc.php @@ -465,6 +465,32 @@ class calendar_rrule implements Iterator return 1 << (int)$time->format('w'); } + /** + * Get datetime of n-th event, 1. is original event-time + * + * This is identical on COUNT parameter of RRULE is evaluated, exceptions are NOT taken into account! + * + * @param int $count + * @return DateTime + */ + public function count2date($count) + { + if ($count <= 1) + { + return clone $this->time; + } + if (isset($this->current)) $backup = $this->current; + $this->rewind(); + + while(--$count > 0) + { + $this->next_no_exception(); + } + $ret = clone $this->current; + if ($backup) $this->current = $backup; + return $ret; + } + /** * Rewind the Iterator to the first element (called at beginning of foreach loop) */