From 682fd42a26ea5473e06c6979b178377b6570b848 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Sat, 2 Apr 2016 10:44:17 +0000 Subject: [PATCH] move CalDAV/CardDAV server to api --- .../inc/class.addressbook_groupdav.inc.php | 82 +++---- .../src/CalDAV.php | 173 +++++++------ .../src/CalDAV/Handler.php | 232 +++--------------- .../src/CalDAV/Hooks.php | 23 +- .../src/CalDAV/Principals.php | 204 +++++++-------- api/src/CalDAV/PropfindIterator.php | 186 ++++++++++++++ api/src/Json/Tail.php | 218 ++++++++++++++++ api/src/Mail/Account.php | 2 +- calendar/inc/class.calendar_groupdav.inc.php | 140 +++++------ groupdav.php | 10 +- infolog/inc/class.infolog_groupdav.inc.php | 70 +++--- phpgwapi/inc/class.common.inc.php | 31 ++- phpgwapi/inc/class.egw_tail.inc.php | 193 +-------------- phpgwapi/inc/common_functions.inc.php | 4 + phpgwapi/js/jsapi/egw_tail.js | 12 +- phpgwapi/setup/setup.inc.php | 4 +- 16 files changed, 842 insertions(+), 742 deletions(-) rename phpgwapi/inc/class.groupdav.inc.php => api/src/CalDAV.php (93%) rename phpgwapi/inc/class.groupdav_handler.inc.php => api/src/CalDAV/Handler.php (80%) rename phpgwapi/inc/class.groupdav_hooks.inc.php => api/src/CalDAV/Hooks.php (89%) rename phpgwapi/inc/class.groupdav_principals.inc.php => api/src/CalDAV/Principals.php (86%) create mode 100644 api/src/CalDAV/PropfindIterator.php create mode 100644 api/src/Json/Tail.php diff --git a/addressbook/inc/class.addressbook_groupdav.inc.php b/addressbook/inc/class.addressbook_groupdav.inc.php index 076120a0f1..25c2aab4a7 100644 --- a/addressbook/inc/class.addressbook_groupdav.inc.php +++ b/addressbook/inc/class.addressbook_groupdav.inc.php @@ -5,7 +5,7 @@ * @link http://www.egroupware.org * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package addressbook - * @subpackage groupdav + * @subpackage carddav * @author Ralf Becker * @copyright (c) 2007-16 by Ralf Becker * @version $Id$ @@ -14,20 +14,20 @@ use EGroupware\Api; /** - * EGroupware: GroupDAV access: addressbook handler + * CalDAV/CardDAV/GroupDAV access: Addressbook handler * - * Propfind now uses a groupdav_propfind_iterator with a callback to query huge addressbooks in chunk, + * Propfind now uses a Api\CalDAV\PropfindIterator with a callback to query huge addressbooks in chunk, * without getting into problems with memory_limit. * - * Permanent error_log() calls should use $this->groupdav->log($str) instead, to be send to PHP error_log() + * Permanent error_log() calls should use $this->caldav->log($str) instead, to be send to PHP error_log() * and our request-log (prefixed with "### " after request and response, like exceptions). */ -class addressbook_groupdav extends groupdav_handler +class addressbook_groupdav extends Api\CalDAV\Handler { /** * bo class of the application * - * @var addressbook_bo + * @var Api\Contacts */ var $bo; @@ -63,13 +63,13 @@ class addressbook_groupdav extends groupdav_handler * Constructor * * @param string $app 'calendar', 'addressbook' or 'infolog' - * @param groupdav $groupdav calling class + * @param Api\CalDAV $caldav calling class */ - function __construct($app, groupdav $groupdav) + function __construct($app, Api\CalDAV $caldav) { - parent::__construct($app, $groupdav); + parent::__construct($app, $caldav); - $this->bo = new addressbook_bo(); + $this->bo = new Api\Contacts(); // since 1.9.007 we allow clients to specify the URL when creating a new contact, as specified by CardDAV // LDAP does NOT have a carddav_name attribute --> stick with id mapped to LDAP attribute uid @@ -77,12 +77,12 @@ class addressbook_groupdav extends groupdav_handler $this->bo->contact_repository != 'sql' || $this->bo->account_repository != 'sql' && strpos($_SERVER['REQUEST_URI'].'/','/addressbook-accounts/') !== false) { - groupdav_handler::$path_extension = '.vcf'; + self::$path_extension = '.vcf'; } else { - groupdav_handler::$path_attr = 'carddav_name'; - groupdav_handler::$path_extension = ''; + self::$path_attr = 'carddav_name'; + self::$path_extension = ''; } if ($this->debug) error_log(__METHOD__."() contact_repository={$this->bo->contact_repository}, account_repository={$this->bo->account_repository}, REQUEST_URI=$_SERVER[REQUEST_URI] --> path_attr=".self::$path_attr.", path_extension=".self::$path_extension); @@ -136,7 +136,7 @@ class addressbook_groupdav extends groupdav_handler // 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'])) + $options['root']['ns'] == Api\CalDAV::CARDDAV) && is_array($options['props'])) { foreach($options['props'] as $prop) { @@ -177,13 +177,13 @@ class addressbook_groupdav extends groupdav_handler else { // return iterator, calling ourself to return result in chunks - $files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']); + $files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']); } return true; } /** - * Callback for profind interator + * Callback for profind iterator * * @param string $path * @param array& $filter @@ -243,7 +243,7 @@ class addressbook_groupdav extends groupdav_handler continue; } $props = array( - 'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'), + 'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', 'text/vcard'), 'getlastmodified' => $contact['modified'], 'displayname' => $contact['n_fn'], ); @@ -251,7 +251,7 @@ class addressbook_groupdav extends groupdav_handler { $content = $handler->getVCard($contact['id'],$this->charset,false); $props['getcontentlength'] = bytes($content); - $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true); + $props[] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'address-data',$content,true); } $files[] = $this->add_resource($path, $contact, $props); } @@ -271,11 +271,11 @@ class addressbook_groupdav extends groupdav_handler $accounts_filter = $filter_in; $accounts_filter['owner'] = '0'; if ($sync_collection_report) $token_was = $this->sync_collection_token; - groupdav_handler::$path_attr = 'id'; - groupdav_handler::$path_extension = '.vcf'; + self::$path_attr = 'id'; + self::$path_extension = '.vcf'; $files = array_merge($files, $this->propfind_callback($path, $accounts_filter, false, false)); - groupdav_handler::$path_attr = 'carddav_name'; - groupdav_handler::$path_extension = ''; + self::$path_attr = 'carddav_name'; + self::$path_extension = ''; if ($sync_collection_report && $token_was > $this->sync_collection_token) { $this->sync_collection_token = $token_was; @@ -310,7 +310,7 @@ class addressbook_groupdav extends groupdav_handler $etag .= ':'.implode('-',$filter['owner']); } $props = array( - 'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'), + 'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', 'text/vcard'), 'getlastmodified' => egw_time::to($list['list_modified'],'ts'), 'displayname' => $list['list_name'], 'getetag' => '"'.$etag.'"', @@ -319,7 +319,7 @@ class addressbook_groupdav extends groupdav_handler { $content = $handler->getGroupVCard($list); $props['getcontentlength'] = bytes($content); - $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true); + $props[] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'address-data',$content,true); } $files[] = $this->add_resource($path, $list, $props); @@ -391,7 +391,7 @@ class addressbook_groupdav extends groupdav_handler switch((string)$filter['name']) { case 'param-filter': - $this->groupdav->log(__METHOD__."(...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!"); + $this->caldav->log(__METHOD__."(...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!"); break; case 'prop-filter': // can be multiple prop-filter, see example if ($matches) $prop_filters[] = implode($prop_test=='allof'?' AND ':' OR ',$matches); @@ -456,7 +456,7 @@ class addressbook_groupdav extends groupdav_handler } // fall through default: - $this->groupdav->log(__METHOD__."(".array2string($options).",,$id) unknown filter=".array2string($filter).' --> ignored'); + $this->caldav->log(__METHOD__."(".array2string($options).",,$id) unknown filter=".array2string($filter).' --> ignored'); break; } } @@ -498,11 +498,11 @@ class addressbook_groupdav extends groupdav_handler case 'sync-level': if ($option['data'] != '1') { - $this->groupdav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other'])); + $this->caldav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other'])); } break; default: - $this->groupdav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other'])); + $this->caldav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other'])); break; } } @@ -517,7 +517,7 @@ class addressbook_groupdav extends groupdav_handler $parts = explode('/',$option['data']); if (($id = urldecode(array_pop($parts)))) { - $ids[] = groupdav_handler::$path_extension ? basename($id,groupdav_handler::$path_extension) : $id; + $ids[] = self::$path_extension ? basename($id,self::$path_extension) : $id; } } } @@ -526,7 +526,7 @@ class addressbook_groupdav extends groupdav_handler } elseif ($id) { - $filters[self::$path_attr] = groupdav_handler::$path_extension ? basename($id,groupdav_handler::$path_extension) : $id; + $filters[self::$path_attr] = self::$path_extension ? basename($id,self::$path_extension) : $id; } //error_log(__METHOD__."() options[other]=".array2string($options['other'])." --> filters=".array2string($filters)); return true; @@ -848,27 +848,27 @@ class addressbook_groupdav extends groupdav_handler if (!isset($props['addressbook-description'])) { // default addressbook description: can be overwritten via PROPPATCH, in which case it's already set - $props['addressbook-description'] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-description',$props['displayname']); + $props['addressbook-description'] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-description',$props['displayname']); } // setting an max image size, so iOS scales the images before transmitting them // we currently scale down to width of 240px, which tests shown to be ~20k - $props['max-image-size'] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'max-image-size',24*1024); + $props['max-image-size'] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'max-image-size',24*1024); // supported reports (required property for CardDAV) $props['supported-report-set'] = array( - 'addressbook-query' => HTTP_WebDAV_Server::mkprop('supported-report',array( - HTTP_WebDAV_Server::mkprop('report',array( - HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-query',''))))), - 'addressbook-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array( - HTTP_WebDAV_Server::mkprop('report',array( - HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget',''))))), + 'addressbook-query' => Api\CalDAV::mkprop('supported-report',array( + Api\CalDAV::mkprop('report',array( + Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-query',''))))), + 'addressbook-multiget' => Api\CalDAV::mkprop('supported-report',array( + Api\CalDAV::mkprop('report',array( + Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-multiget',''))))), ); // only advertice rfc 6578 sync-collection report, if "delete-prevention" is switched on (deleted entries get marked deleted but not actualy deleted if ($GLOBALS['egw_info']['server']['history']) { - $props['supported-report-set']['sync-collection'] = HTTP_WebDAV_Server::mkprop('supported-report',array( - HTTP_WebDAV_Server::mkprop('report',array( - HTTP_WebDAV_Server::mkprop('sync-collection',''))))); + $props['supported-report-set']['sync-collection'] = Api\CalDAV::mkprop('supported-report',array( + Api\CalDAV::mkprop('report',array( + Api\CalDAV::mkprop('sync-collection',''))))); } return $props; } diff --git a/phpgwapi/inc/class.groupdav.inc.php b/api/src/CalDAV.php similarity index 93% rename from phpgwapi/inc/class.groupdav.inc.php rename to api/src/CalDAV.php index 4d5945af3d..e4aee23d2d 100644 --- a/phpgwapi/inc/class.groupdav.inc.php +++ b/api/src/CalDAV.php @@ -5,13 +5,21 @@ * @link http://www.egroupware.org * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package api - * @subpackage groupdav + * @subpackage caldav * @author Ralf Becker * @copyright (c) 2007-16 by Ralf Becker * @version $Id$ */ -require_once(EGW_INCLUDE_ROOT.'/api/src/WebDAV/Server.php'); +namespace EGroupware\Api; + +use EGroupware\Api\CalDAV\Handler; +use EGroupware\Api\CalDAV\Principals; + +// explicit import non-namespaced classes +require_once(__DIR__.'/WebDAV/Server.php'); +use HTTP_WebDAV_Server; +use calendar_hooks; /** * EGroupware: GroupDAV access @@ -54,7 +62,7 @@ require_once(EGW_INCLUDE_ROOT.'/api/src/WebDAV/Server.php'); * @link http://carddav.calconnect.org/ CardDAV resources * @link http://calendarserver.org/ Apple calendar and contacts server */ -class groupdav extends HTTP_WebDAV_Server +class CalDAV extends HTTP_WebDAV_Server { /** * DAV namespace @@ -141,7 +149,7 @@ class groupdav extends HTTP_WebDAV_Server /** * Instance of our application specific handler * - * @var groupdav_handler + * @var Handler */ var $handler; /** @@ -228,7 +236,7 @@ class groupdav extends HTTP_WebDAV_Server $this->crrnd = false; // identify clients, which do NOT support path AND full url in of PROPFIND request - switch(($agent = groupdav_handler::get_agent())) + switch(($agent = Handler::get_agent())) { case 'kde': // KAddressbook (at least in 3.5 can NOT subscribe / does NOT find addressbook) $this->client_require_href_as_url = true; @@ -262,7 +270,7 @@ class groupdav extends HTTP_WebDAV_Server }*/ //error_log($_SERVER['REQUEST_URI']." --> ".$this->_SERVER['REQUEST_URI']); - $this->egw_charset = translation::charset(); + $this->egw_charset = Translation::charset(); if (strpos($this->base_uri, 'http') === 0) { $this->current_user_principal = $this->_slashify($this->base_uri); @@ -288,13 +296,13 @@ class groupdav extends HTTP_WebDAV_Server * get the handler for $app * * @param string $app - * @return groupdav_handler + * @return Handler */ function app_handler($app) { if (isset($this->root[$app]['app'])) $app = $this->root[$app]['app']; - return groupdav_handler::app_handler($app,$this); + return Handler::app_handler($app,$this); } /** @@ -632,7 +640,7 @@ class groupdav extends HTTP_WebDAV_Server $displayname = 'EGroupware (Cal|Card|Group)DAV server'; } - $displayname = translation::convert($displayname, translation::charset(),'utf-8'); + $displayname = Translation::convert($displayname, Translation::charset(),'utf-8'); // self url $props = array( 'displayname' => $displayname, @@ -710,12 +718,12 @@ class groupdav extends HTTP_WebDAV_Server } if ($depth) { - foreach(groupdav_principals::get_resources() as $resource) + foreach(Principals::get_resources() as $resource) { - if ($is_location == groupdav_principals::resource_is_location($resource)) + if ($is_location == Principals::resource_is_location($resource)) { $files['files'][] = $this->add_app('calendar', false, 'r'.$resource['res_id'], - '/'.groupdav_principals::resource2name($resource, $is_location).'/'); + '/'.Principals::resource2name($resource, $is_location).'/'); } } } @@ -800,11 +808,11 @@ class groupdav extends HTTP_WebDAV_Server { if ($this->debug) error_log(__METHOD__."(app='$app', no_extra_types=$no_extra_types, user='$user', path='$path')"); $user_preferences = $GLOBALS['egw_info']['user']['preferences']; - if (is_string($user) && $user[0] == 'r' && ($resource = groupdav_principals::read_resource(substr($user, 1)))) + if (is_string($user) && $user[0] == 'r' && ($resource = Principals::read_resource(substr($user, 1)))) { - $is_location = groupdav_principals::resource_is_location($resource); + $is_location = Principals::resource_is_location($resource); $displayname = null; - list($principalType, $account_lid) = explode('/', groupdav_principals::resource2name($resource, $is_location, $displayname)); + list($principalType, $account_lid) = explode('/', Principals::resource2name($resource, $is_location, $displayname)); } elseif ($user) { @@ -850,7 +858,7 @@ class groupdav extends HTTP_WebDAV_Server } // fall through default: - $props['displayname'] = translation::convert(lang($app).' '.$displayname, $this->egw_charset, 'utf-8'); + $props['displayname'] = Translation::convert(lang($app).' '.$displayname, $this->egw_charset, 'utf-8'); } // rfc 5995 (Use POST to add members to WebDAV collections): we use collection path with add-member query param @@ -926,7 +934,7 @@ class groupdav extends HTTP_WebDAV_Server if (method_exists($handler,'getctag') && $this->prop_requested('getctag') === true) { $props['getctag'] = self::mkprop( - groupdav::CALENDARSERVER,'getctag',$handler->getctag($path,$user)); + self::CALENDARSERVER,'getctag',$handler->getctag($path,$user)); } // add sync-token url if handler supports sync-collection report if (isset($props['supported-report-set']['sync-collection']) && $this->prop_requested('sync-token') === true) @@ -1006,7 +1014,7 @@ class groupdav extends HTTP_WebDAV_Server { return $ret; // no collection } - header('Content-type: text/html; charset='.translation::charset()); + header('Content-type: text/html; charset='.Translation::charset()); echo "\n\n\t".'EGroupware (Cal|Card|Group)DAV server '.htmlspecialchars($options['path'])."\n"; echo "\t\n"; echo "\t