Screenshot instructions:
Windows
Mac
Red Hat Linux
Ubuntu
Click URL instructions:
Right-click on ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)
You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(146) |
Sep
(1294) |
Oct
(1064) |
Nov
(516) |
Dec
(447) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(791) |
Feb
(551) |
Mar
(1110) |
Apr
(521) |
May
(527) |
Jun
(424) |
Jul
(866) |
Aug
(1096) |
Sep
(470) |
Oct
(242) |
Nov
(368) |
Dec
(102) |
2005 |
Jan
(237) |
Feb
(315) |
Mar
(203) |
Apr
(555) |
May
(317) |
Jun
(791) |
Jul
(464) |
Aug
(131) |
Sep
(319) |
Oct
(575) |
Nov
(1068) |
Dec
(213) |
2006 |
Jan
(139) |
Feb
(149) |
Mar
(914) |
Apr
(688) |
May
(203) |
Jun
(313) |
Jul
(195) |
Aug
(207) |
Sep
(167) |
Oct
(203) |
Nov
(19) |
Dec
(284) |
2007 |
Jan
(207) |
Feb
(99) |
Mar
(85) |
Apr
(196) |
May
(222) |
Jun
(258) |
Jul
(118) |
Aug
(63) |
Sep
(70) |
Oct
(136) |
Nov
(112) |
Dec
(139) |
2008 |
Jan
(351) |
Feb
(227) |
Mar
(231) |
Apr
(159) |
May
(164) |
Jun
(139) |
Jul
(152) |
Aug
(136) |
Sep
(69) |
Oct
(294) |
Nov
(243) |
Dec
(66) |
2009 |
Jan
(43) |
Feb
(61) |
Mar
(139) |
Apr
(220) |
May
(323) |
Jun
(188) |
Jul
(249) |
Aug
(172) |
Sep
(163) |
Oct
(234) |
Nov
(394) |
Dec
(215) |
2010 |
Jan
(139) |
Feb
(183) |
Mar
(277) |
Apr
(314) |
May
(420) |
Jun
(584) |
Jul
(317) |
Aug
(188) |
Sep
(386) |
Oct
(242) |
Nov
(315) |
Dec
(213) |
2011 |
Jan
(155) |
Feb
(235) |
Mar
(445) |
Apr
(294) |
May
(247) |
Jun
(423) |
Jul
(162) |
Aug
(395) |
Sep
(279) |
Oct
(223) |
Nov
(183) |
Dec
(120) |
2012 |
Jan
(150) |
Feb
(207) |
Mar
(387) |
Apr
(258) |
May
(202) |
Jun
(193) |
Jul
(278) |
Aug
(138) |
Sep
(105) |
Oct
(261) |
Nov
(169) |
Dec
(109) |
2013 |
Jan
(234) |
Feb
(272) |
Mar
(155) |
Apr
(215) |
May
(185) |
Jun
(220) |
Jul
(246) |
Aug
(274) |
Sep
(179) |
Oct
(377) |
Nov
(357) |
Dec
(218) |
2014 |
Jan
(491) |
Feb
(504) |
Mar
(382) |
Apr
(327) |
May
(309) |
Jun
(301) |
Jul
(486) |
Aug
(413) |
Sep
(430) |
Oct
(453) |
Nov
(367) |
Dec
(347) |
2015 |
Jan
(355) |
Feb
(440) |
Mar
(383) |
Apr
(324) |
May
(189) |
Jun
(157) |
Jul
(228) |
Aug
(244) |
Sep
(266) |
Oct
(337) |
Nov
(285) |
Dec
(226) |
2016 |
Jan
(244) |
Feb
(317) |
Mar
(392) |
Apr
(272) |
May
(189) |
Jun
(3) |
Jul
(1) |
Aug
(4) |
Sep
(2) |
Oct
(6) |
Nov
(5) |
Dec
(5) |
2017 |
Jan
(3) |
Feb
(2) |
Mar
(3) |
Apr
(2) |
May
(1) |
Jun
(3) |
Jul
(4) |
Aug
(5) |
Sep
(3) |
Oct
(1) |
Nov
|
Dec
(1) |
2018 |
Jan
(2) |
Feb
(4) |
Mar
(8) |
Apr
(2) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
1
(12) |
2
(8) |
3
(18) |
4
(6) |
5
(15) |
6
(16) |
7
(15) |
8
(12) |
9
(9) |
10
(6) |
11
(5) |
12
|
13
(1) |
14
(1) |
15
(14) |
16
(18) |
17
(3) |
18
(9) |
19
(8) |
20
(7) |
21
(11) |
22
(16) |
23
(7) |
24
(10) |
25
(12) |
26
(6) |
27
(1) |
28
(7) |
29
(6) |
30
(5) |
31
(13) |
|
|
|
From: <jlehrke@us...> - 2010-03-04 23:10:39
|
Author: jlehrke Date: Fri Mar 5 00:09:55 2010 New Revision: 29385 URL: http://www.egroupware.org/viewvc/egroupware?rev=29385&view=rev Log: Updated GroupDAV code to support InfoLog calendars, Addressbook and new principal implementation Modified: branches/1.6/addressbook/inc/class.addressbook_groupdav.inc.php branches/1.6/addressbook/inc/class.addressbook_so.inc.php branches/1.6/addressbook/inc/class.addressbook_vcal.inc.php branches/1.6/calendar/inc/class.calendar_groupdav.inc.php branches/1.6/calendar/inc/class.calendar_ical.inc.php branches/1.6/egw-pear/HTTP/WebDAV/Server.php branches/1.6/egw-pear/HTTP/WebDAV/Server/Filesystem.php branches/1.6/infolog/inc/class.infolog_bo.inc.php branches/1.6/infolog/inc/class.infolog_groupdav.inc.php branches/1.6/infolog/inc/class.infolog_ical.inc.php branches/1.6/phpgwapi/inc/class.groupdav.inc.php branches/1.6/phpgwapi/inc/class.groupdav_handler.inc.php branches/1.6/phpgwapi/inc/class.groupdav_principals.inc.php branches/1.6/phpgwapi/inc/class.vfs_webdav_server.inc.php Modified: branches/1.6/addressbook/inc/class.addressbook_groupdav.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/addressbook/inc/class.addressbook_groupdav.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/addressbook/inc/class.addressbook_groupdav.inc.php (original) +++ branches/1.6/addressbook/inc/class.addressbook_groupdav.inc.php Fri Mar 5 00:09:55 2010 @@ -68,7 +68,7 @@ */ static function get_path($contact) { - return '/addressbook/'.$contact[self::PATH_ATTRIBUTE].'.vcf'; + return $contact[self::PATH_ATTRIBUTE].'.vcf'; } /** @@ -96,8 +96,9 @@ } if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id) filter=".array2string($filter)); - // check if we have to return the full calendar data or just the etag's - if (!($filter['address_data'] = $options['props'] == 'all' && $options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props'])) + // check if we have to return the full contact data or just the etag's + if (!($filter['address_data'] = $options['props'] == 'all' && + $options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props'])) { foreach($options['props'] as $prop) { @@ -109,7 +110,7 @@ } } // return iterator, calling ourself to return result in chunks - $files['files'] = new groupdav_propfind_iterator($this,$filter,$files['files']); + $files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']); return true; } @@ -117,11 +118,12 @@ /** * Callback for profind interator * + * @param string $path * @param array $filter * @param array|boolean $start=false false=return all or array(start,num) * @return array with "files" array with values for keys path and props */ - function &propfind_callback(array $filter,$start=false) + function &propfind_callback($path,array $filter,$start=false) { $starttime = microtime(true); @@ -139,7 +141,7 @@ { $props = array( HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($contact)), - HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/x-vcard'), + HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'), // getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set HTTP_WebDAV_Server::mkprop('getlastmodified', $contact['modified']), ); @@ -147,19 +149,19 @@ { $content = $handler->getVCard($contact,$this->charset,false); $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content)); - $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content); + $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true); } else { $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it } $files[] = array( - 'path' => self::get_path($contact), + 'path' => $path.self::get_path($contact), 'props' => $props, ); } } - if ($this->debug) error_log(__METHOD__.'('.array2string($filter).','.array2string($start).") took ".(microtime(true) - $starttime).' to return '.count($files).' items'); + if ($this->debug) error_log(__METHOD__."($path,".array2string($filter).','.array2string($start).") took ".(microtime(true) - $starttime).' to return '.count($files).' items'); return $files; } @@ -266,14 +268,24 @@ */ function put(&$options,$id,$user=null) { + if ($this->debug) error_log(__METHOD__.'('.array2string($options).",$id,$user)"); $ok = $this->_common_get_put_delete('PUT',$options,$id); if (!is_null($ok) && !is_array($ok)) { return $ok; } $handler = self::_get_handler(); - $contact = $handler->vcardtoegw($options['content']); - + $vCard = htmlspecialchars_decode($options['content']); + $contactId = (is_array($ok) ? -1 : $ok['id']); + $contact = $handler->vcardtoegw($vCard, $contactId); + if (is_array($contact['category'])) + { + $contact['category'] = implode(',',$this->bo->find_or_add_categories($contact['category'], $contactId)); + } + elseif ($contactId > 0) + { + $contact['category'] = $ok['category']; + } if (!is_null($ok)) { $contact['id'] = $ok['id']; @@ -281,6 +293,10 @@ $contact['uid'] = $ok['uid']; $contact['owner'] = $ok['owner']; $contact['private'] = $ok['private']; + } + else + { + $contact['owner'] = $user; } if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match); @@ -295,13 +311,14 @@ } if (!isset($contact['etag'])) { - $contact = $this->read($contact['id']); + $contact = $this->read($save_ok); } header('ETag: '.$this->get_etag($contact)); if (is_null($ok)) { - header($h='Location: '.$this->base_uri.self::get_path($contact)); + $path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']); + header($h='Location: '.$path.self::get_path($contact)); if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): 201 Created"); return '201 Created'; } @@ -323,7 +340,37 @@ $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 @@ * @link http://www.mail-archive.com/calendarserver-users@.../msg01156.html * * @param array $props=array() regular props by the groupdav handler + * @param string $displayname * @param string $base_uri=null base url of handler * @return array */ - static function extra_properties(array $props=array(), $base_uri=null) - { + static function extra_properties(array $props=array(), $displayname, $base_uri=null) + { + // addressbook description + $displayname = $GLOBALS['egw']->translation->convert(lang('Addressbook of') . ' ' . + $displayname, + $GLOBALS['egw']->translation->charset(),'utf-8'); + $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-description',$displayname); // supported reports (required property for CardDAV) $props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array( HTTP_WebDAV_Server::mkprop('supported-report',array( @@ -359,6 +412,7 @@ HTTP_WebDAV_Server::mkprop('report', HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget','')))), )); + //$props = self::current_user_privilege_set($props); return $props; } @@ -392,7 +446,7 @@ { return '412 Precondition Failed'; } - return $ok; + //return $ok; } /** Modified: branches/1.6/addressbook/inc/class.addressbook_so.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/addressbook/inc/class.addressbook_so.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/addressbook/inc/class.addressbook_so.inc.php (original) +++ branches/1.6/addressbook/inc/class.addressbook_so.inc.php Fri Mar 5 00:09:55 2010 @@ -526,8 +526,8 @@ /** * reads contact data including custom fields * - * @param int/string $contact_id contact_id or 'a'.account_id - * @return array/boolean data if row could be retrived else False + * @param int|string $contact_id contact_id or 'a'.account_id + * @return array|boolean data if row could be retrived else False */ function read($contact_id) { Modified: branches/1.6/addressbook/inc/class.addressbook_vcal.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/addressbook/inc/class.addressbook_vcal.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/addressbook/inc/class.addressbook_vcal.inc.php (original) +++ branches/1.6/addressbook/inc/class.addressbook_vcal.inc.php Fri Mar 5 00:09:55 2010 @@ -123,7 +123,7 @@ */ function addVCard($_vcard, $_abID=null, $merge=false) { - if (!$contact = $this->vcardtoegw($_vcard, $_abID)) + if (!$contact = $this->vcardtoegw($_vcard)) { return false; } @@ -147,6 +147,15 @@ if (isset($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']; } } } @@ -160,6 +169,10 @@ { $contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group']; } + if (is_array($contact['category'])) + { + $contact['category'] = implode(',',$this->find_or_add_categories($contact['category'], -1)); + } } return $this->save($contact); } @@ -455,8 +468,13 @@ { $result = array(); - if (($contact = $this->vcardtoegw($_vcard, $contentID))) - { + if (($contact = $this->vcardtoegw($_vcard))) + { + if (is_array($contact['category'])) + { + $contact['category'] = implode(',',$this->find_or_add_categories($contact['category'], + $contentID ? $contentID : -1)); + } if ($contentID) { $contact['id'] = $contentID; @@ -475,7 +493,7 @@ if (is_array($_supportedFields)) $this->supportedFields = $_supportedFields; } - function vcardtoegw($_vcard, $_abID=null) + function vcardtoegw($_vcard) { // the horde class does the charset conversion. DO NOT CONVERT HERE. // be as flexible as possible @@ -889,7 +907,7 @@ break; case 'cat_id': - $contact[$fieldName] = implode(',',$this->find_or_add_categories($vcardValues[$vcardKey]['values'], $_abID)); + $contact[$fieldName] = $vcardValues[$vcardKey]['values']; break; case 'jpegphoto': Modified: branches/1.6/calendar/inc/class.calendar_groupdav.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/calendar/inc/class.calendar_groupdav.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/calendar/inc/class.calendar_groupdav.inc.php (original) +++ branches/1.6/calendar/inc/class.calendar_groupdav.inc.php Fri Mar 5 00:09:55 2010 @@ -23,8 +23,6 @@ */ var $bo; - const DAV = 'DAV:'; - var $filter_prop2cal = array( 'SUMMARY' => 'cal_title', 'UID' => 'cal_uid', @@ -86,7 +84,7 @@ if (!is_array($event)) $event = $this->bo->read($event); $name = $event[self::PATH_ATTRIBUTE]; } - return '/calendar/'.$name.'.ics'; + return $name.'.ics'; } /** @@ -191,7 +189,7 @@ $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it } $files['files'][] = array( - 'path' => self::get_path($event), + 'path' => $path.self::get_path($event), 'props' => $props, ); } @@ -447,12 +445,19 @@ if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace()); return $event; } + + if (is_null($event) && !$this->bo->check_perms(EGW_ACL_ADD, 0, $user)) + { + // we have not permission on this user's calendar + if ($this->debug) error_log(__METHOD__."(,$user) we have not enough rights on this calendar"); + return '403 Forbidden'; + } + $handler = $this->_get_handler(); - $vCalendar = htmlspecialchars_decode($options['content']); if (!($cal_id = $handler->importVCal($vCalendar, is_numeric($id) ? $id : -1, - self::etag2value($this->http_if_match), false, 0, $this->principalURL))) + self::etag2value($this->http_if_match), false, 0, $this->principalURL, $user))) { if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false"); return '403 Forbidden'; @@ -461,14 +466,10 @@ header('ETag: '.$this->get_etag($cal_id)); if (is_null($event) || !$return_no_access) // let lightning think the event is added { + $path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']); if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id, is_null(\$event)=".(int)is_null($event)); - header('Location: '.$this->base_uri.self::get_path($cal_id)); + header('Location: '.$path.self::get_path($cal_id)); return '201 Created'; - } - if (strpos($_SERVER[HTTP_USER_AGENT], 'Mac OS X') !== false) - { - //return '205 Reset Content'; // would be nicer - return '400 Event updated, please reload'; // Enforce a reload by iCal } return true; } @@ -580,8 +581,7 @@ */ function read($id) { - //$cal_read = $this->bo->read($id,null,false,'server');//njv: do we actually get anything - if ($this->debug > 1) error_log("bo-ical read :$id:");//njv: + if ($this->debug > 1) error_log("bo-ical read :$id:"); return $this->bo->read($id,null,false,'server'); } @@ -622,12 +622,12 @@ { if ($recurrence['reference']) // ignore series master { - $etag .= ':'.substr($this->get_etag($recurrence),1,-1); + $etag .= ':'.substr($this->get_etag($recurrence),4,-4); } } } //error_log(__METHOD__ . "($entry[id] ($entry[etag]): $entry[title] --> etag=$etag"); - return '"'.$etag.'"'; + return 'EGw-'.$etag.'-wGE'; } /** @@ -650,23 +650,23 @@ */ static function current_user_privilege_set(array $props=array()) { - $props[] = HTTP_WebDAV_Server::mkprop(self::DAV,'current-user-privilege-set', - array(HTTP_WebDAV_Server::mkprop(self::DAV,'privilege', - array(//HTTP_WebDAV_Server::mkprop(self::DAV,'all',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'read',''), + $props[] = HTTP_WebDAV_Server::mkprop(groupdav::DAV,'current-user-privilege-set', + array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'privilege', + array(//HTTP_WebDAV_Server::mkprop(groupdav::DAV,'all',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read',''), HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'read-free-busy',''), - //HTTP_WebDAV_Server::mkprop(self::DAV,'read-current-user-privilege-set',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'bind',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'unbind',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-post',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-post-vevent',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-respond',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-respond-vevent',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-deliver',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'schedule-deliver-vevent',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'write',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'write-properties',''), - HTTP_WebDAV_Server::mkprop(self::DAV,'write-content',''), + //HTTP_WebDAV_Server::mkprop(groupdav::DAV,'read-current-user-privilege-set',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'bind',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'unbind',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-post-vevent',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-respond-vevent',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'schedule-deliver-vevent',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-properties',''), + HTTP_WebDAV_Server::mkprop(groupdav::DAV,'write-content',''), )))); return $props; } @@ -675,42 +675,41 @@ * Add extra properties for calendar collections * * @param array $props=array() regular props by the groupdav handler + * @param string $displayname * @param string $base_uri=null base url of handler * @return array */ - static function extra_properties(array $props=array(), $base_uri=null) + static function extra_properties(array $props=array(), $displayname, $base_uri=null) { // calendar description - $displayname = $GLOBALS['egw']->translation->convert(lang('Calendar of'). ' ' . - $GLOBALS['egw_info']['user']['account_fullname'], - $GLOBALS['egw']->translation->charset(),'utf-8'); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname); // BOX URLs of the current user /* $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-inbox-URL', array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/'))); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-outbox-URL', - array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/'))); + array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/'))); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-default-calendar-URL', - array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/'))); + array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/'))); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'dropbox-home-URL', - array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/'))); + array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/'))); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'notifications-URL', - array(HTTP_WebDAV_Server::mkprop(self::DAV,'href',$base_uri.'/calendar/'))); + array(HTTP_WebDAV_Server::mkprop(groupdav::DAV,'href',$base_uri.'/calendar/'))); */ // email of the current user, see caldav-sheduling draft - $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$GLOBALS['egw_info']['user']['email']); + $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array( + HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))); // supported components, currently only VEVENT $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array( HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')), // HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), // not yet supported )); - /* + $props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array( HTTP_WebDAV_Server::mkprop('supported-report',array( HTTP_WebDAV_Server::mkprop('report', HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget')))))); - */ + //$props = self::current_user_privilege_set($props); return $props; } Modified: branches/1.6/calendar/inc/class.calendar_ical.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/calendar/inc/class.calendar_ical.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/calendar/inc/class.calendar_ical.inc.php (original) +++ branches/1.6/calendar/inc/class.calendar_ical.inc.php Fri Mar 5 00:09:55 2010 @@ -1029,9 +1029,10 @@ * @param int $recur_date=0 if set, import the recurrence at this timestamp, * default 0 => import whole series (or events, if not recurring) * @param string $principalURL='' Used for CalDAV imports + * @param int $user=null account_id of owner, default null * @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag */ - function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='') + function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null) { if (!is_array($this->supportedFields)) $this->setSupportedFields(); @@ -1081,7 +1082,7 @@ if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ - ."($cal_id, $etag, $recur_date, $principalURL)\n" + ."($cal_id, $etag, $recur_date, $principalURL, $user)\n" . array2string($event)."\n",3,$this->logfile); } $updated_id = false; @@ -1204,9 +1205,20 @@ $event['non_blocking'] = 1; } + if (!is_null($user)) + { + if ($this->check_perms(EGW_ACL_ADD, 0, $user)) + { + $event['owner'] = $user; + } + else + { + return false; // no permission + } + } // check if an owner is set and the current user has add rights // for that owners calendar; if not set the current user - if (!isset($event['owner']) + elseif (!isset($event['owner']) || !$this->check_perms(EGW_ACL_ADD, 0, $event['owner'])) { $event['owner'] = $this->user; Modified: branches/1.6/egw-pear/HTTP/WebDAV/Server.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/egw-pear/HTTP/WebDAV/Server.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/egw-pear/HTTP/WebDAV/Server.php (original) +++ branches/1.6/egw-pear/HTTP/WebDAV/Server.php Fri Mar 5 00:09:55 2010 @@ -59,6 +59,18 @@ */ var $client_require_href_as_url; + /** + * Set if client requires does not allow namespace redundacy. + * The XML Namespace specification does allow both + * But some clients can NOT deal with one or the other! + * + * @var boolean (client_refuses_redundand_namespace_declarations) + */ + var $crrnd = false; + + /** + + /** * URI path for this request * @@ -229,11 +241,18 @@ $this->$wrapper(); // call method by name } else { // method not found/implemented if ($this->_SERVER["REQUEST_METHOD"] == "LOCK") { - $this->http_status("412 Precondition failed"); + $error = '412 Precondition failed'; + ; } else { - $this->http_status("405 Method not allowed"); + $error = '405 Method not allowed'; header("Allow: ".join(", ", $this->_allow())); // tell client what's allowed } + $this->http_status($error); + echo "<html><head><title>Error $error</title></head>\n"; + echo "<body><h1>$error</h1>\n"; + echo "The requested could not by handled by this server.\n"; + echo '(URI ' . $this->_SERVER['REQUEST_URI'] . ")<br>\n<br>\n"; + echo "</body></html>\n"; } } @@ -432,7 +451,7 @@ */ // }}} - // {{{ LOCK() + // {{{ ACL() /** * ACL implementation @@ -585,7 +604,7 @@ $options['other'] = $propinfo->other; // call user handler - if (!$this->$handler($options, $files)) { + if (!($retval =$this->$handler($options, $files))) { $files = array("files" => array()); if (method_exists($this, "checkLock")) { // is locked? @@ -611,27 +630,43 @@ } } - // now we generate the reply header ... - if ($propinfo->root['name'] == 'principal-search-property-set') + // now we generate the reply header ... + if ($retval === true) { - $this->http_status('200 OK'); + $this->http_status('207 Multi-Status'); } 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"'); // ... and payload echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; - if ($propinfo->root['name'] == 'principal-search-property-set') - { - echo "<D:principal-search-property-set xmlns:D=\"DAV:\">\n"; - } - else - { - echo "<D:multistatus xmlns:D=\"DAV:\">\n"; - } + echo ($this->crrnd?'<':'<D:')."multistatus xmlns:D=\"DAV:\">\n"; // using an ArrayIterator to prevent foreach from copying the array, // as we cant loop by reference, when an iterator is given in $files['files'] @@ -748,7 +783,14 @@ $path = $file['path']; if (!is_string($path) || $path==="") continue; - if ($propinfo->root['name'] != 'principal-search-property-set') echo " <D:response $ns_defs>\n"; + if ($this->crrnd) + { + echo " <response $ns_defs>\n"; + } + else + { + echo " <D:response $ns_defs>\n"; + } /* TODO right now the user implementation has to make sure collections end in a slash, this should be done in here @@ -756,15 +798,20 @@ // path needs to be urlencoded (only basic version of this class!) $href = $this->_urlencode($this->_mergePathes($this->base_uri, $path)); - if ($propinfo->root['name'] != 'principal-search-property-set') echo " <D:href>$href</D:href>\n"; + if ($this->crrnd) + { + echo " <href>$href</href>\n"; + } + else + { + echo " <D:href>$href</D:href>\n"; + } // report all found properties and their values (if any) if (isset($file["props"]) && is_array($file["props"])) { - if ($propinfo->root['name'] != 'principal-search-property-set') - { - echo " <D:propstat>\n"; - echo " <D:prop>\n"; - } + echo ' <'.($this->crrnd?'':'D:')."propstat>\n"; + echo ' <'.($this->crrnd?'':'D:')."prop>\n"; + foreach ($file["props"] as &$prop) { if (!is_array($prop)) continue; @@ -773,7 +820,7 @@ if (!isset($prop["val"]) || $prop["val"] === "" || $prop["val"] === false) { // empty properties (cannot use empty() for check as "0" is a legal value here) if ($prop["ns"]=="DAV:") { - echo " <D:$prop[name]/>\n"; + echo ' <'.($this->crrnd?'':'D:')."$prop[name]/>\n"; } else if (!empty($prop["ns"])) { echo " <".$ns_hash[$prop["ns"]].":$prop[name]/>\n"; } else { @@ -783,61 +830,34 @@ // some WebDAV properties need special treatment switch ($prop["name"]) { case "creationdate": - echo " <D:creationdate ns0:dt=\"dateTime.tz\">" + echo ' <'.($this->crrnd?'':'D:')."creationdate ns0:dt=\"dateTime.tz\">" . gmdate("Y-m-d\\TH:i:s\\Z", $prop['val']) - . "</D:creationdate>\n"; + . '</'.($this->crrnd?'':'D:')."creationdate>\n"; break; case "getlastmodified": - echo " <D:getlastmodified ns0:dt=\"dateTime.rfc1123\">" + echo ' <'.($this->crrnd?'':'D:')."getlastmodified ns0:dt=\"dateTime.rfc1123\">" . gmdate("D, d M Y H:i:s ", $prop['val']) - . "GMT</D:getlastmodified>\n"; + . "GMT</".($this->crrnd?'':'D:')."getlastmodified>\n"; break; - /* @Todo: breaks CalDAV - 2010/03/01 jlehrke - case "resourcetype": - if (!is_array($prop['val'])) { - echo ' <D:resourcetype><D:'.$prop['val']."/></D:resourcetype>\n"; - } else { // multiple resourcetypes from different namespaces as required by GroupDAV - $vals = $extra_ns = ''; - foreach($prop['val'] as $subprop) - { - if ($subprop['ns'] && $subprop['ns'] != 'DAV:') { - // register property namespace if not known yet - if (!isset($ns_hash[$subprop['ns']])) { - $ns_name = "ns".(count($ns_hash) + 1); - $ns_hash[$subprop['ns']] = $ns_name; - } else { - $ns_name = $ns_hash[$subprop['ns']]; - } - if (strchr($extra_ns,$extra=' xmlns:'.$ns_name.'="'.$subprop['ns'].'"') === false) { - $extra_ns .= $extra; - } - $ns_name .= ':'; - } elseif ($subprop['ns'] == 'DAV:') { - $ns_name = 'D:'; - } else { - $ns_name = ''; - } - $vals .= "<$ns_name$subprop[val]/>"; - } - echo " <D:resourcetype$extra_ns>$vals</D:resourcetype>\n"; - //error_log("resourcetype: <D:resourcetype$extra_ns>$vals</D:resourcetype>"); - } - break; - */ case "supportedlock": - echo " <D:supportedlock>$prop[val]</D:supportedlock>\n"; + echo ' <'.($this->crrnd?'':'D:')."supportedlock>$prop[val]</".($this->crrnd?'':'D:')."supportedlock>\n"; break; case "lockdiscovery": - echo " <D:lockdiscovery>\n"; + echo ' <'.($this->crrnd?'':'D:')."lockdiscovery>\n"; echo $prop["val"]; - echo " </D:lockdiscovery>\n"; + echo ' </'.($this->crrnd?'':'D:')."lockdiscovery>\n"; break; default: - echo " <D:$prop[name]>". - (is_array($prop['val']) ? - $this->_hierarchical_prop_encode($prop['val']) : - $this->_prop_encode(htmlspecialchars($prop['val']))). - "</D:$prop[name]>\n"; + if (is_array($prop['val'])) + { + $val = $this->_hierarchical_prop_encode($prop['val']); + } elseif (isset($prop['raw'])) { + $val = $this->_prop_encode('<![CDATA['.$prop['val'].']]>'); + } else { + $val = $this->_prop_encode(htmlspecialchars($prop['val'])); + } + echo ' <'.($this->crrnd?'':'D:')."$prop[name]>$val". + '</'.($this->crrnd?'':'D:')."$prop[name]>\n"; break; } } else { @@ -850,53 +870,75 @@ $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[name]"; - if (is_array($subprop['val'])) // val contains only attributes, no value - { - foreach($subprop['val'] as $attr => $val) - { - $vals .= ' '.$attr.'="'.htmlspecialchars($val).'"'; - } - $vals .= '/>'; - } - else - { - $vals .= '>'.htmlspecialchars($subprop['val'])."</$ns_name$subprop[name]>"; - } - } - echo " <".$ns_hash[$prop['ns']].":$prop[name]$extra_ns>$vals</".$ns_hash[$prop['ns']].":$prop[name]>\n"; - } - else - // properties from namespaces != "DAV:" or without any namespace - if ($prop["ns"]) { - echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]>" - . $this->_prop_encode(htmlspecialchars($prop['val'])) - . "</" . $ns_hash[$prop["ns"]] . ":$prop[name]>\n"; + 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[name]"; + if (is_array($subprop['val'])) // val contains only attributes, no value + { + foreach($subprop['val'] as $attr => $val) + { + $vals .= ' '.$attr.'="'.htmlspecialchars($val).'"'; + } + $vals .= '/>'; + } + else + { + $vals .= '>'; + if (isset($subprop['raw'])) { + $vals .= '<![CDATA['.$subprop['val'].']]>'; + } else { + $vals .= htmlspecialchars($subprop['val']); + } + $vals .= "</$ns_name$subprop[name]>"; + } + } + echo ' <'.$ns_hash[$prop['ns']].":$prop[name]$extra_ns>$vals</".$ns_hash[$prop['ns']].":$prop[name]>\n"; } else { - echo " <$prop[name] xmlns=\"\">" - . $this->_prop_encode(htmlspecialchars($prop['val'])) - . "</$prop[name]>\n"; + if ($prop['raw']) + { + $val = '<![CDATA['.$prop['val'].']]>'; + } else { + $val = htmlspecialchars($prop['val']); + } + $val = $this->_prop_encode($val); + // properties from namespaces != "DAV:" or without any namespace + if ($prop['ns']) { + if ($this->crrnd) { + echo " <$prop[name]> xmlns:".$ns_hash[$prop['ns']]."=".'"'.$prop["ns"].'">' + . $val . "</$prop[name]>\n"; + } else { + echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]>" + . $val . '</'.$ns_hash[$prop['ns']].":$prop[name]>\n"; + } + } else { + echo " <$prop[name] xmlns=\"\">$val</$prop[name]>\n"; + } } } } - if ($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:status>HTTP/1.1 200 OK</D:status>\n"; @@ -906,12 +948,12 @@ // now report all properties requested but not found if (isset($file["noprops"])) { - echo " <D:propstat>\n"; - echo " <D:prop>\n"; + echo ' <'.($this->crrnd?'':'D:')."propstat>\n"; + echo ' <'.($this->crrnd?'':'D:')."prop>\n"; foreach ($file["noprops"] as &$prop) { if ($prop["ns"] == "DAV:") { - echo " <D:$prop[name]/>\n"; + echo ' <'.($this->crrnd?'':'D:')."$prop[name]/>\n"; } else if ($prop["ns"] == "") { echo " <$prop[name] xmlns=\"\"/>\n"; } else { @@ -919,23 +961,24 @@ } } - echo " </D:prop>\n"; - echo " <D:status>HTTP/1.1 404 Not Found</D:status>\n"; - echo " </D:propstat>\n"; - } - - if ($propinfo->root['name'] != 'principal-search-property-set') echo " </D:response>\n"; - } - - if ($propinfo->root['name'] == 'principal-search-property-set') - { - echo "</D:principal-search-property-set>\n"; - } - else - { - echo "</D:multistatus>\n"; - } - + if ($this->crrnd) + { + echo " </prop>\n"; + echo " <status>HTTP/1.1 404 Not Found</status>\n"; + echo " </propstat>\n"; + } + else + { + echo " </D:prop>\n"; + echo " <D:status>HTTP/1.1 404 Not Found</D:status>\n"; + echo " </D:propstat>\n"; + } + } + + echo ' </'.($this->crrnd?'':'D:')."response>\n"; + } + + echo '</'.($this->crrnd?'':'D:')."multistatus>\n"; } @@ -973,24 +1016,24 @@ echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; echo "<D:multistatus xmlns:D=\"DAV:\">\n"; - echo " <D:response>\n"; - echo " <D:href>".$this->_urlencode($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path))."</D:href>\n"; + echo ' <'.($this->crrnd?'':'D:')."response>\n"; + echo ' <'.($this->crrnd?'':'D:')."href>".$this->_urlencode($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path)).'</'.($this->crrnd?'':'D:')."href>\n"; foreach ($options["props"] as $prop) { - echo " <D:propstat>\n"; - echo " <D:prop><$prop[name] xmlns=\"$prop[ns]\"/></D:prop>\n"; - echo " <D:status>HTTP/1.1 $prop[status]</D:status>\n"; - echo " </D:propstat>\n"; + echo ' <'.($this->crrnd?'':'D:')."propstat>\n"; + echo ' <'.($this->crrnd?'':'D:')."prop><$prop[name] xmlns=\"$prop[ns]\"/></".($this->crrnd?'':'D:')."prop>\n"; + echo ' <'.($this->crrnd?'':'D:')."status>HTTP/1.1 $prop[status]</".($this->crrnd?'':'D:')."status>\n"; + echo ' </'.($this->crrnd?'':'D:')."propstat>\n"; } if ($responsedescr) { - echo " <D:responsedescription>". + echo ' <'.($this->crrnd?'':'D:')."responsedescription>". $this->_prop_encode(htmlspecialchars($responsedescr)). - "</D:responsedescription>\n"; - } - - echo " </D:response>\n"; - echo "</D:multistatus>\n"; + '</'.($this->crrnd?'':'D:')."responsedescription>\n"; + } + + echo ' </'.($this->crrnd?'':'D:')."response>\n"; + echo '</'.($this->crrnd?'':'D:')."multistatus>\n"; } else { $this->http_status("423 Locked"); } @@ -1580,17 +1623,17 @@ header("Lock-Token: <$options[locktoken]>"); echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; echo "<D:prop xmlns:D=\"DAV:\">\n"; - echo " <D:lockdiscovery>\n"; - echo " <D:activelock>\n"; - echo " <D:lockscope><D:$options[scope]/></D:lockscope>\n"; - echo " <D:locktype><D:$options[type]/></D:locktype>\n"; - echo " <D:depth>$options[depth]</D:depth>\n"; - echo " <D:owner>$options[owner]</D:owner>\n"; - echo " <D:timeout>$timeout</D:timeout>\n"; - echo " <D:locktoken><D:href>$options[locktoken]</D:href></D:locktoken>\n"; - echo " </D:activelock>\n"; - echo " </D:lockdiscovery>\n"; - echo "</D:prop>\n\n"; + echo ' <'.($this->crrnd?'':'D:')."lockdiscovery>\n"; + echo ' <'.($this->crrnd?'':'D:')."activelock>\n"; + echo ' <'.($this->crrnd?'':'D:')."lockscope><D:$options[scope]/></".($this->crrnd?'':'D:')."lockscope>\n"; + echo ' <'.($this->crrnd?'':'D:')."locktype><D:$options[type]/></".($this->crrnd?'':'D:')."locktype>\n"; + echo ' <'.($this->crrnd?'':'D:')."depth>$options[depth]</".($this->crrnd?'':'D:')."depth>\n"; + echo ' <'.($this->crrnd?'':'D:')."owner>$options[owner]</".($this->crrnd?'':'D:')."owner>\n"; + echo ' <'.($this->crrnd?'':'D:')."timeout>$timeout</".($this->crrnd?'':'D:')."timeout>\n"; + echo ' <'.($this->crrnd?'':'D:')."locktoken><D:href>$options[locktoken]</D:href></".($this->crrnd?'':'D:')."locktoken>\n"; + echo ' </'.($this->crrnd?'':'D:')."activelock>\n"; + echo ' </'.($this->crrnd?'':'D:')."lockdiscovery>\n"; + echo '</'.($this->crrnd?'':'D:')."prop>\n\n"; } } @@ -1627,9 +1670,9 @@ // }}} - // {{{ http_UNLOCK() - - /** + // {{{ http_ACL() + + /** * ACL method handler * * @param void @@ -1660,9 +1703,9 @@ $content .= "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; $content .= "<D:error xmlns:D=\"DAV:\"> \n"; foreach ($options['errors'] as $violation) { - $content .= "<D:$violation/>\n"; + $content .= '<'.($this->crrnd?'':'D:')."$violation/>\n"; } - $content .= "</D:error>\n"; + $content .= '</'.($this->crrnd?'':'D:')."error>\n"; } header("Content-length: ".$this->bytes($content)); if ($content) echo $options['content']; @@ -1765,20 +1808,27 @@ * @param string XML namespace (optional) * @param string property name * @param string property value + * @praram boolen property raw-flag * @return array property array */ function mkprop() { - $args = func_get_args(); - if (count($args) == 3) { - return array("ns" => $args[0], - "name" => $args[1], - "val" => $args[2]); - } else { - return array("ns" => "DAV:", - "name" => $args[0], - "val" => $args[1]); - } + $args = func_get_args(); + switch (count($args)) { + case 4: + return array('ns' => $args[0], + 'name' => $args[1], + 'val' => $args[2], + 'raw' => true); + case 3: + return array('ns' => $args[0], + 'name' => $args[1], + 'val' => $args[2]); + default: + return array("ns" => "DAV:", + "name" => $args[0], + "val" => $args[1]); + } } // {{{ _check_auth @@ -2125,16 +2175,32 @@ } // genreate response block - $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> - "; + if ($this->crrnd) + { + $activelocks.= " + <activelock> + <lockscope><$lock[scope]/></lockscope> + <locktype><$lock[type]/></locktype> + <depth>$lock[depth]</depth> + <owner>$lock[owner]</owner> + <timeout>$timeout</timeout> + <locktoken><href>$lock[token]</href></locktoken> + </activelock> + "; + } + else + { + $activelocks.= " + <D:activelock> + <D:lockscope><D:$lock[scope]/></D:lockscope> + <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 Modified: branches/1.6/egw-pear/HTTP/WebDAV/Server/Filesystem.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/egw-pear/HTTP/WebDAV/Server/Filesystem.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/egw-pear/HTTP/WebDAV/Server/Filesystem.php (original) +++ branches/1.6/egw-pear/HTTP/WebDAV/Server/Filesystem.php Fri Mar 5 00:09:55 2010 @@ -186,7 +186,7 @@ // type and size (caller already made sure that path exists) if (is_dir($fspath)) { // directory (WebDAV collection) - $info["props"][] = $this->mkprop("resourcetype", "collection"); + $info["props"][] = $this->mkprop("resourcetype", array($this->mkprop('collection', ''))); $info["props"][] = $this->mkprop("getcontenttype", "httpd/unix-directory"); } else { // plain file (WebDAV resource) Modified: branches/1.6/infolog/inc/class.infolog_bo.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/infolog/inc/class.infolog_bo.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/infolog/inc/class.infolog_bo.inc.php (original) +++ branches/1.6/infolog/inc/class.infolog_bo.inc.php Fri Mar 5 00:09:55 2010 @@ -420,13 +420,13 @@ /** * Read an infolog entry specified by $info_id * - * @param int/array $info_id integer id or array with key 'info_id' of the entry to read + * @param int|array $info_id integer id or array with key 'info_id' of the entry to read * @param boolean $run_link_id2from=true should link_id2from run, default yes, * need to be set to false if called from link-title to prevent an infinit recursion * @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, * 'array'=array or string with date-format * - * @return array/boolean infolog entry, null if not found or false if no permission to read it + * @return array|boolean infolog entry, null if not found or false if no permission to read it */ function &read($info_id,$run_link_id2from=true,$date_format='ts') { Modified: branches/1.6/infolog/inc/class.infolog_groupdav.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/infolog/inc/class.infolog_groupdav.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/infolog/inc/class.infolog_groupdav.inc.php (original) +++ branches/1.6/infolog/inc/class.infolog_groupdav.inc.php Fri Mar 5 00:09:55 2010 @@ -57,7 +57,7 @@ if (!is_array($info)) $info = $this->bo->read($info); $name = $info[self::PATH_ATTRIBUTE]; } - return '/infolog/'.$name.'.ics'; + return $name.'.ics'; } /** @@ -72,6 +72,8 @@ function propfind($path,$options,&$files,$user,$id='') { $starttime = microtime(true); + + $myself = ($user == $GLOBALS['egw_info']['user']['account_id']); if ($options['filters']) { @@ -113,14 +115,17 @@ $filter = array( 'info_type' => 'task', ); + + //if (!$myself) $filter['info_owner'] = $user; + if ($id) $filter['info_id'] = $id; // propfind on a single id // ToDo: add parameter to only return id & etag if (($tasks =& $this->bo->search($params=array( 'order' => 'info_datemodified', 'sort' => 'DESC', - 'filter' => 'own', // filter my: entries user is responsible for, - // filter own: entries the user own or is responsible for + 'filter' => ($myself ? 'own' : 'own'), // filter my: entries user is responsible for, + // filter own: entries the user own or is responsible for 'date_format' => 'server', 'col_filter' => $filter, )))) @@ -148,7 +153,7 @@ $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it } $files['files'][] = array( - 'path' => self::get_path($task), + 'path' => $path.self::get_path($task), 'props' => $props, ); } @@ -193,8 +198,11 @@ { return $ok; } + $handler = $this->_get_handler(); - if (!($info_id = $handler->importVTODO($options['content'],is_numeric($id) ? $id : -1))) + $vTodo = htmlspecialchars_decode($options['content']); + + if (!($info_id = $handler->importVTODO($vTodo,is_numeric($id) ? $id : -1, false, $user))) { if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false"); return '403 Forbidden'; @@ -202,7 +210,8 @@ header('ETag: '.$this->get_etag($info_id)); if (is_null($ok) || $id != $info_id) { - header('Location: '.$this->base_uri.self::get_path($info_id)); + $path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']); + header('Location: '.$path.self::get_path($info_id)); return '201 Created'; } return true; @@ -263,36 +272,38 @@ { return false; } - return '"'.$info['info_id'].':'.$info['info_datemodified'].'"'; + return 'EGw-'.$info['info_id'].':'.$info['info_datemodified'].'-wGE'; } /** * Add extra properties for calendar collections * * @param array $props=array() regular props by the groupdav handler + * @param string $displayname * @param string $base_uri=null base url of handler * @return array */ - static function extra_properties(array $props=array(), $base_uri=null) + static function extra_properties(array $props=array(), $displayname, $base_uri=null) { // calendar description $displayname = $GLOBALS['egw']->translation->convert(lang('Tasks of') . ' ' . - $GLOBALS['egw_info']['user']['account_fullname'], + $displayname, $GLOBALS['egw']->translation->charset(),'utf-8'); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname); // email of the current user, see caldav-sheduling draft - $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$GLOBALS['egw_info']['user']['email']); + $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array( + HTTP_WebDAV_Server::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))); // supported components, currently only VEVENT $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array( // HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')), HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), )); - /* + $props[] = HTTP_WebDAV_Server::mkprop('supported-report-set',array( HTTP_WebDAV_Server::mkprop('supported-report',array( HTTP_WebDAV_Server::mkprop('report', HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget')))))); - */ + return $props; } Modified: branches/1.6/infolog/inc/class.infolog_ical.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/infolog/inc/class.infolog_ical.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/infolog/inc/class.infolog_ical.inc.php (original) +++ branches/1.6/infolog/inc/class.infolog_ical.inc.php Fri Mar 5 00:09:55 2010 @@ -380,9 +380,10 @@ * @param string $_vcalData * @param int $_taskID=-1 info_id, default -1 = new entry * @param boolean $merge=false merge data with existing entry + * @param int $user=null delegate new task to this account_id, default null * @return int|boolean integer info_id or false on error */ - function importVTODO(&$_vcalData, $_taskID=-1, $merge=false) + function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null) { if (!($taskData = $this->vtodotoegw($_vcalData,$_taskID))) return false; @@ -395,6 +396,11 @@ if (empty($taskData['info_datecompleted'])) { $taskData['info_datecompleted'] = 0; + } + + if (!is_null($user)) + { + $taskData['info_responsible'] = array($user); } if ($this->log) Modified: branches/1.6/phpgwapi/inc/class.groupdav.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/phpgwapi/inc/class.groupdav.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/phpgwapi/inc/class.groupdav.inc.php (original) +++ branches/1.6/phpgwapi/inc/class.groupdav.inc.php Fri Mar 5 00:09:55 2010 @@ -37,6 +37,10 @@ class groupdav extends HTTP_WebDAV_Server { /** + * DAV namespace + */ + const DAV = 'DAV:'; + /** * GroupDAV namespace */ const GROUPDAV = 'http://groupdav.org/';; @@ -107,6 +111,12 @@ * @var string */ var $principalURL; + /** + * Reference to the accounts class + * + * @var accounts + */ + var $accounts; function __construct() @@ -122,6 +132,8 @@ case 'davkit': // iCal app in OS X 10.6 created wrong request, if full url given $this->client_require_href_as_url = false; break; + case 'cfnetwork': + $this->crrnd = true; // Apple Addressbook.app does not cope with namespace redundancy } parent::HTTP_WebDAV_Server(); @@ -136,6 +148,8 @@ $this->principalURL = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:") . '//' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '/'; } + $this->principalURL .= 'principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/'; + $this->accounts = $GLOBALS['egw']->accounts; } /** @@ -162,12 +176,24 @@ switch($app) { case 'calendar': - case 'infolog': + $dav[] = 2; + $dav[] = 'access-control'; $dav[] = 'calendar-access'; + //$dav[] = 'calendar-schedule'; + //$dav[] = 'calendar-proxy'; + //$dav[] = 'calendar-avialibility'; + //$dav[] = 'calendarserver-private-events'; break; case 'addressbook': - $dav[] = 'addressbook'; + $dav[] = 2; + $dav[] = 3; + $dav[] = 'access-control'; + $dav[] = 'addressbook-access'; break; + default: + $dav[] = 2; + $dav[] = 'access-control'; + $dav[] = 'calendar-access'; } // not yet implemented: $dav[] = 'access-control'; } @@ -179,77 +205,101 @@ * @param array return array for file properties * @return bool true on success */ - function PROPFIND(&$options, &$files,$method='PROPFIND') + function PROPFIND(&$options, &$files, $method='PROPFIND') { if ($this->debug) error_log(__CLASS__."::$method(".array2string($options,true).')'); + + if (groupdav_handler::get_agent() == 'cfnetwork' && // Apple Addressbook + $options['root']['name'] == 'propfind') + { + foreach ($options['props'] as $props) + { + if ($props['name'] == 'current-user-privilege-set') + { + if ($this->debug > 2) error_log(__CLASS__."::$method: current-user-privilege-set not implemented!"); + return '501 Not Implemented'; + } + } + } // parse path in form [/account_lid]/app[/more] if (!self::_parse_path($options['path'],$id,$app,$user,$user_prefix) && $app && !$user) { - if ($this->debug > 1) error_log(__CLASS__."::$method: user=$user, app=$app, id=$id: 404 not found!"); + if ($this->debug > 1) error_log(__CLASS__."::$method: user='$user', app='$app', id='$id': 404 not found!"); return '404 Not Found'; } - if ($this->debug > 1) error_log(__CLASS__."::$method: user=$user, app='$app', id=$id"); + if ($this->debug > 1) error_log(__CLASS__."::$method: user='$user', app='$app', id='$id'"); + + 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()); - - if (!$app) // root folder containing apps + $path = $user_prefix = $this->_slashify($user_prefix); + + if (!$app) // user root folder containing apps { if (empty($user_prefix)) { + $user_prefix = '/'.$GLOBALS['egw_info']['user']['account_lid'].'/'; + } + if ($options['depth']) + { $displayname = 'EGroupware (Cal|Card|Group)DAV server'; } - else - { - $displayname = $this->translation->convert($GLOBALS['egw_info']['user']['account_fullname'],$this->egw_charset,'utf-8'); - } // self url - $files['files'][] = array( - 'path' => $user_prefix.'/', - 'props' => array( + $props = array( self::mkprop('displayname',$displayname), - self::mkprop('resourcetype','collection'), + self::mkprop('resourcetype',array(self::mkprop('collection',''))), // adding the calendar extra property (calendar-home-set, etc.) here, allows apple iCal to "autodetect" the URL - self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/calendar/'))), + self::mkprop(groupdav::CALDAV,'calendar-home-set',array( + self::mkprop('href',$this->base_uri.$user_prefix.'calendar/'))), + self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array( + self::mkprop('href',$this->base_uri.$user_prefix))), self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))), - self::mkprop(groupdav::CALDAV,'calendar-user-address-set','MAILTO:'.$GLOBALS['egw_info']['user']['email']), + self::mkprop(groupdav::CALDAV,'calendar-user-address-set',array( + self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))), //self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))), //self::mkprop('principal-collection-set',array(self::mkprop('href',$this->base_uri.'/principals/'))), - ), + ); + //$props = self::current_user_privilege_set($props); + $files['files'][] = array( + 'path' => $path, + 'props' => $props, ); if ($options['depth']) { - if (empty($user_prefix)) + if (strlen($path) == 1) // GroupDAV Root { // principals collection $files['files'][] = array( 'path' => '/principals/', 'props' => array( self::mkprop('displayname',lang('Accounts')), - self::mkprop('resourcetype','collection'), + self::mkprop('resourcetype',array(self::mkprop('collection',''))), self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))), - self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/calendar/'))), - //self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))), + self::mkprop(groupdav::CALDAV,'calendar-home-set',array( + self::mkprop('href',$this->base_uri.$user_prefix.'calendar/'))), + self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array( + self::mkprop('href',$this->base_uri.'/'))), + self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))), ), ); - // 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) { if (!$GLOBALS['egw_info']['user']['apps'][$app]) continue; // no rights for the given app $files['files'][] = array( - 'path' => $user_prefix.'/'.$app.'/', + 'path' => $path.$app.'/', 'props' => $this->_properties($app,false,$user), ); } @@ -266,9 +316,9 @@ if ($method != 'REPORT' && !$id) // no self URL for REPORT requests (only PROPFIND) or propfinds on an id { $files['files'][0] = array( - 'path' => '/'.$app.'/', + 'path' => $path.$app.'/', // KAddressbook doubles the folder, if the self URL contains the GroupDAV/CalDAV resourcetypes - 'props' => $this->_properties($app,$app=='addressbook'&&strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false), + 'props' => $this->_properties($app,$app=='addressbook'&&strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false,$user), ); } if (isset($options['depth']) && !$options['depth'] && !$id) @@ -281,7 +331,7 @@ } return true; // depth 0 --> show only the self url } - return $handler->propfind($options['path'],$options,$files,$user,$id); + return $handler->propfind($this->_slashify($options['path']),$options,$files,$user,$id); } return '501 Not Implemented'; } @@ -296,25 +346,52 @@ */ function _properties($app,$no_extra_types=false,$user=null) { - if (!$user) $user = $GLOBALS['egw_info']['user']['account_fullname']; - $displayname = $this->translation->convert($GLOBALS['egw_info']['user']['account_fullname'],$this->egw_charset,'utf-8'); + if ($this->debug) error_log(__CLASS__."::$method: user='$user', app='$app'"); + if ($user) + { + $account_lid = $this->accounts->id2name($user); + } + else + { + $account_lid = $GLOBALS['egw_info']['user']['account_lid']; + } + $account = $this->accounts->read($account_lid); + $displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'], + $GLOBALS['egw']->translation->charset(),'utf-8'); $props = array( self::mkprop('current-user-principal',array(self::mkprop('href',$this->principalURL))), self::mkprop('owner',$displayname), - //self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))), - //self::mkprop('principal-collection-set',array(self::mkprop('href',$this->base_uri.'/principals/'))), + self::mkprop('principal-URL',array(self::mkprop('href',$this->principalURL))), + self::mkprop('alternate-URI-set',array( + self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))), + self::mkprop(groupdav::CALDAV,'calendar-user-address-set',array( + self::mkprop('href','MAILTO:'.$GLOBALS['egw_info']['user']['email']))), + self::mkprop('principal-collection-set',array( + self::mkprop('href',$this->base_uri.'/principals/users/'), + self::mkprop('href',$this->base_uri.'/principals/groups/'), + )), ); switch ($app) { case 'calendar': - $props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/calendar/'))); + $props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array( + self::mkprop('href',$this->base_uri.'/'.$account_lid.'/calendar/'))); break; case 'infolog': - $props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array(self::mkprop('href',$this->base_uri.'/infolog/'))); + $props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array( + self::mkprop('href',$this->base_uri.'/'.$account_lid.'/infolog/'))); + $displayname = $this->translation->convert(lang($app).' '. + common::grab_owner_name($user),$this->egw_charset,'utf-8'); + break; default: - $displayname = $this->translation->convert(lang($app).' '.common::grab_owner_name($user),$this->egw_charset,'utf-8'); - } + $props[] = self::mkprop(groupdav::CALDAV,'calendar-home-set',array( + self::mkprop('href',$this->base_uri.'/'.$account_lid.'/calendar/'))); + $displayname = $this->translation->convert(lang($app).' '. + common::grab_owner_name($user),$this->egw_charset,'utf-8'); + } + $props[] = self::mkprop(groupdav::CARDDAV,'addressbook-home-set',array( + self::mkprop('href',$this->base_uri.'/'.$account_lid.'/'))); $props[] = self::mkprop('displayname',$displayname); foreach((array)$this->root[$app] as $prop => $values) @@ -343,7 +420,9 @@ } if (method_exists($app.'_groupdav','extra_properties')) { - $props = ExecMethod2($app.'_groupdav::extra_properties',$props,$this->base_uri); + $displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'], + $GLOBALS['egw']->translation->charset(),'utf-8'); + $props = ExecMethod2($app.'_groupdav::extra_properties',$props,$displayname,$this->base_uri); } return $props; } @@ -448,8 +527,7 @@ $props = $this->props2array($file['props']); //echo $file['path']; _debug_array($props); $class = $class == 'row_on' ? 'row_off' : 'row_on'; - $name = $this->_slashify(basename($this->_unslashify($file['path']))); - /* + if (substr($file['path'],-1) == '/') { $name = basename(substr($file['path'],0,-1)).'/'; @@ -458,7 +536,7 @@ { $name = basename($file['path']); } - */ + echo "\t<tr class='$class'>\n\t\t<td>$n</td>\n\t\t<td>".html::a_href(htmlspecialchars($name),'/groupdav.php'.$file['path'])."</td>\n"; echo "\t\t<td>".$props['DAV:getcontentlength']."</td>\n"; echo "\t\t<td>".(!empty($props['DAV:getlastmodified']) ? date('Y-m-d H:i:s',$props['DAV:getlastmodified']) : '')."</td>\n"; @@ -761,7 +839,7 @@ } $parts = explode('/', $this->_unslashify($path)); - if ($GLOBALS['egw']->accounts->name2id($parts[0])) + if ($this->accounts->name2id($parts[0])) { // /$user/$app/... $user = array_shift($parts); @@ -772,7 +850,7 @@ if ($user) { $user_prefix = '/'.$user; - $user = $GLOBALS['egw']->accounts->name2id($user,'account_lid',$app != 'addressbook' ? 'u' : null); + $user = $this->accounts->name2id($user,'account_lid',$app != 'addressbook' ? 'u' : null); } else { @@ -785,13 +863,39 @@ list($id) = explode('.',$id); // remove evtl. .ics extension } - if (!($ok = $id && in_array($app,array('addressbook','calendar','infolog','principals','groups')) && $user)) - { - if ($this->debug) - { - error_log(__METHOD__."('$path') returning false: id=$id, app='$app', user=$user"); - } + $ok = $id && $user && in_array($app,array('addressbook','calendar','infolog','principals','groups')); + if ($this->debug) + { + error_log(__METHOD__."('$path') returning " . ($ok ? 'true' : 'false') . ": id='$id', app='$app', user='$user', user_prefix='$user_prefix'"); } return $ok; } + /** + * Add the privileges of the current user + * + * @param array $props=array() regular props by the groupdav handler + * @return array + */ + static function current_user_privilege_set(array $props=array()) + { + $props[] = HTTP_WebDAV_Server::mkprop('current-user-privilege-set', + array(HTTP_WebDAV_Server::mkprop('privilege', + array(//HTTP_WebDAV_Server::mkprop('all',''), + HTTP_WebDAV_Server::mkprop('read',''), + HTTP_WebDAV_Server::mkprop('read-free-busy',''), + //HTTP_WebDAV_Server::mkprop('read-current-user-privilege-set',''), + HTTP_WebDAV_Server::mkprop('bind',''), + HTTP_WebDAV_Server::mkprop('unbind',''), + HTTP_WebDAV_Server::mkprop('schedule-post',''), + HTTP_WebDAV_Server::mkprop('schedule-post-vevent',''), + HTTP_WebDAV_Server::mkprop('schedule-respond',''), + HTTP_WebDAV_Server::mkprop('schedule-respond-vevent',''), + HTTP_WebDAV_Server::mkprop('schedule-deliver',''), + HTTP_WebDAV_Server::mkprop('schedule-deliver-vevent',''), + HTTP_WebDAV_Server::mkprop('write',''), + HTTP_WebDAV_Server::mkprop('write-properties',''), + HTTP_WebDAV_Server::mkprop('write-content',''), + )))); + return $props; + } } Modified: branches/1.6/phpgwapi/inc/class.groupdav_handler.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/phpgwapi/inc/class.groupdav_handler.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/phpgwapi/inc/class.groupdav_handler.inc.php (original) +++ branches/1.6/phpgwapi/inc/class.groupdav_handler.inc.php Fri Mar 5 00:09:55 2010 @@ -38,6 +38,12 @@ */ var $translation; /** + * Reference to the accounts class + * + * @var accounts + */ + var $accounts; + /** * Translates method names into ACL bits * * @var array @@ -88,7 +94,6 @@ */ function __construct($app,$debug=null,$base_uri=null,$principalURL=null) { - //error_log(__METHOD__." called"); $this->app = $app; if (!is_null($debug)) $this->debug = $debug; $this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME']; @@ -99,13 +104,15 @@ } else { - $this->principalURL = $principalURL; + $this->principalURL = $principalURL.'principals/users/'. + $GLOBALS['egw_info']['user']['account_lid'].'/'; } $this->agent = self::get_agent(); $this->translation =& $GLOBALS['egw']->translation; $this->egw_charset = $this->translation->charset(); + $this->accounts = $GLOBALS['egw']->accounts; } /** @@ -122,12 +129,13 @@ /** * Propfind callback, if interator is used * + * @param string $path * @param array $filter * @param array|boolean $start false=return all or array(start,num) * @param int &$total * @return array with "files" array with values for keys path and props */ - function &propfind_callback(array $filter,$start,&$total) { } + function &propfind_callback($path, array $filter,$start,&$total) { } /** * Handle get request for an applications entry @@ -178,10 +186,11 @@ * Add extra properties for collections * * @param array $props=array() regular props by the groupdav handler + * @param string $displayname * @param string $base_uri=null base url of handler * @return array */ - static function extra_properties(array $props=array(), $base_uri=null) + static function extra_properties(array $props=array(), $displayname, $base_uri=null) { return $props; } @@ -203,7 +212,7 @@ // error_log(__METHOD__."(".array2string($entry).") Cant create etag!"); return false; } - return '"'.$entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']).'"'; + return 'EGw-'.$entry['id'].':'.(isset($entry['etag']) ? $entry['etag'] : $entry['modified']).'-wGE'; } /** @@ -214,7 +223,7 @@ */ static function etag2value($etag) { - list(,$val) = explode(':',substr($etag,1,-1),2); + list(,$val) = explode(':',substr($etag,4,-4),2); return $val; } @@ -278,6 +287,7 @@ * * @static * @param string $app 'calendar', 'addressbook' or 'infolog' + * @param int $user=null owner of the collection, default current user * @param int $debug=null debug-level to set * @param string $base_uri=null base url of handler * @param string $principalURL=null pricipal url of handler @@ -297,7 +307,9 @@ $handler_cache[$app]->$debug = $debug; $handler_cache[$app]->$base_uri = $base_uri; $handler_cache[$app]->$principalURL = $principalURL; - if ($debug) error_log(__METHOD__."($app, $base_uri, $principalURL)"); + + if ($debug) error_log(__METHOD__."('$app', '$base_uri', '$principalURL')"); + return $handler_cache[$app]; } @@ -317,6 +329,7 @@ $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']); foreach(array( 'davkit' => 'davkit', // Apple iCal + 'cfnetwork' => 'cfnetwork', // Apple Addressbook 'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net 'zideone' => 'zideone', // zideone outlook plugin 'lightning' => 'lightning', // Lighting (SOGo connector for addressbook) @@ -357,6 +370,13 @@ class groupdav_propfind_iterator implements Iterator { /** + * current path + * + * @var string + */ + protected $path; + + /** * Handler to call for entries * * @var groupdav_handler @@ -375,8 +395,16 @@ * * @var array */ + protected $common_files; + + /** + * current chunk + * + * @var array + */ protected $files; + /** * Start value for callback * @@ -396,6 +424,8 @@ * @var boolean */ public $debug = false; + + /** /** * Constructor @@ -404,13 +434,14 @@ * @param array $filter filter for propfind call * @param array $files=null extra files/responses to return too */ - public function __construct(groupdav_handler $handler,array $filter,array &$files=null) - { - if ($this->debug) error_log(__METHOD__."(,".array2string($filter).",)"); - + public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=null) + { + if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)"); + $this->path = $path; $this->handler = $handler; $this->filter = $filter; $this->files = $files; + $this->common_files = $files; reset($this->files); } @@ -422,7 +453,6 @@ public function current() { if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files))); - return current($this->files); } @@ -447,21 +477,20 @@ if (next($this->files) !== false) { if ($this->debug) error_log(__METHOD__."() returning TRUE"); - return true; } - if (is_array($this->files) && count($this->files) < self::CHUNK_SIZE) // less entries then asked --> no further available + if (is_array($this->files) && count($this->files) < self::CHUNK_SIZE) // less entries then asked --> no further available { if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)"); - return false; // no further entries } // try query further files via propfind callback of handler and store result in $this->files - $this->files = $this->handler->propfind_callback($this->filter,array($this->start,self::CHUNK_SIZE)); + $this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE)); $this->start += self::CHUNK_SIZE; reset($this->files); if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false)); + return current($this->files) !== false; } @@ -474,7 +503,8 @@ // query first set of files via propfind callback of handler and store result in $this->files $this->start = 0; - $this->files = $this->handler->propfind_callback($this->filter,array($this->start,self::CHUNK_SIZE)); + $files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE)); + $this->files = $this->common_files + $files; $this->start += self::CHUNK_SIZE; reset($this->files); } Modified: branches/1.6/phpgwapi/inc/class.groupdav_principals.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/phpgwapi/inc/class.groupdav_principals.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/phpgwapi/inc/class.groupdav_principals.inc.php (original) +++ branches/1.6/phpgwapi/inc/class.groupdav_principals.inc.php Fri Mar 5 00:09:55 2010 @@ -7,7 +7,7 @@ * @package api * @subpackage groupdav * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> - * @copyright (c) 2008 by Ralf Becker <RalfBecker-AT-outdoor-training.de> + * @copyright (c) 2008-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @version $Id$ */ @@ -16,12 +16,6 @@ */ class groupdav_principals extends groupdav_handler { - /** - * Reference to the accounts class - * - * @var accounts - */ - var $accounts; /** * Constructor @@ -34,8 +28,6 @@ function __construct($app,$debug=null,$base_uri=null,$principalURL=null) { parent::__construct($app,$debug,$base_uri,$principalURL); - - $this->accounts = $GLOBALS['egw']->accounts; } /** @@ -49,10 +41,41 @@ */ function propfind($path,$options,&$files,$user) { - if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id)"); + list(,$principals,$type,$name,$rest) = explode('/',$path,5); + // /principals/users/$name/ + // /users/$name/calendar-proxy-read/ + // /users/$name/calendar-proxy-write/ + // /groups/$name/ + // /resources/$resource/ + // /__uids__/$uid/.../ + + switch($type) + { + case 'users': + $files['files'] = $this->propfind_users($name,$rest,$options); + break; + case 'groups': + $files['files'] = $this->propfind_groups($name,$rest,$options); + break; + case 'resources': + $files['files'] = $this->propfind_resources($name,$rest,$options); + break; + case '__uids__': + $files['files'] = $this->propfind_uids($name,$rest,$options); + break; + case '': + $files['files'] = $this->propfind_principals($options); + break; + default: + return '404 Not Found'; + } + if (!is_array($files['files'])) + { + return $files['files']; + } + return true; list(,,$id) = explode('/',$path); - if ($id && !($id = $this->accounts->id2name($id))) { return false; @@ -61,31 +84,18 @@ { $displayname = $GLOBALS['egw']->translation->convert($account['account_fullname'], $GLOBALS['egw']->translation->charset(),'utf-8'); - if ($options['root']['name'] == 'principal-search-property-set') - { - $props = array(HTTP_WebDAV_Server::mkprop('principal-search-property', - array(HTTP_WebDAV_Server::mkprop('prop', - array(HTTP_WebDAV_Server::mkprop('displayname',$displayname)) - ), - HTTP_WebDAV_Server::mkprop('description', 'Full name'))) - ); - } - else - { - $props = array( - HTTP_WebDAV_Server::mkprop('displayname',$displayname), - HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($account)), - HTTP_WebDAV_Server::mkprop('resourcetype','principal'), - HTTP_WebDAV_Server::mkprop('alternate-URI-set',''), - HTTP_WebDAV_Server::mkprop('current-user-principal',array(HTTP_WebDAV_Server::mkprop('href',$this->principalURL))), - HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/calendar/'))), - HTTP_WebDAV_Server::mkprop(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); - } + $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[] = HTTP_WebDAV_Server::mkprop('group-membership',$this->base_uri.'/groups/'.$group); } $files['files'][] = array( 'path' => '/principals/'.$account['account_lid'], @@ -93,7 +103,250 @@ ); 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 @@ { return $account; } - $displayname = $GLOBALS['egw']->translation->convert( + $name = $GLOBALS['egw']->translation->convert( trim($account['account_firstname'].' '.$account['account_lastname']), $GLOBALS['egw']->translation->charset(),'utf-8'); $options['data'] = 'Principal: '.$account['account_lid']. "\nURL: ".$this->base_uri.$options['path']. - "\nName: ".$displayname. + "\nName: ".$name. "\nEmail: ".$account['account_email']. "\nMemberships: ".implode(', ',$this->accounts->memberships($id))."\n"; $options['mimetype'] = 'text/plain; charset=utf-8'; @@ -156,7 +409,8 @@ */ function read($id) { - return $this->accounts->read($id); + return false; + //return $this->accounts->read($id); } /** @@ -191,6 +445,6 @@ { $account = $this->read($account); } - return '"'.$account['account_id'].':'.md5(serialize($account)).'"'; + return 'EGw-'.$account['account_id'].':'.md5(serialize($account)).'-wGE'; } } Modified: branches/1.6/phpgwapi/inc/class.vfs_webdav_server.inc.php URL: http://www.egroupware.org/viewvc/egroupware/branches/1.6/phpgwapi/inc/class.vfs_webdav_server.inc.php?rev=29385&r1=29384&r2=29385&view=diff ============================================================================== --- branches/1.6/phpgwapi/inc/class.vfs_webdav_server.inc.php (original) +++ branches/1.6/phpgwapi/inc/class.vfs_webdav_server.inc.php Fri Mar 5 00:09:55 2010 @@ -263,7 +263,8 @@ // type and size (caller already made sure that path exists) if (is_dir($fspath)) { // directory (WebDAV collection) - $info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', 'collection'); + $info['props'][] = HTTP_WebDAV_Server::mkprop ('resourcetype', array( + HTTP_WebDAV_Server::mkprop('collection', ''))); $info['props'][] = HTTP_WebDAV_Server::mkprop ('getcontenttype', 'httpd/unix-directory'); } else { // plain file (WebDAV resource) |
From: <ralfbecker@us...> - 2010-03-04 17:18:39
|
Author: ralfbecker Date: Thu Mar 4 18:18:30 2010 New Revision: 29382 URL: http://www.egroupware.org/viewvc/egroupware?rev=29382&view=rev Log: dont use IN ( ), if there's only one value, it's slower for MySQL Modified: trunk/phpgwapi/inc/class.egw_db.inc.php Modified: trunk/phpgwapi/inc/class.egw_db.inc.php URL: http://www.egroupware.org/viewvc/egroupware/trunk/phpgwapi/inc/class.egw_db.inc.php?rev=29382&r1=29381&r2=29382&view=diff ============================================================================== --- trunk/phpgwapi/inc/class.egw_db.inc.php (original) +++ trunk/phpgwapi/inc/class.egw_db.inc.php Thu Mar 4 18:18:30 2010 @@ -7,7 +7,7 @@ * @package api * @subpackage db * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> - * @copyright (c) 2003-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de> + * @copyright (c) 2003-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @version $Id$ */ @@ -1469,6 +1469,11 @@ { $maxlength = $column_definitions[$key]['type'] == 'varchar' ? $column_definitions[$key]['precision'] : null; } + // dont use IN ( ), if there's only one value, it's slower for MySQL + if (is_array($data) && count($data) == 1) + { + $data = array_shift($data); + } if (is_array($data)) { $or_null = ''; |
From: <ralfbecker@us...> - 2010-03-04 17:07:19
|
Author: ralfbecker Date: Thu Mar 4 18:07:10 2010 New Revision: 29379 URL: http://www.egroupware.org/viewvc/egroupware?rev=29379&view=rev Log: Preseed link title-cache for link-list and link-string widget (Performance improvment, as all titles of an application get queried in a single query and NOT once for every link) Modified: trunk/etemplate/inc/class.link_widget.inc.php trunk/phpgwapi/inc/class.egw_link.inc.php Modified: trunk/etemplate/inc/class.link_widget.inc.php URL: http://www.egroupware.org/viewvc/egroupware/trunk/etemplate/inc/class.link_widget.inc.php?rev=29379&r1=29378&r2=29379&view=diff ============================================================================== --- trunk/etemplate/inc/class.link_widget.inc.php (original) +++ trunk/etemplate/inc/class.link_widget.inc.php Thu Mar 4 18:07:10 2010 @@ -195,7 +195,7 @@ } if ($value['to_id'] && $value['to_app']) { - $value = egw_link::get_links($value['to_app'],$value['to_id'],$only_app = $value['only_app']); + $value = egw_link::get_links($value['to_app'],$value['to_id'],$only_app = $value['only_app'],'link_lastmod DESC',true); if ($only_app) { foreach($value as $key => $id) @@ -287,7 +287,7 @@ { $value['title'] = egw_link::title($app,$id); } - $links = egw_link::get_links($app,$id); + $links = egw_link::get_links($app,$id,'','link_lastmod DESC',true); $value['anz_links'] = count($links); $extension_data = $value; Modified: trunk/phpgwapi/inc/class.egw_link.inc.php URL: http://www.egroupware.org/viewvc/egroupware/trunk/phpgwapi/inc/class.egw_link.inc.php?rev=29379&r1=29378&r2=29379&view=diff ============================================================================== --- trunk/phpgwapi/inc/class.egw_link.inc.php (original) +++ trunk/phpgwapi/inc/class.egw_link.inc.php Thu Mar 4 18:07:10 2010 @@ -56,6 +56,11 @@ * 'file_access' => 'app.class.method', // method to be called to check file access rights, see links_stream_wrapper class * // boolean file_access(string $id,int $check,string $rel_path) * 'find_extra' => array('name_preg' => '/^(?!.picture.jpg)$/') // extra options to egw_vfs::find, to eg. remove some files from the list of attachments + * 'edit' => array( + * 'menuaction' => 'app.class.method', + * ), + * 'edit_id' => 'app_id', + * 'edit_popup' => '400x300', * } * All entries are optional, thought you only get conected functionality, if you implement them ... * @@ -283,9 +288,10 @@ * @param string/array $id id of entry in $app or array of links if entry not yet created * @param string $only_app if set return only links from $only_app (eg. only addressbook-entries) or NOT from if $only_app[0]=='!' * @param string $order='link_lastmod DESC' defaults to newest links first + * @param boolean $cache_titles=false should all titles be queryed and cached (allows to query each link app only once!) * @return array of links or empty array if no matching links found */ - static function get_links( $app,$id,$only_app='',$order='link_lastmod DESC' ) + static function get_links( $app,$id,$only_app='',$order='link_lastmod DESC',$cache_titles=false ) { if (self::DEBUG) echo "<p>egw_link::get_links(app='$app',id='$id',only_app='$only_app',order='$order')</p>\n"; @@ -319,7 +325,21 @@ } } //echo "ids=<pre>"; print_r($ids); echo "</pre>\n"; - + if ($cache_titles) + { + // agregate links by app + $app_ids = array(); + foreach($ids as $link) + { + $app_ids[$link['app']][] = $link['id']; + } + reset($ids); + + foreach($app_ids as $appname => $a_ids) + { + self::titles($appname,array_unique($a_ids)); + } + } return $ids; } |
From: <ralfbecker@us...> - 2010-03-04 15:40:01
|
Author: ralfbecker Date: Thu Mar 4 16:39:52 2010 New Revision: 29378 URL: http://www.egroupware.org/viewvc/egroupware?rev=29378&view=rev Log: Create an index over egw_cal_user.cal_user_type and cal_user_id, to speed up calendar queries Modified: trunk/calendar/setup/setup.inc.php trunk/calendar/setup/tables_current.inc.php trunk/calendar/setup/tables_update.inc.php Modified: trunk/calendar/setup/setup.inc.php URL: http://www.egroupware.org/viewvc/egroupware/trunk/calendar/setup/setup.inc.php?rev=29378&r1=29377&r2=29378&view=diff ============================================================================== --- trunk/calendar/setup/setup.inc.php (original) +++ trunk/calendar/setup/setup.inc.php Thu Mar 4 16:39:52 2010 @@ -10,7 +10,7 @@ */ $setup_info['calendar']['name'] = 'calendar'; -$setup_info['calendar']['version'] = '1.7.008'; +$setup_info['calendar']['version'] = '1.7.009'; $setup_info['calendar']['app_order'] = 3; $setup_info['calendar']['enable'] = 1; $setup_info['calendar']['index'] = 'calendar.calendar_uiviews.index'; @@ -65,8 +65,3 @@ 'from' => 'Calendar', ), ); - - - - - Modified: trunk/calendar/setup/tables_current.inc.php URL: http://www.egroupware.org/viewvc/egroupware/trunk/calendar/setup/tables_current.inc.php?rev=29378&r1=29377&r2=29378&view=diff ============================================================================== --- trunk/calendar/setup/tables_current.inc.php (original) +++ trunk/calendar/setup/tables_current.inc.php Thu Mar 4 16:39:52 2010 @@ -80,7 +80,7 @@ ), 'pk' => array('cal_id','cal_recur_date','cal_user_type','cal_user_id'), 'fk' => array(), - 'ix' => array(), + 'ix' => array(array('cal_user_type','cal_user_id')), 'uc' => array() ), 'egw_cal_extra' => array( Modified: trunk/calendar/setup/tables_update.inc.php URL: http://www.egroupware.org/viewvc/egroupware/trunk/calendar/setup/tables_update.inc.php?rev=29378&r1=29377&r2=29378&view=diff ============================================================================== --- trunk/calendar/setup/tables_update.inc.php (original) +++ trunk/calendar/setup/tables_update.inc.php Thu Mar 4 16:39:52 2010 @@ -2052,3 +2052,16 @@ } return $GLOBALS['setup_info']['calendar']['currentver'] = '1.7.008'; } + +/** + * Create an index over egw_cal_user.cal_user_type and cal_user_id, to speed up calendar queries + * + * @return string + */ +function calendar_upgrade1_7_008() +{ + $GLOBALS['egw_setup']->oProc->CreateIndex('egw_cal_user',array('cal_user_type','cal_user_id')); + + return $GLOBALS['setup_info']['calendar']['currentver'] = '1.7.009'; +} + |
From: <leithoff@us...> - 2010-03-04 12:05:52
|
Author: leithoff Date: Thu Mar 4 13:05:42 2010 New Revision: 29376 URL: http://www.egroupware.org/viewvc/egroupware?rev=29376&view=rev Log: pdo statement->execute expects either the prepared statement with already bound parameters OR an array of the vars to be bound. It can NOT handle them MIXED Modified: trunk/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php Modified: trunk/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php URL: http://www.egroupware.org/viewvc/egroupware/trunk/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php?rev=29376&r1=29375&r2=29376&view=diff ============================================================================== --- trunk/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php (original) +++ trunk/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php Thu Mar 4 13:05:42 2010 @@ -326,16 +326,24 @@ if ($this->operation == self::STORE2FS) { $stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_size=:fs_size,fs_mime=:fs_mime,fs_modifier=:fs_modifier,fs_modified=:fs_modified WHERE fs_id=:fs_id'); + if (!($ret = $stmt->execute($values))) + { + error_log(__METHOD__."() execute() failed! errorInfo()=".array2string(self::$pdo->errorInfo())); + } } else { $stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_size=:fs_size,fs_mime=:fs_mime,fs_modifier=:fs_modifier,fs_modified=:fs_modified,fs_content=:fs_content WHERE fs_id=:fs_id'); $this->stream_seek(0,SEEK_SET); // rewind to the start + foreach($values as $name => &$value) + { + $stmt->bindParam($name,$value); + } $stmt->bindParam('fs_content', $this->opened_stream, PDO::PARAM_LOB); - } - if (!($ret = $stmt->execute($values))) - { - error_log(__METHOD__."() execute() failed! errorInfo()=".array2string(self::$pdo->errorInfo())); + if (!($ret = $stmt->execute())) + { + error_log(__METHOD__."() execute() failed! errorInfo()=".array2string(self::$pdo->errorInfo())); + } } } $ret = fclose($this->opened_stream) && $ret; |