move CalDAV/CardDAV server to api

This commit is contained in:
Ralf Becker 2016-04-02 10:44:17 +00:00
parent 25a1bf6360
commit 682fd42a26
16 changed files with 842 additions and 742 deletions

View File

@ -5,7 +5,7 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package addressbook * @package addressbook
* @subpackage groupdav * @subpackage carddav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$ * @version $Id$
@ -14,20 +14,20 @@
use EGroupware\Api; 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. * 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). * 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 * bo class of the application
* *
* @var addressbook_bo * @var Api\Contacts
*/ */
var $bo; var $bo;
@ -63,13 +63,13 @@ class addressbook_groupdav extends groupdav_handler
* Constructor * Constructor
* *
* @param string $app 'calendar', 'addressbook' or 'infolog' * @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 // 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 // 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->contact_repository != 'sql' ||
$this->bo->account_repository != 'sql' && strpos($_SERVER['REQUEST_URI'].'/','/addressbook-accounts/') !== false) $this->bo->account_repository != 'sql' && strpos($_SERVER['REQUEST_URI'].'/','/addressbook-accounts/') !== false)
{ {
groupdav_handler::$path_extension = '.vcf'; self::$path_extension = '.vcf';
} }
else else
{ {
groupdav_handler::$path_attr = 'carddav_name'; self::$path_attr = 'carddav_name';
groupdav_handler::$path_extension = ''; 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); 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 // check if we have to return the full contact data or just the etag's
if (!($filter['address_data'] = $options['props'] == 'all' && 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) foreach($options['props'] as $prop)
{ {
@ -177,13 +177,13 @@ class addressbook_groupdav extends groupdav_handler
else else
{ {
// return iterator, calling ourself to return result in chunks // return iterator, calling ourself to return result in chunks
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']); $files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
} }
return true; return true;
} }
/** /**
* Callback for profind interator * Callback for profind iterator
* *
* @param string $path * @param string $path
* @param array& $filter * @param array& $filter
@ -243,7 +243,7 @@ class addressbook_groupdav extends groupdav_handler
continue; continue;
} }
$props = array( $props = array(
'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'), 'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', 'text/vcard'),
'getlastmodified' => $contact['modified'], 'getlastmodified' => $contact['modified'],
'displayname' => $contact['n_fn'], 'displayname' => $contact['n_fn'],
); );
@ -251,7 +251,7 @@ class addressbook_groupdav extends groupdav_handler
{ {
$content = $handler->getVCard($contact['id'],$this->charset,false); $content = $handler->getVCard($contact['id'],$this->charset,false);
$props['getcontentlength'] = bytes($content); $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); $files[] = $this->add_resource($path, $contact, $props);
} }
@ -271,11 +271,11 @@ class addressbook_groupdav extends groupdav_handler
$accounts_filter = $filter_in; $accounts_filter = $filter_in;
$accounts_filter['owner'] = '0'; $accounts_filter['owner'] = '0';
if ($sync_collection_report) $token_was = $this->sync_collection_token; if ($sync_collection_report) $token_was = $this->sync_collection_token;
groupdav_handler::$path_attr = 'id'; self::$path_attr = 'id';
groupdav_handler::$path_extension = '.vcf'; self::$path_extension = '.vcf';
$files = array_merge($files, $this->propfind_callback($path, $accounts_filter, false, false)); $files = array_merge($files, $this->propfind_callback($path, $accounts_filter, false, false));
groupdav_handler::$path_attr = 'carddav_name'; self::$path_attr = 'carddav_name';
groupdav_handler::$path_extension = ''; self::$path_extension = '';
if ($sync_collection_report && $token_was > $this->sync_collection_token) if ($sync_collection_report && $token_was > $this->sync_collection_token)
{ {
$this->sync_collection_token = $token_was; $this->sync_collection_token = $token_was;
@ -310,7 +310,7 @@ class addressbook_groupdav extends groupdav_handler
$etag .= ':'.implode('-',$filter['owner']); $etag .= ':'.implode('-',$filter['owner']);
} }
$props = array( $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'), 'getlastmodified' => egw_time::to($list['list_modified'],'ts'),
'displayname' => $list['list_name'], 'displayname' => $list['list_name'],
'getetag' => '"'.$etag.'"', 'getetag' => '"'.$etag.'"',
@ -319,7 +319,7 @@ class addressbook_groupdav extends groupdav_handler
{ {
$content = $handler->getGroupVCard($list); $content = $handler->getGroupVCard($list);
$props['getcontentlength'] = bytes($content); $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); $files[] = $this->add_resource($path, $list, $props);
@ -391,7 +391,7 @@ class addressbook_groupdav extends groupdav_handler
switch((string)$filter['name']) switch((string)$filter['name'])
{ {
case 'param-filter': 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; break;
case 'prop-filter': // can be multiple prop-filter, see example case 'prop-filter': // can be multiple prop-filter, see example
if ($matches) $prop_filters[] = implode($prop_test=='allof'?' AND ':' OR ',$matches); if ($matches) $prop_filters[] = implode($prop_test=='allof'?' AND ':' OR ',$matches);
@ -456,7 +456,7 @@ class addressbook_groupdav extends groupdav_handler
} }
// fall through // fall through
default: 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; break;
} }
} }
@ -498,11 +498,11 @@ class addressbook_groupdav extends groupdav_handler
case 'sync-level': case 'sync-level':
if ($option['data'] != '1') 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; break;
default: 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; break;
} }
} }
@ -517,7 +517,7 @@ class addressbook_groupdav extends groupdav_handler
$parts = explode('/',$option['data']); $parts = explode('/',$option['data']);
if (($id = urldecode(array_pop($parts)))) 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) 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)); //error_log(__METHOD__."() options[other]=".array2string($options['other'])." --> filters=".array2string($filters));
return true; return true;
@ -848,27 +848,27 @@ class addressbook_groupdav extends groupdav_handler
if (!isset($props['addressbook-description'])) if (!isset($props['addressbook-description']))
{ {
// default addressbook description: can be overwritten via PROPPATCH, in which case it's already set // 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 // 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 // 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) // supported reports (required property for CardDAV)
$props['supported-report-set'] = array( $props['supported-report-set'] = array(
'addressbook-query' => HTTP_WebDAV_Server::mkprop('supported-report',array( 'addressbook-query' => Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-query',''))))), Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-query',''))))),
'addressbook-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array( 'addressbook-multiget' => Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget',''))))), 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 // 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']) if ($GLOBALS['egw_info']['server']['history'])
{ {
$props['supported-report-set']['sync-collection'] = HTTP_WebDAV_Server::mkprop('supported-report',array( $props['supported-report-set']['sync-collection'] = Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop('sync-collection',''))))); Api\CalDAV::mkprop('sync-collection','')))));
} }
return $props; return $props;
} }

View File

@ -5,13 +5,21 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api * @package api
* @subpackage groupdav * @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$ * @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 * 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://carddav.calconnect.org/ CardDAV resources
* @link http://calendarserver.org/ Apple calendar and contacts server * @link http://calendarserver.org/ Apple calendar and contacts server
*/ */
class groupdav extends HTTP_WebDAV_Server class CalDAV extends HTTP_WebDAV_Server
{ {
/** /**
* DAV namespace * DAV namespace
@ -141,7 +149,7 @@ class groupdav extends HTTP_WebDAV_Server
/** /**
* Instance of our application specific handler * Instance of our application specific handler
* *
* @var groupdav_handler * @var Handler
*/ */
var $handler; var $handler;
/** /**
@ -228,7 +236,7 @@ class groupdav extends HTTP_WebDAV_Server
$this->crrnd = false; $this->crrnd = false;
// identify clients, which do NOT support path AND full url in <D:href> of PROPFIND request // identify clients, which do NOT support path AND full url in <D:href> 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) case 'kde': // KAddressbook (at least in 3.5 can NOT subscribe / does NOT find addressbook)
$this->client_require_href_as_url = true; $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']); //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) if (strpos($this->base_uri, 'http') === 0)
{ {
$this->current_user_principal = $this->_slashify($this->base_uri); $this->current_user_principal = $this->_slashify($this->base_uri);
@ -288,13 +296,13 @@ class groupdav extends HTTP_WebDAV_Server
* get the handler for $app * get the handler for $app
* *
* @param string $app * @param string $app
* @return groupdav_handler * @return Handler
*/ */
function app_handler($app) function app_handler($app)
{ {
if (isset($this->root[$app]['app'])) $app = $this->root[$app]['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 = 'EGroupware (Cal|Card|Group)DAV server';
} }
$displayname = translation::convert($displayname, translation::charset(),'utf-8'); $displayname = Translation::convert($displayname, Translation::charset(),'utf-8');
// self url // self url
$props = array( $props = array(
'displayname' => $displayname, 'displayname' => $displayname,
@ -710,12 +718,12 @@ class groupdav extends HTTP_WebDAV_Server
} }
if ($depth) 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'], $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')"); 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']; $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; $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) elseif ($user)
{ {
@ -850,7 +858,7 @@ class groupdav extends HTTP_WebDAV_Server
} }
// fall through // fall through
default: 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 // 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) if (method_exists($handler,'getctag') && $this->prop_requested('getctag') === true)
{ {
$props['getctag'] = self::mkprop( $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 // add sync-token url if handler supports sync-collection report
if (isset($props['supported-report-set']['sync-collection']) && $this->prop_requested('sync-token') === true) 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 return $ret; // no collection
} }
header('Content-type: text/html; charset='.translation::charset()); header('Content-type: text/html; charset='.Translation::charset());
echo "<html>\n<head>\n\t<title>".'EGroupware (Cal|Card|Group)DAV server '.htmlspecialchars($options['path'])."</title>\n"; echo "<html>\n<head>\n\t<title>".'EGroupware (Cal|Card|Group)DAV server '.htmlspecialchars($options['path'])."</title>\n";
echo "\t<meta http-equiv='content-type' content='text/html; charset=utf-8' />\n"; echo "\t<meta http-equiv='content-type' content='text/html; charset=utf-8' />\n";
echo "\t<style type='text/css'>\n.th { background-color: #e0e0e0; }\n.row_on { background-color: #F1F1F1; vertical-align: top; }\n". echo "\t<style type='text/css'>\n.th { background-color: #e0e0e0; }\n.row_on { background-color: #F1F1F1; vertical-align: top; }\n".
@ -1018,7 +1026,7 @@ class groupdav extends HTTP_WebDAV_Server
foreach(explode('/',$this->_unslashify($options['path'])) as $n => $name) foreach(explode('/',$this->_unslashify($options['path'])) as $n => $name)
{ {
$path .= ($n != 1 ? '/' : '').$name; $path .= ($n != 1 ? '/' : '').$name;
echo html::a_href(htmlspecialchars($name.'/'),$path); echo Html::a_href(htmlspecialchars($name.'/'),$path);
} }
echo "</h1>\n"; echo "</h1>\n";
@ -1069,7 +1077,7 @@ class groupdav extends HTTP_WebDAV_Server
} }
echo "\t<tr class='$class'>\n\t\t<td>$n</td>\n\t\t<td>". echo "\t<tr class='$class'>\n\t\t<td>$n</td>\n\t\t<td>".
html::a_href(htmlspecialchars($name),'/groupdav.php'.strtr($file['path'], array( Html::a_href(htmlspecialchars($name),'/groupdav.php'.strtr($file['path'], array(
'%' => '%25', '%' => '%25',
'#' => '%23', '#' => '%23',
'?' => '%3F', '?' => '%3F',
@ -1107,7 +1115,7 @@ class groupdav extends HTTP_WebDAV_Server
echo "</body>\n</html>\n"; echo "</body>\n</html>\n";
common::egw_exit(); exit;
} }
/** /**
@ -1206,7 +1214,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
// for some reason OS X Addressbook (CFNetwork user-agent) uses now (DAV:add-member given with collection URL+"?add-member") // for some reason OS X Addressbook (CFNetwork user-agent) uses now (DAV:add-member given with collection URL+"?add-member")
// POST to the collection URL plus a UID like name component (like for regular PUT) to create new entrys // POST to the collection URL plus a UID like name component (like for regular PUT) to create new entrys
if (isset($_GET['add-member']) || groupdav_handler::get_agent() == 'cfnetwork') if (isset($_GET['add-member']) || Handler::get_agent() == 'cfnetwork')
{ {
$_GET['add-member'] = ''; // otherwise we give no Location header $_GET['add-member'] = ''; // otherwise we give no Location header
return $this->PUT($options); return $this->PUT($options);
@ -1251,7 +1259,7 @@ class groupdav extends HTTP_WebDAV_Server
* *
* @param array &$options * @param array &$options
* @param string|int $id * @param string|int $id
* @param groupdav_handler $handler * @param Handler $handler
* @param string $action 'attachment-add', 'attachment-update', 'attachment-remove' * @param string $action 'attachment-add', 'attachment-update', 'attachment-remove'
* @return string http status * @return string http status
* *
@ -1259,7 +1267,7 @@ class groupdav extends HTTP_WebDAV_Server
* @todo managed-id does NOT change on update * @todo managed-id does NOT change on update
* @todo updates of attachments through vfs need to call $handler->update_tags($id) too * @todo updates of attachments through vfs need to call $handler->update_tags($id) too
*/ */
protected function managed_attachements(&$options, $id, groupdav_handler $handler, $action) protected function managed_attachements(&$options, $id, Handler $handler, $action)
{ {
error_log(__METHOD__."(path=$options[path], id=$id, ..., action=$action) _GET=".array2string($_GET)); error_log(__METHOD__."(path=$options[path], id=$id, ..., action=$action) _GET=".array2string($_GET));
$entry = $handler->_common_get_put_delete('GET', $options, $id); $entry = $handler->_common_get_put_delete('GET', $options, $id);
@ -1269,7 +1277,7 @@ class groupdav extends HTTP_WebDAV_Server
return $entry ? $entry : "404 Not found"; return $entry ? $entry : "404 Not found";
} }
if (!egw_link::file_access($handler->app, $entry['id'], EGW_ACL_EDIT)) if (!Link::file_access($handler->app, $entry['id'], EGW_ACL_EDIT))
{ {
return '403 Forbidden'; return '403 Forbidden';
} }
@ -1282,7 +1290,7 @@ class groupdav extends HTTP_WebDAV_Server
substr($this->_SERVER['HTTP_CONTENT_DISPOSITION'], 0, 10) === 'attachment' && substr($this->_SERVER['HTTP_CONTENT_DISPOSITION'], 0, 10) === 'attachment' &&
preg_match('/filename="?([^";]+)/', $this->_SERVER['HTTP_CONTENT_DISPOSITION'], $matches)) preg_match('/filename="?([^";]+)/', $this->_SERVER['HTTP_CONTENT_DISPOSITION'], $matches))
{ {
$filename = egw_vfs::basename($matches[1]); $filename = Vfs::basename($matches[1]);
} }
$path = null; $path = null;
if (!($to = self::fopen_attachment($handler->app, $handler->get_id($entry), $filename, $this->_SERVER['CONTENT_TYPE'], $path)) || if (!($to = self::fopen_attachment($handler->app, $handler->get_id($entry), $filename, $this->_SERVER['CONTENT_TYPE'], $path)) ||
@ -1307,7 +1315,7 @@ class groupdav extends HTTP_WebDAV_Server
} }
if ($action == 'attachment-remove') if ($action == 'attachment-remove')
{ {
if (!egw_vfs::unlink($path)) if (!Vfs::unlink($path))
{ {
self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id-parameter', '')); self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id-parameter', ''));
return '403 Forbidden'; return '403 Forbidden';
@ -1320,16 +1328,16 @@ class groupdav extends HTTP_WebDAV_Server
if (isset($this->_SERVER['HTTP_CONTENT_DISPOSITION']) && if (isset($this->_SERVER['HTTP_CONTENT_DISPOSITION']) &&
substr($this->_SERVER['HTTP_CONTENT_DISPOSITION'], 0, 10) === 'attachment' && substr($this->_SERVER['HTTP_CONTENT_DISPOSITION'], 0, 10) === 'attachment' &&
preg_match('/filename="?([^";]+)/', $this->_SERVER['HTTP_CONTENT_DISPOSITION'], $matches) && preg_match('/filename="?([^";]+)/', $this->_SERVER['HTTP_CONTENT_DISPOSITION'], $matches) &&
($filename = egw_vfs::basename($matches[1])) != egw_vfs::basename($path)) ($filename = Vfs::basename($matches[1])) != Vfs::basename($path))
{ {
$old_path = $path; $old_path = $path;
if (!egw_vfs::rename($old_path, $path = egw_vfs::concat(egw_vfs::dirname($path), $filename))) if (!Vfs::rename($old_path, $path = Vfs::concat(Vfs::dirname($path), $filename)))
{ {
self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id-parameter', '')); self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id-parameter', ''));
return '403 Forbidden'; return '403 Forbidden';
} }
} }
if (!($to = egw_vfs::fopen($path, 'w')) || if (!($to = Vfs::fopen($path, 'w')) ||
isset($options['stream']) && ($copied=stream_copy_to_stream($options['stream'], $to)) === false || isset($options['stream']) && ($copied=stream_copy_to_stream($options['stream'], $to)) === false ||
isset($options['content']) && ($copied=fwrite($to, $options['content'])) === false) isset($options['content']) && ($copied=fwrite($to, $options['content'])) === false)
{ {
@ -1377,7 +1385,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
error_log(__METHOD__."('$app', $id, attach=".array2string($attach).", delete_via_put=".array2string($delete_via_put).')'); error_log(__METHOD__."('$app', $id, attach=".array2string($attach).", delete_via_put=".array2string($delete_via_put).')');
if (!egw_link::file_access($app, $id, EGW_ACL_EDIT)) if (!Link::file_access($app, $id, EGW_ACL_EDIT))
{ {
error_log(__METHOD__."('$app', $id, ...) no rights to update attachments"); error_log(__METHOD__."('$app', $id, ...) no rights to update attachments");
return; // no rights --> nothing to do return; // no rights --> nothing to do
@ -1386,7 +1394,7 @@ class groupdav extends HTTP_WebDAV_Server
if ($delete_via_put) if ($delete_via_put)
{ {
foreach(egw_vfs::find(egw_link::vfs_path($app, $id, '', true), array('type' => 'F')) as $path) foreach(Vfs::find(Link::vfs_path($app, $id, '', true), array('type' => 'F')) as $path)
{ {
$found = false; $found = false;
foreach($attach as $key => $attr) foreach($attach as $key => $attr)
@ -1400,8 +1408,8 @@ class groupdav extends HTTP_WebDAV_Server
} }
if (!$found) if (!$found)
{ {
$ok = egw_vfs::unlink($path); $ok = Vfs::unlink($path);
error_log(__METHOD__."('$app', $id, ...) egw_vfs::unlink('$path') returned ".array2string($ok)); error_log(__METHOD__."('$app', $id, ...) Vfs::unlink('$path') returned ".array2string($ok));
} }
} }
} }
@ -1413,24 +1421,24 @@ class groupdav extends HTTP_WebDAV_Server
if (isset($attr['params']['MANAGED-ID'])) if (isset($attr['params']['MANAGED-ID']))
{ {
// invalid managed-id // invalid managed-id
if (!($path = self::managed_id2path($attr['params']['MANAGED-ID'])) || !egw_vfs::is_readable($path)) if (!($path = self::managed_id2path($attr['params']['MANAGED-ID'])) || !Vfs::is_readable($path))
{ {
error_log(__METHOD__."('$app', $id, ...) invalid MANAGED-ID ".array2string($attr)); error_log(__METHOD__."('$app', $id, ...) invalid MANAGED-ID ".array2string($attr));
self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id', '')); self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id', ''));
return false; return false;
} }
if($path == ($link = egw_link::vfs_path($app, $id, egw_vfs::basename($path)))) if($path == ($link = Link::vfs_path($app, $id, Vfs::basename($path))))
{ {
error_log(__METHOD__."('$app', $id, ...) trying to modify existing MANAGED-ID --> ignored! ".array2string($attr)); error_log(__METHOD__."('$app', $id, ...) trying to modify existing MANAGED-ID --> ignored! ".array2string($attr));
continue; continue;
} }
// reuse valid managed-id --> symlink attachment // reuse valid managed-id --> symlink attachment
if (egw_vfs::file_exists($link)) if (Vfs::file_exists($link))
{ {
if (egw_vfs::readlink($link) === $path) continue; // no need to recreate identical link if (Vfs::readlink($link) === $path) continue; // no need to recreate identical link
egw_vfs::unlink($link); // symlink will fail, if $link exists Vfs::unlink($link); // symlink will fail, if $link exists
} }
if (!egw_vfs::symlink($path, $link)) if (!Vfs::symlink($path, $link))
{ {
error_log(__METHOD__."('$app', $id, ...) failed to symlink($path, $link) --> ignored!"); error_log(__METHOD__."('$app', $id, ...) failed to symlink($path, $link) --> ignored!");
} }
@ -1465,15 +1473,15 @@ class groupdav extends HTTP_WebDAV_Server
*/ */
protected static function fopen_attachment($app, $id, $_filename, $mime=null, &$path=null) protected static function fopen_attachment($app, $id, $_filename, $mime=null, &$path=null)
{ {
$filename = empty($_filename) ? 'attachment' : egw_vfs::basename($_filename); $filename = empty($_filename) ? 'attachment' : Vfs::basename($_filename);
if (strpos($mime, ';')) list($mime) = explode(';', $mime); // in case it contains eg. charset info if (strpos($mime, ';')) list($mime) = explode(';', $mime); // in case it contains eg. charset info
$ext = !empty($mime) ? mime_magic::mime2ext($mime) : ''; $ext = !empty($mime) ? MimeMagic::mime2ext($mime) : '';
$matches = null; $matches = null;
if (!$ext || substr($filename, -strlen($ext)-1) == '.'.$ext || if (!$ext || substr($filename, -strlen($ext)-1) == '.'.$ext ||
preg_match('/\.([^.]+)$/', $filename, $matches) && mime_magic::ext2mime($matches[1]) == $mime) preg_match('/\.([^.]+)$/', $filename, $matches) && MimeMagic::ext2mime($matches[1]) == $mime)
{ {
$parts = explode('.', $filename); $parts = explode('.', $filename);
$ext = '.'.array_pop($parts); $ext = '.'.array_pop($parts);
@ -1485,18 +1493,18 @@ class groupdav extends HTTP_WebDAV_Server
} }
for($i = 1; $i < 100; ++$i) for($i = 1; $i < 100; ++$i)
{ {
$path = egw_link::vfs_path($app, $id, $filename.($i > 1 ? '-'.$i : '').$ext, true); $path = Link::vfs_path($app, $id, $filename.($i > 1 ? '-'.$i : '').$ext, true);
if (!egw_vfs::stat($path)) break; if (!Vfs::stat($path)) break;
} }
if ($i >= 100) return null; if ($i >= 100) return null;
if (!egw_vfs::file_exists($dir = egw_vfs::dirname($path)) && !egw_vfs::mkdir($dir, 0777, STREAM_MKDIR_RECURSIVE)) if (!Vfs::file_exists($dir = Vfs::dirname($path)) && !Vfs::mkdir($dir, 0777, STREAM_MKDIR_RECURSIVE))
{ {
error_log(__METHOD__."('$app', $id, ...) failed to create entry dir $dir!"); error_log(__METHOD__."('$app', $id, ...) failed to create entry dir $dir!");
return false; return false;
} }
return egw_vfs::fopen($path, 'w'); return Vfs::fopen($path, 'w');
} }
/** /**
@ -1516,7 +1524,7 @@ class groupdav extends HTTP_WebDAV_Server
$url_prefix = ($_SERVER['HTTPS'] ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST']; $url_prefix = ($_SERVER['HTTPS'] ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST'];
} }
} }
return $url_prefix.egw::link(egw_vfs::download_url($path)); return $url_prefix.egw::link(Vfs::download_url($path));
} }
/** /**
@ -1529,15 +1537,15 @@ class groupdav extends HTTP_WebDAV_Server
*/ */
public static function add_attach($app, $id, array &$attributes, array &$parameters) public static function add_attach($app, $id, array &$attributes, array &$parameters)
{ {
foreach(egw_vfs::find(egw_link::vfs_path($app, $id, '', true), array( foreach(Vfs::find(Link::vfs_path($app, $id, '', true), array(
'type' => 'F', 'type' => 'F',
'need_mime' => true, 'need_mime' => true,
), true) as $path => $stat) ), true) as $path => $stat)
{ {
// handle symlinks --> return target size and mime-type // handle symlinks --> return target size and mime-type
if (($target = egw_vfs::readlink($path))) if (($target = Vfs::readlink($path)))
{ {
if (!($stat = egw_vfs::stat($target))) continue; // broken or inaccessible symlink if (!($stat = Vfs::stat($target))) continue; // broken or inaccessible symlink
// check if target is in /apps, probably reused MANAGED-ID --> return it // check if target is in /apps, probably reused MANAGED-ID --> return it
if (substr($target, 0, 6) == '/apps/') if (substr($target, 0, 6) == '/apps/')
@ -1547,10 +1555,10 @@ class groupdav extends HTTP_WebDAV_Server
} }
$attributes['ATTACH'][] = self::path2location($path); $attributes['ATTACH'][] = self::path2location($path);
$parameters['ATTACH'][] = array( $parameters['ATTACH'][] = array(
'MANAGED-ID' => groupdav::path2managed_id($path), 'MANAGED-ID' => self::path2managed_id($path),
'FMTTYPE' => $stat['mime'], 'FMTTYPE' => $stat['mime'],
'SIZE' => (string)$stat['size'], // Horde_Icalendar renders int as empty string 'SIZE' => (string)$stat['size'], // Horde_Icalendar renders int as empty string
'FILENAME' => egw_vfs::basename($path), 'FILENAME' => Vfs::basename($path),
); );
// if we have attachments, set X-attribute to enable deleting them by put // if we have attachments, set X-attribute to enable deleting them by put
// (works around events synced before without ATTACH attributes) // (works around events synced before without ATTACH attributes)
@ -1581,7 +1589,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
$path = base64_decode($managed_id); $path = base64_decode($managed_id);
if (!$path || substr($path, 0, 6) != '/apps/' || !egw_vfs::stat($path)) if (!$path || substr($path, 0, 6) != '/apps/' || !Vfs::stat($path))
{ {
$path = false; $path = false;
} }
@ -1684,13 +1692,16 @@ class groupdav extends HTTP_WebDAV_Server
{ {
$GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->save_repository(); $GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->save_repository();
// call calendar-hook, if default-alarms are changed, to sync them to calendar prefs // call calendar-hook, if default-alarms are changed, to sync them to calendar prefs
foreach($need_save as $name) if (class_exists('calendar_hooks'))
{ {
list($name) = explode(':', $name); foreach($need_save as $name)
if (in_array($name, array('default-alarm-vevent-date', 'default-alarm-vevent-datetime')))
{ {
calendar_hooks::sync_default_alarms(); list($name) = explode(':', $name);
break; if (in_array($name, array('default-alarm-vevent-date', 'default-alarm-vevent-datetime')))
{
calendar_hooks::sync_default_alarms();
break;
}
} }
} }
} }
@ -1801,7 +1812,7 @@ class groupdav extends HTTP_WebDAV_Server
*/ */
function COPY($options, $del=false) function COPY($options, $del=false)
{ {
if ($this->debug) error_log('groupdav::'.($del ? 'MOVE' : 'COPY').'('.array2string($options).')'); if ($this->debug) error_log('self::'.($del ? 'MOVE' : 'COPY').'('.array2string($options).')');
return '501 Not Implemented'; return '501 Not Implemented';
} }
@ -1816,7 +1827,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
$id = $app = $user = null; $id = $app = $user = null;
self::_parse_path($options['path'],$id,$app,$user); self::_parse_path($options['path'],$id,$app,$user);
$path = egw_vfs::app_entry_lock_path($app,$id); $path = Vfs::app_entry_lock_path($app,$id);
if ($this->debug) error_log(__METHOD__.'('.array2string($options).") path=$path"); if ($this->debug) error_log(__METHOD__.'('.array2string($options).") path=$path");
@ -1832,7 +1843,7 @@ class groupdav extends HTTP_WebDAV_Server
// dont know why, but HTTP_WebDAV_Server passes the owner in D:href tags, which get's passed unchanged to checkLock/PROPFIND // dont know why, but HTTP_WebDAV_Server passes the owner in D:href tags, which get's passed unchanged to checkLock/PROPFIND
// that's wrong according to the standard and cadaver does not show it on discover --> strip_tags removes eventual tags // that's wrong according to the standard and cadaver does not show it on discover --> strip_tags removes eventual tags
if (($ret = egw_vfs::lock($path,$options['locktoken'],$options['timeout'],strip_tags($options['owner']), if (($ret = Vfs::lock($path,$options['locktoken'],$options['timeout'],strip_tags($options['owner']),
$options['scope'],$options['type'],isset($options['update']),false)) && !isset($options['update'])) // false = no ACL check $options['scope'],$options['type'],isset($options['update']),false)) && !isset($options['update'])) // false = no ACL check
{ {
return $ret ? '200 OK' : '409 Conflict'; return $ret ? '200 OK' : '409 Conflict';
@ -1850,10 +1861,10 @@ class groupdav extends HTTP_WebDAV_Server
{ {
$id = $app = $user = null; $id = $app = $user = null;
self::_parse_path($options['path'],$id,$app,$user); self::_parse_path($options['path'],$id,$app,$user);
$path = egw_vfs::app_entry_lock_path($app,$id); $path = Vfs::app_entry_lock_path($app,$id);
if ($this->debug) error_log(__METHOD__.'('.array2string($options).") path=$path"); if ($this->debug) error_log(__METHOD__.'('.array2string($options).") path=$path");
return egw_vfs::unlock($path,$options['token']) ? '204 No Content' : '409 Conflict'; return Vfs::unlock($path,$options['token']) ? '204 No Content' : '409 Conflict';
} }
/** /**
@ -1867,7 +1878,7 @@ class groupdav extends HTTP_WebDAV_Server
$id = $app = $user = null; $id = $app = $user = null;
self::_parse_path($path,$id,$app,$user); self::_parse_path($path,$id,$app,$user);
return egw_vfs::checkLock(egw_vfs::app_entry_lock_path($app, $id)); return Vfs::checkLock(Vfs::app_entry_lock_path($app, $id));
} }
/** /**
@ -1929,7 +1940,7 @@ class groupdav extends HTTP_WebDAV_Server
$user = $parts[0].'/'.$parts[1]; $user = $parts[0].'/'.$parts[1];
array_shift($parts); array_shift($parts);
$res_id = (int)array_shift($parts); $res_id = (int)array_shift($parts);
if (!groupdav_principals::read_resource($res_id)) if (!Principals::read_resource($res_id))
{ {
return false; return false;
} }
@ -1964,7 +1975,7 @@ class groupdav extends HTTP_WebDAV_Server
} }
elseif($app == 'resource' || $app == 'location') elseif($app == 'resource' || $app == 'location')
{ {
if (!groupdav_principals::read_resource($res_id = (int)$username)) if (!Principals::read_resource($res_id = (int)$username))
{ {
return false; return false;
} }
@ -2127,7 +2138,7 @@ class groupdav extends HTTP_WebDAV_Server
{ {
header('Content-type: application/xml; charset=utf-8'); header('Content-type: application/xml; charset=utf-8');
$xml = new XMLWriter; $xml = new \XMLWriter;
$xml->openMemory(); $xml->openMemory();
$xml->setIndent(true); $xml->setIndent(true);
$xml->startDocument('1.0', 'utf-8'); $xml->startDocument('1.0', 'utf-8');
@ -2148,10 +2159,10 @@ class groupdav extends HTTP_WebDAV_Server
/** /**
* Recursivly add properties to XMLWriter object * Recursivly add properties to XMLWriter object
* *
* @param XMLWriter $xml * @param \XMLWriter $xml
* @param string|array $props string with name for empty element in DAV NS or array with props * @param string|array $props string with name for empty element in DAV NS or array with props
*/ */
protected static function add_prop(XMLWriter $xml, $props) protected static function add_prop(\XMLWriter $xml, $props)
{ {
if (is_string($props)) $props = self::mkprop($props, ''); if (is_string($props)) $props = self::mkprop($props, '');
if (isset($props['name'])) $props = array($props); if (isset($props['name'])) $props = array($props);
@ -2202,9 +2213,9 @@ class groupdav extends HTTP_WebDAV_Server
* *
* Does NOT return and get installed in constructor. * Does NOT return and get installed in constructor.
* *
* @param Exception $e * @param \Exception $e
*/ */
public static function exception_handler(Exception $e) public static function exception_handler(\Exception $e)
{ {
// logging exception as regular egw_execption_hander does // logging exception as regular egw_execption_hander does
$headline = null; $headline = null;
@ -2229,10 +2240,20 @@ class groupdav extends HTTP_WebDAV_Server
self::$instance->log_request(); self::$instance->log_request();
} }
} }
if (is_object($GLOBALS['egw']))
{
common::egw_exit();
}
exit; exit;
} }
/**
* Generate a unique id, which can be used for syncronisation
*
* @param string $_appName the appname
* @param string $_eventID the id of the content
* @return string the unique id
*/
static function generate_uid($_appName, $_eventID)
{
if(empty($_appName) || empty($_eventID)) return false;
return $_appName.'-'.$_eventID.'-'.$GLOBALS['egw_info']['server']['install_id'];
}
} }

View File

@ -5,21 +5,25 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api * @package api
* @subpackage groupdav * @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api\CalDAV;
use EGroupware\Api;
/** /**
* EGroupware: GroupDAV access: abstract baseclass for groupdav/caldav/carddav handlers * EGroupware: GroupDAV access: abstract baseclass for groupdav/caldav/carddav handlers
* *
* 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). * and our request-log (prefixed with "### " after request and response, like exceptions).
* *
* @ToDo: If precondition for PUT, see https://tools.ietf.org/html/rfc6578#section-5 * @ToDo: If precondition for PUT, see https://tools.ietf.org/html/rfc6578#section-5
*/ */
abstract class groupdav_handler abstract class Handler
{ {
/** /**
* Debug level: 0 = nothing, 1 = function calls, 2 = more info, eg. complete $_SERVER array * Debug level: 0 = nothing, 1 = function calls, 2 = more info, eg. complete $_SERVER array
@ -39,13 +43,13 @@ abstract class groupdav_handler
/** /**
* Reference to the accounts class * Reference to the accounts class
* *
* @var accounts * @var Api\Accounts
*/ */
var $accounts; var $accounts;
/** /**
* Reference to the ACL class * Reference to the ACL class
* *
* @var acl * @var Api\Acl
*/ */
var $acl; var $acl;
/** /**
@ -65,13 +69,13 @@ abstract class groupdav_handler
*/ */
var $app; var $app;
/** /**
* Calling groupdav object * Calling CalDAV object
* *
* @var groupdav * @var Api\CalDAV
*/ */
var $groupdav; var $caldav;
/** /**
* Base url of handler, need to prefix all pathes not automatic handled by HTTP_WebDAV_Server * Base url of handler, need to prefix all pathes not automatic handled by Api\CalDAV
* *
* @var string * @var string
*/ */
@ -114,18 +118,18 @@ abstract class groupdav_handler
* Constructor * Constructor
* *
* @param string $app 'calendar', 'addressbook' or 'infolog' * @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)
{ {
$this->app = $app; $this->app = $app;
if (!is_null($groupdav->debug)) $this->debug = $groupdav->debug; if (!is_null($caldav->debug)) $this->debug = $caldav->debug;
$this->base_uri = $groupdav->base_uri; $this->base_uri = $caldav->base_uri;
$this->groupdav = $groupdav; $this->caldav = $caldav;
$this->agent = self::get_agent(); $this->agent = self::get_agent();
$this->egw_charset = translation::charset(); $this->egw_charset = Api\Translation::charset();
$this->accounts = $GLOBALS['egw']->accounts; $this->accounts = $GLOBALS['egw']->accounts;
$this->acl = $GLOBALS['egw']->acl; $this->acl = $GLOBALS['egw']->acl;
@ -358,7 +362,7 @@ abstract class groupdav_handler
{ {
if ($_SERVER['REQUEST_METHOD'] == 'POST') if ($_SERVER['REQUEST_METHOD'] == 'POST')
{ {
$location = $this->groupdav->base_uri.$options['path']; $location = $this->caldav->base_uri.$options['path'];
if ($location[0] == '/') if ($location[0] == '/')
{ {
$location = (@$_SERVER['HTTPS'] === 'on' ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST'].$location; $location = (@$_SERVER['HTTPS'] === 'on' ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST'].$location;
@ -372,7 +376,7 @@ abstract class groupdav_handler
if (($ret = $this->get($options, $id ? $id : $this->new_id, $user)) && !empty($options['data'])) if (($ret = $this->get($options, $id ? $id : $this->new_id, $user)) && !empty($options['data']))
{ {
if (!$this->groupdav->use_compression()) header('Content-Length: '.$this->groupdav->bytes($options['data'])); if (!$this->caldav->use_compression()) header('Content-Length: '.$this->caldav->bytes($options['data']));
header('Content-Type: '.$options['mimetype']); header('Content-Type: '.$options['mimetype']);
echo $options['data']; echo $options['data'];
} }
@ -398,17 +402,17 @@ abstract class groupdav_handler
* *
* @static * @static
* @param string $app 'calendar', 'addressbook' or 'infolog' * @param string $app 'calendar', 'addressbook' or 'infolog'
* @param groupdav $groupdav calling class * @param Api\CalDAV $groupdav calling class
* @return groupdav_handler * @return groupdav_handler
*/ */
static function app_handler($app, $groupdav) static function app_handler($app, Api\CalDAV $groupdav)
{ {
static $handler_cache = array(); static $handler_cache = array();
if (!array_key_exists($app,$handler_cache)) if (!array_key_exists($app,$handler_cache))
{ {
$class = $app.'_groupdav'; $class = $app.'_groupdav';
if (!class_exists($class) && !class_exists($class = 'groupdav_'.$app)) return null; if (!class_exists($class) && !class_exists($class = __NAMESPACE__.'\\'.ucfirst($app))) return null;
$handler_cache[$app] = new $class($app, $groupdav); $handler_cache[$app] = new $class($app, $groupdav);
} }
@ -639,21 +643,21 @@ abstract class groupdav_handler
} }
// if requested add privileges // if requested add privileges
$privileges = array('read', 'read-current-user-privilege-set'); $privileges = array('read', 'read-current-user-privilege-set');
if ($this->groupdav->prop_requested('current-user-privilege-set') === true && !isset($props['current-user-privilege-set'])) if ($this->caldav->prop_requested('current-user-privilege-set') === true && !isset($props['current-user-privilege-set']))
{ {
if ($this->check_access(EGW_ACL_EDIT, $entry)) if ($this->check_access(EGW_ACL_EDIT, $entry))
{ {
$privileges[] = 'write-content'; $privileges[] = 'write-content';
} }
} }
if ($this->groupdav->prop_requested('owner') === true && !isset($props['owner']) && if ($this->caldav->prop_requested('owner') === true && !isset($props['owner']) &&
($account_lid = $this->accounts->id2name($entry['owner']))) ($account_lid = $this->accounts->id2name($entry['owner'])))
{ {
$type = $this->accounts->get_type($entry['owner']) == 'u' ? 'users' : 'groups'; $type = $this->accounts->get_type($entry['owner']) == 'u' ? 'users' : 'groups';
$props['owner'] = HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/principals/'.$type.'/'.$account_lid.'/'); $props['owner'] = Api\CalDAV::mkprop('href', $this->base_uri.'/principals/'.$type.'/'.$account_lid.'/');
} }
// we urldecode here, as HTTP_WebDAV_Server uses a minimal (#?%) urlencoding for incomming pathes and urlencodes pathes in propfind // we urldecode here, as Api\CalDAV uses a minimal (#?%) urlencoding for incomming pathes and urlencodes pathes in propfind
return $this->groupdav->add_resource($path.urldecode($this->get_path($entry)), $props, $privileges); return $this->caldav->add_resource($path.urldecode($this->get_path($entry)), $props, $privileges);
} }
/** /**
@ -671,7 +675,7 @@ abstract class groupdav_handler
if (!isset($uri)) if (!isset($uri))
{ {
$uri = $path = $this->groupdav->base_uri; $uri = $path = $this->caldav->base_uri;
if ($uri[0] == '/') if ($uri[0] == '/')
{ {
$uri = ($_SERVER["HTTPS"] === "on" ? "https:" : "http:") .'//' . $_SERVER['HTTP_HOST'] . $uri; $uri = ($_SERVER["HTTPS"] === "on" ? "https:" : "http:") .'//' . $_SERVER['HTTP_HOST'] . $uri;
@ -705,12 +709,12 @@ abstract class groupdav_handler
{ {
$error = $error =
' <D:response> ' <D:response>
<D:href>'.htmlspecialchars($this->groupdav->base_uri.$this->groupdav->path).'</D:href> <D:href>'.htmlspecialchars($this->caldav->base_uri.$this->caldav->path).'</D:href>
<D:status>HTTP/1.1 507 Insufficient Storage</D:status> <D:status>HTTP/1.1 507 Insufficient Storage</D:status>
<D:error><D:number-of-matches-within-limits/></D:error> <D:error><D:number-of-matches-within-limits/></D:error>
</D:response> </D:response>
'; ';
if ($this->groupdav->crrnd) if ($this->caldav->crrnd)
{ {
$error = str_replace(array('<D:', '</D:'), array('<', '</'), $error); $error = str_replace(array('<D:', '</D:'), array('<', '</'), $error);
} }
@ -747,175 +751,3 @@ abstract class groupdav_handler
return $this->base_uri().$path.$token; return $this->base_uri().$path.$token;
} }
} }
/**
* Iterator for propfinds using propfind callback of a groupdav_handler to query results in chunks
*
* The propfind method just computes a filter and then returns an instance of this iterator instead of the files:
*
* function propfind($path,$options,&$files,$user,$id='')
* {
* $filter = array();
* // compute filter from path, options, ...
*
* $files['files'] = new groupdav_propfind_iterator($this,$filter,$files['files']);
*
* return true;
* }
*/
class groupdav_propfind_iterator implements Iterator
{
/**
* current path
*
* @var string
*/
protected $path;
/**
* Handler to call for entries
*
* @var groupdav_handler
*/
protected $handler;
/**
* Filter of propfind call
*
* @var array
*/
protected $filter;
/**
* Extra responses to return too
*
* @var array
*/
protected $common_files;
/**
* current chunk
*
* @var array
*/
protected $files;
/**
* Start value for callback
*
* @var int
*/
protected $start=0;
/**
* Number of entries queried from callback in one call
*
*/
const CHUNK_SIZE = 500;
/**
* Log calls via error_log()
*
* @var boolean
*/
public $debug = false;
/**
/**
* Constructor
*
* @param groupdav_handler $handler
* @param array $filter filter for propfind call
* @param array $files =array() extra files/responses to return too
*/
public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=array())
{
if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)");
$this->path = $path;
$this->handler = $handler;
$this->filter = $filter;
$this->files = $this->common_files = $files;
reset($this->files);
}
/**
* Return the current element
*
* @return array
*/
public function current()
{
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files)));
return current($this->files);
}
/**
* Return the key of the current element
*
* @return int|string
*/
public function key()
{
$current = current($this->files);
if ($this->debug) error_log(__METHOD__."() returning ".array2string($current['path']));
return $current['path']; // we return path as key
}
/**
* Move forward to next element (called after each foreach loop)
*/
public function next()
{
if (next($this->files) !== false)
{
if ($this->debug) error_log(__METHOD__."() returning TRUE");
return true;
}
// check if previous query gave less then CHUNK_SIZE entries --> we're done
if ($this->start && count($this->files) < self::CHUNK_SIZE)
{
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
return false;
}
// try query further files via propfind callback of handler and store result in $this->files
$this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
if (!is_array($this->files) || !($entries = count($this->files)))
{
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
return false; // no further entries
}
$this->start += self::CHUNK_SIZE;
reset($this->files);
if ($this->debug) error_log(__METHOD__."() this->start=$this->start, entries=$entries, count(this->files)=".count($this->files)." returning ".array2string(current($this->files) !== false));
return current($this->files) !== false;
}
/**
* Rewind the Iterator to the first element (called at beginning of foreach loop)
*/
public function rewind()
{
if ($this->debug) error_log(__METHOD__."()");
$this->start = 0;
$this->files = $this->common_files;
if (!$this->files) $this->next(); // otherwise valid will return false and nothing get returned
reset($this->files);
}
/**
* Checks if current position is valid
*
* @return boolean
*/
public function valid ()
{
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false));
return current($this->files) !== false;
}
}

View File

@ -11,10 +11,17 @@
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api\CalDAV;
use EGroupware\Api;
// explicit import old non-namespaced api classes
use egw; // link
/** /**
* GroupDAV hooks: eg. preferences * GroupDAV hooks: eg. preferences
*/ */
class groupdav_hooks class Hooks
{ {
public $public_functions = array( public $public_functions = array(
'log' => true, 'log' => true,
@ -33,7 +40,7 @@ class groupdav_hooks
if ($location == 'preferences') if ($location == 'preferences')
{ {
$file = array( $file = array(
'Preferences' => egw::link('/index.php','menuaction=preferences.uisettings.index&appname='.$appname), 'Preferences' => egw::link('/index.php','menuaction=preferences.preference_settings.index&appname='.$appname),
); );
if ($location == 'preferences') if ($location == 'preferences')
{ {
@ -109,13 +116,13 @@ class groupdav_hooks
if (substr($log,0,$account_lid_len+1) == $GLOBALS['egw_info']['user']['account_lid'].'-' && if (substr($log,0,$account_lid_len+1) == $GLOBALS['egw_info']['user']['account_lid'].'-' &&
substr($log,-4) == '.log') substr($log,-4) == '.log')
{ {
$logs['groupdav/'.$log] = egw_time::to(filemtime($log_dir.'/'.$log)).': '. $logs['groupdav/'.$log] = Api\DateTime::to(filemtime($log_dir.'/'.$log)).': '.
str_replace('!','/',substr($log,$account_lid_len+1,-4)); str_replace('!','/',substr($log,$account_lid_len+1,-4));
} }
} }
} }
$link = egw::link('/index.php',array( $link = egw::link('/index.php',array(
'menuaction' => 'groupdav.groupdav_hooks.log', 'menuaction' => 'api.'.__CLASS__.'.log',
'filename' => '', 'filename' => '',
)); ));
$onchange = "egw_openWindowCentered('$link'+encodeURIComponent(this.value), '_blank', 1000, 500); this.value=''"; $onchange = "egw_openWindowCentered('$link'+encodeURIComponent(this.value), '_blank', 1000, 500); this.value=''";
@ -144,21 +151,21 @@ class groupdav_hooks
* *
* $_GET['filename'] has to be in groupdav sub-dir of files_dir and start with account_lid of current user * $_GET['filename'] has to be in groupdav sub-dir of files_dir and start with account_lid of current user
* *
* @throws egw_exception_wrong_parameter * @throws Api\Exception\WrongParameter
*/ */
public function log() public static function log()
{ {
$filename = $_GET['filename']; $filename = $_GET['filename'];
if (!preg_match('|^groupdav/'.preg_quote($GLOBALS['egw_info']['user']['account_lid'],'|').'-[^/]+\.log$|',$filename)) if (!preg_match('|^groupdav/'.preg_quote($GLOBALS['egw_info']['user']['account_lid'],'|').'-[^/]+\.log$|',$filename))
{ {
throw new egw_exception_wrong_parameter("Access denied to file '$filename'!"); throw new Api\Exception\WrongParameter("Access denied to file '$filename'!");
} }
$GLOBALS['egw_info']['flags']['css'] = ' $GLOBALS['egw_info']['flags']['css'] = '
body { background-color: #e0e0e0; overflow: hidden; } body { background-color: #e0e0e0; overflow: hidden; }
pre.tail { background-color: white; padding-left: 5px; margin-left: 5px; } pre.tail { background-color: white; padding-left: 5px; margin-left: 5px; }
'; ';
$header = str_replace('!','/',substr($filename,10+strlen($GLOBALS['egw_info']['user']['account_lid']),-4)); $header = str_replace('!','/',substr($filename,10+strlen($GLOBALS['egw_info']['user']['account_lid']),-4));
$tail = new egw_tail($filename); $tail = new Api\Json\Tail($filename);
$GLOBALS['egw']->framework->render($tail->show($header),false,false); $GLOBALS['egw']->framework->render($tail->show($header),false,false);
} }
} }

View File

@ -5,24 +5,32 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api * @package api
* @subpackage groupdav * @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2008-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$ * @version $Id$
*/ */
namespace EGroupware\Api\CalDAV;
use EGroupware\Api;
// explicit import classes without namespace
use resources_bo;
use calendar_bo;
/** /**
* EGroupware: GroupDAV access: groupdav/caldav/carddav principals handlers * EGroupware: GroupDAV access: groupdav/caldav/carddav principals handlers
* *
* First-level properties used in this class should have the property name as their key, * First-level properties used in this class should have the property name as their key,
* to allow to check if required properties are set! * to allow to check if required properties are set!
* groupdav_principals::add_principal() converts simple associative props (name => value pairs) * Principals::add_principal() converts simple associative props (name => value pairs)
* to name => HTTP_WebDAV_Server(name, value) pairs. * to name => Api\CalDAV(name, value) pairs.
* *
* 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). * and our request-log (prefixed with "### " after request and response, like exceptions).
*/ */
class groupdav_principals extends groupdav_handler class Principals extends Handler
{ {
/** /**
* Instance of resources_bo * Instance of resources_bo
@ -35,11 +43,11 @@ class groupdav_principals extends groupdav_handler
* Constructor * Constructor
* *
* @param string $app 'calendar', 'addressbook' or 'infolog' * @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);
if (!isset(self::$resources)) self::$resources = new resources_bo(); if (!isset(self::$resources)) self::$resources = new resources_bo();
} }
@ -67,7 +75,7 @@ class groupdav_principals extends groupdav_handler
), ),
/* seems only be used 'til OS X 10.6, no longer in 10.7 /* seems only be used 'til OS X 10.6, no longer in 10.7
'addressbook-findshared' => array( 'addressbook-findshared' => array(
'ns' => groupdav::ADDRESSBOOKSERVER, 'ns' => Api\CalDAV::ADDRESSBOOKSERVER,
'method' => 'addressbook_findshared_report', 'method' => 'addressbook_findshared_report',
),*/ ),*/
); );
@ -79,7 +87,7 @@ class groupdav_principals extends groupdav_handler
* *
* @param string $path eg. '/principals/' * @param string $path eg. '/principals/'
* @param array $reports =null * @param array $reports =null
* @return array HTTP_WebDAV_Server::mkprop('supported-report-set', ...) * @return array Api\CalDAV::mkprop('supported-report-set', ...)
*/ */
protected function supported_report_set($path, array $reports=null) protected function supported_report_set($path, array $reports=null)
{ {
@ -90,10 +98,10 @@ class groupdav_principals extends groupdav_handler
$supported = array(); $supported = array();
foreach($reports as $name => $data) foreach($reports as $name => $data)
{ {
$supported[$name] = HTTP_WebDAV_Server::mkprop('supported-report',array( $supported[$name] = Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
!$data['ns'] ? HTTP_WebDAV_Server::mkprop($name, '') : !$data['ns'] ? Api\CalDAV::mkprop($name, '') :
HTTP_WebDAV_Server::mkprop($data['ns'], $name, ''))))); Api\CalDAV::mkprop($data['ns'], $name, '')))));
} }
return $supported; return $supported;
} }
@ -116,7 +124,7 @@ class groupdav_principals extends groupdav_handler
{ {
return $this->$method($path, $options, $files, $user); return $this->$method($path, $options, $files, $user);
} }
$this->groupdav->log(__METHOD__."('$path', ".array2string($options).",, $user) not implemented report, returning 501 Not Implemented"); $this->caldav->log(__METHOD__."('$path', ".array2string($options).",, $user) not implemented report, returning 501 Not Implemented");
return '501 Not Implemented'; return '501 Not Implemented';
} }
list(,,$type,$name,$rest) = explode('/',$path,5); list(,,$type,$name,$rest) = explode('/',$path,5);
@ -178,7 +186,7 @@ class groupdav_principals extends groupdav_handler
foreach($this->get_shared_addressbooks() as $path) foreach($this->get_shared_addressbooks() as $path)
{ {
$files['files'][] = $f = $this->add_collection($path.'addressbook/', array( $files['files'][] = $f = $this->add_collection($path.'addressbook/', array(
'resourcetype' => array(HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook','')), 'resourcetype' => array(Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook','')),
)); ));
error_log(__METHOD__."() ".array2string($f)); error_log(__METHOD__."() ".array2string($f));
} }
@ -268,14 +276,14 @@ class groupdav_principals extends groupdav_handler
case 'calendar-proxy-write-for': case 'calendar-proxy-write-for':
$prop_path = $path . substr($prop_name, 0, -4).'/'; $prop_path = $path . substr($prop_name, 0, -4).'/';
$prop_name = 'group-member-set'; $prop_name = 'group-member-set';
$prop_ns = groupdav::DAV; $prop_ns = Api\CalDAV::DAV;
break; break;
case 'expanded-group-member-set': case 'expanded-group-member-set':
case 'expanded-group-membership': case 'expanded-group-membership':
// remove 'expanded-' prefix // remove 'expanded-' prefix
$prop_name = substr($prop_name, 9); $prop_name = substr($prop_name, 9);
$prop_ns = groupdav::DAV; $prop_ns = Api\CalDAV::DAV;
break; break;
} }
// run regular propfind for requested property // run regular propfind for requested property
@ -286,10 +294,10 @@ class groupdav_principals extends groupdav_handler
'xmlns' => $prop_ns, 'xmlns' => $prop_ns,
)); ));
$prop_files = array(); $prop_files = array();
$this->groupdav->options = $options; // also modify global variable $this->caldav->options = $options; // also modify global variable
if (empty($prop_name) || $this->propfind($prop_path, $options, $prop_files, $user) !== true) if (empty($prop_name) || $this->propfind($prop_path, $options, $prop_files, $user) !== true)
{ {
$this->groupdav->log('### NO expand-property report for '.$requested_prop['attrs']['name']); $this->caldav->log('### NO expand-property report for '.$requested_prop['attrs']['name']);
continue; continue;
} }
// find prop to expand // find prop to expand
@ -300,7 +308,7 @@ class groupdav_principals extends groupdav_handler
if ($expand_prop['name'] !== $prop_name || !is_array($expand_prop['val']) || if ($expand_prop['name'] !== $prop_name || !is_array($expand_prop['val']) ||
$expand_prop['val'] && $expand_prop['val'][0]['name'] !== 'href') $expand_prop['val'] && $expand_prop['val'][0]['name'] !== 'href')
{ {
$this->groupdav->log('### NO expand-property report for '.$requested_prop['attrs']['name'].' ('.$prop_name.')'); $this->caldav->log('### NO expand-property report for '.$requested_prop['attrs']['name'].' ('.$prop_name.')');
continue; continue;
} }
@ -323,12 +331,12 @@ class groupdav_principals extends groupdav_handler
} }
// put back evtl. read top-level property // put back evtl. read top-level property
if ($prop && $prop['depth'] == 1) array_unshift($requested_props, $prop); if ($prop && $prop['depth'] == 1) array_unshift($requested_props, $prop);
$this->groupdav->options = $options2; // also modify global variable $this->caldav->options = $options2; // also modify global variable
// run regular profind to get requested 2.-level properties for each href // run regular profind to get requested 2.-level properties for each href
foreach($expand_prop['val'] as $key => &$prop_val) foreach($expand_prop['val'] as $key => &$prop_val)
{ {
list(,$expand_path) = explode($this->groupdav->base_uri, $prop_val['val']); list(,$expand_path) = explode($this->caldav->base_uri, $prop_val['val']);
//error_log(__METHOD__."('$path', ..., $user) calling propfind('$expand_path', ".array2string($options2).', '.array2string($prop_val).", $user)"); //error_log(__METHOD__."('$path', ..., $user) calling propfind('$expand_path', ".array2string($options2).', '.array2string($prop_val).", $user)");
if ($this->propfind($expand_path, $options2, $prop_val, $user) !== true || !isset($prop_val['files'][0])) if ($this->propfind($expand_path, $options2, $prop_val, $user) !== true || !isset($prop_val['files'][0]))
{ {
@ -341,7 +349,7 @@ class groupdav_principals extends groupdav_handler
// setting top-level name and namespace // setting top-level name and namespace
$expand_prop['ns'] = $requested_prop['attrs']['namespace']; $expand_prop['ns'] = $requested_prop['attrs']['namespace'];
$expand_prop['name'] = $requested_prop['attrs']['name']; $expand_prop['name'] = $requested_prop['attrs']['name'];
// setting 2.-level props, so HTTP_WebDAV_Server can filter unwanted ones out or mark missing ones // setting 2.-level props, so Api\CalDAV can filter unwanted ones out or mark missing ones
$expand_prop['props'] = $options2['props']; $expand_prop['props'] = $options2['props'];
// add top-level path and property // add top-level path and property
$files['files'][0]['path'] = $path; $files['files'][0]['path'] = $path;
@ -463,13 +471,13 @@ class groupdav_principals extends groupdav_handler
} }
if (!isset($property_search) || !$search_props || !isset($search_props[$property_search]['match'])) if (!isset($property_search) || !$search_props || !isset($search_props[$property_search]['match']))
{ {
$this->groupdav->log(__METHOD__."('$path',...) Could not parse options[other]=".array2string($options['other'])); $this->caldav->log(__METHOD__."('$path',...) Could not parse options[other]=".array2string($options['other']));
return '400 Bad Request'; return '400 Bad Request';
} }
// make sure search property is included in toplevel props (can be missing and defaults to property-search/prop's) // make sure search property is included in toplevel props (can be missing and defaults to property-search/prop's)
foreach($search_props as $prop) foreach($search_props as $prop)
{ {
if (!$this->groupdav->prop_requested($prop['name'], $prop['xmlns'])) if (!$this->caldav->prop_requested($prop['name'], $prop['xmlns']))
{ {
$options['props'][] = array( $options['props'][] = array(
'name' => $prop['name'], 'name' => $prop['name'],
@ -483,7 +491,7 @@ class groupdav_principals extends groupdav_handler
substr($search_props[0]['match'],-13) == '/groupdav.php') substr($search_props[0]['match'],-13) == '/groupdav.php')
{ {
$path = '/principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/'; $path = '/principals/users/'.$GLOBALS['egw_info']['user']['account_lid'].'/';
$this->groupdav->log('Enabling hack for Lightning prior 1.1.1 for searching calendar-home-set matching "/groupdav.php": limiting search to '.$path); $this->caldav->log('Enabling hack for Lightning prior 1.1.1 for searching calendar-home-set matching "/groupdav.php": limiting search to '.$path);
} }
} }
// check type attribute to limit search on a certain tree // check type attribute to limit search on a certain tree
@ -645,18 +653,18 @@ class groupdav_principals extends groupdav_handler
static $search_props = array( static $search_props = array(
// from iOS iCal // from iOS iCal
'displayname' => 'Display Name', 'displayname' => 'Display Name',
'email-address-set' => array('description' => 'Email Addresses', 'ns' => groupdav::CALENDARSERVER), 'email-address-set' => array('description' => 'Email Addresses', 'ns' => Api\CalDAV::CALENDARSERVER),
'last-name' => array('description' => 'Last Name', 'ns' => groupdav::CALENDARSERVER), 'last-name' => array('description' => 'Last Name', 'ns' => Api\CalDAV::CALENDARSERVER),
'calendar-user-type' => array('description' => 'Calendar User Type', 'ns' => groupdav::CALDAV), 'calendar-user-type' => array('description' => 'Calendar User Type', 'ns' => Api\CalDAV::CALDAV),
'first-name' => array('description' => 'First Name', 'ns' => groupdav::CALENDARSERVER), 'first-name' => array('description' => 'First Name', 'ns' => Api\CalDAV::CALENDARSERVER),
'calendar-user-address-set' => array('description' => 'Calendar User Address Set', 'ns' => groupdav::CALDAV), 'calendar-user-address-set' => array('description' => 'Calendar User Address Set', 'ns' => Api\CalDAV::CALDAV),
// Lightning // Lightning
'calendar-home-set' => array('description' => 'Calendar Home Set', 'ns' => groupdav::CALENDARSERVER), 'calendar-home-set' => array('description' => 'Calendar Home Set', 'ns' => Api\CalDAV::CALENDARSERVER),
// others, we generally support all properties of the principal // others, we generally support all properties of the principal
); );
header('Content-type: text/xml; charset=UTF-8'); header('Content-type: text/xml; charset=UTF-8');
$xml = new XMLWriter; $xml = new \XMLWriter;
$xml->openMemory(); $xml->openMemory();
$xml->setIndent(true); $xml->setIndent(true);
$xml->startDocument('1.0', 'UTF-8'); $xml->startDocument('1.0', 'UTF-8');
@ -687,7 +695,7 @@ class groupdav_principals extends groupdav_handler
$xml->endDocument(); $xml->endDocument();
echo $xml->outputMemory(); echo $xml->outputMemory();
common::egw_exit(); exit;
} }
/** /**
@ -791,7 +799,7 @@ class groupdav_principals extends groupdav_handler
!($account = $this->accounts->read($id)) || !($account = $this->accounts->read($id)) ||
!$this->accounts->visible($name)) !$this->accounts->visible($name))
{ {
$this->groupdav->log(__METHOD__."('$name', ...) account '$name' NOT found OR not visible to you (check account-selection preference)!"); $this->caldav->log(__METHOD__."('$name', ...) account '$name' NOT found OR not visible to you (check account-selection preference)!");
return '404 Not Found'; return '404 Not Found';
} }
while (substr($rest,-1) == '/') while (substr($rest,-1) == '/')
@ -913,7 +921,7 @@ class groupdav_principals extends groupdav_handler
{ {
$addressbooks[] = '/'; $addressbooks[] = '/';
} }
foreach(array_keys(ExecMethod('addressbook.addressbook_bo.get_addressbooks',EGW_ACL_READ)) as $id) foreach(array_keys($GLOBALS['egw']->contacts->get_addressbooks(EGW_ACL_READ)) as $id)
{ {
if ((in_array('A',$addressbook_home_set) || in_array((string)$id,$addressbook_home_set)) && if ((in_array('A',$addressbook_home_set) || in_array((string)$id,$addressbook_home_set)) &&
is_numeric($id) && ($owner = $this->accounts->id2name($id))) is_numeric($id) && ($owner = $this->accounts->id2name($id)))
@ -934,50 +942,50 @@ class groupdav_principals extends groupdav_handler
{ {
$addressbooks = $calendars = array(); $addressbooks = $calendars = array();
// since we "show" shared addressbooks and calendars in the user home, no need for individualiced homes // since we "show" shared addressbooks and calendars in the user home, no need for individualiced homes
$addressbooks[] = HTTP_WebDAV_Server::mkprop('href', $addressbooks[] = Api\CalDAV::mkprop('href',
$this->base_uri.'/'.$account['account_lid'].'/'); $this->base_uri.'/'.$account['account_lid'].'/');
$calendars[] = HTTP_WebDAV_Server::mkprop('href', $calendars[] = Api\CalDAV::mkprop('href',
$this->base_uri.'/'.$account['account_lid'].'/'); $this->base_uri.'/'.$account['account_lid'].'/');
$displayname = translation::convert($account['account_fullname'], translation::charset(),'utf-8'); $displayname = Api\Translation::convert($account['account_fullname'], Api\Translation::charset(),'utf-8');
return $this->add_principal('users/'.$account['account_lid'], array( return $this->add_principal('users/'.$account['account_lid'], array(
'getetag' => $this->get_etag($account), 'getetag' => $this->get_etag($account),
'displayname' => $displayname, 'displayname' => $displayname,
// CalDAV // CalDAV
'calendar-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',$calendars), 'calendar-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-home-set',$calendars),
// CalDAV scheduling // CalDAV scheduling
'schedule-outbox-URL' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-outbox-URL',array( 'schedule-outbox-URL' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'schedule-outbox-URL',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/outbox/'))), Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/outbox/'))),
'schedule-inbox-URL' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-inbox-URL',array( 'schedule-inbox-URL' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'schedule-inbox-URL',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/inbox/'))), Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/inbox/'))),
'calendar-user-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array( 'calendar-user-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href','mailto:'.$account['account_email']), Api\CalDAV::mkprop('href','mailto:'.$account['account_email']),
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(true).'/principals/users/'.$account['account_lid'].'/'), Api\CalDAV::mkprop('href',$this->base_uri(true).'/principals/users/'.$account['account_lid'].'/'),
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(false).'/principals/users/'.$account['account_lid'].'/'), Api\CalDAV::mkprop('href',$this->base_uri(false).'/principals/users/'.$account['account_lid'].'/'),
HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('accounts', $account['account_id'])), Api\CalDAV::mkprop('href','urn:uuid:'.Api\CalDAV::generate_uid('accounts', $account['account_id'])),
)), )),
'calendar-user-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-type','INDIVIDUAL'), 'calendar-user-type' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-type','INDIVIDUAL'),
// Calendarserver // Calendarserver
'email-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'email-address-set',array( 'email-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'email-address-set',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'email-address',$account['account_email']))), Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'email-address',$account['account_email']))),
'last-name' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'last-name',$account['account_lastname']), 'last-name' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'last-name',$account['account_lastname']),
'first-name' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'first-name',$account['account_firstname']), 'first-name' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'first-name',$account['account_firstname']),
'record-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'record-type','users'), 'record-type' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'record-type','users'),
// WebDAV ACL and CalDAV proxy // WebDAV ACL and CalDAV proxy
'group-membership' => $this->principal_set('group-membership', $this->accounts->memberships($account['account_id']), 'group-membership' => $this->principal_set('group-membership', $this->accounts->memberships($account['account_id']),
array('calendar', 'resources'), $account['account_id']), // add proxy-rights array('calendar', 'resources'), $account['account_id']), // add proxy-rights
'alternate-URI-set' => array( 'alternate-URI-set' => array(
HTTP_WebDAV_Server::mkprop('href','mailto:'.$account['account_email'])), Api\CalDAV::mkprop('href','mailto:'.$account['account_email'])),
// CardDAV // CardDAV
'addressbook-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',$addressbooks), 'addressbook-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-home-set',$addressbooks),
'principal-address' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'principal-address', 'principal-address' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'principal-address',
$GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'] ? '' : array( $GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'] ? '' : array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/addressbook-accounts/'.$account['person_id'].'.vcf'))), Api\CalDAV::mkprop('href',$this->base_uri.'/addressbook-accounts/'.$account['person_id'].'.vcf'))),
// CardDAV directory // CardDAV directory
'directory-gateway' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV, 'directory-gateway',array( 'directory-gateway' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV, 'directory-gateway',array(
HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/addressbook/'))), Api\CalDAV::mkprop('href', $this->base_uri.'/addressbook/'))),
'resource-id' => array(HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('accounts', $account['account_id']))), 'resource-id' => array(Api\CalDAV::mkprop('href','urn:uuid:'.Api\CalDAV::generate_uid('accounts', $account['account_id']))),
)); ));
} }
@ -1096,7 +1104,7 @@ class groupdav_principals extends groupdav_handler
*/ */
protected function add_group(array $account) protected function add_group(array $account)
{ {
$displayname = translation::convert(lang('Group').' '.$account['account_lid'], translation::charset(), 'utf-8'); $displayname = Api\Translation::convert(lang('Group').' '.$account['account_lid'], Api\Translation::charset(), 'utf-8');
// only return current user, if account-selection == 'none' // only return current user, if account-selection == 'none'
if ($GLOBALS['egw_info']['user']['preferences']['common']['account_selection'] == 'none') if ($GLOBALS['egw_info']['user']['preferences']['common']['account_selection'] == 'none')
@ -1111,19 +1119,19 @@ class groupdav_principals extends groupdav_handler
return $this->add_principal('groups/'.$account['account_lid'], array( return $this->add_principal('groups/'.$account['account_lid'], array(
'getetag' => $this->get_etag($account), 'getetag' => $this->get_etag($account),
'displayname' => $displayname, 'displayname' => $displayname,
'calendar-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array( 'calendar-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))), Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
'addressbook-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array( 'addressbook-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))), Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
'calendar-user-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array( 'calendar-user-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(true).'/principals/groups/'.$account['account_lid'].'/'), Api\CalDAV::mkprop('href',$this->base_uri(true).'/principals/groups/'.$account['account_lid'].'/'),
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(false).'/principals/groups/'.$account['account_lid'].'/'), Api\CalDAV::mkprop('href',$this->base_uri(false).'/principals/groups/'.$account['account_lid'].'/'),
HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('accounts', $account['account_id'])), Api\CalDAV::mkprop('href','urn:uuid:'.Api\CalDAV::generate_uid('accounts', $account['account_id'])),
)), )),
'record-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'record-type','groups'), 'record-type' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'record-type','groups'),
'calendar-user-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-type','GROUP'), 'calendar-user-type' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-type','GROUP'),
'group-member-set' => $this->principal_set('group-member-set', $groupmembers), 'group-member-set' => $this->principal_set('group-member-set', $groupmembers),
'resource-id' => array(HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('accounts', $account['account_id']))), 'resource-id' => array(Api\CalDAV::mkprop('href','urn:uuid:'.Api\CalDAV::generate_uid('accounts', $account['account_id']))),
)); ));
} }
@ -1142,18 +1150,18 @@ class groupdav_principals extends groupdav_handler
return $this->add_principal($name, array( return $this->add_principal($name, array(
'getetag' => $this->get_resource_etag($resource), 'getetag' => $this->get_resource_etag($resource),
'displayname' => $displayname, 'displayname' => $displayname,
'calendar-user-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array( 'calendar-user-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(true).'/principals/'.$name.'/'), Api\CalDAV::mkprop('href',$this->base_uri(true).'/principals/'.$name.'/'),
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(false).'/principals/'.$name.'/'), Api\CalDAV::mkprop('href',$this->base_uri(false).'/principals/'.$name.'/'),
HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('resources', $resource['res_id'])), Api\CalDAV::mkprop('href','urn:uuid:'.Api\CalDAV::generate_uid('resources', $resource['res_id'])),
)), )),
'record-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'record-type',$is_location ? 'locations' : 'resources'), 'record-type' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'record-type',$is_location ? 'locations' : 'resources'),
'calendar-user-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-type',$is_location ? 'ROOM' : 'RESOURCE'), 'calendar-user-type' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-type',$is_location ? 'ROOM' : 'RESOURCE'),
'resource-id' => array(HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('resources', $resource['res_id']))), 'resource-id' => array(Api\CalDAV::mkprop('href','urn:uuid:'.Api\CalDAV::generate_uid('resources', $resource['res_id']))),
// Calendarserver also reports empty email-address-set, thought iCal still does not show resources (only locations) // Calendarserver also reports empty email-address-set, thought iCal still does not show resources (only locations)
'email-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'email-address-set',''), 'email-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'email-address-set',''),
'calendar-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array( 'calendar-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$name.'/'))), Api\CalDAV::mkprop('href',$this->base_uri.'/'.$name.'/'))),
)); ));
} }
@ -1173,10 +1181,10 @@ class groupdav_principals extends groupdav_handler
} }
if (is_null($is_location)) $is_location = self::resource_is_location($resource); if (is_null($is_location)) $is_location = self::resource_is_location($resource);
$displayname = translation::convert($resource['name'], translation::charset(), 'utf-8'); $displayname = Api\Translation::convert($resource['name'], Api\Translation::charset(), 'utf-8');
return ($is_location ? 'locations/' : 'resources/').$resource['res_id'].'-'. return ($is_location ? 'locations/' : 'resources/').$resource['res_id'].'-'.
preg_replace('/[^a-z0-9]+/i','-', translation::to_ascii($resource['name'])); preg_replace('/[^a-z0-9]+/i','-', Api\Translation::to_ascii($resource['name']));
} }
/** /**
@ -1190,7 +1198,7 @@ class groupdav_principals extends groupdav_handler
static $location_cats=null; static $location_cats=null;
if (is_null($location_cats)) if (is_null($location_cats))
{ {
$config = config::read('resources'); $config = Api\Config::read('resources');
$location_cats = $config['location_cats'] ? explode(',', $config['location_cats']) : array(); $location_cats = $config['location_cats'] ? explode(',', $config['location_cats']) : array();
} }
if (!is_array($resource) && !($resource = self::read_resource($resource))) if (!is_array($resource) && !($resource = self::read_resource($resource)))
@ -1298,16 +1306,16 @@ class groupdav_principals extends groupdav_handler
* Add a collection * Add a collection
* *
* @param string $path * @param string $path
* @param array $props =array() extra properties 'resourcetype' is added anyway, name => value pairs or name => HTTP_WebDAV_Server([namespace,]name,value) * @param array $props =array() extra properties 'resourcetype' is added anyway, name => value pairs or name => Api\CalDAV([namespace,]name,value)
* @return array with values for keys 'path' and 'props' * @return array with values for keys 'path' and 'props'
*/ */
protected function add_collection($path, array $props = array()) protected function add_collection($path, array $props = array())
{ {
if ($this->groupdav->prop_requested('supported-report-set')) if ($this->caldav->prop_requested('supported-report-set'))
{ {
$props['supported-report-set'] = $this->supported_report_set($path); $props['supported-report-set'] = $this->supported_report_set($path);
} }
return $this->groupdav->add_collection($path, $props); return $this->caldav->add_collection($path, $props);
} }
/** /**
@ -1320,17 +1328,17 @@ class groupdav_principals extends groupdav_handler
*/ */
protected function add_principal($principal, array $props = array(), $principal_url=null) protected function add_principal($principal, array $props = array(), $principal_url=null)
{ {
$props['resourcetype'][] = HTTP_WebDAV_Server::mkprop('principal', ''); $props['resourcetype'][] = Api\CalDAV::mkprop('principal', '');
// required props per WebDAV ACL // required props per WebDAV ACL
foreach(array('alternate-URI-set', 'group-membership') as $name) foreach(array('alternate-URI-set', 'group-membership') as $name)
{ {
if (!isset($props[$name])) $props[$name] = HTTP_WebDAV_Server::mkprop($name,''); if (!isset($props[$name])) $props[$name] = Api\CalDAV::mkprop($name,'');
} }
if (!$principal_url) $principal_url = $principal; if (!$principal_url) $principal_url = $principal;
$props['principal-URL'] = array( $props['principal-URL'] = array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/principals/'.$principal.'/')); Api\CalDAV::mkprop('href',$this->base_uri.'/principals/'.$principal.'/'));
return $this->add_collection('/principals/'.$principal.'/', $props); return $this->add_collection('/principals/'.$principal.'/', $props);
} }
@ -1412,7 +1420,7 @@ class groupdav_principals extends groupdav_handler
'displayname' => lang('%1 proxy of %2', lang($app).' '.lang($what), basename($principal)), 'displayname' => lang('%1 proxy of %2', lang($app).' '.lang($what), basename($principal)),
'group-member-set' => $this->principal_set('group-member-set', $proxys), 'group-member-set' => $this->principal_set('group-member-set', $proxys),
'getetag' => md5(serialize($proxys)), 'getetag' => md5(serialize($proxys)),
'resourcetype' => array(HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER, $type, '')), 'resourcetype' => array(Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER, $type, '')),
)); ));
} }
@ -1434,7 +1442,7 @@ class groupdav_principals extends groupdav_handler
{ {
if ($this->accounts->visible($account_lid)) // only add visible accounts, gives error in iCal otherwise if ($this->accounts->visible($account_lid)) // only add visible accounts, gives error in iCal otherwise
{ {
$set[] = HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/principals/'.($account_id < 0 ? 'groups/' : 'users/').$account_lid.'/'); $set[] = Api\CalDAV::mkprop('href', $this->base_uri.'/principals/'.($account_id < 0 ? 'groups/' : 'users/').$account_lid.'/');
} }
} }
if ($app_proxys) if ($app_proxys)
@ -1493,7 +1501,7 @@ class groupdav_principals extends groupdav_handler
$rights = $location_grants['L'.$resource['cat_id']]; $rights = $location_grants['L'.$resource['cat_id']];
if (isset($rights)) if (isset($rights))
{ {
$set[] = HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/principals/'.$this->resource2name($resource). $set[] = Api\CalDAV::mkprop('href', $this->base_uri.'/principals/'.$this->resource2name($resource).
'/calendar-proxy-'.($rights & EGW_ACL_DIRECT_BOOKING ? 'write' : 'read').'/'); '/calendar-proxy-'.($rights & EGW_ACL_DIRECT_BOOKING ? 'write' : 'read').'/');
} }
} }
@ -1518,7 +1526,7 @@ class groupdav_principals extends groupdav_handler
($account_lid = $this->accounts->id2name($account_id)) && ($account_lid = $this->accounts->id2name($account_id)) &&
$this->accounts->visible($account_lid)) // only add visible accounts, gives error in iCal otherwise $this->accounts->visible($account_lid)) // only add visible accounts, gives error in iCal otherwise
{ {
$set[] = HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/principals/'. $set[] = Api\CalDAV::mkprop('href', $this->base_uri.'/principals/'.
($account_id < 0 ? 'groups/' : 'users/'). ($account_id < 0 ? 'groups/' : 'users/').
$account_lid.'/'.$app.'-proxy-'.($rights & EGW_ACL_EDIT ? 'write' : 'read').'/'); $account_lid.'/'.$app.'-proxy-'.($rights & EGW_ACL_EDIT ? 'write' : 'read').'/');
} }

