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) 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)); 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 // 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'])) if (!($filter['address_data'] = $options['props'] == 'all' &&
$options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props']))
{ {
foreach($options['props'] as $prop) foreach($options['props'] as $prop)
{ {
@ -109,7 +110,7 @@ class addressbook_groupdav extends groupdav_handler
} }
} }
// return iterator, calling ourself to return result in chunks // 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; return true;
} }
@ -117,11 +118,12 @@ class addressbook_groupdav extends groupdav_handler
/** /**
* Callback for profind interator * Callback for profind interator
* *
* @param string $path
* @param array $filter * @param array $filter
* @param array|boolean $start=false false=return all or array(start,num) * @param array|boolean $start=false false=return all or array(start,num)
* @return array with "files" array with values for keys path and props * @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); $starttime = microtime(true);
@ -139,7 +141,7 @@ class addressbook_groupdav extends groupdav_handler
{ {
$props = array( $props = array(
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($contact)), 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 // getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
HTTP_WebDAV_Server::mkprop('getlastmodified', $contact['modified']), HTTP_WebDAV_Server::mkprop('getlastmodified', $contact['modified']),
); );
@ -147,19 +149,19 @@ class addressbook_groupdav extends groupdav_handler
{ {
$content = $handler->getVCard($contact,$this->charset,false); $content = $handler->getVCard($contact,$this->charset,false);
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content)); $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 else
{ {
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
} }
$files[] = array( $files[] = array(
'path' => self::get_path($contact), 'path' => $path.self::get_path($contact),
'props' => $props, '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; return $files;
} }
@ -266,14 +268,24 @@ class addressbook_groupdav extends groupdav_handler
*/ */
function put(&$options,$id,$user=null) 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); $ok = $this->_common_get_put_delete('PUT',$options,$id);
if (!is_null($ok) && !is_array($ok)) if (!is_null($ok) && !is_array($ok))
{ {
return $ok; return $ok;
} }
$handler = self::_get_handler(); $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)) if (!is_null($ok))
{ {
$contact['id'] = $ok['id']; $contact['id'] = $ok['id'];
@ -282,6 +294,10 @@ class addressbook_groupdav extends groupdav_handler
$contact['owner'] = $ok['owner']; $contact['owner'] = $ok['owner'];
$contact['private'] = $ok['private']; $contact['private'] = $ok['private'];
} }
else
{
$contact['owner'] = $user;
}
if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match); if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match);
if (!($save_ok = $this->bo->save($contact))) if (!($save_ok = $this->bo->save($contact)))
@ -295,13 +311,14 @@ class addressbook_groupdav extends groupdav_handler
} }
if (!isset($contact['etag'])) if (!isset($contact['etag']))
{ {
$contact = $this->read($contact['id']); $contact = $this->read($save_ok);
} }
header('ETag: '.$this->get_etag($contact)); header('ETag: '.$this->get_etag($contact));
if (is_null($ok)) 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"); if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): 201 Created");
return '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); $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 * @link http://www.mail-archive.com/calendarserver-users@lists.macosforge.org/msg01156.html
* *
* @param array $props=array() regular props by the groupdav handler * @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler * @param string $base_uri=null base url of handler
* @return array * @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) // supported reports (required property for CardDAV)
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array( $props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
HTTP_WebDAV_Server::mkprop('supported-report',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('report',
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget','')))), HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget','')))),
)); ));
//$props = self::current_user_privilege_set($props);
return $props; return $props;
} }
@ -392,7 +446,7 @@ class addressbook_groupdav extends groupdav_handler
{ {
return '412 Precondition Failed'; return '412 Precondition Failed';
} }
return $ok; //return $ok;
} }
/** /**

View File

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

View File

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

View File

@ -23,8 +23,6 @@ class calendar_groupdav extends groupdav_handler
*/ */
var $bo; var $bo;
const DAV = 'DAV:';
var $filter_prop2cal = array( var $filter_prop2cal = array(
'SUMMARY' => 'cal_title', 'SUMMARY' => 'cal_title',
'UID' => 'cal_uid', 'UID' => 'cal_uid',
@ -86,7 +84,7 @@ class calendar_groupdav extends groupdav_handler
if (!is_array($event)) $event = $this->bo->read($event); if (!is_array($event)) $event = $this->bo->read($event);
$name = $event[self::PATH_ATTRIBUTE]; $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 $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
} }
$files['files'][] = array( $files['files'][] = array(
'path' => self::get_path($event), 'path' => $path.self::get_path($event),
'props' => $props, 'props' => $props,
); );
} }
@ -447,12 +445,19 @@ class calendar_groupdav extends groupdav_handler
if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace()); if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace());
return $event; 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']); $vCalendar = htmlspecialchars_decode($options['content']);
if (!($cal_id = $handler->importVCal($vCalendar, is_numeric($id) ? $id : -1, 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"); if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false");
return '403 Forbidden'; return '403 Forbidden';
@ -461,15 +466,11 @@ class calendar_groupdav extends groupdav_handler
header('ETag: '.$this->get_etag($cal_id)); header('ETag: '.$this->get_etag($cal_id));
if (is_null($event) || !$return_no_access) // let lightning think the event is added 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)); 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'; 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; return true;
} }
@ -580,8 +581,7 @@ class calendar_groupdav extends groupdav_handler
*/ */
function read($id) 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:");
if ($this->debug > 1) error_log("bo-ical read :$id:");//njv:
return $this->bo->read($id,null,false,'server'); return $this->bo->read($id,null,false,'server');
} }
@ -622,12 +622,12 @@ class calendar_groupdav extends groupdav_handler
{ {
if ($recurrence['reference']) // ignore series master 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"); //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()) static function current_user_privilege_set(array $props=array())
{ {
$props[] = HTTP_WebDAV_Server::mkprop(self::DAV,'current-user-privilege-set', $props[] = HTTP_WebDAV_Server::mkprop(groupdav::DAV,'current-user-privilege-set',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'privilege', array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'privilege',
array(//HTTP_WebDAV_Server::mkprop(self::DAV,'all',''), array(//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'all',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'read',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read',''),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''), HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''),
//HTTP_WebDAV_Server::mkprop(self::DAV,'read-current-user-privilege-set',''), //HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read-current-user-privilege-set',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'bind',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'bind',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'unbind',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'unbind',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-post',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-post-vevent',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post-vevent',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-respond',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-respond-vevent',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond-vevent',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-deliver',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-deliver-vevent',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver-vevent',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'write',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'write-properties',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-properties',''),
HTTP_WebDAV_Server::mkprop(self::DAV,'write-content',''), HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-content',''),
)))); ))));
return $props; return $props;
} }
@ -675,42 +675,41 @@ class calendar_groupdav extends groupdav_handler
* Add extra properties for calendar collections * Add extra properties for calendar collections
* *
* @param array $props=array() regular props by the groupdav handler * @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler * @param string $base_uri=null base url of handler
* @return array * @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 // 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); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
// BOX URLs of the current user // BOX URLs of the current user
/* /*
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-inbox-URL', $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-inbox-URL',
array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/'))); array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/')));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-outbox-URL', $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', $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', $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', $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 // 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 // supported components, currently only VEVENT
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array( $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' => 'VEVENT')),
// HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), // not yet supported // HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), // not yet supported
)); ));
/*
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array( $props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
HTTP_WebDAV_Server::mkprop('supported-report',array( HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report', HTTP_WebDAV_Server::mkprop('report',
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget')))))); HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget'))))));
*/
//$props = self::current_user_privilege_set($props); //$props = self::current_user_privilege_set($props);
return $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, * @param int $recur_date=0 if set, import the recurrence at this timestamp,
* default 0 => import whole series (or events, if not recurring) * default 0 => import whole series (or events, if not recurring)
* @param string $principalURL='' Used for CalDAV imports * @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 * @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(); if (!is_array($this->supportedFields)) $this->setSupportedFields();
@ -1081,7 +1082,7 @@ class calendar_ical extends calendar_boupdate
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ 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); . array2string($event)."\n",3,$this->logfile);
} }
$updated_id = false; $updated_id = false;
@ -1204,9 +1205,20 @@ class calendar_ical extends calendar_boupdate
$event['non_blocking'] = 1; $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 // check if an owner is set and the current user has add rights
// for that owners calendar; if not set the current user // 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'])) || !$this->check_perms(EGW_ACL_ADD, 0, $event['owner']))
{ {
$event['owner'] = $this->user; $event['owner'] = $this->user;

View File

@ -59,6 +59,18 @@ class HTTP_WebDAV_Server
*/ */
var $client_require_href_as_url; 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 * URI path for this request
* *
@ -229,11 +241,18 @@ class HTTP_WebDAV_Server
$this->$wrapper(); // call method by name $this->$wrapper(); // call method by name
} else { // method not found/implemented } else { // method not found/implemented
if ($this->_SERVER["REQUEST_METHOD"] == "LOCK") { if ($this->_SERVER["REQUEST_METHOD"] == "LOCK") {
$this->http_status("412 Precondition failed"); $error = '412 Precondition failed';
;
} else { } else {
$this->http_status("405 Method not allowed"); $error = '405 Method not allowed';
header("Allow: ".join(", ", $this->_allow())); // tell client what's 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 * ACL implementation
@ -585,7 +604,7 @@ class HTTP_WebDAV_Server
$options['other'] = $propinfo->other; $options['other'] = $propinfo->other;
// call user handler // call user handler
if (!$this->$handler($options, $files)) { if (!($retval =$this->$handler($options, $files))) {
$files = array("files" => array()); $files = array("files" => array());
if (method_exists($this, "checkLock")) { if (method_exists($this, "checkLock")) {
// is locked? // is locked?
@ -611,27 +630,43 @@ class HTTP_WebDAV_Server
} }
} }
// now we generate the reply header ... // now we generate the reply header ...
if ($propinfo->root['name'] == 'principal-search-property-set') if ($retval === true)
{ {
$this->http_status('200 OK'); $this->http_status('207 Multi-Status');
} }
else else
{ {
$this->http_status('207 Multi-Status'); $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"'); header('Content-Type: text/xml; charset="utf-8"');
// ... and payload // ... and payload
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
if ($propinfo->root['name'] == 'principal-search-property-set') echo ($this->crrnd?'<':'<D:')."multistatus xmlns:D=\"DAV:\">\n";
{
echo "<D:principal-search-property-set xmlns:D=\"DAV:\">\n";
}
else
{
echo "<D:multistatus xmlns:D=\"DAV:\">\n";
}
// using an ArrayIterator to prevent foreach from copying the array, // using an ArrayIterator to prevent foreach from copying the array,
// as we cant loop by reference, when an iterator is given in $files['files'] // 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']; $path = $file['path'];
if (!is_string($path) || $path==="") continue; 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 /* TODO right now the user implementation has to make sure
collections end in a slash, this should be done in here 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!) // path needs to be urlencoded (only basic version of this class!)
$href = $this->_urlencode($this->_mergePathes($this->base_uri, $path)); $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) // report all found properties and their values (if any)
if (isset($file["props"]) && is_array($file["props"])) { if (isset($file["props"]) && is_array($file["props"])) {
if ($propinfo->root['name'] != 'principal-search-property-set') echo ' <'.($this->crrnd?'':'D:')."propstat>\n";
{ echo ' <'.($this->crrnd?'':'D:')."prop>\n";
echo " <D:propstat>\n";
echo " <D:prop>\n";
}
foreach ($file["props"] as &$prop) { foreach ($file["props"] as &$prop) {
if (!is_array($prop)) continue; if (!is_array($prop)) continue;
@ -773,7 +820,7 @@ class HTTP_WebDAV_Server
if (!isset($prop["val"]) || $prop["val"] === "" || $prop["val"] === false) { if (!isset($prop["val"]) || $prop["val"] === "" || $prop["val"] === false) {
// empty properties (cannot use empty() for check as "0" is a legal value here) // empty properties (cannot use empty() for check as "0" is a legal value here)
if ($prop["ns"]=="DAV:") { if ($prop["ns"]=="DAV:") {
echo " <D:$prop[name]/>\n"; echo ' <'.($this->crrnd?'':'D:')."$prop[name]/>\n";
} else if (!empty($prop["ns"])) { } else if (!empty($prop["ns"])) {
echo " <".$ns_hash[$prop["ns"]].":$prop[name]/>\n"; echo " <".$ns_hash[$prop["ns"]].":$prop[name]/>\n";
} else { } else {
@ -783,61 +830,34 @@ class HTTP_WebDAV_Server
// some WebDAV properties need special treatment // some WebDAV properties need special treatment
switch ($prop["name"]) { switch ($prop["name"]) {
case "creationdate": 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']) . gmdate("Y-m-d\\TH:i:s\\Z", $prop['val'])
. "</D:creationdate>\n"; . '</'.($this->crrnd?'':'D:')."creationdate>\n";
break; break;
case "getlastmodified": 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']) . gmdate("D, d M Y H:i:s ", $prop['val'])
. "GMT</D:getlastmodified>\n"; . "GMT</".($this->crrnd?'':'D:')."getlastmodified>\n";
break; 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": case "supportedlock":
echo " <D:supportedlock>$prop[val]</D:supportedlock>\n"; echo ' <'.($this->crrnd?'':'D:')."supportedlock>$prop[val]</".($this->crrnd?'':'D:')."supportedlock>\n";
break; break;
case "lockdiscovery": case "lockdiscovery":
echo " <D:lockdiscovery>\n"; echo ' <'.($this->crrnd?'':'D:')."lockdiscovery>\n";
echo $prop["val"]; echo $prop["val"];
echo " </D:lockdiscovery>\n"; echo ' </'.($this->crrnd?'':'D:')."lockdiscovery>\n";
break; break;
default: default:
echo " <D:$prop[name]>". if (is_array($prop['val']))
(is_array($prop['val']) ? {
$this->_hierarchical_prop_encode($prop['val']) : $val = $this->_hierarchical_prop_encode($prop['val']);
$this->_prop_encode(htmlspecialchars($prop['val']))). } elseif (isset($prop['raw'])) {
"</D:$prop[name]>\n"; $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; break;
} }
} else { } else {
@ -850,53 +870,75 @@ class HTTP_WebDAV_Server
$vals = $extra_ns = ''; $vals = $extra_ns = '';
foreach($prop['val'] as $subprop) foreach($prop['val'] as $subprop)
{ {
if ($subprop['ns'] && $subprop['ns'] != 'DAV:') { if ($subprop['ns'] && $subprop['ns'] != 'DAV:') {
// register property namespace if not known yet // register property namespace if not known yet
if (!isset($ns_hash[$subprop['ns']])) { if (!isset($ns_hash[$subprop['ns']])) {
$ns_name = "ns".(count($ns_hash) + 1); $ns_name = "ns".(count($ns_hash) + 1);
$ns_hash[$subprop['ns']] = $ns_name; $ns_hash[$subprop['ns']] = $ns_name;
} else { } else {
$ns_name = $ns_hash[$subprop['ns']]; $ns_name = $ns_hash[$subprop['ns']];
} }
if (strchr($extra_ns,$extra=' xmlns:'.$ns_name.'="'.$subprop['ns'].'"') === false) { if (strchr($extra_ns,$extra=' xmlns:'.$ns_name.'="'.$subprop['ns'].'"') === false) {
$extra_ns .= $extra; $extra_ns .= $extra;
} }
$ns_name .= ':'; $ns_name .= ':';
} elseif ($subprop['ns'] == 'DAV:') { } elseif ($subprop['ns'] == 'DAV:') {
$ns_name = 'D:'; $ns_name = 'D:';
} else { } else {
$ns_name = ''; $ns_name = '';
} }
$vals .= "<$ns_name$subprop[name]"; $vals .= "<$ns_name$subprop[name]";
if (is_array($subprop['val'])) // val contains only attributes, no value if (is_array($subprop['val'])) // val contains only attributes, no value
{ {
foreach($subprop['val'] as $attr => $val) foreach($subprop['val'] as $attr => $val)
{ {
$vals .= ' '.$attr.'="'.htmlspecialchars($val).'"'; $vals .= ' '.$attr.'="'.htmlspecialchars($val).'"';
} }
$vals .= '/>'; $vals .= '/>';
} }
else else
{ {
$vals .= '>'.htmlspecialchars($subprop['val'])."</$ns_name$subprop[name]>"; $vals .= '>';
} if (isset($subprop['raw'])) {
} $vals .= '<![CDATA['.$subprop['val'].']]>';
echo " <".$ns_hash[$prop['ns']].":$prop[name]$extra_ns>$vals</".$ns_hash[$prop['ns']].":$prop[name]>\n"; } else {
} $vals .= htmlspecialchars($subprop['val']);
else }
// properties from namespaces != "DAV:" or without any namespace $vals .= "</$ns_name$subprop[name]>";
if ($prop["ns"]) { }
echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]>" }
. $this->_prop_encode(htmlspecialchars($prop['val'])) echo ' <'.$ns_hash[$prop['ns']].":$prop[name]$extra_ns>$vals</".$ns_hash[$prop['ns']].":$prop[name]>\n";
. "</" . $ns_hash[$prop["ns"]] . ":$prop[name]>\n";
} else { } else {
echo " <$prop[name] xmlns=\"\">" if ($prop['raw'])
. $this->_prop_encode(htmlspecialchars($prop['val'])) {
. "</$prop[name]>\n"; $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 ($propinfo->root['name'] != 'principal-search-property-set')
if ($this->crrnd)
{
echo " </prop>\n";
echo " <status>HTTP/1.1 200 OK</status>\n";
echo " </propstat>\n";
}
else
{ {
echo " </D:prop>\n"; echo " </D:prop>\n";
echo " <D:status>HTTP/1.1 200 OK</D:status>\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 // now report all properties requested but not found
if (isset($file["noprops"])) { if (isset($file["noprops"])) {
echo " <D:propstat>\n"; echo ' <'.($this->crrnd?'':'D:')."propstat>\n";
echo " <D:prop>\n"; echo ' <'.($this->crrnd?'':'D:')."prop>\n";
foreach ($file["noprops"] as &$prop) { foreach ($file["noprops"] as &$prop) {
if ($prop["ns"] == "DAV:") { if ($prop["ns"] == "DAV:") {
echo " <D:$prop[name]/>\n"; echo ' <'.($this->crrnd?'':'D:')."$prop[name]/>\n";
} else if ($prop["ns"] == "") { } else if ($prop["ns"] == "") {
echo " <$prop[name] xmlns=\"\"/>\n"; echo " <$prop[name] xmlns=\"\"/>\n";
} else { } else {
@ -919,23 +961,24 @@ class HTTP_WebDAV_Server
} }
} }
echo " </D:prop>\n"; if ($this->crrnd)
echo " <D:status>HTTP/1.1 404 Not Found</D:status>\n"; {
echo " </D:propstat>\n"; 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"; echo ' </'.($this->crrnd?'':'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:')."multistatus>\n";
} }
@ -973,24 +1016,24 @@ class HTTP_WebDAV_Server
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
echo "<D:multistatus xmlns:D=\"DAV:\">\n"; echo "<D:multistatus xmlns:D=\"DAV:\">\n";
echo " <D:response>\n"; echo ' <'.($this->crrnd?'':'D:')."response>\n";
echo " <D:href>".$this->_urlencode($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path))."</D:href>\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) { foreach ($options["props"] as $prop) {
echo " <D:propstat>\n"; echo ' <'.($this->crrnd?'':'D:')."propstat>\n";
echo " <D:prop><$prop[name] xmlns=\"$prop[ns]\"/></D:prop>\n"; echo ' <'.($this->crrnd?'':'D:')."prop><$prop[name] xmlns=\"$prop[ns]\"/></".($this->crrnd?'':'D:')."prop>\n";
echo " <D:status>HTTP/1.1 $prop[status]</D:status>\n"; echo ' <'.($this->crrnd?'':'D:')."status>HTTP/1.1 $prop[status]</".($this->crrnd?'':'D:')."status>\n";
echo " </D:propstat>\n"; echo ' </'.($this->crrnd?'':'D:')."propstat>\n";
} }
if ($responsedescr) { if ($responsedescr) {
echo " <D:responsedescription>". echo ' <'.($this->crrnd?'':'D:')."responsedescription>".
$this->_prop_encode(htmlspecialchars($responsedescr)). $this->_prop_encode(htmlspecialchars($responsedescr)).
"</D:responsedescription>\n"; '</'.($this->crrnd?'':'D:')."responsedescription>\n";
} }
echo " </D:response>\n"; echo ' </'.($this->crrnd?'':'D:')."response>\n";
echo "</D:multistatus>\n"; echo '</'.($this->crrnd?'':'D:')."multistatus>\n";
} else { } else {
$this->http_status("423 Locked"); $this->http_status("423 Locked");
} }
@ -1580,17 +1623,17 @@ class HTTP_WebDAV_Server
header("Lock-Token: <$options[locktoken]>"); header("Lock-Token: <$options[locktoken]>");
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
echo "<D:prop xmlns:D=\"DAV:\">\n"; echo "<D:prop xmlns:D=\"DAV:\">\n";
echo " <D:lockdiscovery>\n"; echo ' <'.($this->crrnd?'':'D:')."lockdiscovery>\n";
echo " <D:activelock>\n"; echo ' <'.($this->crrnd?'':'D:')."activelock>\n";
echo " <D:lockscope><D:$options[scope]/></D:lockscope>\n"; echo ' <'.($this->crrnd?'':'D:')."lockscope><D:$options[scope]/></".($this->crrnd?'':'D:')."lockscope>\n";
echo " <D:locktype><D:$options[type]/></D:locktype>\n"; echo ' <'.($this->crrnd?'':'D:')."locktype><D:$options[type]/></".($this->crrnd?'':'D:')."locktype>\n";
echo " <D:depth>$options[depth]</D:depth>\n"; echo ' <'.($this->crrnd?'':'D:')."depth>$options[depth]</".($this->crrnd?'':'D:')."depth>\n";
echo " <D:owner>$options[owner]</D:owner>\n"; echo ' <'.($this->crrnd?'':'D:')."owner>$options[owner]</".($this->crrnd?'':'D:')."owner>\n";
echo " <D:timeout>$timeout</D:timeout>\n"; echo ' <'.($this->crrnd?'':'D:')."timeout>$timeout</".($this->crrnd?'':'D:')."timeout>\n";
echo " <D:locktoken><D:href>$options[locktoken]</D:href></D:locktoken>\n"; echo ' <'.($this->crrnd?'':'D:')."locktoken><D:href>$options[locktoken]</D:href></".($this->crrnd?'':'D:')."locktoken>\n";
echo " </D:activelock>\n"; echo ' </'.($this->crrnd?'':'D:')."activelock>\n";
echo " </D:lockdiscovery>\n"; echo ' </'.($this->crrnd?'':'D:')."lockdiscovery>\n";
echo "</D:prop>\n\n"; echo '</'.($this->crrnd?'':'D:')."prop>\n\n";
} }
} }
@ -1627,9 +1670,9 @@ class HTTP_WebDAV_Server
// }}} // }}}
// {{{ http_UNLOCK() // {{{ http_ACL()
/** /**
* ACL method handler * ACL method handler
* *
* @param void * @param void
@ -1660,9 +1703,9 @@ class HTTP_WebDAV_Server
$content .= "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; $content .= "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$content .= "<D:error xmlns:D=\"DAV:\"> \n"; $content .= "<D:error xmlns:D=\"DAV:\"> \n";
foreach ($options['errors'] as $violation) { 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)); header("Content-length: ".$this->bytes($content));
if ($content) echo $options['content']; if ($content) echo $options['content'];
@ -1765,20 +1808,27 @@ class HTTP_WebDAV_Server
* @param string XML namespace (optional) * @param string XML namespace (optional)
* @param string property name * @param string property name
* @param string property value * @param string property value
* @praram boolen property raw-flag
* @return array property array * @return array property array
*/ */
function mkprop() function mkprop()
{ {
$args = func_get_args(); $args = func_get_args();
if (count($args) == 3) { switch (count($args)) {
return array("ns" => $args[0], case 4:
"name" => $args[1], return array('ns' => $args[0],
"val" => $args[2]); 'name' => $args[1],
} else { 'val' => $args[2],
return array("ns" => "DAV:", 'raw' => true);
"name" => $args[0], case 3:
"val" => $args[1]); return array('ns' => $args[0],
} 'name' => $args[1],
'val' => $args[2]);
default:
return array("ns" => "DAV:",
"name" => $args[0],
"val" => $args[1]);
}
} }
// {{{ _check_auth // {{{ _check_auth
@ -2125,16 +2175,32 @@ class HTTP_WebDAV_Server
} }
// genreate response block // genreate response block
$activelocks.= " if ($this->crrnd)
<D:activelock> {
<D:lockscope><D:$lock[scope]/></D:lockscope> $activelocks.= "
<D:locktype><D:$lock[type]/></D:locktype> <activelock>
<D:depth>$lock[depth]</D:depth> <lockscope><$lock[scope]/></lockscope>
<D:owner>$lock[owner]</D:owner> <locktype><$lock[type]/></locktype>
<D:timeout>$timeout</D:timeout> <depth>$lock[depth]</depth>
<D:locktoken><D:href>$lock[token]</D:href></D:locktoken> <owner>$lock[owner]</owner>
</D:activelock> <timeout>$timeout</timeout>
"; <locktoken><href>$lock[token]</href></locktoken>
</activelock>
";
}
else
{
$activelocks.= "
<D:activelock>
<D:lockscope><D:$lock[scope]/></D:lockscope>
<D:locktype><D:$lock[type]/></D:locktype>
<D:depth>$lock[depth]</D:depth>
<D:owner>$lock[owner]</D:owner>
<D:timeout>$timeout</D:timeout>
<D:locktoken><D:href>$lock[token]</D:href></D:locktoken>
</D:activelock>
";
}
} }
// return generated response // return generated response

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) // type and size (caller already made sure that path exists)
if (is_dir($fspath)) { if (is_dir($fspath)) {
// directory (WebDAV collection) // 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"); $info["props"][] = $this->mkprop("getcontenttype", "httpd/unix-directory");
} else { } else {
// plain file (WebDAV resource) // plain file (WebDAV resource)

View File

@ -420,13 +420,13 @@ class infolog_bo
/** /**
* Read an infolog entry specified by $info_id * 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, * @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 * 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, * @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
* 'array'=array or string with date-format * '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') 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); if (!is_array($info)) $info = $this->bo->read($info);
$name = $info[self::PATH_ATTRIBUTE]; $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); $starttime = microtime(true);
$myself = ($user == $GLOBALS['egw_info']['user']['account_id']);
if ($options['filters']) if ($options['filters'])
{ {
@ -113,14 +115,17 @@ class infolog_groupdav extends groupdav_handler
$filter = array( $filter = array(
'info_type' => 'task', 'info_type' => 'task',
); );
//if (!$myself) $filter['info_owner'] = $user;
if ($id) $filter['info_id'] = $id; // propfind on a single id if ($id) $filter['info_id'] = $id; // propfind on a single id
// ToDo: add parameter to only return id & etag // ToDo: add parameter to only return id & etag
if (($tasks =& $this->bo->search($params=array( if (($tasks =& $this->bo->search($params=array(
'order' => 'info_datemodified', 'order' => 'info_datemodified',
'sort' => 'DESC', '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 // filter own: entries the user own or is responsible for
'date_format' => 'server', 'date_format' => 'server',
'col_filter' => $filter, '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 $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
} }
$files['files'][] = array( $files['files'][] = array(
'path' => self::get_path($task), 'path' => $path.self::get_path($task),
'props' => $props, 'props' => $props,
); );
} }
@ -193,8 +198,11 @@ class infolog_groupdav extends groupdav_handler
{ {
return $ok; return $ok;
} }
$handler = $this->_get_handler(); $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"); if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false");
return '403 Forbidden'; return '403 Forbidden';
@ -202,7 +210,8 @@ class infolog_groupdav extends groupdav_handler
header('ETag: '.$this->get_etag($info_id)); header('ETag: '.$this->get_etag($info_id));
if (is_null($ok) || $id != $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 '201 Created';
} }
return true; return true;
@ -263,36 +272,38 @@ class infolog_groupdav extends groupdav_handler
{ {
return false; return false;
} }
return '"'.$info['info_id'].':'.$info['info_datemodified'].'"'; return 'EGw-'.$info['info_id'].':'.$info['info_datemodified'].'-wGE';
} }
/** /**
* Add extra properties for calendar collections * Add extra properties for calendar collections
* *
* @param array $props=array() regular props by the groupdav handler * @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler * @param string $base_uri=null base url of handler
* @return array * @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 // calendar description
$displayname = $GLOBALS['egw']->translation->convert(lang('Tasks of') . ' ' . $displayname = $GLOBALS['egw']->translation->convert(lang('Tasks of') . ' ' .
$GLOBALS['egw_info']['user']['account_fullname'], $displayname,
$GLOBALS['egw']->translation->charset(),'utf-8'); $GLOBALS['egw']->translation->charset(),'utf-8');
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname);
// email of the current user, see caldav-sheduling draft // 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 // supported components, currently only VEVENT
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array( $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' => 'VEVENT')),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')),
)); ));
/*
$props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array( $props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array(
HTTP_WebDAV_Server::mkprop('supported-report',array( HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report', HTTP_WebDAV_Server::mkprop('report',
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget')))))); HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget'))))));
*/
return $props; return $props;
} }

View File

@ -380,9 +380,10 @@ class infolog_ical extends infolog_bo
* @param string $_vcalData * @param string $_vcalData
* @param int $_taskID=-1 info_id, default -1 = new entry * @param int $_taskID=-1 info_id, default -1 = new entry
* @param boolean $merge=false merge data with existing 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 * @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; if (!($taskData = $this->vtodotoegw($_vcalData,$_taskID))) return false;
@ -397,6 +398,11 @@ class infolog_ical extends infolog_bo
$taskData['info_datecompleted'] = 0; $taskData['info_datecompleted'] = 0;
} }
if (!is_null($user))
{
$taskData['info_responsible'] = array($user);
}
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" .

