Updated GroupDAV code to support InfoLog calendars, Addressbook and new principal implementation

This commit is contained in:
Jörg Lehrke 2010-03-04 23:09:55 +00:00
parent 9e0f73f0dc
commit 19081734cd
14 changed files with 922 additions and 367 deletions

View File

@ -68,7 +68,7 @@ class addressbook_groupdav extends groupdav_handler
*/
static function get_path($contact)
{
return '/addressbook/'.$contact[self::PATH_ATTRIBUTE].'.vcf';
return $contact[self::PATH_ATTRIBUTE].'.vcf';
}
/**
@ -96,8 +96,9 @@ class addressbook_groupdav extends groupdav_handler
}
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id) filter=".array2string($filter));
// check if we have to return the full calendar data or just the etag's
if (!($filter['address_data'] = $options['props'] == 'all' && $options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props']))
// check if we have to return the full contact data or just the etag's
if (!($filter['address_data'] = $options['props'] == 'all' &&
$options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props']))
{
foreach($options['props'] as $prop)
{
@ -109,7 +110,7 @@ class addressbook_groupdav extends groupdav_handler
}
}
// return iterator, calling ourself to return result in chunks
$files['files'] = new groupdav_propfind_iterator($this,$filter,$files['files']);
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
return true;
}
@ -117,11 +118,12 @@ class addressbook_groupdav extends groupdav_handler
/**
* Callback for profind interator
*
* @param string $path
* @param array $filter
* @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(array $filter,$start=false)
function &propfind_callback($path,array $filter,$start=false)
{
$starttime = microtime(true);
@ -139,7 +141,7 @@ class addressbook_groupdav extends groupdav_handler
{
$props = array(
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($contact)),
HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/x-vcard'),
HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
HTTP_WebDAV_Server::mkprop('getlastmodified', $contact['modified']),
);
@ -147,19 +149,19 @@ class addressbook_groupdav extends groupdav_handler
{
$content = $handler->getVCard($contact,$this->charset,false);
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
}
else
{
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
}
$files[] = array(
'path' => self::get_path($contact),
'path' => $path.self::get_path($contact),
'props' => $props,
);
}
}
if ($this->debug) error_log(__METHOD__.'('.array2string($filter).','.array2string($start).") took ".(microtime(true) - $starttime).' to return '.count($files).' items');
if ($this->debug) error_log(__METHOD__."($path,".array2string($filter).','.array2string($start).") took ".(microtime(true) - $starttime).' to return '.count($files).' items');
return $files;
}
@ -266,14 +268,24 @@ class addressbook_groupdav extends groupdav_handler
*/
function put(&$options,$id,$user=null)
{
if ($this->debug) error_log(__METHOD__.'('.array2string($options).",$id,$user)");
$ok = $this->_common_get_put_delete('PUT',$options,$id);
if (!is_null($ok) && !is_array($ok))
{
return $ok;
}
$handler = self::_get_handler();
$contact = $handler->vcardtoegw($options['content']);
$vCard = htmlspecialchars_decode($options['content']);
$contactId = (is_array($ok) ? -1 : $ok['id']);
$contact = $handler->vcardtoegw($vCard, $contactId);
if (is_array($contact['category']))
{
$contact['category'] = implode(',',$this->bo->find_or_add_categories($contact['category'], $contactId));
}
elseif ($contactId > 0)
{
$contact['category'] = $ok['category'];
}
if (!is_null($ok))
{
$contact['id'] = $ok['id'];
@ -282,6 +294,10 @@ class addressbook_groupdav extends groupdav_handler
$contact['owner'] = $ok['owner'];
$contact['private'] = $ok['private'];
}
else
{
$contact['owner'] = $user;
}
if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match);
if (!($save_ok = $this->bo->save($contact)))
@ -295,13 +311,14 @@ class addressbook_groupdav extends groupdav_handler
}
if (!isset($contact['etag']))
{
$contact = $this->read($contact['id']);
$contact = $this->read($save_ok);
}
header('ETag: '.$this->get_etag($contact));
if (is_null($ok))
{
header($h='Location: '.$this->base_uri.self::get_path($contact));
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header($h='Location: '.$path.self::get_path($contact));
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): 201 Created");
return '201 Created';
}
@ -323,7 +340,37 @@ class addressbook_groupdav extends groupdav_handler
$result = $this->bo->search(array(),'MAX(contact_modified) AS contact_modified','','','','','',$filter);
return '"'.$result[0]['modified'].'"';
$ctag = 'EGw-'.$result[0]['modified'].'-wGE';
return $ctag;
}
/**
* Add the privileges of the current user
*
* @param array $props=array() regular props by the groupdav handler
* @return array
*/
static function current_user_privilege_set(array $props=array())
{
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::DAV,'current-user-privilege-set',
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'privilege',
array(//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'all',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read',''),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''),
//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read-current-user-privilege-set',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'bind',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'unbind',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post-vevent',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond-vevent',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver-vevent',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-properties',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-content',''),
))));
return $props;
}
/**
@ -345,11 +392,17 @@ class addressbook_groupdav extends groupdav_handler
* @link http://www.mail-archive.com/calendarserver-users@lists.macosforge.org/msg01156.html
*
* @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler
* @return array
*/
static function extra_properties(array $props=array(), $base_uri=null)
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
{
// addressbook description
$displayname = $GLOBALS['egw']->translation->convert(lang('Addressbook of') . ' ' .
$displayname,
$GLOBALS['egw']->translation->charset(),'utf-8');
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-description',$displayname);
// supported reports (required property for CardDAV)
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
HTTP_WebDAV_Server::mkprop('supported-report',array(
@ -359,6 +412,7 @@ class addressbook_groupdav extends groupdav_handler
HTTP_WebDAV_Server::mkprop('report',
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget','')))),
));
//$props = self::current_user_privilege_set($props);
return $props;
}
@ -392,7 +446,7 @@ class addressbook_groupdav extends groupdav_handler
{
return '412 Precondition Failed';
}
return $ok;
//return $ok;
}
/**

View File

@ -526,8 +526,8 @@ class addressbook_so
/**
* reads contact data including custom fields
*
* @param int/string $contact_id contact_id or 'a'.account_id
* @return array/boolean data if row could be retrived else False
* @param int|string $contact_id contact_id or 'a'.account_id
* @return array|boolean data if row could be retrived else False
*/
function read($contact_id)
{

View File

@ -123,7 +123,7 @@ class addressbook_vcal extends addressbook_bo
*/
function addVCard($_vcard, $_abID=null, $merge=false)
{
if (!$contact = $this->vcardtoegw($_vcard, $_abID))
if (!$contact = $this->vcardtoegw($_vcard))
{
return false;
}
@ -148,6 +148,15 @@ class addressbook_vcal extends addressbook_bo
{
$contact['account_id'] = $old_contact['account_id'];
}
if (is_array($contact['category']))
{
$contact['category'] = implode(',',$this->find_or_add_categories($contact['category'], $_abID));
}
else
{
// restore from orignal
$contact['category'] = $old_contact['category'];
}
}
}
// update entry
@ -160,6 +169,10 @@ class addressbook_vcal extends addressbook_bo
{
$contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group'];
}
if (is_array($contact['category']))
{
$contact['category'] = implode(',',$this->find_or_add_categories($contact['category'], -1));
}
}
return $this->save($contact);
}
@ -455,8 +468,13 @@ class addressbook_vcal extends addressbook_bo
{
$result = array();
if (($contact = $this->vcardtoegw($_vcard, $contentID)))
if (($contact = $this->vcardtoegw($_vcard)))
{
if (is_array($contact['category']))
{
$contact['category'] = implode(',',$this->find_or_add_categories($contact['category'],
$contentID ? $contentID : -1));
}
if ($contentID)
{
$contact['id'] = $contentID;
@ -475,7 +493,7 @@ class addressbook_vcal extends addressbook_bo
if (is_array($_supportedFields)) $this->supportedFields = $_supportedFields;
}
function vcardtoegw($_vcard, $_abID=null)
function vcardtoegw($_vcard)
{
// the horde class does the charset conversion. DO NOT CONVERT HERE.
// be as flexible as possible
@ -889,7 +907,7 @@ class addressbook_vcal extends addressbook_bo
break;
case 'cat_id':
$contact[$fieldName] = implode(',',$this->find_or_add_categories($vcardValues[$vcardKey]['values'], $_abID));
$contact[$fieldName] = $vcardValues[$vcardKey]['values'];
break;
case 'jpegphoto':

View File

@ -23,8 +23,6 @@ class calendar_groupdav extends groupdav_handler
*/
var $bo;
const DAV = 'DAV:';
var $filter_prop2cal = array(
'SUMMARY' => 'cal_title',
'UID' => 'cal_uid',
@ -86,7 +84,7 @@ class calendar_groupdav extends groupdav_handler
if (!is_array($event)) $event = $this->bo->read($event);
$name = $event[self::PATH_ATTRIBUTE];
}
return '/calendar/'.$name.'.ics';
return $name.'.ics';
}
/**
@ -191,7 +189,7 @@ class calendar_groupdav extends groupdav_handler
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
}
$files['files'][] = array(
'path' => self::get_path($event),
'path' => $path.self::get_path($event),
'props' => $props,
);
}
@ -447,12 +445,19 @@ class calendar_groupdav extends groupdav_handler
if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace());
return $event;
}
$handler = $this->_get_handler();
if (is_null($event) && !$this->bo->check_perms(EGW_ACL_ADD, 0, $user))
{
// we have not permission on this user's calendar
if ($this->debug) error_log(__METHOD__."(,$user) we have not enough rights on this calendar");
return '403 Forbidden';
}
$handler = $this->_get_handler();
$vCalendar = htmlspecialchars_decode($options['content']);
if (!($cal_id = $handler->importVCal($vCalendar, is_numeric($id) ? $id : -1,
self::etag2value($this->http_if_match), false, 0, $this->principalURL)))
self::etag2value($this->http_if_match), false, 0, $this->principalURL, $user)))
{
if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false");
return '403 Forbidden';
@ -461,15 +466,11 @@ class calendar_groupdav extends groupdav_handler
header('ETag: '.$this->get_etag($cal_id));
if (is_null($event) || !$return_no_access) // let lightning think the event is added
{
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id, is_null(\$event)=".(int)is_null($event));
header('Location: '.$this->base_uri.self::get_path($cal_id));
header('Location: '.$path.self::get_path($cal_id));
return '201 Created';
}
if (strpos($_SERVER[HTTP_USER_AGENT], 'Mac OS X') !== false)
{
//return '205 Reset Content'; // would be nicer
return '400 Event updated, please reload'; // Enforce a reload by iCal
}
return true;
}
@ -580,8 +581,7 @@ class calendar_groupdav extends groupdav_handler
*/
function read($id)
{
//$cal_read = $this->bo->read($id,null,false,'server');//njv: do we actually get anything
if ($this->debug > 1) error_log("bo-ical read :$id:");//njv:
if ($this->debug > 1) error_log("bo-ical read :$id:");
return $this->bo->read($id,null,false,'server');
}
@ -622,12 +622,12 @@ class calendar_groupdav extends groupdav_handler
{
if ($recurrence['reference']) // ignore series master
{
$etag .= ':'.substr($this->get_etag($recurrence),1,-1);
$etag .= ':'.substr($this->get_etag($recurrence),4,-4);
}
}
}
//error_log(__METHOD__ . "($entry[id] ($entry[etag]): $entry[title] --> etag=$etag");
return '"'.$etag.'"';
return 'EGw-'.$etag.'-wGE';
}
/**
@ -650,23 +650,23 @@ class calendar_groupdav extends groupdav_handler
*/
static function current_user_privilege_set(array $props=array())
{
$props[] = HTTP_WebDAV_Server::mkprop(self::DAV,'current-user-privilege-set',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'privilege',
array(//HTTP_WebDAV_Server::mkprop(self::DAV,'all',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'read',''),
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::DAV,'current-user-privilege-set',
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'privilege',
array(//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'all',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read',''),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''),
//HTTP_WebDAV_Server::mkprop(self::DAV,'read-current-user-privilege-set',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'bind',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'unbind',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-post',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-post-vevent',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-respond',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-respond-vevent',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-deliver',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-deliver-vevent',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'write',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'write-properties',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'write-content',''),
//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read-current-user-privilege-set',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'bind',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'unbind',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post-vevent',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond-vevent',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver-vevent',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-properties',''),
HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-content',''),
))));
return $props;
}
@ -675,42 +675,41 @@ class calendar_groupdav extends groupdav_handler
* Add extra properties for calendar collections
*
* @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler
* @return array
*/
static function extra_properties(array $props=array(), $base_uri=null)
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
{
// calendar description
$displayname = $GLOBALS['egw']->translation->convert(lang('Calendar of'). ' ' .
$GLOBALS['egw_info']['user']['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8');
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
// BOX URLs of the current user
/*
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-inbox-URL',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/')));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-outbox-URL',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/')));
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-default-calendar-URL',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/')));
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'dropbox-home-URL',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/')));
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'notifications-URL',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/')));
array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/')));
*/
// email of the current user, see caldav-sheduling draft
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$GLOBALS['egw_info']['user']['email']);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email'])));
// supported components, currently only VEVENT
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')),
// HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), // not yet supported
));
/*
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget'))))));
*/
//$props = self::current_user_privilege_set($props);
return $props;
}

