mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-25 01:13:25 +01:00
* CalDAV/Calendar: storing now all properties send by client and not known to EGroupware and fixed acknowledging and snoozing of alarms
This commit is contained in:
parent
b8192fec8c
commit
6d2ef17b0f
@ -6,7 +6,7 @@
|
||||
* @package calendar
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @author Joerg Lehrke <jlehrke@noc.de>
|
||||
* @copyright (c) 2005-12 by RalfBecker-At-outdoor-training.de
|
||||
* @copyright (c) 2005-15 by RalfBecker-At-outdoor-training.de
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
@ -92,11 +92,12 @@ class calendar_boupdate extends calendar_bo
|
||||
* updates or creates an event, it (optionaly) checks for conflicts and sends the necessary notifications
|
||||
*
|
||||
* @param array &$event event-array, on return some values might be changed due to set defaults
|
||||
* @param boolean $ignore_conflicts=false just ignore conflicts or do a conflict check and return the conflicting events
|
||||
* @param boolean $touch_modified=true NOT USED ANYMORE (was only used in old csv-import), modified&modifier is always updated!
|
||||
* @param boolean $ignore_acl=false should we ignore the acl
|
||||
* @param boolean $updateTS=true update the content history of the event
|
||||
* @param boolean $ignore_conflicts =false just ignore conflicts or do a conflict check and return the conflicting events
|
||||
* @param boolean $touch_modified =true NOT USED ANYMORE (was only used in old csv-import), modified&modifier is always updated!
|
||||
* @param boolean $ignore_acl =false should we ignore the acl
|
||||
* @param boolean $updateTS =true update the content history of the event
|
||||
* @param array &$messages=null messages about because of missing ACL removed participants or categories
|
||||
* @param boolean $skip_notification =false true: send NO notifications, default false = send them
|
||||
* @return mixed on success: int $cal_id > 0, on error false or array with conflicting events (only if $check_conflicts)
|
||||
* Please note: the events are not garantied to be readable by the user (no read grant or private)!
|
||||
*
|
||||
@ -141,8 +142,7 @@ class calendar_boupdate extends calendar_bo
|
||||
// set owner as participant if none is given
|
||||
if (!is_array($event['participants']) || !count($event['participants']))
|
||||
{
|
||||
$status = $event['owner'] == $this->user ? 'A' : 'U';
|
||||
$status = calendar_so::combine_status($status, 1, 'CHAIR');
|
||||
$status = calendar_so::combine_status($event['owner'] == $this->user ? 'A' : 'U', 1, 'CHAIR');
|
||||
$event['participants'] = array($event['owner'] => $status);
|
||||
}
|
||||
}
|
||||
@ -205,6 +205,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
foreach((array)$event['participants'] as $uid => $status)
|
||||
{
|
||||
$q = $r = null;
|
||||
calendar_so::split_status($status,$q,$r);
|
||||
if ($status != 'U')
|
||||
{
|
||||
@ -399,7 +400,7 @@ class calendar_boupdate extends calendar_bo
|
||||
* Remove participants current user has no right to invite
|
||||
*
|
||||
* @param array &$event new event
|
||||
* @param array $old_event=null old event with already invited participants
|
||||
* @param array $old_event =null old event with already invited participants
|
||||
* @return array removed participants because of missing invite grants
|
||||
*/
|
||||
public function remove_no_acl_invite(array &$event,array $old_event=null)
|
||||
@ -413,7 +414,7 @@ class calendar_boupdate extends calendar_bo
|
||||
$old_event = $this->read($event['id']);
|
||||
}
|
||||
$removed = array();
|
||||
foreach((array)$event['participants'] as $uid => $status)
|
||||
foreach(array_keys((array)$event['participants']) as $uid)
|
||||
{
|
||||
if ((is_null($old_event) || !isset($old_event['participants'][$uid])) && !$this->check_acl_invite($uid))
|
||||
{
|
||||
@ -479,7 +480,7 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
}
|
||||
// Find new participants ...
|
||||
foreach((array)$new_event['participants'] as $new_userid => $new_status)
|
||||
foreach(array_keys((array)$new_event['participants']) as $new_userid)
|
||||
{
|
||||
if(!isset($old_event['participants'][$new_userid]))
|
||||
{
|
||||
@ -590,8 +591,8 @@ class calendar_boupdate extends calendar_bo
|
||||
* Check calendar prefs, if a given user (integer account_id) or email (user or externals) should get notified
|
||||
*
|
||||
* @param int|string $user_or_email
|
||||
* @param string $ical_method='REQUEST'
|
||||
* @param string $role='REQ-PARTICIPANT'
|
||||
* @param string $ical_method ='REQUEST'
|
||||
* @param string $role ='REQ-PARTICIPANT'
|
||||
* @return boolean true if user requested to be notified, false if not
|
||||
*/
|
||||
static public function email_update_requested($user_or_email, $ical_method='REQUEST', $role='REQ-PARTICIPANT')
|
||||
@ -710,8 +711,8 @@ class calendar_boupdate extends calendar_bo
|
||||
* @param int $msg_type type of the notification: MSG_ADDED, MSG_MODIFIED, MSG_ACCEPTED, ...
|
||||
* @param array $to_notify numerical user-ids as keys (!) (value is not used)
|
||||
* @param array $old_event Event before the change
|
||||
* @param array $new_event=null Event after the change
|
||||
* @param int $user=0 User who started the notify, default current user
|
||||
* @param array $new_event =null Event after the change
|
||||
* @param int $user =0 User who started the notify, default current user
|
||||
* @return bool true/false
|
||||
*/
|
||||
function send_update($msg_type,$to_notify,$old_event,$new_event=null,$user=0)
|
||||
@ -1004,6 +1005,7 @@ class calendar_boupdate extends calendar_bo
|
||||
|
||||
function get_update_message($event,$added)
|
||||
{
|
||||
$nul = null;
|
||||
$details = $this->_get_event_details($event,$added ? lang('Added') : lang('Modified'),$nul);
|
||||
|
||||
$notify_msg = $this->cal_prefs[$added || empty($this->cal_prefs['notifyModified']) ? 'notifyAdded' : 'notifyModified'];
|
||||
@ -1051,7 +1053,8 @@ class calendar_boupdate extends calendar_bo
|
||||
$alarm['time'] = $this->date2ts($event['start']) - $alarm['offset'];
|
||||
unset($alarm['times']);
|
||||
unset($alarm['next']);
|
||||
$this->save_alarm($alarm['cal_id'],$alarm);
|
||||
//error_log(__METHOD__."() moving alarm to next recurrence ".array2string($alarm));
|
||||
$this->save_alarm($alarm['cal_id'], $alarm, false); // false = do NOT update timestamp, as nothing changed for iCal clients
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
@ -1062,8 +1065,8 @@ class calendar_boupdate extends calendar_bo
|
||||
* This methode converts from user to server time and handles the insertion of users and dates of repeating events
|
||||
*
|
||||
* @param array $event
|
||||
* @param boolean $ignore_acl=false should we ignore the acl
|
||||
* @param boolean $updateTS=true update the content history of the event
|
||||
* @param boolean $ignore_acl =false should we ignore the acl
|
||||
* @param boolean $updateTS =true update the content history of the event
|
||||
* @return int|boolean $cal_id > 0 or false on error (eg. permission denied)
|
||||
*/
|
||||
function save($event,$ignore_acl=false,$updateTS=true)
|
||||
@ -1095,8 +1098,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
if (!empty($event['start']))
|
||||
{
|
||||
$time = new egw_time($event['start'], egw_time::$user_timezone);
|
||||
$time = $this->so->startOfDay($time);
|
||||
$time = $this->so->startOfDay(new egw_time($event['start'], egw_time::$user_timezone));
|
||||
$event['start'] = egw_time::to($time, 'ts');
|
||||
$save_event['start'] = $time;
|
||||
}
|
||||
@ -1109,14 +1111,12 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
if (!empty($event['recurrence']))
|
||||
{
|
||||
$time = new egw_time($event['recurrence'], egw_time::$user_timezone);
|
||||
$time = $this->so->startOfDay($time);
|
||||
$time = $this->so->startOfDay(new egw_time($event['recurrence'], egw_time::$user_timezone));
|
||||
$event['recurrence'] = egw_time::to($time, 'ts');
|
||||
}
|
||||
if (!empty($event['recur_enddate']))
|
||||
{
|
||||
$time = new egw_time($event['recur_enddate'], egw_time::$user_timezone);
|
||||
$time = $this->so->startOfDay($time);
|
||||
$time = $this->so->startOfDay(new egw_time($event['recur_enddate'], egw_time::$user_timezone));
|
||||
$event['recur_enddate'] = egw_time::to($time, 'ts');
|
||||
$time->setUser();
|
||||
$save_event['recur_enddate'] = egw_time::to($time, 'ts');
|
||||
@ -1147,8 +1147,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
if ($event['whole_day'])
|
||||
{
|
||||
$time = new egw_time($date, egw_time::$user_timezone);
|
||||
$time =& $this->so->startOfDay($time);
|
||||
$time = $this->so->startOfDay(new egw_time($date, egw_time::$user_timezone));
|
||||
$date = egw_time::to($time, 'ts');
|
||||
}
|
||||
else
|
||||
@ -1161,11 +1160,8 @@ class calendar_boupdate extends calendar_bo
|
||||
// same with the alarms
|
||||
if (isset($event['alarm']) && is_array($event['alarm']) && isset($event['start']))
|
||||
{
|
||||
foreach($event['alarm'] as $id => $alarm)
|
||||
foreach($event['alarm'] as $id => &$alarm)
|
||||
{
|
||||
// recalculate alarms to also cope with moved events (beside server time adjustment)
|
||||
$event['alarm'][$id]['time'] = $event['start'] - $alarm['offset'];
|
||||
|
||||
// remove alarms belonging to not longer existing or rejected participants
|
||||
if ($alarm['owner'] && isset($event['participants']))
|
||||
{
|
||||
@ -1182,18 +1178,19 @@ class calendar_boupdate extends calendar_bo
|
||||
// update all existing alarm times, in case alarm got moved and alarms are not include in $event
|
||||
if ($old_event && is_array($old_event['alarm']) && isset($event['start']))
|
||||
{
|
||||
foreach($old_event['alarm'] as $id => $alarm)
|
||||
foreach($old_event['alarm'] as $id => &$alarm)
|
||||
{
|
||||
if (!isset($event['alarm'][$id]))
|
||||
{
|
||||
$alarm['time'] = $event['start'] - $alarm['offset'];
|
||||
// remove (not store) alarms belonging to not longer existing or rejected participants
|
||||
if ($alarm['time'] < time()) calendar_so::shift_alarm($event, $alarm);
|
||||
// remove (not store) alarms belonging to not longer existing or rejected participants
|
||||
$status = isset($event['participants']) ? $event['participants'][$alarm['owner']] :
|
||||
$old_event['participants'][$alarm['owner']];
|
||||
if (!$alarm['owner'] || isset($status) && calendar_so::split_status($status) !== 'R')
|
||||
{
|
||||
$this->so->save_alarm($event['id'], $alarm, $this->now);
|
||||
error_log(__LINE__.': '.__METHOD__."() so->save_alarm($event[id], ".array2string($alarm).", $this->now)");
|
||||
$this->so->save_alarm($event['id'], $alarm);
|
||||
error_log(__LINE__.': '.__METHOD__."() so->save_alarm($event[id], ".array2string($alarm).")");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1229,6 +1226,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
{
|
||||
$user_type = $user_id = null;
|
||||
calendar_so::split_user($uid, $user_type, $user_id);
|
||||
if ($user_type == 'c' && (!$old_event || !isset($old_event['participants'][$uid])))
|
||||
{
|
||||
@ -1332,7 +1330,7 @@ class calendar_boupdate extends calendar_bo
|
||||
/**
|
||||
* Get rights for a given category id
|
||||
*
|
||||
* @param int $cat_id=null null to return array with all cats
|
||||
* @param int $cat_id =null null to return array with all cats
|
||||
* @return array with account_id => right pairs
|
||||
*/
|
||||
public static function get_cat_rights($cat_id=null)
|
||||
@ -1384,7 +1382,7 @@ class calendar_boupdate extends calendar_bo
|
||||
*/
|
||||
public static function has_cat_right($right,$cat_id,$user)
|
||||
{
|
||||
static $cache;
|
||||
static $cache=null;
|
||||
|
||||
if (!isset($cache[$cat_id]))
|
||||
{
|
||||
@ -1392,7 +1390,7 @@ class calendar_boupdate extends calendar_bo
|
||||
$cat_rights = self::get_cat_rights($cat_id);
|
||||
if (!is_null($cat_rights))
|
||||
{
|
||||
static $memberships;
|
||||
static $memberships=null;
|
||||
if (is_null($memberships))
|
||||
{
|
||||
$memberships = $GLOBALS['egw']->accounts->memberships($user,true);
|
||||
@ -1432,6 +1430,7 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$quantity = $role = null;
|
||||
calendar_so::split_status($status, $quantity, $role);
|
||||
if ($this->log)
|
||||
{
|
||||
@ -1486,7 +1485,7 @@ class calendar_boupdate extends calendar_bo
|
||||
*
|
||||
* @param array $new_event event-array with the new 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
|
||||
* @param boolean $skip_notification Do not send notifications. Parameter passed on to set_status().
|
||||
*/
|
||||
function update_status($new_event, $old_event , $recur_date=0, $skip_notification=false)
|
||||
@ -1517,10 +1516,10 @@ class calendar_boupdate extends calendar_bo
|
||||
* deletes an event
|
||||
*
|
||||
* @param int $cal_id id of the event to delete
|
||||
* @param int $recur_date=0 if a single event from a series should be deleted, its date
|
||||
* @param boolean $ignore_acl=false true for no ACL check, default do ACL check
|
||||
* @param boolean $skip_notification=false
|
||||
* @param boolean $delete_exceptions=true true: delete, false: keep exceptions (with new UID)
|
||||
* @param int $recur_date =0 if a single event from a series should be deleted, its date
|
||||
* @param boolean $ignore_acl =false true for no ACL check, default do ACL check
|
||||
* @param boolean $skip_notification =false
|
||||
* @param boolean $delete_exceptions =true true: delete, false: keep exceptions (with new UID)
|
||||
* @param int &$exceptions_kept=null on return number of kept exceptions
|
||||
* @return boolean true on success, false on error (usually permission denied)
|
||||
*/
|
||||
@ -1594,6 +1593,7 @@ class calendar_boupdate extends calendar_bo
|
||||
// check if deleted recurrance has alarms (because it's the next recurrance) --> move it to next recurrance
|
||||
if ($event['alarm'])
|
||||
{
|
||||
$next_recurrance = null;
|
||||
foreach($event['alarm'] as &$alarm)
|
||||
{
|
||||
if (($alarm['time'] == $recur_date) || ($alarm['time']+$alarm['offset'] == $recur_date))
|
||||
@ -1604,19 +1604,10 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
$checkdate = $recur_date;
|
||||
//if ($alarm['time']+$alarm['offset'] == $recur_date) $checkdate = $recur_date + $alarm['offset'];
|
||||
if ($e = $this->read($cal_id,$checkdate+1))
|
||||
if (($e = $this->read($cal_id,$checkdate+1)))
|
||||
{
|
||||
$next_recurrance = $this->date2ts($e['start']);
|
||||
}
|
||||
/*
|
||||
foreach(calendar_rrule::event2rrule($event, true) as $time)
|
||||
{
|
||||
$time->setUser(); // $time is in timezone of event, convert it to usertime used here
|
||||
$next_recurrance = $this->date2ts($time);
|
||||
if ($next_recurrance > $checkdate) break;
|
||||
}
|
||||
*/
|
||||
//error_log(__METHOD__.__LINE__." $next_recurrance > $checkdate");
|
||||
}
|
||||
$alarm['time'] = $this->date2ts($next_recurrance, true); // user to server-time
|
||||
$alarm['cal_id'] = $cal_id;
|
||||
@ -1644,6 +1635,11 @@ class calendar_boupdate extends calendar_bo
|
||||
/**
|
||||
* helper for send_update and get_update_message
|
||||
* @internal
|
||||
* @param array $event
|
||||
* @param string $action
|
||||
* @param array $event_arr
|
||||
* @param array $disinvited
|
||||
* @return array
|
||||
*/
|
||||
function _get_event_details($event,$action,&$event_arr,$disinvited=array())
|
||||
{
|
||||
@ -1787,8 +1783,8 @@ class calendar_boupdate extends calendar_bo
|
||||
*
|
||||
* @param array $event2save event-data before calling save
|
||||
* @param array $event_saved event-data read back from the DB
|
||||
* @param array $old_event=null event-data in the DB before calling save
|
||||
* @param string $type='update'
|
||||
* @param array $old_event =null event-data in the DB before calling save
|
||||
* @param string $type ='update'
|
||||
*/
|
||||
function log2file($event2save,$event_saved,$old_event=null,$type='update')
|
||||
{
|
||||
@ -1820,9 +1816,10 @@ class calendar_boupdate extends calendar_bo
|
||||
*
|
||||
* @param int $cal_id Id of the calendar-entry
|
||||
* @param array $alarm array with fields: text, owner, enabled, ..
|
||||
* @param boolean $update_modified =true call update modified, default true
|
||||
* @return string id of the alarm, or false on error (eg. no perms)
|
||||
*/
|
||||
function save_alarm($cal_id,$alarm)
|
||||
function save_alarm($cal_id, $alarm, $update_modified=true)
|
||||
{
|
||||
if (!$cal_id || !$this->check_perms(EGW_ACL_EDIT,$alarm['all'] ? $cal_id : 0,!$alarm['all'] ? $alarm['owner'] : 0))
|
||||
{
|
||||
@ -1833,7 +1830,7 @@ class calendar_boupdate extends calendar_bo
|
||||
|
||||
$GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'modify', $this->now);
|
||||
|
||||
return $this->so->save_alarm($cal_id,$alarm);
|
||||
return $this->so->save_alarm($cal_id, $alarm, $update_modified);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1861,7 +1858,7 @@ class calendar_boupdate extends calendar_bo
|
||||
* currently used for ical/sif import
|
||||
*
|
||||
* @param array $catname_list names of the categories which should be found or added
|
||||
* @param int|array $old_event=null match against existing event and expand the returned category ids
|
||||
* @param int|array $old_event =null match against existing event and expand the returned category ids
|
||||
* by the ones the user normally does not see due to category permissions - used to preserve categories
|
||||
* @return array category ids (found, added and preserved categories)
|
||||
*/
|
||||
@ -2191,7 +2188,7 @@ class calendar_boupdate extends calendar_bo
|
||||
if ($filter == 'master')
|
||||
{
|
||||
// We found the master
|
||||
$matchingEvents = array($egwEvent['id']);;
|
||||
$matchingEvents = array($egwEvent['id']);
|
||||
break;
|
||||
}
|
||||
if ($filter == 'exact')
|
||||
@ -2446,14 +2443,14 @@ class calendar_boupdate extends calendar_bo
|
||||
}
|
||||
|
||||
// append pseudos as last entries
|
||||
$matchingEvents = array_merge($matchingEvents, $pseudos);
|
||||
$matches = array_merge($matchingEvents, $pseudos);
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
|
||||
'[MATCHES]:' . array2string($matchingEvents)."\n",3,$this->logfile);
|
||||
'[MATCHES]:' . array2string($matches)."\n",3,$this->logfile);
|
||||
}
|
||||
return $matchingEvents;
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2493,8 +2490,8 @@ class calendar_boupdate extends calendar_bo
|
||||
{
|
||||
$type = 'SERIES-PSEUDO-EXCEPTION';
|
||||
$wasPseudo = true;
|
||||
list($eventID, $recur_date) = explode(':', $eventID);
|
||||
$recur_date = $this->date2usertime($recur_date);
|
||||
list($eventID, $date) = explode(':', $eventID);
|
||||
$recur_date = $this->date2usertime($date);
|
||||
$stored_event = $this->read($eventID, $recur_date, false, 'server');
|
||||
$master_event = $this->read($eventID, 0, false, 'server');
|
||||
$recurrence_event = $stored_event;
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @package calendar
|
||||
* @subpackage groupdav
|
||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-13 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @copyright (c) 2007-15 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
@ -135,7 +135,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
* @param array &$options
|
||||
* @param array &$files
|
||||
* @param int $user account_id
|
||||
* @param string $id=''
|
||||
* @param string $id =''
|
||||
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
|
||||
*/
|
||||
function propfind($path,&$options,&$files,$user,$id='')
|
||||
@ -157,6 +157,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
'daywise' => false,
|
||||
'date_format' => 'server',
|
||||
'no_total' => true, // we need no total number of rows (saves extra query)
|
||||
'cfs' => array(), // return custom-fields, as we use them to store X- attributes
|
||||
);
|
||||
foreach(array(
|
||||
'start' => $GLOBALS['egw_info']['user']['preferences']['groupdav']['calendar-past-limit'],
|
||||
@ -252,7 +253,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $filter
|
||||
* @param array|boolean $start=false false=return all or array(start,num)
|
||||
* @param array|boolean $start =false false=return all or array(start,num)
|
||||
* @return array with "files" array with values for keys path and props
|
||||
*/
|
||||
function propfind_callback($path,array $filter,$start=false)
|
||||
@ -289,6 +290,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
$files[] = array('path' => $path.urldecode($this->get_path($event)));
|
||||
continue;
|
||||
}
|
||||
$schedule_tag = null;
|
||||
$etag = $this->get_etag($event, $schedule_tag);
|
||||
|
||||
//header('X-EGROUPWARE-EVENT-'.$event['id'].': '.$event['title'].': '.date('Y-m-d H:i:s',$event['start']).' - '.date('Y-m-d H:i:s',$event['end']));
|
||||
@ -555,7 +557,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
*
|
||||
* @param array &$options
|
||||
* @param int $id
|
||||
* @param int $user=null account_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')
|
||||
*/
|
||||
function get(&$options,$id,$user=null)
|
||||
@ -568,6 +570,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
$options['data'] = $this->iCal($event, $user, strpos($options['path'], '/inbox/') !== false ? 'REQUEST' : null);
|
||||
$options['mimetype'] = 'text/calendar; charset=utf-8';
|
||||
header('Content-Encoding: identity');
|
||||
$schedule_tag = null;
|
||||
header('ETag: "'.$this->get_etag($event, $schedule_tag).'"');
|
||||
if ($this->use_schedule_tag)
|
||||
{
|
||||
@ -582,9 +585,9 @@ class calendar_groupdav extends groupdav_handler
|
||||
* Taking into account virtual an real exceptions for recuring events
|
||||
*
|
||||
* @param array $event
|
||||
* @param int $user=null account_id of calendar to display
|
||||
* @param string $method=null eg. 'PUBLISH' for inbox, nothing anywhere else
|
||||
* @param boolean|array $expand=false true or array with values for 'start', 'end' to expand recurrences
|
||||
* @param int $user =null account_id of calendar to display
|
||||
* @param string $method =null eg. 'PUBLISH' for inbox, nothing anywhere else
|
||||
* @param boolean|array $expand =false true or array with values for 'start', 'end' to expand recurrences
|
||||
* @return string
|
||||
*/
|
||||
private function iCal(array $event,$user=null, $method=null, $expand=false)
|
||||
@ -626,9 +629,9 @@ class calendar_groupdav extends groupdav_handler
|
||||
* Maybe that should be part of calendar_bo
|
||||
*
|
||||
* @param string $uid UID
|
||||
* @param calendar_bo $bo=null calendar_bo object to reuse for search call
|
||||
* @param boolean|array $expand=false true or array with values for 'start', 'end' to expand recurrences
|
||||
* @param int $user=null account_id of calendar to display, to remove master, if current user does not participate in
|
||||
* @param calendar_bo $bo =null calendar_bo object to reuse for search call
|
||||
* @param boolean|array $expand =false true or array with values for 'start', 'end' to expand recurrences
|
||||
* @param int $user =null account_id of calendar to display, to remove master, if current user does not participate in
|
||||
* @return array
|
||||
*/
|
||||
private static function &get_series($uid,calendar_bo $bo=null, $expand=false, $user=null)
|
||||
@ -640,6 +643,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
'filter' => 'owner', // return all possible entries
|
||||
'daywise' => false,
|
||||
'date_format' => 'server',
|
||||
'cfs' => array(), // read cfs as we use them to store X- attributes
|
||||
);
|
||||
if (is_array($expand)) $params += $expand;
|
||||
|
||||
@ -690,6 +694,13 @@ class calendar_groupdav extends groupdav_handler
|
||||
}
|
||||
continue; // nothing to change
|
||||
}
|
||||
// alarms are reported on recurrences --> move them to master
|
||||
foreach($recurrence['alarm'] as $alarm)
|
||||
{
|
||||
$master['alarm'][] = $alarm;
|
||||
}
|
||||
$recurrence['alarm'] = array();
|
||||
|
||||
// now we need to check if this recurrence is an exception
|
||||
if (!$expand && $master['participants'] == $recurrence['participants'])
|
||||
{
|
||||
@ -731,8 +742,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
*
|
||||
* @param array &$options
|
||||
* @param int $id
|
||||
* @param int $user=null account_id of owner, default null
|
||||
* @param string $prefix=null user prefix from path (eg. /ralf from /ralf/addressbook)
|
||||
* @param int $user =null account_id of owner, default null
|
||||
* @param string $prefix =null user prefix from path (eg. /ralf from /ralf/addressbook)
|
||||
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
|
||||
*/
|
||||
function put(&$options,$id,$user=null,$prefix=null)
|
||||
@ -811,6 +822,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
{
|
||||
$schedule_tag_match = $_SERVER['HTTP_IF_SCHEDULE_TAG_MATCH'];
|
||||
if ($schedule_tag_match[0] == '"') $schedule_tag_match = substr($schedule_tag_match, 1, -1);
|
||||
$schedule_tag = null;
|
||||
$this->get_etag($oldEvent, $schedule_tag);
|
||||
|
||||
if ($schedule_tag_match !== $schedule_tag)
|
||||
@ -835,6 +847,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
if (($events = $handler->icaltoegw($vCalendar)))
|
||||
{
|
||||
$modified = 0;
|
||||
$series = null;
|
||||
foreach($events as $n => $event)
|
||||
{
|
||||
// for recurrances of event series, we need to read correct recurrence (or if series master is no first event)
|
||||
@ -883,7 +896,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
// import alarms, if given and changed
|
||||
if ((array)$event['alarm'] !== (array)$oldEvent['alarm'])
|
||||
{
|
||||
$modified += $this->sync_alarms($oldEvent['id'], (array)$event['alarm'], (array)$oldEvent['alarm'], $user, $event['start']);
|
||||
$event['id'] = $oldEvent['id'];
|
||||
$modified += $handler->sync_alarms($event, (array)$oldEvent['alarm'], $user);
|
||||
}
|
||||
}
|
||||
if (!$modified) // NO modififictions, or none we understood --> log it and return Ok: "204 No Content"
|
||||
@ -951,59 +965,12 @@ class calendar_groupdav extends groupdav_handler
|
||||
return $retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync alarms of current user: add alarms added on client and remove the ones removed
|
||||
*
|
||||
* @param int $cal_id of event to set alarms
|
||||
* @param array $alarms
|
||||
* @param array $old_alarms
|
||||
* @param int $user account_id of user to create alarm for
|
||||
* @param int $start start-time of event
|
||||
* @ToDo store other alarm properties like: ACTION, DESCRIPTION, X-WR-ALARMUID
|
||||
* @return int number of modified alarms
|
||||
*/
|
||||
private function sync_alarms($cal_id, array $alarms, array $old_alarms, $user, $start)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."($cal_id, ".array2string($alarms).', '.array2string($old_alarms).", $user, $start)");
|
||||
$modified = 0;
|
||||
foreach($alarms as $alarm)
|
||||
{
|
||||
if ($alarm['owner'] != $this->user) continue; // only import alarms of current user
|
||||
|
||||
// check if alarm is already stored or from other users
|
||||
foreach($old_alarms as $id => $old_alarm)
|
||||
{
|
||||
if ($old_alarm['owner'] != $user || $alarm['offset'] == $old_alarm['offset'])
|
||||
{
|
||||
unset($old_alarms[$id]); // remove alarms of other user, or already existing alarms
|
||||
}
|
||||
}
|
||||
// alarm not found --> add it
|
||||
if ($alarm['offset'] != $old_alarm['offset'] || $old_alarm['owner'] != $user)
|
||||
{
|
||||
$alarm['owner'] = $user;
|
||||
$alarm['time'] = $start - $alarm['offset'];
|
||||
if ($this->debug) error_log(__METHOD__."() adding new alarm from client ".array2string($alarm));
|
||||
$this->bo->save_alarm($cal_id, $alarm);
|
||||
++$modified;
|
||||
}
|
||||
}
|
||||
// remove all old alarms left from current user
|
||||
foreach($old_alarms as $id => $old_alarm)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."() deleting alarm '$id' deleted on client ".array2string($old_alarm));
|
||||
$this->bo->delete_alarm($id);
|
||||
++$modified;
|
||||
}
|
||||
return $modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle post request for a schedule entry
|
||||
*
|
||||
* @param array &$options
|
||||
* @param int $id
|
||||
* @param int $user=null account_id of owner, default null
|
||||
* @param int $user =null account_id of owner, default null
|
||||
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
|
||||
*/
|
||||
function post(&$options,$id,$user=null)
|
||||
@ -1057,8 +1024,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
$handler = $this->_get_handler();
|
||||
if (($foundEvents = $handler->search($vCalendar, null, false, $charset)))
|
||||
{
|
||||
$eventId = array_shift($foundEvents);
|
||||
list($eventId) = explode(':', $eventId);
|
||||
$id = array_shift($foundEvents);
|
||||
list($eventId) = explode(':', $id);
|
||||
|
||||
if (!($cal_id = $handler->importVCal($vCalendar, $eventId, null,
|
||||
false, 0, $this->groupdav->current_user_principal, $user, $charset)))
|
||||
@ -1082,6 +1049,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
*/
|
||||
protected function outbox_freebusy_request($ical, $charset, $user, array &$options)
|
||||
{
|
||||
unset($options); // not used, but required by function signature
|
||||
|
||||
$vcal = new Horde_Icalendar();
|
||||
if (!$vcal->parsevCalendar($ical, 'VCALENDAR', $charset))
|
||||
{
|
||||
@ -1108,7 +1077,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
$organizer = $component->getAttribute('ORGANIZER');
|
||||
$attendees = (array)$component->getAttribute('ATTENDEE');
|
||||
// X-CALENDARSERVER-MASK-UID specifies to exclude given event from busy-time
|
||||
$mask_uid = $component->getAttribute('X-CALENDARSERVER-MASK-UID');
|
||||
$mask_uid = $component->getAttributeDefault('X-CALENDARSERVER-MASK-UID', null);
|
||||
|
||||
header('Content-type: text/xml; charset=UTF-8');
|
||||
|
||||
@ -1118,7 +1087,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
$xml->startDocument('1.0', 'UTF-8');
|
||||
$xml->startElementNs('C', 'schedule-response', groupdav::CALDAV);
|
||||
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
foreach(array_keys($event['participants']) as $uid)
|
||||
{
|
||||
$xml->startElementNs('C', 'response', null);
|
||||
|
||||
@ -1155,6 +1124,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
*/
|
||||
function free_busy_report($path,$options,$user)
|
||||
{
|
||||
unset($path); // unused, but required by function signature
|
||||
if (!$this->bo->check_perms(EGW_ACL_FREEBUSY, 0, $user))
|
||||
{
|
||||
return '403 Forbidden';
|
||||
@ -1180,7 +1150,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
* Reimplemented to add read-free-busy and schedule-deliver privilege
|
||||
*
|
||||
* @param string $path path of collection
|
||||
* @param int $user=null owner of the collection, default current user
|
||||
* @param int $user =null owner of the collection, default current user
|
||||
* @return array with privileges
|
||||
*/
|
||||
public function current_user_privileges($path, $user=null)
|
||||
@ -1306,7 +1276,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
// check if user is a participant or one of the groups he is a member of --> reject the meeting request
|
||||
$ret = '403 Forbidden';
|
||||
$memberships = $GLOBALS['egw']->accounts->memberships($this->bo->user, true);
|
||||
foreach($event['participants'] as $uid => $status)
|
||||
foreach(array_keys($event['participants']) as $uid)
|
||||
{
|
||||
if ($this->bo->user == $uid || in_array($uid, $memberships))
|
||||
{
|
||||
@ -1391,7 +1361,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
/**
|
||||
* Get the etag for an entry
|
||||
*
|
||||
* @param array|int $event array with event or cal_id
|
||||
* @param array|int $entry array with event or cal_id
|
||||
* @param string $schedule_tag =null on return schedule-tag
|
||||
* @return string|boolean string with etag or false
|
||||
*/
|
||||
function get_etag($entry, &$schedule_tag=null)
|
||||
@ -1410,10 +1381,11 @@ class calendar_groupdav extends groupdav_handler
|
||||
* @param int|array $entry id or array of new created entry
|
||||
* @param string $path
|
||||
* @param int|string $retval
|
||||
* @param boolean $path_attr_is_name=true true: path_attr is ca(l|rd)dav_name, false: id (GroupDAV needs Location header)
|
||||
* @param boolean $path_attr_is_name =true true: path_attr is ca(l|rd)dav_name, false: id (GroupDAV needs Location header)
|
||||
*/
|
||||
function put_response_headers($entry, $path, $retval, $path_attr_is_name=true)
|
||||
{
|
||||
$schedule_tag = null;
|
||||
$etag = $this->get_etag($entry, $schedule_tag);
|
||||
|
||||
if ($this->use_schedule_tag)
|
||||
@ -1443,15 +1415,16 @@ class calendar_groupdav extends groupdav_handler
|
||||
/**
|
||||
* Add extra properties for calendar collections
|
||||
*
|
||||
* @param array $props=array() regular props by the groupdav handler
|
||||
* @param array $props regular props by the groupdav handler
|
||||
* @param string $displayname
|
||||
* @param string $base_uri=null base url of handler
|
||||
* @param int $user=null account_id of owner of current collection
|
||||
* @param string $path=null path of the collection
|
||||
* @param string $base_uri =null base url of handler
|
||||
* @param int $user =null account_id of owner of current collection
|
||||
* @param string $path =null path of the collection
|
||||
* @return array
|
||||
*/
|
||||
public function extra_properties(array $props=array(), $displayname, $base_uri=null, $user=null, $path=null)
|
||||
public function extra_properties(array $props, $displayname, $base_uri=null, $user=null, $path=null)
|
||||
{
|
||||
unset($base_uri); // unused, but required by function signature
|
||||
if (!isset($props['calendar-description']))
|
||||
{
|
||||
// default calendar description: can be overwritten via PROPPATCH, in which case it's already set
|
||||
@ -1523,8 +1496,8 @@ class calendar_groupdav extends groupdav_handler
|
||||
function get_shared()
|
||||
{
|
||||
$shared = array();
|
||||
$calendar_home_set = $GLOBALS['egw_info']['user']['preferences']['groupdav']['calendar-home-set'];
|
||||
$calendar_home_set = $calendar_home_set ? explode(',',$calendar_home_set) : array();
|
||||
$pref = $GLOBALS['egw_info']['user']['preferences']['groupdav']['calendar-home-set'];
|
||||
$calendar_home_set = $pref ? explode(',', $pref) : array();
|
||||
// replace symbolic id's with real nummeric id's
|
||||
foreach(array(
|
||||
'G' => $GLOBALS['egw_info']['user']['account_primary_group'],
|
||||
|
@ -251,9 +251,9 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
if ($this->read($event, $recurrence, true, 'server'))
|
||||
{
|
||||
if ($this->bo->check_perms(EGW_ACL_FREEBUSY, $event, 0, 'server'))
|
||||
if ($this->check_perms(EGW_ACL_FREEBUSY, $event, 0, 'server'))
|
||||
{
|
||||
$this->bo->clear_private_infos($event, array($this->user, $event['owner']));
|
||||
$this->clear_private_infos($event, array($this->user, $event['owner']));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -631,7 +631,10 @@ class calendar_ical extends calendar_boupdate
|
||||
else // $version == '2.0'
|
||||
{
|
||||
$attributes['RRULE'] = '';
|
||||
$parameters['RRULE'] = $rrule;
|
||||
foreach($rrule as $n => $v)
|
||||
{
|
||||
$attributes['RRULE'] .= ($attributes['RRULE']?';':'').$n.'='.$v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -833,6 +836,25 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
}
|
||||
|
||||
// for CalDAV add all X-Properties previously parsed
|
||||
if ($this->productManufacturer == 'groupdav' || $this->productManufacturer == 'file')
|
||||
{
|
||||
foreach($event as $name => $value)
|
||||
{
|
||||
if (substr($name, 0, 2) == '##')
|
||||
{
|
||||
if (($attr = json_decode($value, true)) && is_array($attr))
|
||||
{
|
||||
$vevent->setAttribute(substr($name, 2), $attr['value'], $attr['params'], true, $attr['values']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$vevent->setAttribute(substr($name, 2), $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->productManufacturer == 'nokia')
|
||||
{
|
||||
if ($event['special'] == '1')
|
||||
@ -862,7 +884,7 @@ class calendar_ical extends calendar_boupdate
|
||||
foreach ((array)$event['alarm'] as $alarmData)
|
||||
{
|
||||
// skip over alarms that don't have the minimum required info
|
||||
if (!$alarmData['offset'] && !$alarmData['time']) continue;
|
||||
if (!isset($alarmData['offset']) && !isset($alarmData['time'])) continue;
|
||||
|
||||
// skip alarms not being set for all users and alarms owned by other users
|
||||
if ($alarmData['all'] != true && $alarmData['owner'] != $this->user)
|
||||
@ -899,8 +921,9 @@ class calendar_ical extends calendar_boupdate
|
||||
// VCalendar 2.0 / RFC 2445
|
||||
|
||||
// RFC requires DESCRIPTION for DISPLAY
|
||||
if (!$event['title'] && !$description) continue;
|
||||
if (!$event['title'] && !$description) $description = 'Alarm';
|
||||
|
||||
/* Disabling for now
|
||||
// Lightning infinitly pops up alarms for recuring events, if the only use an offset
|
||||
if ($this->productName == 'lightning' && $event['recur_type'] != MCAL_RECUR_NONE)
|
||||
{
|
||||
@ -914,7 +937,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// for SyncML non-whole-day events always use absolute times
|
||||
// (probably because some devices have no clue about timezones)
|
||||
@ -930,7 +953,7 @@ class calendar_ical extends calendar_boupdate
|
||||
if ($alarmData['offset'] !== false)
|
||||
{
|
||||
$valarm->setAttribute('TRIGGER', -$alarmData['offset'],
|
||||
array('VALUE' => 'DURATION', 'RELATED' => 'START'));
|
||||
array('VALUE' => 'DURATION', 'RELATED' => 'START'));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -938,9 +961,28 @@ class calendar_ical extends calendar_boupdate
|
||||
$value = self::getDateTime($alarmData['time'],$tzid,$params);
|
||||
$valarm->setAttribute('TRIGGER', $value, $params);
|
||||
}
|
||||
|
||||
$valarm->setAttribute('ACTION','DISPLAY');
|
||||
$valarm->setAttribute('DESCRIPTION',$event['title'] ? $event['title'] : $description);
|
||||
if (!empty($alarmData['uid']))
|
||||
{
|
||||
$valarm->setAttribute('UID', $alarmData['uid']);
|
||||
$valarm->setAttribute('X-WR-ALARMUID', $alarmData['uid']);
|
||||
}
|
||||
// set evtl. existing attributes set by iCal clients not used by EGroupware
|
||||
if (isset($alarmData['attrs']))
|
||||
{
|
||||
foreach($alarmData['attrs'] as $attr => $data)
|
||||
{
|
||||
$valarm->setAttribute($attr, $data['value'], $data['params']);
|
||||
}
|
||||
}
|
||||
// set default ACTION and DESCRIPTION, if not set by a client
|
||||
if (!isset($alarmData['attrs']) || !isset($alarmData['attrs']['ACTION']))
|
||||
{
|
||||
$valarm->setAttribute('ACTION','DISPLAY');
|
||||
}
|
||||
if (!isset($alarmData['attrs']) || !isset($alarmData['attrs']['DESCRIPTION']))
|
||||
{
|
||||
$valarm->setAttribute('DESCRIPTION',$event['title'] ? $event['title'] : $description);
|
||||
}
|
||||
$vevent->addComponent($valarm);
|
||||
}
|
||||
}
|
||||
@ -968,6 +1010,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$paramData['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||
}
|
||||
/* disable automatic QP encoding eg. for new-lines as it also encodes non-ascii/utf-8 which TB does NOT decode
|
||||
else
|
||||
{
|
||||
$paramData['CHARSET'] = '';
|
||||
@ -979,7 +1022,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
$paramData['ENCODING'] = '';
|
||||
}
|
||||
}
|
||||
}*/
|
||||
break;
|
||||
case 'funambol':
|
||||
$paramData['ENCODING'] = 'FUNAMBOL-QP';
|
||||
@ -1216,6 +1259,14 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
}
|
||||
}
|
||||
// unset old X-* attributes stored in custom-fields
|
||||
foreach ($event_info['stored_event'] as $key => $value)
|
||||
{
|
||||
if ($key[0] == '#' && $key[1] == '#' && !isset($event[$key]))
|
||||
{
|
||||
$event[$key] = '';
|
||||
}
|
||||
}
|
||||
if ($merge)
|
||||
{
|
||||
if ($this->log)
|
||||
@ -1422,46 +1473,9 @@ class calendar_ical extends calendar_boupdate
|
||||
case 'SERIES-MASTER':
|
||||
case 'SERIES-EXCEPTION':
|
||||
case 'SERIES-EXCEPTION-PROPAGATE':
|
||||
if (count($event['alarm']) > 0)
|
||||
if (isset($event['alarm']))
|
||||
{
|
||||
foreach ($event['alarm'] as $newid => &$alarm)
|
||||
{
|
||||
if (!isset($alarm['offset']) && isset($alarm['time']))
|
||||
{
|
||||
$alarm['offset'] = $event['start'] - $alarm['time'];
|
||||
}
|
||||
elseif (!isset($alarm['time']) && isset($alarm['offset']))
|
||||
{
|
||||
$alarm['time'] = $event['start'] - $alarm['offset'];
|
||||
}
|
||||
$alarm['owner'] = $this->user;
|
||||
$alarm['all'] = false;
|
||||
|
||||
// if no edit rights, allow participants to set alarms directly (like status)
|
||||
if ($event_info['stored_event'] && !$event_info['acl_edit'])
|
||||
{
|
||||
if ($alarm['time'] < time() && !calendar_so::shift_alarm($event, $alarm))
|
||||
{
|
||||
continue; //pgoerzen: don't add an alarm in the past
|
||||
}
|
||||
$this->save_alarm($event_info['stored_event']['id'], $alarm);
|
||||
}
|
||||
|
||||
if (is_array($event_info['stored_event'])
|
||||
&& count($event_info['stored_event']['alarm']) > 0)
|
||||
{
|
||||
foreach ($event_info['stored_event']['alarm'] as $alarm_id => $alarm_data)
|
||||
{
|
||||
if ($alarm['offset'] == $alarm_data['offset'] &&
|
||||
($alarm_data['all'] || $alarm_data['owner'] == $this->user))
|
||||
{
|
||||
unset($event['alarm'][$newid]);
|
||||
unset($event_info['stored_event']['alarm'][$alarm_id]);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->sync_alarms($event, (array)$event_info['stored_event']['alarm'], $this->user);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1469,18 +1483,6 @@ class calendar_ical extends calendar_boupdate
|
||||
// nothing to do here
|
||||
break;
|
||||
}
|
||||
if (is_array($event_info['stored_event'])
|
||||
&& count($event_info['stored_event']['alarm']) > 0)
|
||||
{
|
||||
foreach ($event_info['stored_event']['alarm'] as $alarm_id => $alarm_data)
|
||||
{
|
||||
// only touch own alarms
|
||||
if ($alarm_data['all'] == false && $alarm_data['owner'] == $this->user)
|
||||
{
|
||||
$this->delete_alarm($alarm_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->log)
|
||||
@ -1764,6 +1766,73 @@ class calendar_ical extends calendar_boupdate
|
||||
return $updated_id === 0 ? 0 : $return_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync alarms of current user: add alarms added on client and remove the ones removed
|
||||
*
|
||||
* @param array& $event
|
||||
* @param array $old_alarms
|
||||
* @param int $user account_id of user to create alarm for
|
||||
* @return int number of modified alarms
|
||||
*/
|
||||
public function sync_alarms(array &$event, array $old_alarms, $user)
|
||||
{
|
||||
if ($this->debug) error_log(__METHOD__."(".array2string($event).', old_alarms='.array2string($old_alarms).", $user,)");
|
||||
$modified = 0;
|
||||
foreach($event['alarm'] as &$alarm)
|
||||
{
|
||||
// check if alarm is already stored or from other users
|
||||
foreach($old_alarms as $id => $old_alarm)
|
||||
{
|
||||
// not current users alarm --> ignore
|
||||
if (!$old_alarm['all'] && $old_alarm['owner'] != $user)
|
||||
{
|
||||
unset($old_alarm[$id]);
|
||||
continue;
|
||||
}
|
||||
// alarm found --> stop
|
||||
if (empty($alarm['uid']) && $alarm['offset'] == $old_alarm['offset'] || $alarm['uid'] && $alarm['uid'] == $old_alarm['uid'])
|
||||
{
|
||||
unset($old_alarms[$id]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// alarm not found --> add it
|
||||
if ($alarm['offset'] != $old_alarm['offset'] || $old_alarm['owner'] != $user && !$alarm['all'])
|
||||
{
|
||||
$alarm['owner'] = $user;
|
||||
if (!isset($alarm['time'])) $alarm['time'] = $event['start'] - $alarm['offset'];
|
||||
if ($alarm['time'] < time()) calendar_so::shift_alarm($event, $alarm);
|
||||
if ($this->debug) error_log(__METHOD__."() adding new alarm from client ".array2string($alarm));
|
||||
if ($event['id']) $alarm['id'] = $this->save_alarm($event['id'], $alarm);
|
||||
++$modified;
|
||||
}
|
||||
// existing alarm --> update it
|
||||
elseif ($alarm['offset'] == $old_alarm['offset'] && ($old_alarm['owner'] == $user || $old_alarm['all']))
|
||||
{
|
||||
if (!isset($alarm['time'])) $alarm['time'] = $event['start'] - $alarm['offset'];
|
||||
if ($alarm['time'] < time()) calendar_so::shift_alarm($event, $alarm);
|
||||
$alarm = array_merge($old_alarm, $alarm);
|
||||
if ($this->debug) error_log(__METHOD__."() updating existing alarm from client ".array2string($alarm));
|
||||
$alarm['id'] = $this->save_alarm($event['id'], $alarm);
|
||||
++$modified;
|
||||
}
|
||||
}
|
||||
// remove all old alarms left from current user
|
||||
foreach($old_alarms as $id => $old_alarm)
|
||||
{
|
||||
// not current users alarm --> ignore
|
||||
if (!$old_alarm['all'] && $old_alarm['owner'] != $user)
|
||||
{
|
||||
unset($old_alarm[$id]);
|
||||
continue;
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."() deleting alarm '$id' deleted on client ".array2string($old_alarm));
|
||||
$this->delete_alarm($id);
|
||||
++$modified;
|
||||
}
|
||||
return $modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the value of an attribute by its name
|
||||
*
|
||||
@ -1784,9 +1853,17 @@ class calendar_ical extends calendar_boupdate
|
||||
return false;
|
||||
}
|
||||
|
||||
static function valarm2egw(&$alarms, &$valarm)
|
||||
/**
|
||||
* Parsing a valarm component preserving all attributes unknown to EGw
|
||||
*
|
||||
* @param array &$alarms on return alarms parsed
|
||||
* @param Horde_Icalendar_Valarm $valarm valarm component
|
||||
* @param int $duration in seconds to be able to convert RELATED=END
|
||||
* @return int number of parsed alarms
|
||||
*/
|
||||
static function valarm2egw(&$alarms, Horde_Icalendar_Valarm $valarm, $duration)
|
||||
{
|
||||
$count = 0;
|
||||
$alarm = array();
|
||||
foreach ($valarm->getAllAttributes() as $vattr)
|
||||
{
|
||||
switch ($vattr['name'])
|
||||
@ -1797,40 +1874,47 @@ class calendar_ical extends calendar_boupdate
|
||||
switch ($vtype)
|
||||
{
|
||||
case 'DURATION':
|
||||
if (isset($vattr['params']['RELATED'])
|
||||
&& $vattr['params']['RELATED'] != 'START')
|
||||
if (isset($vattr['params']['RELATED']) && $vattr['params']['RELATED'] == 'END')
|
||||
{
|
||||
$alarm['offset'] = $duration -$vattr['value'];
|
||||
}
|
||||
elseif (isset($vattr['params']['RELATED']) && $vattr['params']['RELATED'] != 'START')
|
||||
{
|
||||
error_log("Unsupported VALARM offset anchor ".$vattr['params']['RELATED']);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$alarms[] = array('offset' => -$vattr['value']);
|
||||
$count++;
|
||||
$alarm['offset'] = -$vattr['value'];
|
||||
}
|
||||
break;
|
||||
case 'DATE-TIME':
|
||||
$alarms[] = array('time' => $vattr['value']);
|
||||
$count++;
|
||||
$alarm['time'] = $vattr['value'];
|
||||
break;
|
||||
default:
|
||||
// we should also do ;RELATED=START|END
|
||||
error_log('VALARM/TRIGGER: unsupported value type:' . $vtype);
|
||||
}
|
||||
break;
|
||||
case 'ACTION':
|
||||
case 'DISPLAY':
|
||||
case 'DESCRIPTION':
|
||||
case 'SUMMARY':
|
||||
case 'ATTACH':
|
||||
case 'ATTENDEE':
|
||||
// we ignore these fields silently
|
||||
break;
|
||||
|
||||
default:
|
||||
error_log('VALARM field ' .$vattr['name'] . ': ' . $vattr['value'] . ' HAS NO CONVERSION YET');
|
||||
case 'UID':
|
||||
case 'X-WR-ALARMUID':
|
||||
$alarm['uid'] = $vattr['value'];
|
||||
break;
|
||||
|
||||
default: // store all other attributes, so we dont loose them
|
||||
$alarm['attrs'][$vattr['name']] = array(
|
||||
'params' => $vattr['params'],
|
||||
'value' => $vattr['value'],
|
||||
);
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
if (isset($alarm['offset']) || isset($alarm['time']))
|
||||
{
|
||||
//error_log(__METHOD__."(..., ".$valarm->exportvCalendar().", $duration) alarm=".array2string($alarm));
|
||||
$alarms[] = $alarm;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function setSupportedFields($_productManufacturer='', $_productName='')
|
||||
@ -2246,7 +2330,7 @@ class calendar_ical extends calendar_boupdate
|
||||
{
|
||||
if (is_a($valarm, 'Horde_Icalendar_Valarm'))
|
||||
{
|
||||
$this->valarm2egw($alarms, $valarm);
|
||||
self::valarm2egw($alarms, $valarm, $event['end'] - $event['start']);
|
||||
}
|
||||
}
|
||||
$event['alarm'] = $alarms;
|
||||
@ -2282,19 +2366,6 @@ class calendar_ical extends calendar_boupdate
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
$mozillaACK = $component->getAttributeDefault('X-MOZ-LASTACK', null);
|
||||
if ($this->productName == 'lightning' && !isset($mozillaACK))
|
||||
{
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.'()' .
|
||||
"X-MOZ-LASTACK found\n",3,$this->logfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!empty($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
|
||||
@ -2908,6 +2979,31 @@ class calendar_ical extends calendar_boupdate
|
||||
case 'STATUS': // currently no EGroupware event column, but needed as Android uses it to delete single recurrences
|
||||
$event['status'] = $attributes['value'];
|
||||
break;
|
||||
|
||||
// ignore all PROPS, we dont want to store like X-properties or unsupported props
|
||||
case 'DTSTAMP':
|
||||
case 'SEQUENCE':
|
||||
case 'CREATED':
|
||||
case 'LAST-MODIFIED':
|
||||
case 'DTSTART':
|
||||
case 'DTEND':
|
||||
case 'DURATION':
|
||||
case 'X-LIC-ERROR': // parse errors from libical, makes no sense to store them
|
||||
break;
|
||||
|
||||
default: // X- attribute or other by EGroupware unsupported property
|
||||
//error_log(__METHOD__."() $attributes[name] = ".array2string($attributes));
|
||||
// for attributes with multiple values in multiple lines, merge the values
|
||||
if (isset($event['##'.$attributes['name']]))
|
||||
{
|
||||
//error_log(__METHOD__."() taskData['##$attribute[name]'] = ".array2string($taskData['##'.$attribute['name']]));
|
||||
$attributes['values'] = array_merge(
|
||||
is_array($event['##'.$attributes['name']]) ? $event['##'.$attributes['name']]['values'] : (array)$event['##'.$attributes['name']],
|
||||
$attributes['values']);
|
||||
}
|
||||
$event['##'.$attributes['name']] = $attributes['params'] || count($attributes['values']) > 1 ?
|
||||
json_encode($attributes) : $attributes['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// check if the entry is a birthday
|
||||
|
@ -1628,8 +1628,10 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
{
|
||||
foreach ($event['alarm'] as $id => $alarm)
|
||||
{
|
||||
if (is_numeric($id)) unset($alarm['id']); // unset the temporary id to add the alarm
|
||||
|
||||
if ($alarm['id'] && strpos($alarm['id'], 'cal:'.$cal_id.':') !== 0)
|
||||
{
|
||||
unset($alarm['id']); // unset the temporary id to add the alarm
|
||||
}
|
||||
if(!isset($alarm['offset']))
|
||||
{
|
||||
$alarm['offset'] = $event['cal_start'] - $alarm['time'];
|
||||
@ -1784,7 +1786,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
/**
|
||||
* Combine status, quantity and role into one value
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $status status letter: U, T, A, R
|
||||
* @param int $quantity =1
|
||||
* @param string $role ='REQ-PARTICIPANT'
|
||||
* @return string
|
||||
@ -2298,6 +2300,8 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
$this->async->cancel_timer($id);
|
||||
}
|
||||
$alarm['cal_id'] = $cal_id; // we need the back-reference
|
||||
// add an alarm uid, if none is given
|
||||
if (empty($alarm['uid']) && class_exists('Horde_Support_Uuid')) $alarm['uid'] = (string)new Horde_Support_Uuid;
|
||||
//error_log(__METHOD__.__LINE__.' Save Alarm for CalID:'.$cal_id.'->'.array2string($alarm).'-->'.$id.'#'.function_backtrace());
|
||||
// allways store job with the alarm owner as job-owner to get eg. the correct from address
|
||||
if (!$this->async->set_timer($alarm['time'],$id,'calendar.calendar_boupdate.send_alarm',$alarm,$alarm['owner']))
|
||||
@ -2855,7 +2859,7 @@ ORDER BY cal_user_type, cal_usre_id
|
||||
/**
|
||||
* Moves a datetime to the beginning of the day within timezone
|
||||
*
|
||||
* @param egw_time &time the datetime entry
|
||||
* @param egw_time $time the datetime entry
|
||||
* @param string tz_id timezone
|
||||
*
|
||||
* @return DateTime
|
||||
|
Loading…
Reference in New Issue
Block a user