View File

@ -36,6 +36,10 @@ require_once('HTTP/WebDAV/Server.php');
*/ */
class groupdav extends HTTP_WebDAV_Server class groupdav extends HTTP_WebDAV_Server
{ {
/**
* DAV namespace
*/
const DAV = 'DAV:';
/** /**
* GroupDAV namespace * GroupDAV namespace
*/ */
@ -107,6 +111,12 @@ class groupdav extends HTTP_WebDAV_Server
* @var string * @var string
*/ */
var $principalURL; var $principalURL;
/**
* Reference to the accounts class
*
* @var accounts
*/
var $accounts;
function __construct() 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 case 'davkit': // iCal app in OS X 10.6 created wrong request, if full url given
$this->client_require_href_as_url = false; $this->client_require_href_as_url = false;
break; break;
case 'cfnetwork':
$this->crrnd = true; // Apple Addressbook.app does not cope with namespace redundancy
} }
parent::HTTP_WebDAV_Server(); parent::HTTP_WebDAV_Server();
@ -136,6 +148,8 @@ class groupdav extends HTTP_WebDAV_Server
$this->principalURL = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:") . $this->principalURL = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:") .
'//' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '/'; '//' . $_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) switch($app)
{ {
case 'calendar': case 'calendar':
case 'infolog': $dav[] = 2;
$dav[] = 'access-control';
$dav[] = 'calendar-access'; $dav[] = 'calendar-access';
//$dav[] = 'calendar-schedule';
//$dav[] = 'calendar-proxy';
//$dav[] = 'calendar-avialibility';
//$dav[] = 'calendarserver-private-events';
break; break;
case 'addressbook': case 'addressbook':
$dav[] = 'addressbook'; $dav[] = 2;
$dav[] = 3;
$dav[] = 'access-control';
$dav[] = 'addressbook-access';
break; break;
default:
$dav[] = 2;
$dav[] = 'access-control';
$dav[] = 'calendar-access';
} }
// not yet implemented: $dav[] = 'access-control'; // not yet implemented: $dav[] = 'access-control';
} }
@ -179,77 +205,101 @@ class groupdav extends HTTP_WebDAV_Server
* @param array return array for file properties * @param array return array for file properties
* @return bool true on success * @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 ($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] // parse path in form [/account_lid]/app[/more]
if (!self::_parse_path($options['path'],$id,$app,$user,$user_prefix) && $app && !$user) 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'; 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'");
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');
$files = array('files' => array()); $files = array('files' => array());
$path = $user_prefix = $this->_slashify($user_prefix);
if (!$app) // root folder containing apps if (!$app) // user root folder containing apps
{ {
if (empty($user_prefix)) if (empty($user_prefix))
{
$user_prefix = '/'.$GLOBALS['egw_info']['user']['account_lid'].'/';
}
if ($options['depth'])
{ {
$displayname = 'EGroupware (Cal|Card|Group)DAV server'; $displayname = 'EGroupware (Cal|Card|Group)DAV server';
} }
else
{
$displayname = $this->translation->convert($GLOBALS['egw_info']['user']['account_fullname'],$this->egw_charset,'utf-8');
}
// self url // self url
$files['files'][] = array( $props = array(
'path' => $user_prefix.'/',
'props' => array(
self::mkprop('displayname',$displayname), 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 // 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('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-URL',array(self::mkprop('href',$this->principalURL))),
//self::mkprop('principal-collection-set',array(self::mkprop('href',$this->base_uri.'/principals/'))), //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 ($options['depth'])
{ {
if (empty($user_prefix)) if (strlen($path) == 1) // GroupDAV Root
{ {
// principals collection // principals collection
$files['files'][] = array( $files['files'][] = array(
'path' => '/principals/', 'path' => '/principals/',
'props' => array( 'props' => array(
self::mkprop('displayname',lang('Accounts')), 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('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(groupdav::CALDAV,'calendar-home-set',array(
//self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))), 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))),
), ),
); );
// 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))),
),
);
} }
foreach($this->root as $app => $data) foreach($this->root as $app => $data)
{ {
if (!$GLOBALS['egw_info']['user']['apps'][$app]) continue; // no rights for the given app if (!$GLOBALS['egw_info']['user']['apps'][$app]) continue; // no rights for the given app
$files['files'][] = array( $files['files'][] = array(
'path' => $user_prefix.'/'.$app.'/', 'path' => $path.$app.'/',
'props' => $this->_properties($app,false,$user), '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 if ($method != 'REPORT' && !$id) // no self URL for REPORT requests (only PROPFIND) or propfinds on an id
{ {
$files['files'][0] = array( $files['files'][0] = array(
'path' => '/'.$app.'/', 'path' => $path.$app.'/',
// KAddressbook doubles the folder, if the self URL contains the GroupDAV/CalDAV resourcetypes // 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) 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 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'; return '501 Not Implemented';
} }
@ -296,25 +346,52 @@ class groupdav extends HTTP_WebDAV_Server
*/ */
function _properties($app,$no_extra_types=false,$user=null) function _properties($app,$no_extra_types=false,$user=null)
{ {
if (!$user) $user = $GLOBALS['egw_info']['user']['account_fullname']; if ($this->debug) error_log(__CLASS__."::$method: user='$user', app='$app'");
$displayname = $this->translation->convert($GLOBALS['egw_info']['user']['account_fullname'],$this->egw_charset,'utf-8'); 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( $props = array(
self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))), self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))),
self::mkprop('owner',$displayname), self::mkprop('owner',$displayname),
//self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))), 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('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) switch ($app)
{ {
case 'calendar': 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; break;
case 'infolog': 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: 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); $props[] = self::mkprop('displayname',$displayname);
foreach((array)$this->root[$app] as $prop => $values) 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')) 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; return $props;
} }
@ -448,8 +527,7 @@ class groupdav extends HTTP_WebDAV_Server
$props = $this->props2array($file['props']); $props = $this->props2array($file['props']);
//echo $file['path']; _debug_array($props); //echo $file['path']; _debug_array($props);
$class = $class == 'row_on' ? 'row_off' : 'row_on'; $class = $class == 'row_on' ? 'row_off' : 'row_on';
$name = $this->_slashify(basename($this->_unslashify($file['path'])));
/*
if (substr($file['path'],-1) == '/') if (substr($file['path'],-1) == '/')
{ {
$name = basename(substr($file['path'],0,-1)).'/'; $name = basename(substr($file['path'],0,-1)).'/';
@ -458,7 +536,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
$name = basename($file['path']); $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<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>".$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"; 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)); $parts = explode('/', $this->_unslashify($path));
if ($GLOBALS['egw']->accounts->name2id($parts[0])) if ($this->accounts->name2id($parts[0]))
{ {
// /$user/$app/... // /$user/$app/...
$user = array_shift($parts); $user = array_shift($parts);
@ -772,7 +850,7 @@ class groupdav extends HTTP_WebDAV_Server
if ($user) if ($user)
{ {
$user_prefix = '/'.$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 else
{ {
@ -785,13 +863,39 @@ class groupdav extends HTTP_WebDAV_Server
list($id) = explode('.',$id); // remove evtl. .ics extension 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)
{ {
if ($this->debug) error_log(__METHOD__."('$path') returning " . ($ok ? 'true' : 'false') . ": id='$id', app='$app', user='$user', user_prefix='$user_prefix'");
{
error_log(__METHOD__."('$path') returning false: id=$id, app='$app', user=$user");
}
} }
return $ok; 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
*/ */
var $translation; var $translation;
/**
* Reference to the accounts class
*
* @var accounts
*/
var $accounts;
/** /**
* Translates method names into ACL bits * Translates method names into ACL bits
* *
@ -88,7 +94,6 @@ abstract class groupdav_handler
*/ */
function __construct($app,$debug=null,$base_uri=null,$principalURL=null) function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
{ {
//error_log(__METHOD__." called");
$this->app = $app; $this->app = $app;
if (!is_null($debug)) $this->debug = $debug; if (!is_null($debug)) $this->debug = $debug;
$this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME']; $this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME'];
@ -99,13 +104,15 @@ abstract class groupdav_handler
} }
else else
{ {
$this->principalURL = $principalURL; $this->principalURL = $principalURL.'principals/users/'.
$GLOBALS['egw_info']['user']['account_lid'].'/';
} }
$this->agent = self::get_agent(); $this->agent = self::get_agent();
$this->translation =& $GLOBALS['egw']->translation; $this->translation =& $GLOBALS['egw']->translation;
$this->egw_charset = $this->translation->charset(); $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 * Propfind callback, if interator is used
* *
* @param string $path
* @param array $filter * @param array $filter
* @param array|boolean $start false=return all or array(start,num) * @param array|boolean $start false=return all or array(start,num)
* @param int &$total * @param int &$total
* @return array with "files" array with values for keys path and props * @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 * Handle get request for an applications entry
@ -178,10 +186,11 @@ abstract class groupdav_handler
* Add extra properties for collections * Add extra properties for collections
* *
* @param array $props=array() regular props by the groupdav handler * @param array $props=array() regular props by the groupdav handler
* @param string $displayname
* @param string $base_uri=null base url of handler * @param string $base_uri=null base url of handler
* @return array * @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; return $props;
} }
@ -203,7 +212,7 @@ abstract class groupdav_handler
// error_log(__METHOD__."(".array2string($entry).") Cant create etag!"); // error_log(__METHOD__."(".array2string($entry).") Cant create etag!");
return false; 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) static function etag2value($etag)
{ {
list(,$val) = explode(':',substr($etag,1,-1),2); list(,$val) = explode(':',substr($etag,4,-4),2);
return $val; return $val;
} }
@ -278,6 +287,7 @@ abstract class groupdav_handler
* *
* @static * @static
* @param string $app 'calendar', 'addressbook' or 'infolog' * @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 int $debug=null debug-level to set
* @param string $base_uri=null base url of handler * @param string $base_uri=null base url of handler
* @param string $principalURL=null pricipal 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]->$debug = $debug;
$handler_cache[$app]->$base_uri = $base_uri; $handler_cache[$app]->$base_uri = $base_uri;
$handler_cache[$app]->$principalURL = $principalURL; $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]; return $handler_cache[$app];
} }
@ -317,6 +329,7 @@ abstract class groupdav_handler
$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']); $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
foreach(array( foreach(array(
'davkit' => 'davkit', // Apple iCal 'davkit' => 'davkit', // Apple iCal
'cfnetwork' => 'cfnetwork', // Apple Addressbook
'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net 'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net
'zideone' => 'zideone', // zideone outlook plugin 'zideone' => 'zideone', // zideone outlook plugin
'lightning' => 'lightning', // Lighting (SOGo connector for addressbook) 'lightning' => 'lightning', // Lighting (SOGo connector for addressbook)
@ -356,6 +369,13 @@ abstract class groupdav_handler
*/ */
class groupdav_propfind_iterator implements Iterator class groupdav_propfind_iterator implements Iterator
{ {
/**
* current path
*
* @var string
*/
protected $path;
/** /**
* Handler to call for entries * Handler to call for entries
* *
@ -375,8 +395,16 @@ class groupdav_propfind_iterator implements Iterator
* *
* @var array * @var array
*/ */
protected $common_files;
/**
* current chunk
*
* @var array
*/
protected $files; protected $files;
/** /**
* Start value for callback * Start value for callback
* *
@ -397,6 +425,8 @@ class groupdav_propfind_iterator implements Iterator
*/ */
public $debug = false; public $debug = false;
/**
/** /**
* Constructor * Constructor
* *
@ -404,13 +434,14 @@ class groupdav_propfind_iterator implements Iterator
* @param array $filter filter for propfind call * @param array $filter filter for propfind call
* @param array $files=null extra files/responses to return too * @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->handler = $handler;
$this->filter = $filter; $this->filter = $filter;
$this->files = $files; $this->files = $files;
$this->common_files = $files;
reset($this->files); reset($this->files);
} }
@ -422,7 +453,6 @@ class groupdav_propfind_iterator implements Iterator
public function current() public function current()
{ {
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files))); if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files)));
return current($this->files); return current($this->files);
} }
@ -447,21 +477,20 @@ class groupdav_propfind_iterator implements Iterator
if (next($this->files) !== false) if (next($this->files) !== false)
{ {
if ($this->debug) error_log(__METHOD__."() returning TRUE"); if ($this->debug) error_log(__METHOD__."() returning TRUE");
return true; return true;
} }
if (is_array($this->files) && count($this->files) < self::CHUNK_SIZE) // less entries then asked --> no further available 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)"); if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
return false; // no further entries return false; // no further entries
} }
// try query further files via propfind callback of handler and store result in $this->files // 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; $this->start += self::CHUNK_SIZE;
reset($this->files); reset($this->files);
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false)); if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false));
return 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 // query first set of files via propfind callback of handler and store result in $this->files
$this->start = 0; $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; $this->start += self::CHUNK_SIZE;
reset($this->files); reset($this->files);
} }

View File

@ -7,7 +7,7 @@
* @package api * @package api
* @subpackage groupdav * @subpackage groupdav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @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$ * @version $Id$
*/ */
@ -16,12 +16,6 @@
*/ */
class groupdav_principals extends groupdav_handler class groupdav_principals extends groupdav_handler
{ {
/**
* Reference to the accounts class
*
* @var accounts
*/
var $accounts;
/** /**
* Constructor * Constructor
@ -34,8 +28,6 @@ class groupdav_principals extends groupdav_handler
function __construct($app,$debug=null,$base_uri=null,$principalURL=null) function __construct($app,$debug=null,$base_uri=null,$principalURL=null)
{ {
parent::__construct($app,$debug,$base_uri,$principalURL); 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) 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); list(,,$id) = explode('/',$path);
if ($id && !($id = $this->accounts->id2name($id))) if ($id && !($id = $this->accounts->id2name($id)))
{ {
return false; return false;
@ -61,31 +84,18 @@ class groupdav_principals extends groupdav_handler
{ {
$displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'], $displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'],
$GLOBALS['egw']->translation->charset(),'utf-8'); $GLOBALS['egw']->translation->charset(),'utf-8');
if ($options['root']['name'] == 'principal-search-property-set') $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('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']),
);
foreach($this->accounts->memberships($account['account_id']) as $gid => $group)
{ {
$props = array(HTTP_WebDAV_Server::mkprop('principal-search-property', $props[] = HTTP_WebDAV_Server::mkprop('group-membership',$this->base_uri.'/groups/'.$group);
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(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( $files['files'][] = array(
'path' => '/principals/'.$account['account_lid'], 'path' => '/principals/'.$account['account_lid'],
@ -93,7 +103,250 @@ class groupdav_principals extends groupdav_handler
); );
if ($this->debug > 1) error_log(__METHOD__."($path) path=/principals/".$account['account_lid'].', props='.array2string($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; return $account;
} }
$displayname = $GLOBALS['egw']->translation->convert( $name = $GLOBALS['egw']->translation->convert(
trim($account['account_firstname'].' '.$account['account_lastname']), trim($account['account_firstname'].' '.$account['account_lastname']),
$GLOBALS['egw']->translation->charset(),'utf-8'); $GLOBALS['egw']->translation->charset(),'utf-8');
$options['data'] = 'Principal: '.$account['account_lid']. $options['data'] = 'Principal: '.$account['account_lid'].
"\nURL: ".$this->base_uri.$options['path']. "\nURL: ".$this->base_uri.$options['path'].
"\nName: ".$displayname. "\nName: ".$name.
"\nEmail: ".$account['account_email']. "\nEmail: ".$account['account_email'].
"\nMemberships: ".implode(', ',$this->accounts->memberships($id))."\n"; "\nMemberships: ".implode(', ',$this->accounts->memberships($id))."\n";
$options['mimetype'] = 'text/plain; charset=utf-8'; $options['mimetype'] = 'text/plain; charset=utf-8';
@ -156,7 +409,8 @@ class groupdav_principals extends groupdav_handler
*/ */
function read($id) 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); $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) // type and size (caller already made sure that path exists)
if (is_dir($fspath)) { if (is_dir($fspath)) {
// directory (WebDAV collection) // 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'); $info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', 'httpd/unix-directory');
} else { } else {
// plain file (WebDAV resource) // plain file (WebDAV resource)