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

View File

@ -20,6 +20,7 @@ define('MSG_TENTATIVE',4);
define('MSG_ACCEPTED',5);
define('MSG_ALARM',6);
define('MSG_DISINVITE',7);
define('MSG_DELEGATED',8);
/**
* 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
//
$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'])
{
@ -619,6 +620,12 @@ class calendar_boupdate extends calendar_bo
$msgtype = '"calendar";';
$method = 'REPLY';
break;
case MSG_DELEGATED:
$action = lang('Delegated');
$msg = 'Response';
$msgtype = '"calendar";';
$method = 'REPLY';
break;
case MSG_ALARM:
$action = lang('Alarm');
$msg = 'Alarm';
@ -825,8 +832,16 @@ class calendar_boupdate extends calendar_bo
return false;
}
if ($event['id'])
{
// invalidate the read-cache if it contains the event we store now
if ($event['id'] && $event['id'] == self::$cached_event['id']) self::$cached_event = array();
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;
// 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_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)
{
$save_event['id'] = $cal_id;
@ -1062,7 +1075,7 @@ class calendar_boupdate extends calendar_bo
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"($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 ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time());
@ -1071,6 +1084,7 @@ class calendar_boupdate extends calendar_bo
'R' => MSG_REJECTED,
'T' => MSG_TENTATIVE,
'A' => MSG_ACCEPTED,
'D' => MSG_DELEGATED,
);
if (isset($status2msg[$status]))
{
@ -1080,7 +1094,7 @@ class calendar_boupdate extends calendar_bo
}
// 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->track($event, $old_event);
@ -1098,8 +1112,6 @@ class calendar_boupdate extends calendar_bo
*/
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)) ||
!$ignore_acl && !$this->check_perms(EGW_ACL_DELETE,$event))
{
@ -1112,10 +1124,6 @@ class calendar_boupdate extends calendar_bo
$this->so->delete($cal_id);
$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
egw_link::unlink(0,'calendar',$cal_id);
}
@ -1448,6 +1456,7 @@ class calendar_boupdate extends calendar_bo
{
$matchingEvents = array();
$query = array();
$recur_date = 0;
if ($this->log)
{
@ -1459,17 +1468,12 @@ class calendar_boupdate extends calendar_bo
{
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'])
@ -1501,13 +1505,14 @@ class calendar_boupdate extends calendar_bo
return $matchingEvents;
}
}
if ($filter == 'exact' || $filter == 'check') return array();
if ($filter == 'exact') return array();
}
unset($event['id']);
if ($filter == 'master')
{
$query[] = 'recur_type!='. MCAL_RECUR_NONE;
$query['cal_recurrence'] = 0;
}
// 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__.
'(' . $event['uid'] . ')[EventUID]');
}
if (isset($event['recurrence']))
if ($filter != 'master' && isset($event['recurrence']))
{
$query['cal_recurrence'] = $event['recurrence'];
}
@ -1637,17 +1642,17 @@ class calendar_boupdate extends calendar_bo
foreach($foundEvents as $egwEvent)
{
if (in_array($egwEvent['id'], $matchingEvents)) continue;
if ($this->log)
{
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
'[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
if ($filter = 'master') break;
continue;
}
@ -1849,6 +1854,7 @@ class calendar_boupdate extends calendar_bo
}
}
$matchingEvents[] = $egwEvent['id']; // exact match
if ($filter = 'master') break;
}
// append pseudos as last entries
$matchingEvents = array_merge($matchingEvents, $pseudos);
@ -1942,20 +1948,24 @@ class calendar_boupdate extends calendar_bo
in_array($event['recurrence'], $master_event['recur_exception']))
{
$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;
}
elseif (in_array($event['start'], $master_event['recur_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;
}
else
{
// try to find a suitable pseudo exception date
$egw_rrule = calendar_rrule::event2rrule($master_event, false);
$egw_rrule->rewind();
$egw_rrule->current = clone $egw_rrule->time;
while ($egw_rrule->valid())
{
$occurrence = egw_time::to($egw_rrule->current(), 'server');
@ -1967,7 +1977,9 @@ class calendar_boupdate extends calendar_bo
if ($event['start'] == $occurrence)
{
$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;
}
if (isset($event['recurrence']) && $event['recurrence'] == $occurrence)

View File

@ -110,10 +110,12 @@ class calendar_groupdav extends groupdav_handler
'daywise' => false,
'date_format' => 'server',
);
/*
if ($this->client_shared_uid_exceptions)
{
$cal_filters['query']['cal_reference'] = 0;
}
*/
// process REPORT filters or multiget href's
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)
{
// 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'];
}
$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)
{
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(
'query' => array('cal_uid' => $uid),
'daywise' => false,
'date_format' => 'server',
));
$master = null;
$events = array_merge(array($master), $events);
foreach($events as $k => &$recurrence)
{
if (!isset($master)) // first event is always the series master
{
$master =& $events[$k];
//error_log('master: '.array2string($master));
continue; // nothing to change
}
//error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// "($uid)[$k]:" . array2string($recurrence));
if (!$k) continue; // nothing to change
if ($recurrence['id'] != $master['id']) // real exception
{
//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
// in the whole resource / VCALENDAR component
// 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
}
@ -386,13 +403,14 @@ class calendar_groupdav extends groupdav_handler
unset($events[$k]); // no exception --> remove it
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));
$recurrence['recurrence'] = $recurrence['start'];
$recurrence['reference'] = $master['id'];
$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'];
}
$events[0]['recur_exception'] = $exceptions;
return $events;
}
@ -416,10 +434,12 @@ class calendar_groupdav extends groupdav_handler
return $event;
}
$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);
}
if (!($cal_id = $handler->importVCal($options['content'],is_numeric($id) ? $id : -1,
self::etag2value($this->http_if_match))))
{
@ -448,14 +468,15 @@ class calendar_groupdav extends groupdav_handler
static function fix_series(array &$events)
{
foreach($events as $n => $event) error_log(__METHOD__." $n before: ".array2string($event));
$master =& $events[0];
//$master =& $events[0];
$bo = new calendar_boupdate();
// get array with orginal recurrences indexed by recurrence-id
$org_recurrences = array();
foreach(self::get_series($master['uid'],$bo) as $event)
$org_recurrences = $exceptions = array();
foreach(self::get_series($events[0]['uid'],$bo) as $k => $event)
{
if (!$k) $master = $event;
if ($event['recurrence'])
{
$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
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
$org_recurrence = $org_recurrences[$recurrence['recurrence']];
@ -478,12 +505,13 @@ class calendar_groupdav extends groupdav_handler
if ($recurrence['id'] != $master['id'])
{
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
unset($org_recurrences[$recurrence['recurrence']]);
}
}
$master['recur_exception'] = array_merge($exceptions, $master['recur_exception']);
// delete not longer existing recurrences
foreach($org_recurrences as $org_recurrence)

View File

@ -41,6 +41,7 @@ class calendar_ical extends calendar_boupdate
'A' => 'ACCEPTED',
'R' => 'DECLINED',
'T' => 'TENTATIVE',
'D' => 'DELEGATED'
);
/**
* @var array conversation of the participant status ical => egw
@ -51,6 +52,7 @@ class calendar_ical extends calendar_boupdate
'ACCEPTED' => 'A',
'DECLINED' => 'R',
'TENTATIVE' => 'T',
'DELEGATED' => 'D',
);
/**
@ -227,7 +229,7 @@ class calendar_ical extends calendar_boupdate
if ($this->log)
{
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);
}
return -1; // Permission denied
@ -238,7 +240,7 @@ class calendar_ical extends calendar_boupdate
if ($this->log)
{
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"() Event $_id not found.\n",
"() Event $event not found.\n",
3, $this->logfile);
}
}
@ -342,15 +344,21 @@ class calendar_ical extends calendar_boupdate
$horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE');
// DTSTART must be in local time!
$standard = $horde_vtimezone->findComponent('STANDARD');
if (is_a($standard, 'Horde_iCalendar'))
{
$dtstart = $standard->getAttribute('DTSTART');
$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');
if (is_a($daylight, 'Horde_iCalendar'))
{
$dtstart = $daylight->getAttribute('DTSTART');
$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);
$vtimezones_added[] = $tzid;
}
@ -396,6 +404,7 @@ class calendar_ical extends calendar_boupdate
sort($exceptions);
}
$event['recur_exception'] = $exceptions;
/*
// Adjust the event start -- must not be an exception
$length = $event['end'] - $event['start'];
$rriter = calendar_rrule::event2rrule($event, false, $tzid);
@ -415,13 +424,21 @@ class calendar_ical extends calendar_boupdate
{
// the series dissolved completely into exceptions
continue;
}
}*/
}
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();
switch ($icalFieldName)
{
@ -928,11 +945,30 @@ class calendar_ical extends calendar_boupdate
{
if (!is_array($this->supportedFields)) $this->setSupportedFields();
if (!($events = $this->icaltoegw($_vcalData,$cal_id,$etag,$recur_date)))
if (!($events = $this->icaltoegw($_vcalData)))
{
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
// only first event / series master get's cal_id from URL
// 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)
{
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)
{
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
array2string($event)."\n",3,$this->logfile);
}
/*
if ($event['recur_type'] != MCAL_RECUR_NONE)
{
// 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;
}
*/
$updated_id = false;
$event_info = $this->get_event_info($event);
@ -1066,11 +1107,11 @@ class calendar_ical extends calendar_boupdate
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"() 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
{
$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))
{
$recur_exceptions = array();
/*
if (!isset($days[$event_info['stored_event']['start']]) &&
$event_info['stored_event']['start'] < $event['start'])
{
@ -1318,7 +1359,7 @@ class calendar_ical extends calendar_boupdate
$event['start'] = $startdate;
$event['end'] = $startdate + $length;
}
} */
foreach ($event['recur_exception'] as $recur_exception)
{
@ -1363,7 +1404,7 @@ class calendar_ical extends calendar_boupdate
$event_info['master_event']['recur_exception'] =
array_unique(array_merge($event_info['master_event']['recur_exception'],
array($event['recurrence'])));
/*
// Adjust the event start -- must not be an exception
$length = $event_info['master_event']['end'] - $event_info['master_event']['start'];
$rriter = calendar_rrule::event2rrule($event_info['master_event'], false);
@ -1376,6 +1417,21 @@ class calendar_ical extends calendar_boupdate
// remove leading exceptions
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]);
}
}
@ -1384,15 +1440,15 @@ class calendar_ical extends calendar_boupdate
{
$event_info['master_event']['start'] = $newstart;
$event_info['master_event']['end'] = $newstart + $length;
}*/
$event['reference'] = $event_info['master_event']['id'];
$event['category'] = $event_info['master_event']['category'];
$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['reference'] = $event_info['master_event']['id'];
$event['category'] = $event_info['master_event']['category'];
$event['owner'] = $event_info['master_event']['owner'];
}
$event_to_store = $event; // prevent $event from being changed by update method
$this->server2usertime($event_to_store);
@ -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)
{
@ -1906,7 +1962,7 @@ class calendar_ical extends calendar_boupdate
{
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
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']);
// 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;
}
@ -1957,11 +2008,10 @@ class calendar_ical extends calendar_boupdate
* @param array $component VEVENT
* @param string $version vCal version (1.0/2.0)
* @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
*/
function vevent2egw(&$component, $version, $supportedFields, $cal_id=-1)
function vevent2egw(&$component, $version, $supportedFields)
{
if (!is_a($component, 'Horde_iCalendar_vevent')) return false;
@ -2353,7 +2403,7 @@ class calendar_ical extends calendar_boupdate
case 'CATEGORIES':
if ($attributes['value'])
{
$vcardData['category'] = $this->find_or_add_categories(explode(',',$attributes['value']), $cal_id);
$vcardData['category'] = explode(',', $attributes['value']);
}
else
{
@ -2369,6 +2419,7 @@ class calendar_ical extends calendar_boupdate
if (isset($attributes['params']['STATUS']))
{
$status = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])];
if (empty($status)) $status = 'X';
}
else
{
@ -2599,8 +2650,6 @@ class calendar_ical extends calendar_boupdate
if ($this->calendarOwner) $event['owner'] = $this->calendarOwner;
if ($cal_id > 0) $event['id'] = $cal_id;
if ($this->log)
{
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .
@ -2613,7 +2662,15 @@ class calendar_ical extends calendar_boupdate
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
if (count($events) == 1)
@ -2621,6 +2678,7 @@ class calendar_ical extends calendar_boupdate
$filter = $relax ? 'relax' : 'check';
$event = array_shift($events);
if ($this->so->isWholeDay($event)) $event['whole_day'] = true;
$event['category'] = $this->find_or_add_categories($event['category'], $eventId);
if ($contentID) $event['id'] = $contentID;
return $this->find_event($event, $filter);
}

View File

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

View File

@ -44,6 +44,7 @@ define('REJECTED',0);
define('NO_RESPONSE',1);
define('TENTATIVE',2);
define('ACCEPTED',3);
define('DELEGATED',4);
define('HOUR_s',60*60);
define('DAY_s',24*HOUR_s);
@ -188,6 +189,18 @@ class calendar_so
$this->db->update($this->cal_table, array('cal_uid' => $event['uid']),
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
@ -377,6 +390,8 @@ class calendar_so
$where[] = "cal_status='T'"; break;
case 'rejected':
$where[] = "cal_status='R'"; break;
case 'delegated':
$where[] = "cal_status='D'"; break;
case 'all':
case 'owner':
break;
@ -649,6 +664,8 @@ ORDER BY cal_user_type, cal_usre_id
$minimum_uid_length = 8;
}
$old_min = $old_duration = 0;
//echo '<p>'.__METHOD__.'('.array2string($event).",$change_since) event="; _debug_array($event);
//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
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
if (isset($event['cal_participants']))
@ -1157,7 +1174,8 @@ ORDER BY cal_user_type, cal_usre_id
REJECTED => 'R',
NO_RESPONSE => 'U',
TENTATIVE => 'T',
ACCEPTED => 'A'
ACCEPTED => 'A',
DELEGATED => 'D'
);
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 $end=0 if != 0: enddate of the search/list (servertime)
* @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
* tz_rrule/tz_only, return (only by) timezone transition affected entries
* 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'));
$egw_rrule = calendar_rrule::event2rrule($event, false);
$egw_rrule->rewind();
$egw_rrule->current = clone $egw_rrule->time;
if ($expand_all)
{
unset($event['recur_excpetion']);
$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->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();
$locts = (int)egw_time::to($day,'server');
$tz_exception = ($filter == 'tz_rrule');
@ -1659,7 +1708,6 @@ ORDER BY cal_user_type, cal_usre_id
// '() status exception: ' . $day->format('Ymd\THis'));
if ($expand_all)
{
$remts = (int)egw_time::to($remote_day,'server');
if ($filter == 'tz_only')
{
unset($days[$remts]);
@ -1699,40 +1747,11 @@ ORDER BY cal_user_type, cal_usre_id
}
}
}
do
{
$egw_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;
}
@ -1831,6 +1850,13 @@ ORDER BY cal_user_type, cal_usre_id
continue;
}
break;
case 'delegated':
if ($status != 'D')
{
unset($participants[$uid]);
continue;
}
break;
case 'default':
if ($status == 'R')
{

View File

@ -708,6 +708,7 @@ class calendar_ui
'accepted' => array(lang('Accepted'), lang('Show only accepted events')),
'unknown' => array(lang('Invitations'), lang('Show only invitations, not yet accepted or rejected')),
'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')),
'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')),

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B