- show user collections /<username>/(addressbook|calendar|infolog)/ in propfind

- only define addressbook-home-set and calendar-home-set for principal-collections
- advertice /addressbook/ as addressbook-gateway (searchable collection for all contacts accessible to a user)
This commit is contained in:
Ralf Becker 2011-09-20 19:16:24 +00:00
parent 4a3c3cf659
commit d5f9c5b93c
2 changed files with 108 additions and 92 deletions

View File

@ -20,20 +20,25 @@ require_once('HTTP/WebDAV/Server.php');
*
* One can use the following url's releative (!) to http://domain.com/egroupware/groupdav.php
*
* - /addressbook/ all addressbooks current user has rights to
* - /calendar/ calendar of current user
* - /infolog/ infologs of current user
* - / base of the above, only certain clients (KDE, Apple) can autodetect folders from there
* - / base of Cal|Card|GroupDAV tree, only certain clients (KDE, Apple) can autodetect folders from here
* - /principals/ principal-collection-set for WebDAV ACL
* - /principals/users/<username>/
* - /principals/groups/<groupname>/
* - /<username>/ users home-set with
* - /<username>/addressbook/ addressbook of user or group <username> given the user has rights to view it
* - /<username>/calendar/ calendar of user <username> given the user has rights to view it
* - /<username>/infolog/ InfoLog's of user <username> given the user has rights to view it
* - /<username>/ base of the above, only certain clients (KDE, Apple) can autodetect folders from there
* - /addressbook/ all addressbooks current user has rights to, announced as directory-gateway now
* - /calendar/ calendar of current user
* - /infolog/ infologs of current user
*
* Calling one of the above collections with a GET request / regular browser generates an automatic index
* from the data of a allprop PROPFIND, allow to browse CalDAV/CardDAV/GroupDAV tree with a regular browser.
*
* @todo All principal urls should either contain no account_lid (eg. base64 of it) or use urlencode($account_lid)
* @link http://www.groupdav.org GroupDAV spec
* @link http://www.groupdav.org/ GroupDAV spec
* @link http://caldav.calconnect.org/ CalDAV resources
* @link http://carddav.calconnect.org/ CardDAV resources
* @link http://calendarserver.org/ Apple calendar and contacts server
*/
class groupdav extends HTTP_WebDAV_Server
{
@ -86,9 +91,6 @@ class groupdav extends HTTP_WebDAV_Server
'resourcetype' => array(self::GROUPDAV => 'vtodo-collection', self::CALDAV => 'calendar'),
'component-set' => array(self::GROUPDAV => 'VTODO'),
),
'principals' => array(
'resourcetype' => array(self::DAV => 'collection'),
)
);
/**
* Debug level: 0 = nothing, 1 = function calls, 2 = more info, 3 = complete $_SERVER array
@ -132,9 +134,12 @@ class groupdav extends HTTP_WebDAV_Server
if ($this->debug > 2) error_log('groupdav: $_SERVER='.array2string($_SERVER));
// identify clients, which do NOT support path AND full url in <D:href> of PROPFIND request
// crrnd: client refuses redundand namespace declarations
// cnrnd: client needs redundand namespace declarations
// setting redundand namespaces as the default for (Cal|Card|Group)DAV, as the majority of the clients either require or can live with it
$this->cnrnd = true;
// identify clients, which do NOT support path AND full url in <D:href> of PROPFIND request
switch(($agent = groupdav_handler::get_agent()))
{
case 'kde': // KAddressbook (at least in 3.5 can NOT subscribe / does NOT find addressbook)
@ -299,84 +304,25 @@ class groupdav extends HTTP_WebDAV_Server
}
if ($this->debug > 1) error_log(__CLASS__."::$method: user='$user', app='$app', id='$id'");
if ($user)
{
$account_lid = $this->accounts->id2name($user);
}
else
{
$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
}
$account = $this->accounts->read($account_lid);
$files = array('files' => array());
$path = $user_prefix = $this->_slashify($user_prefix);
if (!$app) // user root folder containing apps
{
if (empty($user_prefix))
{
$user_prefix = '/'; //.$GLOBALS['egw_info']['user']['account_lid'].'/';
}
$calendar_user_address_set = array(
self::mkprop('href','urn:uuid:'.$account['account_lid']),
);
if ($user < 0)
{
$principalType = 'groups';
$displayname = lang('Group').' '.$account['account_lid'];
}
else
{
$principalType = 'users';
$displayname = $account['account_fullname'];
$calendar_user_address_set[] = self::mkprop('href','MAILTO:'.$account['account_email']);
}
$calendar_user_address_set[] = self::mkprop('href',$this->base_uri.'/principals/'.$principalType.'/'.$account['account_lid'].'/');
// add root with current users apps
$this->add_home($files, $path, $user, $options['depth']);
if ($options['depth'] && $user_prefix == '/')
// add principals and user-homes
if ($path == '/' && $options['depth'])
{
$displayname = 'EGroupware (Cal|Card|Group)DAV server';
}
$displayname = translation::convert($displayname, translation::charset(),'utf-8');
// self url
$files['files'][] = $this->add_collection($path, array(
'displayname' => $displayname,
'owner' => array(self::mkprop('href',$this->base_uri.'/principals/'.$principalType.'/'.$account_lid.'/')),
// adding the calendar extra property (calendar-home-set, etc.) here, allows apple iCal to "autodetect" the URL
'calendar-home-set' => self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.$user_prefix))),
'addressbook-home-set' => self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
self::mkprop('href',$this->base_uri.$user_prefix))),
'calendar-user-address-set' => self::mkprop(groupdav::CALDAV,'calendar-user-address-set',$calendar_user_address_set),
'email-address-set' => self::mkprop(groupdav::CALENDARSERVER,'email-address-set',array(
self::mkprop(groupdav::CALENDARSERVER,'email-address',$GLOBALS['egw_info']['user']['email']))),
// OUTBOX URLs of the current user
'schedule-outbox-URL' => self::mkprop(groupdav::CALDAV,'schedule-outbox-URL',array(
self::mkprop(groupdav::DAV,'href',$this->base_uri.'/calendar/'))),
//'current-user-privilege-set' => self::current_user_privilege_set(),
));
if ($options['depth'])
{
if (strlen($path) == 1) // GroupDAV Root
// principals collection
$files['files'][] = $this->add_collection('/principals/', array(
'displayname' => lang('Accounts'),
));
// todo: account_selection owngroups and none!!!
foreach($this->accounts->search(array('type' => 'both')) as $account)
{
// principals collection
$files['files'][] = $this->add_collection('/principals/', array(
'displayname' => lang('Accounts'),
));
}
foreach($this->root as $app => $data)
{
if (!$GLOBALS['egw_info']['user']['apps'][$app]) continue; // no rights for the given app
$props = $this->_properties($app,false,$user,$path);
// add ctag if handler implements it
if (($handler = self::app_handler($app)) && method_exists($handler,'getctag'))
{
$props['getctag'] = self::mkprop(
groupdav::CALENDARSERVER,'getctag',$handler->getctag($options['path'],$user));
}
$props['getetag'] = 'EGw-'.$app.'-wGE';
$files['files'][] = $this->add_collection($path.$app.'/',$props);
$this->add_home($files, $path.$account['account_lid'].'/', $user, $options['depth'] == 'infinity' ? 'infinity' : $options['depth']-1);
}
}
return true;
@ -407,6 +353,80 @@ class groupdav extends HTTP_WebDAV_Server
return '501 Not Implemented';
}
/**
* Add user home with addressbook, calendar, infolog
*
* @param array $files
* @param string $path / or /<username>/
* @param int $user
* @param int $depth
* @return string|boolean http status or true|false
*/
protected function add_home(array &$files, $path, $user, $depth)
{
if ($user)
{
$account_lid = $this->accounts->id2name($user);
}
else
{
$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
}
$account = $this->accounts->read($account_lid);
$calendar_user_address_set = array(
self::mkprop('href','urn:uuid:'.$account['account_lid']),
);
if ($user < 0)
{
$principalType = 'groups';
$displayname = lang('Group').' '.$account['account_lid'];
}
else
{
$principalType = 'users';
$displayname = $account['account_fullname'];
$calendar_user_address_set[] = self::mkprop('href','MAILTO:'.$account['account_email']);
}
$calendar_user_address_set[] = self::mkprop('href',$this->base_uri.'/principals/'.$principalType.'/'.$account['account_lid'].'/');
if ($depth && $path == '/')
{
$displayname = 'EGroupware (Cal|Card|Group)DAV server';
}
$displayname = translation::convert($displayname, translation::charset(),'utf-8');
// self url
$files['files'][] = $this->add_collection($path, array(
'displayname' => $displayname,
'owner' => array(self::mkprop('href',$this->base_uri.'/principals/'.$principalType.'/'.$account_lid.'/')),
'calendar-user-address-set' => self::mkprop(groupdav::CALDAV,'calendar-user-address-set',$calendar_user_address_set),
'email-address-set' => self::mkprop(groupdav::CALENDARSERVER,'email-address-set',array(
self::mkprop(groupdav::CALENDARSERVER,'email-address',$GLOBALS['egw_info']['user']['email']))),
// OUTBOX URLs of the current user
'schedule-outbox-URL' => self::mkprop(groupdav::CALDAV,'schedule-outbox-URL',array(
self::mkprop(groupdav::DAV,'href',$this->base_uri.'/calendar/'))),
//'current-user-privilege-set' => self::current_user_privilege_set(),
));
if ($depth)
{
foreach($this->root as $app => $data)
{
if (!$GLOBALS['egw_info']['user']['apps'][$app]) continue; // no rights for the given app
$props = $this->_properties($app,false,$user,$path);
// add ctag if handler implements it
if (($handler = self::app_handler($app)) && method_exists($handler,'getctag'))
{
$props['getctag'] = self::mkprop(
groupdav::CALENDARSERVER,'getctag',$handler->getctag($path,$user));
}
$props['getetag'] = 'EGw-'.$app.'-wGE';
$files['files'][] = $this->add_collection($path.$app.'/',$props);
}
}
return true;
}
/**
* Get properties of an application collection
*
@ -473,25 +493,14 @@ class groupdav extends HTTP_WebDAV_Server
switch ($app)
{
case 'calendar':
$props['calendar-home-set'] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.$path.'calendar/')));
// OUTBOX URLs of the current user
$props['schedule-outbox-URL'] = self::mkprop(groupdav::CALDAV,'schedule-outbox-URL',
array(self::mkprop(groupdav::DAV,'href',$this->base_uri.'/calendar/')));
$props['calendar-color'] = self::mkprop(groupdav::ICAL,'calendar-color',$display_color);
break;
case 'infolog':
$props['calendar-home-set'] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.$path.'infolog/')));
break;
default:
$props['calendar-home-set'] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.$path)));
$displayname = translation::convert(lang($app).' '.
common::grab_owner_name($user),$this->egw_charset,'utf-8');
}
$props['addressbook-home-set'] = self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
self::mkprop('href',$this->base_uri.$path)));
$props['displayname'] = $displayname;
foreach((array)$this->root[$app] as $prop => $values)
@ -504,6 +513,11 @@ class groupdav extends HTTP_WebDAV_Server
{
$props['resourcetype'][] = self::mkprop($ns,$type,'');
}
// add /addressbook/ as directory gateway
if ($app == 'addressbook' && $path == '/')
{
$props['resourcetype'][] = self::mkprop(self::CARDDAV, 'directory', '');
}
}
}
else

View File

@ -403,6 +403,8 @@ class groupdav_principals extends groupdav_handler
'addressbook-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',$addressbooks),
'group-membership' => $this->principal_set('group-membership', $this->accounts->memberships($account['account_id']),
'calendar', $account['account_id']), // add proxy-rights
'directory-gateway' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV, 'directory-gateway',array(
HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/addressbook/'))),
));
}