View File

@ -0,0 +1,186 @@
<?php
/**
* EGroupware: CalDAV/CardDAV/GroupDAV access: iterator for (huge) propfind sets
*
* @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
*/
namespace EGroupware\Api\CalDAV;
/**
* Iterator for propfinds using propfind callback of a Handler to query results in chunks
*
* The propfind method just computes a filter and then returns an instance of this iterator instead of the files:
*
* function propfind($path,$options,&$files,$user,$id='')
* {
* $filter = array();
* // compute filter from path, options, ...
*
* $files['files'] = new groupdav_propfind_iterator($this,$filter,$files['files']);
*
* return true;
* }
*/
class PropfindIterator implements \Iterator
{
/**
* current path
*
* @var string
*/
protected $path;
/**
* Handler to call for entries
*
* @var Handler
*/
protected $handler;
/**
* Filter of propfind call
*
* @var array
*/
protected $filter;
/**
* Extra responses to return too
*
* @var array
*/
protected $common_files;
/**
* current chunk
*
* @var array
*/
protected $files;
/**
* Start value for callback
*
* @var int
*/
protected $start=0;
/**
* Number of entries queried from callback in one call
*
*/
const CHUNK_SIZE = 500;
/**
* Log calls via error_log()
*
* @var boolean
*/
public $debug = false;
/**
/**
* Constructor
*
* @param Handler $handler
* @param array $filter filter for propfind call
* @param array $files =array() extra files/responses to return too
*/
public function __construct(Handler $handler, $path, array $filter,array &$files=array())
{
if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)");
$this->path = $path;
$this->handler = $handler;
$this->filter = $filter;
$this->files = $this->common_files = $files;
reset($this->files);
}
/**
* Return the current element
*
* @return array
*/
public function current()
{
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files)));
return current($this->files);
}
/**
* Return the key of the current element
*
* @return int|string
*/
public function key()
{
$current = current($this->files);
if ($this->debug) error_log(__METHOD__."() returning ".array2string($current['path']));
return $current['path']; // we return path as key
}
/**
* Move forward to next element (called after each foreach loop)
*/
public function next()
{
if (next($this->files) !== false)
{
if ($this->debug) error_log(__METHOD__."() returning TRUE");
return true;
}
// check if previous query gave less then CHUNK_SIZE entries --> we're done
if ($this->start && count($this->files) < self::CHUNK_SIZE)
{
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
return false;
}
// try query further files via propfind callback of handler and store result in $this->files
$this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
if (!is_array($this->files) || !($entries = count($this->files)))
{
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
return false; // no further entries
}
$this->start += self::CHUNK_SIZE;
reset($this->files);
if ($this->debug) error_log(__METHOD__."() this->start=$this->start, entries=$entries, count(this->files)=".count($this->files)." returning ".array2string(current($this->files) !== false));
return current($this->files) !== false;
}
/**
* Rewind the Iterator to the first element (called at beginning of foreach loop)
*/
public function rewind()
{
if ($this->debug) error_log(__METHOD__."()");
$this->start = 0;
$this->files = $this->common_files;
if (!$this->files) $this->next(); // otherwise valid will return false and nothing get returned
reset($this->files);
}
/**
* Checks if current position is valid
*
* @return boolean
*/
public function valid ()
{
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false));
return current($this->files) !== false;
}
}

