Page MenuHomePhorge

No OneTemporary

This document is not UTF8. It was detected as JIS and converted to UTF8 for display.
diff --git a/config/dav.inc.php.sample b/config/dav.inc.php.sample
index ebba468..623f7b4 100644
--- a/config/dav.inc.php.sample
+++ b/config/dav.inc.php.sample
@@ -1,41 +1,48 @@
<?php
/*
+-------------------------------------------------------------------------+
| Configuration for the Kolab DAV server |
| |
| Copyright (C) 2013, Kolab Systems AG |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as |
| published by the Free Software Foundation, either version 3 of the |
| License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License|
| along with this program. If not, see <http://www.gnu.org/licenses/>. |
| |
+-------------------------------------------------------------------------+
*/
-$rcmail_config = array();
+$config = array();
// Log DAV requests to <log_dir>/davdebug
-$rcmail_config['base_uri'] = null;
+$config['base_uri'] = null;
// User agent string written to kolab storage MIME messages
-$rcmail_config['useragent'] = 'Kolab DAV Server libkolab/' . RCUBE_VERSION;
+$config['useragent'] = 'Kolab DAV Server libkolab/' . RCUBE_VERSION;
// Roundcube plugins. Not all are supported here.
-$rcmail_config['kolabdav_plugins'] = array('kolab_auth');
+$config['kolabdav_plugins'] = array('kolab_auth');
// Type of Auth cache. Supported values: 'db', 'apc' and 'memcache'.
// Note: This is only for username canonification map.
-$rcmail_config['kolabdav_auth_cache'] = 'apc';
+$config['kolabdav_auth_cache'] = 'apc';
// lifetime of the Auth cache, possible units: s, m, h, d, w
-$rcmail_config['kolabdav_auth_cache_ttl'] = '1h';
+$config['kolabdav_auth_cache_ttl'] = '1h';
+
+// enable debug console showing the internal function calls triggered
+// by http requests. This will write log to /var/log/iRony/console
+$config['kolabdav_console'] = false;
+
+// enable per-user debugging if /var/log/iRony/<username>/ folder exists
+$config['kolabdav_user_debug'] = false;
diff --git a/lib/Kolab/Utils/DAVBackend.php b/lib/Kolab/Utils/DAVBackend.php
index 0734be9..1111216 100644
--- a/lib/Kolab/Utils/DAVBackend.php
+++ b/lib/Kolab/Utils/DAVBackend.php
@@ -1,251 +1,251 @@
<?php
/**
- * Utility class prividing a simple API to PHP's APC cache
+ * Utility class providing a simple API to PHP's APC cache
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Kolab\Utils;
use \rcube;
use \kolab_storage;
use \rcube_utils;
use \rcube_charset;
/**
*
*/
class DAVBackend
{
const IMAP_UID_KEY = '/shared/vendor/kolab/uniqueid';
const IMAP_UID_KEY_PRIVATE = '/private/vendor/kolab/uniqueid';
const IMAP_UID_KEY_CYRUS = '/shared/vendor/cmu/cyrus-imapd/uniqueid';
/**
* Getter for a kolab_storage_folder with the given UID
*
* @param string Folder UID (saved in annotation)
* @param string Kolab folder type (for selecting candidates)
* @return object \kolab_storage_folder instance
*/
public static function get_storage_folder($uid, $type)
{
foreach (kolab_storage::get_folders($type) as $folder) {
if (self::get_uid($folder) == $uid)
return $folder;
}
return null;
}
/**
* Helper method to extract folder UID metadata
*
* @param object \kolab_storage_folder Folder to get UID for
* @return string Folder's UID
*/
public static function get_uid($folder)
{
// UID is defined in folder METADATA
$metakeys = array(self::IMAP_UID_KEY, self::IMAP_UID_KEY_PRIVATE, self::IMAP_UID_KEY_CYRUS);
$metadata = $folder->get_metadata($metakeys);
foreach ($metakeys as $key) {
if (($uid = $metadata[$key])) {
return $uid;
}
}
// generate a folder UID and set it to IMAP
$uid = rtrim(chunk_split(md5($folder->name . $folder->get_owner()), 12, '-'), '-');
self::set_uid($folder, $uid);
return $uid;
}
/**
* Helper method to set an UID value to the given IMAP folder instance
*
* @param object \kolab_storage_folder Folder to set UID
* @param string Folder's UID
* @return boolean True on succes, False on failure
*/
public static function set_uid($folder, $uid)
{
if (!($success = $folder->set_metadata(array(self::IMAP_UID_KEY => $uid)))) {
$success = $folder->set_metadata(array(self::IMAP_UID_KEY_PRIVATE => $uid));
}
return $success;
}
/**
* Build an absolute URL with the given parameters
*/
public static function abs_url($parts = array())
{
$schema = 'http';
$default_port = 80;
if (rcube_utils::https_check()) {
$schema = 'https';
$default_port = 443;
}
$url = $schema . '://' . $_SERVER['HTTP_HOST'];
if ($_SERVER['SERVER_PORT'] != $default_port)
$url .= ':' . $_SERVER['SERVER_PORT'];
if (dirname($_SERVER['SCRIPT_NAME']) != '/')
$url .= dirname($_SERVER['SCRIPT_NAME']);
$url .= '/' . join('/', array_map('urlencode', $parts));
return $url;
}
/**
* Updates properties for a recourse (kolab folder)
*
* The mutations array uses the propertyName in clark-notation as key,
* and the array value for the property value. In the case a property
* should be deleted, the property value will be null.
*
* This method must be atomic. If one property cannot be changed, the
* entire operation must fail.
*
* If the operation was successful, true is returned.
* If the operation failed, detailed information about any
* failures is returned.
*
* @param object $folder kolab_storage_folder instance to operate on
* @param array $mutations Hash array with propeties to change
* @return bool|array
*/
public static function folder_update($folder, array $mutations)
{
$errors = array();
$updates = array();
foreach ($mutations as $prop => $val) {
switch ($prop) {
case '{DAV:}displayname':
// restrict renaming to personal folders only
if ($folder->get_namespace() == 'personal') {
$parts = preg_split('!(\s*/\s*|\s+[サ:]\s+)!', $val);
$updates['oldname'] = $folder->name;
$updates['name'] = array_pop($parts);
$updates['parent'] = join('/', $parts);
}
else {
$updates['displayname'] = $val;
}
break;
case '{http://apple.com/ns/ical/}calendar-color':
$updates['color'] = substr(trim($val, '#'), 0, 6);
break;
case '{urn:ietf:params:xml:ns:caldav}calendar-description':
default:
// unsupported property
$errors[403][$prop] = null;
}
}
// execute folder update
if (!empty($updates)) {
// 'name' and 'parent' properties are always required
if (empty($updates['name'])) {
$parts = explode('/', $folder->name);
$updates['name'] = rcube_charset::convert(array_pop($parts), 'UTF7-IMAP');
$updates['parent'] = join('/', $parts);
$updates['oldname'] = $folder->name;
}
if (!kolab_storage::folder_update($updates)) {
rcube::raise_error(array(
'code' => 600, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Error updating properties for folder $folder->name:" . kolab_storage::$last_error),
true, false);
return false;
}
}
return empty($errors) ? true : $errors;
}
/**
* Creates a new resource (i.e. IMAP folder) of a given type
*
* If the creation was a success, an id must be returned that can be used to reference
* this resource in other methods.
*
* @param array $properties
* @param string $type
* @param string $uid
* @return false|string
*/
public function folder_create($type, array $properties, $uid)
{
$props = array(
'type' => $type,
'name' => '',
'subscribed' => true,
);
foreach ($properties as $prop => $val) {
switch ($prop) {
case '{DAV:}displayname':
$parts = explode('/', $val);
$props['name'] = array_pop($parts);
$props['parent'] = join('/', $parts);
break;
case '{http://apple.com/ns/ical/}calendar-color':
$props['color'] = substr(trim($val, '#'), 0, 6);
break;
case '{urn:ietf:params:xml:ns:caldav}calendar-description':
default:
// unsupported property
}
}
// use UID as name if it doesn't seem to be a real UID
// TODO: append number to default "Untitled" folder name if one already exists
if (empty($props['name'])) {
$props['name'] = strlen($uid) < 16 ? $uid : 'Untitled';
}
if (!($fname = kolab_storage::folder_update($props))) {
rcube::raise_error(array(
'code' => 600, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Error creating a new $type folder '$props[name]':" . kolab_storage::$last_error),
true, false);
return false;
}
// save UID in folder annotations
if ($folder = kolab_storage::get_folder($fname)) {
self::set_uid($folder, $uid);
}
return $uid;
}
}
diff --git a/lib/Kolab/Utils/DAVLogger.php b/lib/Kolab/Utils/DAVLogger.php
new file mode 100644
index 0000000..982d87e
--- /dev/null
+++ b/lib/Kolab/Utils/DAVLogger.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Utility class logging DAV requests
+ *
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Kolab\Utils;
+
+use Sabre\DAV;
+
+
+/**
+ * Utility class to log debug information about processed DAV requests
+ */
+class DAVLogger extends DAV\ServerPlugin
+{
+ private $server;
+ private $method;
+
+ /**
+ * This initializes the plugin.
+ * This method should set up the required event subscriptions.
+ *
+ * @param Server $server
+ */
+ public function initialize(DAV\Server $server)
+ {
+ $this->server = $server;
+
+ $server->subscribeEvent('beforeMethod', array($this, '_beforeMethod'));
+ $server->subscribeEvent('exception', array($this, '_exception'));
+ $server->subscribeEvent('exit', array($this, '_exit'));
+ }
+
+ /**
+ * Handler for 'beforeMethod' events
+ */
+ public function _beforeMethod($method, $uri)
+ {
+ $this->method = $method;
+
+ // log to console
+ console($method . ' ' . $uri);
+ }
+
+ /**
+ * Handler for 'exception' events
+ */
+ public function _exception($e)
+ {
+ // log to console
+ console(get_class($e) . ' (EXCEPTION)', $e->getMessage() /*, $e->getTraceAsString()*/);
+ }
+
+ /**
+ * Handler for 'exit' events
+ */
+ public function _exit()
+ {
+ $time = microtime(true) - KOLAB_DAV_START;
+
+ if (function_exists('memory_get_usage'))
+ $mem = round(memory_get_usage() / 1024) . 'K';
+ if (function_exists('memory_get_peak_usage'))
+ $mem .= '/' . round(memory_get_peak_usage() / 1024) . 'K';
+
+ console(sprintf("/%s: %0.4f sec; %s", $this->method, $time, $mem));
+ }
+}
\ No newline at end of file
diff --git a/public_html/index.php b/public_html/index.php
index 8a86bd1..64f02ea 100644
--- a/public_html/index.php
+++ b/public_html/index.php
@@ -1,155 +1,186 @@
<?php
/**
* iRony, the Kolab WebDAV/CalDAV/CardDAV Server
*
* This is the public API to provide *DAV-based access to the Kolab Groupware backend
*
* @version 0.2.3
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// define some environment variables used throughout the app and libraries
define('KOLAB_DAV_ROOT', realpath('../'));
-define('KOLAB_DAV_VERSION', '0.2.3');
+define('KOLAB_DAV_VERSION', '0.2.4');
define('KOLAB_DAV_START', microtime(true));
define('RCUBE_INSTALL_PATH', KOLAB_DAV_ROOT . '/');
define('RCUBE_CONFIG_DIR', KOLAB_DAV_ROOT . '/config/');
define('RCUBE_PLUGINS_DIR', KOLAB_DAV_ROOT . '/lib/plugins/');
// suppress error notices
ini_set('error_reporting', E_ALL &~ E_NOTICE &~ E_STRICT);
/**
* Mapping PHP errors to exceptions.
*
* While this is not strictly needed, it makes a lot of sense to do so. If an
* E_NOTICE or anything appears in your code, this allows SabreDAV to intercept
* the issue and send a proper response back to the client (HTTP/1.1 500).
*/
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
//set_error_handler("exception_error_handler");
// use composer's autoloader for both dependencies and local lib
require_once KOLAB_DAV_ROOT . '/vendor/autoload.php';
// load the Roundcube framework
require_once KOLAB_DAV_ROOT . '/lib/Roundcube/bootstrap.php';
// Roundcube framework initialization
$rcube = rcube::get_instance(rcube::INIT_WITH_DB | rcube::INIT_WITH_PLUGINS);
$rcube->config->load_from_file(RCUBE_CONFIG_DIR . 'dav.inc.php');
// Load plugins
$plugins = (array)$rcube->config->get('kolabdav_plugins', array('kolab_auth'));
$required = array('libkolab', 'libcalendaring');
$rcube->plugins->init($rcube);
$rcube->plugins->load_plugins($plugins, $required);
+
// convenience function, you know it well :-)
-function console() { call_user_func_array(array('rcube', 'console'), func_get_args()); }
+function console()
+{
+ global $rcube;
+
+ // write to global console log
+ if ($rcube->config->get('kolabdav_console', false)) {
+ call_user_func_array(array('rcube', 'console'), func_get_args());
+ }
+
+ // dump console data per user
+ if ($rcube->config->get('kolabdav_user_debug', false)) {
+ $uname = \Kolab\DAV\Auth\HTTPBasic::$current_user;
+ $log_dir = $rcube->config->get('log_dir', RCUBE_INSTALL_PATH . 'logs');
+
+ if ($uname && $log_dir && is_writable($log_dir . '/' . $uname)) {
+ $msg = array();
+ foreach (func_get_args() as $arg) {
+ $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
+ }
+
+ rcube::write_log($uname . '/console', join(";\n", $msg));
+ }
+ }
+}
// Make sure this setting is turned on and reflects the root url of the *DAV server.
$base_uri = $rcube->config->get('base_uri', slashify(substr(dirname($_SERVER['SCRIPT_FILENAME']), strlen($_SERVER['DOCUMENT_ROOT']))));
// add filename to base URI when called without mod_rewrite (e.g. /dav/index.php/calendar)
if (strpos($_SERVER['REQUEST_URI'], 'index.php'))
$base_uri .= 'index.php/';
// create the various backend instances
$auth_backend = new \Kolab\DAV\Auth\HTTPBasic();
$principal_backend = new \Kolab\DAVACL\PrincipalBackend();
$services = array();
foreach (array('CALDAV','CARDDAV','WEBDAV') as $skey) {
if (getenv($skey))
$services[$skey] = 1;
}
// no config means *all* services
if (empty($services))
$services = array('CALDAV' => 1, 'CARDDAV' => 1, 'WEBDAV' => 1);
// Build the directory tree
// This is an array which contains the 'top-level' directories in the WebDAV server.
if ($services['CALDAV'] || $services['CARDDAV']) {
$nodes = array(
new \Sabre\CalDAV\Principal\Collection($principal_backend),
);
if ($services['CALDAV']) {
$caldav_backend = new \Kolab\CalDAV\CalendarBackend();
$caldav_backend->setUserAgent($_SERVER['HTTP_USER_AGENT']);
$nodes[] = new \Kolab\CalDAV\CalendarRootNode($principal_backend, $caldav_backend);
}
if ($services['CARDDAV']) {
$carddav_backend = new \Kolab\CardDAV\ContactsBackend();
$carddav_backend->setUserAgent($_SERVER['HTTP_USER_AGENT']);
$nodes[] = new \Kolab\CardDAV\AddressBookRoot($principal_backend, $carddav_backend);
}
if ($services['WEBDAV']) {
$nodes[] = new \Kolab\DAV\Collection(\Kolab\DAV\Collection::ROOT_DIRECTORY);
}
}
// register WebDAV service as root
else if ($services['WEBDAV']) {
$nodes = new \Kolab\DAV\Collection('');
}
// the object tree needs in turn to be passed to the server class
$server = new \Sabre\DAV\Server($nodes);
$server->setBaseUri($base_uri);
+// enable logger
+if ($rcube->config->get('kolabdav_console') || $rcube->config->get('kolabdav_user_debug')) {
+ $server->addPlugin(new \Kolab\Utils\DAVLogger());
+}
+
// register some plugins
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth_backend, 'KolabDAV'));
$server->addPlugin(new \Sabre\DAVACL\Plugin());
if ($services['CALDAV']) {
$caldav_plugin = new \Kolab\CalDAV\Plugin();
$caldav_plugin->setIMipHandler(new \Kolab\CalDAV\IMip());
$server->addPlugin($caldav_plugin);
}
if ($services['CARDDAV']) {
$server->addPlugin(new \Kolab\CardDAV\Plugin());
}
if ($services['WEBDAV']) {
// the lock manager is reponsible for making sure users don't overwrite each others changes.
// TODO: replace this with a class that manages locks in the Kolab backend
$locks_backend = new \Sabre\DAV\Locks\Backend\File(KOLAB_DAV_ROOT . '/temp/locks');
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($locks_backend));
// intercept some of the garbage files operation systems tend to generate when mounting a WebDAV share
$server->addPlugin(new \Sabre\DAV\TemporaryFileFilterPlugin(KOLAB_DAV_ROOT . '/temp'));
}
// HTML UI for browser-based access (recommended only for development)
if (getenv('DAVBROWSER')) {
$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
}
// finally, process the request
$server->exec();
+// trigger log
+$server->broadcastEvent('exit', array());

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 9:26 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10075830
Default Alt Text
(21 KB)

Event Timeline