mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-22 23:00:56 +01:00
complete rework of the ical import part: removed unclear 1:N relations, introduced get_event_info method which completely classifies incoming events first, removed code duplicates, re-organized importVCal() to have a more linear code structure and to make debugging easier in future. -- please forgive me if i may have introduced some bugs with that but its a huge change --"
This commit is contained in:
parent
9ed090d1a6
commit
5602cac698
@ -782,71 +782,58 @@ class calendar_ical extends calendar_boupdate
|
|||||||
* @param int $cal_id=-1 must be -1 for new entries!
|
* @param int $cal_id=-1 must be -1 for new entries!
|
||||||
* @param string $etag=null if an etag is given, it has to match the current etag or the import will fail
|
* @param string $etag=null if an etag is given, it has to match the current etag or the import will fail
|
||||||
* @param boolean $merge=false merge data with existing entry
|
* @param boolean $merge=false merge data with existing entry
|
||||||
* @param int $recur_date=0 if set, import the recurrance at this timestamp,
|
* @param int $recur_date=0 if set, import the recurrence at this timestamp,
|
||||||
* default 0 => import whole series (or events, if not recurring)
|
* default 0 => import whole series (or events, if not recurring)
|
||||||
* @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag
|
* @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag
|
||||||
*/
|
*/
|
||||||
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0)
|
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0)
|
||||||
{
|
{
|
||||||
$Ok = false; // returning false, if file contains no components
|
|
||||||
if($this->log)error_log(__LINE__.__METHOD__.__FILE__.array2string($_vcalData)."\n",3,$this->logfile);
|
if($this->log)error_log(__LINE__.__METHOD__.__FILE__.array2string($_vcalData)."\n",3,$this->logfile);
|
||||||
|
|
||||||
$vcal = new Horde_iCalendar;
|
if(!$events = $this->icaltoegw($_vcalData,$cal_id,$etag,$recur_date))
|
||||||
if (!$vcal->parsevCalendar($_vcalData))
|
|
||||||
{
|
{
|
||||||
return $Ok;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$version = $vcal->getAttribute('VERSION');
|
|
||||||
|
|
||||||
if (!is_array($this->supportedFields)) $this->setSupportedFields();
|
if (!is_array($this->supportedFields)) $this->setSupportedFields();
|
||||||
|
|
||||||
foreach ($vcal->getComponents() as $component)
|
foreach ($events as $event)
|
||||||
{
|
{
|
||||||
if (is_a($component, 'Horde_iCalendar_vevent'))
|
$updated_id = false;
|
||||||
{
|
$event_info = $this->get_event_info($event);
|
||||||
$event = $this->vevent2egw($component, $version, $this->supportedFields);
|
|
||||||
|
|
||||||
if ($cal_id > 0) {
|
// common adjustments for new events
|
||||||
$event['id'] = $cal_id;
|
if(!isset($event['id']))
|
||||||
|
{
|
||||||
|
// set non blocking all day depending on the user setting
|
||||||
|
if($this->isWholeDay($event) && $this->nonBlockingAllday)
|
||||||
|
{
|
||||||
|
$event['non_blocking'] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->productManufacturer == '' && $this->productName == ''
|
// check if an owner is set and the current user has add rights
|
||||||
&& !empty($event['recur_enddate']))
|
// for that owners calendar; if not set the current user
|
||||||
|
if(!isset($event['owner'])
|
||||||
|
|| !$this->check_perms(EGW_ACL_ADD,0,$event['owner']))
|
||||||
{
|
{
|
||||||
// syncevolution needs an adjusted recur_enddate
|
$event['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||||
$event['recur_enddate'] = (int)$event['recur_enddate'] + 86400;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cal_id < 0 && (!isset($this->supportedFields['participants']) ||
|
|
||||||
!isset($event['participants'][$GLOBALS['egw_info']['user']['account_id']])))
|
|
||||||
{
|
|
||||||
// add ourself to new events as participant
|
// add ourself to new events as participant
|
||||||
|
if(!isset($this->supportedFields['participants'])
|
||||||
|
||!isset($event['participants'][$GLOBALS['egw_info']['user']['account_id']]))
|
||||||
|
{
|
||||||
$event['participants'][$GLOBALS['egw_info']['user']['account_id']] = 'A';
|
$event['participants'][$GLOBALS['egw_info']['user']['account_id']] = 'A';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
|
||||||
{
|
|
||||||
// No RECURRENCE-ID for series events
|
|
||||||
$event['reference'] = $event['recurrence'] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$recur_date && $cal_id > 0 && ($egw_event = $this->read($cal_id)))
|
// common adjustments for existing events
|
||||||
|
if (isset($event['id']) && is_array($event_info['stored_event']))
|
||||||
{
|
{
|
||||||
// overwrite with server data for merge
|
|
||||||
if ($merge)
|
if ($merge)
|
||||||
{
|
{
|
||||||
if ($egw_event['recur_type'] != MCAL_RECUR_NONE && $recur_date)
|
// overwrite with server data for merge
|
||||||
{
|
foreach ($event_info['stored_event'] as $key => $value)
|
||||||
// update only the stati of the exception
|
|
||||||
if ($this->check_perms(EGW_ACL_EDIT, $cal_id))
|
|
||||||
{
|
|
||||||
$this->update_status($event, $egw_event, $recur_date);
|
|
||||||
}
|
|
||||||
$Ok = $cal_id . ':' . $recur_date;
|
|
||||||
continue; // nothing more to do
|
|
||||||
}
|
|
||||||
foreach ($egw_event as $key => $value)
|
|
||||||
{
|
{
|
||||||
switch ($key)
|
switch ($key)
|
||||||
{
|
{
|
||||||
@ -854,7 +841,7 @@ class calendar_ical extends calendar_boupdate
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'participants':
|
case 'participants':
|
||||||
foreach ($egw_event['participants'] as $uid => $status)
|
foreach ($event_info['stored_event']['participants'] as $uid => $status)
|
||||||
{
|
{
|
||||||
// Is a participant and no longer present in the event?
|
// Is a participant and no longer present in the event?
|
||||||
if (!isset($event['participants'][$uid]))
|
if (!isset($event['participants'][$uid]))
|
||||||
@ -873,17 +860,18 @@ class calendar_ical extends calendar_boupdate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // not merge
|
else
|
||||||
{
|
{
|
||||||
|
// no merge
|
||||||
if (!isset($this->supportedFields['participants']) || !count($event['participants']))
|
if (!isset($this->supportedFields['participants']) || !count($event['participants']))
|
||||||
{
|
{
|
||||||
// If this is an updated meeting, and the client doesn't support
|
// If this is an updated meeting, and the client doesn't support
|
||||||
// participants OR the event no longer contains participants, add them back
|
// participants OR the event no longer contains participants, add them back
|
||||||
$event['participants'] = $egw_event['participants'];
|
$event['participants'] = $event_info['stored_event']['participants'];
|
||||||
$event['participant_types'] = $egw_event['participant_types'];
|
$event['participant_types'] = $event_info['stored_event']['participant_types'];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($egw_event['participants'] as $uid => $status)
|
foreach ($event_info['stored_event']['participants'] as $uid => $status)
|
||||||
{
|
{
|
||||||
// Is it a resource and no longer present in the event?
|
// Is it a resource and no longer present in the event?
|
||||||
if ( $uid[0] == 'r' && !isset($event['participants'][$uid]) )
|
if ( $uid[0] == 'r' && !isset($event['participants'][$uid]) )
|
||||||
@ -893,121 +881,34 @@ class calendar_ical extends calendar_boupdate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// avoid that iCal changes the organizer, which is not allowed
|
// avoid that iCal changes the organizer, which is not allowed
|
||||||
$event['owner'] = $egw_event['owner'];
|
$event['owner'] = $event_info['stored_event']['owner'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// new event
|
|
||||||
$cal_id = -1;
|
|
||||||
$recur_date = $event['recurrence'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($event['uid']) && $cal_id > 0 &&
|
// save event depending on the given event type
|
||||||
($egw_event = $this->read($cal_id)))
|
switch($event_info['type'])
|
||||||
{
|
{
|
||||||
$event['uid'] = $egw_event['uid'];
|
case 'SINGLE':
|
||||||
}
|
Horde::logMessage('importVCAL event SINGLE',__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
|
|
||||||
if ($event['recur_type'] == MCAL_RECUR_NONE
|
// update the event
|
||||||
&& !empty($event['uid']) && $recur_date)
|
if($event_info['acl_edit'])
|
||||||
{
|
{
|
||||||
// We handle a recurrence exception
|
$event_to_store = $event; // prevent $event from being changed by the update method
|
||||||
$recur_exceptions = $this->so->get_related($event['uid']);
|
$updated_id = $this->update($event_to_store, true);
|
||||||
$recur_id = array_search($recur_date, $recur_exceptions);
|
unset($event_to_store);
|
||||||
if ($recur_id === false || !($egw_event = $this->read($recur_id)))
|
}
|
||||||
{
|
|
||||||
// We found no real exception, let't try "status only"
|
|
||||||
if (($egw_event = $this->read($event['uid']))
|
|
||||||
&& $egw_event['recur_type'] != MCAL_RECUR_NONE)
|
|
||||||
{
|
|
||||||
// Same start and duration is obligatory for status only
|
|
||||||
$old_duration = $egw_event['end'] - $egw_event['start'];
|
|
||||||
$new_duration = $event['end'] - $event['start'];
|
|
||||||
$unchanged = ($event['start'] == $recur_date && $old_duration == $new_duration);
|
|
||||||
foreach (array('uid','owner','title','description',
|
|
||||||
'location','priority','public','special','non_blocking') as $key)
|
|
||||||
{
|
|
||||||
//Horde::logMessage('importVCAL test ' .$key . ': '. $egw_event[$key] . ' == ' .$event[$key],
|
|
||||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
if (!$unchanged && !empty($event[$key]) //|| !empty($egw_event[$key]))
|
|
||||||
&& $egw_event[$key] != $event[$key])
|
|
||||||
{
|
|
||||||
$unchanged = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($unchanged)
|
|
||||||
{
|
|
||||||
Horde::logMessage('importVCAL event unchanged',
|
|
||||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
|
|
||||||
$recur_exceptions = array();
|
case 'SERIES-MASTER':
|
||||||
foreach ($egw_event['recur_exception'] as $recur_exception)
|
Horde::logMessage('importVCAL event SERIES-MASTER',__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
{
|
|
||||||
//Horde::logMessage('importVCAL exception ' .$recur_exception,
|
|
||||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
if ($recur_exception != $recur_date)
|
|
||||||
{
|
|
||||||
$recur_exceptions[] = $recur_exception;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$egw_event['recur_exception'] = $recur_exceptions;
|
|
||||||
//Horde::logMessage("importVCAL exceptions\n" . print_r($recur_exceptions, true),
|
|
||||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
|
|
||||||
$this->update($egw_event, true);
|
// remove all known "status only" exceptions and update the event
|
||||||
|
if($event_info['acl_edit'])
|
||||||
// update the stati from the exception
|
|
||||||
if ($this->check_perms(EGW_ACL_EDIT, $egw_event['id']))
|
|
||||||
{
|
{
|
||||||
$this->update_status($event, $egw_event, $recur_date);
|
|
||||||
}
|
|
||||||
elseif (isset($event['participants'][$this->user]) || isset($egw_event['participants'][$this->user]))
|
|
||||||
{
|
|
||||||
// check if current user is an attendee and tried to change his status
|
|
||||||
$this->set_status($egw_event, $this->user,
|
|
||||||
($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), $recur_date, true);
|
|
||||||
}
|
|
||||||
$Ok = $egw_event['id'] . ':' . $recur_date;
|
|
||||||
continue; // nothing more to do
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We need to create an new exception
|
|
||||||
$egw_event['recur_exception'] = array_unique(array_merge($egw_event['recur_exception'], array($recur_date)));
|
|
||||||
$this->update($egw_event, true);
|
|
||||||
$event['reference'] = $egw_event['id'];
|
|
||||||
$event['category'] = $egw_event['category'];
|
|
||||||
unset($event['id']);
|
|
||||||
$cal_id = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The series event was not found
|
|
||||||
$cal_id = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We update an existing exception
|
|
||||||
$cal_id = $egw_event['id'];
|
|
||||||
$event['id'] = $egw_event['id'];
|
|
||||||
$event['category'] = $egw_event['category'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We handle a single event or the series master
|
|
||||||
$days = $this->so->get_recurrence_exceptions($event);
|
$days = $this->so->get_recurrence_exceptions($event);
|
||||||
if(is_array($days))
|
if(is_array($days))
|
||||||
{
|
{
|
||||||
Horde::logMessage("importVCAL event\n" . print_r($event, true),
|
|
||||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
Horde::logMessage("importVCAL days\n" . print_r($days, true),
|
|
||||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
// remove all known "stati only" exceptions
|
|
||||||
$recur_exceptions = array();
|
$recur_exceptions = array();
|
||||||
foreach($event['recur_exception'] as $recur_exception)
|
foreach($event['recur_exception'] as $recur_exception)
|
||||||
{
|
{
|
||||||
@ -1016,135 +917,182 @@ class calendar_ical extends calendar_boupdate
|
|||||||
$recur_exceptions[] = $recur_exception;
|
$recur_exceptions[] = $recur_exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Horde::logMessage("importVCAL exceptions\n" . print_r($recur_exceptions, true),
|
|
||||||
__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
$event['recur_exception'] = $recur_exceptions;
|
$event['recur_exception'] = $recur_exceptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$event_to_store = $event; // prevent $event from being changed by the update method
|
||||||
|
$updated_id = $this->update($event_to_store, true);
|
||||||
|
unset($event_to_store);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cal_id <= 0)
|
|
||||||
{
|
|
||||||
// new entry
|
|
||||||
if ($this->isWholeDay($event) && $this->nonBlockingAllday)
|
|
||||||
{
|
|
||||||
$event['non_blocking'] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($event['owner'])
|
|
||||||
|| !$this->check_perms(EGW_ACL_ADD,0,$event['owner']))
|
|
||||||
{
|
|
||||||
// check for new events if an owner is set and the current user has add rights
|
|
||||||
// for that owners calendar; if not set the current user
|
|
||||||
$event['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if an etag is given, include it in the update
|
|
||||||
if (!is_null($etag))
|
|
||||||
{
|
|
||||||
$event['etag'] = $etag;
|
|
||||||
}
|
|
||||||
|
|
||||||
$original_event = $event;
|
|
||||||
if($this->log)error_log(__LINE__.__METHOD__.__FILE__.array2string($original_event)."\n",3,$this->logfile);
|
|
||||||
|
|
||||||
if (!($Ok = $this->update($event, true)))
|
|
||||||
{
|
|
||||||
if($this->log)error_log(__LINE__.__METHOD__.__FILE__.array2string($Ok)."\n",3,$this->logfile);
|
|
||||||
|
|
||||||
if ($Ok === false && $cal_id > 0 && ($egw_event = $this->read($cal_id)))
|
|
||||||
{
|
|
||||||
$unchanged = true;
|
|
||||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
|
||||||
{
|
|
||||||
// Check if a recurring event "status only" exception is created by the client
|
|
||||||
foreach (array('uid','owner','title','description',
|
|
||||||
'location','priority','public','special','non_blocking') as $key)
|
|
||||||
{
|
|
||||||
//Horde::logMessage('importVCAL test ' .$key . ': '. $egw_event[$key] . ' == ' .$event[$key],
|
|
||||||
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
if (!empty($event[$key]) //|| !empty($egw_event[$key]))
|
|
||||||
&& $egw_event[$key] != $event[$key])
|
|
||||||
{
|
|
||||||
$unchanged = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check if current user is an attendee and tried to change his status
|
|
||||||
if (isset($event['participants'][$this->user]) || isset($egw_event['participants'][$this->user]))
|
|
||||||
{
|
|
||||||
$this->set_status($egw_event, $this->user,
|
|
||||||
($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), $recur_date);
|
|
||||||
|
|
||||||
$Ok = $cal_id;
|
case 'SERIES-EXCEPTION':
|
||||||
continue;
|
Horde::logMessage('importVCAL event SERIES-EXCEPTION',__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
}
|
|
||||||
|
|
||||||
if ($unchanged)
|
// update event
|
||||||
|
if($event_info['acl_edit'])
|
||||||
{
|
{
|
||||||
$Ok = $cal_id;
|
if(isset($event_info['stored_event']['id']))
|
||||||
continue;
|
{
|
||||||
}
|
// We update an existing exception
|
||||||
}
|
$event['id'] = $event_info['stored_event']['id'];
|
||||||
break; // stop with the first error
|
$event['category'] = $event_info['stored_event']['category'];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$eventID = &$Ok;
|
// We create a new exception
|
||||||
if($this->log)error_log(__LINE__.__METHOD__.__FILE__.array2string($eventID)."\n",3,$this->logfile);
|
unset($event['id']);
|
||||||
|
$event_info['master_event']['recur_exception'] = array_unique(array_merge($event_info['master_event']['recur_exception'], array($event['recurrence'])));
|
||||||
|
$event_to_store = $event_info['master_event']; // prevent the master_event from being changed by the update method
|
||||||
|
$this->update($event_to_store, true);
|
||||||
|
unset($event_to_store);
|
||||||
|
$event['reference'] = $event_info['master_event']['id'];
|
||||||
|
$event['category'] = $event_info['master_event']['category'];
|
||||||
|
}
|
||||||
|
|
||||||
/* if(isset($egw_event)
|
$event_to_store = $event; // prevent $event from being changed by update method
|
||||||
&& $original_event['participants'] != $egw_event['participants'])
|
$updated_id = $this->update($event_to_store, true);
|
||||||
{
|
unset($event_to_store);
|
||||||
$this->update_status($original_event, $egw_event, $recur_date);
|
}
|
||||||
} */
|
break;
|
||||||
|
|
||||||
$alarms = $event['alarm'];
|
case 'SERIES-EXCEPTION-STATUS':
|
||||||
|
Horde::logMessage('importVCAL event SERIES-EXCEPTION-STATUS',__FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
|
|
||||||
// handle the alarms
|
if($event_info['acl_edit'])
|
||||||
foreach ($component->getComponents() as $valarm)
|
|
||||||
{
|
{
|
||||||
if (is_a($valarm, 'Horde_iCalendar_valarm'))
|
// truncate the status only exception from the series master
|
||||||
|
$recur_exceptions = array();
|
||||||
|
foreach ($event_info['master_event']['recur_exception'] as $recur_exception)
|
||||||
{
|
{
|
||||||
$this->valarm2egw($alarms, $valarm);
|
if ($recur_exception != $event['recurrence'])
|
||||||
|
{
|
||||||
|
$recur_exceptions[] = $recur_exception;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$event_info['master_event']['recur_exception'] = $recur_exceptions;
|
||||||
|
|
||||||
|
// save the series master with the adjusted exceptions
|
||||||
|
$event_to_store = $event_info['master_event']; // prevent the master_event from being changed by the update method
|
||||||
|
$updated_id = $this->update($event_to_store, true);
|
||||||
|
unset($event_to_store);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read stored event into info array for fresh stored (new) events
|
||||||
|
if(!is_array($event_info['stored_event']) && $updated_id > 0)
|
||||||
|
{
|
||||||
|
$event_info['stored_event'] = $this->read($updated_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update status depending on the given event type
|
||||||
|
switch($event_info['type'])
|
||||||
|
{
|
||||||
|
case 'SINGLE':
|
||||||
|
case 'SERIES-MASTER':
|
||||||
|
case 'SERIES-EXCEPTION':
|
||||||
|
if(is_array($event_info['stored_event'])) // status update requires a stored event
|
||||||
|
{
|
||||||
|
if($event_info['acl_edit'])
|
||||||
|
{
|
||||||
|
// update all participants if we have the right to do that
|
||||||
|
$this->update_status($event, $event_info['stored_event']);
|
||||||
|
}
|
||||||
|
elseif(isset($event['participants'][$this->user]) || isset($event_info['stored_event']['participants'][$this->user]))
|
||||||
|
{
|
||||||
|
// update the users status only
|
||||||
|
$this->set_status($event_info['stored_event']['id'], $this->user,
|
||||||
|
($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SERIES-EXCEPTION-STATUS':
|
||||||
|
if(is_array($event_info['stored_event'])) // status update requires a stored master event
|
||||||
|
{
|
||||||
|
if($event_info['acl_edit'])
|
||||||
|
{
|
||||||
|
// update all participants if we have the right to do that
|
||||||
|
$this->update_status($event, $event_info['stored_event'], $event['recurrence']);
|
||||||
|
}
|
||||||
|
elseif(isset($event['participants'][$this->user]) || isset($event_info['master_event']['participants'][$this->user]))
|
||||||
|
{
|
||||||
|
// update the users status only
|
||||||
|
$this->set_status($event_info['master_event']['id'], $this->user,
|
||||||
|
($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), $event['recurrence'], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update alarms depending on the given event type
|
||||||
|
switch($event_info['type'])
|
||||||
|
{
|
||||||
|
case 'SINGLE':
|
||||||
|
case 'SERIES-MASTER':
|
||||||
|
case 'SERIES-EXCEPTION':
|
||||||
|
if(is_array($event_info['stored_event'])) // alarm update requires a stored event
|
||||||
|
{
|
||||||
|
// delete old alarms
|
||||||
|
if(count($event['alarm']) > 0
|
||||||
|
|| (isset($this->supportedFields['alarms']) && count($event['alarm']) == 0))
|
||||||
|
{
|
||||||
|
foreach ($event_info['stored_event']['alarm'] as $alarm_id => $alarm_data)
|
||||||
|
{
|
||||||
|
$this->delete_alarm($alarm_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($alarms) > 0
|
// save given alarms
|
||||||
|| (isset($this->supportedFields['alarms'])
|
if(count($event['alarm']) > 0)
|
||||||
&& count($alarms) == 0))
|
|
||||||
{
|
{
|
||||||
// delete the old alarms
|
foreach ($event['alarm'] as $alarm)
|
||||||
$updatedEvent = $this->read($eventID);
|
|
||||||
foreach ($updatedEvent['alarm'] as $alarmID => $alarmData)
|
|
||||||
{
|
{
|
||||||
$this->delete_alarm($alarmID);
|
if(!isset($alarm['offset']) && isset($alarm['time']))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($alarms as $alarm)
|
|
||||||
{
|
|
||||||
if (!isset($alarm['offset']))
|
|
||||||
{
|
{
|
||||||
$alarm['offset'] = $event['start'] - $alarm['time'];
|
$alarm['offset'] = $event['start'] - $alarm['time'];
|
||||||
}
|
}
|
||||||
if (!isset($alarm['time']))
|
if(!isset($alarm['time']) && isset($alarm['offset']))
|
||||||
{
|
{
|
||||||
$alarm['time'] = $event['start'] - $alarm['offset'];
|
$alarm['time'] = $event['start'] - $alarm['offset'];
|
||||||
}
|
}
|
||||||
$alarm['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
$alarm['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
||||||
$alarm['all'] = true;
|
$alarm['all'] = true;
|
||||||
$this->save_alarm($eventID, $alarm);
|
$this->save_alarm($event_info['stored_event']['id'], $alarm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$cal_id = -1;
|
|
||||||
}
|
}
|
||||||
$egw_event = $this->read($eventID);
|
break;
|
||||||
if($this->log)error_log(__LINE__.__METHOD__.__FILE__.array2string($egw_event)."\n",3,$this->logfile);
|
|
||||||
|
|
||||||
|
case 'SERIES-EXCEPTION-STATUS':
|
||||||
|
// nothing to do here
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return $Ok;
|
|
||||||
|
// choose which id to return to the client
|
||||||
|
switch($event_info['type'])
|
||||||
|
{
|
||||||
|
case 'SINGLE':
|
||||||
|
case 'SERIES-MASTER':
|
||||||
|
case 'SERIES-EXCEPTION':
|
||||||
|
$return_id = is_array($event_info['stored_event']) ? $event_info['stored_event']['id'] : false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SERIES-EXCEPTION-STATUS':
|
||||||
|
$return_id = is_array($event_info['master_event']) ? $event_info['master_event']['id'] . ':' . $event['recurrence'] : false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->log)
|
||||||
|
{
|
||||||
|
$egw_event = $this->read($event['id']);
|
||||||
|
error_log(__LINE__.__METHOD__.__FILE__.array2string($egw_event)."\n",3,$this->logfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1422,51 +1370,74 @@ class calendar_ical extends calendar_boupdate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function icaltoegw($_vcalData, $cal_id=-1)
|
function icaltoegw($_vcalData, $cal_id=-1, $etag=null, $recur_date=0)
|
||||||
{
|
{
|
||||||
$event = false; // returning false, if file contains no components
|
$events = array();
|
||||||
|
|
||||||
$vcal = new Horde_iCalendar;
|
$vcal = new Horde_iCalendar;
|
||||||
if (!$vcal->parsevCalendar($_vcalData)) return false;
|
if (!$vcal->parsevCalendar($_vcalData)) return false;
|
||||||
|
|
||||||
$version = $vcal->getAttribute('VERSION');
|
$version = $vcal->getAttribute('VERSION');
|
||||||
|
|
||||||
if (!is_array($this->supportedFields)) $this->setSupportedFields();
|
if (!is_array($this->supportedFields)) $this->setSupportedFields();
|
||||||
|
|
||||||
foreach ($vcal->getComponents() as $component)
|
foreach ($vcal->getComponents() as $component)
|
||||||
{
|
{
|
||||||
if (is_a($component, 'Horde_iCalendar_vevent'))
|
if (is_a($component, 'Horde_iCalendar_vevent'))
|
||||||
{
|
{
|
||||||
// We expect only a single VEVENT
|
if ($event = $this->vevent2egw($component, $version, $this->supportedFields))
|
||||||
$event = $this->vevent2egw($component, $version, $this->supportedFields);
|
|
||||||
if ($event)
|
|
||||||
{
|
{
|
||||||
if ($cal_id > 0) {
|
//common adjustments
|
||||||
$event['id'] = $cal_id;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if($this->isWholeDay($event)
|
|
||||||
&& $this->nonBlockingAllday)
|
|
||||||
{
|
|
||||||
$event['non_blocking'] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->productManufacturer == '' && $this->productName == ''
|
if ($this->productManufacturer == '' && $this->productName == ''
|
||||||
&& !empty($event['recur_enddate']))
|
&& !empty($event['recur_enddate']))
|
||||||
{
|
{
|
||||||
// syncevolution needs an adjusted recur_enddate
|
// syncevolution needs an adjusted recur_enddate
|
||||||
$event['recur_enddate'] = (int)$event['recur_enddate'] + 86400;
|
$event['recur_enddate'] = (int)$event['recur_enddate'] + 86400;
|
||||||
}
|
}
|
||||||
|
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
||||||
|
{
|
||||||
|
// No reference or RECURRENCE-ID for the series master
|
||||||
|
$event['reference'] = $event['recurrence'] = 0;
|
||||||
}
|
}
|
||||||
return $event;
|
|
||||||
|
// handle the alarms
|
||||||
|
$alarms = $event['alarm'];
|
||||||
|
foreach ($component->getComponents() as $valarm)
|
||||||
|
{
|
||||||
|
if (is_a($valarm, 'Horde_iCalendar_valarm'))
|
||||||
|
{
|
||||||
|
$this->valarm2egw($alarms, $valarm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$event['alarm'] = $alarms;
|
||||||
|
|
||||||
|
$events[] = $event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decide what to return
|
||||||
|
if(count($events) == 1)
|
||||||
|
{
|
||||||
|
$event = array_shift($events);
|
||||||
|
if($cal_id > 0) $event['id'] = $cal_id;
|
||||||
|
if(!is_null($etag)) $event['etag'] = $etag;
|
||||||
|
if($recur_date) $event['recurrence'] = $recur_date;
|
||||||
|
|
||||||
|
return array($event);
|
||||||
|
}
|
||||||
|
else if($count($events) == 0 || $cal_id > 0 || !is_null($etag) || $recur_date)
|
||||||
|
{
|
||||||
|
// no events to return
|
||||||
|
// or not allowed N:1 relation with params just meant for a single event
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an VEVENT
|
* Parse a VEVENT
|
||||||
*
|
*
|
||||||
* @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)
|
||||||
@ -2018,16 +1989,16 @@ class calendar_ical extends calendar_boupdate
|
|||||||
|
|
||||||
function search($_vcalData, $contentID=null, $relax=false)
|
function search($_vcalData, $contentID=null, $relax=false)
|
||||||
{
|
{
|
||||||
$result = false;
|
if($events = $this->icaltoegw($_vcalData,!is_null($contentID) ? $contentID : -1))
|
||||||
|
|
||||||
if($event = $this->icaltoegw($_vcalData))
|
|
||||||
{
|
{
|
||||||
if ($contentID) {
|
// this function only supports searching a single event
|
||||||
$event['id'] = $contentID;
|
if(count($events) == 1)
|
||||||
|
{
|
||||||
|
$event = array_shift($events);
|
||||||
|
return $this->find_event($event, $relax);
|
||||||
}
|
}
|
||||||
$result = $this->find_event($event, $relax);
|
|
||||||
}
|
}
|
||||||
return $result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2121,9 +2092,8 @@ class calendar_ical extends calendar_boupdate
|
|||||||
* @param array $old_event event-array with the old stati
|
* @param array $old_event event-array with the old stati
|
||||||
* @param int $recur_date=0 date to change, or 0 = all since now
|
* @param int $recur_date=0 date to change, or 0 = all since now
|
||||||
*/
|
*/
|
||||||
function update_status($new_event, $old_event , $recur_date)
|
function update_status($new_event, $old_event , $recur_date=0)
|
||||||
{
|
{
|
||||||
|
|
||||||
// check the old list against the new list
|
// check the old list against the new list
|
||||||
foreach ($old_event['participants'] as $userid => $status)
|
foreach ($old_event['participants'] as $userid => $status)
|
||||||
{
|
{
|
||||||
@ -2141,4 +2111,89 @@ class calendar_ical extends calendar_boupdate
|
|||||||
$this->set_status($old_event, $userid, $status, $recur_date, true);
|
$this->set_status($old_event, $userid, $status, $recur_date, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* classifies an incoming event from the eGW point-of-view
|
||||||
|
*
|
||||||
|
* exceptions: unlike other calendar apps eGW does not create an event exception
|
||||||
|
* if just the participant state changes - therefore we have to distinguish between
|
||||||
|
* real exceptions and status only exceptions
|
||||||
|
*
|
||||||
|
* @param array $event the event to check
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* type =>
|
||||||
|
* SINGLE a single event
|
||||||
|
* SERIES-MASTER the series master
|
||||||
|
* SERIES-EXCEPTION event is a real exception
|
||||||
|
* SERIES-EXCEPTION-STATUS event is a status only exception
|
||||||
|
* stored_event => if event already exists in the database array with event data or false
|
||||||
|
* master_event => if event is of type SERIES-EXCEPTION or SERIES-EXCEPTION-STATUS the corresponding series master event array
|
||||||
|
*/
|
||||||
|
private function get_event_info($event)
|
||||||
|
{
|
||||||
|
$type = 'SINGLE'; // default
|
||||||
|
$return_master = false; //default
|
||||||
|
|
||||||
|
if($event['recur_type'] != MCAL_RECUR_NONE)
|
||||||
|
{
|
||||||
|
$type = 'SERIES-MASTER';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SINGLE, SERIES-EXCEPTION OR SERIES-EXCEPTON-STATUS
|
||||||
|
if(empty($event['uid']) && $event['id'] > 0 && ($stored_event = $this->read($event['id'])))
|
||||||
|
{
|
||||||
|
$event['uid'] = $stored_event['uid']; // restore the UID if it was not delivered
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($event['uid'])
|
||||||
|
&& $event['recurrence']
|
||||||
|
&& ($master_event = $this->read($event['uid']))
|
||||||
|
&& isset($master_event['recur_type'])
|
||||||
|
&& $master_event['recur_type'] != MCAL_RECUR_NONE
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// SERIES-EXCEPTION OR SERIES-EXCEPTON-STATUS
|
||||||
|
$return_master = true; // we have a valid master and can return it
|
||||||
|
|
||||||
|
if(isset($event['id']) && $master_event['id'] != $event['id'])
|
||||||
|
{
|
||||||
|
$type = 'SERIES-EXCEPTION'; //event is already a real exception
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$type = 'SERIES-EXCEPTION-STATUS'; // default if we cannot find a proof for a fundamental change
|
||||||
|
$recurrence_event = $this->read($master_event['id'],$event['recurrence']);
|
||||||
|
// check for changed data
|
||||||
|
foreach (array('start','end','uid','owner','title','description',
|
||||||
|
'location','priority','public','special','non_blocking') as $key)
|
||||||
|
{
|
||||||
|
if (!empty($event[$key]) && $recurrence_event[$key] != $event[$key])
|
||||||
|
{
|
||||||
|
$type = 'SERIES-EXCEPTION';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SINGLE
|
||||||
|
$type = 'SINGLE';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($event['id']))
|
||||||
|
{
|
||||||
|
$stored_event = $this->read($event['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'type' => $type,
|
||||||
|
'acl_edit' => is_array($stored_event) ? $this->check_perms(EGW_ACL_EDIT, $stored_event) : true,
|
||||||
|
'stored_event' => is_array($stored_event) ? $stored_event : false,
|
||||||
|
'master_event' => $return_master ? $master_event : false,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user