* 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!)

This commit is contained in:
Ralf Becker 2013-02-27 14:36:13 +00:00
parent 8f4d044041
commit ea2809369b
2 changed files with 41 additions and 88 deletions

View File

@ -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')) &&

View File

@ -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)
*/