mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-11 08:28:43 +01:00
- implemented principal-property-search report required for WebDAV ACL and used by Lightning to search for calendar-home-set
- had to implement a workaround for Lightning, as it wrongly interprets principal-property-search for calendar-home-set in the principal-collection-set matching our *DAV root returning all principals, as all have a matching calendar-home-set, as NOT supporting CalDAV scheduling --> search only current user's principal, when Lightning searches for calendar-home-set - OPTIONS / return now calendar-auto-scheduling too, as Lightning only searches there, to check if server supports CalDAV scheduling - fixed outbox freebusy request to cope with no X-CALENDARSERVER-MASK-UID and a single attendee
This commit is contained in:
parent
53c78cd9e2
commit
3f830b2bff
@ -713,7 +713,7 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
}
|
}
|
||||||
//print_r($event);
|
//print_r($event);
|
||||||
$organizer = $component->getAttribute('ORGANIZER');
|
$organizer = $component->getAttribute('ORGANIZER');
|
||||||
$attendees = $component->getAttribute('ATTENDEE');
|
$attendees = (array)$component->getAttribute('ATTENDEE');
|
||||||
// X-CALENDARSERVER-MASK-UID specifies to exclude given event from busy-time
|
// X-CALENDARSERVER-MASK-UID specifies to exclude given event from busy-time
|
||||||
$mask_uid = $component->getAttribute('X-CALENDARSERVER-MASK-UID');
|
$mask_uid = $component->getAttribute('X-CALENDARSERVER-MASK-UID');
|
||||||
|
|
||||||
@ -735,11 +735,12 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
if (is_numeric($uid))
|
if (is_numeric($uid))
|
||||||
{
|
{
|
||||||
$xml->writeElementNs('C', 'request-status', null, '2.0;Success');
|
$xml->writeElementNs('C', 'request-status', null, '2.0;Success');
|
||||||
$xml->writeElementNs('C', 'calendar-data', null, str_replace("\r", '', // CalDAV rfc example has no encoded "\r"
|
$xml->writeElementNs('C', 'calendar-data', null,
|
||||||
$handler->freebusy($uid, $event['end'], true, 'utf-8', $event['start'], 'REPLY', array(
|
$handler->freebusy($uid, $event['end'], true, 'utf-8', $event['start'], 'REPLY', array(
|
||||||
'UID' => $event['uid'],
|
'UID' => $event['uid'],
|
||||||
'ORGANIZER' => $organizer,
|
'ORGANIZER' => $organizer,
|
||||||
'ATTENDEE' => $attendee,
|
'ATTENDEE' => $attendee,
|
||||||
|
)+(empty($mask_uid) || !is_string($mask_uid) ? array() : array(
|
||||||
'X-CALENDARSERVER-MASK-UID' => $mask_uid,
|
'X-CALENDARSERVER-MASK-UID' => $mask_uid,
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
|
@ -295,13 +295,14 @@ class groupdav extends HTTP_WebDAV_Server
|
|||||||
$dav[] = 'access-control';
|
$dav[] = 'access-control';
|
||||||
$dav[] = 'addressbook'; // CardDAV uses "addressbook" NOT "addressbook-access"
|
$dav[] = 'addressbook'; // CardDAV uses "addressbook" NOT "addressbook-access"
|
||||||
break;
|
break;
|
||||||
default:
|
default: // used eg. for root, and needs all above settings, as some clients only use these!
|
||||||
if (!in_array(2,$dav)) $dav[] = 2;
|
if (!in_array(2,$dav)) $dav[] = 2;
|
||||||
$dav[] = 'access-control';
|
$dav[] = 'access-control';
|
||||||
$dav[] = 'calendar-access';
|
$dav[] = 'calendar-access';
|
||||||
|
$dav[] = 'calendar-auto-schedule';
|
||||||
|
$dav[] = 'calendar-proxy';
|
||||||
$dav[] = 'addressbook';
|
$dav[] = 'addressbook';
|
||||||
}
|
}
|
||||||
// not yet implemented: $dav[] = 'access-control';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,6 +43,9 @@ class groupdav_principals extends groupdav_handler
|
|||||||
'acl-principal-prop-set' => array(
|
'acl-principal-prop-set' => array(
|
||||||
// not sure why we return that report, if we not implement it ...
|
// not sure why we return that report, if we not implement it ...
|
||||||
),
|
),
|
||||||
|
'principal-property-search' => array(
|
||||||
|
'method' => 'principal_property_search_report',
|
||||||
|
),
|
||||||
'addressbook-findshared' => array(
|
'addressbook-findshared' => array(
|
||||||
'ns' => groupdav::ADDRESSBOOKSERVER,
|
'ns' => groupdav::ADDRESSBOOKSERVER,
|
||||||
'method' => 'addressbook_findshared_report',
|
'method' => 'addressbook_findshared_report',
|
||||||
@ -155,6 +158,135 @@ class groupdav_principals extends groupdav_handler
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle principal-property-search report
|
||||||
|
*
|
||||||
|
* Current implementation runs a full infinity propfind and filters out not matching resources.
|
||||||
|
*
|
||||||
|
* Eg. from Lightning on the principal collection /principals/:
|
||||||
|
* <D:principal-property-search xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||||
|
* <D:property-search>
|
||||||
|
* <D:prop>
|
||||||
|
* <C:calendar-home-set/>
|
||||||
|
* </D:prop>
|
||||||
|
* <D:match>/egroupware/groupdav.php</D:match>
|
||||||
|
* </D:property-search>
|
||||||
|
* <D:prop>
|
||||||
|
* <C:calendar-home-set/>
|
||||||
|
* <C:calendar-user-address-set/>
|
||||||
|
* <C:schedule-inbox-URL/>
|
||||||
|
* <C:schedule-outbox-URL/>
|
||||||
|
* </D:prop>
|
||||||
|
* </D:principal-property-search>
|
||||||
|
*
|
||||||
|
* Hack for Lightning: it requests calendar-home-set matching our root (/egroupware/groupdav.php),
|
||||||
|
* but interprets returning all principals (all have a matching calendar-home-set) as NOT supporting CalDAV scheduling
|
||||||
|
* --> search only current user's principal, when Lightning searches for calendar-home-set
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param array $options
|
||||||
|
* @param array &$files
|
||||||
|
* @param int $user account_id
|
||||||
|
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
|
||||||
|
*/
|
||||||
|
function principal_property_search_report($path,&$options,&$files,$user)
|
||||||
|
{
|
||||||
|
//error_log(__METHOD__."('$path', ".array2string($options).",, $user)");
|
||||||
|
|
||||||
|
// parse property-search prop(s) contained in $options['other']
|
||||||
|
foreach($options['other'] as $n => $prop)
|
||||||
|
{
|
||||||
|
switch($prop['name'])
|
||||||
|
{
|
||||||
|
case 'apply-to-principal-collection-set': // optinal prop to apply search on principal-collection-set == '/principals/'
|
||||||
|
$path = '/principals/';
|
||||||
|
break;
|
||||||
|
case 'property-search':
|
||||||
|
$property_search = $n; // should be 1
|
||||||
|
break;
|
||||||
|
case 'prop':
|
||||||
|
if (isset($property_search))
|
||||||
|
{
|
||||||
|
$search_props[$property_search] = array();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'match':
|
||||||
|
if (isset($property_search) && is_array($search_props[$property_search]))
|
||||||
|
{
|
||||||
|
$search_props[$property_search]['match'] = $prop['data'];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (isset($property_search) && $search_props[$property_search] === array())
|
||||||
|
{
|
||||||
|
$search_props[$property_search] = $prop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isset($property_search) || !$search_props || !isset($search_props[$property_search]['match']))
|
||||||
|
{
|
||||||
|
error_log(__METHOD__."('$path',...) Could not parse options[other]=".array2string($options['other']));
|
||||||
|
return '400 Bad Request';
|
||||||
|
}
|
||||||
|
// make sure search property is included in toplevel props (can be missing and defaults to property-search/prop's)
|
||||||
|
foreach($search_props as $prop)
|
||||||
|
{
|
||||||
|
if (!$this->groupdav->prop_requested($prop['name'], $prop['xmlns']))
|
||||||
|
{
|
||||||
|
$options['props'][] = array(
|
||||||
|
'name' => $prop['name'],
|
||||||
|
'xmlns' => $prop['xmlns'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Hack for Lightning: it requests calendar-home-set matching our root (/egroupware/groupdav.php),
|
||||||
|
// but interprets returning all principals (all have a matching calendar-home-set) as NOT supporting CalDAV scheduling
|
||||||
|
// --> search only current user's principal
|
||||||
|
if ($prop['name'] == 'calendar-home-set' && stripos($_SERVER['HTTP_USER_AGENT'], 'Lightning') !== false)
|
||||||
|
{
|
||||||
|
$path = '/principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// run "regular" propfind
|
||||||
|
$options['other'] = array();
|
||||||
|
$options['root']['name'] = 'propfind';
|
||||||
|
if (($ret = $this->propfind($path, $options, $files, $user)) !== true)
|
||||||
|
{
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
// now filter out not matching "files"
|
||||||
|
foreach($files['files'] as $n => $resource)
|
||||||
|
{
|
||||||
|
if (count(explode('/', $resource['path'])) < 4) // hack to only return principals, not the collections itself
|
||||||
|
{
|
||||||
|
unset($files['files'][$n]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// search with all $search_props
|
||||||
|
foreach($search_props as $search_prop)
|
||||||
|
{
|
||||||
|
// search resource for $search_prop
|
||||||
|
foreach($resource['props'] as $prop) if ($prop['name'] === $search_prop['name']) break;
|
||||||
|
if ($prop['name'] === $search_prop['name']) // search_prop NOT found
|
||||||
|
{
|
||||||
|
foreach((array)$prop['val'] as $value)
|
||||||
|
{
|
||||||
|
if (is_array($value)) $value = $value['val']; // eg. href prop
|
||||||
|
if (stripos($value, $search_prop['match']) !== false) // prop does match
|
||||||
|
{
|
||||||
|
//error_log("$resource[path]: $search_prop[name]=".array2string($prop['name'] !== $search_prop['name'] ? null : $prop['val'])." does match '$search_prop[match]'");
|
||||||
|
continue 2; // search next search_prop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//error_log("$resource[path]: $search_prop[name]=".array2string($prop['name'] !== $search_prop['name'] ? null : $prop['val'])." does NOT match '$search_prop[match]' --> remove from result");
|
||||||
|
unset($files['files'][$n]);
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do propfind in /pricipals/users
|
* Do propfind in /pricipals/users
|
||||||
*
|
*
|
||||||
@ -566,7 +698,7 @@ class groupdav_principals extends groupdav_handler
|
|||||||
|
|
||||||
if ($options['depth'])
|
if ($options['depth'])
|
||||||
{
|
{
|
||||||
$options['depth'] = 0;
|
if (is_numeric($options['depth'])) --$options['depth'];
|
||||||
$files = array_merge($files,$this->propfind_users('','',$options));
|
$files = array_merge($files,$this->propfind_users('','',$options));
|
||||||
$files = array_merge($files,$this->propfind_groups('','',$options));
|
$files = array_merge($files,$this->propfind_groups('','',$options));
|
||||||
//$files = array_merge($this->propfind_resources('','',$options));
|
//$files = array_merge($this->propfind_resources('','',$options));
|
||||||
|
Loading…
Reference in New Issue
Block a user