218
api/src/Json/Tail.php Normal file
View File

@ -0,0 +1,218 @@
<?php
/**
* EGroupware - Ajax log file viewer (tail -f)
*
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker@outdoor-training.de>
* @copyright 2012-16 by RalfBecker@outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage json
* @version $Id$
*/
namespace EGroupware\Api\Json;
use EGroupware\Api;
/**
* Ajax log file viewer (tail -f)
*
* To not allow to view arbitrary files, allowed filenames are stored in the session.
* Class fetches log-file periodically in chunks for 8k.
* If fetch returns no new content next request will be in 2s, otherwise in 200ms.
* As logfiles can be quiet huge, we display at max the last 32k of it!
*
* Example usage:
*
* $error_log = new Api\Json\Tail('/var/log/apache2/error_log');
* echo $error_log->show();
*
* Strongly prefered for security reasons is to use a path relative to EGroupware's files_dir,
* eg. new Api\Json\Tail('groupdav/somelog')!
*/
class Tail
{
/**
* Maximum size of single ajax request
*
* Currently also maximum size / 4 of displayed logfile content!
*/
const MAX_CHUNK_SIZE = 8192;
/**
* Contains allowed filenames to display, we can NOT allow to display arbitrary files!
*
* @param array
*/
protected $filenames;
/**
* Filename class is instanciated to view, set by constructor
*
* @param string
*/
protected $filename;
/**
* Methods allowed to call via menuaction
*
* @var array
*/
public $public_functions = array(
'download' => true,
);
/**
* Constructor
*
* @param string $filename =null if not starting with as slash relative to EGw files dir (this is strongly prefered for security reasons)
*/
public function __construct($filename=null)
{
$this->filenames =& Api\Cache::getSession('phpgwapi', __CLASS__);
if ($filename)
{
$this->filename = $filename;
if (!$this->filenames || !in_array($filename,$this->filenames)) $this->filenames[] = $filename;
}
}
/**
* Ajax callback to load next chunk of log-file
*
* @param string $filename
* @param int $start =0 last position in log-file
* @throws Api\Exception\WrongParameter
*/
public function ajax_chunk($filename,$start=0)
{
if (!in_array($filename,$this->filenames))
{
throw new Api\Exception\WrongParameter("Not allowed to view '$filename'!");
}
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
if (file_exists($filename))
{
$size = filesize($filename);
if (!$start || $start < 0 || $start > $size || $size-$start > 4*self::MAX_CHUNK_SIZE)
{
$start = $size - 4*self::MAX_CHUNK_SIZE;
if ($start < 0) $start = 0;
}
$hsize = Api\Vfs::hsize($size);
$content = file_get_contents($filename, false, null, $start, self::MAX_CHUNK_SIZE);
$length = bytes($content);
$writable = is_writable($filename) || is_writable(dirname($filename));
}
else
{
$start = $length = 0;
$content = '';
$writable = $hsize = false;
}
$response = Response::get();
$response->data(array( // send all responses as data
'size' => $hsize,
'writable' => $writable,
'next' => $start + $length,
'length' => $length,
'content' => $content,
));
}
/**
* Ajax callback to delete log-file
*
* @param string $filename
* @param boolean $truncate =false true: truncate file, false: delete file
* @throws Api\Exception\WrongParameter
*/
public function ajax_delete($filename,$truncate=false)
{
if (!in_array($filename,$this->filenames))
{
throw new Api\Exception\WrongParameter("Not allowed to view '$filename'!");
}
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
if ($truncate)
{
file_put_contents($filename, '');
}
else
{
unlink($filename);
}
}
/**
* Return html & javascript for logviewer
*
* @param string $header =null default $this->filename
* @return string
* @throws Api\Exception\WrongParameter
*/
public function show($header=null)
{
if (!isset($this->filename))
{
throw new Api\Exception\WrongParameter("Must be instanciated with filename!");
}
if (is_null($header)) $header = $this->filename;
return '
<p style="float: left; margin: 5px"><b>'.htmlspecialchars($header).'</b></p>
<div style="float: right; margin: 2px; margin-right: 5px">
'.Api\Html::form(
Api\Html::input('clear_log',lang('Clear window'),'button','id="clear_log"')."\n".
Api\Html::input('delete_log',lang('Delete file'),'button','id="purge_log"')."\n".
Api\Html::input('empty_log',lang('Empty file'),'button','id="empty_log"')."\n".
Api\Html::input('download_log',lang('Download'),'submit','id="download_log"'),
'','/index.php',array(
'menuaction' => 'api.'.__CLASS__.'.download',
'filename' => $this->filename,
)).'
</div>
<pre class="tail" id="log" data-filename="'.$this->filename.'" style="clear: both; width: 99.5%; border: 2px groove silver; margin-bottom: 0; overflow: auto;"></pre>';
}
/**
* Download a file specified per GET parameter (must be in $this->filesnames!)
*
* @throws Api\Exception\WrongParameter
*/
public function download()
{
$filename = $_GET['filename'];
if (!in_array($filename,$this->filenames))
{
throw new Api\Exception\WrongParameter("Not allowed to download '$filename'!");
}
Api\Header\Content::type(basename($filename), 'text/plain');
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
for($n=ob_get_level(); $n > 0; --$n)
{
ob_end_clean(); // stop all output buffering, to NOT run into memory_limit
}
readfile($filename);
exit;
}
}
// some testcode, if this file is called via it's URL (you need to uncomment and adapt filename!)
/*if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__)
{
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => 'admin',
'nonavbar' => true,
),
);
include_once '../../header.inc.php';
$error_log = new Tail('/opt/local/apache2/logs/error_log');
echo $error_log->show();
}*/

