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
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package addressbook
* @subpackage groupdav
* @subpackage carddav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
@ -14,20 +14,20 @@
use EGroupware\Api;
/**
* EGroupware: GroupDAV access: addressbook handler
* CalDAV/CardDAV/GroupDAV access: Addressbook handler
*
* Propfind now uses a groupdav_propfind_iterator with a callback to query huge addressbooks in chunk,
* Propfind now uses a Api\CalDAV\PropfindIterator with a callback to query huge addressbooks in chunk,
* without getting into problems with memory_limit.
*
* Permanent error_log() calls should use $this->groupdav->log($str) instead, to be send to PHP error_log()
* Permanent error_log() calls should use $this->caldav->log($str) instead, to be send to PHP error_log()
* and our request-log (prefixed with "### " after request and response, like exceptions).
*/
class addressbook_groupdav extends groupdav_handler
class addressbook_groupdav extends Api\CalDAV\Handler
{
/**
* bo class of the application
*
* @var addressbook_bo
* @var Api\Contacts
*/
var $bo;
@ -63,13 +63,13 @@ class addressbook_groupdav extends groupdav_handler
* Constructor
*
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param groupdav $groupdav calling class
* @param Api\CalDAV $caldav calling class
*/
function __construct($app, groupdav $groupdav)
function __construct($app, Api\CalDAV $caldav)
{
parent::__construct($app, $groupdav);
parent::__construct($app, $caldav);
$this->bo = new addressbook_bo();
$this->bo = new Api\Contacts();
// since 1.9.007 we allow clients to specify the URL when creating a new contact, as specified by CardDAV
// LDAP does NOT have a carddav_name attribute --> stick with id mapped to LDAP attribute uid
@ -77,12 +77,12 @@ class addressbook_groupdav extends groupdav_handler
$this->bo->contact_repository != 'sql' ||
$this->bo->account_repository != 'sql' && strpos($_SERVER['REQUEST_URI'].'/','/addressbook-accounts/') !== false)
{
groupdav_handler::$path_extension = '.vcf';
self::$path_extension = '.vcf';
}
else
{
groupdav_handler::$path_attr = 'carddav_name';
groupdav_handler::$path_extension = '';
self::$path_attr = 'carddav_name';
self::$path_extension = '';
}
if ($this->debug) error_log(__METHOD__."() contact_repository={$this->bo->contact_repository}, account_repository={$this->bo->account_repository}, REQUEST_URI=$_SERVER[REQUEST_URI] --> path_attr=".self::$path_attr.", path_extension=".self::$path_extension);
@ -136,7 +136,7 @@ class addressbook_groupdav extends groupdav_handler
// check if we have to return the full contact data or just the etag's
if (!($filter['address_data'] = $options['props'] == 'all' &&
$options['root']['ns'] == groupdav::CARDDAV) && is_array($options['props']))
$options['root']['ns'] == Api\CalDAV::CARDDAV) && is_array($options['props']))
{
foreach($options['props'] as $prop)
{
@ -177,13 +177,13 @@ class addressbook_groupdav extends groupdav_handler
else
{
// return iterator, calling ourself to return result in chunks
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
$files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
}
return true;
}
/**
* Callback for profind interator
* Callback for profind iterator
*
* @param string $path
* @param array& $filter
@ -243,7 +243,7 @@ class addressbook_groupdav extends groupdav_handler
continue;
}
$props = array(
'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', 'text/vcard'),
'getlastmodified' => $contact['modified'],
'displayname' => $contact['n_fn'],
);
@ -251,7 +251,7 @@ class addressbook_groupdav extends groupdav_handler
{
$content = $handler->getVCard($contact['id'],$this->charset,false);
$props['getcontentlength'] = bytes($content);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
$props[] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'address-data',$content,true);
}
$files[] = $this->add_resource($path, $contact, $props);
}
@ -271,11 +271,11 @@ class addressbook_groupdav extends groupdav_handler
$accounts_filter = $filter_in;
$accounts_filter['owner'] = '0';
if ($sync_collection_report) $token_was = $this->sync_collection_token;
groupdav_handler::$path_attr = 'id';
groupdav_handler::$path_extension = '.vcf';
self::$path_attr = 'id';
self::$path_extension = '.vcf';
$files = array_merge($files, $this->propfind_callback($path, $accounts_filter, false, false));
groupdav_handler::$path_attr = 'carddav_name';
groupdav_handler::$path_extension = '';
self::$path_attr = 'carddav_name';
self::$path_extension = '';
if ($sync_collection_report && $token_was > $this->sync_collection_token)
{
$this->sync_collection_token = $token_was;
@ -310,7 +310,7 @@ class addressbook_groupdav extends groupdav_handler
$etag .= ':'.implode('-',$filter['owner']);
}
$props = array(
'getcontenttype' => HTTP_WebDAV_Server::mkprop('getcontenttype', 'text/vcard'),
'getcontenttype' => Api\CalDAV::mkprop('getcontenttype', 'text/vcard'),
'getlastmodified' => egw_time::to($list['list_modified'],'ts'),
'displayname' => $list['list_name'],
'getetag' => '"'.$etag.'"',
@ -319,7 +319,7 @@ class addressbook_groupdav extends groupdav_handler
{
$content = $handler->getGroupVCard($list);
$props['getcontentlength'] = bytes($content);
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
$props[] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'address-data',$content,true);
}
$files[] = $this->add_resource($path, $list, $props);
@ -391,7 +391,7 @@ class addressbook_groupdav extends groupdav_handler
switch((string)$filter['name'])
{
case 'param-filter':
$this->groupdav->log(__METHOD__."(...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!");
$this->caldav->log(__METHOD__."(...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!");
break;
case 'prop-filter': // can be multiple prop-filter, see example
if ($matches) $prop_filters[] = implode($prop_test=='allof'?' AND ':' OR ',$matches);
@ -456,7 +456,7 @@ class addressbook_groupdav extends groupdav_handler
}
// fall through
default:
$this->groupdav->log(__METHOD__."(".array2string($options).",,$id) unknown filter=".array2string($filter).' --> ignored');
$this->caldav->log(__METHOD__."(".array2string($options).",,$id) unknown filter=".array2string($filter).' --> ignored');
break;
}
}
@ -498,11 +498,11 @@ class addressbook_groupdav extends groupdav_handler
case 'sync-level':
if ($option['data'] != '1')
{
$this->groupdav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other']));
$this->caldav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other']));
}
break;
default:
$this->groupdav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other']));
$this->caldav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other']));
break;
}
}
@ -517,7 +517,7 @@ class addressbook_groupdav extends groupdav_handler
$parts = explode('/',$option['data']);
if (($id = urldecode(array_pop($parts))))
{
$ids[] = groupdav_handler::$path_extension ? basename($id,groupdav_handler::$path_extension) : $id;
$ids[] = self::$path_extension ? basename($id,self::$path_extension) : $id;
}
}
}
@ -526,7 +526,7 @@ class addressbook_groupdav extends groupdav_handler
}
elseif ($id)
{
$filters[self::$path_attr] = groupdav_handler::$path_extension ? basename($id,groupdav_handler::$path_extension) : $id;
$filters[self::$path_attr] = self::$path_extension ? basename($id,self::$path_extension) : $id;
}
//error_log(__METHOD__."() options[other]=".array2string($options['other'])." --> filters=".array2string($filters));
return true;
@ -848,27 +848,27 @@ class addressbook_groupdav extends groupdav_handler
if (!isset($props['addressbook-description']))
{
// default addressbook description: can be overwritten via PROPPATCH, in which case it's already set
$props['addressbook-description'] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-description',$props['displayname']);
$props['addressbook-description'] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-description',$props['displayname']);
}
// setting an max image size, so iOS scales the images before transmitting them
// we currently scale down to width of 240px, which tests shown to be ~20k
$props['max-image-size'] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'max-image-size',24*1024);
$props['max-image-size'] = Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'max-image-size',24*1024);
// supported reports (required property for CardDAV)
$props['supported-report-set'] = array(
'addressbook-query' => HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-query',''))))),
'addressbook-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-multiget',''))))),
'addressbook-query' => Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-query',''))))),
'addressbook-multiget' => Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-multiget',''))))),
);
// only advertice rfc 6578 sync-collection report, if "delete-prevention" is switched on (deleted entries get marked deleted but not actualy deleted
if ($GLOBALS['egw_info']['server']['history'])
{
$props['supported-report-set']['sync-collection'] = HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop('sync-collection','')))));
$props['supported-report-set']['sync-collection'] = Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop('sync-collection','')))));
}
return $props;
}

View File

@ -5,13 +5,21 @@
* @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage groupdav
* @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
*/
require_once(EGW_INCLUDE_ROOT.'/api/src/WebDAV/Server.php');
namespace EGroupware\Api;
use EGroupware\Api\CalDAV\Handler;
use EGroupware\Api\CalDAV\Principals;
// explicit import non-namespaced classes
require_once(__DIR__.'/WebDAV/Server.php');
use HTTP_WebDAV_Server;
use calendar_hooks;
/**
* EGroupware: GroupDAV access
@ -54,7 +62,7 @@ require_once(EGW_INCLUDE_ROOT.'/api/src/WebDAV/Server.php');
* @link http://carddav.calconnect.org/ CardDAV resources
* @link http://calendarserver.org/ Apple calendar and contacts server
*/
class groupdav extends HTTP_WebDAV_Server
class CalDAV extends HTTP_WebDAV_Server
{
/**
* DAV namespace
@ -141,7 +149,7 @@ class groupdav extends HTTP_WebDAV_Server
/**
* Instance of our application specific handler
*
* @var groupdav_handler
* @var Handler
*/
var $handler;
/**
@ -228,7 +236,7 @@ class groupdav extends HTTP_WebDAV_Server
$this->crrnd = false;
// identify clients, which do NOT support path AND full url in <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)
$this->client_require_href_as_url = true;
@ -262,7 +270,7 @@ class groupdav extends HTTP_WebDAV_Server
}*/
//error_log($_SERVER['REQUEST_URI']." --> ".$this->_SERVER['REQUEST_URI']);
$this->egw_charset = translation::charset();
$this->egw_charset = Translation::charset();
if (strpos($this->base_uri, 'http') === 0)
{
$this->current_user_principal = $this->_slashify($this->base_uri);
@ -288,13 +296,13 @@ class groupdav extends HTTP_WebDAV_Server
* get the handler for $app
*
* @param string $app
* @return groupdav_handler
* @return Handler
*/
function app_handler($app)
{
if (isset($this->root[$app]['app'])) $app = $this->root[$app]['app'];
return groupdav_handler::app_handler($app,$this);
return Handler::app_handler($app,$this);
}
/**
@ -632,7 +640,7 @@ class groupdav extends HTTP_WebDAV_Server
$displayname = 'EGroupware (Cal|Card|Group)DAV server';
}
$displayname = translation::convert($displayname, translation::charset(),'utf-8');
$displayname = Translation::convert($displayname, Translation::charset(),'utf-8');
// self url
$props = array(
'displayname' => $displayname,
@ -710,12 +718,12 @@ class groupdav extends HTTP_WebDAV_Server
}
if ($depth)
{
foreach(groupdav_principals::get_resources() as $resource)
foreach(Principals::get_resources() as $resource)
{
if ($is_location == groupdav_principals::resource_is_location($resource))
if ($is_location == Principals::resource_is_location($resource))
{
$files['files'][] = $this->add_app('calendar', false, 'r'.$resource['res_id'],
'/'.groupdav_principals::resource2name($resource, $is_location).'/');
'/'.Principals::resource2name($resource, $is_location).'/');
}
}
}
@ -800,11 +808,11 @@ class groupdav extends HTTP_WebDAV_Server
{
if ($this->debug) error_log(__METHOD__."(app='$app', no_extra_types=$no_extra_types, user='$user', path='$path')");
$user_preferences = $GLOBALS['egw_info']['user']['preferences'];
if (is_string($user) && $user[0] == 'r' && ($resource = groupdav_principals::read_resource(substr($user, 1))))
if (is_string($user) && $user[0] == 'r' && ($resource = Principals::read_resource(substr($user, 1))))
{
$is_location = groupdav_principals::resource_is_location($resource);
$is_location = Principals::resource_is_location($resource);
$displayname = null;
list($principalType, $account_lid) = explode('/', groupdav_principals::resource2name($resource, $is_location, $displayname));
list($principalType, $account_lid) = explode('/', Principals::resource2name($resource, $is_location, $displayname));
}
elseif ($user)
{
@ -850,7 +858,7 @@ class groupdav extends HTTP_WebDAV_Server
}
// fall through
default:
$props['displayname'] = translation::convert(lang($app).' '.$displayname, $this->egw_charset, 'utf-8');
$props['displayname'] = Translation::convert(lang($app).' '.$displayname, $this->egw_charset, 'utf-8');
}
// rfc 5995 (Use POST to add members to WebDAV collections): we use collection path with add-member query param
@ -926,7 +934,7 @@ class groupdav extends HTTP_WebDAV_Server
if (method_exists($handler,'getctag') && $this->prop_requested('getctag') === true)
{
$props['getctag'] = self::mkprop(
groupdav::CALENDARSERVER,'getctag',$handler->getctag($path,$user));
self::CALENDARSERVER,'getctag',$handler->getctag($path,$user));
}
// add sync-token url if handler supports sync-collection report
if (isset($props['supported-report-set']['sync-collection']) && $this->prop_requested('sync-token') === true)
@ -1006,7 +1014,7 @@ class groupdav extends HTTP_WebDAV_Server
{
return $ret; // no collection
}
header('Content-type: text/html; charset='.translation::charset());
header('Content-type: text/html; charset='.Translation::charset());
echo "<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<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)
{
$path .= ($n != 1 ? '/' : '').$name;
echo html::a_href(htmlspecialchars($name.'/'),$path);
echo Html::a_href(htmlspecialchars($name.'/'),$path);
}
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>".
html::a_href(htmlspecialchars($name),'/groupdav.php'.strtr($file['path'], array(
Html::a_href(htmlspecialchars($name),'/groupdav.php'.strtr($file['path'], array(
'%' => '%25',
'#' => '%23',
'?' => '%3F',
@ -1107,7 +1115,7 @@ class groupdav extends HTTP_WebDAV_Server
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")
// 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
return $this->PUT($options);
@ -1251,7 +1259,7 @@ class groupdav extends HTTP_WebDAV_Server
*
* @param array &$options
* @param string|int $id
* @param groupdav_handler $handler
* @param Handler $handler
* @param string $action 'attachment-add', 'attachment-update', 'attachment-remove'
* @return string http status
*
@ -1259,7 +1267,7 @@ class groupdav extends HTTP_WebDAV_Server
* @todo managed-id does NOT change on update
* @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));
$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";
}
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';
}
@ -1282,7 +1290,7 @@ class groupdav extends HTTP_WebDAV_Server
substr($this->_SERVER['HTTP_CONTENT_DISPOSITION'], 0, 10) === 'attachment' &&
preg_match('/filename="?([^";]+)/', $this->_SERVER['HTTP_CONTENT_DISPOSITION'], $matches))
{
$filename = egw_vfs::basename($matches[1]);
$filename = Vfs::basename($matches[1]);
}
$path = null;
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 (!egw_vfs::unlink($path))
if (!Vfs::unlink($path))
{
self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id-parameter', ''));
return '403 Forbidden';
@ -1320,16 +1328,16 @@ class groupdav extends HTTP_WebDAV_Server
if (isset($this->_SERVER['HTTP_CONTENT_DISPOSITION']) &&
substr($this->_SERVER['HTTP_CONTENT_DISPOSITION'], 0, 10) === 'attachment' &&
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;
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', ''));
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['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).')');
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");
return; // no rights --> nothing to do
@ -1386,7 +1394,7 @@ class groupdav extends HTTP_WebDAV_Server
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;
foreach($attach as $key => $attr)
@ -1400,8 +1408,8 @@ class groupdav extends HTTP_WebDAV_Server
}
if (!$found)
{
$ok = egw_vfs::unlink($path);
error_log(__METHOD__."('$app', $id, ...) egw_vfs::unlink('$path') returned ".array2string($ok));
$ok = Vfs::unlink($path);
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']))
{
// 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));
self::xml_error(self::mkprop(self::CALDAV, 'valid-managed-id', ''));
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));
continue;
}
// 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
egw_vfs::unlink($link); // symlink will fail, if $link exists
if (Vfs::readlink($link) === $path) continue; // no need to recreate identical link
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!");
}
@ -1465,15 +1473,15 @@ class groupdav extends HTTP_WebDAV_Server
*/
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
$ext = !empty($mime) ? mime_magic::mime2ext($mime) : '';
$ext = !empty($mime) ? MimeMagic::mime2ext($mime) : '';
$matches = null;
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);
$ext = '.'.array_pop($parts);
@ -1485,18 +1493,18 @@ class groupdav extends HTTP_WebDAV_Server
}
for($i = 1; $i < 100; ++$i)
{
$path = egw_link::vfs_path($app, $id, $filename.($i > 1 ? '-'.$i : '').$ext, true);
if (!egw_vfs::stat($path)) break;
$path = Link::vfs_path($app, $id, $filename.($i > 1 ? '-'.$i : '').$ext, true);
if (!Vfs::stat($path)) break;
}
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!");
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'];
}
}
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)
{
foreach(egw_vfs::find(egw_link::vfs_path($app, $id, '', true), array(
foreach(Vfs::find(Link::vfs_path($app, $id, '', true), array(
'type' => 'F',
'need_mime' => true,
), true) as $path => $stat)
{
// 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
if (substr($target, 0, 6) == '/apps/')
@ -1547,10 +1555,10 @@ class groupdav extends HTTP_WebDAV_Server
}
$attributes['ATTACH'][] = self::path2location($path);
$parameters['ATTACH'][] = array(
'MANAGED-ID' => groupdav::path2managed_id($path),
'MANAGED-ID' => self::path2managed_id($path),
'FMTTYPE' => $stat['mime'],
'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
// (works around events synced before without ATTACH attributes)
@ -1581,7 +1589,7 @@ class groupdav extends HTTP_WebDAV_Server
{
$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;
}
@ -1684,13 +1692,16 @@ class groupdav extends HTTP_WebDAV_Server
{
$GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->save_repository();
// 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);
if (in_array($name, array('default-alarm-vevent-date', 'default-alarm-vevent-datetime')))
foreach($need_save as $name)
{
calendar_hooks::sync_default_alarms();
break;
list($name) = explode(':', $name);
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)
{
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';
}
@ -1816,7 +1827,7 @@ class groupdav extends HTTP_WebDAV_Server
{
$id = $app = $user = null;
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");
@ -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
// 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
{
return $ret ? '200 OK' : '409 Conflict';
@ -1850,10 +1861,10 @@ class groupdav extends HTTP_WebDAV_Server
{
$id = $app = $user = null;
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");
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;
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];
array_shift($parts);
$res_id = (int)array_shift($parts);
if (!groupdav_principals::read_resource($res_id))
if (!Principals::read_resource($res_id))
{
return false;
}
@ -1964,7 +1975,7 @@ class groupdav extends HTTP_WebDAV_Server
}
elseif($app == 'resource' || $app == 'location')
{
if (!groupdav_principals::read_resource($res_id = (int)$username))
if (!Principals::read_resource($res_id = (int)$username))
{
return false;
}
@ -2127,7 +2138,7 @@ class groupdav extends HTTP_WebDAV_Server
{
header('Content-type: application/xml; charset=utf-8');
$xml = new XMLWriter;
$xml = new \XMLWriter;
$xml->openMemory();
$xml->setIndent(true);
$xml->startDocument('1.0', 'utf-8');
@ -2148,10 +2159,10 @@ class groupdav extends HTTP_WebDAV_Server
/**
* 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
*/
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 (isset($props['name'])) $props = array($props);
@ -2202,9 +2213,9 @@ class groupdav extends HTTP_WebDAV_Server
*
* 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
$headline = null;
@ -2229,10 +2240,20 @@ class groupdav extends HTTP_WebDAV_Server
self::$instance->log_request();
}
}
if (is_object($GLOBALS['egw']))
{
common::egw_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
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage groupdav
* @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;
use EGroupware\Api;
/**
* 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).
*
* @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
@ -39,13 +43,13 @@ abstract class groupdav_handler
/**
* Reference to the accounts class
*
* @var accounts
* @var Api\Accounts
*/
var $accounts;
/**
* Reference to the ACL class
*
* @var acl
* @var Api\Acl
*/
var $acl;
/**
@ -65,13 +69,13 @@ abstract class groupdav_handler
*/
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
*/
@ -114,18 +118,18 @@ abstract class groupdav_handler
* Constructor
*
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param groupdav $groupdav calling class
* @param Api\CalDAV $caldav calling class
*/
function __construct($app, groupdav $groupdav)
function __construct($app, Api\CalDAV $caldav)
{
$this->app = $app;
if (!is_null($groupdav->debug)) $this->debug = $groupdav->debug;
$this->base_uri = $groupdav->base_uri;
$this->groupdav = $groupdav;
if (!is_null($caldav->debug)) $this->debug = $caldav->debug;
$this->base_uri = $caldav->base_uri;
$this->caldav = $caldav;
$this->agent = self::get_agent();
$this->egw_charset = translation::charset();
$this->egw_charset = Api\Translation::charset();
$this->accounts = $GLOBALS['egw']->accounts;
$this->acl = $GLOBALS['egw']->acl;
@ -358,7 +362,7 @@ abstract class groupdav_handler
{
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$location = $this->groupdav->base_uri.$options['path'];
$location = $this->caldav->base_uri.$options['path'];
if ($location[0] == '/')
{
$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 (!$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']);
echo $options['data'];
}
@ -398,17 +402,17 @@ abstract class groupdav_handler
*
* @static
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param groupdav $groupdav calling class
* @param Api\CalDAV $groupdav calling class
* @return groupdav_handler
*/
static function app_handler($app, $groupdav)
static function app_handler($app, Api\CalDAV $groupdav)
{
static $handler_cache = array();
if (!array_key_exists($app,$handler_cache))
{
$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);
}
@ -639,21 +643,21 @@ abstract class groupdav_handler
}
// if requested add privileges
$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))
{
$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'])))
{
$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
return $this->groupdav->add_resource($path.urldecode($this->get_path($entry)), $props, $privileges);
// we urldecode here, as Api\CalDAV uses a minimal (#?%) urlencoding for incomming pathes and urlencodes pathes in propfind
return $this->caldav->add_resource($path.urldecode($this->get_path($entry)), $props, $privileges);
}
/**
@ -671,7 +675,7 @@ abstract class groupdav_handler
if (!isset($uri))
{
$uri = $path = $this->groupdav->base_uri;
$uri = $path = $this->caldav->base_uri;
if ($uri[0] == '/')
{
$uri = ($_SERVER["HTTPS"] === "on" ? "https:" : "http:") .'//' . $_SERVER['HTTP_HOST'] . $uri;
@ -705,12 +709,12 @@ abstract class groupdav_handler
{
$error =
' <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:error><D:number-of-matches-within-limits/></D:error>
</D:response>
';
if ($this->groupdav->crrnd)
if ($this->caldav->crrnd)
{
$error = str_replace(array('<D:', '</D:'), array('<', '</'), $error);
}
@ -747,175 +751,3 @@ abstract class groupdav_handler
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$
*/
namespace EGroupware\Api\CalDAV;
use EGroupware\Api;
// explicit import old non-namespaced api classes
use egw; // link
/**
* GroupDAV hooks: eg. preferences
*/
class groupdav_hooks
class Hooks
{
public $public_functions = array(
'log' => true,
@ -33,7 +40,7 @@ class groupdav_hooks
if ($location == 'preferences')
{
$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')
{
@ -109,13 +116,13 @@ class groupdav_hooks
if (substr($log,0,$account_lid_len+1) == $GLOBALS['egw_info']['user']['account_lid'].'-' &&
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));
}
}
}
$link = egw::link('/index.php',array(
'menuaction' => 'groupdav.groupdav_hooks.log',
'menuaction' => 'api.'.__CLASS__.'.log',
'filename' => '',
));
$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
*
* @throws egw_exception_wrong_parameter
* @throws Api\Exception\WrongParameter
*/
public function log()
public static function log()
{
$filename = $_GET['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'] = '
body { background-color: #e0e0e0; overflow: hidden; }
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));
$tail = new egw_tail($filename);
$tail = new Api\Json\Tail($filename);
$GLOBALS['egw']->framework->render($tail->show($header),false,false);
}
}

View File

@ -5,24 +5,32 @@
* @link http://www.egroupware.org
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage groupdav
* @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @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
*
* First-level properties used in this class should have the property name as their key,
* to allow to check if required properties are set!
* groupdav_principals::add_principal() converts simple associative props (name => value pairs)
* to name => HTTP_WebDAV_Server(name, value) pairs.
* Principals::add_principal() converts simple associative props (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).
*/
class groupdav_principals extends groupdav_handler
class Principals extends Handler
{
/**
* Instance of resources_bo
@ -35,11 +43,11 @@ class groupdav_principals extends groupdav_handler
* Constructor
*
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param groupdav $groupdav calling class
* @param Api\CalDAV $caldav calling class
*/
function __construct($app, groupdav $groupdav)
function __construct($app, Api\CalDAV $caldav)
{
parent::__construct($app, $groupdav);
parent::__construct($app, $caldav);
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
'addressbook-findshared' => array(
'ns' => groupdav::ADDRESSBOOKSERVER,
'ns' => Api\CalDAV::ADDRESSBOOKSERVER,
'method' => 'addressbook_findshared_report',
),*/
);
@ -79,7 +87,7 @@ class groupdav_principals extends groupdav_handler
*
* @param string $path eg. '/principals/'
* @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)
{
@ -90,10 +98,10 @@ class groupdav_principals extends groupdav_handler
$supported = array();
foreach($reports as $name => $data)
{
$supported[$name] = HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
!$data['ns'] ? HTTP_WebDAV_Server::mkprop($name, '') :
HTTP_WebDAV_Server::mkprop($data['ns'], $name, '')))));
$supported[$name] = Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
!$data['ns'] ? Api\CalDAV::mkprop($name, '') :
Api\CalDAV::mkprop($data['ns'], $name, '')))));
}
return $supported;
}
@ -116,7 +124,7 @@ class groupdav_principals extends groupdav_handler
{
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';
}
list(,,$type,$name,$rest) = explode('/',$path,5);
@ -178,7 +186,7 @@ class groupdav_principals extends groupdav_handler
foreach($this->get_shared_addressbooks() as $path)
{
$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));
}
@ -268,14 +276,14 @@ class groupdav_principals extends groupdav_handler
case 'calendar-proxy-write-for':
$prop_path = $path . substr($prop_name, 0, -4).'/';
$prop_name = 'group-member-set';
$prop_ns = groupdav::DAV;
$prop_ns = Api\CalDAV::DAV;
break;
case 'expanded-group-member-set':
case 'expanded-group-membership':
// remove 'expanded-' prefix
$prop_name = substr($prop_name, 9);
$prop_ns = groupdav::DAV;
$prop_ns = Api\CalDAV::DAV;
break;
}
// run regular propfind for requested property
@ -286,10 +294,10 @@ class groupdav_principals extends groupdav_handler
'xmlns' => $prop_ns,
));
$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)
{
$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;
}
// 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']) ||
$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;
}
@ -323,12 +331,12 @@ class groupdav_principals extends groupdav_handler
}
// put back evtl. read top-level property
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
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)");
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
$expand_prop['ns'] = $requested_prop['attrs']['namespace'];
$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'];
// add top-level path and property
$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']))
{
$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';
}
// make sure search property is included in toplevel props (can be missing and defaults to property-search/prop's)
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(
'name' => $prop['name'],
@ -483,7 +491,7 @@ class groupdav_principals extends groupdav_handler
substr($search_props[0]['match'],-13) == '/groupdav.php')
{
$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
@ -645,18 +653,18 @@ class groupdav_principals extends groupdav_handler
static $search_props = array(
// from iOS iCal
'displayname' => 'Display Name',
'email-address-set' => array('description' => 'Email Addresses', 'ns' => groupdav::CALENDARSERVER),
'last-name' => array('description' => 'Last Name', 'ns' => groupdav::CALENDARSERVER),
'calendar-user-type' => array('description' => 'Calendar User Type', 'ns' => groupdav::CALDAV),
'first-name' => array('description' => 'First Name', 'ns' => groupdav::CALENDARSERVER),
'calendar-user-address-set' => array('description' => 'Calendar User Address Set', 'ns' => groupdav::CALDAV),
'email-address-set' => array('description' => 'Email Addresses', 'ns' => Api\CalDAV::CALENDARSERVER),
'last-name' => array('description' => 'Last Name', 'ns' => Api\CalDAV::CALENDARSERVER),
'calendar-user-type' => array('description' => 'Calendar User Type', 'ns' => Api\CalDAV::CALDAV),
'first-name' => array('description' => 'First Name', 'ns' => Api\CalDAV::CALENDARSERVER),
'calendar-user-address-set' => array('description' => 'Calendar User Address Set', 'ns' => Api\CalDAV::CALDAV),
// 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
);
header('Content-type: text/xml; charset=UTF-8');
$xml = new XMLWriter;
$xml = new \XMLWriter;
$xml->openMemory();
$xml->setIndent(true);
$xml->startDocument('1.0', 'UTF-8');
@ -687,7 +695,7 @@ class groupdav_principals extends groupdav_handler
$xml->endDocument();
echo $xml->outputMemory();
common::egw_exit();
exit;
}
/**
@ -791,7 +799,7 @@ class groupdav_principals extends groupdav_handler
!($account = $this->accounts->read($id)) ||
!$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';
}
while (substr($rest,-1) == '/')
@ -913,7 +921,7 @@ class groupdav_principals extends groupdav_handler
{
$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)) &&
is_numeric($id) && ($owner = $this->accounts->id2name($id)))
@ -934,50 +942,50 @@ class groupdav_principals extends groupdav_handler
{
$addressbooks = $calendars = array();
// 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'].'/');
$calendars[] = HTTP_WebDAV_Server::mkprop('href',
$calendars[] = Api\CalDAV::mkprop('href',
$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(
'getetag' => $this->get_etag($account),
'displayname' => $displayname,
// 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
'schedule-outbox-URL' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-outbox-URL',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/outbox/'))),
'schedule-inbox-URL' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'schedule-inbox-URL',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/inbox/'))),
'calendar-user-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href','mailto:'.$account['account_email']),
HTTP_WebDAV_Server::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'].'/'),
HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('accounts', $account['account_id'])),
'schedule-outbox-URL' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'schedule-outbox-URL',array(
Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/outbox/'))),
'schedule-inbox-URL' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'schedule-inbox-URL',array(
Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/inbox/'))),
'calendar-user-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-address-set',array(
Api\CalDAV::mkprop('href','mailto:'.$account['account_email']),
Api\CalDAV::mkprop('href',$this->base_uri(true).'/principals/users/'.$account['account_lid'].'/'),
Api\CalDAV::mkprop('href',$this->base_uri(false).'/principals/users/'.$account['account_lid'].'/'),
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
'email-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'email-address-set',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'email-address',$account['account_email']))),
'last-name' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'last-name',$account['account_lastname']),
'first-name' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'first-name',$account['account_firstname']),
'record-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'record-type','users'),
'email-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'email-address-set',array(
Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'email-address',$account['account_email']))),
'last-name' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'last-name',$account['account_lastname']),
'first-name' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'first-name',$account['account_firstname']),
'record-type' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'record-type','users'),
// WebDAV ACL and CalDAV proxy
'group-membership' => $this->principal_set('group-membership', $this->accounts->memberships($account['account_id']),
array('calendar', 'resources'), $account['account_id']), // add proxy-rights
'alternate-URI-set' => array(
HTTP_WebDAV_Server::mkprop('href','mailto:'.$account['account_email'])),
Api\CalDAV::mkprop('href','mailto:'.$account['account_email'])),
// CardDAV
'addressbook-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',$addressbooks),
'principal-address' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'principal-address',
'addressbook-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-home-set',$addressbooks),
'principal-address' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'principal-address',
$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
'directory-gateway' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV, 'directory-gateway',array(
HTTP_WebDAV_Server::mkprop('href', $this->base_uri.'/addressbook/'))),
'resource-id' => array(HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('accounts', $account['account_id']))),
'directory-gateway' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV, 'directory-gateway',array(
Api\CalDAV::mkprop('href', $this->base_uri.'/addressbook/'))),
'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)
{
$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'
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(
'getetag' => $this->get_etag($account),
'displayname' => $displayname,
'calendar-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
'addressbook-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'addressbook-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
'calendar-user-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::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'].'/'),
HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('accounts', $account['account_id'])),
'calendar-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-home-set',array(
Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
'addressbook-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CARDDAV,'addressbook-home-set',array(
Api\CalDAV::mkprop('href',$this->base_uri.'/'.$account['account_lid'].'/'))),
'calendar-user-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-address-set',array(
Api\CalDAV::mkprop('href',$this->base_uri(true).'/principals/groups/'.$account['account_lid'].'/'),
Api\CalDAV::mkprop('href',$this->base_uri(false).'/principals/groups/'.$account['account_lid'].'/'),
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'),
'calendar-user-type' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-type','GROUP'),
'record-type' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'record-type','groups'),
'calendar-user-type' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-type','GROUP'),
'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(
'getetag' => $this->get_resource_etag($resource),
'displayname' => $displayname,
'calendar-user-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-user-address-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(true).'/principals/'.$name.'/'),
HTTP_WebDAV_Server::mkprop('href',$this->base_uri(false).'/principals/'.$name.'/'),
HTTP_WebDAV_Server::mkprop('href','urn:uuid:'.common::generate_uid('resources', $resource['res_id'])),
'calendar-user-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-address-set',array(
Api\CalDAV::mkprop('href',$this->base_uri(true).'/principals/'.$name.'/'),
Api\CalDAV::mkprop('href',$this->base_uri(false).'/principals/'.$name.'/'),
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'),
'calendar-user-type' => HTTP_WebDAV_Server::mkprop(groupdav::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']))),
'record-type' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'record-type',$is_location ? 'locations' : 'resources'),
'calendar-user-type' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-user-type',$is_location ? 'ROOM' : 'RESOURCE'),
'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)
'email-address-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'email-address-set',''),
'calendar-home-set' => HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-home-set',array(
HTTP_WebDAV_Server::mkprop('href',$this->base_uri.'/'.$name.'/'))),
'email-address-set' => Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'email-address-set',''),
'calendar-home-set' => Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-home-set',array(
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);
$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'].'-'.
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;
if (is_null($location_cats))
{
$config = config::read('resources');
$config = Api\Config::read('resources');
$location_cats = $config['location_cats'] ? explode(',', $config['location_cats']) : array();
}
if (!is_array($resource) && !($resource = self::read_resource($resource)))
@ -1298,16 +1306,16 @@ class groupdav_principals extends groupdav_handler
* Add a collection
*
* @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'
*/
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);
}
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)
{
$props['resourcetype'][] = HTTP_WebDAV_Server::mkprop('principal', '');
$props['resourcetype'][] = Api\CalDAV::mkprop('principal', '');
// required props per WebDAV ACL
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;
$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);
}
@ -1412,7 +1420,7 @@ class groupdav_principals extends groupdav_handler
'displayname' => lang('%1 proxy of %2', lang($app).' '.lang($what), basename($principal)),
'group-member-set' => $this->principal_set('group-member-set', $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
{
$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)
@ -1493,7 +1501,7 @@ class groupdav_principals extends groupdav_handler
$rights = $location_grants['L'.$resource['cat_id']];
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').'/');
}
}
@ -1518,7 +1526,7 @@ class groupdav_principals extends groupdav_handler
($account_lid = $this->accounts->id2name($account_id)) &&
$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_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 (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'];
}

