summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas <tb@woodcrest.local>2013-10-24 08:07:40 (GMT)
committerThomas <tb@woodcrest.local>2013-10-24 08:07:40 (GMT)
commitc8ac2064748b25b841bfa02f468dd3a6124e978e (patch)
tree37e0caf3536ec84b96bb04507b95d5d5fa1c4df3
parentfecd314fe86e48e6bf6384dd830fefccc0b53b84 (diff)
downloadiRony-dev/caldav-scheduling.tar.gz
First attempts to implement a schedule-inboxdev/caldav-scheduling
-rw-r--r--composer.json2
-rw-r--r--lib/Kolab/CalDAV/CalendarBackend.php61
-rw-r--r--lib/Kolab/CalDAV/Plugin.php42
-rw-r--r--lib/Kolab/CalDAV/Schedule/Inbox.php257
-rw-r--r--lib/Kolab/CalDAV/UserCalendars.php15
-rw-r--r--lib/Kolab/Utils/VObjectUtils.php14
-rw-r--r--public_html/index.php4
7 files changed, 388 insertions, 7 deletions
diff --git a/composer.json b/composer.json
index af4e9e4..2c963a6 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "kolab/irony",
"description": "iRony - The Kolab WebDAV/CalDAV/CardDAV Server",
"license": "AGPL-3.0",
- "version": "0.2.2",
+ "version": "0.3.0-beta",
"repositories": [
{
"type": "pear",
diff --git a/lib/Kolab/CalDAV/CalendarBackend.php b/lib/Kolab/CalDAV/CalendarBackend.php
index 8ed1589..439775c 100644
--- a/lib/Kolab/CalDAV/CalendarBackend.php
+++ b/lib/Kolab/CalDAV/CalendarBackend.php
@@ -111,6 +111,32 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
}
/**
+ * Getter for the default calendar resource
+ */
+ public function get_default_calendar()
+ {
+ $folders = kolab_storage::get_folders('event');
+ $default = null;
+
+ foreach ($folders as $folder) {
+ if (!$default || $folder->default) {
+ $default = $folder;
+ }
+ }
+
+ if ($default) {
+ $id = $default->get_uid();
+ return array(
+ 'id' => $id,
+ 'uri' => $id,
+ '{DAV:}displayname' => html_entity_decode($default->get_name(), ENT_COMPAT, RCUBE_CHARSET),
+ );
+ }
+
+ return false;
+ }
+
+ /**
* Returns a list of calendars for a principal.
*
* Every calendars is an array with the following keys:
@@ -575,6 +601,41 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
}
/**
+ * Extract scheduling objects from iTip messages in INBOX
+ *
+ * TODO: Improve this with caching or a dedicated scheduling inbox container
+ */
+ public function getSchedulingInboxObjects()
+ {
+ console(__METHOD__);
+
+ $objects = array();
+ $imap = rcube::get_instance()->get_storage();
+ $index = $imap->search_once('INBOX', 'OR OR OR HEADER CONTENT-TYPE text/calendar HEADER CONTENT-TYPE application/ics HEADER CONTENT-TYPE multipart/mixed HEADER CONTENT-TYPE multipart/alternative');
+
+ foreach ($index->get() as $msguid) {
+ $message = new \rcube_message($msguid, 'INBOX');
+ foreach ((array)$message->mime_parts as $part) {
+ if (VObjectUtils::is_vcalendar($part) || $part->ctype_parameters['method']) {
+ $data = $message->get_part_content($part->mime_id);
+ $event = $this->parse_calendar_data($data, '-');
+ $objects[] = array(
+ 'id' => $event['uid'],
+ 'uri' => $event['uid'] . '.ics',
+ 'lastmodified' => $event['changed'] ? $event['changed']->format('U') : null,
+ 'calendarid' => 'inbox',
+ 'calendardata' => $data,
+ 'etag' => self::_get_etag($event),
+ );
+ break;
+ }
+ }
+ }
+
+ return $objects;
+ }
+
+ /**
* Set User-Agent string of the connected client
*/
public function setUserAgent($uastring)
diff --git a/lib/Kolab/CalDAV/Plugin.php b/lib/Kolab/CalDAV/Plugin.php
index c3b064f..69dda2c 100644
--- a/lib/Kolab/CalDAV/Plugin.php
+++ b/lib/Kolab/CalDAV/Plugin.php
@@ -24,6 +24,7 @@
namespace Kolab\CalDAV;
use Sabre\DAV;
+use Sabre\DAVACL;
use Sabre\CalDAV;
use Sabre\VObject;
use Kolab\DAV\Auth\HTTPBasic;
@@ -53,6 +54,47 @@ class Plugin extends CalDAV\Plugin
$server->subscribeEvent('afterCreateFile', array($this, 'afterWriteContent'));
$server->subscribeEvent('afterWriteContent', array($this, 'afterWriteContent'));
+
+ $server->resourceTypeMapping['\\Kolab\\CalDAV\\ScheduleInbox'] = '{urn:ietf:params:xml:ns:caldav}schedule-inbox';
+ }
+
+ /**
+ * beforeGetProperties
+ *
+ * This method handler is invoked before any after properties for a
+ * resource are fetched. This allows us to add in any CalDAV specific
+ * properties.
+ *
+ * @param string $path
+ * @param DAV\INode $node
+ * @param array $requestedProperties
+ * @param array $returnedProperties
+ * @return void
+ */
+ public function beforeGetProperties($path, DAV\INode $node, &$requestedProperties, &$returnedProperties)
+ {
+ // schedule-inbox-URL property
+ if ($node instanceof DAVACL\IPrincipal) {
+ $scheduleProp = '{' . self::NS_CALDAV . '}schedule-inbox-URL';
+ if (in_array($scheduleProp, $requestedProperties)) {
+ $principalId = $node->getName();
+ $inboxPath = self::CALENDAR_ROOT . '/' . $principalId . '/inbox';
+
+ unset($requestedProperties[array_search($scheduleProp, $requestedProperties)]);
+ $returnedProperties[200][$scheduleProp] = new DAV\Property\Href($inboxPath);
+ }
+ }
+
+ // schedule-default-calendar-URL
+ if ($node instanceof Schedule\Inbox) {
+ $defaultCalendarProp = '{' . self::NS_CALDAV . '}schedule-default-calendar-URL';
+ if (in_array($defaultCalendarProp, $requestedProperties) && ($calendarURL = $node->schedule_default_calendar_url())) {
+ unset($requestedProperties[array_search($defaultCalendarProp, $requestedProperties)]);
+ $returnedProperties[200][$defaultCalendarProp] = new DAV\Property\Href(self::CALENDAR_ROOT . '/' . $calendarURL);
+ }
+ }
+
+ parent::beforeGetProperties($path, $node, $requestedProperties, $returnedProperties);
}
/**
diff --git a/lib/Kolab/CalDAV/Schedule/Inbox.php b/lib/Kolab/CalDAV/Schedule/Inbox.php
new file mode 100644
index 0000000..54970d5
--- /dev/null
+++ b/lib/Kolab/CalDAV/Schedule/Inbox.php
@@ -0,0 +1,257 @@
+<?php
+
+/**
+ * CalDAV scheduling inbox for the Kolab.
+ *
+ * @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\CalDAV\Schedule;
+
+use Sabre\DAV;
+use Sabre\CalDAV;
+use Sabre\DAVACL;
+
+/**
+ * The CalDAV scheduling inbox
+ */
+class Inbox extends DAV\Collection implements DAV\ICollection, DAVACL\IACL
+{
+ /**
+ * The principal Uri
+ *
+ * @var string
+ */
+ protected $principalUri;
+
+ protected $principalId;
+
+ /**
+ * CalDAV backend
+ *
+ * @var Sabre\CalDAV\Backend\BackendInterface
+ */
+ protected $caldavBackend;
+
+ /**
+ * Constructor
+ *
+ * @param string $principalUri
+ */
+ public function __construct(CalDAV\Backend\BackendInterface $caldavBackend, $principalUri)
+ {
+ $this->caldavBackend = $caldavBackend;
+
+ $principal = explode('/', $principalUri);
+ $this->principalId = end($principal);
+ $this->principalUri = $principalUri;
+
+ $this->calendarInfo = array(
+ 'id' => 'inbox',
+ 'principaluri' => $principalUri,
+ );
+ }
+
+ /**
+ * Provide the URL for the default calendar for event scheduling
+ */
+ public function schedule_default_calendar_url()
+ {
+ if ($cal = $this->caldavBackend->get_default_calendar()) {
+ return $this->principalId . '/' . $cal['uri'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the name of the node.
+ *
+ * This is used to generate the url.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ console(__METHOD__);
+ return 'inbox';
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return \Sabre\DAV\INode[]
+ */
+ public function getChildren()
+ {
+ console(__METHOD__);
+
+ $children = array();
+ $objs = $this->caldavBackend->getSchedulingInboxObjects();
+ foreach ($objs as $obj) {
+ $children[] = new CalDAV\CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
+ }
+
+ return $children;
+ }
+
+ /**
+ * Returns a child object, by its name.
+ *
+ * @param string $name
+ * @throws Exception\NotFound
+ * @return INode
+ */
+ public function getChild($name)
+ {
+ console(__METHOD__, $name);
+
+ // TODO: improve this
+ $objs = $this->caldavBackend->getSchedulingInboxObjects();
+ foreach ($objs as $obj) {
+ if ($obj['uri'] == $name) {
+ return new CalDAV\CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
+ }
+ }
+
+ throw new DAV\Exception\NotFound('File not found: ' . $name);
+ }
+
+ /**
+ * Checks is a child-node exists.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function childExists($name)
+ {
+ console(__METHOD__, $name);
+
+ // TODO: improve this
+ $objs = $this->caldavBackend->getSchedulingInboxObjects();
+ foreach ($objs as $obj) {
+ if ($obj['uri'] == $name) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner()
+ {
+ return $this->principalUri;
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup()
+ {
+ return null;
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-invite',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-reply',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}unbind',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ );
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl)
+ {
+ throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet()
+ {
+ $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
+
+ $default['aggregates'][] = array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-invite',
+ );
+ $default['aggregates'][] = array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-reply',
+ );
+
+ return $default;
+ }
+
+}
diff --git a/lib/Kolab/CalDAV/UserCalendars.php b/lib/Kolab/CalDAV/UserCalendars.php
index dcd2aff..528d310 100644
--- a/lib/Kolab/CalDAV/UserCalendars.php
+++ b/lib/Kolab/CalDAV/UserCalendars.php
@@ -25,16 +25,17 @@ namespace Kolab\CalDAV;
use Sabre\DAV;
use Sabre\DAVACL;
+use Sabre\CalDAV;
use Sabre\CalDAV\Backend;
-use Sabre\CalDAV\Schedule;
use Kolab\CalDAV\Calendar;
/**
* The UserCalenders class contains all calendars associated to one user
*
*/
-class UserCalendars extends \Sabre\CalDAV\UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL
+class UserCalendars extends CalDAV\UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL
{
+ private $inbox;
private $outbox;
/**
@@ -62,7 +63,10 @@ class UserCalendars extends \Sabre\CalDAV\UserCalendars implements DAV\IExtended
}
// add support for scheduling AKA free/busy
- $objs[] = new Schedule\Outbox($this->principalInfo['uri']);
+ $this->inbox = new Schedule\Inbox($this->caldavBackend, $this->principalInfo['uri']);
+ $this->outbox = new CalDAV\Schedule\Outbox($this->principalInfo['uri']);
+ $objs[] = $this->inbox;
+ $objs[] = $this->outbox;
// TODO: add notification support (check with clients first, if anybody supports it)
if ($this->caldavBackend instanceof Backend\NotificationSupport) {
@@ -80,8 +84,11 @@ class UserCalendars extends \Sabre\CalDAV\UserCalendars implements DAV\IExtended
*/
public function getChild($name)
{
+ if ($name == 'inbox') {
+ return $this->inbox ?: ($this->inbox = new Schedule\Inbox($this->caldavBackend, $this->principalInfo['uri']));
+ }
if ($name == 'outbox') {
- return new Schedule\Outbox($this->principalInfo['uri']);
+ return $this->outbox ?: ($this->outbox = new CalDAV\Schedule\Outbox($this->principalInfo['uri']));
}
if ($calendar = $this->caldavBackend->getCalendarByName($name)) {
$calendar['principaluri'] = $this->principalInfo['uri'];
diff --git a/lib/Kolab/Utils/VObjectUtils.php b/lib/Kolab/Utils/VObjectUtils.php
index f04884e..eb35fb2 100644
--- a/lib/Kolab/Utils/VObjectUtils.php
+++ b/lib/Kolab/Utils/VObjectUtils.php
@@ -57,4 +57,18 @@ class VObjectUtils
return $out;
}
+ /**
+ * Checks if specified message part is a vcalendar data
+ *
+ * @param rcube_message_part Part object
+ * @return boolean True if part is of type vcard
+ */
+ public static function is_vcalendar($part)
+ {
+ return (
+ in_array($part->mimetype, array('text/calendar', 'text/x-vcalendar', 'application/ics')) ||
+ // Apple sends files as application/x-any (!?)
+ ($part->mimetype == 'application/x-any' && $part->filename && preg_match('/\.ics$/i', $part->filename))
+ );
+ }
} \ No newline at end of file
diff --git a/public_html/index.php b/public_html/index.php
index f4ebc77..d354105 100644
--- a/public_html/index.php
+++ b/public_html/index.php
@@ -5,7 +5,7 @@
*
* This is the public API to provide *DAV-based access to the Kolab Groupware backend
*
- * @version 0.2.2
+ * @version 0.3.0-beta
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
@@ -26,7 +26,7 @@
// define some environment variables used throughout the app and libraries
define('KOLAB_DAV_ROOT', realpath('../'));
-define('KOLAB_DAV_VERSION', '0.2.0');
+define('KOLAB_DAV_VERSION', '0.3.0-beta');
define('KOLAB_DAV_START', microtime(true));
define('RCUBE_INSTALL_PATH', KOLAB_DAV_ROOT . '/');