diff options
author | Thomas <tb@woodcrest.local> | 2013-10-24 08:07:40 (GMT) |
---|---|---|
committer | Thomas <tb@woodcrest.local> | 2013-10-24 08:07:40 (GMT) |
commit | c8ac2064748b25b841bfa02f468dd3a6124e978e (patch) | |
tree | 37e0caf3536ec84b96bb04507b95d5d5fa1c4df3 | |
parent | fecd314fe86e48e6bf6384dd830fefccc0b53b84 (diff) | |
download | iRony-dev/caldav-scheduling.tar.gz |
First attempts to implement a schedule-inboxdev/caldav-scheduling
-rw-r--r-- | composer.json | 2 | ||||
-rw-r--r-- | lib/Kolab/CalDAV/CalendarBackend.php | 61 | ||||
-rw-r--r-- | lib/Kolab/CalDAV/Plugin.php | 42 | ||||
-rw-r--r-- | lib/Kolab/CalDAV/Schedule/Inbox.php | 257 | ||||
-rw-r--r-- | lib/Kolab/CalDAV/UserCalendars.php | 15 | ||||
-rw-r--r-- | lib/Kolab/Utils/VObjectUtils.php | 14 | ||||
-rw-r--r-- | public_html/index.php | 4 |
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 . '/'); |