View File

@ -11,17 +11,19 @@
* @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).
*
* @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
* - 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
@ -78,7 +80,7 @@ class calendar_groupdav extends groupdav_handler
/**
* 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';
@ -86,11 +88,11 @@ class calendar_groupdav extends groupdav_handler
* Constructor
*
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param groupdav $groupdav calling class
* @param Api\CalDAV $caldav calling class
*/
function __construct($app, groupdav $groupdav)
function __construct($app, Api\CalDAV $caldav)
{
parent::__construct($app, $groupdav);
parent::__construct($app, $caldav);
$this->bo = new calendar_boupdate();
$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', '>='))
{
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);
$name = $event[self::$path_attr];
}
$name .= groupdav_handler::$path_extension;
//error_log(__METHOD__.'('.array2string($event).") path_attr='".self::$path_attr."', path_extension='".groupdav_handler::$path_extension."' returning ".array2string($name));
$name .= self::$path_extension;
//error_log(__METHOD__.'('.array2string($event).") path_attr='".self::$path_attr."', path_extension='".self::$path_extension."' returning ".array2string($name));
return $name;
}
@ -152,8 +154,8 @@ class calendar_groupdav extends groupdav_handler
if (isset($_GET['download']))
{
$this->groupdav->propfind_options['props'] = array(array(
'xmlns' => groupdav::CALDAV,
$this->caldav->propfind_options['props'] = array(array(
'xmlns' => Api\CalDAV::CALDAV,
'name' => 'calendar-data',
));
}
@ -251,7 +253,7 @@ class calendar_groupdav extends groupdav_handler
else
{
// return iterator, calling ourself to return result in chunks
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
$files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
}
if (isset($_GET['download']))
{
@ -319,7 +321,7 @@ class calendar_groupdav extends groupdav_handler
{
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
$files = array();
@ -358,14 +360,14 @@ class calendar_groupdav extends groupdav_handler
'getetag' => '"'.$etag.'"',
'getlastmodified' => $event['modified'],
// 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'])),
'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'])),
);
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");
if ($calendar_data)
@ -375,16 +377,16 @@ class calendar_groupdav extends groupdav_handler
!isset($calendar_data['children']['expand']) ? false :
($calendar_data['children']['expand']['attrs'] ? $calendar_data['children']['expand']['attrs'] : true));
$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
* 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(
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'dtstamp',gmdate('Ymd\THis',$event['created']).'Z'),
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'action',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALENDARSERVER,'create',''),
$props['schedule-changes'] = Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'schedule-changes',array(
Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'dtstamp',gmdate('Ymd\THis',$event['created']).'Z'),
Api\CalDAV::mkprop(Api\CalDAV::CALENDARSERVER,'action',array(
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)))
{
$ns = groupdav::CALENDARSERVER;
$ns = Api\CalDAV::CALENDARSERVER;
if ($prop == 'href')
{
$ns = '';
$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)
{
$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));
return $props ? $props : '';
@ -567,11 +569,11 @@ class calendar_groupdav extends groupdav_handler
case 'sync-level':
if ($option['data'] != '1')
{
$this->groupdav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other']));
$this->caldav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other']));
}
break;
default:
$this->groupdav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other']));
$this->caldav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other']));
break;
}
}
@ -587,8 +589,8 @@ class calendar_groupdav extends groupdav_handler
if ($id)
{
$cal_filters['query'][self::$path_attr] = groupdav_handler::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id;
$cal_filters['query'][self::$path_attr] = self::$path_extension ?
basename($id,self::$path_extension) : $id;
}
else // fetch all given url's
{
@ -599,8 +601,8 @@ class calendar_groupdav extends groupdav_handler
$parts = explode('/',$option['data']);
if (($id = urldecode(array_pop($parts))))
{
$cal_filters['query'][self::$path_attr][] = groupdav_handler::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id;
$cal_filters['query'][self::$path_attr][] = self::$path_extension ?
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'])
{
$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']);
}
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
@ -935,7 +937,7 @@ class calendar_groupdav extends groupdav_handler
!($oldEvent['recur_date'] == $event['recurrence'] || !$event['recurrence'] && !$oldEvent['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;
}
}
@ -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"
{
$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');
@ -1002,7 +1004,7 @@ class calendar_groupdav extends groupdav_handler
}
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 ($eventId && $cal_id === false)
@ -1092,7 +1094,7 @@ class calendar_groupdav extends groupdav_handler
list($eventId) = explode(':', $id);
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");
}
@ -1128,13 +1130,13 @@ class calendar_groupdav extends groupdav_handler
$handler->setSupportedFields('groupdav');
$handler->calendarOwner = $handler->user = 0; // to NOT default owner/organizer to something
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';
}
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';
}
//print_r($event);
@ -1149,7 +1151,7 @@ class calendar_groupdav extends groupdav_handler
$xml->openMemory();
$xml->setIndent(true);
$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)
{
@ -1224,16 +1226,16 @@ class calendar_groupdav extends groupdav_handler
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))
{
$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))
{
$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
// and current user has no invite grant
@ -1494,47 +1496,47 @@ class calendar_groupdav extends groupdav_handler
if (!isset($props['calendar-description']))
{
// 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(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VCALENDAR')),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VEVENT')),
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VCALENDAR')),
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VEVENT')),
);
// outbox supports VFREEBUSY too, it is required from OS X iCal to autocomplete locations
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 reports
$props['supported-report-set'] = array(
'calendar-query' => HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))))),
'calendar-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget',''))))),
'free-busy-query' => HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'free-busy-query',''))))),
'calendar-query' => Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-query',''))))),
'calendar-multiget' => Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-multiget',''))))),
'free-busy-query' => Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'free-busy-query',''))))),
);
// 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
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(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop('sync-collection','')))));
$props['supported-report-set']['sync-collection'] = Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop('sync-collection','')))));
}
$props['supported-calendar-data'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-data',array(
HTTP_WebDAV_Server::mkprop(groupdav::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'))));
$props['supported-calendar-data'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'supported-calendar-data',array(
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-data', array('content-type' => 'text/calendar', 'version'=> '2.0')),
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-data', array('content-type' => 'text/x-calendar', 'version'=> '1.0'))));
// 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));
}
return $props;
@ -1594,7 +1596,7 @@ class calendar_groupdav extends groupdav_handler
foreach(explode(',', $pref) as $res_id)
{
$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
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();
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'];
}

View File

@ -9,17 +9,17 @@
*
* 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
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package api
* @subpackage groupdav
* @subpackage caldav
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2007-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
*/
use EGroupware\Api;
// switching off output compression for Lighttpd and HTTPS, as it makes problems with TB Lightning
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' &&
strpos($_SERVER['SERVER_SOFTWARE'],'lighttpd/1.4') === 0 &&
@ -48,6 +48,6 @@ $GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->read
$headertime = microtime(true);
$groupdav = new groupdav();
$groupdav->ServeRequest();
$caldav = new Api\CalDAV();
$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));

View File

@ -11,13 +11,15 @@
* @version $Id$
*/
use EGroupware\Api;
/**
* 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).
*/
class infolog_groupdav extends groupdav_handler
class infolog_groupdav extends Api\CalDAV\Handler
{
/**
* 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
*
* 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';
@ -57,11 +59,11 @@ class infolog_groupdav extends groupdav_handler
* Constructor
*
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param groupdav $groupdav calling class
* @param Api\CalDAV $caldav calling class
*/
function __construct($app, groupdav $groupdav)
function __construct($app, Api\CalDAV $caldav)
{
parent::__construct($app, $groupdav);
parent::__construct($app, $caldav);
$this->bo = new infolog_bo();
$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', '>='))
{
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);
$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
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)
{
@ -208,7 +210,7 @@ class infolog_groupdav extends groupdav_handler
else
{
// return iterator, calling ourself to return result in chunks
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
$files['files'] = new Api\CalDAV\PropfindIterator($this,$path,$filter,$files['files']);
}
return true;
}
@ -295,7 +297,7 @@ class infolog_groupdav extends groupdav_handler
{
$content = $handler->exportVTODO($task, '2.0', null); // no METHOD:PUBLISH for CalDAV
$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);
}
@ -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)
// 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)
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;
}
@ -414,11 +416,11 @@ class infolog_groupdav extends groupdav_handler
case 'sync-level':
if ($option['data'] != '1')
{
$this->groupdav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other']));
$this->caldav->log(__METHOD__."(...) only sync-level {$option['data']} requested, but only 1 supported! options[other]=".array2string($options['other']));
}
break;
default:
$this->groupdav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other']));
$this->caldav->log(__METHOD__."(...) unknown xml tag '{$option['name']}': options[other]=".array2string($options['other']));
break;
}
}
@ -429,8 +431,8 @@ class infolog_groupdav extends groupdav_handler
$ids = array();
if ($id)
{
$cal_filters[self::$path_attr] = groupdav_handler::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id;
$cal_filters[self::$path_attr] = self::$path_extension ?
basename($id,self::$path_extension) : $id;
}
else // fetch all given url's
{
@ -441,8 +443,8 @@ class infolog_groupdav extends groupdav_handler
$parts = explode('/',$option['data']);
if (($id = basename(urldecode(array_pop($parts)))))
{
$cal_filters[self::$path_attr][] = groupdav_handler::$path_extension ?
basename($id,groupdav_handler::$path_extension) : $id;
$cal_filters[self::$path_attr][] = self::$path_extension ?
basename($id,self::$path_extension) : $id;
}
}
}
@ -474,7 +476,7 @@ class infolog_groupdav extends groupdav_handler
}
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
}
// 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
$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
$props['supported-calendar-component-set'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-component-set',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VCALENDAR')),
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'comp',array('name' => 'VTODO')),
$props['supported-calendar-component-set'] = Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'supported-calendar-component-set',array(
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VCALENDAR')),
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'comp',array('name' => 'VTODO')),
));
// supported reports
$props['supported-report-set'] = array(
'calendar-query' => HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))))),
'calendar-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget',''))))),
'calendar-query' => Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop(Api\CalDAV::CALDAV,'calendar-query',''))))),
'calendar-multiget' => Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
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
$config = config::read('infolog');
if ($config['history'])
{
$props['supported-report-set']['sync-collection'] = HTTP_WebDAV_Server::mkprop('supported-report',array(
HTTP_WebDAV_Server::mkprop('report',array(
HTTP_WebDAV_Server::mkprop('sync-collection','')))));
$props['supported-report-set']['sync-collection'] = Api\CalDAV::mkprop('supported-report',array(
Api\CalDAV::mkprop('report',array(
Api\CalDAV::mkprop('sync-collection','')))));
}
// 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));
}
return $props;