View File

@ -1054,7 +1054,7 @@ class Account implements \ArrayAccess
} }
if ($data['acc_smtp_type']) if ($data['acc_smtp_type'])
{ {
if (substr($data['acc_imap_type'], 0, 4) == 'Smtp') if (substr($data['acc_smtp_type'], 0, 4) == 'Smtp')
{ {
$data['acc_smtp_type'] = __NAMESPACE__.'\\'.$data['acc_smtp_type']; $data['acc_smtp_type'] = __NAMESPACE__.'\\'.$data['acc_smtp_type'];
} }

View File

@ -11,17 +11,19 @@
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* EGroupware: CalDAV / GroupDAV access: calendar handler * CalDAV/CardDAV/GroupDAV access: Calendar handler
* *
* 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). * and our request-log (prefixed with "### " after request and response, like exceptions).
* *
* @ToDo: new properties on calendars and it's ressources specially from sharing: * @ToDo: new properties on calendars and it's ressources specially from sharing:
* - for the invite property: 5.2.2 in https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-sharing.txt * - for the invite property: 5.2.2 in https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-sharing.txt
* - https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.txt * - https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-schedulingchanges.txt
*/ */
class calendar_groupdav extends groupdav_handler class calendar_groupdav extends Api\CalDAV\Handler
{ {
/** /**
* bo class of the application * bo class of the application
@ -78,7 +80,7 @@ class calendar_groupdav extends groupdav_handler
/** /**
* Are we using id, uid or caldav_name for the path/url * Are we using id, uid or caldav_name for the path/url
* *
* Get's set in constructor to 'caldav_name' and groupdav_handler::$path_extension = ''! * Get's set in constructor to 'caldav_name' and self::$path_extension = ''!
*/ */
static $path_attr = 'id'; static $path_attr = 'id';
@ -86,11 +88,11 @@ class calendar_groupdav extends groupdav_handler
* Constructor * Constructor
* *
* @param string $app 'calendar', 'addressbook' or 'infolog' * @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 calendar_boupdate(); $this->bo = new calendar_boupdate();
$this->vCalendar = new Horde_Icalendar; $this->vCalendar = new Horde_Icalendar;
@ -99,7 +101,7 @@ class calendar_groupdav extends groupdav_handler
if (version_compare($GLOBALS['egw_info']['apps']['calendar']['version'], '1.9.003', '>=')) if (version_compare($GLOBALS['egw_info']['apps']['calendar']['version'], '1.9.003', '>='))
{ {
self::$path_attr = 'caldav_name'; self::$path_attr = 'caldav_name';
groupdav_handler::$path_extension = ''; self::$path_extension = '';
} }
} }
@ -120,8 +122,8 @@ class calendar_groupdav extends groupdav_handler
if (!is_array($event)) $event = $this->bo->read($event); if (!is_array($event)) $event = $this->bo->read($event);
$name = $event[self::$path_attr]; $name = $event[self::$path_attr];
} }
$name .= groupdav_handler::$path_extension; $name .= self::$path_extension;
//error_log(__METHOD__.'('.array2string($event).") path_attr='".self::$path_attr."', path_extension='".groupdav_handler::$path_extension."' returning ".array2string($name)); //error_log(__METHOD__.'('.array2string($event).") path_attr='".self::$path_attr."', path_extension='".self::$path_extension."' returning ".array2string($name));
return $name; return $name;
} }
@ -152,8 +154,8 @@ class calendar_groupdav extends groupdav_handler
if (isset($_GET['download'])) if (isset($_GET['download']))
{ {
$this->groupdav->propfind_options['props'] = array(array( $this->caldav->propfind_options['props'] = array(array(
'xmlns' => groupdav::CALDAV, 'xmlns' => Api\CalDAV::CALDAV,
'name' => 'calendar-data', 'name' => 'calendar-data',
)); ));
} }
@ -251,7 +253,7 @@ class calendar_groupdav extends groupdav_handler
else else
{ {
// return iterator, calling ourself to return result in chunks // return iterator, calling ourself to return result in chunks
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']); $files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
} }
if (isset($_GET['download'])) if (isset($_GET['download']))
{ {
@ -319,7 +321,7 @@ class calendar_groupdav extends groupdav_handler
{ {
if ($this->debug) $starttime = microtime(true); if ($this->debug) $starttime = microtime(true);
$calendar_data = $this->groupdav->prop_requested('calendar-data', groupdav::CALDAV, true); $calendar_data = $this->caldav->prop_requested('calendar-data', Api\CalDAV::CALDAV, true);
if (!is_array($calendar_data)) $calendar_data = false; // not in allprop or autoindex if (!is_array($calendar_data)) $calendar_data = false; // not in allprop or autoindex
$files = array(); $files = array();
@ -358,14 +360,14 @@ class calendar_groupdav extends groupdav_handler
'getetag' => '"'.$etag.'"', 'getetag' => '"'.$etag.'"',
'getlastmodified' => $event['modified'], 'getlastmodified' => $event['modified'],
// user and timestamp of creation or last modification of event, used in calendarserver only for shared calendars // user and timestamp of creation or last modification of event, used in calendarserver only for shared calendars
'created-by' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER, 'created-by', 'created-by' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER, 'created-by',
$this->_created_updated_by_prop($event['creator'], $event['created'])), $this->_created_updated_by_prop($event['creator'], $event['created'])),
'updated-by' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER, 'updated-by', 'updated-by' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER, 'updated-by',
$this->_created_updated_by_prop($event['modifier'], $event['modified'])), $this->_created_updated_by_prop($event['modifier'], $event['modified'])),
); );
if ($this->use_schedule_tag) if ($this->use_schedule_tag)
{ {
$props['schedule-tag'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV, 'schedule-tag', '"'.$schedule_tag.'"'); $props['schedule-tag'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV, 'schedule-tag', '"'.$schedule_tag.'"');
} }
//error_log(__FILE__ . __METHOD__ . "Calendar Data : $calendar_data"); //error_log(__FILE__ . __METHOD__ . "Calendar Data : $calendar_data");
if ($calendar_data) if ($calendar_data)
@ -375,16 +377,16 @@ class calendar_groupdav extends groupdav_handler
!isset($calendar_data['children']['expand']) ? false : !isset($calendar_data['children']['expand']) ? false :
($calendar_data['children']['expand']['attrs'] ? $calendar_data['children']['expand']['attrs'] : true)); ($calendar_data['children']['expand']['attrs'] ? $calendar_data['children']['expand']['attrs'] : true));
$props['getcontentlength'] = bytes($content); $props['getcontentlength'] = bytes($content);
$props['calendar-data'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content); $props['calendar-data'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-data',$content);
} }
/* Calendarserver reports new events with schedule-changes: action: create, which iCal request /* Calendarserver reports new events with schedule-changes: action: create, which iCal request
* adding it, unfortunately does not lead to showing the new event in the users inbox * adding it, unfortunately does not lead to showing the new event in the users inbox
if (strpos($path, '/inbox/') !== false && $this->groupdav->prop_requested('schedule-changes')) if (strpos($path, '/inbox/') !== false && $this->caldav->prop_requested('schedule-changes'))
{ {
$props['schedule-changes'] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'schedule-changes',array( $props['schedule-changes'] = Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'schedule-changes',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'dtstamp',gmdate('Ymd\THis',$event['created']).'Z'), Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'dtstamp',gmdate('Ymd\THis',$event['created']).'Z'),
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'action',array( Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'action',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'create',''), Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'create',''),
)), )),
)); ));
}*/ }*/
@ -438,18 +440,18 @@ class calendar_groupdav extends groupdav_handler
{ {
if ($user && ($val = $this->accounts->id2name($user, $name))) if ($user && ($val = $this->accounts->id2name($user, $name)))
{ {
$ns = groupdav::CALENDARSERVER; $ns = Api\CalDAV::CALENDARSERVER;
if ($prop == 'href') if ($prop == 'href')
{ {
$ns = ''; $ns = '';
$val = 'mailto:'.$val; $val = 'mailto:'.$val;
} }
$props[$prop] = $ns ? HTTP_WebDAV_Server::mkprop($ns, $prop, $val) : HTTP_WebDAV_Server::mkprop($prop, $val); $props[$prop] = $ns ? Api\CalDAV::mkprop($ns, $prop, $val) : Api\CalDAV::mkprop($prop, $val);
} }
} }
if ($time) if ($time)
{ {
$props['dtstamp'] = HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER, 'dtstamp', gmdate('Ymd\\This\\Z', $time)); $props['dtstamp'] = Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER, 'dtstamp', gmdate('Ymd\\This\\Z', $time));
} }
//error_log(__METHOD__."($user, $time) returning ".array2string($props)); //error_log(__METHOD__."($user, $time) returning ".array2string($props));
return $props ? $props : ''; return $props ? $props : '';
@ -567,11 +569,11 @@ class calendar_groupdav extends groupdav_handler
case 'sync-level': case 'sync-level':
if ($option['data'] != '1') 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; break;
default: 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; break;
} }
} }
@ -587,8 +589,8 @@ class calendar_groupdav extends groupdav_handler
if ($id) if ($id)
{ {
$cal_filters['query'][self::$path_attr] = groupdav_handler::$path_extension ? $cal_filters['query'][self::$path_attr] = self::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id; basename($id,self::$path_extension) : $id;
} }
else // fetch all given url's else // fetch all given url's
{ {
@ -599,8 +601,8 @@ class calendar_groupdav extends groupdav_handler
$parts = explode('/',$option['data']); $parts = explode('/',$option['data']);
if (($id = urldecode(array_pop($parts)))) if (($id = urldecode(array_pop($parts))))
{ {
$cal_filters['query'][self::$path_attr][] = groupdav_handler::$path_extension ? $cal_filters['query'][self::$path_attr][] = self::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id; basename($id,self::$path_extension) : $id;
} }
} }
} }
@ -872,12 +874,12 @@ class calendar_groupdav extends groupdav_handler
{ {
if ($oldEvent['owner'] == $GLOBALS['egw_info']['user']['account_id']) if ($oldEvent['owner'] == $GLOBALS['egw_info']['user']['account_id'])
{ {
$this->groupdav->log("Both If-Match and If-Schedule-Tag-Match header given: If-Schedule-Tag-Match ignored for event owner!"); $this->caldav->log("Both If-Match and If-Schedule-Tag-Match header given: If-Schedule-Tag-Match ignored for event owner!");
unset($_SERVER['HTTP_IF_SCHEDULE_TAG_MATCH']); unset($_SERVER['HTTP_IF_SCHEDULE_TAG_MATCH']);
} }
else else
{ {
$this->groupdav->log("Both If-Match and If-Schedule-Tag-Match header given: If-Schedule-Tag-Match takes precedence for participants!"); $this->caldav->log("Both If-Match and If-Schedule-Tag-Match header given: If-Schedule-Tag-Match takes precedence for participants!");
} }
} }
// check CalDAV Scheduling schedule-tag precondition // check CalDAV Scheduling schedule-tag precondition
@ -935,7 +937,7 @@ class calendar_groupdav extends groupdav_handler
!($oldEvent['recur_date'] == $event['recurrence'] || !$event['recurrence'] && !$oldEvent['recurrence'])) !($oldEvent['recur_date'] == $event['recurrence'] || !$event['recurrence'] && !$oldEvent['recurrence']))
{ {
// if recurrence not found --> log it and continue with other recurrence // if recurrence not found --> log it and continue with other recurrence
$this->groupdav->log(__METHOD__."(,,$user) could NOT find recurrence=$event[recurrence]=".egw_time::to($event['recurrence']).' of event series! event='.array2string($event)); $this->caldav->log(__METHOD__."(,,$user) could NOT find recurrence=$event[recurrence]=".egw_time::to($event['recurrence']).' of event series! event='.array2string($event));
continue; continue;
} }
} }
@ -966,7 +968,7 @@ class calendar_groupdav extends groupdav_handler
} }
if (!$modified) // NO modififictions, or none we understood --> log it and return Ok: "204 No Content" if (!$modified) // NO modififictions, or none we understood --> log it and return Ok: "204 No Content"
{ {
$this->groupdav->log(__METHOD__."(,,$user) NO changes for current user events=".array2string($events).', old-event='.array2string($oldEvent)); $this->caldav->log(__METHOD__."(,,$user) NO changes for current user events=".array2string($events).', old-event='.array2string($oldEvent));
} }
$this->put_response_headers($eventId, $options['path'], '204 No Content', self::$path_attr == 'caldav_name'); $this->put_response_headers($eventId, $options['path'], '204 No Content', self::$path_attr == 'caldav_name');
@ -1002,7 +1004,7 @@ class calendar_groupdav extends groupdav_handler
} }
if (!($cal_id = $handler->importVCal($vCalendar, $eventId, if (!($cal_id = $handler->importVCal($vCalendar, $eventId,
self::etag2value($this->http_if_match), false, 0, $this->groupdav->current_user_principal, $user, $charset, $id))) self::etag2value($this->http_if_match), false, 0, $this->caldav->current_user_principal, $user, $charset, $id)))
{ {
if ($this->debug) error_log(__METHOD__."(,$id) eventId=$eventId: importVCal('$options[content]') returned ".array2string($cal_id)); if ($this->debug) error_log(__METHOD__."(,$id) eventId=$eventId: importVCal('$options[content]') returned ".array2string($cal_id));
if ($eventId && $cal_id === false) if ($eventId && $cal_id === false)
@ -1092,7 +1094,7 @@ class calendar_groupdav extends groupdav_handler
list($eventId) = explode(':', $id); list($eventId) = explode(':', $id);
if (!($cal_id = $handler->importVCal($vCalendar, $eventId, null, if (!($cal_id = $handler->importVCal($vCalendar, $eventId, null,
false, 0, $this->groupdav->current_user_principal, $user, $charset))) false, 0, $this->caldav->current_user_principal, $user, $charset)))
{ {
if ($this->debug) error_log(__METHOD__."() importVCal($eventId) returned false"); if ($this->debug) error_log(__METHOD__."() importVCal($eventId) returned false");
} }
@ -1128,13 +1130,13 @@ class calendar_groupdav extends groupdav_handler
$handler->setSupportedFields('groupdav'); $handler->setSupportedFields('groupdav');
$handler->calendarOwner = $handler->user = 0; // to NOT default owner/organizer to something $handler->calendarOwner = $handler->user = 0; // to NOT default owner/organizer to something
if (!($component = $vcal->getComponent(0)) || if (!($component = $vcal->getComponent(0)) ||
!($event = $handler->vevent2egw($component, $version, $handler->supportedFields, $this->groupdav->current_user_principal, 'Horde_Icalendar_Vfreebusy'))) !($event = $handler->vevent2egw($component, $version, $handler->supportedFields, $this->caldav->current_user_principal, 'Horde_Icalendar_Vfreebusy')))
{ {
return '400 Bad request'; return '400 Bad request';
} }
if ($event['owner'] != $user) if ($event['owner'] != $user)
{ {
$this->groupdav->log(__METHOD__."('$ical',,$user) ORGANIZER is NOT principal!"); $this->caldav->log(__METHOD__."('$ical',,$user) ORGANIZER is NOT principal!");
return '403 Forbidden'; return '403 Forbidden';
} }
//print_r($event); //print_r($event);
@ -1149,7 +1151,7 @@ class calendar_groupdav extends groupdav_handler
$xml->openMemory(); $xml->openMemory();
$xml->setIndent(true); $xml->setIndent(true);
$xml->startDocument('1.0', 'UTF-8'); $xml->startDocument('1.0', 'UTF-8');
$xml->startElementNs('C', 'schedule-response', groupdav::CALDAV); $xml->startElementNs('C', 'schedule-response', Api\CalDAV::CALDAV);
foreach(array_keys($event['participants']) as $uid) foreach(array_keys($event['participants']) as $uid)
{ {
@ -1224,16 +1226,16 @@ class calendar_groupdav extends groupdav_handler
if ($this->bo->check_perms(EGW_ACL_FREEBUSY, 0, $user)) if ($this->bo->check_perms(EGW_ACL_FREEBUSY, 0, $user))
{ {
$privileges['read-free-busy'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV, 'read-free-busy', ''); $privileges['read-free-busy'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV, 'read-free-busy', '');
if (substr($path, -8) == '/outbox/' && $this->bo->check_acl_invite($user)) if (substr($path, -8) == '/outbox/' && $this->bo->check_acl_invite($user))
{ {
$privileges['schedule-send'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV, 'schedule-send', ''); $privileges['schedule-send'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV, 'schedule-send', '');
} }
} }
if (substr($path, -7) == '/inbox/' && $this->bo->check_acl_invite($user)) if (substr($path, -7) == '/inbox/' && $this->bo->check_acl_invite($user))
{ {
$privileges['schedule-deliver'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV, 'schedule-deliver', ''); $privileges['schedule-deliver'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV, 'schedule-deliver', '');
} }
// remove bind privilege on other users or groups calendars, if calendar config require_acl_invite is set // remove bind privilege on other users or groups calendars, if calendar config require_acl_invite is set
// and current user has no invite grant // and current user has no invite grant
@ -1494,47 +1496,47 @@ class calendar_groupdav extends groupdav_handler
if (!isset($props['calendar-description'])) if (!isset($props['calendar-description']))
{ {
// default calendar description: can be overwritten via PROPPATCH, in which case it's already set // default calendar description: can be overwritten via PROPPATCH, in which case it's already set
$props['calendar-description'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname); $props['calendar-description'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-description',$displayname);
} }
$supported_components = array( $supported_components = array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VCALENDAR')), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VCALENDAR')),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VEVENT')),
); );
// outbox supports VFREEBUSY too, it is required from OS X iCal to autocomplete locations // outbox supports VFREEBUSY too, it is required from OS X iCal to autocomplete locations
if (substr($path,-8) == '/outbox/') if (substr($path,-8) == '/outbox/')
{ {
$supported_components[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VFREEBUSY')); $supported_components[] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VFREEBUSY'));
} }
$props['supported-calendar-component-set'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV, $props['supported-calendar-component-set'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,
'supported-calendar-component-set',$supported_components); 'supported-calendar-component-set',$supported_components);
// supported reports // supported reports
$props['supported-report-set'] = array( $props['supported-report-set'] = array(
'calendar-query' => HTTP_WebDAV_Server::mkprop('supported-report',array( 'calendar-query' => Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))))), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-query',''))))),
'calendar-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array( 'calendar-multiget' => Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget',''))))), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-multiget',''))))),
'free-busy-query' => HTTP_WebDAV_Server::mkprop('supported-report',array( 'free-busy-query' => Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'free-busy-query',''))))), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'free-busy-query',''))))),
); );
// rfc 6578 sync-collection report for everything but outbox // rfc 6578 sync-collection report for everything but outbox
// only if "delete-prevention" is switched on (deleted entries get marked deleted but not actualy deleted // only if "delete-prevention" is switched on (deleted entries get marked deleted but not actualy deleted
if (strpos($path, '/outbox/') === false && $GLOBALS['egw_info']['server']['calendar_delete_history']) if (strpos($path, '/outbox/') === false && $GLOBALS['egw_info']['server']['calendar_delete_history'])
{ {
$props['supported-report-set']['sync-collection'] = HTTP_WebDAV_Server::mkprop('supported-report',array( $props['supported-report-set']['sync-collection'] = Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop('sync-collection',''))))); Api\CalDAV::mkprop('sync-collection','')))));
} }
$props['supported-calendar-data'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-data',array( $props['supported-calendar-data'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'supported-calendar-data',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data', array('content-type' => 'text/calendar', 'version'=> '2.0')), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-data', array('content-type' => 'text/calendar', 'version'=> '2.0')),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data', array('content-type' => 'text/x-calendar', 'version'=> '1.0')))); Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-data', array('content-type' => 'text/x-calendar', 'version'=> '1.0'))));
// get timezone of calendar // get timezone of calendar
if ($this->groupdav->prop_requested('calendar-timezone')) if ($this->caldav->prop_requested('calendar-timezone'))
{ {
$props['calendar-timezone'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-timezone', $props['calendar-timezone'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-timezone',
calendar_timezones::user_timezone($user)); calendar_timezones::user_timezone($user));
} }
return $props; return $props;
@ -1594,7 +1596,7 @@ class calendar_groupdav extends groupdav_handler
foreach(explode(',', $pref) as $res_id) foreach(explode(',', $pref) as $res_id)
{ {
$is_location = $res == 'locations'; $is_location = $res == 'locations';
$shared['r'.$res_id] = str_replace('s/', '-', groupdav_principals::resource2name($res_id, $is_location)); $shared['r'.$res_id] = str_replace('s/', '-', Api\CalDAV\Principals::resource2name($res_id, $is_location));
} }
} }
} }
@ -1652,12 +1654,12 @@ class calendar_groupdav extends groupdav_handler
); );
// allow to subscribe to resources // allow to subscribe to resources
if ($GLOBALS['egw_info']['user']['apps']['resources'] && ($all_resources = groupdav_principals::get_resources())) if ($GLOBALS['egw_info']['user']['apps']['resources'] && ($all_resources = Api\CalDAV\Principals::get_resources()))
{ {
$resources = $locations = array(); $resources = $locations = array();
foreach($all_resources as $resource) foreach($all_resources as $resource)
{ {
if (groupdav_principals::resource_is_location($resource)) if (Api\CalDAV\Principals::resource_is_location($resource))
{ {
$locations[$resource['res_id']] = $resource['name']; $locations[$resource['res_id']] = $resource['name'];
} }

View File

@ -9,17 +9,17 @@
* *
* Otherwise authentication request will be send over and over again, as password is NOT available to PHP! * Otherwise authentication request will be send over and over again, as password is NOT available to PHP!
* *
* Using the PEAR HTTP/WebDAV/Server class (which need to be installed!)
*
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api * @package api
* @subpackage groupdav * @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
// switching off output compression for Lighttpd and HTTPS, as it makes problems with TB Lightning // switching off output compression for Lighttpd and HTTPS, as it makes problems with TB Lightning
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' && if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' &&
strpos($_SERVER['SERVER_SOFTWARE'],'lighttpd/1.4') === 0 && strpos($_SERVER['SERVER_SOFTWARE'],'lighttpd/1.4') === 0 &&
@ -48,6 +48,6 @@ $GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->read
$headertime = microtime(true); $headertime = microtime(true);
$groupdav = new groupdav(); $caldav = new Api\CalDAV();
$groupdav->ServeRequest(); $caldav->ServeRequest();
//error_log(sprintf('GroupDAV %s: status "%s", took %5.3f s'.($headertime?' (header include took %5.3f s)':''),$_SERVER['REQUEST_METHOD'].($_SERVER['REQUEST_METHOD']=='REPORT'?' '.$groupdav->propfind_options['root']['name']:'').' '.$_SERVER['PATH_INFO'],$groupdav->_http_status,microtime(true)-$starttime,$headertime-$starttime)); //error_log(sprintf('GroupDAV %s: status "%s", took %5.3f s'.($headertime?' (header include took %5.3f s)':''),$_SERVER['REQUEST_METHOD'].($_SERVER['REQUEST_METHOD']=='REPORT'?' '.$groupdav->propfind_options['root']['name']:'').' '.$_SERVER['PATH_INFO'],$groupdav->_http_status,microtime(true)-$starttime,$headertime-$starttime));

View File

@ -11,13 +11,15 @@
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* EGroupware: GroupDAV access: infolog handler * EGroupware: GroupDAV access: infolog handler
* *
* 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). * and our request-log (prefixed with "### " after request and response, like exceptions).
*/ */
class infolog_groupdav extends groupdav_handler class infolog_groupdav extends Api\CalDAV\Handler
{ {
/** /**
* bo class of the application * bo class of the application
@ -49,7 +51,7 @@ class infolog_groupdav extends groupdav_handler
/** /**
* Are we using info_id, info_uid or caldav_name for the path/url * Are we using info_id, info_uid or caldav_name for the path/url
* *
* Get's set in constructor to 'caldav_name' and groupdav_handler::$path_extension = ''! * Get's set in constructor to 'caldav_name' and self::$path_extension = ''!
*/ */
static $path_attr = 'info_id'; static $path_attr = 'info_id';
@ -57,11 +59,11 @@ class infolog_groupdav extends groupdav_handler
* Constructor * Constructor
* *
* @param string $app 'calendar', 'addressbook' or 'infolog' * @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 infolog_bo(); $this->bo = new infolog_bo();
$this->vCalendar = new Horde_Icalendar; $this->vCalendar = new Horde_Icalendar;
@ -70,7 +72,7 @@ class infolog_groupdav extends groupdav_handler
if (version_compare($GLOBALS['egw_info']['apps']['calendar']['version'], '1.9.002', '>=')) if (version_compare($GLOBALS['egw_info']['apps']['calendar']['version'], '1.9.002', '>='))
{ {
self::$path_attr = 'caldav_name'; self::$path_attr = 'caldav_name';
groupdav_handler::$path_extension = ''; self::$path_extension = '';
} }
} }
@ -91,7 +93,7 @@ class infolog_groupdav extends groupdav_handler
if (!is_array($info)) $info = $this->bo->read($info); if (!is_array($info)) $info = $this->bo->read($info);
$name = $info[self::$path_attr]; $name = $info[self::$path_attr];
} }
return $name.groupdav_handler::$path_extension; return $name.self::$path_extension;
} }
/** /**
@ -166,7 +168,7 @@ class infolog_groupdav extends groupdav_handler
// check if we have to return the full calendar data or just the etag's // check if we have to return the full calendar data or just the etag's
if (!($filter['calendar_data'] = $options['props'] == 'all' && if (!($filter['calendar_data'] = $options['props'] == 'all' &&
$options['root']['ns'] == groupdav::CALDAV) && is_array($options['props'])) $options['root']['ns'] == Api\CalDAV::CALDAV) && is_array($options['props']))
{ {
foreach($options['props'] as $prop) foreach($options['props'] as $prop)
{ {
@ -208,7 +210,7 @@ class infolog_groupdav extends groupdav_handler
else else
{ {
// return iterator, calling ourself to return result in chunks // return iterator, calling ourself to return result in chunks
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']); $files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
} }
return true; return true;
} }
@ -295,7 +297,7 @@ class infolog_groupdav extends groupdav_handler
{ {
$content = $handler->exportVTODO($task, '2.0', null); // no METHOD:PUBLISH for CalDAV $content = $handler->exportVTODO($task, '2.0', null); // no METHOD:PUBLISH for CalDAV
$props['getcontentlength'] = bytes($content); $props['getcontentlength'] = bytes($content);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content); $props[] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-data',$content);
} }
$files[] = $this->add_resource($path, $task, $props); $files[] = $this->add_resource($path, $task, $props);
} }
@ -317,7 +319,7 @@ class infolog_groupdav extends groupdav_handler
// hack to support limit with sync-collection report: tasks are returned in modified ASC order (oldest first) // hack to support limit with sync-collection report: tasks are returned in modified ASC order (oldest first)
// if limit is smaller then full result, return modified-1 as sync-token, so client requests next chunk incl. modified // if limit is smaller then full result, return modified-1 as sync-token, so client requests next chunk incl. modified
// (which might contain further entries with identical modification time) // (which might contain further entries with identical modification time)
if ($start[0] == 0 && $start[1] != groupdav_propfind_iterator::CHUNK_SIZE && $this->bo->total > $start[1]) if ($start[0] == 0 && $start[1] != Api\CalDAV\PropfindIterator::CHUNK_SIZE && $this->bo->total > $start[1])
{ {
--$this->sync_collection_token; --$this->sync_collection_token;
} }
@ -414,11 +416,11 @@ class infolog_groupdav extends groupdav_handler
case 'sync-level': case 'sync-level':
if ($option['data'] != '1') 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; break;
default: 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; break;
} }
} }
@ -429,8 +431,8 @@ class infolog_groupdav extends groupdav_handler
$ids = array(); $ids = array();
if ($id) if ($id)
{ {
$cal_filters[self::$path_attr] = groupdav_handler::$path_extension ? $cal_filters[self::$path_attr] = self::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id; basename($id,self::$path_extension) : $id;
} }
else // fetch all given url's else // fetch all given url's
{ {
@ -441,8 +443,8 @@ class infolog_groupdav extends groupdav_handler
$parts = explode('/',$option['data']); $parts = explode('/',$option['data']);
if (($id = basename(urldecode(array_pop($parts))))) if (($id = basename(urldecode(array_pop($parts)))))
{ {
$cal_filters[self::$path_attr][] = groupdav_handler::$path_extension ? $cal_filters[self::$path_attr][] = self::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id; basename($id,self::$path_extension) : $id;
} }
} }
} }
@ -474,7 +476,7 @@ class infolog_groupdav extends groupdav_handler
} }
elseif (empty($attrs['start'])) elseif (empty($attrs['start']))
{ {
$this->groupdav->log(__METHOD__.'('.array2string($attrs).') minimum one of start or end is required!'); $this->caldav->log(__METHOD__.'('.array2string($attrs).') minimum one of start or end is required!');
return '1'; // to not give sql error, but simply not filter out anything return '1'; // to not give sql error, but simply not filter out anything
} }
// we dont need to care for DURATION line in rfc4791#section-9.9, as we always put that in DUE/info_enddate // we dont need to care for DURATION line in rfc4791#section-9.9, as we always put that in DUE/info_enddate
@ -784,33 +786,33 @@ class infolog_groupdav extends groupdav_handler
// calendar description // calendar description
$displayname = translation::convert(lang('Tasks of'),translation::charset(),'utf-8').' '.$displayname; $displayname = translation::convert(lang('Tasks of'),translation::charset(),'utf-8').' '.$displayname;
$props['calendar-description'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-description',$displayname); $props['calendar-description'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-description',$displayname);
// supported components, currently only VEVENT // supported components, currently only VEVENT
$props['supported-calendar-component-set'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array( $props['supported-calendar-component-set'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'supported-calendar-component-set',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VCALENDAR')), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VCALENDAR')),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VTODO')),
)); ));
// supported reports // supported reports
$props['supported-report-set'] = array( $props['supported-report-set'] = array(
'calendar-query' => HTTP_WebDAV_Server::mkprop('supported-report',array( 'calendar-query' => Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))))), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-query',''))))),
'calendar-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array( 'calendar-multiget' => Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget',''))))), Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-multiget',''))))),
); );
// only advertice rfc 6578 sync-collection report, if "delete-prevention" is switched on (deleted entries get marked deleted but not actualy deleted // only advertice rfc 6578 sync-collection report, if "delete-prevention" is switched on (deleted entries get marked deleted but not actualy deleted
$config = config::read('infolog'); $config = config::read('infolog');
if ($config['history']) if ($config['history'])
{ {
$props['supported-report-set']['sync-collection'] = HTTP_WebDAV_Server::mkprop('supported-report',array( $props['supported-report-set']['sync-collection'] = Api\CalDAV::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array( Api\CalDAV::mkprop('report',array(
HTTP_WebDAV_Server::mkprop('sync-collection',''))))); Api\CalDAV::mkprop('sync-collection','')))));
} }
// get timezone of calendar // get timezone of calendar
if ($this->groupdav->prop_requested('calendar-timezone')) if ($this->caldav->prop_requested('calendar-timezone'))
{ {
$props['calendar-timezone'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-timezone', $props['calendar-timezone'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-timezone',
calendar_timezones::user_timezone($user)); calendar_timezones::user_timezone($user));
} }
return $props; return $props;

View File

@ -115,28 +115,25 @@ class common
} }
/** /**
* generate a unique id, which can be used for syncronisation * generate a unique id, which can be used for syncronisation
* *
* @param string $_appName the appname * @param string $_appName the appname
* @param string $_eventID the id of the content * @param string $_eventID the id of the content
* @return string the unique id * @deprecated use Api\CalDAV::generate_uid($_appName, $_eventID)
*/ * @return string the unique id
*/
static function generate_uid($_appName, $_eventID) static function generate_uid($_appName, $_eventID)
{ {
if(empty($_appName) || empty($_eventID)) return false; return Api\CalDAV::generate_uid($_appName, $_eventID);
// not used: $suffix = $GLOBALS['egw_info']['server']['hostname'] ? $GLOBALS['egw_info']['server']['hostname'] : 'local';
$prefix = $_appName.'-'.$_eventID.'-'.$GLOBALS['egw_info']['server']['install_id'];
return $prefix;
} }
/** /**
* get the local content id from a global UID * get the local content id from a global UID
* *
* @param sting $_globalUid the global UID * @param sting $_globalUid the global UID
* @return int local egw content id * @deprecated dont use, as only EGroupware interal uids are reversable
*/ * @return int local egw content id
*/
static function get_egwId($_globalUid) static function get_egwId($_globalUid)
{ {
if(empty($_globalUid)) return false; if(empty($_globalUid)) return false;

View File

@ -4,13 +4,15 @@
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker@outdoor-training.de> * @author Ralf Becker <RalfBecker@outdoor-training.de>
* @copyright 2012 by RalfBecker@outdoor-training.de * @copyright 2012-16 by RalfBecker@outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate * @package api
* @subpackage api * @subpackage json
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api\Json\Tail;
/** /**
* Ajax log file viewer (tail -f) * Ajax log file viewer (tail -f)
* *
@ -26,186 +28,7 @@
* *
* Strongly prefered for security reasons is to use a path relative to EGroupware's files_dir, * Strongly prefered for security reasons is to use a path relative to EGroupware's files_dir,
* eg. new egw_tail('groupdav/somelog')! * eg. new egw_tail('groupdav/somelog')!
*
* @deprecated use Api\Json\Tail
*/ */
class egw_tail class egw_tail extends Tail {}
{
/**
* Maximum size of single ajax request
*
* Currently also maximum size / 4 of displayed logfile content!
*/
const MAX_CHUNK_SIZE = 8192;
/**
* Contains allowed filenames to display, we can NOT allow to display arbitrary files!
*
* @param array
*/
protected $filenames;
/**
* Filename class is instanciated to view, set by constructor
*
* @param string
*/
protected $filename;
/**
* Methods allowed to call via menuaction
*
* @var array
*/
public $public_functions = array(
'download' => true,
);
/**
* Constructor
*
* @param string $filename=null if not starting with as slash relative to EGw files dir (this is strongly prefered for security reasons)
*/
public function __construct($filename=null)
{
$this->filenames =& egw_cache::getSession('phpgwapi', __CLASS__);
if ($filename)
{
$this->filename = $filename;
if (!$this->filenames || !in_array($filename,$this->filenames)) $this->filenames[] = $filename;
}
}
/**
* Ajax callback to load next chunk of log-file
*
* @param string $filename
* @param int $start=0 last position in log-file
* @throws egw_exception_wrong_parameter
*/
public function ajax_chunk($filename,$start=0)
{
if (!in_array($filename,$this->filenames))
{
throw new egw_exception_wrong_parameter("Not allowed to view '$filename'!");
}
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
if (file_exists($filename))
{
$size = filesize($filename);
if (!$start || $start < 0 || $start > $size || $size-$start > 4*self::MAX_CHUNK_SIZE)
{
$start = $size - 4*self::MAX_CHUNK_SIZE;
if ($start < 0) $start = 0;
}
$size = egw_vfs::hsize($size);
$content = file_get_contents($filename, false, null, $start, self::MAX_CHUNK_SIZE);
$length = bytes($content);
$writable = is_writable($filename) || is_writable(dirname($filename));
}
else
{
$start = $length = 0;
$content = '';
$writable = $size = false;
}
$response = egw_json_response::get();
$response->data(array( // send all responses as data
'size' => $size,
'writable' => $writable,
'next' => $start + $length,
'length' => $length,
'content' => $content,
));
}
/**
* Ajax callback to delete log-file
*
* @param string $filename
* @param boolean $truncate=false true: truncate file, false: delete file
* @throws egw_exception_wrong_parameter
*/
public function ajax_delete($filename,$truncate=false)
{
if (!in_array($filename,$this->filenames))
{
throw new egw_exception_wrong_parameter("Not allowed to view '$filename'!");
}
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
if ($truncate)
{
file_put_contents($filename, '');
}
else
{
unlink($filename);
}
}
/**
* Return html & javascript for logviewer
*
* @param string $header=null default $this->filename
* @return string
* @throws egw_exception_wrong_parameter
*/
public function show($header=null)
{
if (!isset($this->filename))
{
throw new egw_exception_wrong_parameter("Must be instanciated with filename!");
}
if (is_null($header)) $header = $this->filename;
return '
<p style="float: left; margin: 5px"><b>'.htmlspecialchars($header).'</b></p>
<div style="float: right; margin: 2px; margin-right: 5px">
'.html::form(
html::input('clear_log',lang('Clear window'),'button','id="clear_log"')."\n".
html::input('delete_log',lang('Delete file'),'button','id="purge_log"')."\n".
html::input('empty_log',lang('Empty file'),'button','id="empty_log"')."\n".
html::input('download_log',lang('Download'),'submit','id="download_log"'),
'','/index.php',array(
'menuaction' => 'phpgwapi.egw_tail.download',
'filename' => $this->filename,
)).'
</div>
<pre class="tail" id="log" data-filename="'.$this->filename.'" style="clear: both; width: 99.5%; border: 2px groove silver; margin-bottom: 0; overflow: auto;"></pre>';
}
/**
* Download a file specified per GET parameter (must be in $this->filesnames!)
*
* @throws egw_exception_wrong_parameter
*/
public function download()
{
$filename = $_GET['filename'];
if (!in_array($filename,$this->filenames))
{
throw new egw_exception_wrong_parameter("Not allowed to download '$filename'!");
}
html::content_header(basename($filename),'text/plain');
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
for($n=ob_get_level(); $n > 0; --$n) ob_end_clean(); // stop all output buffering, to NOT run into memory_limit
readfile($filename);
common::egw_exit();
}
}
// some testcode, if this file is called via it's URL (you need to uncomment and adapt filename!)
/*if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__)
{
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => 'admin',
'nonavbar' => true,
),
);
include_once '../../header.inc.php';
$error_log = new egw_tail('/opt/local/apache2/logs/error_log');
echo $error_log->show();
}*/

View File

@ -1127,6 +1127,10 @@ function ExecMethod($method, $functionparam = '_UNDEF_', $loglevel = 3, $classpa
{ {
$GLOBALS[$classname] = CreateObject($appname.'.'.$classname, $classparams); $GLOBALS[$classname] = CreateObject($appname.'.'.$classname, $classparams);
} }
elseif (class_exists($classname))
{
$GLOBALS[$classname] = new $classname;
}
else else
{ {
$GLOBALS[$classname] = CreateObject($appname.'.'.$classname); $GLOBALS[$classname] = CreateObject($appname.'.'.$classname);

View File

@ -7,7 +7,7 @@
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Hadi Nategh (as AT stylite.de) * @author Hadi Nategh (as AT stylite.de)
* @author Ralf Becker <RalfBecker@outdoor-training.de> * @author Ralf Becker <RalfBecker@outdoor-training.de>
* @version $Id$ * @version $Id$
*/ */
@ -27,15 +27,15 @@ jQuery(function()
{ {
if (buttonId != "clear_log") if (buttonId != "clear_log")
{ {
var ajax = new egw_json_request("home.egw_tail.ajax_delete",[filename,buttonId=="empty_log"]); egw.json("api.EGroupware\\Api\\Json\\Tail.ajax_delete",[filename,buttonId=="empty_log"])
ajax.sendRequest(true); .sendRequest(true);
} }
$j("#log").text(""); $j("#log").text("");
} }
function refresh_log() function refresh_log()
{ {
var ajax = new egw_json_request("home.egw_tail.ajax_chunk",[filename,log_tail_start]); egw.json("api.EGroupware\\Api\\Json\\Tail.ajax_chunk",[filename,log_tail_start], function(_data)
ajax.sendRequest(true,function(_data) { {
if (_data.length) { if (_data.length) {
log_tail_start = _data.next; log_tail_start = _data.next;
var log = $j("#log").append(_data.content.replace(/</g,"&lt;")); var log = $j("#log").append(_data.content.replace(/</g,"&lt;"));
@ -60,7 +60,7 @@ jQuery(function()
$j("#empty_log").show(); $j("#empty_log").show();
} }
window.setTimeout(refresh_log,_data.length?200:2000); window.setTimeout(refresh_log,_data.length?200:2000);
}); }).sendRequest(true);
} }
function resize_log() function resize_log()
{ {

View File

@ -70,7 +70,7 @@ $setup_info['groupdav']['author'] = $setup_info['groupdav']['maintainer'] = arra
'email' => 'RalfBecker@outdoor-training.de' 'email' => 'RalfBecker@outdoor-training.de'
); );
$setup_info['groupdav']['license'] = 'GPL'; $setup_info['groupdav']['license'] = 'GPL';
$setup_info['groupdav']['hooks']['preferences'] = 'groupdav_hooks::menus'; $setup_info['groupdav']['hooks']['preferences'] = 'EGroupware\\Api\\CalDAV\\Hooks::menus';
$setup_info['groupdav']['hooks']['settings'] = 'groupdav_hooks::settings'; $setup_info['groupdav']['hooks']['settings'] = 'EGroupware\\Api\\CalDAV\\Hooks::settings';