View File

@ -1029,9 +1029,10 @@ class calendar_ical extends calendar_boupdate
* @param int $recur_date=0 if set, import the recurrence at this timestamp,
* default 0 => import whole series (or events, if not recurring)
* @param string $principalURL='' Used for CalDAV imports
* @param int $user=null account_id of owner, default null
* @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag
*/
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='')
function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null)
{
if (!is_array($this->supportedFields)) $this->setSupportedFields();
@ -1081,7 +1082,7 @@ class calendar_ical extends calendar_boupdate
if ($this->log)
{
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
."($cal_id, $etag, $recur_date, $principalURL)\n"
."($cal_id, $etag, $recur_date, $principalURL, $user)\n"
. array2string($event)."\n",3,$this->logfile);
}
$updated_id = false;
@ -1204,9 +1205,20 @@ class calendar_ical extends calendar_boupdate
$event['non_blocking'] = 1;
}
if (!is_null($user))
{
if ($this->check_perms(EGW_ACL_ADD, 0, $user))
{
$event['owner'] = $user;
}
else
{
return false; // no permission
}
}
// check if an owner is set and the current user has add rights
// for that owners calendar; if not set the current user
if (!isset($event['owner'])
elseif (!isset($event['owner'])
|| !$this->check_perms(EGW_ACL_ADD, 0, $event['owner']))
{
$event['owner'] = $this->user;

View File

@ -59,6 +59,18 @@ class HTTP_WebDAV_Server
*/
var $client_require_href_as_url;
/**
* Set if client requires does not allow namespace redundacy.
* The XML Namespace specification does allow both
* But some clients can NOT deal with one or the other!
*
* @var boolean (client_refuses_redundand_namespace_declarations)
*/
var $crrnd = false;
/**
/**
* URI path for this request
*
@ -229,11 +241,18 @@ class HTTP_WebDAV_Server
$this->$wrapper(); // call method by name
} else { // method not found/implemented
if ($this->_SERVER["REQUEST_METHOD"] == "LOCK") {
$this->http_status("412 Precondition failed");
$error = '412 Precondition failed';
;
} else {
$this->http_status("405 Method not allowed");
$error = '405 Method not allowed';
header("Allow: ".join(", ", $this->_allow())); // tell client what's allowed
}
$this->http_status($error);
echo "<html><head><title>Error $error</title></head>\n";
echo "<body><h1>$error</h1>\n";
echo "The requested could not by handled by this server.\n";
echo '(URI ' . $this->_SERVER['REQUEST_URI'] . ")<br>\n<br>\n";
echo "</body></html>\n";
}
}
@ -432,7 +451,7 @@ class HTTP_WebDAV_Server
*/
// }}}
// {{{ LOCK()
// {{{ ACL()
/**
* ACL implementation
@ -585,7 +604,7 @@ class HTTP_WebDAV_Server
$options['other'] = $propinfo->other;
// call user handler
if (!$this->$handler($options, $files)) {
if (!($retval =$this->$handler($options, $files))) {
$files = array("files" => array());
if (method_exists($this, "checkLock")) {
// is locked?
@ -612,26 +631,42 @@ class HTTP_WebDAV_Server
}
// now we generate the reply header ...
if ($propinfo->root['name'] == 'principal-search-property-set')
{
$this->http_status('200 OK');
}
else
if ($retval === true)
{
$this->http_status('207 Multi-Status');
}
else
{
$this->http_status($retval);
header('Content-Type: text/html');
echo "<html><head><title>Error $retval</title></head>\n";
echo "<body><h1>$retval</h1>\n";
switch (substr($retval, 0 ,3))
{
case '501': // Not Implemented
echo "The requested feature is not (yet) supported by this server.\n";
break;
default:
echo "The request could not be handled by this server.\n";
}
echo '(URI ' . $this->_SERVER['REQUEST_URI'] . ")<br>\n<br>\n";
echo "</body></html>\n";
return;
}
// dav header
$dav = array(1); // assume we are always dav class 1 compliant
$allow = false;
// allow extending class to modify DAV
if (method_exists($this,'OPTIONS')) {
$this->OPTIONS($this->path,$dav,$allow);
}
header("DAV: " .join(", ", $dav));
header('Content-Type: text/xml; charset="utf-8"');
// ... and payload
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
if ($propinfo->root['name'] == 'principal-search-property-set')
{
echo "<D:principal-search-property-set xmlns:D=\"DAV:\">\n";
}
else
{
echo "<D:multistatus xmlns:D=\"DAV:\">\n";
}
echo ($this->crrnd?'<':'<D:')."multistatus xmlns:D=\"DAV:\">\n";
// using an ArrayIterator to prevent foreach from copying the array,
// as we cant loop by reference, when an iterator is given in $files['files']
@ -748,7 +783,14 @@ class HTTP_WebDAV_Server
$path = $file['path'];
if (!is_string($path) || $path==="") continue;
if ($propinfo->root['name'] != 'principal-search-property-set') echo " <D:response $ns_defs>\n";
if ($this->crrnd)
{
echo " <response $ns_defs>\n";
}
else
{
echo " <D:response $ns_defs>\n";
}
/* TODO right now the user implementation has to make sure
collections end in a slash, this should be done in here
@ -756,15 +798,20 @@ class HTTP_WebDAV_Server
// path needs to be urlencoded (only basic version of this class!)
$href = $this->_urlencode($this->_mergePathes($this->base_uri, $path));
if ($propinfo->root['name'] != 'principal-search-property-set') echo " <D:href>$href</D:href>\n";
if ($this->crrnd)
{
echo " <href>$href</href>\n";
}
else
{
echo " <D:href>$href</D:href>\n";
}
// report all found properties and their values (if any)
if (isset($file["props"]) && is_array($file["props"])) {
if ($propinfo->root['name'] != 'principal-search-property-set')
{
echo " <D:propstat>\n";
echo " <D:prop>\n";
}
echo ' <'.($this->crrnd?'':'D:')."propstat>\n";
echo ' <'.($this->crrnd?'':'D:')."prop>\n";
foreach ($file["props"] as &$prop) {
if (!is_array($prop)) continue;
@ -773,7 +820,7 @@ class HTTP_WebDAV_Server
if (!isset($prop["val"]) || $prop["val"] === "" || $prop["val"] === false) {
// empty properties (cannot use empty() for check as "0" is a legal value here)
if ($prop["ns"]=="DAV:") {
echo " <D:$prop[name]/>\n";
echo ' <'.($this->crrnd?'':'D:')."$prop[name]/>\n";
} else if (!empty($prop["ns"])) {
echo " <".$ns_hash[$prop["ns"]].":$prop[name]/>\n";
} else {
@ -783,61 +830,34 @@ class HTTP_WebDAV_Server
// some WebDAV properties need special treatment
switch ($prop["name"]) {
case "creationdate":
echo " <D:creationdate ns0:dt=\"dateTime.tz\">"
echo ' <'.($this->crrnd?'':'D:')."creationdate ns0:dt=\"dateTime.tz\">"
. gmdate("Y-m-d\\TH:i:s\\Z", $prop['val'])
. "</D:creationdate>\n";
. '</'.($this->crrnd?'':'D:')."creationdate>\n";
break;
case "getlastmodified":
echo " <D:getlastmodified ns0:dt=\"dateTime.rfc1123\">"
echo ' <'.($this->crrnd?'':'D:')."getlastmodified ns0:dt=\"dateTime.rfc1123\">"
. gmdate("D, d M Y H:i:s ", $prop['val'])
. "GMT</D:getlastmodified>\n";
. "GMT</".($this->crrnd?'':'D:')."getlastmodified>\n";
break;
/* @Todo: breaks CalDAV - 2010/03/01 jlehrke
case "resourcetype":
if (!is_array($prop['val'])) {
echo ' <D:resourcetype><D:'.$prop['val']."/></D:resourcetype>\n";
} else { // multiple resourcetypes from different namespaces as required by GroupDAV
$vals = $extra_ns = '';
foreach($prop['val'] as $subprop)
{
if ($subprop['ns'] && $subprop['ns'] != 'DAV:') {
// register property namespace if not known yet
if (!isset($ns_hash[$subprop['ns']])) {
$ns_name = "ns".(count($ns_hash) + 1);
$ns_hash[$subprop['ns']] = $ns_name;
} else {
$ns_name = $ns_hash[$subprop['ns']];
}
if (strchr($extra_ns,$extra=' xmlns:'.$ns_name.'="'.$subprop['ns'].'"') === false) {
$extra_ns .= $extra;
}
$ns_name .= ':';
} elseif ($subprop['ns'] == 'DAV:') {
$ns_name = 'D:';
} else {
$ns_name = '';
}
$vals .= "<$ns_name$subprop[val]/>";
}
echo " <D:resourcetype$extra_ns>$vals</D:resourcetype>\n";
//error_log("resourcetype: <D:resourcetype$extra_ns>$vals</D:resourcetype>");
}
break;
*/
case "supportedlock":
echo " <D:supportedlock>$prop[val]</D:supportedlock>\n";
echo ' <'.($this->crrnd?'':'D:')."supportedlock>$prop[val]</".($this->crrnd?'':'D:')."supportedlock>\n";
break;
case "lockdiscovery":
echo " <D:lockdiscovery>\n";
echo ' <'.($this->crrnd?'':'D:')."lockdiscovery>\n";
echo $prop["val"];
echo " </D:lockdiscovery>\n";
echo ' </'.($this->crrnd?'':'D:')."lockdiscovery>\n";
break;
default:
echo " <D:$prop[name]>".
(is_array($prop['val']) ?
$this->_hierarchical_prop_encode($prop['val']) :
$this->_prop_encode(htmlspecialchars($prop['val']))).
"</D:$prop[name]>\n";
if (is_array($prop['val']))
{
$val = $this->_hierarchical_prop_encode($prop['val']);
} elseif (isset($prop['raw'])) {
$val = $this->_prop_encode('<![CDATA['.$prop['val'].']]>');
} else {
$val = $this->_prop_encode(htmlspecialchars($prop['val']));
}
echo ' <'.($this->crrnd?'':'D:')."$prop[name]>$val".
'</'.($this->crrnd?'':'D:')."$prop[name]>\n";
break;
}
} else {
@ -878,25 +898,47 @@ class HTTP_WebDAV_Server
}
else
{
$vals .= '>'.htmlspecialchars($subprop['val'])."</$ns_name$subprop[name]>";
$vals .= '>';
if (isset($subprop['raw'])) {
$vals .= '<![CDATA['.$subprop['val'].']]>';
} else {
$vals .= htmlspecialchars($subprop['val']);
}
$vals .= "</$ns_name$subprop[name]>";
}
}
echo " <".$ns_hash[$prop['ns']].":$prop[name]$extra_ns>$vals</".$ns_hash[$prop['ns']].":$prop[name]>\n";
echo ' <'.$ns_hash[$prop['ns']].":$prop[name]$extra_ns>$vals</".$ns_hash[$prop['ns']].":$prop[name]>\n";
} else {
if ($prop['raw'])
{
$val = '<![CDATA['.$prop['val'].']]>';
} else {
$val = htmlspecialchars($prop['val']);
}
$val = $this->_prop_encode($val);
// properties from namespaces != "DAV:" or without any namespace
if ($prop['ns']) {
if ($this->crrnd) {
echo " <$prop[name]> xmlns:".$ns_hash[$prop['ns']]."=".'"'.$prop["ns"].'">'
. $val . "</$prop[name]>\n";
} else {
echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]>"
. $val . '</'.$ns_hash[$prop['ns']].":$prop[name]>\n";
}
} else {
echo " <$prop[name] xmlns=\"\">$val</$prop[name]>\n";
}
}
}
}
if ($this->crrnd)
{
echo " </prop>\n";
echo " <status>HTTP/1.1 200 OK</status>\n";
echo " </propstat>\n";
}
else
// properties from namespaces != "DAV:" or without any namespace
if ($prop["ns"]) {
echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]>"
. $this->_prop_encode(htmlspecialchars($prop['val']))
. "</" . $ns_hash[$prop["ns"]] . ":$prop[name]>\n";
} else {
echo " <$prop[name] xmlns=\"\">"
. $this->_prop_encode(htmlspecialchars($prop['val']))
. "</$prop[name]>\n";
}
}
}
if ($propinfo->root['name'] != 'principal-search-property-set')
{
echo " </D:prop>\n";
echo " <D:status>HTTP/1.1 200 OK</D:status>\n";
@ -906,12 +948,12 @@ class HTTP_WebDAV_Server
// now report all properties requested but not found
if (isset($file["noprops"])) {
echo " <D:propstat>\n";
echo " <D:prop>\n";
echo ' <'.($this->crrnd?'':'D:')."propstat>\n";
echo ' <'.($this->crrnd?'':'D:')."prop>\n";
foreach ($file["noprops"] as &$prop) {
if ($prop["ns"] == "DAV:") {
echo " <D:$prop[name]/>\n";
echo ' <'.($this->crrnd?'':'D:')."$prop[name]/>\n";
} else if ($prop["ns"] == "") {
echo " <$prop[name] xmlns=\"\"/>\n";
} else {
@ -919,23 +961,24 @@ class HTTP_WebDAV_Server
}
}
if ($this->crrnd)
{
echo " </prop>\n";
echo " <status>HTTP/1.1 404 Not Found</status>\n";
echo " </propstat>\n";
}
else
{
echo " </D:prop>\n";
echo " <D:status>HTTP/1.1 404 Not Found</D:status>\n";
echo " </D:propstat>\n";
}
if ($propinfo->root['name'] != 'principal-search-property-set') echo " </D:response>\n";
}
if ($propinfo->root['name'] == 'principal-search-property-set')
{
echo "</D:principal-search-property-set>\n";
}
else
{
echo "</D:multistatus>\n";
echo ' </'.($this->crrnd?'':'D:')."response>\n";
}
echo '</'.($this->crrnd?'':'D:')."multistatus>\n";
}
@ -973,24 +1016,24 @@ class HTTP_WebDAV_Server
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
echo "<D:multistatus xmlns:D=\"DAV:\">\n";
echo " <D:response>\n";
echo " <D:href>".$this->_urlencode($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path))."</D:href>\n";
echo ' <'.($this->crrnd?'':'D:')."response>\n";
echo ' <'.($this->crrnd?'':'D:')."href>".$this->_urlencode($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path)).'</'.($this->crrnd?'':'D:')."href>\n";
foreach ($options["props"] as $prop) {
echo " <D:propstat>\n";
echo " <D:prop><$prop[name] xmlns=\"$prop[ns]\"/></D:prop>\n";
echo " <D:status>HTTP/1.1 $prop[status]</D:status>\n";
echo " </D:propstat>\n";
echo ' <'.($this->crrnd?'':'D:')."propstat>\n";
echo ' <'.($this->crrnd?'':'D:')."prop><$prop[name] xmlns=\"$prop[ns]\"/></".($this->crrnd?'':'D:')."prop>\n";
echo ' <'.($this->crrnd?'':'D:')."status>HTTP/1.1 $prop[status]</".($this->crrnd?'':'D:')."status>\n";
echo ' </'.($this->crrnd?'':'D:')."propstat>\n";
}
if ($responsedescr) {
echo " <D:responsedescription>".
echo ' <'.($this->crrnd?'':'D:')."responsedescription>".
$this->_prop_encode(htmlspecialchars($responsedescr)).
"</D:responsedescription>\n";
'</'.($this->crrnd?'':'D:')."responsedescription>\n";
}
echo " </D:response>\n";
echo "</D:multistatus>\n";
echo ' </'.($this->crrnd?'':'D:')."response>\n";
echo '</'.($this->crrnd?'':'D:')."multistatus>\n";
} else {
$this->http_status("423 Locked");
}
@ -1580,17 +1623,17 @@ class HTTP_WebDAV_Server
header("Lock-Token: <$options[locktoken]>");
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
echo "<D:prop xmlns:D=\"DAV:\">\n";
echo " <D:lockdiscovery>\n";
echo " <D:activelock>\n";
echo " <D:lockscope><D:$options[scope]/></D:lockscope>\n";
echo " <D:locktype><D:$options[type]/></D:locktype>\n";
echo " <D:depth>$options[depth]</D:depth>\n";
echo " <D:owner>$options[owner]</D:owner>\n";
echo " <D:timeout>$timeout</D:timeout>\n";
echo " <D:locktoken><D:href>$options[locktoken]</D:href></D:locktoken>\n";
echo " </D:activelock>\n";
echo " </D:lockdiscovery>\n";
echo "</D:prop>\n\n";
echo ' <'.($this->crrnd?'':'D:')."lockdiscovery>\n";
echo ' <'.($this->crrnd?'':'D:')."activelock>\n";
echo ' <'.($this->crrnd?'':'D:')."lockscope><D:$options[scope]/></".($this->crrnd?'':'D:')."lockscope>\n";
echo ' <'.($this->crrnd?'':'D:')."locktype><D:$options[type]/></".($this->crrnd?'':'D:')."locktype>\n";
echo ' <'.($this->crrnd?'':'D:')."depth>$options[depth]</".($this->crrnd?'':'D:')."depth>\n";
echo ' <'.($this->crrnd?'':'D:')."owner>$options[owner]</".($this->crrnd?'':'D:')."owner>\n";
echo ' <'.($this->crrnd?'':'D:')."timeout>$timeout</".($this->crrnd?'':'D:')."timeout>\n";
echo ' <'.($this->crrnd?'':'D:')."locktoken><D:href>$options[locktoken]</D:href></".($this->crrnd?'':'D:')."locktoken>\n";
echo ' </'.($this->crrnd?'':'D:')."activelock>\n";
echo ' </'.($this->crrnd?'':'D:')."lockdiscovery>\n";
echo '</'.($this->crrnd?'':'D:')."prop>\n\n";
}
}
@ -1627,7 +1670,7 @@ class HTTP_WebDAV_Server
// }}}
// {{{ http_UNLOCK()
// {{{ http_ACL()
/**
* ACL method handler
@ -1660,9 +1703,9 @@ class HTTP_WebDAV_Server
$content .= "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$content .= "<D:error xmlns:D=\"DAV:\"> \n";
foreach ($options['errors'] as $violation) {
$content .= "<D:$violation/>\n";
$content .= '<'.($this->crrnd?'':'D:')."$violation/>\n";
}
$content .= "</D:error>\n";
$content .= '</'.($this->crrnd?'':'D:')."error>\n";
}
header("Content-length: ".$this->bytes($content));
if ($content) echo $options['content'];
@ -1765,16 +1808,23 @@ class HTTP_WebDAV_Server
* @param string XML namespace (optional)
* @param string property name
* @param string property value
* @praram boolen property raw-flag
* @return array property array
*/
function mkprop()
{
$args = func_get_args();
if (count($args) == 3) {
return array("ns" => $args[0],
"name" => $args[1],
"val" => $args[2]);
} else {
switch (count($args)) {
case 4:
return array('ns' => $args[0],
'name' => $args[1],
'val' => $args[2],
'raw' => true);
case 3:
return array('ns' => $args[0],
'name' => $args[1],
'val' => $args[2]);
default:
return array("ns" => "DAV:",
"name" => $args[0],
"val" => $args[1]);
@ -2125,6 +2175,21 @@ class HTTP_WebDAV_Server
}
// genreate response block
if ($this->crrnd)
{
$activelocks.= "
<activelock>
<lockscope><$lock[scope]/></lockscope>
<locktype><$lock[type]/></locktype>
<depth>$lock[depth]</depth>
<owner>$lock[owner]</owner>
<timeout>$timeout</timeout>
<locktoken><href>$lock[token]</href></locktoken>
</activelock>
";
}
else
{
$activelocks.= "
<D:activelock>
<D:lockscope><D:$lock[scope]/></D:lockscope>
@ -2136,6 +2201,7 @@ class HTTP_WebDAV_Server
</D:activelock>
";
}
}
// return generated response
//error_log(__METHOD__."\n".print_r($activelocks,true));

View File

@ -186,7 +186,7 @@ class HTTP_WebDAV_Server_Filesystem extends HTTP_WebDAV_Server
// type and size (caller already made sure that path exists)
if (is_dir($fspath)) {
// directory (WebDAV collection)
$info["props"][] = $this->mkprop("resourcetype", "collection");
$info["props"][] = $this->mkprop("resourcetype", array($this->mkprop('collection', '')));
$info["props"][] = $this->mkprop("getcontenttype", "httpd/unix-directory");
} else {
// plain file (WebDAV resource)

View File

@ -420,13 +420,13 @@ class infolog_bo
/**
* Read an infolog entry specified by $info_id
*
* @param int/array $info_id integer id or array with key 'info_id' of the entry to read
* @param int|array $info_id integer id or array with key 'info_id' of the entry to read
* @param boolean $run_link_id2from=true should link_id2from run, default yes,
* need to be set to false if called from link-title to prevent an infinit recursion
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
* 'array'=array or string with date-format
*
* @return array/boolean infolog entry, null if not found or false if no permission to read it
* @return array|boolean infolog entry, null if not found or false if no permission to read it
*/
function &read($info_id,$run_link_id2from=true,$date_format='ts')
{

View File

@ -57,7 +57,7 @@ class infolog_groupdav extends groupdav_handler
if (!is_array($info)) $info = $this->bo->read($info);
$name = $info[self::PATH_ATTRIBUTE];
}
return '/infolog/'.$name.'.ics';
return $name.'.ics';
}
/**
@ -73,6 +73,8 @@ class infolog_groupdav extends groupdav_handler
{
$starttime = microtime(true);
$myself = ($user == $GLOBALS['egw_info']['user']['account_id']);
if ($options['filters'])
{
@ -113,13 +115,16 @@ class infolog_groupdav extends groupdav_handler
$filter = array(
'info_type' => 'task',
);
//if (!$myself) $filter['info_owner'] = $user;
if ($id) $filter['info_id'] = $id; // propfind on a single id
// ToDo: add parameter to only return id & etag
if (($tasks =& $this->bo->search($params=array(
'order' => 'info_datemodified',
'sort' => 'DESC',
'filter' => 'own', // filter my: entries user is responsible for,
'filter' => ($myself ? 'own' : 'own'), // filter my: entries user is responsible for,
// filter own: entries the user own or is responsible for
'date_format' => 'server',
'col_filter' => $filter,
@ -148,7 +153,7 @@ class infolog_groupdav extends groupdav_handler
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
}
$files['files'][] = array(
'path' => self::get_path($task),
'path' => $path.self::get_path($task),
'props' => $props,
);
}
@ -193,8 +198,11 @@ class infolog_groupdav extends groupdav_handler
{
return $ok;
}
$handler = $this->_get_handler();
if (!($info_id = $handler->importVTODO($options['content'],is_numeric($id) ? $id : -1)))
$vTodo = htmlspecialchars_decode($options['content']);
if (!($info_id = $handler->importVTODO($vTodo,is_numeric($id) ? $id : -1, false, $user)))
{
if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false");
return '403 Forbidden';
@ -202,7 +210,8 @@ class infolog_groupdav extends groupdav_handler
header('ETag: '.$this->get_etag($info_id));
if (is_null($ok) || $id != $info_id)
{
header('Location: '.$this->base_uri.self::get_path($info_id));
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header('Location: '.$path.self::get_path($info_id));
return '201 Created';
}
return true;
@ -263,36 +272,38 @@ class infolog_groupdav extends groupdav_handler
{
return false;
}
return '"'.$info['info_id'].':'.$info['info_datemodified'].'"';
return 'EGw-'.$info['info_id'].':'.$info['info_datemodified'].'-wGE';
}
/**
* Add extra properties for calendar collections
*
* @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler
* @return array
*/
static function extra_properties(array $props=array(), $base_uri=null)
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
{
// calendar description
$displayname = $GLOBALS['egw']->translation->convert(lang('Tasks of') . ' ' .
$GLOBALS['egw_info']['user']['account_fullname'],
$displayname,
$GLOBALS['egw']->translation->charset(),'utf-8');
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
// email of the current user, see caldav-sheduling draft
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$GLOBALS['egw_info']['user']['email']);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email'])));
// supported components, currently only VEVENT
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array(
// HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')),
));
/*
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget'))))));
*/
return $props;
}