View File

@ -115,28 +115,25 @@ class common
}
/**
* 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
*/
* generate a unique id, which can be used for syncronisation
*
* @param string $_appName the appname
* @param string $_eventID the id of the content
* @deprecated use Api\CalDAV::generate_uid($_appName, $_eventID)
* @return string the unique id
*/
static function generate_uid($_appName, $_eventID)
{
if(empty($_appName) || empty($_eventID)) return false;
// 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;
return Api\CalDAV::generate_uid($_appName, $_eventID);
}
/**
* get the local content id from a global UID
*
* @param sting $_globalUid the global UID
* @return int local egw content id
*/
* get the local content id from a global UID
*
* @param sting $_globalUid the global UID
* @deprecated dont use, as only EGroupware interal uids are reversable
* @return int local egw content id
*/
static function get_egwId($_globalUid)
{
if(empty($_globalUid)) return false;

View File

@ -4,13 +4,15 @@
*
* @link http://www.egroupware.org
* @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
* @package etemplate
* @subpackage api
* @package api
* @subpackage json
* @version $Id$
*/
use EGroupware\Api\Json\Tail;
/**
* 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,
* eg. new egw_tail('groupdav/somelog')!
*
* @deprecated use Api\Json\Tail
*/
class egw_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();
}*/
class egw_tail extends Tail {}

View File

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

View File

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

View File

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