Fix various synchronization issues (SyncML & CalDAV)

This commit is contained in:
Jörg Lehrke 2010-02-17 13:29:28 +00:00
parent 8204d84ca5
commit 21ccdd5f28
9 changed files with 264 additions and 133 deletions

View File

@ -95,6 +95,7 @@ class calendar_bo
'R' => 'Rejected', 'R' => 'Rejected',
'T' => 'Tentative', 'T' => 'Tentative',
'U' => 'No Response', 'U' => 'No Response',
'D' => 'Delegated',
'G' => 'Group invitation', 'G' => 'Group invitation',
); );
/** /**
@ -1349,6 +1350,9 @@ class calendar_bo
case 'U': // no response = unknown case 'U': // no response = unknown
$status = html::image('calendar','cnr-pending',$this->verbose_status[$status]); $status = html::image('calendar','cnr-pending',$this->verbose_status[$status]);
break; break;
case 'D': // delegated
$status = html::image('calendar','forward',$this->verbose_status[$status]);
break;
case 'G': // group invitation case 'G': // group invitation
// Todo: Image, seems not to be used // Todo: Image, seems not to be used
$status = '('.$this->verbose_status[$status].')'; $status = '('.$this->verbose_status[$status].')';

View File

@ -20,6 +20,7 @@ define('MSG_TENTATIVE',4);
define('MSG_ACCEPTED',5); define('MSG_ACCEPTED',5);
define('MSG_ALARM',6); define('MSG_ALARM',6);
define('MSG_DISINVITE',7); define('MSG_DISINVITE',7);
define('MSG_DELEGATED',8);
/** /**
* Class to access AND manipulate all calendar data (business object) * Class to access AND manipulate all calendar data (business object)
@ -493,7 +494,7 @@ class calendar_boupdate extends calendar_bo
// the following switch falls through all cases, as each included the following too // the following switch falls through all cases, as each included the following too
// //
$msg_is_response = $msg_type == MSG_REJECTED || $msg_type == MSG_ACCEPTED || $msg_type == MSG_TENTATIVE; $msg_is_response = $msg_type == MSG_REJECTED || $msg_type == MSG_ACCEPTED || $msg_type == MSG_TENTATIVE || $msg_type == MSG_DELEGATED;
switch($ru = $part_prefs['calendar']['receive_updates']) switch($ru = $part_prefs['calendar']['receive_updates'])
{ {
@ -619,6 +620,12 @@ class calendar_boupdate extends calendar_bo
$msgtype = '"calendar";'; $msgtype = '"calendar";';
$method = 'REPLY'; $method = 'REPLY';
break; break;
case MSG_DELEGATED:
$action = lang('Delegated');
$msg = 'Response';
$msgtype = '"calendar";';
$method = 'REPLY';
break;
case MSG_ALARM: case MSG_ALARM:
$action = lang('Alarm'); $action = lang('Alarm');
$msg = 'Alarm'; $msg = 'Alarm';
@ -825,8 +832,16 @@ class calendar_boupdate extends calendar_bo
return false; return false;
} }
// invalidate the read-cache if it contains the event we store now if ($event['id'])
if ($event['id'] && $event['id'] == self::$cached_event['id']) self::$cached_event = array(); {
// invalidate the read-cache if it contains the event we store now
if ($event['id'] == self::$cached_event['id']) self::$cached_event = array();
$old_event = $this->read($event['id'], $event['recurrence'], false, 'server');
}
else
{
$old_event = null;
}
$save_event = $event; $save_event = $event;
// we run all dates through date2ts, to adjust to server-time and the possible date-formats // we run all dates through date2ts, to adjust to server-time and the possible date-formats
@ -858,8 +873,6 @@ class calendar_boupdate extends calendar_bo
} }
$set_recurrences = false; $set_recurrences = false;
$set_recurrences_start = 0; $set_recurrences_start = 0;
$old_event = $this->read($event['id'], $event['recurrence']);
if (($cal_id = $this->so->save($event,$set_recurrences,$set_recurrences_start,0,$event['etag'])) && $set_recurrences && $event['recur_type'] != MCAL_RECUR_NONE) if (($cal_id = $this->so->save($event,$set_recurrences,$set_recurrences_start,0,$event['etag'])) && $set_recurrences && $event['recur_type'] != MCAL_RECUR_NONE)
{ {
$save_event['id'] = $cal_id; $save_event['id'] = $cal_id;
@ -1062,7 +1075,7 @@ class calendar_boupdate extends calendar_bo
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"($cal_id, $uid, $status, $recur_date)"); "($cal_id, $uid, $status, $recur_date)");
} }
$old_event = $this->read($cal_id, $recur_date); $old_event = $this->read($cal_id, $recur_date, false, 'server');
if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],is_numeric($uid)?$uid:substr($uid,1),$status,$recur_date ? $this->date2ts($recur_date,true) : 0,$role))) if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],is_numeric($uid)?$uid:substr($uid,1),$status,$recur_date ? $this->date2ts($recur_date,true) : 0,$role)))
{ {
if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time()); if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time());
@ -1071,6 +1084,7 @@ class calendar_boupdate extends calendar_bo
'R' => MSG_REJECTED, 'R' => MSG_REJECTED,
'T' => MSG_TENTATIVE, 'T' => MSG_TENTATIVE,
'A' => MSG_ACCEPTED, 'A' => MSG_ACCEPTED,
'D' => MSG_DELEGATED,
); );
if (isset($status2msg[$status])) if (isset($status2msg[$status]))
{ {
@ -1080,7 +1094,7 @@ class calendar_boupdate extends calendar_bo
} }
// Update history // Update history
if (!is_array($event)) $event = $this->read($cal_id); $event = $this->read($cal_id, $recur_date, false, 'server');
$tracking = new calendar_tracking($this); $tracking = new calendar_tracking($this);
$tracking->track($event, $old_event); $tracking->track($event, $old_event);
@ -1098,8 +1112,6 @@ class calendar_boupdate extends calendar_bo
*/ */
function delete($cal_id,$recur_date=0,$ignore_acl=false) function delete($cal_id,$recur_date=0,$ignore_acl=false)
{ {
$event = $this->read($cal_id,$recur_date);
if (!($event = $this->read($cal_id,$recur_date)) || if (!($event = $this->read($cal_id,$recur_date)) ||
!$ignore_acl && !$this->check_perms(EGW_ACL_DELETE,$event)) !$ignore_acl && !$this->check_perms(EGW_ACL_DELETE,$event))
{ {
@ -1111,10 +1123,6 @@ class calendar_boupdate extends calendar_bo
{ {
$this->so->delete($cal_id); $this->so->delete($cal_id);
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'delete',time()); $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'delete',time());
// Update history
$tracking = new calendar_tracking($this);
$tracking->track($event, $event, null, true);
// delete all links to the event // delete all links to the event
egw_link::unlink(0,'calendar',$cal_id); egw_link::unlink(0,'calendar',$cal_id);
@ -1448,6 +1456,7 @@ class calendar_boupdate extends calendar_bo
{ {
$matchingEvents = array(); $matchingEvents = array();
$query = array(); $query = array();
$recur_date = 0;
if ($this->log) if ($this->log)
{ {
@ -1459,17 +1468,12 @@ class calendar_boupdate extends calendar_bo
{ {
if (isset($event['recurrence'])) if (isset($event['recurrence']))
{ {
$recur_date = $event['recurrence']; $recur_date = $this->date2usertime($event['recurrence']);
} }
else elseif (isset($event['start']))
{ {
$recur_date = $event['start']; $recur_date = $this->date2usertime($event['start']);
} }
$recur_date = $this->date2usertime($recur_date);
}
else
{
$recur_date = 0;
} }
if ($event['id']) if ($event['id'])
@ -1501,13 +1505,14 @@ class calendar_boupdate extends calendar_bo
return $matchingEvents; return $matchingEvents;
} }
} }
if ($filter == 'exact' || $filter == 'check') return array(); if ($filter == 'exact') return array();
} }
unset($event['id']); unset($event['id']);
if ($filter == 'master') if ($filter == 'master')
{ {
$query[] = 'recur_type!='. MCAL_RECUR_NONE; $query[] = 'recur_type!='. MCAL_RECUR_NONE;
$query['cal_recurrence'] = 0;
} }
// only query calendars of users, we have READ-grants from // only query calendars of users, we have READ-grants from
@ -1611,7 +1616,7 @@ class calendar_boupdate extends calendar_bo
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
'(' . $event['uid'] . ')[EventUID]'); '(' . $event['uid'] . ')[EventUID]');
} }
if (isset($event['recurrence'])) if ($filter != 'master' && isset($event['recurrence']))
{ {
$query['cal_recurrence'] = $event['recurrence']; $query['cal_recurrence'] = $event['recurrence'];
} }
@ -1637,17 +1642,17 @@ class calendar_boupdate extends calendar_bo
foreach($foundEvents as $egwEvent) foreach($foundEvents as $egwEvent)
{ {
if (in_array($egwEvent['id'], $matchingEvents)) continue;
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
'[FOUND]: ' . array2string($egwEvent)); '[FOUND]: ' . array2string($egwEvent));
} }
if (in_array($egwEvent['id'], $matchingEvents)) continue;
if ($filter == 'chec' && !empty($event['uid'])) if (in_array($filter, array('exact', 'master')) && !empty($event['uid']))
{ {
$matchingEvents[] = $egwEvent['id']; // UID found $matchingEvents[] = $egwEvent['id']; // UID found
if ($filter = 'master') break;
continue; continue;
} }
@ -1849,6 +1854,7 @@ class calendar_boupdate extends calendar_bo
} }
} }
$matchingEvents[] = $egwEvent['id']; // exact match $matchingEvents[] = $egwEvent['id']; // exact match
if ($filter = 'master') break;
} }
// append pseudos as last entries // append pseudos as last entries
$matchingEvents = array_merge($matchingEvents, $pseudos); $matchingEvents = array_merge($matchingEvents, $pseudos);
@ -1942,20 +1948,24 @@ class calendar_boupdate extends calendar_bo
in_array($event['recurrence'], $master_event['recur_exception'])) in_array($event['recurrence'], $master_event['recur_exception']))
{ {
$type = 'SERIES-PSEUDO-EXCEPTION'; // could also be a real one $type = 'SERIES-PSEUDO-EXCEPTION'; // could also be a real one
$recurrence_event = $event; $recurrence_event = $master_event;
$recurrence_event['start'] = $event['recurrence'];
$recurrence_event['end'] -= $master_event['start'] - $event['recurrence'];
break; break;
} }
elseif (in_array($event['start'], $master_event['recur_exception'])) elseif (in_array($event['start'], $master_event['recur_exception']))
{ {
$type='SERIES-PSEUDO-EXCEPTION'; // new pseudo exception? $type='SERIES-PSEUDO-EXCEPTION'; // new pseudo exception?
$recurrence_event = $event; $recurrence_event = $master_event;
$recurrence_event['start'] = $event['start'];
$recurrence_event['end'] -= $master_event['start'] - $event['start'];
break; break;
} }
else else
{ {
// try to find a suitable pseudo exception date // try to find a suitable pseudo exception date
$egw_rrule = calendar_rrule::event2rrule($master_event, false); $egw_rrule = calendar_rrule::event2rrule($master_event, false);
$egw_rrule->rewind(); $egw_rrule->current = clone $egw_rrule->time;
while ($egw_rrule->valid()) while ($egw_rrule->valid())
{ {
$occurrence = egw_time::to($egw_rrule->current(), 'server'); $occurrence = egw_time::to($egw_rrule->current(), 'server');
@ -1967,7 +1977,9 @@ class calendar_boupdate extends calendar_bo
if ($event['start'] == $occurrence) if ($event['start'] == $occurrence)
{ {
$type = 'SERIES-PSEUDO-EXCEPTION'; // let's try a pseudo exception $type = 'SERIES-PSEUDO-EXCEPTION'; // let's try a pseudo exception
$recurrence_event = $event; $recurrence_event = $master_event;
$recurrence_event['start'] = $occurrence;
$recurrence_event['end'] -= $master_event['start'] - $occurrence;
break 2; break 2;
} }
if (isset($event['recurrence']) && $event['recurrence'] == $occurrence) if (isset($event['recurrence']) && $event['recurrence'] == $occurrence)
@ -2077,4 +2089,4 @@ class calendar_boupdate extends calendar_bo
} }
} }
} }
} }

