* CalDAV/Lightning: fixed under some conditions infinit poping up alarms and user not able to add alarms

- Lightning pops up alarm, until Sequence/etag get updated: if user has no edit rights on an other users calendar, etag never got updated, now we update it
- fixed user was not able to add alarms via CalDAV, if he had no edit rights for event (was always possible in web UI)
- alarms from other users calendars are not included any more, as they make no sense but a lot of trouble
- fixed wrong condition on adding alarms, causing some alarms no being saved
This commit is contained in:
Ralf Becker 2011-03-05 10:21:32 +00:00
parent 738966ca68
commit 3bb9e89bcf
8 changed files with 73 additions and 42 deletions

View File

@ -276,9 +276,10 @@ class addressbook_groupdav extends groupdav_handler
* *
* @param array &$options * @param array &$options
* @param int $id * @param int $id
* @param int $user=null account_id
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found') * @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
*/ */
function get(&$options,$id) function get(&$options,$id,$user=null)
{ {
if (!is_array($contact = $this->_common_get_put_delete('GET',$options,$id))) if (!is_array($contact = $this->_common_get_put_delete('GET',$options,$id)))
{ {

View File

@ -220,7 +220,7 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
//error_log(__FILE__ . __METHOD__ . "Calendar Data : $calendar_data"); //error_log(__FILE__ . __METHOD__ . "Calendar Data : $calendar_data");
if ($calendar_data) if ($calendar_data)
{ {
$content = $this->iCal($event); $content = $this->iCal($event,$filter['users']);
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content)); $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content);
} }
@ -382,15 +382,16 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
* *
* @param array &$options * @param array &$options
* @param int $id * @param int $id
* @param int $user=null account_id
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found') * @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
*/ */
function get(&$options,$id) function get(&$options,$id,$user=null)
{ {
if (!is_array($event = $this->_common_get_put_delete('GET',$options,$id))) if (!is_array($event = $this->_common_get_put_delete('GET',$options,$id)))
{ {
return $event; return $event;
} }
$options['data'] = $this->iCal($event); $options['data'] = $this->iCal($event,$user);
$options['mimetype'] = 'text/calendar; charset=utf-8'; $options['mimetype'] = 'text/calendar; charset=utf-8';
header('Content-Encoding: identity'); header('Content-Encoding: identity');
header('ETag: '.$this->get_etag($event)); header('ETag: '.$this->get_etag($event));
@ -403,13 +404,23 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
* Taking into account virtual an real exceptions for recuring events * Taking into account virtual an real exceptions for recuring events
* *
* @param array $event * @param array $event
* @param int $user=null account_id of calendar to display
* @return string * @return string
*/ */
private function iCal(array $event) private function iCal(array $event,$user=null)
{ {
static $handler = null; static $handler = null;
if (is_null($handler)) $handler = $this->_get_handler(); if (is_null($handler)) $handler = $this->_get_handler();
if (!$user) $user = $GLOBALS['egw_info']['user']['account_id'];
// only return alarms in own calendar, not other users calendars
if ($user != $GLOBALS['egw_info']['user']['account_id'])
{
//error_log(__METHOD__.'('.array2string($event).", $user) clearing alarms");
$event['alarm'] = array();
}
$events = array($event); $events = array($event);
// for recuring events we have to add the exceptions // for recuring events we have to add the exceptions
@ -551,8 +562,18 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
} }
else else
{ {
// let lightning think the event is added $retval = '204 No Content';
$retval = '201 Created';
// lightning will pop up the alarm, as long as the Sequence (etag) does NOT change
// --> update the etag alone, if user has no edit rights
if ($this->agent == 'lightning' && !$this->check_access(EGW_ACL_EDIT, $oldEvent) &&
isset($oldEvent['participants'][$GLOBALS['egw_info']['user']['account_id']]))
{
// just update etag in database
$GLOBALS['egw']->db->update($this->bo->so->cal_table,'cal_etag=cal_etag+1',array(
'cal_id' => $eventId,
),__LINE__,__FILE__,'calendar');
}
} }
} }
else else

View File

@ -276,7 +276,7 @@ class calendar_ical extends calendar_boupdate
} }
continue; continue;
} }
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
@ -568,7 +568,7 @@ class calendar_ical extends calendar_boupdate
'CUTYPE' => 'INDIVIDUAL', 'CUTYPE' => 'INDIVIDUAL',
//'RSVP' => 'FALSE', //'RSVP' => 'FALSE',
); );
if (!empty($organizerCN)) $options['CN'] = $organizerCN; if (!empty($organizerCN)) $options['CN'] = $organizerCN;
if (!empty($organizerEMail)) $options['EMAIL'] = $organizerEMail; if (!empty($organizerEMail)) $options['EMAIL'] = $organizerEMail;
if (!empty($event['owner'])) $options['X-EGROUPWARE-UID'] = $event['owner']; if (!empty($event['owner'])) $options['X-EGROUPWARE-UID'] = $event['owner'];
$attributes['ATTENDEE'][] = $organizerURL; $attributes['ATTENDEE'][] = $organizerURL;
@ -631,7 +631,7 @@ class calendar_ical extends calendar_boupdate
$length = ($event['end'] - $event['start']) / 2; $length = ($event['end'] - $event['start']) / 2;
$rrule['UNTIL']->modify($length . ' second'); $rrule['UNTIL']->modify($length . ' second');
} }
if (!$tzid || $version != '1.0') if (!$tzid || $version != '1.0')
{ {
if (!isset(self::$tz_cache['UTC'])) if (!isset(self::$tz_cache['UTC']))
@ -645,7 +645,7 @@ class calendar_ical extends calendar_boupdate
if ($version == '1.0') if ($version == '1.0')
{ {
if ($event['recur_enddate'] && $tzid) if ($event['recur_enddate'] && $tzid)
{ {
$rrule['UNTIL'] = self::getDateTime($rrule['UNTIL'],$tzid); $rrule['UNTIL'] = self::getDateTime($rrule['UNTIL'],$tzid);
} }
$attributes['RRULE'] = $rrule['FREQ'].' '.$rrule['UNTIL']; $attributes['RRULE'] = $rrule['FREQ'].' '.$rrule['UNTIL'];
@ -690,7 +690,7 @@ class calendar_ical extends calendar_boupdate
$event['recur_exception'] = $days; $event['recur_exception'] = $days;
if ($version != '1.0') $parameters['EXDATE']['VALUE'] = 'DATE'; if ($version != '1.0') $parameters['EXDATE']['VALUE'] = 'DATE';
} }
if ($this->productManufacturer == 'groupdav' && if ($this->productManufacturer == 'groupdav' &&
($this->productName == 'iphone' || $this->productName == 'davkit')) ($this->productName == 'iphone' || $this->productName == 'davkit'))
{ {
foreach ($event['recur_exception'] as $exdate) foreach ($event['recur_exception'] as $exdate)
@ -917,14 +917,14 @@ class calendar_ical extends calendar_boupdate
// RFC requires DESCRIPTION for DISPLAY // RFC requires DESCRIPTION for DISPLAY
if (!$event['title'] && !$description) continue; if (!$event['title'] && !$description) continue;
if ($this->productName == 'lightning') if ($this->productName == 'lightning')
{ {
// return only future alarms to lightning // return only future alarms to lightning
if (($nextOccurence = $this->read($event['id'], $this->now_su + $alarmData['offset'], false, 'server'))) if (($nextOccurence = $this->read($event['id'], $this->now_su + $alarmData['offset'], false, 'server')))
{ {
$alarmData['time'] = $nextOccurence['start'] - $alarmData['offset']; $alarmData['time'] = $nextOccurence['start'] - $alarmData['offset'];
$alarmData['offset'] = false; $alarmData['offset'] = false;
} }
else else
{ {
@ -932,12 +932,12 @@ class calendar_ical extends calendar_boupdate
} }
} }
if (!empty($event['whole_day']) && $alarmData['offset']) if (!empty($event['whole_day']) && $alarmData['offset'])
{ {
$alarmData['time'] = $event['start'] - $alarmData['offset']; $alarmData['time'] = $event['start'] - $alarmData['offset'];
$alarmData['offset'] = false; $alarmData['offset'] = false;
} }
$valarm = Horde_iCalendar::newComponent('VALARM',$vevent); $valarm = Horde_iCalendar::newComponent('VALARM',$vevent);
if ($alarmData['offset']) if ($alarmData['offset'])
{ {
@ -1118,7 +1118,7 @@ class calendar_ical extends calendar_boupdate
{ {
calendar_groupdav::fix_series($events); calendar_groupdav::fix_series($events);
} }
if ($this->tzid) if ($this->tzid)
{ {
$tzid = $this->tzid; $tzid = $this->tzid;
@ -1127,9 +1127,9 @@ class calendar_ical extends calendar_boupdate
{ {
$tzid = egw_time::$user_timezone->getName(); $tzid = egw_time::$user_timezone->getName();
} }
date_default_timezone_set($tzid); date_default_timezone_set($tzid);
foreach ($events as $event) foreach ($events as $event)
{ {
if (!is_array($event)) continue; // the iterator may return false if (!is_array($event)) continue; // the iterator may return false
@ -1149,7 +1149,7 @@ class calendar_ical extends calendar_boupdate
} }
$updated_id = false; $updated_id = false;
if ($replace) if ($replace)
{ {
$event_info['type'] = $event['recur_type'] == MCAL_RECUR_NONE ? $event_info['type'] = $event['recur_type'] == MCAL_RECUR_NONE ?
@ -1423,6 +1423,12 @@ class calendar_ical extends calendar_boupdate
$alarm['owner'] = $this->user; $alarm['owner'] = $this->user;
$alarm['all'] = false; $alarm['all'] = false;
// if no edit rights, allow participants to set alarms directly (like status)
if ($event_info['stored_event'] && !$event_info['acl_edit'])
{
$this->save_alarm($event_info['stored_event']['id'], $alarm);
}
if (is_array($event_info['stored_event']) if (is_array($event_info['stored_event'])
&& count($event_info['stored_event']['alarm']) > 0) && count($event_info['stored_event']['alarm']) > 0)
{ {
@ -1458,7 +1464,7 @@ class calendar_ical extends calendar_boupdate
} }
} }
} }
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . '(' error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . '('
@ -1508,7 +1514,7 @@ class calendar_ical extends calendar_boupdate
if (is_array($days)) if (is_array($days))
{ {
$recur_exceptions = array(); $recur_exceptions = array();
foreach ($event['recur_exception'] as $recur_exception) foreach ($event['recur_exception'] as $recur_exception)
{ {
if (isset($days[$recur_exception])) if (isset($days[$recur_exception]))
@ -1581,7 +1587,7 @@ class calendar_ical extends calendar_boupdate
array_unique(array_merge($event_info['master_event']['recur_exception'], array_unique(array_merge($event_info['master_event']['recur_exception'],
array($event['recurrence']))); array($event['recurrence'])));
} }
$event['reference'] = $event_info['master_event']['id']; $event['reference'] = $event_info['master_event']['id'];
$event['category'] = $event_info['master_event']['category']; $event['category'] = $event_info['master_event']['category'];
$event['owner'] = $event_info['master_event']['owner']; $event['owner'] = $event_info['master_event']['owner'];
@ -2128,7 +2134,7 @@ class calendar_ical extends calendar_boupdate
{ {
return new egw_ical_iterator($_vcalData,'VCALENDAR',$charset,array($this,'_ical2egw_callback'),array($this->tzid,$principalURL)); return new egw_ical_iterator($_vcalData,'VCALENDAR',$charset,array($this,'_ical2egw_callback'),array($this->tzid,$principalURL));
} }
if ($this->tzid) if ($this->tzid)
{ {
$tzid = $this->tzid; $tzid = $this->tzid;
@ -2137,9 +2143,9 @@ class calendar_ical extends calendar_boupdate
{ {
$tzid = egw_time::$user_timezone->getName(); $tzid = egw_time::$user_timezone->getName();
} }
date_default_timezone_set($tzid); date_default_timezone_set($tzid);
$events = array(); $events = array();
$vcal = new Horde_iCalendar; $vcal = new Horde_iCalendar;
if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset)) if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset))
@ -2177,7 +2183,7 @@ class calendar_ical extends calendar_boupdate
function _ical2egw_callback(Horde_iCalendar $component, $tzid, $principalURL='') function _ical2egw_callback(Horde_iCalendar $component, $tzid, $principalURL='')
{ {
//unset($component->_container); _debug_array($component); //unset($component->_container); _debug_array($component);
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.'() '.get_class($component)." found\n",3,$this->logfile); error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.'() '.get_class($component)." found\n",3,$this->logfile);
@ -2238,7 +2244,7 @@ class calendar_ical extends calendar_boupdate
} }
return false; return false;
} }
/* /*
$mozillaACK = $component->getAttribute('X-MOZ-LASTACK'); $mozillaACK = $component->getAttribute('X-MOZ-LASTACK');
if ($this->productName == 'lightning' && !is_a($mozillaACK, 'PEAR_Error')) if ($this->productName == 'lightning' && !is_a($mozillaACK, 'PEAR_Error'))

View File

@ -1090,18 +1090,18 @@ ORDER BY cal_user_type, cal_usre_id
$alarm['time'] = $event['cal_start'] - $alarm['offset']; $alarm['time'] = $event['cal_start'] - $alarm['offset'];
} }
$start = (int)time() + $alarm['offset']; if ($alarm['time'] < time())
if ($alarm['time'] < $start)
{ {
//pgoerzen: don't add an alarm in the past //pgoerzen: don't add an alarm in the past
if ($event['recur_type'] == MCAL_RECUR_NONE) continue; if ($event['recur_type'] == MCAL_RECUR_NONE) continue;
$start = (int)time() + $alarm['offset'];
$event['start'] = $event['cal_start']; $event['start'] = $event['cal_start'];
$event['end'] = $event['cal_end']; $event['end'] = $event['cal_end'];
$event['tzid'] = $event['cal_tzid']; $event['tzid'] = $event['cal_tzid'];
$rrule = calendar_rrule::event2rrule($event, false); $rrule = calendar_rrule::event2rrule($event, false);
foreach ($rrule as $time) foreach ($rrule as $time)
{ {
if ($start< ($ts = egw_time::to($time,'server'))) break; if ($start < ($ts = egw_time::to($time,'server'))) break;
$ts = 0; $ts = 0;
} }
if (!$ts) continue; if (!$ts) continue;

View File

@ -331,9 +331,10 @@ class infolog_groupdav extends groupdav_handler
* *
* @param array &$options * @param array &$options
* @param int $id * @param int $id
* @param int $user=null account_id
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found') * @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
*/ */
function get(&$options,$id) function get(&$options,$id,$user=null)
{ {
if (!is_array($task = $this->_common_get_put_delete('GET',$options,$id))) if (!is_array($task = $this->_common_get_put_delete('GET',$options,$id)))
{ {

View File

@ -400,7 +400,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
$account_lid = $GLOBALS['egw_info']['user']['account_lid']; $account_lid = $GLOBALS['egw_info']['user']['account_lid'];
} }
if (strlen($user_preferences['calendar']['display_color']) == 9 && if (strlen($user_preferences['calendar']['display_color']) == 9 &&
$user_preferences['calendar']['display_color'][0] == '#') $user_preferences['calendar']['display_color'][0] == '#')
{ {
@ -410,7 +410,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
$display_color = '#0040A0FF'; $display_color = '#0040A0FF';
} }
$account = $this->accounts->read($account_lid); $account = $this->accounts->read($account_lid);
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'], $displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8'); $GLOBALS['egw']->translation->charset(),'utf-8');
@ -548,7 +548,7 @@ class groupdav extends HTTP_WebDAV_Server
} }
if (($handler = self::app_handler($app))) if (($handler = self::app_handler($app)))
{ {
return $handler->get($options,$id); return $handler->get($options,$id,$user);
} }
error_log(__METHOD__."(".array2string($options).") 501 Not Implemented"); error_log(__METHOD__."(".array2string($options).") 501 Not Implemented");
return '501 Not Implemented'; return '501 Not Implemented';