View File

@ -380,9 +380,10 @@ class infolog_ical extends infolog_bo
* @param string $_vcalData
* @param int $_taskID=-1 info_id, default -1 = new entry
* @param boolean $merge=false merge data with existing entry
* @param int $user=null delegate new task to this account_id, default null
* @return int|boolean integer info_id or false on error
*/
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false)
function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null)
{
if (!($taskData = $this->vtodotoegw($_vcalData,$_taskID))) return false;
@ -397,6 +398,11 @@ class infolog_ical extends infolog_bo
$taskData['info_datecompleted'] = 0;
}
if (!is_null($user))
{
$taskData['info_responsible'] = array($user);
}
if ($this->log)
{
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .

View File

@ -36,6 +36,10 @@ require_once('HTTP/WebDAV/Server.php');
*/
class groupdav extends HTTP_WebDAV_Server
{
/**
* DAV namespace
*/
const DAV = 'DAV:';
/**
* GroupDAV namespace
*/
@ -107,6 +111,12 @@ class groupdav extends HTTP_WebDAV_Server
* @var string
*/
var $principalURL;
/**
* Reference to the accounts class
*
* @var accounts
*/
var $accounts;
function __construct()
@ -122,6 +132,8 @@ class groupdav extends HTTP_WebDAV_Server
case 'davkit': // iCal app in OS X 10.6 created wrong request, if full url given
$this->client_require_href_as_url = false;
break;
case 'cfnetwork':
$this->crrnd = true; // Apple Addressbook.app does not cope with namespace redundancy
}
parent::HTTP_WebDAV_Server();
@ -136,6 +148,8 @@ class groupdav extends HTTP_WebDAV_Server
$this->principalURL = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:") .
'//' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '/';
}
$this->principalURL .= 'principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/';
$this->accounts = $GLOBALS['egw']->accounts;
}
/**
@ -162,12 +176,24 @@ class groupdav extends HTTP_WebDAV_Server
switch($app)
{
case 'calendar':
case 'infolog':
$dav[] = 2;
$dav[] = 'access-control';
$dav[] = 'calendar-access';
//$dav[] = 'calendar-schedule';
//$dav[] = 'calendar-proxy';
//$dav[] = 'calendar-avialibility';
//$dav[] = 'calendarserver-private-events';
break;
case 'addressbook':
$dav[] = 'addressbook';
$dav[] = 2;
$dav[] = 3;
$dav[] = 'access-control';
$dav[] = 'addressbook-access';
break;
default:
$dav[] = 2;
$dav[] = 'access-control';
$dav[] = 'calendar-access';
}
// not yet implemented: $dav[] = 'access-control';
}
@ -179,68 +205,92 @@ class groupdav extends HTTP_WebDAV_Server
* @param array return array for file properties
* @return bool true on success
*/
function PROPFIND(&$options, &$files,$method='PROPFIND')
function PROPFIND(&$options, &$files, $method='PROPFIND')
{
if ($this->debug) error_log(__CLASS__."::$method(".array2string($options,true).')');
if (groupdav_handler::get_agent() == 'cfnetwork' && // Apple Addressbook
$options['root']['name'] == 'propfind')
{
foreach ($options['props'] as $props)
{
if ($props['name'] == 'current-user-privilege-set')
{
if ($this->debug > 2) error_log(__CLASS__."::$method: current-user-privilege-set not implemented!");
return '501 Not Implemented';
}
}
}
// parse path in form [/account_lid]/app[/more]
if (!self::_parse_path($options['path'],$id,$app,$user,$user_prefix) && $app && !$user)
{
if ($this->debug > 1) error_log(__CLASS__."::$method: user=$user, app=$app, id=$id: 404 not found!");
if ($this->debug > 1) error_log(__CLASS__."::$method: user='$user', app='$app', id='$id': 404 not found!");
return '404 Not Found';
}
if ($this->debug > 1) error_log(__CLASS__."::$method: user=$user, app='$app', id=$id");
if ($this->debug > 1) error_log(__CLASS__."::$method: user='$user', app='$app', id='$id'");
$files = array('files' => array());
if (!$app) // root folder containing apps
if ($user)
{
if (empty($user_prefix))
{
$displayname = 'EGroupware (Cal|Card|Group)DAV server';
$account_lid = $this->accounts->id2name($user);
}
else
{
$displayname = $this->translation->convert($GLOBALS['egw_info']['user']['account_fullname'],$this->egw_charset,'utf-8');
$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
}
$account = $this->accounts->read($account_lid);
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8');
$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'].'/';
}
if ($options['depth'])
{
$displayname = 'EGroupware (Cal|Card|Group)DAV server';
}
// self url
$files['files'][] = array(
'path' => $user_prefix.'/',
'props' => array(
$props = array(
self::mkprop('displayname',$displayname),
self::mkprop('resourcetype','collection'),
self::mkprop('resourcetype',array(self::mkprop('collection',''))),
// adding the calendar extra property (calendar-home-set, etc.) here, allows apple iCal to "autodetect" the URL
self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/calendar/'))),
self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.$user_prefix.'calendar/'))),
self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
self::mkprop('href',$this->base_uri.$user_prefix))),
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
self::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$GLOBALS['egw_info']['user']['email']),
self::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))),
//self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
//self::mkprop('principal-collection-set',array(self::mkprop('href',$this->base_uri.'/principals/'))),
),
);
//$props = self::current_user_privilege_set($props);
$files['files'][] = array(
'path' => $path,
'props' => $props,
);
if ($options['depth'])
{
if (empty($user_prefix))
if (strlen($path) == 1) // GroupDAV Root
{
// principals collection
$files['files'][] = array(
'path' => '/principals/',
'props' => array(
self::mkprop('displayname',lang('Accounts')),
self::mkprop('resourcetype','collection'),
self::mkprop('resourcetype',array(self::mkprop('collection',''))),
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/calendar/'))),
//self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
),
);
// groups collection
$files['files'][] = array(
'path' => '/groups/',
'props' => array(
self::mkprop('displayname',lang('Groups')),
self::mkprop('resourcetype','collection'),
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/calendar/'))),
//self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.$user_prefix.'calendar/'))),
self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
self::mkprop('href',$this->base_uri.'/'))),
self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
),
);
}
@ -249,7 +299,7 @@ class groupdav extends HTTP_WebDAV_Server
if (!$GLOBALS['egw_info']['user']['apps'][$app]) continue; // no rights for the given app
$files['files'][] = array(
'path' => $user_prefix.'/'.$app.'/',
'path' => $path.$app.'/',
'props' => $this->_properties($app,false,$user),
);
}
@ -266,9 +316,9 @@ class groupdav extends HTTP_WebDAV_Server
if ($method != 'REPORT' && !$id) // no self URL for REPORT requests (only PROPFIND) or propfinds on an id
{
$files['files'][0] = array(
'path' => '/'.$app.'/',
'path' => $path.$app.'/',
// KAddressbook doubles the folder, if the self URL contains the GroupDAV/CalDAV resourcetypes
'props' => $this->_properties($app,$app=='addressbook'&&strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false),
'props' => $this->_properties($app,$app=='addressbook'&&strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false,$user),
);
}
if (isset($options['depth']) && !$options['depth'] && !$id)
@ -281,7 +331,7 @@ class groupdav extends HTTP_WebDAV_Server
}
return true; // depth 0 --> show only the self url
}
return $handler->propfind($options['path'],$options,$files,$user,$id);
return $handler->propfind($this->_slashify($options['path']),$options,$files,$user,$id);
}
return '501 Not Implemented';
}
@ -296,25 +346,52 @@ class groupdav extends HTTP_WebDAV_Server
*/
function _properties($app,$no_extra_types=false,$user=null)
{
if (!$user) $user = $GLOBALS['egw_info']['user']['account_fullname'];
$displayname = $this->translation->convert($GLOBALS['egw_info']['user']['account_fullname'],$this->egw_charset,'utf-8');
if ($this->debug) error_log(__CLASS__."::$method: user='$user', app='$app'");
if ($user)
{
$account_lid = $this->accounts->id2name($user);
}
else
{
$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
}
$account = $this->accounts->read($account_lid);
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8');
$props = array(
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
self::mkprop('owner',$displayname),
//self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
//self::mkprop('principal-collection-set',array(self::mkprop('href',$this->base_uri.'/principals/'))),
self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
self::mkprop('alternate-URI-set',array(
self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))),
self::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))),
self::mkprop('principal-collection-set',array(
self::mkprop('href',$this->base_uri.'/principals/users/'),
self::mkprop('href',$this->base_uri.'/principals/groups/'),
)),
);
switch ($app)
{
case 'calendar':
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/calendar/')));
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/calendar/')));
break;
case 'infolog':
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/infolog/')));
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/infolog/')));
$displayname = $this->translation->convert(lang($app).' '.
common::grab_owner_name($user),$this->egw_charset,'utf-8');
break;
default:
$displayname = $this->translation->convert(lang($app).' '.common::grab_owner_name($user),$this->egw_charset,'utf-8');
$props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/calendar/')));
$displayname = $this->translation->convert(lang($app).' '.
common::grab_owner_name($user),$this->egw_charset,'utf-8');
}
$props[] = self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
self::mkprop('href',$this->base_uri.'/'.$account_lid.'/')));
$props[] = self::mkprop('displayname',$displayname);
foreach((array)$this->root[$app] as $prop => $values)
@ -343,7 +420,9 @@ class groupdav extends HTTP_WebDAV_Server
}
if (method_exists($app.'_groupdav','extra_properties'))
{
$props = ExecMethod2($app.'_groupdav::extra_properties',$props,$this->base_uri);
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8');
$props = ExecMethod2($app.'_groupdav::extra_properties',$props,$displayname,$this->base_uri);
}
return $props;
}
@ -448,8 +527,7 @@ class groupdav extends HTTP_WebDAV_Server
$props = $this->props2array($file['props']);
//echo $file['path']; _debug_array($props);
$class = $class == 'row_on' ? 'row_off' : 'row_on';
$name = $this->_slashify(basename($this->_unslashify($file['path'])));
/*
if (substr($file['path'],-1) == '/')
{
$name = basename(substr($file['path'],0,-1)).'/';
@ -458,7 +536,7 @@ class groupdav extends HTTP_WebDAV_Server
{
$name = basename($file['path']);
}
*/
echo "\t<tr class='$class'>\n\t\t<td>$n</td>\n\t\t<td>".html::a_href(htmlspecialchars($name),'/groupdav.php'.$file['path'])."</td>\n";
echo "\t\t<td>".$props['DAV:getcontentlength']."</td>\n";
echo "\t\t<td>".(!empty($props['DAV:getlastmodified']) ? date('Y-m-d H:i:s',$props['DAV:getlastmodified']) : '')."</td>\n";
@ -761,7 +839,7 @@ class groupdav extends HTTP_WebDAV_Server
}
$parts = explode('/', $this->_unslashify($path));
if ($GLOBALS['egw']->accounts->name2id($parts[0]))
if ($this->accounts->name2id($parts[0]))
{
// /$user/$app/...
$user = array_shift($parts);
@ -772,7 +850,7 @@ class groupdav extends HTTP_WebDAV_Server
if ($user)
{
$user_prefix = '/'.$user;
$user = $GLOBALS['egw']->accounts->name2id($user,'account_lid',$app != 'addressbook' ? 'u' : null);
$user = $this->accounts->name2id($user,'account_lid',$app != 'addressbook' ? 'u' : null);
}
else
{
@ -785,13 +863,39 @@ class groupdav extends HTTP_WebDAV_Server
list($id) = explode('.',$id); // remove evtl. .ics extension
}
if (!($ok = $id && in_array($app,array('addressbook','calendar','infolog','principals','groups')) && $user))
{
$ok = $id && $user && in_array($app,array('addressbook','calendar','infolog','principals','groups'));
if ($this->debug)
{
error_log(__METHOD__."('$path') returning false: id=$id, app='$app', user=$user");
}
error_log(__METHOD__."('$path') returning " . ($ok ? 'true' : 'false') . ": id='$id', app='$app', user='$user', user_prefix='$user_prefix'");
}
return $ok;
}
/**
* Add the privileges of the current user
*
* @param array $props=array() regular props by the groupdav handler
* @return array
*/
static function current_user_privilege_set(array $props=array())
{
$props[] = HTTP_WebDAV_Server::mkprop('current-user-privilege-set',
array(HTTP_WebDAV_Server::mkprop('privilege',
array(//HTTP_WebDAV_Server::mkprop('all',''),
HTTP_WebDAV_Server::mkprop('read',''),
HTTP_WebDAV_Server::mkprop('read-free-busy',''),
//HTTP_WebDAV_Server::mkprop('read-current-user-privilege-set',''),
HTTP_WebDAV_Server::mkprop('bind',''),
HTTP_WebDAV_Server::mkprop('unbind',''),
HTTP_WebDAV_Server::mkprop('schedule-post',''),
HTTP_WebDAV_Server::mkprop('schedule-post-vevent',''),
HTTP_WebDAV_Server::mkprop('schedule-respond',''),
HTTP_WebDAV_Server::mkprop('schedule-respond-vevent',''),
HTTP_WebDAV_Server::mkprop('schedule-deliver',''),
HTTP_WebDAV_Server::mkprop('schedule-deliver-vevent',''),
HTTP_WebDAV_Server::mkprop('write',''),
HTTP_WebDAV_Server::mkprop('write-properties',''),
HTTP_WebDAV_Server::mkprop('write-content',''),
))));
return $props;
}
}