View File

@ -110,10 +110,12 @@ class calendar_groupdav extends groupdav_handler
'daywise' => false, 'daywise' => false,
'date_format' => 'server', 'date_format' => 'server',
); );
/*
if ($this->client_shared_uid_exceptions) if ($this->client_shared_uid_exceptions)
{ {
$cal_filters['query']['cal_reference'] = 0; $cal_filters['query']['cal_reference'] = 0;
} }
*/
// process REPORT filters or multiget href's // process REPORT filters or multiget href's
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$cal_filters,$id)) if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$cal_filters,$id))
{ {
@ -137,8 +139,17 @@ class calendar_groupdav extends groupdav_handler
if ($events) if ($events)
{ {
// get all max user modified times at once // get all max user modified times at once
foreach($events as &$event) foreach($events as $k => &$event)
{ {
if ($this->client_shared_uid_exceptions &&
$event['reference'] &&
($master = $this->bo->read($event['reference'], 0, false, 'server')) &&
array_search($event['recurrence'], $master['recur_exception']) !== false)
{
// this exception will be handled with the series master
unset($events[$k]);
continue;
}
$ids[] = $event['id']; $ids[] = $event['id'];
} }
$max_user_modified = $this->bo->so->max_user_modified($ids); $max_user_modified = $this->bo->so->max_user_modified($ids);
@ -350,22 +361,28 @@ class calendar_groupdav extends groupdav_handler
*/ */
private static function &get_series($uid,calendar_bo $bo=null) private static function &get_series($uid,calendar_bo $bo=null)
{ {
if (is_null($bo)) $bo = new calendar_bo(); if (is_null($bo)) $bo = new calendar_bopdate();
if (!($masterId = array_shift($bo->find_event(array('uid' => $uid), 'master')))
|| !($master = $bo->read($masterId, 0, false, 'server')))
{
return array(); // should never happen
}
$exceptions = $master['recur_exception'];
$events =& $bo->search(array( $events =& $bo->search(array(
'query' => array('cal_uid' => $uid), 'query' => array('cal_uid' => $uid),
'daywise' => false, 'daywise' => false,
'date_format' => 'server', 'date_format' => 'server',
)); ));
$master = null; $events = array_merge(array($master), $events);
foreach($events as $k => &$recurrence) foreach($events as $k => &$recurrence)
{ {
if (!isset($master)) // first event is always the series master //error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
{ // "($uid)[$k]:" . array2string($recurrence));
$master =& $events[$k]; if (!$k) continue; // nothing to change
//error_log('master: '.array2string($master));
continue; // nothing to change
}
if ($recurrence['id'] != $master['id']) // real exception if ($recurrence['id'] != $master['id']) // real exception
{ {
//error_log('real exception: '.array2string($recurrence)); //error_log('real exception: '.array2string($recurrence));
@ -373,9 +390,9 @@ class calendar_groupdav extends groupdav_handler
// at least Lightning "understands" EXDATE as exception from what's included // at least Lightning "understands" EXDATE as exception from what's included
// in the whole resource / VCALENDAR component // in the whole resource / VCALENDAR component
// not removing it causes Lightning to remove the exception itself // not removing it causes Lightning to remove the exception itself
if (($k = array_search($recurrence['recurrence'],$master['recur_exception'])) !== false) if (($e = array_search($recurrence['recurrence'],$exceptions)) !== false)
{ {
unset($master['recur_exception'][$k]); unset($exceptions[$e]);
} }
continue; // nothing to change continue; // nothing to change
} }
@ -386,13 +403,14 @@ class calendar_groupdav extends groupdav_handler
unset($events[$k]); // no exception --> remove it unset($events[$k]); // no exception --> remove it
continue; continue;
} }
// this is a virtual excetion now (no extra event/cal_id in DB) // this is a virtual exception now (no extra event/cal_id in DB)
//error_log('virtual exception: '.array2string($recurrence)); //error_log('virtual exception: '.array2string($recurrence));
$recurrence['recurrence'] = $recurrence['start']; $recurrence['recurrence'] = $recurrence['start'];
$recurrence['reference'] = $master['id']; $recurrence['reference'] = $master['id'];
$recurrence['recur_type'] = MCAL_RECUR_NONE; // is set, as this is a copy of the master $recurrence['recur_type'] = MCAL_RECUR_NONE; // is set, as this is a copy of the master
// not for included exceptions (Lightning): $master['recur_exception'][] = $recurrence['start']; // not for included exceptions (Lightning): $master['recur_exception'][] = $recurrence['start'];
} }
$events[0]['recur_exception'] = $exceptions;
return $events; return $events;
} }
@ -416,10 +434,12 @@ class calendar_groupdav extends groupdav_handler
return $event; return $event;
} }
$handler = $this->_get_handler(); $handler = $this->_get_handler();
if (!is_numeric($id) && ($foundEntries = $handler->find_event($options['content'], 'check')))
if (!is_numeric($id) && ($foundEntries = $handler->find_event($options['content'], 'exact')))
{ {
$id = array_shift($foundEntries); $id = array_shift($foundEntries);
} }
if (!($cal_id = $handler->importVCal($options['content'],is_numeric($id) ? $id : -1, if (!($cal_id = $handler->importVCal($options['content'],is_numeric($id) ? $id : -1,
self::etag2value($this->http_if_match)))) self::etag2value($this->http_if_match))))
{ {
@ -448,14 +468,15 @@ class calendar_groupdav extends groupdav_handler
static function fix_series(array &$events) static function fix_series(array &$events)
{ {
foreach($events as $n => $event) error_log(__METHOD__." $n before: ".array2string($event)); foreach($events as $n => $event) error_log(__METHOD__." $n before: ".array2string($event));
$master =& $events[0]; //$master =& $events[0];
$bo = new calendar_boupdate(); $bo = new calendar_boupdate();
// get array with orginal recurrences indexed by recurrence-id // get array with orginal recurrences indexed by recurrence-id
$org_recurrences = array(); $org_recurrences = $exceptions = array();
foreach(self::get_series($master['uid'],$bo) as $event) foreach(self::get_series($events[0]['uid'],$bo) as $k => $event)
{ {
if (!$k) $master = $event;
if ($event['recurrence']) if ($event['recurrence'])
{ {
$org_recurrences[$event['recurrence']] = $event; $org_recurrences[$event['recurrence']] = $event;
@ -463,9 +484,15 @@ class calendar_groupdav extends groupdav_handler
} }
// assign cal_id's to already existing recurrences and evtl. re-add recur_exception to master // assign cal_id's to already existing recurrences and evtl. re-add recur_exception to master
foreach($events as &$recurrence) foreach($events as $k => &$recurrence)
{ {
if ($recurrence['id'] || !$recurrence['recurrence']) continue; // master if (!$recurrence['recurrence'])
{
// master
$recurrence['id'] = $master['id'];
$master =& $events[$k];
continue;
}
// from now on we deal with exceptions // from now on we deal with exceptions
$org_recurrence = $org_recurrences[$recurrence['recurrence']]; $org_recurrence = $org_recurrences[$recurrence['recurrence']];
@ -478,12 +505,13 @@ class calendar_groupdav extends groupdav_handler
if ($recurrence['id'] != $master['id']) if ($recurrence['id'] != $master['id'])
{ {
error_log(__METHOD__.'() re-adding recur_exception '.$recurrence['recurrence'].' = '.date('Y-m-d H:i:s',$recurrence['recurrence'])); error_log(__METHOD__.'() re-adding recur_exception '.$recurrence['recurrence'].' = '.date('Y-m-d H:i:s',$recurrence['recurrence']));
$master['recur_exception'][] = $recurrence['recurrence']; $exceptions[] = $recurrence['recurrence'];
} }
// remove recurrence to be able to detect deleted exceptions // remove recurrence to be able to detect deleted exceptions
unset($org_recurrences[$recurrence['recurrence']]); unset($org_recurrences[$recurrence['recurrence']]);
} }
} }
$master['recur_exception'] = array_merge($exceptions, $master['recur_exception']);
// delete not longer existing recurrences // delete not longer existing recurrences
foreach($org_recurrences as $org_recurrence) foreach($org_recurrences as $org_recurrence)

View File

@ -41,6 +41,7 @@ class calendar_ical extends calendar_boupdate
'A' => 'ACCEPTED', 'A' => 'ACCEPTED',
'R' => 'DECLINED', 'R' => 'DECLINED',
'T' => 'TENTATIVE', 'T' => 'TENTATIVE',
'D' => 'DELEGATED'
); );
/** /**
* @var array conversation of the participant status ical => egw * @var array conversation of the participant status ical => egw
@ -51,6 +52,7 @@ class calendar_ical extends calendar_boupdate
'ACCEPTED' => 'A', 'ACCEPTED' => 'A',
'DECLINED' => 'R', 'DECLINED' => 'R',
'TENTATIVE' => 'T', 'TENTATIVE' => 'T',
'DELEGATED' => 'D',
); );
/** /**
@ -227,7 +229,7 @@ class calendar_ical extends calendar_boupdate
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"() User does not have the permission to read event $_id.\n", '() User does not have the permission to read event ' . $event['id']. "\n",
3,$this->logfile); 3,$this->logfile);
} }
return -1; // Permission denied return -1; // Permission denied
@ -238,8 +240,8 @@ class calendar_ical extends calendar_boupdate
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"() Event $_id not found.\n", "() Event $event not found.\n",
3,$this->logfile); 3, $this->logfile);
} }
} }
continue; continue;
@ -342,15 +344,21 @@ class calendar_ical extends calendar_boupdate
$horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE'); $horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE');
// DTSTART must be in local time! // DTSTART must be in local time!
$standard = $horde_vtimezone->findComponent('STANDARD'); $standard = $horde_vtimezone->findComponent('STANDARD');
$dtstart = $standard->getAttribute('DTSTART'); if (is_a($standard, 'Horde_iCalendar'))
$dtstart = new egw_time($dtstart, egw_time::$server_timezone); {
$dtstart->setTimezone(self::$tz_cache[$tzid]); $dtstart = $standard->getAttribute('DTSTART');
$standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false); $dtstart = new egw_time($dtstart, egw_time::$server_timezone);
$dtstart->setTimezone(self::$tz_cache[$tzid]);
$standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
}
$daylight = $horde_vtimezone->findComponent('DAYLIGHT'); $daylight = $horde_vtimezone->findComponent('DAYLIGHT');
$dtstart = $daylight->getAttribute('DTSTART'); if (is_a($daylight, 'Horde_iCalendar'))
$dtstart = new egw_time($dtstart, egw_time::$server_timezone); {
$dtstart->setTimezone(self::$tz_cache[$tzid]); $dtstart = $daylight->getAttribute('DTSTART');
$daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false); $dtstart = new egw_time($dtstart, egw_time::$server_timezone);
$dtstart->setTimezone(self::$tz_cache[$tzid]);
$daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false);
}
$vcal->addComponent($horde_vtimezone); $vcal->addComponent($horde_vtimezone);
$vtimezones_added[] = $tzid; $vtimezones_added[] = $tzid;
} }
@ -396,6 +404,7 @@ class calendar_ical extends calendar_boupdate
sort($exceptions); sort($exceptions);
} }
$event['recur_exception'] = $exceptions; $event['recur_exception'] = $exceptions;
/*
// Adjust the event start -- must not be an exception // Adjust the event start -- must not be an exception
$length = $event['end'] - $event['start']; $length = $event['end'] - $event['start'];
$rriter = calendar_rrule::event2rrule($event, false, $tzid); $rriter = calendar_rrule::event2rrule($event, false, $tzid);
@ -415,13 +424,21 @@ class calendar_ical extends calendar_boupdate
{ {
// the series dissolved completely into exceptions // the series dissolved completely into exceptions
continue; continue;
} }*/
} }
foreach ($egwSupportedFields as $icalFieldName => $egwFieldName) foreach ($egwSupportedFields as $icalFieldName => $egwFieldName)
{ {
if (!isset($this->supportedFields[$egwFieldName])) continue; if (!isset($this->supportedFields[$egwFieldName]))
{
if ($this->log)
{
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
'(' . $event['id'] . ") [$icalFieldName] not supported\n",
3,$this->logfile);
}
continue;
}
$values[$icalFieldName] = array(); $values[$icalFieldName] = array();
switch ($icalFieldName) switch ($icalFieldName)
{ {
@ -928,11 +945,30 @@ class calendar_ical extends calendar_boupdate
{ {
if (!is_array($this->supportedFields)) $this->setSupportedFields(); if (!is_array($this->supportedFields)) $this->setSupportedFields();
if (!($events = $this->icaltoegw($_vcalData,$cal_id,$etag,$recur_date))) if (!($events = $this->icaltoegw($_vcalData)))
{ {
return false; return false;
} }
if ($cal_id > 0)
{
if (count($events) == 1)
{
$events[0]['id'] = $cal_id;
if (!is_null($etag)) $events[0]['etag'] = (int) $etag;
if ($recur_date) $events[0]['recurrence'] = $recur_date;
}
elseif (($foundEvent = $this->find_event(array('id' => $cal_id), 'exact')) &&
($eventId = array_shift($foundEvent)) &&
($egwEvent = $this->read($eventId)))
{
foreach ($events as $k => $event)
{
if (!isset($event['uid'])) $events[$k]['uid'] = $egwEvent['uid'];
}
}
}
// check if we are importing an event series with exceptions in CalDAV // check if we are importing an event series with exceptions in CalDAV
// only first event / series master get's cal_id from URL // only first event / series master get's cal_id from URL
// other events are exceptions and need to be checked if they are new // other events are exceptions and need to be checked if they are new
@ -947,13 +983,18 @@ class calendar_ical extends calendar_boupdate
foreach ($events as $event) foreach ($events as $event)
{ {
if ($this->so->isWholeDay($event)) $event['whole_day'] = true; if ($this->so->isWholeDay($event)) $event['whole_day'] = true;
if (is_array($event['category']))
{
$event['category'] = $this->find_or_add_categories($event['category'],
isset($event['id']) ? $event['id'] : -1);
}
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
array2string($event)."\n",3,$this->logfile); array2string($event)."\n",3,$this->logfile);
} }
/*
if ($event['recur_type'] != MCAL_RECUR_NONE) if ($event['recur_type'] != MCAL_RECUR_NONE)
{ {
// Adjust the event start -- no exceptions before and at the start // Adjust the event start -- no exceptions before and at the start
@ -987,7 +1028,7 @@ class calendar_ical extends calendar_boupdate
} }
$event['recur_exception'] = $exceptions; $event['recur_exception'] = $exceptions;
} }
*/
$updated_id = false; $updated_id = false;
$event_info = $this->get_event_info($event); $event_info = $this->get_event_info($event);
@ -1066,11 +1107,11 @@ class calendar_ical extends calendar_boupdate
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"() Restore status for $uid\n",3,$this->logfile); "() Restore status for $uid\n",3,$this->logfile);
} }
$event['participants']['uid'] = $event_info['stored_event']['participants'][$uid]; $event['participants'][$uid] = $event_info['stored_event']['participants'][$uid];
} }
else else
{ {
$event['participants']['uid'] = calendar_so::combine_status('U'); $event['participants'][$uid] = calendar_so::combine_status('U');
} }
} }
} }
@ -1271,7 +1312,7 @@ class calendar_ical extends calendar_boupdate
if (is_array($days)) if (is_array($days))
{ {
$recur_exceptions = array(); $recur_exceptions = array();
/*
if (!isset($days[$event_info['stored_event']['start']]) && if (!isset($days[$event_info['stored_event']['start']]) &&
$event_info['stored_event']['start'] < $event['start']) $event_info['stored_event']['start'] < $event['start'])
{ {
@ -1318,7 +1359,7 @@ class calendar_ical extends calendar_boupdate
$event['start'] = $startdate; $event['start'] = $startdate;
$event['end'] = $startdate + $length; $event['end'] = $startdate + $length;
} } */
foreach ($event['recur_exception'] as $recur_exception) foreach ($event['recur_exception'] as $recur_exception)
{ {
@ -1363,7 +1404,7 @@ class calendar_ical extends calendar_boupdate
$event_info['master_event']['recur_exception'] = $event_info['master_event']['recur_exception'] =
array_unique(array_merge($event_info['master_event']['recur_exception'], array_unique(array_merge($event_info['master_event']['recur_exception'],
array($event['recurrence']))); array($event['recurrence'])));
/*
// Adjust the event start -- must not be an exception // Adjust the event start -- must not be an exception
$length = $event_info['master_event']['end'] - $event_info['master_event']['start']; $length = $event_info['master_event']['end'] - $event_info['master_event']['start'];
$rriter = calendar_rrule::event2rrule($event_info['master_event'], false); $rriter = calendar_rrule::event2rrule($event_info['master_event'], false);
@ -1376,6 +1417,21 @@ class calendar_ical extends calendar_boupdate
// remove leading exceptions // remove leading exceptions
if ($day < $newstart) if ($day < $newstart)
{ {
if (($foundEvents = $this->find_event(
array('uid' => $event_info['master_event']['uid'],
'recurrence' => $day), 'exact')) &&
($eventId = array_shift($foundEvents)) &&
($exception = read($eventId, 0, 'server')))
{
// Unlink this exception
unset($exception['uid']);
$this->update($exception, true);
}
if ($event['recurrence'] == $day)
{
// Unlink this exception
unset($event['uid']);
}
unset($event_info['master_event']['recur_exception'][$key]); unset($event_info['master_event']['recur_exception'][$key]);
} }
} }
@ -1384,14 +1440,14 @@ class calendar_ical extends calendar_boupdate
{ {
$event_info['master_event']['start'] = $newstart; $event_info['master_event']['start'] = $newstart;
$event_info['master_event']['end'] = $newstart + $length; $event_info['master_event']['end'] = $newstart + $length;
$event_to_store = $event_info['master_event']; // prevent the master_event from being changed by the update method }*/
$this->server2usertime($event_to_store);
$this->update($event_to_store, true);
unset($event_to_store);
}
$event['reference'] = $event_info['master_event']['id']; $event['reference'] = $event_info['master_event']['id'];
$event['category'] = $event_info['master_event']['category']; $event['category'] = $event_info['master_event']['category'];
$event['owner'] = $event_info['master_event']['owner']; $event['owner'] = $event_info['master_event']['owner'];
$event_to_store = $event_info['master_event']; // prevent the master_event from being changed by the update method
$this->server2usertime($event_to_store);
$this->update($event_to_store, true);
unset($event_to_store);
} }
$event_to_store = $event; // prevent $event from being changed by update method $event_to_store = $event; // prevent $event from being changed by update method
@ -1864,7 +1920,7 @@ class calendar_ical extends calendar_boupdate
} }
} }
function icaltoegw($_vcalData, $cal_id=-1, $etag=null, $recur_date=0) function icaltoegw($_vcalData)
{ {
if ($this->log) if ($this->log)
{ {
@ -1906,7 +1962,7 @@ class calendar_ical extends calendar_boupdate
{ {
if (is_a($component, 'Horde_iCalendar_vevent')) if (is_a($component, 'Horde_iCalendar_vevent'))
{ {
if (($event = $this->vevent2egw($component, $version, $this->supportedFields, $cal_id))) if (($event = $this->vevent2egw($component, $version, $this->supportedFields)))
{ {
//common adjustments //common adjustments
if ($this->productManufacturer == '' && $this->productName == '' if ($this->productManufacturer == '' && $this->productName == ''
@ -1943,11 +1999,6 @@ class calendar_ical extends calendar_boupdate
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']); date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']);
// if cal_id, etag or recur_date is given, use/set it for 1. event
if ($cal_id > 0) $events[0]['id'] = $cal_id;
if (!is_null($etag)) $events[0]['etag'] = (int) $etag;
if ($recur_date) $events[0]['recurrence'] = $recur_date;
return $events; return $events;
} }
@ -1957,11 +2008,10 @@ class calendar_ical extends calendar_boupdate
* @param array $component VEVENT * @param array $component VEVENT
* @param string $version vCal version (1.0/2.0) * @param string $version vCal version (1.0/2.0)
* @param array $supportedFields supported fields of the device * @param array $supportedFields supported fields of the device
* @param int $cal_id id of existing event in the content (only used to merge categories)
* *
* @return array|boolean event on success, false on failure * @return array|boolean event on success, false on failure
*/ */
function vevent2egw(&$component, $version, $supportedFields, $cal_id=-1) function vevent2egw(&$component, $version, $supportedFields)
{ {
if (!is_a($component, 'Horde_iCalendar_vevent')) return false; if (!is_a($component, 'Horde_iCalendar_vevent')) return false;
@ -2353,7 +2403,7 @@ class calendar_ical extends calendar_boupdate
case 'CATEGORIES': case 'CATEGORIES':
if ($attributes['value']) if ($attributes['value'])
{ {
$vcardData['category'] = $this->find_or_add_categories(explode(',',$attributes['value']), $cal_id); $vcardData['category'] = explode(',', $attributes['value']);
} }
else else
{ {
@ -2369,6 +2419,7 @@ class calendar_ical extends calendar_boupdate
if (isset($attributes['params']['STATUS'])) if (isset($attributes['params']['STATUS']))
{ {
$status = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])]; $status = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])];
if (empty($status)) $status = 'X';
} }
else else
{ {
@ -2599,8 +2650,6 @@ class calendar_ical extends calendar_boupdate
if ($this->calendarOwner) $event['owner'] = $this->calendarOwner; if ($this->calendarOwner) $event['owner'] = $this->calendarOwner;
if ($cal_id > 0) $event['id'] = $cal_id;
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
@ -2613,7 +2662,15 @@ class calendar_ical extends calendar_boupdate
function search($_vcalData, $contentID=null, $relax=false) function search($_vcalData, $contentID=null, $relax=false)
{ {
if (($events = $this->icaltoegw($_vcalData,!is_null($contentID) ? $contentID : -1))) if (is_null($contentID))
{
$eventId = -1;
}
else
{
$eventId = $contentID;
}
if (($events = $this->icaltoegw($_vcalData)))
{ {
// this function only supports searching a single event // this function only supports searching a single event
if (count($events) == 1) if (count($events) == 1)
@ -2621,6 +2678,7 @@ class calendar_ical extends calendar_boupdate
$filter = $relax ? 'relax' : 'check'; $filter = $relax ? 'relax' : 'check';
$event = array_shift($events); $event = array_shift($events);
if ($this->so->isWholeDay($event)) $event['whole_day'] = true; if ($this->so->isWholeDay($event)) $event['whole_day'] = true;
$event['category'] = $this->find_or_add_categories($event['category'], $eventId);
if ($contentID) $event['id'] = $contentID; if ($contentID) $event['id'] = $contentID;
return $this->find_event($event, $filter); return $this->find_event($event, $filter);
} }

View File

@ -430,6 +430,7 @@ class calendar_sif extends calendar_boupdate
return false; return false;
} }
/*
if ($event['recur_type'] != MCAL_RECUR_NONE) if ($event['recur_type'] != MCAL_RECUR_NONE)
{ {
// Adjust the event start -- no exceptions before and at the start // Adjust the event start -- no exceptions before and at the start
@ -462,7 +463,7 @@ class calendar_sif extends calendar_boupdate
} }
} }
$event['recur_exception'] = $exceptions; $event['recur_exception'] = $exceptions;
} } */
if ($recur_date) $event['recurrence'] = $recur_date; if ($recur_date) $event['recurrence'] = $recur_date;
$event_info = $this->get_event_info($event); $event_info = $this->get_event_info($event);
@ -684,7 +685,7 @@ class calendar_sif extends calendar_boupdate
$event_info['master_event']['recur_exception'] = $event_info['master_event']['recur_exception'] =
array_unique(array_merge($event_info['master_event']['recur_exception'], array_unique(array_merge($event_info['master_event']['recur_exception'],
array($event['recurrence']))); array($event['recurrence'])));
/*
// Adjust the event start -- must not be an exception // Adjust the event start -- must not be an exception
$length = $event_info['master_event']['end'] - $event_info['master_event']['start']; $length = $event_info['master_event']['end'] - $event_info['master_event']['start'];
$rriter = calendar_rrule::event2rrule($event_info['master_event'], false); $rriter = calendar_rrule::event2rrule($event_info['master_event'], false);
@ -709,7 +710,7 @@ class calendar_sif extends calendar_boupdate
$this->server2usertime($event_to_store); $this->server2usertime($event_to_store);
$this->update($event_to_store, true); $this->update($event_to_store, true);
unset($event_to_store); unset($event_to_store);
} } */
$event['reference'] = $event_info['master_event']['id']; $event['reference'] = $event_info['master_event']['id'];
$event['category'] = $event_info['master_event']['category']; $event['category'] = $event_info['master_event']['category'];
$event['owner'] = $event_info['master_event']['owner']; $event['owner'] = $event_info['master_event']['owner'];
@ -914,6 +915,7 @@ class calendar_sif extends calendar_boupdate
array2string($exceptions)."\n",3,$this->logfile); array2string($exceptions)."\n",3,$this->logfile);
} }
$event['recur_exception'] = $exceptions; $event['recur_exception'] = $exceptions;
/*
// Adjust the event start -- must not be an exception // Adjust the event start -- must not be an exception
$length = $event['end'] - $event['start']; $length = $event['end'] - $event['start'];
$rriter = calendar_rrule::event2rrule($event, false, $tzid); $rriter = calendar_rrule::event2rrule($event, false, $tzid);
@ -927,7 +929,7 @@ class calendar_sif extends calendar_boupdate
// remove leading exceptions // remove leading exceptions
if ($day <= $event['start']) unset($exceptions[$key]); if ($day <= $event['start']) unset($exceptions[$key]);
} }
$event['recur_exception'] = $exceptions; $event['recur_exception'] = $exceptions; */
} }
if ($this->uidExtension) if ($this->uidExtension)

View File

@ -44,6 +44,7 @@ define('REJECTED',0);
define('NO_RESPONSE',1); define('NO_RESPONSE',1);
define('TENTATIVE',2); define('TENTATIVE',2);
define('ACCEPTED',3); define('ACCEPTED',3);
define('DELEGATED',4);
define('HOUR_s',60*60); define('HOUR_s',60*60);
define('DAY_s',24*HOUR_s); define('DAY_s',24*HOUR_s);
@ -188,6 +189,18 @@ class calendar_so
$this->db->update($this->cal_table, array('cal_uid' => $event['uid']), $this->db->update($this->cal_table, array('cal_uid' => $event['uid']),
array('cal_id' => $event['id']),__LINE__,__FILE__,'calendar'); array('cal_id' => $event['id']),__LINE__,__FILE__,'calendar');
} }
if ((int) $recur_date == 0 &&
$event['recur_type'] != MCAL_RECUR_NONE &&
!empty($event['recur_exception']))
{
sort($event['recur_exception']);
if ($event['recur_exception'][0] < $event['start'])
{
// leading exceptions => move start and end
$event['end'] -= $event['start'] - $event['recur_exception'][0];
$event['start'] = $event['recur_exception'][0];
}
}
} }
// check if we have a real recurance, if not set $recur_date=0 // check if we have a real recurance, if not set $recur_date=0
@ -377,6 +390,8 @@ class calendar_so
$where[] = "cal_status='T'"; break; $where[] = "cal_status='T'"; break;
case 'rejected': case 'rejected':
$where[] = "cal_status='R'"; break; $where[] = "cal_status='R'"; break;
case 'delegated':
$where[] = "cal_status='D'"; break;
case 'all': case 'all':
case 'owner': case 'owner':
break; break;
@ -649,6 +664,8 @@ ORDER BY cal_user_type, cal_usre_id
$minimum_uid_length = 8; $minimum_uid_length = 8;
} }
$old_min = $old_duration = 0;
//echo '<p>'.__METHOD__.'('.array2string($event).",$change_since) event="; _debug_array($event); //echo '<p>'.__METHOD__.'('.array2string($event).",$change_since) event="; _debug_array($event);
//error_log(__METHOD__.'('.array2string($event).",$set_recurrences,$change_since,$etag)"); //error_log(__METHOD__.'('.array2string($event).",$set_recurrences,$change_since,$etag)");
@ -827,7 +844,7 @@ ORDER BY cal_user_type, cal_usre_id
// update start- and endtime if present in the event-array, evtl. we need to move all recurrences // update start- and endtime if present in the event-array, evtl. we need to move all recurrences
if (isset($event['cal_start']) && isset($event['cal_end'])) if (isset($event['cal_start']) && isset($event['cal_end']))
{ {
$this->move($cal_id,$event['cal_start'],$event['cal_end'],!$cal_id ? false : $change_since); $this->move($cal_id,$event['cal_start'],$event['cal_end'],!$cal_id ? false : $change_since, $old_min, $old_min + $old_duration);
} }
// update participants if present in the event-array // update participants if present in the event-array
if (isset($event['cal_participants'])) if (isset($event['cal_participants']))
@ -1157,7 +1174,8 @@ ORDER BY cal_user_type, cal_usre_id
REJECTED => 'R', REJECTED => 'R',
NO_RESPONSE => 'U', NO_RESPONSE => 'U',
TENTATIVE => 'T', TENTATIVE => 'T',
ACCEPTED => 'A' ACCEPTED => 'A',
DELEGATED => 'D'
); );
if (!(int)$cal_id || !(int)$user_id && $user_type != 'e') if (!(int)$cal_id || !(int)$user_id && $user_type != 'e')
{ {
@ -1581,7 +1599,7 @@ ORDER BY cal_user_type, cal_usre_id
* @param int $start=0 if != 0: startdate of the search/list (servertime) * @param int $start=0 if != 0: startdate of the search/list (servertime)
* @param int $end=0 if != 0: enddate of the search/list (servertime) * @param int $end=0 if != 0: enddate of the search/list (servertime)
* @param string $filter='all' string filter-name: all (not rejected), * @param string $filter='all' string filter-name: all (not rejected),
* accepted, unknown, tentative, rejected, * accepted, unknown, tentative, rejected, delegated
* rrule return array of remote exceptions in servertime * rrule return array of remote exceptions in servertime
* tz_rrule/tz_only, return (only by) timezone transition affected entries * tz_rrule/tz_only, return (only by) timezone transition affected entries
* map return array of dates with no pseudo exception * map return array of dates with no pseudo exception
@ -1607,15 +1625,46 @@ ORDER BY cal_user_type, cal_usre_id
$remote = in_array($filter, array('tz_rrule', 'rrule')); $remote = in_array($filter, array('tz_rrule', 'rrule'));
$egw_rrule = calendar_rrule::event2rrule($event, false); $egw_rrule = calendar_rrule::event2rrule($event, false);
$egw_rrule->rewind(); $egw_rrule->current = clone $egw_rrule->time;
if ($expand_all) if ($expand_all)
{ {
unset($event['recur_excpetion']); unset($event['recur_excpetion']);
$remote_rrule = calendar_rrule::event2rrule($event, false, $tz_id); $remote_rrule = calendar_rrule::event2rrule($event, false, $tz_id);
$remote_rrule->rewind(); $remote_rrule->current = clone $remote_rrule->time;
} }
while ($egw_rrule->valid()) while ($egw_rrule->valid())
{ {
while ($egw_rrule->exceptions &&
in_array($egw_rrule->current->format('Ymd'),$egw_rrule->exceptions))
{
if (in_array($filter, array('map','tz_map','rrule','tz_rrule')))
{
// real exception
$locts = (int)egw_time::to($egw_rrule->current(),'server');
if ($expand_all)
{
$remts = (int)egw_time::to($remote_rrule->current(),'server');
if ($remote)
{
$days[$locts]= $remts;
}
else
{
$days[$remts]= $locts;
}
}
else
{
$days[$locts]= $locts;
}
}
if ($expand_all)
{
$remote_rrule->next_no_exception();
}
$egw_rrule->next_no_exception();
if (!$egw_rrule->valid()) return $days;
}
$day = $egw_rrule->current(); $day = $egw_rrule->current();
$locts = (int)egw_time::to($day,'server'); $locts = (int)egw_time::to($day,'server');
$tz_exception = ($filter == 'tz_rrule'); $tz_exception = ($filter == 'tz_rrule');
@ -1659,7 +1708,6 @@ ORDER BY cal_user_type, cal_usre_id
// '() status exception: ' . $day->format('Ymd\THis')); // '() status exception: ' . $day->format('Ymd\THis'));
if ($expand_all) if ($expand_all)
{ {
$remts = (int)egw_time::to($remote_day,'server');
if ($filter == 'tz_only') if ($filter == 'tz_only')
{ {
unset($days[$remts]); unset($days[$remts]);
@ -1699,40 +1747,11 @@ ORDER BY cal_user_type, cal_usre_id
} }
} }
} }
do if ($expand_all)
{ {
$egw_rrule->next_no_exception(); $remote_rrule->next_no_exception();
$day = $egw_rrule->current();
if ($expand_all)
{
$remote_rrule->next_no_exception();
$remts = (int)egw_time::to($remote_rrule->current(),'server');
}
$exception = $egw_rrule->exceptions &&
in_array($day->format('Ymd'),$egw_rrule->exceptions);
if (in_array($filter, array('map','tz_map','rrule','tz_rrule'))
&& $exception)
{
// real exception
$locts = (int)egw_time::to($day,'ts');
if ($expand_all)
{
if ($remote)
{
$days[$locts]= $remts;
}
else
{
$days[$remts]= $locts;
}
}
else
{
$days[$locts]= $locts;
}
}
} }
while ($exception); $egw_rrule->next_no_exception();
} }
return $days; return $days;
} }
@ -1831,6 +1850,13 @@ ORDER BY cal_user_type, cal_usre_id
continue; continue;
} }
break; break;
case 'delegated':
if ($status != 'D')
{
unset($participants[$uid]);
continue;
}
break;
case 'default': case 'default':
if ($status == 'R') if ($status == 'R')
{ {

View File

@ -146,7 +146,7 @@ class calendar_ui
$this->accountsel = $GLOBALS['egw']->uiaccountsel; $this->accountsel = $GLOBALS['egw']->uiaccountsel;
$this->categories = new categories($this->user,'calendar'); $this->categories = new categories($this->user,'calendar');
$this->common_prefs = &$GLOBALS['egw_info']['user']['preferences']['common']; $this->common_prefs = &$GLOBALS['egw_info']['user']['preferences']['common'];
$this->cal_prefs = &$GLOBALS['egw_info']['user']['preferences']['calendar']; $this->cal_prefs = &$GLOBALS['egw_info']['user']['preferences']['calendar'];
$this->bo->check_set_default_prefs(); $this->bo->check_set_default_prefs();
@ -708,6 +708,7 @@ class calendar_ui
'accepted' => array(lang('Accepted'), lang('Show only accepted events')), 'accepted' => array(lang('Accepted'), lang('Show only accepted events')),
'unknown' => array(lang('Invitations'), lang('Show only invitations, not yet accepted or rejected')), 'unknown' => array(lang('Invitations'), lang('Show only invitations, not yet accepted or rejected')),
'tentative' => array(lang('Tentative'), lang('Show only tentative accepted events')), 'tentative' => array(lang('Tentative'), lang('Show only tentative accepted events')),
'delegated' => array(lang('Delegated'), lang('Show only delegated events')),
'rejected' => array(lang('Rejected'),lang('Show only rejected events')), 'rejected' => array(lang('Rejected'),lang('Show only rejected events')),
'owner' => array(lang('Owner too'),lang('Show also events just owned by selected user')), 'owner' => array(lang('Owner too'),lang('Show also events just owned by selected user')),
'all' => array(lang('All incl. rejected'),lang('Show all status incl. rejected events')), 'all' => array(lang('All incl. rejected'),lang('Show all status incl. rejected events')),

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B