mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-25 16:19:00 +01:00
Fix various synchronization issues (SyncML & CalDAV)
This commit is contained in:
parent
8204d84ca5
commit
21ccdd5f28
@ -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].')';
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// 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'])
|
||||
{
|
||||
// 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;
|
||||
// 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))
|
||||
{
|
||||
@ -1111,10 +1123,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)
|
||||
@ -2077,4 +2089,4 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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,8 +240,8 @@ class calendar_ical extends calendar_boupdate
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
"() Event $_id not found.\n",
|
||||
3,$this->logfile);
|
||||
"() Event $event not found.\n",
|
||||
3, $this->logfile);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@ -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');
|
||||
$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);
|
||||
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');
|
||||
$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);
|
||||
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,14 +1440,14 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$event_info['master_event']['start'] = $newstart;
|
||||
$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['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_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)
|
||||
{
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
if ($expand_all)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
$remote_rrule->next_no_exception();
|
||||
}
|
||||
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')
|
||||
{
|
||||
|
@ -146,7 +146,7 @@ class calendar_ui
|
||||
$this->accountsel = $GLOBALS['egw']->uiaccountsel;
|
||||
|
||||
$this->categories = new categories($this->user,'calendar');
|
||||
|
||||
|
||||
$this->common_prefs = &$GLOBALS['egw_info']['user']['preferences']['common'];
|
||||
$this->cal_prefs = &$GLOBALS['egw_info']['user']['preferences']['calendar'];
|
||||
$this->bo->check_set_default_prefs();
|
||||
@ -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')),
|
||||
|
BIN
calendar/templates/default/images/forward.gif
Normal file
BIN
calendar/templates/default/images/forward.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 319 B |
BIN
calendar/templates/default/images/forward.png
Normal file
BIN
calendar/templates/default/images/forward.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 494 B |
Loading…
Reference in New Issue
Block a user