View File

@ -37,6 +37,12 @@ abstract class groupdav_handler
* @var translation
*/
var $translation;
/**
* Reference to the accounts class
*
* @var accounts
*/
var $accounts;
/**
* Translates method names into ACL bits
*
@ -88,7 +94,6 @@ abstract class groupdav_handler
*/
function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
{
//error_log(__METHOD__." called");
$this->app = $app;
if (!is_null($debug)) $this->debug = $debug;
$this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME'];
@ -99,13 +104,15 @@ abstract class groupdav_handler
}
else
{
$this->principalURL = $principalURL;
$this->principalURL = $principalURL.'principals/users/'.
$GLOBALS['egw_info']['user']['account_lid'].'/';
}
$this->agent = self::get_agent();
$this->translation =& $GLOBALS['egw']->translation;
$this->egw_charset = $this->translation->charset();
$this->accounts = $GLOBALS['egw']->accounts;
}
/**
@ -122,12 +129,13 @@ abstract class groupdav_handler
/**
* Propfind callback, if interator is used
*
* @param string $path
* @param array $filter
* @param array|boolean $start false=return all or array(start,num)
* @param int &$total
* @return array with "files" array with values for keys path and props
*/
function &propfind_callback(array $filter,$start,&$total) { }
function &propfind_callback($path, array $filter,$start,&$total) { }
/**
* Handle get request for an applications entry
@ -178,10 +186,11 @@ abstract class groupdav_handler
* Add extra properties for collections
*
* @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler
* @return array
*/
static function extra_properties(array $props=array(), $base_uri=null)
static function extra_properties(array $props=array(), $displayname, $base_uri=null)
{
return $props;
}
@ -203,7 +212,7 @@ abstract class groupdav_handler
// error_log(__METHOD__."(".array2string($entry).") Cant create etag!");
return false;
}
return '"'.$entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']).'"';
return 'EGw-'.$entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']).'-wGE';
}
/**
@ -214,7 +223,7 @@ abstract class groupdav_handler
*/
static function etag2value($etag)
{
list(,$val) = explode(':',substr($etag,1,-1),2);
list(,$val) = explode(':',substr($etag,4,-4),2);
return $val;
}
@ -278,6 +287,7 @@ abstract class groupdav_handler
*
* @static
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param int $user=null owner of the collection, default current user
* @param int $debug=null debug-level to set
* @param string $base_uri=null base url of handler
* @param string $principalURL=null pricipal url of handler
@ -297,7 +307,9 @@ abstract class groupdav_handler
$handler_cache[$app]->$debug = $debug;
$handler_cache[$app]->$base_uri = $base_uri;
$handler_cache[$app]->$principalURL = $principalURL;
if ($debug) error_log(__METHOD__."($app, $base_uri, $principalURL)");
if ($debug) error_log(__METHOD__."('$app', '$base_uri', '$principalURL')");
return $handler_cache[$app];
}
@ -317,6 +329,7 @@ abstract class groupdav_handler
$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
foreach(array(
'davkit' => 'davkit', // Apple iCal
'cfnetwork' => 'cfnetwork', // Apple Addressbook
'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net
'zideone' => 'zideone', // zideone outlook plugin
'lightning' => 'lightning', // Lighting (SOGo connector for addressbook)
@ -356,6 +369,13 @@ abstract class groupdav_handler
*/
class groupdav_propfind_iterator implements Iterator
{
/**
* current path
*
* @var string
*/
protected $path;
/**
* Handler to call for entries
*
@ -375,8 +395,16 @@ class groupdav_propfind_iterator implements Iterator
*
* @var array
*/
protected $common_files;
/**
* current chunk
*
* @var array
*/
protected $files;
/**
* Start value for callback
*
@ -397,6 +425,8 @@ class groupdav_propfind_iterator implements Iterator
*/
public $debug = false;
/**
/**
* Constructor
*
@ -404,13 +434,14 @@ class groupdav_propfind_iterator implements Iterator
* @param array $filter filter for propfind call
* @param array $files=null extra files/responses to return too
*/
public function __construct(groupdav_handler $handler,array $filter,array &$files=null)
public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=null)
{
if ($this->debug) error_log(__METHOD__."(,".array2string($filter).",)");
if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)");
$this->path = $path;
$this->handler = $handler;
$this->filter = $filter;
$this->files = $files;
$this->common_files = $files;
reset($this->files);
}
@ -422,7 +453,6 @@ class groupdav_propfind_iterator implements Iterator
public function current()
{
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files)));
return current($this->files);
}
@ -447,21 +477,20 @@ class groupdav_propfind_iterator implements Iterator
if (next($this->files) !== false)
{
if ($this->debug) error_log(__METHOD__."() returning TRUE");
return true;
}
if (is_array($this->files) && count($this->files) < self::CHUNK_SIZE) // less entries then asked --> no further available
{
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
return false; // no further entries
}
// try query further files via propfind callback of handler and store result in $this->files
$this->files = $this->handler->propfind_callback($this->filter,array($this->start,self::CHUNK_SIZE));
$this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
$this->start += self::CHUNK_SIZE;
reset($this->files);
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false));
return current($this->files) !== false;
}
@ -474,7 +503,8 @@ class groupdav_propfind_iterator implements Iterator
// query first set of files via propfind callback of handler and store result in $this->files
$this->start = 0;
$this->files = $this->handler->propfind_callback($this->filter,array($this->start,self::CHUNK_SIZE));
$files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
$this->files = $this->common_files + $files;
$this->start += self::CHUNK_SIZE;
reset($this->files);
}

