mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-13 17:38:28 +01:00
* CalDAV/CardDAV: sync-collection report for all apps allowing a more efficient sync
This commit is contained in:
parent
b3ef030984
commit
52675388a3
@ -149,18 +149,24 @@ class addressbook_groupdav extends groupdav_handler
|
||||
// rfc 6578 sync-collection report: filter for sync-token is already set in _report_filters
|
||||
if ($options['root']['name'] == 'sync-collection')
|
||||
{
|
||||
// query sync-token before result, so changed happening while result get queried are not lost
|
||||
$files['sync-token'] = $this->get_sync_token($path, $user);
|
||||
// callback to query sync-token, after propfind_callbacks / iterator is run and
|
||||
// stored max. modification-time in $this->sync_collection_token
|
||||
$files['sync-token'] = array($this, 'get_sync_collection_token');
|
||||
$files['sync-token-params'] = array($path, $user);
|
||||
|
||||
$this->sync_collection_token = null;
|
||||
}
|
||||
|
||||
if (isset($nresults))
|
||||
{
|
||||
$files['files'] = $this->propfind_callback($path, $filter, array(0, (int)$nresults));
|
||||
|
||||
if ($options['root']['name'] == 'sync-collection' && isset($files['files']['sync-token']))
|
||||
// hack to support limit with sync-collection report: contacts are returned in modified ASC order (oldest first)
|
||||
// if limit is smaller then full result, return modified-1 as sync-token, so client requests next chunk incl. modified
|
||||
// (which might contain further entries with identical modification time)
|
||||
if ($options['root']['name'] == 'sync-collection' && $this->bo->total > $nresults)
|
||||
{
|
||||
$files['sync-token'] = $this->get_sync_token($path, $user, $files['files']['sync-token']);
|
||||
unset($files['files']['sync-token']);
|
||||
--$this->sync_collection_token;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -198,6 +204,9 @@ class addressbook_groupdav extends groupdav_handler
|
||||
{
|
||||
$order = 'egw_addressbook.contact_id';
|
||||
}
|
||||
// detect sync-collection report
|
||||
$sync_collection_report = isset($filter[0]) && strpos($filter[0], 'contact_modified>') === 0;
|
||||
|
||||
$files = array();
|
||||
// we query etag and modified, as LDAP does not have the strong sql etag
|
||||
$cols = array('id','uid','etag','modified','n_fn');
|
||||
@ -209,7 +218,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
foreach($contacts as &$contact)
|
||||
{
|
||||
// sync-collection report: deleted entry need to be reported without properties
|
||||
if ($contact['tid'] == addressbook_bo::DELETED_TYPE && array_key_exists('tid', $filter) && !isset($filter['tid']))
|
||||
if ($contact['tid'] == addressbook_bo::DELETED_TYPE)
|
||||
{
|
||||
$files[] = array('path' => $path.urldecode($this->get_path($contact)));
|
||||
continue;
|
||||
@ -227,14 +236,11 @@ class addressbook_groupdav extends groupdav_handler
|
||||
}
|
||||
$files[] = $this->add_resource($path, $contact, $props);
|
||||
}
|
||||
}
|
||||
// hack to support limit with sync-collection report: contacts are returned in modified ASC order (oldest first)
|
||||
// if limit is smaller then full result, return modified-1 as sync-token, so client requests next chunk incl. modified
|
||||
// (which might contain further entries with identical modification time)
|
||||
if ($contact['tid'] == addressbook_bo::DELETED_TYPE && array_key_exists('tid', $filter) &&
|
||||
$start[0] == 0 && $start[1] != groupdav_propfind_iterator::CHUNK_SIZE && $this->bo->total > $start[1])
|
||||
{
|
||||
$files['sync-token'] = $contact['modified']-1;
|
||||
// sync-collection report --> return modified of last contact as sync-token
|
||||
if ($sync_collection_report)
|
||||
{
|
||||
$this->sync_collection_token = $contact['modified'];
|
||||
}
|
||||
}
|
||||
// add groups after contacts, but only if enabled and NOT for '/addressbook/' (!isset($filter['owner'])
|
||||
if (in_array('D',$this->home_set_pref) && (!$start || count($contacts) < $start[1]) && isset($filter['owner']))
|
||||
@ -243,7 +249,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
'list_owner' => isset($filter['owner'])?$filter['owner']:array_keys($this->bo->grants)
|
||||
);
|
||||
// add sync-token to support sync-collection report
|
||||
if (isset($filter[0]) && strpos($filter[0], 'contact_modified>') === 0)
|
||||
if ($sync_collection_report)
|
||||
{
|
||||
list(,$sync_token) = explode('>', $filter[0]);
|
||||
$where[] = 'list_modified>FROM_UNIXTIME('.(int)$sync_token.')';
|
||||
@ -277,6 +283,11 @@ class addressbook_groupdav extends groupdav_handler
|
||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
|
||||
}
|
||||
$files[] = $this->add_resource($path, $list, $props);
|
||||
|
||||
if ($sync_collection_report && $this->sync_collection_token < $list['list_modified'])
|
||||
{
|
||||
$this->sync_collection_token = $list['list_modified'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -705,9 +716,9 @@ class addressbook_groupdav extends groupdav_handler
|
||||
public function getctag($path,$user)
|
||||
{
|
||||
static $ctags = array(); // a little per request caching, in case ctag and sync-token is both requested
|
||||
|
||||
if (isset($ctags[$path])) return $ctags[$path];
|
||||
|
||||
$user_in = $user;
|
||||
// not showing addressbook of a single user?
|
||||
if (is_null($user) || $user === '' || $path == '/addressbook/') $user = null;
|
||||
|
||||
@ -722,7 +733,7 @@ class addressbook_groupdav extends groupdav_handler
|
||||
{
|
||||
$lists_ctag = $this->bo->lists_ctag($user);
|
||||
}
|
||||
//error_log(__METHOD__."('$path', ".array2string($user).") ctag=$ctag=".date('Y-m-d H:i:s',$ctag).", lists_ctag=".($lists_ctag ? $lists_ctag.'='.date('Y-m-d H:i:s',$lists_ctag) : '').' returning '.max($ctag,$lists_ctag));
|
||||
//error_log(__METHOD__."('$path', ".array2string($user_in).") --> user=".array2string($user)." --> ctag=$ctag=".date('Y-m-d H:i:s',$ctag).", lists_ctag=".($lists_ctag ? $lists_ctag.'='.date('Y-m-d H:i:s',$lists_ctag) : '').' returning '.max($ctag,$lists_ctag));
|
||||
return $ctags[$path] = max($ctag,$lists_ctag);
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,7 @@ class calendar_bo
|
||||
* end date enddate of the search/list, defaults to start + one day
|
||||
* users int|array integer user-id or array of user-id's to use, defaults to the current user
|
||||
* cat_id int|array category-id or array of cat-id's (incl. all sub-categories), default 0 = all
|
||||
* filter string all (not rejected), accepted, unknown, tentative, rejected or hideprivate
|
||||
* filter string all (not rejected), accepted, unknown, tentative, rejected, hideprivate or everything (incl. rejected, deleted)
|
||||
* query string pattern so search for, if unset or empty all matching entries are returned (no search)
|
||||
* Please Note: a search never returns repeating events more then once AND does not honor start+end date !!!
|
||||
* daywise boolean on True it returns an array with YYYYMMDD strings as keys and an array with events
|
||||
@ -469,7 +469,7 @@ class calendar_bo
|
||||
// socal::search() returns rejected group-invitations, as only the user not also the group is rejected
|
||||
// as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed
|
||||
$users_in = (array)$params_in['users'];
|
||||
$remove_rejected_by_user = !in_array($filter,array('all','rejected')) &&
|
||||
$remove_rejected_by_user = !in_array($filter,array('all','rejected','everything')) &&
|
||||
count($users_in) == 1 && $users_in[0] > 0 ? $users_in[0] : null;
|
||||
//error_log(__METHOD__.'('.array2string($params_in).", $sql_filter) params[users]=".array2string($params['users']).' --> remove_rejected_by_user='.array2string($remove_rejected_by_user));
|
||||
|
||||
|
@ -181,7 +181,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
}
|
||||
|
||||
// process REPORT filters or multiget href's
|
||||
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$filter,$id))
|
||||
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options, $filter, $id, $nresults))
|
||||
{
|
||||
// return empty collection, as iCal under iOS 5 had problems with returning "404 Not found" status
|
||||
// when trying to request not supported components, eg. VTODO on a calendar collection
|
||||
@ -194,9 +194,34 @@ class calendar_groupdav extends groupdav_handler
|
||||
error_log(__METHOD__."($path,,,$user,$id) filter=".array2string($filter));
|
||||
}
|
||||
|
||||
// return iterator, calling ourself to return result in chunks
|
||||
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
|
||||
// rfc 6578 sync-collection report: filter for sync-token is already set in _report_filters
|
||||
if ($options['root']['name'] == 'sync-collection')
|
||||
{
|
||||
// callback to query sync-token, after propfind_callbacks / iterator is run and
|
||||
// stored max. modification-time in $this->sync_collection_token
|
||||
$files['sync-token'] = array($this, 'get_sync_collection_token');
|
||||
$files['sync-token-params'] = array($path, $user);
|
||||
|
||||
$this->sync_collection_token = null;
|
||||
}
|
||||
|
||||
if (isset($nresults))
|
||||
{
|
||||
$files['files'] = $this->propfind_callback($path, $filter, array(0, (int)$nresults));
|
||||
|
||||
// hack to support limit with sync-collection report: events are returned in modified ASC order (oldest first)
|
||||
// if limit is smaller then full result, return modified-1 as sync-token, so client requests next chunk incl. modified
|
||||
// (which might contain further entries with identical modification time)
|
||||
if ($options['root']['name'] == 'sync-collection' && $this->bo->total > $nresults)
|
||||
{
|
||||
--$this->sync_collection_token;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// return iterator, calling ourself to return result in chunks
|
||||
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -225,8 +250,16 @@ class calendar_groupdav extends groupdav_handler
|
||||
$events =& $this->bo->search($filter);
|
||||
if ($events)
|
||||
{
|
||||
$sync_collection = strpos($filter['query'][0],'cal_modified>') === 0 && $filter['filter'] == 'everything';
|
||||
|
||||
foreach($events as $event)
|
||||
{
|
||||
// sync-collection report: deleted entries need to be reported without properties, same for rejected or deleted invitations
|
||||
if ($sync_collection && ($event['deleted'] || in_array($event['participants'][$filter['users']][0], array('R','X'))))
|
||||
{
|
||||
$files[] = array('path' => $path.urldecode($this->get_path($event)));
|
||||
continue;
|
||||
}
|
||||
$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']));
|
||||
$props = array(
|
||||
@ -261,6 +294,11 @@ class calendar_groupdav extends groupdav_handler
|
||||
}*/
|
||||
$files[] = $this->add_resource($path, $event, $props);
|
||||
}
|
||||
// sync-collection report --> return modified of last contact as sync-token
|
||||
if ($sync_collection_report)
|
||||
{
|
||||
$this->sync_collection_token = $event['modified'];
|
||||
}
|
||||
}
|
||||
if ($this->debug)
|
||||
{
|
||||
@ -276,9 +314,10 @@ class calendar_groupdav extends groupdav_handler
|
||||
* @param array $options
|
||||
* @param array &$cal_filters
|
||||
* @param string $id
|
||||
* @return boolean true if filter could be processed, false for requesting not here supported VTODO items
|
||||
* @param int &$nresult on return limit for number or results or unchanged/null
|
||||
* @return boolean true if filter could be processed
|
||||
*/
|
||||
function _report_filters($options,&$cal_filters,$id)
|
||||
function _report_filters($options, &$cal_filters, $id, &$nresults)
|
||||
{
|
||||
if ($options['filters'])
|
||||
{
|
||||
@ -348,6 +387,49 @@ class calendar_groupdav extends groupdav_handler
|
||||
}
|
||||
}
|
||||
|
||||
// parse limit from $options['other']
|
||||
/* Example limit
|
||||
<B:limit>
|
||||
<B:nresults>10</B:nresults>
|
||||
</B:limit>
|
||||
*/
|
||||
foreach((array)$options['other'] as $option)
|
||||
{
|
||||
switch($option['name'])
|
||||
{
|
||||
case 'nresults':
|
||||
$nresults = (int)$option['data'];
|
||||
//error_log(__METHOD__."(...) options[other]=".array2string($options['other'])." --> nresults=$nresults");
|
||||
break;
|
||||
case 'limit':
|
||||
break;
|
||||
case 'href':
|
||||
break; // from addressbook-multiget, handled below
|
||||
// rfc 6578 sync-report
|
||||
case 'sync-token':
|
||||
if (!empty($option['data']))
|
||||
{
|
||||
$parts = explode('/', $option['data']);
|
||||
$sync_token = array_pop($parts);
|
||||
$cal_filters['query'][] = 'cal_modified>'.(int)$sync_token;
|
||||
$cal_filters['filter'] = 'everything'; // to return deleted entries too
|
||||
$cal_filters['order'] = 'cal_modified ASC'; // return oldest modifications first
|
||||
// no standard time-range!
|
||||
unset($cal_filters['start']);
|
||||
unset($cal_filters['end']);
|
||||
}
|
||||
break;
|
||||
case 'sync-level':
|
||||
if ($option['data'] != '1')
|
||||
{
|
||||
$this->groupdav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other']));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->groupdav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other']));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// multiget or propfind on a given id
|
||||
//error_log(__FILE__ . __METHOD__ . "multiget of propfind:");
|
||||
if ($options['root']['name'] == 'calendar-multiget' || $id)
|
||||
@ -1215,6 +1297,7 @@ class calendar_groupdav extends groupdav_handler
|
||||
}
|
||||
$props['supported-calendar-component-set'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,
|
||||
'supported-calendar-component-set',$supported_components);
|
||||
// supported reports
|
||||
$props['supported-report-set'] = array(
|
||||
'calendar-query' => HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
@ -1225,6 +1308,10 @@ class calendar_groupdav extends groupdav_handler
|
||||
'free-busy-query' => HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'free-busy-query',''))))),
|
||||
// rfc 6578 sync-collection report
|
||||
'sync-collection' => HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
HTTP_WebDAV_Server::mkprop('sync-collection',''))))),
|
||||
);
|
||||
$props['supported-calendar-data'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-data',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data', array('content-type' => 'text/calendar', 'version'=> '2.0')),
|
||||
|
@ -431,6 +431,8 @@ class calendar_ical extends calendar_boupdate
|
||||
|
||||
if (!($info = $this->resource_info($uid))) continue;
|
||||
|
||||
if ($status == 'X') continue; // dont include deleted participants
|
||||
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
|
||||
|
@ -350,7 +350,7 @@ class calendar_so
|
||||
* @param int $end enddate of the search/list (servertime)
|
||||
* @param int|array $users user-id or array of user-id's, !$users means all entries regardless of users
|
||||
* @param int|array $cat_id=0 mixed category-id or array of cat-id's (incl. all sub-categories), default 0 = all
|
||||
* @param string $filter='all' string filter-name: all (not rejected), accepted, unknown, tentative, rejected or hideprivate (handled elsewhere!)
|
||||
* @param string $filter='all' string filter-name: all (not rejected), accepted, unknown, tentative, rejected or everything (incl. rejected, deleted)
|
||||
* @param int|boolean $offset=False offset for a limited query or False (default)
|
||||
* @param int $num_rows=0 number of rows to return if offset set, default 0 = use default in user prefs
|
||||
* @param array $params=array()
|
||||
@ -458,12 +458,14 @@ class calendar_so
|
||||
// this is only used, when we cannot use UNIONS
|
||||
if (!$useUnionQuery) $where[] = '('.implode(' OR ',$to_or).')';
|
||||
|
||||
if($filter != 'deleted')
|
||||
if($filter != 'deleted' && $filter != 'everything')
|
||||
{
|
||||
$where[] = 'cal_deleted IS NULL';
|
||||
}
|
||||
switch($filter)
|
||||
{
|
||||
case 'everything': // no filter at all
|
||||
break;
|
||||
case 'showonlypublic':
|
||||
$where['cal_public'] = 1;
|
||||
$where[] = "$this->user_table.cal_status NOT IN ('R','X')"; break;
|
||||
@ -516,7 +518,7 @@ class calendar_so
|
||||
|
||||
if (!preg_match('/^[a-z_ ,c]+$/i',$params['order'])) $params['order'] = 'cal_start'; // gard against SQL injection
|
||||
|
||||
if ($remove_rejected_by_user)
|
||||
if ($remove_rejected_by_user && $filter != 'everything')
|
||||
{
|
||||
$rejected_by_user_join = "LEFT JOIN $this->user_table rejected_by_user".
|
||||
" ON $this->cal_table.cal_id=rejected_by_user.cal_id".
|
||||
@ -674,7 +676,8 @@ class calendar_so
|
||||
// now ready all users with the given cal_id AND (cal_recur_date=0 or the fitting recur-date)
|
||||
// This will always read the first entry of each recuring event too, we eliminate it later
|
||||
$recur_dates[] = 0;
|
||||
$utcal_id_view = " (SELECT * FROM ".$this->user_table." WHERE cal_id IN (".implode(',',$ids).") AND cal_status!='X') utcalid ";
|
||||
$utcal_id_view = " (SELECT * FROM ".$this->user_table." WHERE cal_id IN (".implode(',',$ids).")".
|
||||
($filter != 'everything' ? " AND cal_status!='X'" : '').") utcalid ";
|
||||
//$utrecurdate_view = " (select * from ".$this->user_table." where cal_recur_date in (".implode(',',array_unique($recur_dates)).")) utrecurdates ";
|
||||
foreach($this->db->select($utcal_id_view,'*',array(
|
||||
//'cal_id' => array_unique($ids),
|
||||
|
@ -182,19 +182,17 @@ class infolog_groupdav extends groupdav_handler
|
||||
// rfc 6578 sync-collection report: filter for sync-token is already set in _report_filters
|
||||
if ($options['root']['name'] == 'sync-collection')
|
||||
{
|
||||
// query sync-token before result, so changed happening while result get queried are not lost
|
||||
$files['sync-token'] = $this->get_sync_token($path, $user);
|
||||
// callback to query sync-token, after propfind_callbacks / iterator is run and
|
||||
// stored max. modification-time in $this->sync_collection_token
|
||||
$files['sync-token'] = array($this, 'get_sync_collection_token');
|
||||
$files['sync-token-params'] = array($path, $user);
|
||||
|
||||
$this->sync_collection_token = null;
|
||||
}
|
||||
|
||||
if (isset($nresults))
|
||||
{
|
||||
$files['files'] = $this->propfind_callback($path, $filter, array(0, (int)$nresults));
|
||||
|
||||
if ($options['root']['name'] == 'sync-collection' && isset($files['files']['sync-token']))
|
||||
{
|
||||
$files['sync-token'] = $this->get_sync_token($path, $user, $files['files']['sync-token']);
|
||||
unset($files['files']['sync-token']);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -232,7 +230,6 @@ class infolog_groupdav extends groupdav_handler
|
||||
if ($matches[2]) $sort = $matches[2];
|
||||
unset($filter['order']);
|
||||
}
|
||||
|
||||
$query = array(
|
||||
'order' => $order,
|
||||
'sort' => $sort,
|
||||
@ -265,7 +262,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
// sync-collection report: deleted entry need to be reported without properties
|
||||
if ($task['info_status'] == 'deleted' && strpos($task_filter, '+deleted') !== false)
|
||||
if ($task['info_status'] == 'deleted')
|
||||
{
|
||||
$files[] = array('path' => $path.urldecode($this->get_path($task)));
|
||||
continue;
|
||||
@ -284,13 +281,19 @@ class infolog_groupdav extends groupdav_handler
|
||||
$files[] = $this->add_resource($path, $task, $props);
|
||||
}
|
||||
}
|
||||
// hack to support limit with sync-collection report: tasks are returned in modified ASC order (oldest first)
|
||||
// if limit is smaller then full result, return modified-1 as sync-token, so client requests next chunk incl. modified
|
||||
// (which might contain further entries with identical modification time)
|
||||
if (strpos($task_filter, '+deleted') !== false &&
|
||||
$start[0] == 0 && $start[1] != groupdav_propfind_iterator::CHUNK_SIZE && $query['total'] > $start[1])
|
||||
// sync-collection report --> return modified of last contact as sync-token
|
||||
$sync_collection_report = strpos($task_filter, '+deleted') !== false;
|
||||
if ($sync_collection_report)
|
||||
{
|
||||
$files['sync-token'] = $task['info_datemodified']-1;
|
||||
$this->sync_collection_token = $info['date_modified'];
|
||||
|
||||
// hack to support limit with sync-collection report: tasks are returned in modified ASC order (oldest first)
|
||||
// if limit is smaller then full result, return modified-1 as sync-token, so client requests next chunk incl. modified
|
||||
// (which might contain further entries with identical modification time)
|
||||
if ($start[0] == 0 && $start[1] != groupdav_propfind_iterator::CHUNK_SIZE && $query['total'] > $start[1])
|
||||
{
|
||||
--$this->sync_collection_token;
|
||||
}
|
||||
}
|
||||
if ($this->debug) error_log(__METHOD__."($path) took ".(microtime(true) - $starttime).' to return '.count($files).' items');
|
||||
return $files;
|
||||
@ -739,7 +742,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))))),
|
||||
'calendar-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'calendar-multiget',''))))),
|
||||
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget',''))))),
|
||||
// rfc 6578 sync-collection report
|
||||
'sync-collection' => HTTP_WebDAV_Server::mkprop('supported-report',array(
|
||||
HTTP_WebDAV_Server::mkprop('report',array(
|
||||
|
@ -16,6 +16,8 @@
|
||||
*
|
||||
* Permanent error_log() calls should use $this->groupdav->log($str) instead, to be send to PHP error_log()
|
||||
* and our request-log (prefixed with "### " after request and response, like exceptions).
|
||||
*
|
||||
* @ToDo: If precondition for PUT, see https://tools.ietf.org/html/rfc6578#section-5
|
||||
*/
|
||||
abstract class groupdav_handler
|
||||
{
|
||||
@ -359,8 +361,10 @@ abstract class groupdav_handler
|
||||
'davkit' => 'davkit', // Apple iCal 10.6
|
||||
'coredav' => 'coredav', // Apple iCal 10.7
|
||||
'calendarstore' => 'calendarstore', // Apple iCal 5.0.1 under OS X 10.7.2
|
||||
'calendaragent/' => 'calendaragent', // Apple iCal OS X 10.8*: Mac OS X/10.8.2 (12C54) CalendarAgent/55
|
||||
'dataaccess' => 'dataaccess', // Apple addressbook iPhone
|
||||
'cfnetwork' => 'cfnetwork', // Apple Addressbook 10.6/7
|
||||
'addressbook/' => 'cfnetwork', // Apple Addressbook OS X 10.8*: Mac OS X/10.8.2 (12C54) AddressBook/1167
|
||||
'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net
|
||||
'zideone' => 'zideone', // zideone outlook plugin
|
||||
'lightning' => 'lightning', // Lighting (incl. SOGo connector for addressbook)
|
||||
@ -580,6 +584,25 @@ abstract class groupdav_handler
|
||||
return $full_uri ? $uri : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* sync-token to be filled by propfind_callback and returned by get_sync_token method
|
||||
*/
|
||||
protected $sync_collection_token;
|
||||
|
||||
/**
|
||||
* Query sync-token from a just run sync-collection report
|
||||
*
|
||||
* Modified time is taken from value filled by propfind_callback in sync_collection_token.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $user parameter necessary to call getctag, if no $token specified
|
||||
* @return string
|
||||
*/
|
||||
public function get_sync_collection_token($path, $user=null)
|
||||
{
|
||||
return $this->get_sync_token($path, $user, $this->sync_collection_token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query sync-token
|
||||
*
|
||||
@ -588,19 +611,24 @@ abstract class groupdav_handler
|
||||
*
|
||||
* Therefor we are never returning current time, but 1sec less!
|
||||
*
|
||||
* Modified time is either taken from value filled by propfind_callback in $this->sync_token or
|
||||
* by call to getctag();
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $user
|
||||
* @param int $modified=null default getctag
|
||||
* @param int $user parameter necessary to call getctag, if no $token specified
|
||||
* @param int $token=null modification time, default call getctag($path, $user) to fetch it
|
||||
* @return string
|
||||
*/
|
||||
public function get_sync_token($path, $user, $modified=null)
|
||||
public function get_sync_token($path, $user, $token=null)
|
||||
{
|
||||
if (!isset($modified)) $modified = $this->getctag($path, $user);
|
||||
if (!isset($token)) $token = $this->getctag($path, $user);
|
||||
|
||||
// never return current time, as more modifications might happen --> decrement it by 1sec
|
||||
if ($modified == time()) --$modified;
|
||||
|
||||
return $this->base_uri().$path.$modified;
|
||||
// never return current time, as more modifications might happen due to second granularity --> return 1sec less
|
||||
if ($token >= (int)$GLOBALS['egw_info']['flags']['page_start_time'])
|
||||
{
|
||||
$token = (int)$GLOBALS['egw_info']['flags']['page_start_time'] - 1;
|
||||
}
|
||||
return $this->base_uri().$path.$token;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user