View File

@ -135,9 +135,10 @@ abstract class groupdav_handler
* *
* @param array &$options * @param array &$options
* @param int $id * @param int $id
* @param int $user=null account_id
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found') * @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
*/ */
abstract function get(&$options,$id); abstract function get(&$options,$id,$user=null);
/** /**
* Handle get request for an applications entry * Handle get request for an applications entry

View File

@ -13,7 +13,7 @@
/** /**
* EGroupware: GroupDAV access: groupdav/caldav/carddav principals handlers * EGroupware: GroupDAV access: groupdav/caldav/carddav principals handlers
* *
* @todo All principal urls should either contain no account_lid (eg. base64 of it) or use urlencode($account_lid) * @todo All principal urls should either contain no account_lid (eg. base64 of it) or use urlencode($account_lid)
*/ */
class groupdav_principals extends groupdav_handler class groupdav_principals extends groupdav_handler
@ -92,7 +92,7 @@ class groupdav_principals extends groupdav_handler
{ {
$displayname = translation::convert($account['account_fullname'], $displayname = translation::convert($account['account_fullname'],
translation::charset(),'utf-8'); translation::charset(),'utf-8');
$props = array( $props = array(
HTTP_WebDAV_Server::mkprop('displayname',$displayname), HTTP_WebDAV_Server::mkprop('displayname',$displayname),
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)), HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)),
@ -105,7 +105,7 @@ class groupdav_principals extends groupdav_handler
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array( HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))), HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
); );
foreach($this->accounts->memberships($account['account_id']) as $gid => $group) foreach($this->accounts->memberships($account['account_id']) as $gid => $group)
{ {
$props[] = HTTP_WebDAV_Server::mkprop('group-membership',$this->base_uri.'/groups/'.$group); $props[] = HTTP_WebDAV_Server::mkprop('group-membership',$this->base_uri.'/groups/'.$group);
@ -440,9 +440,10 @@ class groupdav_principals extends groupdav_handler
* *
* @param array &$options * @param array &$options
* @param int $id * @param int $id
* @param int $user=null account_id
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found') * @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
*/ */
function get(&$options,$id) function get(&$options,$id,$user=null)
{ {
if (!is_array($account = $this->_common_get_put_delete('GET',$options,$id))) if (!is_array($account = $this->_common_get_put_delete('GET',$options,$id)))
{ {
@ -533,7 +534,7 @@ class groupdav_principals extends groupdav_handler
} }
return 'EGw-'.$account['account_id'].':'.md5(serialize($account)). return 'EGw-'.$account['account_id'].':'.md5(serialize($account)).
// as the pricipal of current user is influenced by GroupDAV prefs, we have to include them in the etag // as the pricipal of current user is influenced by GroupDAV prefs, we have to include them in the etag
($account['account_id'] == $GLOBALS['egw_info']['user']['account_id'] ? ($account['account_id'] == $GLOBALS['egw_info']['user']['account_id'] ?
':'.md5(serialize($GLOBALS['egw_info']['user']['preferences']['groupdav'])) : '').'-wGE'; ':'.md5(serialize($GLOBALS['egw_info']['user']['preferences']['groupdav'])) : '').'-wGE';
} }
} }