View File

@ -7,7 +7,7 @@
* @package api
* @subpackage groupdav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
*/
@ -16,12 +16,6 @@
*/
class groupdav_principals extends groupdav_handler
{
/**
* Reference to the accounts class
*
* @var accounts
*/
var $accounts;
/**
* Constructor
@ -34,8 +28,6 @@ class groupdav_principals extends groupdav_handler
function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
{
parent::__construct($app,$debug,$base_uri,$principalURL);
$this->accounts = $GLOBALS['egw']->accounts;
}
/**
@ -49,10 +41,41 @@ class groupdav_principals extends groupdav_handler
*/
function propfind($path,$options,&$files,$user)
{
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id)");
list(,$principals,$type,$name,$rest) = explode('/',$path,5);
// /principals/users/$name/
// /users/$name/calendar-proxy-read/
// /users/$name/calendar-proxy-write/
// /groups/$name/
// /resources/$resource/
// /__uids__/$uid/.../
switch($type)
{
case 'users':
$files['files'] = $this->propfind_users($name,$rest,$options);
break;
case 'groups':
$files['files'] = $this->propfind_groups($name,$rest,$options);
break;
case 'resources':
$files['files'] = $this->propfind_resources($name,$rest,$options);
break;
case '__uids__':
$files['files'] = $this->propfind_uids($name,$rest,$options);
break;
case '':
$files['files'] = $this->propfind_principals($options);
break;
default:
return '404 Not Found';
}
if (!is_array($files['files']))
{
return $files['files'];
}
return true;
list(,,$id) = explode('/',$path);
if ($id && !($id = $this->accounts->id2name($id)))
{
return false;
@ -61,39 +84,269 @@ class groupdav_principals extends groupdav_handler
{
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8');
if ($options['root']['name'] == 'principal-search-property-set')
{
$props = array(HTTP_WebDAV_Server::mkprop('principal-search-property',
array(HTTP_WebDAV_Server::mkprop('prop',
array(HTTP_WebDAV_Server::mkprop('displayname',$displayname))
),
HTTP_WebDAV_Server::mkprop('description', 'Full name')))
);
}
else
{
$props = array(
HTTP_WebDAV_Server::mkprop('displayname',$displayname),
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)),
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
HTTP_WebDAV_Server::mkprop('alternate-URI-set',''),
HTTP_WebDAV_Server::mkprop('current-user-principal',array(HTTP_WebDAV_Server::mkprop('href',$this->principalURL))),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/calendar/'))),
HTTP_WebDAV_Server::mkprop('principal-URL',$this->base_uri.'/principals/'.$account['account_lid']),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',$this->base_uri.$account['account_lid'].'/calendar/'),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$account['account_email']),
//HTTP_WebDAV_Server::mkprop('principal-URL',array(HTTP_WebDAV_Server::mkprop('href',$this->principalURL))),
);
foreach($this->accounts->memberships($account['account_id']) as $gid => $group)
{
$props[] = HTTP_WebDAV_Server::mkprop('group-membership',$this->base_uri.'/groups/'.$group);
}
}
$files['files'][] = array(
'path' => '/principals/'.$account['account_lid'],
'props' => $props,
);
if ($this->debug > 1) error_log(__METHOD__."($path) path=/principals/".$account['account_lid'].', props='.array2string($props));
}
return true;
return files;
}
/**
* Do propfind in /pricipals/users
*
* @param string $name name of account or empty
* @param string $rest rest of path behind account-name
* @param array $options
* @return array|string array with files or HTTP error code
*/
protected function propfind_users($name,$rest,array $options)
{
//echo "<p>".__METHOD__."($name,$rest,".array2string($options).")</p>\n";
if (empty($name))
{
$files = array();
// add /pricipals/users/ entry
$files[] = $this->add_collection('/principals/users/',array(
HTTP_WebDAV_Server::mkprop('current-user-principal',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
));
if ($options['depth'])
{
// add all users
foreach($this->accounts->search(array('type' => 'accounts')) as $account)
{
$files[] = $this->add_account($account);
}
}
}
else
{
if (!($id = $GLOBALS['egw']->accounts->name2id($name,'account_lid','u')) ||
!($account = $GLOBALS['egw']->accounts->read($id)))
{
return '404 Not Found';
}
switch((string)$rest)
{
case '':
$files[] = $this->add_account($account);
$files[] = $this->add_collection('/principals/users/'.$account['account_lid'].'/calendar-proxy-read');
$files[] = $this->add_collection('/principals/users/'.$account['account_lid'].'/calendar-proxy-write');
break;
case 'calendar-proxy-read':
case 'calendar-proxy-write':
$files = array();
$files[] = $this->add_collection('/principals/users/'.$account['account_lid'].'/'.$rest);
// add proxys
break;
default:
return '404 Not Found';
}
}
return $files;
}
/**
* Do propfind in /pricipals/groups
*
* @param string $name name of group or empty
* @param string $rest rest of path behind account-name
* @param array $options
* @return array|string array with files or HTTP error code
*/
protected function propfind_groups($name,$rest,array $options)
{
//echo "<p>".__METHOD__."($name,$rest,".array2string($options).")</p>\n";
if (empty($name))
{
$files = array();
// add /pricipals/users/ entry
$files[] = $this->add_collection('/principals/groups/',array(
HTTP_WebDAV_Server::mkprop('current-user-principal',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/principals/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
));
if ($options['depth'])
{
// add all users
foreach($this->accounts->search(array('type' => 'groups')) as $account)
{
$files[] = $this->add_group($account);
}
}
}
else
{
if (!($id = $GLOBALS['egw']->accounts->name2id($name,'account_lid','g')) ||
!($account = $GLOBALS['egw']->accounts->read($id)))
{
return '404 Not Found';
}
switch((string)$rest)
{
case '':
$files[] = $this->add_group($account);
$files[] = $this->add_collection('/principals/groups/'.$account['account_lid'].'/calendar-proxy-read');
$files[] = $this->add_collection('/principals/groups/'.$account['account_lid'].'/calendar-proxy-write');
break;
case 'calendar-proxy-read':
case 'calendar-proxy-write':
$files = array();
$files[] = $this->add_collection('/principals/groups/'.$account['account_lid'].'/'.$rest);
// add proxys
break;
default:
return '404 Not Found';
}
}
return $files;
}
/**
* Add collection of a single account to a collection
*
* @param array $account
* @return array with values for keys 'path' and 'props'
*/
protected function add_account(array $account)
{
//echo "<p>".__METHOD__."(".array2string($account).")</p>\n";
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8');
$memberships = array();
foreach($this->accounts->memberships($account['account_id']) as $gid => $group)
{
if ($group)
{
$memberships[] = HTTP_WebDAV_Server::mkprop('href',
$this->base_uri.'/principals/groups/'.$group);
}
}
$props = array(
HTTP_WebDAV_Server::mkprop('displayname',$displayname),
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)),
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
HTTP_WebDAV_Server::mkprop('alternate-URI-set',array(
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$account['account_email']))),
HTTP_WebDAV_Server::mkprop('principal-URL',$this->base_uri.'/principals/users/'.$account['account_lid'].'/'),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/calendar/'))),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$account['account_email']))),
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
HTTP_WebDAV_Server::mkprop('group-member-ship', $memberships),
HTTP_WebDAV_Server::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
);
if ($this->debug > 1) error_log(__METHOD__."($path) path=/principals/users/".$account['account_lid'].', props='.array2string($props));
return array(
'path' => '/principals/users/'.$account['account_lid'].'/',
'props' => $props,
);
}
/**
* Add collection of a single group to a collection
*
* @param array $account
* @return array with values for keys 'path' and 'props'
*/
protected function add_group(array $account)
{
$displayname = $GLOBALS['egw']->translation->convert(lang('Group').' '.$account['account_lid'],
$GLOBALS['egw']->translation->charset(),'utf-8');
$members = array();
foreach($this->accounts->members($account['account_id']) as $gid => $user)
{
if ($user)
{
$members[] = HTTP_WebDAV_Server::mkprop('href',
$this->base_uri.'/principals/users/'.$user);
}
}
$props = array(
HTTP_WebDAV_Server::mkprop('displayname',$displayname),
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)),
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
HTTP_WebDAV_Server::mkprop('alternate-URI-set',''),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/calendar/'))),
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
HTTP_WebDAV_Server::mkprop('group-member-set', $members),
//HTTP_WebDAV_Server::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))),
);
$files['files'][] = array(
'path' => '/principals/groups/'.$account['account_lid'].'/',
'props' => $props,
);
if ($this->debug > 1) error_log(__METHOD__."($path) path=/principals/groups/".$account['account_lid'].', props='.array2string($props));
return array(
'path' => '/principals/groups/'.$account['account_lid'].'/',
'props' => $props,
);
}
/**
* Add a collection
*
* @param string $path
* @param array $props=array() extra properties 'resourcetype' is added anyway
* @return array
*/
protected function add_collection($path,$props=array())
{
//echo "<p>".__METHOD__."($path,".array($props).")</p>\n";
$props[] = HTTP_WebDAV_Server::mkprop('resourcetype',array(
HTTP_WebDAV_Server::mkprop('collection',''),
HTTP_WebDAV_Server::mkprop('resourcetype','principal'),
));
return array(
'path' => $path,
'props' => $props,
);
}
/**
* Do propfind of /pricipals
*
* @param string $name name of group or empty
* @param string $rest name of rest of path behind group-name
* @param array $options
* @return array|string array with files or HTTP error code
*/
protected function propfind_principals(array $options)
{
//echo "<p>".__METHOD__."(".array($options).")</p>\n";
$files = array();
$files[] = $this->add_collection('/principals/',array(
HTTP_WebDAV_Server::mkprop('current-user-principal',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/'))),
));
if ($options['depth'])
{
$options['depth'] = 0;
$files = array_merge($files,$this->propfind_users('','',$options));
$files = array_merge($files,$this->propfind_groups('','',$options));
//$files = array_merge($this->propfind_resources('','',$options));
//$files = array_merge($this->propfind_uids('','',$options));
}
return $files;
}
/**
@ -109,12 +362,12 @@ class groupdav_principals extends groupdav_handler
{
return $account;
}
$displayname = $GLOBALS['egw']->translation->convert(
$name = $GLOBALS['egw']->translation->convert(
trim($account['account_firstname'].' '.$account['account_lastname']),
$GLOBALS['egw']->translation->charset(),'utf-8');
$options['data'] = 'Principal: '.$account['account_lid'].
"\nURL: ".$this->base_uri.$options['path'].
"\nName: ".$displayname.
"\nName: ".$name.
"\nEmail: ".$account['account_email'].
"\nMemberships: ".implode(', ',$this->accounts->memberships($id))."\n";
$options['mimetype'] = 'text/plain; charset=utf-8';
@ -156,7 +409,8 @@ class groupdav_principals extends groupdav_handler
*/
function read($id)
{
return $this->accounts->read($id);
return false;
//return $this->accounts->read($id);
}
/**
@ -191,6 +445,6 @@ class groupdav_principals extends groupdav_handler
{
$account = $this->read($account);
}
return '"'.$account['account_id'].':'.md5(serialize($account)).'"';
return 'EGw-'.$account['account_id'].':'.md5(serialize($account)).'-wGE';
}
}

View File

@ -263,7 +263,8 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
// type and size (caller already made sure that path exists)
if (is_dir($fspath)) {
// directory (WebDAV collection)
$info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', 'collection');
$info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', array(
HTTP_WebDAV_Server::mkprop('collection', '')));
$info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', 'httpd/unix-directory');
} else {
// plain file (WebDAV resource)