Sending in Baikal 0.0.1
This commit is contained in:
parent
5a0ae13665
commit
9e028f4b59
337 changed files with 42834 additions and 0 deletions
1
Core
Symbolic link
1
Core
Symbolic link
|
@ -0,0 +1 @@
|
|||
CoreVersions/Baikal_0.1
|
95
CoreVersions/Baikal_0.1/Bootstrap.php
Normal file
95
CoreVersions/Baikal_0.1/Bootstrap.php
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2012 Jérôme Schneider <mail@jeromeschneider.fr>
|
||||
* All rights reserved
|
||||
*
|
||||
* http://baikal.codr.fr
|
||||
*
|
||||
* This script is part of the Baïkal Server project. The Baïkal
|
||||
* Server project is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script 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 General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
if(!defined("BAIKAL_CONTEXT") || BAIKAL_CONTEXT !== TRUE) {
|
||||
die("Bootstrap.php may not be included outside the Baikal context");
|
||||
}
|
||||
|
||||
if(version_compare(PHP_VERSION, '5.2.0', '<')) {
|
||||
die('Baikal Fatal Error: Baikal requires PHP 5.2.0+ to run properly. You version is: ' . PHP_VERSION . '.');
|
||||
}
|
||||
|
||||
if(!defined('PDO::ATTR_DRIVER_NAME')) {
|
||||
die('Baikal Fatal Error: PDO is unavailable. It\'s required by Baikal.');
|
||||
}
|
||||
|
||||
if(!in_array('sqlite', PDO::getAvailableDrivers())) {
|
||||
die('Baikal Fatal Error: PDO::sqlite is unavailable. It\'s required by Baikal.');
|
||||
}
|
||||
|
||||
# determine Baïkal install root path
|
||||
# adaptive, either ../../ or ../ relative to the Bootstrap
|
||||
# not using realpath here as it resolves symlinks
|
||||
|
||||
$sTemp = dirname(dirname(__FILE__)) . "/"; #../ if Baïkal distrib is at the same level than "Core" symlink
|
||||
if(@file_exists($sTemp) && (@is_dir($sTemp . "Core") || @is_link($sTemp . "Core"))) {
|
||||
define("BAIKAL_PATH_ROOT", $sTemp); # ../
|
||||
} else {
|
||||
$sTemp = dirname($sTemp) . "/"; # ../../ relative to bootstrap
|
||||
if(@file_exists($sTemp) && (@is_dir($sTemp . "Core") || @is_link($sTemp . "Core"))) {
|
||||
define("BAIKAL_PATH_ROOT", $sTemp); # ../../
|
||||
} else {
|
||||
die('Baikal Fatal Error: Unable to determine Baikal root path.');
|
||||
}
|
||||
}
|
||||
|
||||
define("BAIKAL_PATH_CORE", BAIKAL_PATH_ROOT . "Core/");
|
||||
define("BAIKAL_PATH_SPECIFIC", BAIKAL_PATH_ROOT . "Specific/");
|
||||
|
||||
require_once(BAIKAL_PATH_SPECIFIC . "config.php");
|
||||
|
||||
date_default_timezone_set(BAIKAL_TIMEZONE);
|
||||
|
||||
# Check if DB exists
|
||||
if(!file_exists(BAIKAL_SQLITE_FILE)) {
|
||||
die("DB file does not exist.<br />To create it, please copy '<b>Core/Resources/baikal.empty.sqlite</b>' to '<b>Specific/db/baikal.sqlite</b>'.<br /><span style='color: red; font-weight: bold'>Please note the change in the file name while doing so</span> (from 'baikal.empty.sqlite' to 'baikal.sqlite').");
|
||||
}
|
||||
|
||||
# Database
|
||||
$pdo = new PDO('sqlite:' . BAIKAL_SQLITE_FILE);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
# Check if at least one user exists
|
||||
if(!defined("BAIKAL_CONTEXT_CLI") || BAIKAL_CONTEXT_CLI === FALSE) {
|
||||
if(($iNbUsers = intval($pdo->query('SELECT count(*) FROM users')->fetchColumn())) === 0) {
|
||||
die("No users are defined.<br />To create a user, you can use the helper <b>Core/Scripts/adduser.php</b> (requires command line access)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!defined("BAIKAL_CONTEXT_CLI") || BAIKAL_CONTEXT_CLI === FALSE) {
|
||||
# Mapping PHP errors to exceptions
|
||||
function exception_error_handler($errno, $errstr, $errfile, $errline) {
|
||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
}
|
||||
|
||||
set_error_handler("exception_error_handler");
|
||||
} else {
|
||||
error_reporting(E_ALL ^ E_NOTICE);
|
||||
}
|
||||
|
||||
// Autoloader
|
||||
require_once(BAIKAL_PATH_SABREDAV . 'autoload.php');
|
1
CoreVersions/Baikal_0.1/Frameworks/SabreDAV
Symbolic link
1
CoreVersions/Baikal_0.1/Frameworks/SabreDAV
Symbolic link
|
@ -0,0 +1 @@
|
|||
Versions/SabreDAV.1.5.7-stable
|
636
CoreVersions/Baikal_0.1/Frameworks/Versions/SabreDAV.1.5.7-stable/ChangeLog
Executable file
636
CoreVersions/Baikal_0.1/Frameworks/Versions/SabreDAV.1.5.7-stable/ChangeLog
Executable file
|
@ -0,0 +1,636 @@
|
|||
1.5.7-stable (2012-02-19)
|
||||
* Fixed: VObject properties are now always encoded before components.
|
||||
* Fixed: Sabre_DAVACL had issues with multiple levels of privilege
|
||||
aggregration.
|
||||
* Changed: Added 'GuessContentType' plugin to fileserver.php example.
|
||||
* Fixed: The Browser plugin will now trigger the correct events when
|
||||
creating files.
|
||||
* Fixed: The ICSExportPlugin now considers ACL's.
|
||||
* Added: Made it optional to supply carddata from an Addressbook backend
|
||||
when requesting getCards. This can make some operations much faster, and
|
||||
could result in much lower memory use.
|
||||
* Fixed: Issue 187: Sabre_DAV_UUIDUtil was missing from includes file.
|
||||
* Fixed: Issue 191: beforeUnlock was triggered twice.
|
||||
|
||||
1.5.6-stable (2012-01-07)
|
||||
* Fixed: Issue 174: VObject could break UTF-8 characters.
|
||||
* Fixed: pear package installation issues.
|
||||
|
||||
1.5.5-stable (2011-12-16)
|
||||
* Fixed: CalDAV time-range filter workaround for recurring events.
|
||||
* Fixed: Bug in Sabre_DAV_Locks_Backend_File that didn't allow multiple
|
||||
files to be locked at the same time.
|
||||
|
||||
1.5.4-stable (2011-10-28)
|
||||
* Fixed: GuessContentType plugin now supports mixed case file extensions.
|
||||
* Fixed: DATE-TIME encoding was wrong in VObject. (we used 'DATETIME').
|
||||
* Changed: Sending back HTTP 204 after a PUT request on an existing resource
|
||||
instead of HTTP 200. This should fix Evolution CardDAV client
|
||||
compatibility.
|
||||
* Fixed: Issue 95: Parsing X-LIC-LOCATION if it's available.
|
||||
* Added: All VObject elements now have a reference to their parent node.
|
||||
|
||||
1.5.3-stable (2011-09-28)
|
||||
* Fixed: Sabre_DAV_Collection was missing from the includes file.
|
||||
* Fixed: Issue 152. iOS 1.4.2 apparantly requires HTTP/1.1 200 OK to be in
|
||||
uppercase.
|
||||
* Fixed: Issue 153: Support for files with mixed newline styles in
|
||||
Sabre_VObject.
|
||||
* Fixed: Issue 159: Automatically converting any vcard and icalendardata
|
||||
to UTF-8.
|
||||
* Added: Sabre_DAV_SimpleFile class for easy static file creation.
|
||||
* Added: Issue 158: Support for the CARDDAV:supported-address-data
|
||||
property.
|
||||
|
||||
1.5.2-stable (2011-09-21)
|
||||
* Fixed: carddata and calendardata MySQL fields are now of type
|
||||
'mediumblob'. 'TEXT' was too small sometimes to hold all the data.
|
||||
* Fixed: {DAV:}supported-report-set is now correctly reporting the reports
|
||||
for IAddressBook.
|
||||
* Added: Sabre_VObject_Property::add() to add duplicate parameters to
|
||||
properties.
|
||||
* Added: Issue 151: Sabre_CalDAV_ICalendar and Sabre_CalDAV_ICalendarObject
|
||||
interfaces.
|
||||
* Fixed: Issue 140: Not returning 201 Created if an event cancelled the
|
||||
creation of a file.
|
||||
* Fixed: Issue 150: Faster URLUtil::encodePath() implementation.
|
||||
* Fixed: Issue 144: Browser plugin could interfere with
|
||||
TemporaryFileFilterPlugin if it was loaded first.
|
||||
* Added: It's not possible to specify more 'alternate uris' in principal
|
||||
backends.
|
||||
|
||||
1.5.1-stable (2011-08-24)
|
||||
* Fixed: Issue 137. Hiding action interface in HTML browser for
|
||||
non-collections.
|
||||
* Fixed: addressbook-query is now correctly returned from the
|
||||
{DAV:}supported-report-set property.
|
||||
* Fixed: Issue 142: Bugs in groupwareserver.php example.
|
||||
* Fixed: Issue 139: Rejecting PUT requests with Content-Range.
|
||||
|
||||
1.5.0-stable (2011-08-12)
|
||||
* Added: CardDAV support.
|
||||
* Added: An experimental WebDAV client.
|
||||
* Added: MIME-Directory grouping support in the VObject library. This is
|
||||
very useful for people attempting to parse vcards.
|
||||
* BC Break: Adding parameters with the VObject libraries now overwrites
|
||||
the previous parameter, rather than just add it. This makes more sense
|
||||
for 99% of the cases.
|
||||
* BC Break: lib/Sabre.autoload.php is now removed in favor of
|
||||
lib/Sabre/autoload.php.
|
||||
* Deprecated: Sabre_DAV_Directory is now deprecated and will be removed in
|
||||
a future version. Use Sabre_DAV_Collection instead.
|
||||
* Deprecated: Sabre_DAV_SimpleDirectory is now deprecated and will be
|
||||
removed in a future version. Use Sabre_DAV_SimpleCollection instead.
|
||||
* Fixed: Problem with overriding tablenames for the CalDAV backend.
|
||||
* Added: Clark-notation parser to XML utility.
|
||||
* Added: unset() support to VObject components.
|
||||
* Fixed: Refactored CalDAV property fetching to be faster and simpler.
|
||||
* Added: Central string-matcher for CalDAV and CardDAV plugins.
|
||||
* Added: i;unicode-casemap support
|
||||
* Fixed: VObject bug: wouldn't parse parameters if they weren't specified
|
||||
in uppercase.
|
||||
* Fixed: VObject bug: Parameters now behave more like Properties.
|
||||
* Fixed: VObject bug: Parameters with no value are now correctly parsed.
|
||||
* Changed: If calendars don't specify which components they allow, 'all'
|
||||
components are assumed (e.g.: VEVENT, VTODO, VJOURNAL).
|
||||
* Changed: Browser plugin now uses POST variable 'sabreAction' instead of
|
||||
'action' to reduce the chance of collisions.
|
||||
|
||||
1.4.4-stable (2011-07-07)
|
||||
* Fixed: Issue 131: Custom CalDAV backends could break in certain cases.
|
||||
* Added: The option to override the default tablename all PDO backends
|
||||
use. (Issue 60).
|
||||
* Fixed: Issue 124: 'File' authentication backend now takes realm into
|
||||
consideration.
|
||||
* Fixed: Sabre_DAV_Property_HrefList now properly deserializes. This
|
||||
allows users to update the {DAV:}group-member-set property.
|
||||
* Added: Helper functions for DateTime-values in Sabre_VObject package.
|
||||
* Added: VObject library can now automatically map iCalendar properties to
|
||||
custom classes.
|
||||
|
||||
1.4.3-stable (2011-04-25)
|
||||
* Fixed: Issue 123: Added workaround for Windows 7 UNLOCK bug.
|
||||
* Fixed: datatype of lastmodified field in mysql.calendars.sql. Please
|
||||
change the DATETIME field to an INT to ensure this field will work
|
||||
correctly.
|
||||
* Change: Sabre_DAV_Property_Principal is now renamed to
|
||||
Sabre_DAVACL_Property_Principal.
|
||||
* Added: API level support for ACL HTTP method.
|
||||
* Fixed: Bug in serializing {DAV:}acl property.
|
||||
* Added: deserializer for {DAV:}resourcetype property.
|
||||
* Added: deserializer for {DAV:}acl property.
|
||||
* Added: deserializer for {DAV:}principal property.
|
||||
|
||||
1.4.2-beta (2011-04-01)
|
||||
* Added: It's not possible to disable listing of nodes that are denied
|
||||
read access by ACL.
|
||||
* Fixed: Changed a few properties in CalDAV classes from private to
|
||||
protected.
|
||||
* Fixed: Issue 119: Terrible things could happen when relying on
|
||||
guessBaseUri, the server was running on the root of the domain and a user
|
||||
tried to access a file ending in .php. This is a slight BC break.
|
||||
* Fixed: Issue 118: Lock tokens in If headers without a uri should be
|
||||
treated as the request uri, not 'all relevant uri's.
|
||||
* Fixed: Issue 120: PDO backend was incorrectly fetching too much locks in
|
||||
cases where there were similar named locked files in a directory.
|
||||
|
||||
1.4.1-beta (2011-02-26)
|
||||
* Fixed: Sabre_DAV_Locks_Backend_PDO returned too many locks.
|
||||
* Fixed: Sabre_HTTP_Request::getHeader didn't return Content-Type when
|
||||
running on apache, so a few workarounds were added.
|
||||
* Change: Slightly changed CalDAV Backend API's, to allow for heavy
|
||||
optimizations. This is non-bc breaking.
|
||||
|
||||
1.4.0-beta (2011-02-12)
|
||||
* Added: Partly RFC3744 ACL support.
|
||||
* Added: Calendar-delegation (caldav-proxy) support.
|
||||
* BC break: In order to fix Issue 99, a new argument had to be added to
|
||||
Sabre_DAV_Locks_Backend_*::getLocks classes. Consult the classes for
|
||||
details.
|
||||
* Deprecated: Sabre_DAV_Locks_Backend_FS is now deprecated and will be
|
||||
removed in a later version. Use PDO or the new File class instead.
|
||||
* Deprecated: The Sabre_CalDAV_ICalendarUtil class is now marked
|
||||
deprecated, and will be removed in a future version. Please use
|
||||
Sabre_VObject instead.
|
||||
* Removed: All principal-related functionality has been removed from the
|
||||
Sabre_DAV_Auth_Plugin, and moved to the Sabre_DAVACL_Plugin.
|
||||
* Added: VObject library, for easy vcard/icalendar parsing using a natural
|
||||
interface.
|
||||
* Added: Ability to automatically generate full .ics feeds off calendars.
|
||||
To use: Add the Sabre_CalDAV_ICSExportPlugin, and add ?export to your
|
||||
calendar url.
|
||||
* Added: Plugins can now specify a pluginname, for easy access using
|
||||
Sabre_DAV_Server::getPlugin().
|
||||
* Added: beforeGetProperties event.
|
||||
* Added: updateProperties event.
|
||||
* Added: Principal listings and calendar-access can now be done privately,
|
||||
disallowing users from accessing or modifying other users' data.
|
||||
* Added: You can now pass arrays to the Sabre_DAV_Server constructor. If
|
||||
it's an array with node-objects, a Root collection will automatically be
|
||||
created, and the nodes are used as top-level children.
|
||||
* Added: The principal base uri is now customizable. It used to be
|
||||
hardcoded to 'principals/[user]'.
|
||||
* Added: getSupportedReportSet method in ServerPlugin class. This allows
|
||||
you to easily specify which reports you're implementing.
|
||||
* Added: A '..' link to the HTML browser.
|
||||
* Fixed: Issue 99: Locks on child elements were ignored when their parent
|
||||
nodes were deleted.
|
||||
* Fixed: Issue 90: lockdiscovery property and LOCK response now include a
|
||||
{DAV}lockroot element.
|
||||
* Fixed: Issue 96: support for 'default' collation in CalDAV text-match
|
||||
filters.
|
||||
* Fixed: Issue 102: Ensuring that copy and move with identical source and
|
||||
destination uri's fails.
|
||||
* Fixed: Issue 105: Supporting MKCALENDAR with no body.
|
||||
* Fixed: Issue 109: Small fixes in Sabre_HTTP_Util.
|
||||
* Fixed: Issue 111: Properly catching the ownername in a lock (if it's a
|
||||
string)
|
||||
* Fixed: Sabre_DAV_ObjectTree::nodeExist always returned false for the
|
||||
root node.
|
||||
* Added: Global way to easily supply new resourcetypes for cetain node
|
||||
classes.
|
||||
* Fixed: Issue 59: Allowing the user to override the authentication realm
|
||||
in Sabre_CalDAV_Server.
|
||||
* Update: Issue 97: Looser time-range checking if there's a reccurrence
|
||||
rule in an event. This fixes 'missing recurring events'.
|
||||
|
||||
1.3.0 (2010-10-14)
|
||||
* Added: childExists method to Sabre_DAV_ICollection. This is an api
|
||||
break, so if you implement Sabre_DAV_ICollection directly, add the method.
|
||||
* Changed: Almost all HTTP method implementations now take a uri argument,
|
||||
including events. This allows for internal rerouting of certain calls.
|
||||
If you have custom plugins, make sure they use this argument. If they
|
||||
don't, they will likely still work, but it might get in the way of
|
||||
future changes.
|
||||
* Changed: All getETag methods MUST now surround the etag with
|
||||
double-quotes. This was a mistake made in all previous SabreDAV
|
||||
versions. If you don't do this, any If-Match, If-None-Match and If:
|
||||
headers using Etags will work incorrectly. (Issue 85).
|
||||
* Added: Sabre_DAV_Auth_Backend_AbstractBasic class, which can be used to
|
||||
easily implement basic authentication.
|
||||
* Removed: Sabre_DAV_PermissionDenied class. Use Sabre_DAV_Forbidden
|
||||
instead.
|
||||
* Removed: Sabre_DAV_IDirectory interface, use Sabre_DAV_ICollection
|
||||
instead.
|
||||
* Added: Browser plugin now uses {DAV:}displayname if this property is
|
||||
available.
|
||||
* Added: Cache layer in the ObjectTree.
|
||||
* Added: Tree classes now have a delete and getChildren method.
|
||||
* Fixed: If-Modified-Since and If-Unmodified-Since would be incorrect if
|
||||
the date is an exact match.
|
||||
* Fixed: Support for multiple ETags in If-Match and If-None-Match headers.
|
||||
* Fixed: Improved baseUrl handling.
|
||||
* Fixed: Issue 67: Non-seekable stream support in ::put()/::get().
|
||||
* Fixed: Issue 65: Invalid dates are now ignored.
|
||||
* Updated: Refactoring in Sabre_CalDAV to make everything a bit more
|
||||
ledgable.
|
||||
* Fixed: Issue 88, Issue 89: Fixed compatibility for running SabreDAV on
|
||||
Windows.
|
||||
* Fixed: Issue 86: Fixed Content-Range top-boundary from 'file size' to
|
||||
'file size'-1.
|
||||
|
||||
1.2.4 (2010-07-13)
|
||||
* Fixed: Issue 62: Guessing baseUrl fails when url contains a
|
||||
query-string.
|
||||
* Added: Apache configuration sample for CGI/FastCGI setups.
|
||||
* Fixed: Issue 64: Only returning calendar-data when it was actually
|
||||
requested.
|
||||
|
||||
1.2.3 (2010-06-26)
|
||||
* Fixed: Issue 57: Supporting quotes around etags in If-Match and
|
||||
If-None-Match
|
||||
|
||||
1.2.2 (2010-06-21)
|
||||
* Updated: SabreDAV now attempts to guess the BaseURI if it's not set.
|
||||
* Updated: Better compatibility with BitKinex
|
||||
* Fixed: Issue 56: Incorrect behaviour for If-None-Match headers and GET
|
||||
requests.
|
||||
* Fixed: Issue with certain encoded paths in Browser Plugin.
|
||||
|
||||
1.2.1 (2010-06-07)
|
||||
* Fixed: Issue 50, patch by Mattijs Hoitink.
|
||||
* Fixed: Issue 51, Adding windows 7 lockfiles to TemporaryFileFilter.
|
||||
* Fixed: Issue 38, Allowing custom filters to be added to
|
||||
TemporaryFileFilter.
|
||||
* Fixed: Issue 53, ETags in the If: header were always failing. This
|
||||
behaviour is now corrected.
|
||||
* Added: Apache Authentication backend, in case authentication through
|
||||
.htaccess is desired.
|
||||
* Updated: Small improvements to example files.
|
||||
|
||||
1.2.0 (2010-05-24)
|
||||
* Fixed: Browser plugin now displays international characters.
|
||||
* Changed: More properties in CalDAV classes are now protected instead of
|
||||
private.
|
||||
|
||||
1.2.0beta3 (2010-05-14)
|
||||
* Fixed: Custom properties were not propertly sent back for allprops
|
||||
requests.
|
||||
* Fixed: Issue 49, incorrect parsing of PROPPATCH, affecting Office 2007.
|
||||
* Changed: Removed CalDAV items from includes.php, and added a few missing
|
||||
ones.
|
||||
|
||||
1.2.0beta2 (2010-05-04)
|
||||
* Fixed: Issue 46: Fatal error for some non-existant nodes.
|
||||
* Updated: some example sql to include email address.
|
||||
* Added: 208 and 508 statuscodes from RFC5842.
|
||||
* Added: Apache2 configuration examples
|
||||
|
||||
1.2.0beta1 (2010-04-28)
|
||||
* Fixed: redundant namespace declaration in resourcetypes.
|
||||
* Fixed: 2 locking bugs triggered by litmus when no Sabre_DAV_ILockable
|
||||
interface is used.
|
||||
* Changed: using http://sabredav.org/ns for all custom xml properties.
|
||||
* Added: email address property to principals.
|
||||
* Updated: CalendarObject validation.
|
||||
|
||||
1.2.0alpha4 (2010-04-24)
|
||||
* Added: Support for If-Range, If-Match, If-None-Match, If-Modified-Since,
|
||||
If-Unmodified-Since.
|
||||
* Changed: Brand new build system. Functionality is split up between
|
||||
Sabre, Sabre_HTTP, Sabre_DAV and Sabre_CalDAV packages. In addition to
|
||||
that a new non-pear package will be created with all this functionality
|
||||
combined.
|
||||
* Changed: Autoloader moved to Sabre/autoload.php.
|
||||
* Changed: The Allow: header is now more accurate, with appropriate HTTP
|
||||
methods per uri.
|
||||
* Changed: Now throwing back Sabre_DAV_Exception_MethodNotAllowed on a few
|
||||
places where Sabre_DAV_Exception_NotImplemented was used.
|
||||
|
||||
1.2.0alpha3 (2010-04-20)
|
||||
* Update: Complete rewrite of property updating. Now easier to use and
|
||||
atomic.
|
||||
* Fixed: Issue 16, automatically adding trailing / to baseUri.
|
||||
* Added: text/plain is used for .txt files in GuessContentType plugin.
|
||||
* Added: support for principal-property-search and
|
||||
principal-search-property-set reports.
|
||||
* Added: Issue 31: Hiding exception information by default. Can be turned
|
||||
on with the Sabre_DAV_Server::$debugExceptions property.
|
||||
|
||||
1.2.0alpha2 (2010-04-08)
|
||||
* Added: Calendars are now private and can only be read by the owner.
|
||||
* Fixed: double namespace declaration in multistatus responses.
|
||||
* Added: MySQL database dumps. MySQL is now also supported next to SQLite.
|
||||
* Added: expand-properties REPORT from RFC 3253.
|
||||
* Added: Sabre_DAV_Property_IHref interface for properties exposing urls.
|
||||
* Added: Issue 25: Throwing error on broken Finder behaviour.
|
||||
* Changed: Authentication backend is now aware of current user.
|
||||
|
||||
1.2.0alpha1 (2010-03-31)
|
||||
* Fixed: Issue 26: Workaround for broken GVFS behaviour with encoded
|
||||
special characters.
|
||||
* Fixed: Issue 34: Incorrect Lock-Token response header for LOCK. Fixes
|
||||
Office 2010 compatibility.
|
||||
* Added: Issue 35: SabreDAV version to header to OPTIONS response to ease
|
||||
debugging.
|
||||
* Fixed: Issue 36: Incorrect variable name, throwing error in some
|
||||
requests.
|
||||
* Fixed: Issue 37: Incorrect smultron regex in temporary filefilter.
|
||||
* Fixed: Issue 33: Converting ISO-8859-1 characters to UTF-8.
|
||||
* Fixed: Issue 39 & Issue 40: Basename fails on non-utf-8 locales.
|
||||
* Added: More unittests.
|
||||
* Added: SabreDAV version to all error responses.
|
||||
* Added: URLUtil class for decoding urls.
|
||||
* Changed: Now using pear.sabredav.org pear channel.
|
||||
* Changed: Sabre_DAV_Server::getCopyAndMoveInfo is now a public method.
|
||||
|
||||
1.1.2-alpha (2010-03-18)
|
||||
* Added: RFC5397 - current-user-principal support.
|
||||
* Fixed: Issue 27: encoding entities in property responses.
|
||||
* Added: naturalselection script now allows the user to specify a 'minimum
|
||||
number of bytes' for deletion. This should reduce load due to less
|
||||
crawling
|
||||
* Added: Full support for the calendar-query report.
|
||||
* Added: More unittests.
|
||||
* Added: Support for complex property deserialization through the static
|
||||
::unserialize() method.
|
||||
* Added: Support for modifying calendar-component-set
|
||||
* Fixed: Issue 29: Added TIMEOUT_INFINITE constant
|
||||
|
||||
1.1.1-alpha (2010-03-11)
|
||||
* Added: RFC5689 - Extended MKCOL support.
|
||||
* Fixed: Evolution support for CalDAV.
|
||||
* Fixed: PDO-locks backend was pretty much completely broken. This is
|
||||
100% unittested now.
|
||||
* Added: support for ctags.
|
||||
* Fixed: Comma's between HTTP methods in 'Allow' method.
|
||||
* Changed: default argument for Sabre_DAV_Locks_Backend_FS. This means a
|
||||
datadirectory must always be specified from now on.
|
||||
* Changed: Moved Sabre_DAV_Server::parseProps to
|
||||
Sabre_DAV_XMLUtil::parseProperties.
|
||||
* Changed: Sabre_DAV_IDirectory is now Sabre_DAV_ICollection.
|
||||
* Changed: Sabre_DAV_Exception_PermissionDenied is now
|
||||
Sabre_DAV_Exception_Forbidden.
|
||||
* Changed: Sabre_CalDAV_ICalendarCollection is removed.
|
||||
* Added: Sabre_DAV_IExtendedCollection.
|
||||
* Added: Many more unittests.
|
||||
* Added: support for calendar-timezone property.
|
||||
|
||||
1.1.0-alpha (2010-03-01)
|
||||
* Added: CalDAV - RFC 4791
|
||||
* Removed: Sabre_PHP_Exception. PHP has a built-in ErrorException for
|
||||
this.
|
||||
* Added: PDO authentication backend.
|
||||
* Added: Example sql for auth, caldav, locks for sqlite.
|
||||
* Added: Sabre_DAV_Browser_GuessContentType plugin
|
||||
* Changed: Authentication plugin refactored, making it possible to
|
||||
implement non-digest authentication.
|
||||
* Fixed: Better error display in browser plugin.
|
||||
* Added: Support for {DAV:}supported-report-set
|
||||
* Added: XML utility class with helper functions for the WebDAV protocol.
|
||||
* Added: Tons of unittests
|
||||
* Added: PrincipalCollection and Principal classes
|
||||
* Added: Sabre_DAV_Server::getProperties for easy property retrieval
|
||||
* Changed: {DAV:}resourceType defaults to 0
|
||||
* Changed: Any non-null resourceType now gets a / appended to the href
|
||||
value. Before this was just for {DAV:}collection's, but this is now also
|
||||
the case for for example {DAV:}principal.
|
||||
* Changed: The Href property class can now optionally create non-relative
|
||||
uri's.
|
||||
* Changed: Sabre_HTTP_Response now returns false if headers are already
|
||||
sent and header-methods are called.
|
||||
* Fixed: Issue 19: HEAD requests on Collections
|
||||
* Fixed: Issue 21: Typo in Sabre_DAV_Property_Response
|
||||
* Fixed: Issue 18: Doesn't work with Evolution Contacts
|
||||
|
||||
1.0.5-stable (2010-01-22)
|
||||
* Fixed: Fatal error when a malformed url was used for unlocking, in
|
||||
conjuction with Sabre.autoload.php due to a incorrect filename.
|
||||
* Fixed: Improved unittests and build system
|
||||
|
||||
1.0.4-stable (2010-01-11)
|
||||
* Fixed: needed 2 different releases. One for googlecode and one for
|
||||
pearfarm. This is to retain the old method to install SabreDAV until
|
||||
pearfarm becomes the standard installation method.
|
||||
|
||||
1.0.3-stable (2010-01-11)
|
||||
* Added: RFC4709 support (davmount)
|
||||
* Added: 6 unittests
|
||||
* Added: naturalselection. A tool to keep cache directories below a
|
||||
specified theshold.
|
||||
* Changed: Now using pearfarm.org channel server.
|
||||
|
||||
1.0.1-stable (2009-12-22)
|
||||
* Fixed: Issue 15: typos in examples
|
||||
* Fixed: Minor pear installation issues
|
||||
|
||||
1.0.0-stable (2009-11-02)
|
||||
* Added: SimpleDirectory class. This class allows creating static
|
||||
directory structures with ease.
|
||||
* Changed: Custom complex properties and exceptions now get an instance of
|
||||
Sabre_DAV_Server as their first argument in serialize()
|
||||
* Changed: Href complex property now prepends server's baseUri
|
||||
* Changed: delete before an overwriting copy/move is now handles by server
|
||||
class instead of tree classes
|
||||
* Changed: events must now explicitly return false to stop execution.
|
||||
Before, execution would be stopped by anything loosely evaluating to
|
||||
false.
|
||||
* Changed: the getPropertiesForPath method now takes a different set of
|
||||
arguments, and returns a different response. This allows plugin
|
||||
developers to return statuses for properties other than 200 and 404. The
|
||||
hrefs are now also always calculated relative to the baseUri, and not
|
||||
the uri of the request.
|
||||
* Changed: generatePropFindResponse is renamed to generateMultiStatus, and
|
||||
now takes a list of properties similar to the response of
|
||||
getPropertiesForPath. This was also needed to improve flexibility for
|
||||
plugin development.
|
||||
* Changed: Auth plugins are no longer included. They were not yet stable
|
||||
quality, so they will probably be reintroduced in a later version.
|
||||
* Changed: PROPPATCH also used generateMultiStatus now.
|
||||
* Removed: unknownProperties event. This is replaced by the
|
||||
afterGetProperties event, which should provide more flexibility.
|
||||
* Fixed: Only calling getSize() on IFile instances in httpHead()
|
||||
* Added: beforeBind event. This is invoked upon file or directory creation
|
||||
* Added: beforeWriteContent event, this is invoked by PUT and LOCK on an
|
||||
existing resource.
|
||||
* Added: beforeUnbind event. This is invoked right before deletion of any
|
||||
resource.
|
||||
* Added: afterGetProperties event. This event can be used to make
|
||||
modifications to property responses.
|
||||
* Added: beforeLock and beforeUnlock events.
|
||||
* Added: afterBind event.
|
||||
* Fixed: Copy and Move could fail in the root directory. This is now
|
||||
fixed.
|
||||
* Added: Plugins can now be retrieved by their classname. This is useful
|
||||
for inter-plugin communication.
|
||||
* Added: The Auth backend can now return usernames and user-id's.
|
||||
* Added: The Auth backend got a getUsers method
|
||||
* Added: Sabre_DAV_FSExt_Directory now returns quota info
|
||||
|
||||
0.12.1-beta (2009-09-11)
|
||||
* Fixed: UNLOCK bug. Unlock didn't work at all
|
||||
|
||||
0.12-beta (2009-09-10)
|
||||
* Updated: Browser plugin now shows multiple {DAV:}resourcetype values
|
||||
if available.
|
||||
* Added: Experimental PDO backend for Locks Manager
|
||||
* Fixed: Sending Content-Length: 0 for every empty response. This
|
||||
improves NGinx compatibility.
|
||||
* Fixed: Last modification time is reported in UTC timezone. This improves
|
||||
Finder compatibility.
|
||||
|
||||
0.11-beta (2009-08-11)
|
||||
* Updated: Now in Beta
|
||||
* Updated: Pear package no longer includes docs/ directory. These just
|
||||
contained rfc's, which are publically available. This reduces the
|
||||
package from ~800k to ~60k
|
||||
* Added: generatePropfindResponse now takes a baseUri argument
|
||||
* Added: ResourceType property can now contain multiple resourcetypes.
|
||||
* Fixed: Issue 13.
|
||||
|
||||
0.10-alpha (2009-08-03)
|
||||
* Added: Plugin to automatically map GET requests to non-files to
|
||||
PROPFIND (Sabre_DAV_Browser_MapGetToPropFind). This should allow
|
||||
easier debugging of complicated WebDAV setups.
|
||||
* Added: Sabre_DAV_Property_Href class. For future use.
|
||||
* Added: Ability to choose to use auth-int, auth or both for HTTP Digest
|
||||
authentication. (Issue 11)
|
||||
* Changed: Made more methods in Sabre_DAV_Server public.
|
||||
* Fixed: TemporaryFileFilter plugin now intercepts HTTP LOCK requests
|
||||
to non-existant files. (Issue 12)
|
||||
* Added: Central list of defined xml namespace prefixes. This can reduce
|
||||
Bandwidth and legibility for xml bodies with user-defined namespaces.
|
||||
* Added: now a PEAR-compatible package again, thanks to Michael Gauthier
|
||||
* Changed: moved default copy and move logic from ObjectTree to Tree class
|
||||
|
||||
0.9-alpha (2009-07-21)
|
||||
* Changed: Major refactoring, removed most of the logic from the Tree
|
||||
objects. The Server class now directly works with the INode, IFile
|
||||
and IDirectory objects. If you created your own Tree objects,
|
||||
this will most likely break in this release.
|
||||
* Changed: Moved all the Locking logic from the Tree and Server classes
|
||||
into a separate plugin.
|
||||
* Changed: TemporaryFileFilter is now a plugin.
|
||||
* Added: Comes with an autoloader script. This can be used instead of
|
||||
the includer script, and is preferered by some people.
|
||||
* Added: AWS Authentication class.
|
||||
* Added: simpleserversetup.py script. This will quickly get a fileserver
|
||||
up and running.
|
||||
* Added: When subscribing to events, it is now possible to supply a
|
||||
priority. This is for example needed to ensure that the Authentication
|
||||
Plugin is used before any other Plugin.
|
||||
* Added: 22 new tests.
|
||||
* Added: Users-manager plugin for .htdigest files. Experimental and
|
||||
subject to change.
|
||||
* Added: RFC 2324 HTTP 418 status code
|
||||
* Fixed: Exclusive locks could in some cases be picked up as shared locks
|
||||
* Fixed: Digest auth for non-apache servers had a bug (still not actually
|
||||
tested this well).
|
||||
|
||||
0.8-alpha (2009-05-30)
|
||||
* Changed: Renamed all exceptions! This is a compatibility break. Every
|
||||
Exception now follows Sabre_DAV_Exception_FileNotFound convention
|
||||
instead of Sabre_DAV_FileNotFoundException.
|
||||
* Added: Browser plugin now allows uploading and creating directories
|
||||
straight from the browser.
|
||||
* Added: 12 more unittests
|
||||
* Fixed: Locking bug, which became prevalent on Windows Vista.
|
||||
* Fixed: Netdrive support
|
||||
* Fixed: TemporaryFileFilter filtered out too many files. Fixed some
|
||||
of the regexes.
|
||||
* Fixed: Added README and ChangeLog to package
|
||||
|
||||
0.7-alpha (2009-03-29)
|
||||
* Added: System to return complex properties from PROPFIND.
|
||||
* Added: support for {DAV:}supportedlock.
|
||||
* Added: support for {DAV:}lockdiscovery.
|
||||
* Added: 6 new tests.
|
||||
* Added: New plugin system.
|
||||
* Added: Simple HTML directory plugin, for browser access.
|
||||
* Added: Server class now sends back standard pre-condition error xml
|
||||
bodies. This was new since RFC4918.
|
||||
* Added: Sabre_DAV_Tree_Aggregrate, which can 'host' multiple Tree objects
|
||||
into one.
|
||||
* Added: simple basis for HTTP REPORT method. This method is not used yet,
|
||||
but can be used by plugins to add reports.
|
||||
* Changed: ->getSize is only called for files, no longer for collections.
|
||||
r303
|
||||
* Changed: Sabre_DAV_FilterTree is now Sabre_DAV_Tree_Filter
|
||||
* Changed: Sabre_DAV_TemporaryFileFilter is now called
|
||||
Sabre_DAV_Tree_TemporaryFileFilter.
|
||||
* Changed: removed functions (get(/set)HTTPRequest(/Response)) from Server
|
||||
class, and using a public property instead.
|
||||
* Fixed: bug related to parsing proppatch and propfind requests. Didn't
|
||||
show up in most clients, but it needed fixing regardless. (r255)
|
||||
* Fixed: auth-int is now properly supported within HTTP Digest.
|
||||
* Fixed: Using application/xml for a mimetype vs. text/xml as per RFC4918
|
||||
sec 8.2.
|
||||
* Fixed: TemporaryFileFilter now lets through GET's if they actually
|
||||
exist on the backend. (r274)
|
||||
* FIxed: Some methods didn't get passed through in the FilterTree (r283).
|
||||
* Fixed: LockManager is now slightly more complex, Tree classes slightly
|
||||
less. (r287)
|
||||
|
||||
0.6-alpha (2009-02-16)
|
||||
* Added: Now uses streams for files, instead of strings.
|
||||
This means it won't require to hold entire files in memory, which can be
|
||||
an issue if you're dealing with big files. Note that this breaks
|
||||
compatibility for put() and createFile methods.
|
||||
* Added: HTTP Digest Authentication helper class.
|
||||
* Added: Support for HTTP Range header
|
||||
* Added: Support for ETags within If: headers
|
||||
* Added: The API can now return ETags and override the default Content-Type
|
||||
* Added: starting with basic framework for unittesting, using PHPUnit.
|
||||
* Added: 49 unittests.
|
||||
* Added: Abstraction for the HTTP request.
|
||||
* Updated: Using Clark Notation for tags in properties. This means tags
|
||||
are serialized as {namespace}tagName instead of namespace#tagName
|
||||
* Fixed: HTTP_BasicAuth class now works as expected.
|
||||
* Fixed: DAV_Server uses / for a default baseUrl.
|
||||
* Fixed: Last modification date is no longer ignored in PROPFIND.
|
||||
* Fixed: PROPFIND now sends back information about the requestUri even
|
||||
when "Depth: 1" is specified.
|
||||
|
||||
0.5-alpha (2009-01-14)
|
||||
* Added: Added a very simple example for implementing a mapping to PHP
|
||||
file streams. This should allow easy implementation of for example a
|
||||
WebDAV to FTP proxy.
|
||||
* Added: HTTP Basic Authentication helper class.
|
||||
* Added: Sabre_HTTP_Reponse class. This centralizes HTTP operations and
|
||||
will be a start towards the creating of a testing framework.
|
||||
* Updated: Backwards compatibility break: all require_once() statements
|
||||
are removed
|
||||
from all the files. It is now recommended to use autoloading of
|
||||
classes, or just including lib/Sabre.includes.php. This fix was made
|
||||
to allow easier integration into applications not using this standard
|
||||
inclusion model.
|
||||
* Updated: Better in-file documentation.
|
||||
* Updated: Sabre_DAV_Tree can now work with Sabre_DAV_LockManager.
|
||||
* Updated: Fixes a shared-lock bug.
|
||||
* Updated: Removed ?> from the bottom of each php file.
|
||||
* Updated: Split up some operations from Sabre_DAV_Server to
|
||||
Sabre_HTTP_Response.
|
||||
* Fixed: examples are now actually included in the pear package.
|
||||
|
||||
0.4-alpha (2008-11-05)
|
||||
* Passes all litmus tests!
|
||||
* Added: more examples
|
||||
* Added: Custom property support
|
||||
* Added: Shared lock support
|
||||
* Added: Depth support to locks
|
||||
* Added: Locking on unmapped urls (non-existant nodes)
|
||||
* Fixed: Advertising as WebDAV class 3 support
|
||||
|
||||
0.3-alpha (2008-06-29)
|
||||
* Fully working in MS Windows clients.
|
||||
* Added: temporary file filter: support for smultron files.
|
||||
* Added: Phing build scripts
|
||||
* Added: PEAR package
|
||||
* Fixed: MOVE bug identied using finder.
|
||||
* Fixed: Using gzuncompress instead of gzdecode in the temporary file
|
||||
filter. This seems more common.
|
||||
|
||||
0.2-alpha (2008-05-27)
|
||||
* Somewhat working in Windows clients
|
||||
* Added: Working PROPPATCH method (doesn't support custom properties yet)
|
||||
* Added: Temporary filename handling system
|
||||
* Added: Sabre_DAV_IQuota to return quota information
|
||||
* Added: PROPFIND now reads the request body and only supplies the
|
||||
requested properties
|
||||
|
||||
0.1-alpha (2008-04-04)
|
||||
* First release!
|
||||
* Passes litmus: basic, http and copymove test.
|
||||
* Fully working in Finder and DavFSv2
|
||||
|
||||
Project started: 2007-12-13
|
28
CoreVersions/Baikal_0.1/Frameworks/Versions/SabreDAV.1.5.7-stable/LICENSE
Executable file
28
CoreVersions/Baikal_0.1/Frameworks/Versions/SabreDAV.1.5.7-stable/LICENSE
Executable file
|
@ -0,0 +1,28 @@
|
|||
Copyright (C) 2007-2012 Rooftop Solutions.
|
||||
Copyright (C) 2007-2009 FileMobile inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the SabreDAV nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,140 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2009-2010 Evert Pot
|
||||
# All rights reserved.
|
||||
# http://www.rooftopsolutions.nl/
|
||||
#
|
||||
# This utility is distributed along with SabreDAV
|
||||
# license: http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
|
||||
import os
|
||||
from optparse import OptionParser
|
||||
import time
|
||||
|
||||
def getfreespace(path):
|
||||
stat = os.statvfs(path)
|
||||
return stat.f_frsize * stat.f_bavail
|
||||
|
||||
def getbytesleft(path,treshold):
|
||||
return getfreespace(path)-treshold
|
||||
|
||||
def run(cacheDir, treshold, sleep=5, simulate=False, min_erase = 0):
|
||||
|
||||
bytes = getbytesleft(cacheDir,treshold)
|
||||
if (bytes>0):
|
||||
print "Bytes to go before we hit treshhold:", bytes
|
||||
else:
|
||||
print "Treshold exceeded with:", -bytes, "bytes"
|
||||
dir = os.listdir(cacheDir)
|
||||
dir2 = []
|
||||
for file in dir:
|
||||
path = cacheDir + '/' + file
|
||||
dir2.append({
|
||||
"path" : path,
|
||||
"atime": os.stat(path).st_atime,
|
||||
"size" : os.stat(path).st_size
|
||||
})
|
||||
|
||||
dir2.sort(lambda x,y: int(x["atime"]-y["atime"]))
|
||||
|
||||
filesunlinked = 0
|
||||
gainedspace = 0
|
||||
|
||||
# Left is the amount of bytes that need to be freed up
|
||||
# The default is the 'min_erase setting'
|
||||
left = min_erase
|
||||
|
||||
# If the min_erase setting is lower than the amount of bytes over
|
||||
# the treshold, we use that number instead.
|
||||
if left < -bytes :
|
||||
left = -bytes
|
||||
|
||||
print "Need to delete at least:", left;
|
||||
|
||||
for file in dir2:
|
||||
|
||||
# Only deleting files if we're not simulating
|
||||
if not simulate: os.unlink(file["path"])
|
||||
left = int(left - file["size"])
|
||||
gainedspace = gainedspace + file["size"]
|
||||
filesunlinked = filesunlinked + 1
|
||||
|
||||
if(left<0):
|
||||
break
|
||||
|
||||
print "%d files deleted (%d bytes)" % (filesunlinked, gainedspace)
|
||||
|
||||
|
||||
time.sleep(sleep)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
parser = OptionParser(
|
||||
version="naturalselecton v0.3",
|
||||
description="Cache directory manager. Deletes cache entries based on accesstime and free space tresholds.\n" +
|
||||
"This utility is distributed alongside SabreDAV.",
|
||||
usage="usage: %prog [options] cacheDirectory",
|
||||
)
|
||||
parser.add_option(
|
||||
'-s',
|
||||
dest="simulate",
|
||||
action="store_true",
|
||||
help="Don't actually make changes, but just simulate the behaviour",
|
||||
)
|
||||
parser.add_option(
|
||||
'-r','--runs',
|
||||
help="How many times to check before exiting. -1 is infinite, which is the default",
|
||||
type="int",
|
||||
dest="runs",
|
||||
default=-1
|
||||
)
|
||||
parser.add_option(
|
||||
'-n','--interval',
|
||||
help="Sleep time in seconds (default = 5)",
|
||||
type="int",
|
||||
dest="sleep",
|
||||
default=5
|
||||
)
|
||||
parser.add_option(
|
||||
'-l','--treshold',
|
||||
help="Treshhold in bytes (default = 10737418240, which is 10GB)",
|
||||
type="int",
|
||||
dest="treshold",
|
||||
default=10737418240
|
||||
)
|
||||
parser.add_option(
|
||||
'-m', '--min-erase',
|
||||
help="Minimum number of bytes to erase when the treshold is reached. " +
|
||||
"Setting this option higher will reduce the amount of times the cache directory will need to be scanned. " +
|
||||
"(the default is 1073741824, which is 1GB.)",
|
||||
type="int",
|
||||
dest="min_erase",
|
||||
default=1073741824
|
||||
)
|
||||
|
||||
options,args = parser.parse_args()
|
||||
if len(args)<1:
|
||||
parser.error("This utility requires at least 1 argument")
|
||||
cacheDir = args[0]
|
||||
|
||||
print "Natural Selection"
|
||||
print "Cache directory:", cacheDir
|
||||
free = getfreespace(cacheDir);
|
||||
print "Current free disk space:", free
|
||||
|
||||
runs = options.runs;
|
||||
while runs!=0 :
|
||||
run(
|
||||
cacheDir,
|
||||
sleep=options.sleep,
|
||||
simulate=options.simulate,
|
||||
treshold=options.treshold,
|
||||
min_erase=options.min_erase
|
||||
)
|
||||
if runs>0:
|
||||
runs = runs - 1
|
||||
|
||||
if __name__ == '__main__' :
|
||||
main()
|
|
@ -0,0 +1 @@
|
|||
jerome:Domaine:69b58669c7c355c2a7c85395b27421b5
|
|
@ -0,0 +1 @@
|
|||
../lib/Sabre
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|
||||
Addressbook/CardDAV server example
|
||||
|
||||
This server features CardDAV support
|
||||
|
||||
*/
|
||||
|
||||
// settings
|
||||
date_default_timezone_set('Canada/Eastern');
|
||||
|
||||
// Make sure this setting is turned on and reflect the root url for your WebDAV server.
|
||||
// This can be for example the root / or a complete path to your server script
|
||||
$baseUri = '/';
|
||||
|
||||
/* Database */
|
||||
$pdo = new PDO('sqlite:data/db.sqlite');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
//Mapping PHP errors to exceptions
|
||||
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
|
||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
}
|
||||
set_error_handler("exception_error_handler");
|
||||
|
||||
// Autoloader
|
||||
require_once 'lib/Sabre/autoload.php';
|
||||
|
||||
// Backends
|
||||
$authBackend = new Sabre_DAV_Auth_Backend_PDO($pdo);
|
||||
$principalBackend = new Sabre_DAVACL_PrincipalBackend_PDO($pdo);
|
||||
$carddavBackend = new Sabre_CardDAV_Backend_PDO($pdo);
|
||||
//$caldavBackend = new Sabre_CalDAV_Backend_PDO($pdo);
|
||||
|
||||
// Setting up the directory tree //
|
||||
$nodes = array(
|
||||
new Sabre_DAVACL_PrincipalCollection($principalBackend),
|
||||
// new Sabre_CalDAV_CalendarRootNode($authBackend, $caldavBackend),
|
||||
new Sabre_CardDAV_AddressBookRoot($principalBackend, $carddavBackend),
|
||||
);
|
||||
|
||||
// The object tree needs in turn to be passed to the server class
|
||||
$server = new Sabre_DAV_Server($nodes);
|
||||
$server->setBaseUri($baseUri);
|
||||
|
||||
// Plugins
|
||||
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend,'SabreDAV'));
|
||||
$server->addPlugin(new Sabre_DAV_Browser_Plugin());
|
||||
//$server->addPlugin(new Sabre_CalDAV_Plugin());
|
||||
$server->addPlugin(new Sabre_CardDAV_Plugin());
|
||||
$server->addPlugin(new Sabre_DAVACL_Plugin());
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
// !!!! Make sure the Sabre directory is in the include_path !!!
|
||||
// example:
|
||||
// set_include_path('lib/' . PATH_SEPARATOR . get_include_path());
|
||||
|
||||
// settings
|
||||
date_default_timezone_set('Canada/Eastern');
|
||||
|
||||
// Files we need
|
||||
require_once 'Sabre/autoload.php';
|
||||
|
||||
$u = 'admin';
|
||||
$p = '1234';
|
||||
|
||||
$auth = new Sabre_HTTP_BasicAuth();
|
||||
|
||||
$result = $auth->getUserPass();
|
||||
|
||||
if (!$result || $result[0]!=$u || $result[1]!=$p) {
|
||||
|
||||
$auth->requireLogin();
|
||||
echo "Authentication required\n";
|
||||
die();
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|
||||
CalendarServer example
|
||||
|
||||
This server features CalDAV support
|
||||
|
||||
*/
|
||||
|
||||
// settings
|
||||
date_default_timezone_set('Canada/Eastern');
|
||||
|
||||
// If you want to run the SabreDAV server in a custom location (using mod_rewrite for instance)
|
||||
// You can override the baseUri here.
|
||||
// $baseUri = '/';
|
||||
|
||||
/* Database */
|
||||
$pdo = new PDO('sqlite:data/db.sqlite');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
//Mapping PHP errors to exceptions
|
||||
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
|
||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
}
|
||||
set_error_handler("exception_error_handler");
|
||||
|
||||
// Files we need
|
||||
require_once 'lib/Sabre/autoload.php';
|
||||
|
||||
// The 'caldav server' only needs the pdo object. Note that if you plan to
|
||||
// extend the server in any way, you'll probably don't want to use
|
||||
// Sabre_CalDAV_Server, but plain Sabre_DAV_Server instead.
|
||||
// You'll need to add your own nodes and plugins manually then.
|
||||
$server = new Sabre_CalDAV_Server($pdo);
|
||||
|
||||
if (isset($baseUri))
|
||||
$server->setBaseUri($baseUri);
|
||||
|
||||
// Support for html frontend
|
||||
$browser = new Sabre_DAV_Browser_Plugin();
|
||||
$server->addPlugin($browser);
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
// !!!! Make sure the Sabre directory is in the include_path !!!
|
||||
// example:
|
||||
// set_include_path('lib/' . PATH_SEPARATOR . get_include_path());
|
||||
|
||||
// settings
|
||||
date_default_timezone_set('Canada/Eastern');
|
||||
|
||||
// Files we need
|
||||
require_once 'Sabre/autoload.php';
|
||||
|
||||
$u = 'admin';
|
||||
$p = '1234';
|
||||
|
||||
$auth = new Sabre_HTTP_DigestAuth();
|
||||
$auth->init();
|
||||
|
||||
if ($auth->getUsername() != $u || !$auth->validatePassword($p)) {
|
||||
|
||||
$auth->requireLogin();
|
||||
echo "Authentication required\n";
|
||||
die();
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
// !!!! Make sure the Sabre directory is in the include_path !!!
|
||||
// example:
|
||||
set_include_path('lib/' . PATH_SEPARATOR . get_include_path());
|
||||
|
||||
/*
|
||||
|
||||
This is the best starting point if you're just interested in setting up a fileserver.
|
||||
|
||||
Make sure that the 'public' and 'tmpdata' exists, with write permissions
|
||||
for your server.
|
||||
|
||||
*/
|
||||
|
||||
// settings
|
||||
date_default_timezone_set('Canada/Eastern');
|
||||
$publicDir = 'public';
|
||||
$tmpDir = 'tmpdata';
|
||||
|
||||
// If you want to run the SabreDAV server in a custom location (using mod_rewrite for instance)
|
||||
// You can override the baseUri here.
|
||||
// $baseUri = '/';
|
||||
|
||||
|
||||
// Files we need
|
||||
require_once 'Sabre/autoload.php';
|
||||
|
||||
// Create the root node
|
||||
$root = new Sabre_DAV_FS_Directory($publicDir);
|
||||
|
||||
// The rootnode needs in turn to be passed to the server class
|
||||
$server = new Sabre_DAV_Server($root);
|
||||
|
||||
if (isset($baseUri))
|
||||
$server->setBaseUri($baseUri);
|
||||
|
||||
// Support for LOCK and UNLOCK
|
||||
$lockBackend = new Sabre_DAV_Locks_Backend_File($tmpDir . '/locksdb');
|
||||
$lockPlugin = new Sabre_DAV_Locks_Plugin($lockBackend);
|
||||
$server->addPlugin($lockPlugin);
|
||||
|
||||
// Support for html frontend
|
||||
$browser = new Sabre_DAV_Browser_Plugin();
|
||||
$server->addPlugin($browser);
|
||||
|
||||
// Automatically guess (some) contenttypes, based on extesion
|
||||
$server->addPlugin(new Sabre_DAV_Browser_GuessContentType());
|
||||
|
||||
// Authentication backend
|
||||
$authBackend = new Sabre_DAV_Auth_Backend_File('.htdigest');
|
||||
$auth = new Sabre_DAV_Auth_Plugin($authBackend,'SabreDAV');
|
||||
$server->addPlugin($auth);
|
||||
|
||||
// Temporary file filter
|
||||
$tempFF = new Sabre_DAV_TemporaryFileFilterPlugin($tmpDir);
|
||||
$server->addPlugin($tempFF);
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This server combines both CardDAV and CalDAV functionality into a single
|
||||
* server. It is assumed that the server runs at the root of a HTTP domain (be
|
||||
* that a domainname-based vhost or a specific TCP port.
|
||||
*
|
||||
* This example also assumes that you're using SQLite and the database has
|
||||
* already been setup (along with the database tables).
|
||||
*
|
||||
* You may choose to use MySQL instead, just change the PDO connection
|
||||
* statement.
|
||||
*/
|
||||
|
||||
/**
|
||||
* UTC or GMT is easy to work with, and usually recommended for any
|
||||
* application.
|
||||
*/
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
/**
|
||||
* Make sure this setting is turned on and reflect the root url for your WebDAV
|
||||
* server.
|
||||
*
|
||||
* This can be for example the root / or a complete path to your server script.
|
||||
*/
|
||||
$baseUri = '/';
|
||||
|
||||
/**
|
||||
* Database
|
||||
*
|
||||
* Feel free to switch this to MySQL, it will definitely be better for higher
|
||||
* concurrency.
|
||||
*/
|
||||
$pdo = new PDO('sqlite:data/db.sqlite');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
// Autoloader
|
||||
require_once 'lib/Sabre/autoload.php';
|
||||
|
||||
/**
|
||||
* The backends. Yes we do really need all of them.
|
||||
*
|
||||
* This allows any developer to subclass just any of them and hook into their
|
||||
* own backend systems.
|
||||
*/
|
||||
$authBackend = new Sabre_DAV_Auth_Backend_PDO($pdo);
|
||||
$principalBackend = new Sabre_DAVACL_PrincipalBackend_PDO($pdo);
|
||||
$carddavBackend = new Sabre_CardDAV_Backend_PDO($pdo);
|
||||
$caldavBackend = new Sabre_CalDAV_Backend_PDO($pdo);
|
||||
|
||||
/**
|
||||
* The directory tree
|
||||
*
|
||||
* Basically this is an array which contains the 'top-level' directories in the
|
||||
* WebDAV server.
|
||||
*/
|
||||
$nodes = array(
|
||||
// /principals
|
||||
new Sabre_CalDAV_Principal_Collection($principalBackend),
|
||||
// /calendars
|
||||
new Sabre_CalDAV_CalendarRootNode($principalBackend, $caldavBackend),
|
||||
// /addressbook
|
||||
new Sabre_CardDAV_AddressBookRoot($principalBackend, $carddavBackend),
|
||||
);
|
||||
|
||||
// The object tree needs in turn to be passed to the server class
|
||||
$server = new Sabre_DAV_Server($nodes);
|
||||
$server->setBaseUri($baseUri);
|
||||
|
||||
// Plugins
|
||||
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend,'SabreDAV'));
|
||||
$server->addPlugin(new Sabre_DAV_Browser_Plugin());
|
||||
$server->addPlugin(new Sabre_CalDAV_Plugin());
|
||||
$server->addPlugin(new Sabre_CardDAV_Plugin());
|
||||
$server->addPlugin(new Sabre_DAVACL_Plugin());
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
// !!!! Make sure the Sabre directory is in the include_path !!!
|
||||
// example:
|
||||
// set_include_path('lib/' . PATH_SEPARATOR . get_include_path());
|
||||
|
||||
/*
|
||||
|
||||
This example demonstrates a simple way to create your own virtual filesystems.
|
||||
By extending the _File and Directory classes, you can easily create a tree
|
||||
based on various datasources.
|
||||
|
||||
The most obvious example is the filesystem itself. A more complete and documented
|
||||
example can be found in:
|
||||
|
||||
lib/Sabre/DAV/FS/Node.php
|
||||
lib/Sabre/DAV/FS/Directory.php
|
||||
lib/Sabre/DAV/FS/File.php
|
||||
|
||||
*/
|
||||
|
||||
// settings
|
||||
date_default_timezone_set('Canada/Eastern');
|
||||
$publicDir = 'public';
|
||||
|
||||
// Files we need
|
||||
require_once 'Sabre/autoload.php';
|
||||
|
||||
class MyDirectory extends Sabre_DAV_Directory {
|
||||
|
||||
private $myPath;
|
||||
|
||||
function __construct($myPath) {
|
||||
|
||||
$this->myPath = $myPath;
|
||||
|
||||
}
|
||||
|
||||
function getChildren() {
|
||||
|
||||
$children = array();
|
||||
// Loop through the directory, and create objects for each node
|
||||
foreach(scandir($this->myPath) as $node) {
|
||||
|
||||
// Ignoring files staring with .
|
||||
if ($node[0]==='.') continue;
|
||||
|
||||
$children[] = $this->getChild($node);
|
||||
|
||||
}
|
||||
|
||||
return $children;
|
||||
|
||||
}
|
||||
|
||||
function getChild($name) {
|
||||
|
||||
$path = $this->myPath . '/' . $name;
|
||||
|
||||
// We have to throw a FileNotFound exception if the file didn't exist
|
||||
if (!file_exists($this->myPath)) throw new Sabre_DAV_Exception_FileNotFound('The file with name: ' . $name . ' could not be found');
|
||||
// Some added security
|
||||
|
||||
if ($name[0]=='.') throw new Sabre_DAV_Exception_FileNotFound('Access denied');
|
||||
|
||||
if (is_dir($path)) {
|
||||
|
||||
return new MyDirectory($name);
|
||||
|
||||
} else {
|
||||
|
||||
return new MyFile($path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getName() {
|
||||
|
||||
return basename($this->myPath);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MyFile extends Sabre_DAV_File {
|
||||
|
||||
private $myPath;
|
||||
|
||||
function __construct($myPath) {
|
||||
|
||||
$this->myPath = $myPath;
|
||||
|
||||
}
|
||||
|
||||
function getName() {
|
||||
|
||||
return basename($this->myPath);
|
||||
|
||||
}
|
||||
|
||||
function get() {
|
||||
|
||||
return fopen($this->myPath,'r');
|
||||
|
||||
}
|
||||
|
||||
function getSize() {
|
||||
|
||||
return filesize($this->myPath);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure there is a directory in your current directory named 'public'. We will be exposing that directory to WebDAV
|
||||
$rootNode = new MyDirectory($publicDir);
|
||||
|
||||
// The rootNode needs to be passed to the server object.
|
||||
$server = new Sabre_DAV_Server($rootNode);
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
||||
|
||||
?>
|
|
@ -0,0 +1,17 @@
|
|||
CREATE TABLE addressbooks (
|
||||
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
principaluri VARCHAR(255),
|
||||
displayname VARCHAR(255),
|
||||
uri VARCHAR(100),
|
||||
description TEXT,
|
||||
ctag INT(11) UNSIGNED NOT NULL DEFAULT '1'
|
||||
);
|
||||
|
||||
CREATE TABLE cards (
|
||||
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
addressbookid INT(11) UNSIGNED NOT NULL,
|
||||
carddata MEDIUMBLOB,
|
||||
uri VARCHAR(100),
|
||||
lastmodified INT(11) UNSIGNED
|
||||
);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE calendarobjects (
|
||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
calendardata MEDIUMBLOB,
|
||||
uri VARCHAR(100),
|
||||
calendarid INTEGER UNSIGNED NOT NULL,
|
||||
lastmodified INT(11)
|
||||
);
|
||||
|
||||
CREATE TABLE calendars (
|
||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
principaluri VARCHAR(100),
|
||||
displayname VARCHAR(100),
|
||||
uri VARCHAR(100),
|
||||
ctag INTEGER UNSIGNED NOT NULL DEFAULT '0',
|
||||
description TEXT,
|
||||
calendarorder INTEGER UNSIGNED NOT NULL DEFAULT '0',
|
||||
calendarcolor VARCHAR(10),
|
||||
timezone TEXT,
|
||||
components VARCHAR(20)
|
||||
);
|
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE locks (
|
||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
owner VARCHAR(100),
|
||||
timeout INTEGER UNSIGNED,
|
||||
created INTEGER,
|
||||
token VARCHAR(100),
|
||||
scope TINYINT,
|
||||
depth TINYINT,
|
||||
uri text
|
||||
);
|
|
@ -0,0 +1,21 @@
|
|||
CREATE TABLE principals (
|
||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
uri VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(80),
|
||||
displayname VARCHAR(80),
|
||||
UNIQUE(uri)
|
||||
);
|
||||
|
||||
CREATE TABLE groupmembers (
|
||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
principal_id INTEGER UNSIGNED NOT NULL,
|
||||
member_id INTEGER UNSIGNED NOT NULL,
|
||||
UNIQUE(principal_id, member_id)
|
||||
);
|
||||
|
||||
|
||||
INSERT INTO principals (uri,email,displayname) VALUES
|
||||
('principals/admin', 'admin@example.org','Adminstrator'),
|
||||
('principals/admin/calendar-proxy-read', null, null),
|
||||
('principals/admin/calendar-proxy-write', null, null);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
CREATE TABLE users (
|
||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
username VARCHAR(50),
|
||||
digesta1 VARCHAR(32),
|
||||
UNIQUE(username)
|
||||
);
|
||||
|
||||
INSERT INTO users (username,digesta1) VALUES
|
||||
('admin', '87fd274b7b6c01e48d7c2f965da8ddf7');
|
|
@ -0,0 +1,17 @@
|
|||
CREATE TABLE addressbooks (
|
||||
id integer primary key asc,
|
||||
principaluri text,
|
||||
displayname text,
|
||||
uri text,
|
||||
description text,
|
||||
ctag integer
|
||||
);
|
||||
|
||||
CREATE TABLE cards (
|
||||
id integer primary key asc,
|
||||
addressbookid integer,
|
||||
carddata blob,
|
||||
uri text,
|
||||
lastmodified integer
|
||||
);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE calendarobjects (
|
||||
id integer primary key asc,
|
||||
calendardata blob,
|
||||
uri text,
|
||||
calendarid integer,
|
||||
lastmodified integer
|
||||
);
|
||||
|
||||
CREATE TABLE calendars (
|
||||
id integer primary key asc,
|
||||
principaluri text,
|
||||
displayname text,
|
||||
uri text,
|
||||
ctag integer,
|
||||
description text,
|
||||
calendarorder integer,
|
||||
calendarcolor text,
|
||||
timezone text,
|
||||
components text
|
||||
);
|
|
@ -0,0 +1,12 @@
|
|||
BEGIN TRANSACTION;
|
||||
CREATE TABLE locks (
|
||||
id integer primary key asc,
|
||||
owner text,
|
||||
timeout integer,
|
||||
created integer,
|
||||
token text,
|
||||
scope integer,
|
||||
depth integer,
|
||||
uri text
|
||||
);
|
||||
COMMIT;
|
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE principals (
|
||||
id INTEGER PRIMARY KEY ASC,
|
||||
uri TEXT,
|
||||
email TEXT,
|
||||
displayname TEXT,
|
||||
UNIQUE(uri)
|
||||
);
|
||||
|
||||
CREATE TABLE groupmembers (
|
||||
id INTEGER PRIMARY KEY ASC,
|
||||
principal_id INTEGER,
|
||||
member_id INTEGER,
|
||||
UNIQUE(principal_id, member_id)
|
||||
);
|
||||
|
||||
|
||||
INSERT INTO principals (uri,email,displayname) VALUES ('principals/admin', 'admin@example.org','Adminstrator');
|
||||
INSERT INTO principals (uri,email,displayname) VALUES ('principals/admin/calendar-proxy-read', null, null);
|
||||
INSERT INTO principals (uri,email,displayname) VALUES ('principals/admin/calendar-proxy-write', null, null);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
CREATE TABLE users (
|
||||
id integer primary key asc,
|
||||
username TEXT,
|
||||
digesta1 TEXT,
|
||||
UNIQUE(username)
|
||||
);
|
||||
|
||||
INSERT INTO users (username,digesta1) VALUES
|
||||
('admin', '87fd274b7b6c01e48d7c2f965da8ddf7');
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Library include file
|
||||
*
|
||||
* This file contains all includes to the rest of the SabreDAV library
|
||||
* Make sure the lib/ directory is in PHP's include_path
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
|
||||
/* Utilities */
|
||||
include 'Sabre/HTTP/Util.php';
|
||||
include 'Sabre/HTTP/Response.php';
|
||||
include 'Sabre/HTTP/Request.php';
|
||||
include 'Sabre/HTTP/AbstractAuth.php';
|
||||
include 'Sabre/HTTP/BasicAuth.php';
|
||||
include 'Sabre/HTTP/DigestAuth.php';
|
||||
include 'Sabre/HTTP/AWSAuth.php';
|
||||
|
||||
/* Version */
|
||||
include 'Sabre/DAV/Version.php';
|
||||
include 'Sabre/HTTP/Version.php';
|
||||
|
||||
/* Exceptions */
|
||||
include 'Sabre/DAV/Exception.php';
|
||||
include 'Sabre/DAV/Exception/BadRequest.php';
|
||||
include 'Sabre/DAV/Exception/Conflict.php';
|
||||
include 'Sabre/DAV/Exception/FileNotFound.php';
|
||||
include 'Sabre/DAV/Exception/InsufficientStorage.php';
|
||||
include 'Sabre/DAV/Exception/Locked.php';
|
||||
include 'Sabre/DAV/Exception/LockTokenMatchesRequestUri.php';
|
||||
include 'Sabre/DAV/Exception/MethodNotAllowed.php';
|
||||
include 'Sabre/DAV/Exception/NotImplemented.php';
|
||||
include 'Sabre/DAV/Exception/Forbidden.php';
|
||||
include 'Sabre/DAV/Exception/PreconditionFailed.php';
|
||||
include 'Sabre/DAV/Exception/RequestedRangeNotSatisfiable.php';
|
||||
include 'Sabre/DAV/Exception/UnsupportedMediaType.php';
|
||||
include 'Sabre/DAV/Exception/NotAuthenticated.php';
|
||||
|
||||
include 'Sabre/DAV/Exception/ConflictingLock.php';
|
||||
include 'Sabre/DAV/Exception/ReportNotImplemented.php';
|
||||
include 'Sabre/DAV/Exception/InvalidResourceType.php';
|
||||
|
||||
/* Properties */
|
||||
include 'Sabre/DAV/Property.php';
|
||||
include 'Sabre/DAV/Property/GetLastModified.php';
|
||||
include 'Sabre/DAV/Property/ResourceType.php';
|
||||
include 'Sabre/DAV/Property/SupportedLock.php';
|
||||
include 'Sabre/DAV/Property/LockDiscovery.php';
|
||||
include 'Sabre/DAV/Property/IHref.php';
|
||||
include 'Sabre/DAV/Property/Href.php';
|
||||
include 'Sabre/DAV/Property/HrefList.php';
|
||||
include 'Sabre/DAV/Property/SupportedReportSet.php';
|
||||
include 'Sabre/DAV/Property/Response.php';
|
||||
include 'Sabre/DAV/Property/ResponseList.php';
|
||||
|
||||
/* Node interfaces */
|
||||
include 'Sabre/DAV/INode.php';
|
||||
include 'Sabre/DAV/IFile.php';
|
||||
include 'Sabre/DAV/ICollection.php';
|
||||
include 'Sabre/DAV/IProperties.php';
|
||||
include 'Sabre/DAV/ILockable.php';
|
||||
include 'Sabre/DAV/IQuota.php';
|
||||
include 'Sabre/DAV/IExtendedCollection.php';
|
||||
|
||||
/* Node abstract implementations */
|
||||
include 'Sabre/DAV/Node.php';
|
||||
include 'Sabre/DAV/File.php';
|
||||
include 'Sabre/DAV/Collection.php';
|
||||
include 'Sabre/DAV/Directory.php';
|
||||
|
||||
/* Utilities */
|
||||
include 'Sabre/DAV/SimpleCollection.php';
|
||||
include 'Sabre/DAV/SimpleDirectory.php';
|
||||
include 'Sabre/DAV/XMLUtil.php';
|
||||
include 'Sabre/DAV/URLUtil.php';
|
||||
include 'Sabre/DAV/UUIDUtil.php';
|
||||
|
||||
/* Filesystem implementation */
|
||||
include 'Sabre/DAV/FS/Node.php';
|
||||
include 'Sabre/DAV/FS/File.php';
|
||||
include 'Sabre/DAV/FS/Directory.php';
|
||||
|
||||
/* Advanced filesystem implementation */
|
||||
include 'Sabre/DAV/FSExt/Node.php';
|
||||
include 'Sabre/DAV/FSExt/File.php';
|
||||
include 'Sabre/DAV/FSExt/Directory.php';
|
||||
|
||||
/* Trees */
|
||||
include 'Sabre/DAV/Tree.php';
|
||||
include 'Sabre/DAV/ObjectTree.php';
|
||||
include 'Sabre/DAV/Tree/Filesystem.php';
|
||||
|
||||
/* Server */
|
||||
include 'Sabre/DAV/Server.php';
|
||||
include 'Sabre/DAV/ServerPlugin.php';
|
||||
|
||||
/* Browser */
|
||||
include 'Sabre/DAV/Browser/Plugin.php';
|
||||
include 'Sabre/DAV/Browser/MapGetToPropFind.php';
|
||||
include 'Sabre/DAV/Browser/GuessContentType.php';
|
||||
|
||||
/* Locks */
|
||||
include 'Sabre/DAV/Locks/LockInfo.php';
|
||||
include 'Sabre/DAV/Locks/Plugin.php';
|
||||
include 'Sabre/DAV/Locks/Backend/Abstract.php';
|
||||
include 'Sabre/DAV/Locks/Backend/FS.php';
|
||||
include 'Sabre/DAV/Locks/Backend/PDO.php';
|
||||
|
||||
/* Temporary File Filter plugin */
|
||||
include 'Sabre/DAV/TemporaryFileFilterPlugin.php';
|
||||
|
||||
/* Authentication plugin */
|
||||
include 'Sabre/DAV/Auth/Plugin.php';
|
||||
include 'Sabre/DAV/Auth/IBackend.php';
|
||||
include 'Sabre/DAV/Auth/Backend/AbstractDigest.php';
|
||||
include 'Sabre/DAV/Auth/Backend/AbstractBasic.php';
|
||||
include 'Sabre/DAV/Auth/Backend/File.php';
|
||||
include 'Sabre/DAV/Auth/Backend/PDO.php';
|
||||
|
||||
/* DavMount plugin */
|
||||
include 'Sabre/DAV/Mount/Plugin.php';
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Abstract Calendaring backend. Extend this class to create your own backends.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_CalDAV_Backend_Abstract {
|
||||
|
||||
/**
|
||||
* Returns a list of calendars for a principal.
|
||||
*
|
||||
* Every project is an array with the following keys:
|
||||
* * id, a unique id that will be used by other functions to modify the
|
||||
* calendar. This can be the same as the uri or a database key.
|
||||
* * uri, which the basename of the uri with which the calendar is
|
||||
* accessed.
|
||||
* * principalUri. The owner of the calendar. Almost always the same as
|
||||
* principalUri passed to this method.
|
||||
*
|
||||
* Furthermore it can contain webdav properties in clark notation. A very
|
||||
* common one is '{DAV:}displayname'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarsForUser($principalUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar for a principal.
|
||||
*
|
||||
* If the creation was a success, an id must be returned that can be used to reference
|
||||
* this calendar in other methods, such as updateCalendar.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $calendarUri
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
abstract function createCalendar($principalUri,$calendarUri,array $properties);
|
||||
|
||||
/**
|
||||
* Updates properties for a calendar.
|
||||
*
|
||||
* 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 can be returned.
|
||||
* If the operation failed, false can be returned.
|
||||
*
|
||||
* Deletion of a non-existant property is always succesful.
|
||||
*
|
||||
* Lastly, it is optional to return detailed information about any
|
||||
* failures. In this case an array should be returned with the following
|
||||
* structure:
|
||||
*
|
||||
* array(
|
||||
* 403 => array(
|
||||
* '{DAV:}displayname' => null,
|
||||
* ),
|
||||
* 424 => array(
|
||||
* '{DAV:}owner' => null,
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* In this example it was forbidden to update {DAV:}displayname.
|
||||
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
|
||||
* (424 Failed Dependency) because the request needs to be atomic.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @return void
|
||||
*/
|
||||
abstract function deleteCalendar($calendarId);
|
||||
|
||||
/**
|
||||
* Returns all calendar objects within a calendar.
|
||||
*
|
||||
* Every item contains an array with the following keys:
|
||||
* * id - unique identifier which will be used for subsequent updates
|
||||
* * calendardata - The iCalendar-compatible calnedar data
|
||||
* * uri - a unique key which will be used to construct the uri. This can be any arbitrary string.
|
||||
* * lastmodified - a timestamp of the last modification time
|
||||
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
|
||||
* ' "abcdef"')
|
||||
* * calendarid - The calendarid as it was passed to this function.
|
||||
*
|
||||
* Note that the etag is optional, but it's highly encouraged to return for
|
||||
* speed reasons.
|
||||
*
|
||||
* The calendardata is also optional. If it's not returned
|
||||
* 'getCalendarObject' will be called later, which *is* expected to return
|
||||
* calendardata.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarObjects($calendarId);
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return void
|
||||
*/
|
||||
abstract function createCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return void
|
||||
*/
|
||||
abstract function updateCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
abstract function deleteCalendarObject($calendarId,$objectUri);
|
||||
|
||||
}
|
|
@ -0,0 +1,386 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PDO CalDAV backend
|
||||
*
|
||||
* This backend is used to store calendar-data in a PDO database, such as
|
||||
* sqlite or MySQL
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
|
||||
|
||||
/**
|
||||
* pdo
|
||||
*
|
||||
* @var PDO
|
||||
*/
|
||||
protected $pdo;
|
||||
|
||||
/**
|
||||
* The table name that will be used for calendars
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $calendarTableName;
|
||||
|
||||
/**
|
||||
* The table name that will be used for calendar objects
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $calendarObjectTableName;
|
||||
|
||||
/**
|
||||
* List of CalDAV properties, and how they map to database fieldnames
|
||||
*
|
||||
* Add your own properties by simply adding on to this array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $propertyMap = array(
|
||||
'{DAV:}displayname' => 'displayname',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'timezone',
|
||||
'{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates the backend
|
||||
*
|
||||
* @param PDO $pdo
|
||||
*/
|
||||
public function __construct(PDO $pdo, $calendarTableName = 'calendars', $calendarObjectTableName = 'calendarobjects') {
|
||||
|
||||
$this->pdo = $pdo;
|
||||
$this->calendarTableName = $calendarTableName;
|
||||
$this->calendarObjectTableName = $calendarObjectTableName;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of calendars for a principal.
|
||||
*
|
||||
* Every project is an array with the following keys:
|
||||
* * id, a unique id that will be used by other functions to modify the
|
||||
* calendar. This can be the same as the uri or a database key.
|
||||
* * uri, which the basename of the uri with which the calendar is
|
||||
* accessed.
|
||||
* * principalUri. The owner of the calendar. Almost always the same as
|
||||
* principalUri passed to this method.
|
||||
*
|
||||
* Furthermore it can contain webdav properties in clark notation. A very
|
||||
* common one is '{DAV:}displayname'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri) {
|
||||
|
||||
$fields = array_values($this->propertyMap);
|
||||
$fields[] = 'id';
|
||||
$fields[] = 'uri';
|
||||
$fields[] = 'ctag';
|
||||
$fields[] = 'components';
|
||||
$fields[] = 'principaluri';
|
||||
|
||||
// Making fields a comma-delimited list
|
||||
$fields = implode(', ', $fields);
|
||||
$stmt = $this->pdo->prepare("SELECT " . $fields . " FROM `".$this->calendarTableName."` WHERE principaluri = ?");
|
||||
$stmt->execute(array($principalUri));
|
||||
|
||||
$calendars = array();
|
||||
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
|
||||
$components = explode(',',$row['components']);
|
||||
|
||||
$calendar = array(
|
||||
'id' => $row['id'],
|
||||
'uri' => $row['uri'],
|
||||
'principaluri' => $row['principaluri'],
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $row['ctag']?$row['ctag']:'0',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet($components),
|
||||
);
|
||||
|
||||
|
||||
foreach($this->propertyMap as $xmlName=>$dbName) {
|
||||
$calendar[$xmlName] = $row[$dbName];
|
||||
}
|
||||
|
||||
$calendars[] = $calendar;
|
||||
|
||||
}
|
||||
|
||||
return $calendars;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar for a principal.
|
||||
*
|
||||
* If the creation was a success, an id must be returned that can be used to reference
|
||||
* this calendar in other methods, such as updateCalendar
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $calendarUri
|
||||
* @param array $properties
|
||||
*/
|
||||
public function createCalendar($principalUri,$calendarUri, array $properties) {
|
||||
|
||||
$fieldNames = array(
|
||||
'principaluri',
|
||||
'uri',
|
||||
'ctag',
|
||||
);
|
||||
$values = array(
|
||||
':principaluri' => $principalUri,
|
||||
':uri' => $calendarUri,
|
||||
':ctag' => 1,
|
||||
);
|
||||
|
||||
// Default value
|
||||
$sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
|
||||
$fieldNames[] = 'components';
|
||||
if (!isset($properties[$sccs])) {
|
||||
$values[':components'] = 'VEVENT,VTODO';
|
||||
} else {
|
||||
if (!($properties[$sccs] instanceof Sabre_CalDAV_Property_SupportedCalendarComponentSet)) {
|
||||
throw new Sabre_DAV_Exception('The ' . $sccs . ' property must be of type: Sabre_CalDAV_Property_SupportedCalendarComponentSet');
|
||||
}
|
||||
$values[':components'] = implode(',',$properties[$sccs]->getValue());
|
||||
}
|
||||
|
||||
foreach($this->propertyMap as $xmlName=>$dbName) {
|
||||
if (isset($properties[$xmlName])) {
|
||||
|
||||
$myValue = $properties[$xmlName];
|
||||
$values[':' . $dbName] = $properties[$xmlName];
|
||||
$fieldNames[] = $dbName;
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = $this->pdo->prepare("INSERT INTO `".$this->calendarTableName."` (".implode(', ', $fieldNames).") VALUES (".implode(', ',array_keys($values)).")");
|
||||
$stmt->execute($values);
|
||||
|
||||
return $this->pdo->lastInsertId();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties for a calendar.
|
||||
*
|
||||
* 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 can be returned.
|
||||
* If the operation failed, false can be returned.
|
||||
*
|
||||
* Deletion of a non-existant property is always succesful.
|
||||
*
|
||||
* Lastly, it is optional to return detailed information about any
|
||||
* failures. In this case an array should be returned with the following
|
||||
* structure:
|
||||
*
|
||||
* array(
|
||||
* 403 => array(
|
||||
* '{DAV:}displayname' => null,
|
||||
* ),
|
||||
* 424 => array(
|
||||
* '{DAV:}owner' => null,
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* In this example it was forbidden to update {DAV:}displayname.
|
||||
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
|
||||
* (424 Failed Dependency) because the request needs to be atomic.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations) {
|
||||
|
||||
$newValues = array();
|
||||
$result = array(
|
||||
200 => array(), // Ok
|
||||
403 => array(), // Forbidden
|
||||
424 => array(), // Failed Dependency
|
||||
);
|
||||
|
||||
$hasError = false;
|
||||
|
||||
foreach($mutations as $propertyName=>$propertyValue) {
|
||||
|
||||
// We don't know about this property.
|
||||
if (!isset($this->propertyMap[$propertyName])) {
|
||||
$hasError = true;
|
||||
$result[403][$propertyName] = null;
|
||||
unset($mutations[$propertyName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldName = $this->propertyMap[$propertyName];
|
||||
$newValues[$fieldName] = $propertyValue;
|
||||
|
||||
}
|
||||
|
||||
// If there were any errors we need to fail the request
|
||||
if ($hasError) {
|
||||
// Properties has the remaining properties
|
||||
foreach($mutations as $propertyName=>$propertyValue) {
|
||||
$result[424][$propertyName] = null;
|
||||
}
|
||||
|
||||
// Removing unused statuscodes for cleanliness
|
||||
foreach($result as $status=>$properties) {
|
||||
if (is_array($properties) && count($properties)===0) unset($result[$status]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
// Success
|
||||
|
||||
// Now we're generating the sql query.
|
||||
$valuesSql = array();
|
||||
foreach($newValues as $fieldName=>$value) {
|
||||
$valuesSql[] = $fieldName . ' = ?';
|
||||
}
|
||||
$valuesSql[] = 'ctag = ctag + 1';
|
||||
|
||||
$stmt = $this->pdo->prepare("UPDATE `" . $this->calendarTableName . "` SET " . implode(', ',$valuesSql) . " WHERE id = ?");
|
||||
$newValues['id'] = $calendarId;
|
||||
$stmt->execute(array_values($newValues));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId) {
|
||||
|
||||
$stmt = $this->pdo->prepare('DELETE FROM `'.$this->calendarObjectTableName.'` WHERE calendarid = ?');
|
||||
$stmt->execute(array($calendarId));
|
||||
|
||||
$stmt = $this->pdo->prepare('DELETE FROM `'.$this->calendarTableName.'` WHERE id = ?');
|
||||
$stmt->execute(array($calendarId));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all calendar objects within a calendar.
|
||||
*
|
||||
* Every item contains an array with the following keys:
|
||||
* * id - unique identifier which will be used for subsequent updates
|
||||
* * calendardata - The iCalendar-compatible calnedar data
|
||||
* * uri - a unique key which will be used to construct the uri. This can be any arbitrary string.
|
||||
* * lastmodified - a timestamp of the last modification time
|
||||
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
|
||||
* ' "abcdef"')
|
||||
* * calendarid - The calendarid as it was passed to this function.
|
||||
*
|
||||
* Note that the etag is optional, but it's highly encouraged to return for
|
||||
* speed reasons.
|
||||
*
|
||||
* The calendardata is also optional. If it's not returned
|
||||
* 'getCalendarObject' will be called later, which *is* expected to return
|
||||
* calendardata.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObjects($calendarId) {
|
||||
|
||||
$stmt = $this->pdo->prepare('SELECT * FROM `'.$this->calendarObjectTableName.'` WHERE calendarid = ?');
|
||||
$stmt->execute(array($calendarId));
|
||||
return $stmt->fetchAll();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObject($calendarId,$objectUri) {
|
||||
|
||||
$stmt = $this->pdo->prepare('SELECT * FROM `'.$this->calendarObjectTableName.'` WHERE calendarid = ? AND uri = ?');
|
||||
$stmt->execute(array($calendarId, $objectUri));
|
||||
return $stmt->fetch();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return void
|
||||
*/
|
||||
public function createCalendarObject($calendarId,$objectUri,$calendarData) {
|
||||
|
||||
$stmt = $this->pdo->prepare('INSERT INTO `'.$this->calendarObjectTableName.'` (calendarid, uri, calendardata, lastmodified) VALUES (?,?,?,?)');
|
||||
$stmt->execute(array($calendarId,$objectUri,$calendarData,time()));
|
||||
$stmt = $this->pdo->prepare('UPDATE `'.$this->calendarTableName.'` SET ctag = ctag + 1 WHERE id = ?');
|
||||
$stmt->execute(array($calendarId));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return void
|
||||
*/
|
||||
public function updateCalendarObject($calendarId,$objectUri,$calendarData) {
|
||||
|
||||
$stmt = $this->pdo->prepare('UPDATE `'.$this->calendarObjectTableName.'` SET calendardata = ?, lastmodified = ? WHERE calendarid = ? AND uri = ?');
|
||||
$stmt->execute(array($calendarData,time(),$calendarId,$objectUri));
|
||||
$stmt = $this->pdo->prepare('UPDATE `'.$this->calendarTableName.'` SET ctag = ctag + 1 WHERE id = ?');
|
||||
$stmt->execute(array($calendarId));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendarObject($calendarId,$objectUri) {
|
||||
|
||||
$stmt = $this->pdo->prepare('DELETE FROM `'.$this->calendarObjectTableName.'` WHERE calendarid = ? AND uri = ?');
|
||||
$stmt->execute(array($calendarId,$objectUri));
|
||||
$stmt = $this->pdo->prepare('UPDATE `'. $this->calendarTableName .'` SET ctag = ctag + 1 WHERE id = ?');
|
||||
$stmt->execute(array($calendarId));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This object represents a CalDAV calendar.
|
||||
*
|
||||
* A calendar can contain multiple TODO and or Events. These are represented
|
||||
* as Sabre_CalDAV_CalendarObject objects.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProperties, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* This is an array with calendar information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $calendarInfo;
|
||||
|
||||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* Principal backend
|
||||
*
|
||||
* @var Sabre_DAVACL_IPrincipalBackend
|
||||
*/
|
||||
protected $principalBackend;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param array $calendarInfo
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_Abstract $caldavBackend, $calendarInfo) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->principalBackend = $principalBackend;
|
||||
$this->calendarInfo = $calendarInfo;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the calendar
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return $this->calendarInfo['uri'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties such as the display name and description
|
||||
*
|
||||
* @param array $mutations
|
||||
* @return array
|
||||
*/
|
||||
public function updateProperties($mutations) {
|
||||
|
||||
return $this->caldavBackend->updateCalendar($this->calendarInfo['id'],$mutations);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of properties
|
||||
*
|
||||
* @param array $properties
|
||||
* @return array
|
||||
*/
|
||||
public function getProperties($requestedProperties) {
|
||||
|
||||
$response = array();
|
||||
|
||||
foreach($requestedProperties as $prop) switch($prop) {
|
||||
|
||||
case '{urn:ietf:params:xml:ns:caldav}supported-calendar-data' :
|
||||
$response[$prop] = new Sabre_CalDAV_Property_SupportedCalendarData();
|
||||
break;
|
||||
case '{urn:ietf:params:xml:ns:caldav}supported-collation-set' :
|
||||
$response[$prop] = new Sabre_CalDAV_Property_SupportedCollationSet();
|
||||
break;
|
||||
case '{DAV:}owner' :
|
||||
$response[$prop] = new Sabre_DAVACL_Property_Principal(Sabre_DAVACL_Property_Principal::HREF,$this->calendarInfo['principaluri']);
|
||||
break;
|
||||
default :
|
||||
if (isset($this->calendarInfo[$prop])) $response[$prop] = $this->calendarInfo[$prop];
|
||||
break;
|
||||
|
||||
}
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a calendar object
|
||||
*
|
||||
* The contained calendar objects are for example Events or Todo's.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Sabre_DAV_ICalendarObject
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'],$name);
|
||||
if (!$obj) throw new Sabre_DAV_Exception_FileNotFound('Calendar object not found');
|
||||
return new Sabre_CalDAV_CalendarObject($this->caldavBackend,$this->calendarInfo,$obj);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full list of calendar objects
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']);
|
||||
$children = array();
|
||||
foreach($objs as $obj) {
|
||||
$children[] = new Sabre_CalDAV_CalendarObject($this->caldavBackend,$this->calendarInfo,$obj);
|
||||
}
|
||||
return $children;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a child-node exists.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function childExists($name) {
|
||||
|
||||
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'],$name);
|
||||
if (!$obj)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new directory
|
||||
*
|
||||
* We actually block this, as subdirectories are not allowed in calendars.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Creating collections in calendar objects is not allowed');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new file
|
||||
*
|
||||
* The contents of the new file must be a valid ICalendar string.
|
||||
*
|
||||
* @param string $name
|
||||
* @param resource $calendarData
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($name,$calendarData = null) {
|
||||
|
||||
$calendarData = stream_get_contents($calendarData);
|
||||
// Converting to UTF-8, if needed
|
||||
$calendarData = Sabre_DAV_StringUtil::ensureUTF8($calendarData);
|
||||
|
||||
$supportedComponents = $this->calendarInfo['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set'];
|
||||
if ($supportedComponents) {
|
||||
$supportedComponents = $supportedComponents->getValue();
|
||||
} else {
|
||||
$supportedComponents = null;
|
||||
}
|
||||
Sabre_CalDAV_ICalendarUtil::validateICalendarObject($calendarData, $supportedComponents);
|
||||
|
||||
$this->caldavBackend->createCalendarObject($this->calendarInfo['id'],$name,$calendarData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the calendar.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
$this->caldavBackend->deleteCalendar($this->calendarInfo['id']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the calendar. Note that most calendars use the
|
||||
* {DAV:}displayname to display a name to display a name.
|
||||
*
|
||||
* @param string $newName
|
||||
* @return void
|
||||
*/
|
||||
public function setName($newName) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Renaming calendars is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date as a unix timestamp.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->calendarInfo['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' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->calendarInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
|
||||
'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 Sabre_DAV_Exception_MethodNotAllowed('Changing ACL is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The CalendarObject represents a single VEVENT or VTODO within a Calendar.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV_ICalendarObject, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* Sabre_CalDAV_Backend_Abstract
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* Array with information about this CalendarObject
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $objectData;
|
||||
|
||||
/**
|
||||
* Array with information about the containing calendar
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $calendarInfo;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param array $calendarInfo
|
||||
* @param array $objectData
|
||||
*/
|
||||
public function __construct(Sabre_CalDAV_Backend_Abstract $caldavBackend,array $calendarInfo,array $objectData) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
||||
if (!isset($objectData['calendarid'])) {
|
||||
throw new InvalidArgumentException('The objectData argument must contain a \'calendarid\' property');
|
||||
}
|
||||
if (!isset($objectData['uri'])) {
|
||||
throw new InvalidArgumentException('The objectData argument must contain an \'uri\' property');
|
||||
}
|
||||
|
||||
$this->calendarInfo = $calendarInfo;
|
||||
$this->objectData = $objectData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uri for this object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return $this->objectData['uri'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ICalendar-formatted object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get() {
|
||||
|
||||
// Pre-populating the 'calendardata' is optional, if we don't have it
|
||||
// already we fetch it from the backend.
|
||||
if (!isset($this->objectData['calendardata'])) {
|
||||
$this->objectData = $this->caldavBackend->getCalendarObject($this->objectData['calendarid'], $this->objectData['uri']);
|
||||
}
|
||||
return $this->objectData['calendardata'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ICalendar-formatted object
|
||||
*
|
||||
* @param string $calendarData
|
||||
* @return void
|
||||
*/
|
||||
public function put($calendarData) {
|
||||
|
||||
if (is_resource($calendarData))
|
||||
$calendarData = stream_get_contents($calendarData);
|
||||
|
||||
// Converting to UTF-8, if needed
|
||||
$calendarData = Sabre_DAV_StringUtil::ensureUTF8($calendarData);
|
||||
|
||||
$supportedComponents = $this->calendarInfo['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set'];
|
||||
if ($supportedComponents) {
|
||||
$supportedComponents = $supportedComponents->getValue();
|
||||
} else {
|
||||
$supportedComponents = null;
|
||||
}
|
||||
Sabre_CalDAV_ICalendarUtil::validateICalendarObject($calendarData, $supportedComponents);
|
||||
|
||||
$this->caldavBackend->updateCalendarObject($this->calendarInfo['id'],$this->objectData['uri'],$calendarData);
|
||||
$this->objectData['calendardata'] = $calendarData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the calendar object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
$this->caldavBackend->deleteCalendarObject($this->calendarInfo['id'],$this->objectData['uri']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime content-type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContentType() {
|
||||
|
||||
return 'text/calendar';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ETag for this object.
|
||||
*
|
||||
* The ETag is an arbritrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getETag() {
|
||||
|
||||
if (isset($this->objectData['etag'])) {
|
||||
return $this->objectData['etag'];
|
||||
} else {
|
||||
return '"' . md5($this->get()). '"';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date as a unix timestamp
|
||||
*
|
||||
* @return time
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return $this->objectData['lastmodified'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of this object in bytes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() {
|
||||
|
||||
return strlen($this->objectData['calendardata']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->calendarInfo['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' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->calendarInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
|
||||
'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 Sabre_DAV_Exception_MethodNotAllowed('Changing ACL is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Users collection
|
||||
*
|
||||
* This object is responsible for generating a collection of users.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_CalendarRootNode extends Sabre_DAVACL_AbstractPrincipalCollection {
|
||||
|
||||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* This constructor needs both an authentication and a caldav backend.
|
||||
*
|
||||
* By default this class will show a list of calendar collections for
|
||||
* principals in the 'principals' collection. If your main principals are
|
||||
* actually located in a different path, use the $principalPrefix argument
|
||||
* to override this.
|
||||
*
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param string $principalPrefix
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend,Sabre_CalDAV_Backend_Abstract $caldavBackend, $principalPrefix = 'principals') {
|
||||
|
||||
parent::__construct($principalBackend, $principalPrefix);
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nodename
|
||||
*
|
||||
* We're overriding this, because the default will be the 'principalPrefix',
|
||||
* and we want it to be Sabre_CalDAV_Plugin::CALENDAR_ROOT
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return Sabre_CalDAV_Plugin::CALENDAR_ROOT;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a node for a principal.
|
||||
*
|
||||
* The passed array contains principal information, and is guaranteed to
|
||||
* at least contain a uri item. Other properties may or may not be
|
||||
* supplied by the authentication backend.
|
||||
*
|
||||
* @param array $principal
|
||||
* @return Sabre_DAV_INode
|
||||
*/
|
||||
public function getChildForPrincipal(array $principal) {
|
||||
|
||||
return new Sabre_CalDAV_UserCalendars($this->principalBackend, $this->caldavBackend, $principal['uri']);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* InvalidICalendarObject
|
||||
*
|
||||
* This exception is thrown when an attempt is made to create or update
|
||||
* an invalid ICalendar object
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Exception_InvalidICalendarObject extends Sabre_DAV_Exception_PreconditionFailed {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ICS Exporter
|
||||
*
|
||||
* This plugin adds the ability to export entire calendars as .ics files.
|
||||
* This is useful for clients that don't support CalDAV yet. They often do
|
||||
* support ics files.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_ICSExportPlugin extends Sabre_DAV_ServerPlugin {
|
||||
|
||||
/**
|
||||
* Reference to Server class
|
||||
*
|
||||
* @var Sabre_DAV_Server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* Initializes the plugin and registers event handlers
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 'beforeMethod' event handles. This event handles intercepts GET requests ending
|
||||
* with ?export
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $uri
|
||||
* @return void
|
||||
*/
|
||||
public function beforeMethod($method, $uri) {
|
||||
|
||||
if ($method!='GET') return;
|
||||
if ($this->server->httpRequest->getQueryString()!='export') return;
|
||||
|
||||
// splitting uri
|
||||
list($uri) = explode('?',$uri,2);
|
||||
|
||||
$node = $this->server->tree->getNodeForPath($uri);
|
||||
|
||||
if (!($node instanceof Sabre_CalDAV_Calendar)) return;
|
||||
|
||||
// Checking ACL, if available.
|
||||
if ($aclPlugin = $this->server->getPlugin('acl')) {
|
||||
$aclPlugin->checkPrivileges($uri, '{DAV:}read');
|
||||
}
|
||||
|
||||
$this->server->httpResponse->setHeader('Content-Type','text/calendar');
|
||||
$this->server->httpResponse->sendStatus(200);
|
||||
|
||||
$nodes = $this->server->getPropertiesForPath($uri, array(
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data',
|
||||
),1);
|
||||
|
||||
$this->server->httpResponse->sendBody($this->generateICS($nodes));
|
||||
|
||||
// Returning false to break the event chain
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges all calendar objects, and builds one big ics export
|
||||
*
|
||||
* @param array $nodes
|
||||
* @return void
|
||||
*/
|
||||
public function generateICS(array $nodes) {
|
||||
|
||||
$calendar = new Sabre_VObject_Component('vcalendar');
|
||||
$calendar->version = '2.0';
|
||||
$calendar->prodid = '-//SabreDAV//SabreDAV ' . Sabre_DAV_Version::VERSION . '//EN';
|
||||
$calendar->calscale = 'GREGORIAN';
|
||||
|
||||
$collectedTimezones = array();
|
||||
|
||||
$timezones = array();
|
||||
$objects = array();
|
||||
|
||||
foreach($nodes as $node) {
|
||||
|
||||
if (!isset($node[200]['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data'])) {
|
||||
continue;
|
||||
}
|
||||
$nodeData = $node[200]['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data'];
|
||||
|
||||
$nodeComp = Sabre_VObject_Reader::read($nodeData);
|
||||
|
||||
foreach($nodeComp->children() as $child) {
|
||||
|
||||
switch($child->name) {
|
||||
case 'VEVENT' :
|
||||
case 'VTODO' :
|
||||
case 'VJOURNAL' :
|
||||
$objects[] = $child;
|
||||
break;
|
||||
|
||||
// VTIMEZONE is special, because we need to filter out the duplicates
|
||||
case 'VTIMEZONE' :
|
||||
// Naively just checking tzid.
|
||||
if (in_array((string)$child->TZID, $collectedTimezones)) continue;
|
||||
|
||||
$timezones[] = $child;
|
||||
$collectedTimezones[] = $child->TZID;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach($timezones as $tz) $calendar->add($tz);
|
||||
foreach($objects as $obj) $calendar->add($obj);
|
||||
|
||||
return $calendar->serialize();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Calendar interface
|
||||
*
|
||||
* Implement this interface to allow a node to be recognized as an calendar.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CalDAV_ICalendar extends Sabre_DAV_ICollection {
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* CalendarObject interface
|
||||
/**
|
||||
* Extend the ICalendarObject interface to allow your custom nodes to be picked up as
|
||||
* CalendarObjects.
|
||||
*
|
||||
* Calendar objects are resources such as Events, Todo's or Journals.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CalDAV_ICalendarObject extends Sabre_DAV_IFile {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class contains several utilities related to the ICalendar (rfc2445) format
|
||||
*
|
||||
* This class is now deprecated, and won't be further maintained. Please use
|
||||
* the Sabre_VObject package for your ics parsing needs.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
* @deprecated Use Sabre_VObject instead.
|
||||
*/
|
||||
class Sabre_CalDAV_ICalendarUtil {
|
||||
|
||||
/**
|
||||
* Validates an ICalendar object
|
||||
*
|
||||
* This method makes sure this ICalendar object is properly formatted.
|
||||
* If we can't parse it, we'll throw exceptions.
|
||||
*
|
||||
* @param string $icalData
|
||||
* @param array $allowedComponents
|
||||
* @return bool
|
||||
*/
|
||||
static function validateICalendarObject($icalData, array $allowedComponents = null) {
|
||||
|
||||
$xcal = simplexml_load_string(self::toXCal($icalData));
|
||||
if (!$xcal) throw new Sabre_CalDAV_Exception_InvalidICalendarObject('Invalid calendarobject format');
|
||||
|
||||
$xcal->registerXPathNameSpace('cal','urn:ietf:params:xml:ns:xcal');
|
||||
|
||||
// Check if there's only 1 component
|
||||
$components = array('vevent','vtodo','vjournal','vfreebusy');
|
||||
$componentsFound = array();
|
||||
|
||||
foreach($components as $component) {
|
||||
$test = $xcal->xpath('/cal:iCalendar/cal:vcalendar/cal:' . $component);
|
||||
if (is_array($test)) $componentsFound = array_merge($componentsFound, $test);
|
||||
}
|
||||
if (count($componentsFound)<1) {
|
||||
throw new Sabre_CalDAV_Exception_InvalidICalendarObject('One VEVENT, VTODO, VJOURNAL or VFREEBUSY must be specified. 0 found.');
|
||||
}
|
||||
$component = $componentsFound[0];
|
||||
|
||||
if (is_null($allowedComponents)) return true;
|
||||
|
||||
// Check if the component is allowed
|
||||
$name = $component->getName();
|
||||
if (!in_array(strtoupper($name),$allowedComponents)) {
|
||||
throw new Sabre_CalDAV_Exception_InvalidICalendarObject(strtoupper($name) . ' is not allowed in this calendar.');
|
||||
}
|
||||
|
||||
if (count($xcal->xpath('/cal:iCalendar/cal:vcalendar/cal:method'))>0) {
|
||||
throw new Sabre_CalDAV_Exception_InvalidICalendarObject('The METHOD property is not allowed in calendar objects');
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ICalendar data to XML.
|
||||
*
|
||||
* Properties are converted to lowercase xml elements. Parameters are;
|
||||
* converted to attributes. BEGIN:VEVENT is converted to <vevent> and
|
||||
* END:VEVENT </vevent> as well as other components.
|
||||
*
|
||||
* It's a very loose parser. If any line does not conform to the spec, it
|
||||
* will simply be ignored. It will try to detect if \r\n or \n line endings
|
||||
* are used.
|
||||
*
|
||||
* @todo Currently quoted attributes are not parsed correctly.
|
||||
* @see http://tools.ietf.org/html/draft-royer-calsch-xcal-03
|
||||
* @param string $icalData
|
||||
* @return string.
|
||||
*/
|
||||
static function toXCAL($icalData) {
|
||||
|
||||
// Detecting line endings
|
||||
$lb="\r\n";
|
||||
if (strpos($icalData,"\r\n")!==false) $lb = "\r\n";
|
||||
elseif (strpos($icalData,"\n")!==false) $lb = "\n";
|
||||
|
||||
// Splitting up items per line
|
||||
$lines = explode($lb,$icalData);
|
||||
|
||||
// Properties can be folded over 2 lines. In this case the second
|
||||
// line will be preceeded by a space or tab.
|
||||
$lines2 = array();
|
||||
foreach($lines as $line) {
|
||||
|
||||
if (!$line) continue;
|
||||
if ($line[0]===" " || $line[0]==="\t") {
|
||||
$lines2[count($lines2)-1].=substr($line,1);
|
||||
continue;
|
||||
}
|
||||
|
||||
$lines2[]=$line;
|
||||
|
||||
}
|
||||
|
||||
$xml = '<?xml version="1.0"?>' . "\n";
|
||||
$xml.= "<iCalendar xmlns=\"urn:ietf:params:xml:ns:xcal\">\n";
|
||||
|
||||
$spaces = 2;
|
||||
foreach($lines2 as $line) {
|
||||
|
||||
$matches = array();
|
||||
// This matches PROPERTYNAME;ATTRIBUTES:VALUE
|
||||
if (!preg_match('/^([^:^;]*)(?:;([^:]*))?:(.*)$/',$line,$matches))
|
||||
continue;
|
||||
|
||||
$propertyName = strtolower($matches[1]);
|
||||
$attributes = $matches[2];
|
||||
$value = $matches[3];
|
||||
|
||||
// If the line was in the format BEGIN:COMPONENT or END:COMPONENT, we need to special case it.
|
||||
if ($propertyName === 'begin') {
|
||||
$xml.=str_repeat(" ",$spaces);
|
||||
$xml.='<' . strtolower($value) . ">\n";
|
||||
$spaces+=2;
|
||||
continue;
|
||||
} elseif ($propertyName === 'end') {
|
||||
$spaces-=2;
|
||||
$xml.=str_repeat(" ",$spaces);
|
||||
$xml.='</' . strtolower($value) . ">\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$xml.=str_repeat(" ",$spaces);
|
||||
$xml.='<' . $propertyName;
|
||||
if ($attributes) {
|
||||
// There can be multiple attributes
|
||||
$attributes = explode(';',$attributes);
|
||||
foreach($attributes as $att) {
|
||||
|
||||
list($attName,$attValue) = explode('=',$att,2);
|
||||
$attName = strtolower($attName);
|
||||
if ($attName === 'language') $attName='xml:lang';
|
||||
$xml.=' ' . $attName . '="' . htmlspecialchars($attValue) . '"';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$xml.='>'. htmlspecialchars(trim($value)) . '</' . $propertyName . ">\n";
|
||||
|
||||
}
|
||||
$xml.="</iCalendar>";
|
||||
return $xml;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,788 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* CalDAV plugin
|
||||
*
|
||||
* This plugin provides functionality added by CalDAV (RFC 4791)
|
||||
* It implements new reports, and the MKCALENDAR method.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
||||
|
||||
/**
|
||||
* This is the official CalDAV namespace
|
||||
*/
|
||||
const NS_CALDAV = 'urn:ietf:params:xml:ns:caldav';
|
||||
|
||||
/**
|
||||
* This is the namespace for the proprietary calendarserver extensions
|
||||
*/
|
||||
const NS_CALENDARSERVER = 'http://calendarserver.org/ns/';
|
||||
|
||||
/**
|
||||
* The following constants are used to differentiate
|
||||
* the various filters for the calendar-query report
|
||||
*/
|
||||
const FILTER_COMPFILTER = 1;
|
||||
const FILTER_TIMERANGE = 3;
|
||||
const FILTER_PROPFILTER = 4;
|
||||
const FILTER_PARAMFILTER = 5;
|
||||
const FILTER_TEXTMATCH = 6;
|
||||
|
||||
/**
|
||||
* The hardcoded root for calendar objects. It is unfortunate
|
||||
* that we're stuck with it, but it will have to do for now
|
||||
*/
|
||||
const CALENDAR_ROOT = 'calendars';
|
||||
|
||||
/**
|
||||
* Reference to server object
|
||||
*
|
||||
* @var Sabre_DAV_Server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* Use this method to tell the server this plugin defines additional
|
||||
* HTTP methods.
|
||||
*
|
||||
* This method is passed a uri. It should only return HTTP methods that are
|
||||
* available for the specified uri.
|
||||
*
|
||||
* @param string $uri
|
||||
* @return array
|
||||
*/
|
||||
public function getHTTPMethods($uri) {
|
||||
|
||||
// The MKCALENDAR is only available on unmapped uri's, whose
|
||||
// parents extend IExtendedCollection
|
||||
list($parent, $name) = Sabre_DAV_URLUtil::splitPath($uri);
|
||||
|
||||
$node = $this->server->tree->getNodeForPath($parent);
|
||||
|
||||
if ($node instanceof Sabre_DAV_IExtendedCollection) {
|
||||
try {
|
||||
$node->getChild($name);
|
||||
} catch (Sabre_DAV_Exception_FileNotFound $e) {
|
||||
return array('MKCALENDAR');
|
||||
}
|
||||
}
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of features for the DAV: HTTP header.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFeatures() {
|
||||
|
||||
return array('calendar-access', 'calendar-proxy');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plugin name.
|
||||
*
|
||||
* Using this name other plugins will be able to access other plugins
|
||||
* using Sabre_DAV_Server::getPlugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginName() {
|
||||
|
||||
return 'caldav';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of reports this plugin supports.
|
||||
*
|
||||
* This will be used in the {DAV:}supported-report-set property.
|
||||
* Note that you still need to subscribe to the 'report' event to actually
|
||||
* implement them
|
||||
*
|
||||
* @param string $uri
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedReportSet($uri) {
|
||||
|
||||
$node = $this->server->tree->getNodeForPath($uri);
|
||||
if ($node instanceof Sabre_CalDAV_ICalendar || $node instanceof Sabre_CalDAV_ICalendarObject) {
|
||||
return array(
|
||||
'{' . self::NS_CALDAV . '}calendar-multiget',
|
||||
'{' . self::NS_CALDAV . '}calendar-query',
|
||||
);
|
||||
}
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the plugin
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
$this->server = $server;
|
||||
$server->subscribeEvent('unknownMethod',array($this,'unknownMethod'));
|
||||
//$server->subscribeEvent('unknownMethod',array($this,'unknownMethod2'),1000);
|
||||
$server->subscribeEvent('report',array($this,'report'));
|
||||
$server->subscribeEvent('beforeGetProperties',array($this,'beforeGetProperties'));
|
||||
|
||||
$server->xmlNamespaces[self::NS_CALDAV] = 'cal';
|
||||
$server->xmlNamespaces[self::NS_CALENDARSERVER] = 'cs';
|
||||
|
||||
$server->propertyMap['{' . self::NS_CALDAV . '}supported-calendar-component-set'] = 'Sabre_CalDAV_Property_SupportedCalendarComponentSet';
|
||||
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_ICalendar'] = '{urn:ietf:params:xml:ns:caldav}calendar';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Principal_ProxyRead'] = '{http://calendarserver.org/ns/}calendar-proxy-read';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Principal_ProxyWrite'] = '{http://calendarserver.org/ns/}calendar-proxy-write';
|
||||
|
||||
array_push($server->protectedProperties,
|
||||
|
||||
'{' . self::NS_CALDAV . '}supported-calendar-component-set',
|
||||
'{' . self::NS_CALDAV . '}supported-calendar-data',
|
||||
'{' . self::NS_CALDAV . '}max-resource-size',
|
||||
'{' . self::NS_CALDAV . '}min-date-time',
|
||||
'{' . self::NS_CALDAV . '}max-date-time',
|
||||
'{' . self::NS_CALDAV . '}max-instances',
|
||||
'{' . self::NS_CALDAV . '}max-attendees-per-instance',
|
||||
'{' . self::NS_CALDAV . '}calendar-home-set',
|
||||
'{' . self::NS_CALDAV . '}supported-collation-set',
|
||||
'{' . self::NS_CALDAV . '}calendar-data',
|
||||
|
||||
// scheduling extension
|
||||
'{' . self::NS_CALDAV . '}calendar-user-address-set',
|
||||
|
||||
// CalendarServer extensions
|
||||
'{' . self::NS_CALENDARSERVER . '}getctag',
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for',
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for'
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles support for the MKCALENDAR method
|
||||
*
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
public function unknownMethod($method, $uri) {
|
||||
|
||||
if ($method!=='MKCALENDAR') return;
|
||||
|
||||
$this->httpMkCalendar($uri);
|
||||
// false is returned to stop the unknownMethod event
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This functions handles REPORT requests specific to CalDAV
|
||||
*
|
||||
* @param string $reportName
|
||||
* @param DOMNode $dom
|
||||
* @return bool
|
||||
*/
|
||||
public function report($reportName,$dom) {
|
||||
|
||||
switch($reportName) {
|
||||
case '{'.self::NS_CALDAV.'}calendar-multiget' :
|
||||
$this->calendarMultiGetReport($dom);
|
||||
return false;
|
||||
case '{'.self::NS_CALDAV.'}calendar-query' :
|
||||
$this->calendarQueryReport($dom);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles the MKCALENDAR HTTP method, which creates
|
||||
* a new calendar.
|
||||
*
|
||||
* @param string $uri
|
||||
* @return void
|
||||
*/
|
||||
public function httpMkCalendar($uri) {
|
||||
|
||||
// Due to unforgivable bugs in iCal, we're completely disabling MKCALENDAR support
|
||||
// for clients matching iCal in the user agent
|
||||
//$ua = $this->server->httpRequest->getHeader('User-Agent');
|
||||
//if (strpos($ua,'iCal/')!==false) {
|
||||
// throw new Sabre_DAV_Exception_Forbidden('iCal has major bugs in it\'s RFC3744 support. Therefore we are left with no other choice but disabling this feature.');
|
||||
//}
|
||||
|
||||
$body = $this->server->httpRequest->getBody(true);
|
||||
$properties = array();
|
||||
|
||||
if ($body) {
|
||||
|
||||
$dom = Sabre_DAV_XMLUtil::loadDOMDocument($body);
|
||||
|
||||
foreach($dom->firstChild->childNodes as $child) {
|
||||
|
||||
if (Sabre_DAV_XMLUtil::toClarkNotation($child)!=='{DAV:}set') continue;
|
||||
foreach(Sabre_DAV_XMLUtil::parseProperties($child,$this->server->propertyMap) as $k=>$prop) {
|
||||
$properties[$k] = $prop;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:caldav}calendar');
|
||||
|
||||
$this->server->createCollection($uri,$resourceType,$properties);
|
||||
|
||||
$this->server->httpResponse->sendStatus(201);
|
||||
$this->server->httpResponse->setHeader('Content-Length',0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Sabre_DAV_INode $node
|
||||
* @param array $requestedProperties
|
||||
* @param array $returnedProperties
|
||||
* @return void
|
||||
*/
|
||||
public function beforeGetProperties($path, Sabre_DAV_INode $node, &$requestedProperties, &$returnedProperties) {
|
||||
|
||||
if ($node instanceof Sabre_DAVACL_IPrincipal) {
|
||||
|
||||
// calendar-home-set property
|
||||
$calHome = '{' . self::NS_CALDAV . '}calendar-home-set';
|
||||
if (in_array($calHome,$requestedProperties)) {
|
||||
$principalId = $node->getName();
|
||||
$calendarHomePath = self::CALENDAR_ROOT . '/' . $principalId . '/';
|
||||
unset($requestedProperties[$calHome]);
|
||||
$returnedProperties[200][$calHome] = new Sabre_DAV_Property_Href($calendarHomePath);
|
||||
}
|
||||
|
||||
// calendar-user-address-set property
|
||||
$calProp = '{' . self::NS_CALDAV . '}calendar-user-address-set';
|
||||
if (in_array($calProp,$requestedProperties)) {
|
||||
|
||||
$addresses = $node->getAlternateUriSet();
|
||||
$addresses[] = $this->server->getBaseUri() . $node->getPrincipalUrl();
|
||||
unset($requestedProperties[$calProp]);
|
||||
$returnedProperties[200][$calProp] = new Sabre_DAV_Property_HrefList($addresses, false);
|
||||
|
||||
}
|
||||
|
||||
// These two properties are shortcuts for ical to easily find
|
||||
// other principals this principal has access to.
|
||||
$propRead = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for';
|
||||
$propWrite = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for';
|
||||
if (in_array($propRead,$requestedProperties) || in_array($propWrite,$requestedProperties)) {
|
||||
|
||||
$membership = $node->getGroupMembership();
|
||||
$readList = array();
|
||||
$writeList = array();
|
||||
|
||||
foreach($membership as $group) {
|
||||
|
||||
$groupNode = $this->server->tree->getNodeForPath($group);
|
||||
|
||||
// If the node is either ap proxy-read or proxy-write
|
||||
// group, we grab the parent principal and add it to the
|
||||
// list.
|
||||
if ($groupNode instanceof Sabre_CalDAV_Principal_ProxyRead) {
|
||||
list($readList[]) = Sabre_DAV_URLUtil::splitPath($group);
|
||||
}
|
||||
if ($groupNode instanceof Sabre_CalDAV_Principal_ProxyWrite) {
|
||||
list($writeList[]) = Sabre_DAV_URLUtil::splitPath($group);
|
||||
}
|
||||
|
||||
}
|
||||
if (in_array($propRead,$requestedProperties)) {
|
||||
unset($requestedProperties[$propRead]);
|
||||
$returnedProperties[200][$propRead] = new Sabre_DAV_Property_HrefList($readList);
|
||||
}
|
||||
if (in_array($propWrite,$requestedProperties)) {
|
||||
unset($requestedProperties[$propWrite]);
|
||||
$returnedProperties[200][$propWrite] = new Sabre_DAV_Property_HrefList($writeList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // instanceof IPrincipal
|
||||
|
||||
|
||||
if ($node instanceof Sabre_CalDAV_ICalendarObject) {
|
||||
// The calendar-data property is not supposed to be a 'real'
|
||||
// property, but in large chunks of the spec it does act as such.
|
||||
// Therefore we simply expose it as a property.
|
||||
$calDataProp = '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data';
|
||||
if (in_array($calDataProp, $requestedProperties)) {
|
||||
unset($requestedProperties[$calDataProp]);
|
||||
$val = $node->get();
|
||||
if (is_resource($val))
|
||||
$val = stream_get_contents($val);
|
||||
|
||||
// Taking out \r to not screw up the xml output
|
||||
$returnedProperties[200][$calDataProp] = str_replace("\r","", $val);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles the calendar-multiget REPORT.
|
||||
*
|
||||
* This report is used by the client to fetch the content of a series
|
||||
* of urls. Effectively avoiding a lot of redundant requests.
|
||||
*
|
||||
* @param DOMNode $dom
|
||||
* @return void
|
||||
*/
|
||||
public function calendarMultiGetReport($dom) {
|
||||
|
||||
$properties = array_keys(Sabre_DAV_XMLUtil::parseProperties($dom->firstChild));
|
||||
|
||||
$hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href');
|
||||
foreach($hrefElems as $elem) {
|
||||
$uri = $this->server->calculateUri($elem->nodeValue);
|
||||
list($objProps) = $this->server->getPropertiesForPath($uri,$properties);
|
||||
$propertyList[]=$objProps;
|
||||
|
||||
}
|
||||
|
||||
$this->server->httpResponse->sendStatus(207);
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
|
||||
$this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles the calendar-query REPORT
|
||||
*
|
||||
* This report is used by clients to request calendar objects based on
|
||||
* complex conditions.
|
||||
*
|
||||
* @param DOMNode $dom
|
||||
* @return void
|
||||
*/
|
||||
public function calendarQueryReport($dom) {
|
||||
|
||||
$requestedProperties = array_keys(Sabre_DAV_XMLUtil::parseProperties($dom->firstChild));
|
||||
|
||||
$filterNode = $dom->getElementsByTagNameNS('urn:ietf:params:xml:ns:caldav','filter');
|
||||
if ($filterNode->length!==1) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The calendar-query report must have a filter element');
|
||||
}
|
||||
$filters = Sabre_CalDAV_XMLUtil::parseCalendarQueryFilters($filterNode->item(0));
|
||||
|
||||
$requestedCalendarData = true;
|
||||
|
||||
if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) {
|
||||
// We always retrieve calendar-data, as we need it for filtering.
|
||||
$requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data';
|
||||
|
||||
// If calendar-data wasn't explicitly requested, we need to remove
|
||||
// it after processing.
|
||||
$requestedCalendarData = false;
|
||||
}
|
||||
|
||||
// These are the list of nodes that potentially match the requirement
|
||||
$candidateNodes = $this->server->getPropertiesForPath($this->server->getRequestUri(),$requestedProperties,$this->server->getHTTPDepth(0));
|
||||
|
||||
$verifiedNodes = array();
|
||||
|
||||
foreach($candidateNodes as $node) {
|
||||
|
||||
// If the node didn't have a calendar-data property, it must not be a calendar object
|
||||
if (!isset($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) continue;
|
||||
|
||||
if ($this->validateFilters($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'],$filters)) {
|
||||
|
||||
if (!$requestedCalendarData) {
|
||||
unset($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
|
||||
}
|
||||
$verifiedNodes[] = $node;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->server->httpResponse->sendStatus(207);
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
|
||||
$this->server->httpResponse->sendBody($this->server->generateMultiStatus($verifiedNodes));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify if a list of filters applies to the calendar data object
|
||||
*
|
||||
* The calendarData object must be a valid iCalendar blob. The list of
|
||||
* filters must be formatted as parsed by Sabre_CalDAV_Plugin::parseCalendarQueryFilters
|
||||
*
|
||||
* @param string $calendarData
|
||||
* @param array $filters
|
||||
* @return bool
|
||||
*/
|
||||
public function validateFilters($calendarData,$filters) {
|
||||
|
||||
// We are converting the calendar object to an XML structure
|
||||
// This makes it far easier to parse
|
||||
$xCalendarData = Sabre_CalDAV_ICalendarUtil::toXCal($calendarData);
|
||||
$xml = simplexml_load_string($xCalendarData);
|
||||
$xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:xcal');
|
||||
|
||||
foreach($filters as $xpath=>$filter) {
|
||||
|
||||
// if-not-defined comes first
|
||||
if (isset($filter['is-not-defined'])) {
|
||||
if (!$xml->xpath($xpath))
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
$elem = $xml->xpath($xpath);
|
||||
|
||||
if (!$elem) return false;
|
||||
$elem = $elem[0];
|
||||
|
||||
if (isset($filter['time-range'])) {
|
||||
|
||||
switch($elem->getName()) {
|
||||
case 'vevent' :
|
||||
$result = $this->validateTimeRangeFilterForEvent($xml,$xpath,$filter);
|
||||
if ($result===false) return false;
|
||||
break;
|
||||
case 'vtodo' :
|
||||
$result = $this->validateTimeRangeFilterForTodo($xml,$xpath,$filter);
|
||||
if ($result===false) return false;
|
||||
break;
|
||||
case 'vjournal' :
|
||||
case 'vfreebusy' :
|
||||
case 'valarm' :
|
||||
// TODO: not implemented
|
||||
break;
|
||||
|
||||
/*
|
||||
|
||||
case 'vjournal' :
|
||||
$result = $this->validateTimeRangeFilterForJournal($xml,$xpath,$filter);
|
||||
if ($result===false) return false;
|
||||
break;
|
||||
case 'vfreebusy' :
|
||||
$result = $this->validateTimeRangeFilterForFreeBusy($xml,$xpath,$filter);
|
||||
if ($result===false) return false;
|
||||
break;
|
||||
case 'valarm' :
|
||||
$result = $this->validateTimeRangeFilterForAlarm($xml,$xpath,$filter);
|
||||
if ($result===false) return false;
|
||||
break;
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($filter['text-match'])) {
|
||||
$currentString = (string)$elem;
|
||||
|
||||
$isMatching = Sabre_DAV_StringUtil::textMatch($currentString, $filter['text-match']['value'], $filter['text-match']['collation']);
|
||||
if ($filter['text-match']['negate-condition'] && $isMatching) return false;
|
||||
if (!$filter['text-match']['negate-condition'] && !$isMatching) return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a time-range filter matches an event.
|
||||
*
|
||||
* @param SimpleXMLElement $xml Event as xml object
|
||||
* @param string $currentXPath XPath to check
|
||||
* @param array $currentFilter Filter information
|
||||
* @return void
|
||||
*/
|
||||
private function validateTimeRangeFilterForEvent(SimpleXMLElement $xml,$currentXPath,array $currentFilter) {
|
||||
|
||||
// Grabbing the DTSTART property
|
||||
$xdtstart = $xml->xpath($currentXPath.'/c:dtstart');
|
||||
if (!count($xdtstart)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('DTSTART property missing from calendar object');
|
||||
}
|
||||
|
||||
// The dtstart can be both a date, or datetime property
|
||||
if ((string)$xdtstart[0]['value']==='DATE' || strlen((string)$xdtstart[0])===8) {
|
||||
$isDateTime = false;
|
||||
} else {
|
||||
$isDateTime = true;
|
||||
}
|
||||
|
||||
// Determining the timezone
|
||||
if ($tzid = (string)$xdtstart[0]['tzid']) {
|
||||
$tz = new DateTimeZone($tzid);
|
||||
} else {
|
||||
$tz = null;
|
||||
}
|
||||
if ($isDateTime) {
|
||||
$dtstart = Sabre_CalDAV_XMLUtil::parseICalendarDateTime((string)$xdtstart[0],$tz);
|
||||
} else {
|
||||
$dtstart = Sabre_CalDAV_XMLUtil::parseICalendarDate((string)$xdtstart[0]);
|
||||
}
|
||||
|
||||
|
||||
// Grabbing the DTEND property
|
||||
$xdtend = $xml->xpath($currentXPath.'/c:dtend');
|
||||
$dtend = null;
|
||||
|
||||
if (count($xdtend)) {
|
||||
// Determining the timezone
|
||||
if ($tzid = (string)$xdtend[0]['tzid']) {
|
||||
$tz = new DateTimeZone($tzid);
|
||||
} else {
|
||||
$tz = null;
|
||||
}
|
||||
|
||||
// Since the VALUE prameter of both DTSTART and DTEND must be the same
|
||||
// we can assume we don't need to check the VALUE paramter of DTEND.
|
||||
if ($isDateTime) {
|
||||
$dtend = Sabre_CalDAV_XMLUtil::parseICalendarDateTime((string)$xdtend[0],$tz);
|
||||
} else {
|
||||
$dtend = Sabre_CalDAV_XMLUtil::parseICalendarDate((string)$xdtend[0],$tz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is_null($dtend)) {
|
||||
// The DTEND property was not found. We will first see if the event has a duration
|
||||
// property
|
||||
|
||||
$xduration = $xml->xpath($currentXPath.'/c:duration');
|
||||
if (count($xduration)) {
|
||||
$duration = Sabre_CalDAV_XMLUtil::parseICalendarDuration((string)$xduration[0]);
|
||||
|
||||
// Making sure that the duration is bigger than 0 seconds.
|
||||
$tempDT = clone $dtstart;
|
||||
$tempDT->modify($duration);
|
||||
if ($tempDT > $dtstart) {
|
||||
|
||||
// use DTEND = DTSTART + DURATION
|
||||
$dtend = $tempDT;
|
||||
} else {
|
||||
// use DTEND = DTSTART
|
||||
$dtend = $dtstart;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($dtend)) {
|
||||
if ($isDateTime) {
|
||||
// DTEND = DTSTART
|
||||
$dtend = $dtstart;
|
||||
} else {
|
||||
// DTEND = DTSTART + 1 DAY
|
||||
$dtend = clone $dtstart;
|
||||
$dtend->modify('+1 day');
|
||||
}
|
||||
}
|
||||
// TODO: we need to properly parse RRULE's, but it's very difficult.
|
||||
// For now, we're always returning events if they have an RRULE at all.
|
||||
$rrule = $xml->xpath($currentXPath.'/c:rrule');
|
||||
$hasRrule = (count($rrule))>0;
|
||||
|
||||
if (!is_null($currentFilter['time-range']['start']) && $currentFilter['time-range']['start'] >= $dtend && !$hasRrule) return false;
|
||||
if (!is_null($currentFilter['time-range']['end']) && $currentFilter['time-range']['end'] <= $dtstart && !$hasRrule) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private function validateTimeRangeFilterForTodo(SimpleXMLElement $xml,$currentXPath,array $filter) {
|
||||
|
||||
// Gathering all relevant elements
|
||||
|
||||
$dtStart = null;
|
||||
$duration = null;
|
||||
$due = null;
|
||||
$completed = null;
|
||||
$created = null;
|
||||
|
||||
$xdt = $xml->xpath($currentXPath.'/c:dtstart');
|
||||
if (count($xdt)) {
|
||||
// The dtstart can be both a date, or datetime property
|
||||
if ((string)$xdt[0]['value']==='DATE') {
|
||||
$isDateTime = false;
|
||||
} else {
|
||||
$isDateTime = true;
|
||||
}
|
||||
|
||||
// Determining the timezone
|
||||
if ($tzid = (string)$xdt[0]['tzid']) {
|
||||
$tz = new DateTimeZone($tzid);
|
||||
} else {
|
||||
$tz = null;
|
||||
}
|
||||
if ($isDateTime) {
|
||||
$dtStart = Sabre_CalDAV_XMLUtil::parseICalendarDateTime((string)$xdt[0],$tz);
|
||||
} else {
|
||||
$dtStart = Sabre_CalDAV_XMLUtil::parseICalendarDate((string)$xdt[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Only need to grab duration if dtStart is set
|
||||
if (!is_null($dtStart)) {
|
||||
|
||||
$xduration = $xml->xpath($currentXPath.'/c:duration');
|
||||
if (count($xduration)) {
|
||||
$duration = Sabre_CalDAV_XMLUtil::parseICalendarDuration((string)$xduration[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!is_null($dtStart) && !is_null($duration)) {
|
||||
|
||||
// Comparision from RFC 4791:
|
||||
// (start <= DTSTART+DURATION) AND ((end > DTSTART) OR (end >= DTSTART+DURATION))
|
||||
|
||||
$end = clone $dtStart;
|
||||
$end->modify($duration);
|
||||
|
||||
if( (is_null($filter['time-range']['start']) || $filter['time-range']['start'] <= $end) &&
|
||||
(is_null($filter['time-range']['end']) || $filter['time-range']['end'] > $dtStart || $filter['time-range']['end'] >= $end) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Need to grab the DUE property
|
||||
$xdt = $xml->xpath($currentXPath.'/c:due');
|
||||
if (count($xdt)) {
|
||||
// The due property can be both a date, or datetime property
|
||||
if ((string)$xdt[0]['value']==='DATE') {
|
||||
$isDateTime = false;
|
||||
} else {
|
||||
$isDateTime = true;
|
||||
}
|
||||
// Determining the timezone
|
||||
if ($tzid = (string)$xdt[0]['tzid']) {
|
||||
$tz = new DateTimeZone($tzid);
|
||||
} else {
|
||||
$tz = null;
|
||||
}
|
||||
if ($isDateTime) {
|
||||
$due = Sabre_CalDAV_XMLUtil::parseICalendarDateTime((string)$xdt[0],$tz);
|
||||
} else {
|
||||
$due = Sabre_CalDAV_XMLUtil::parseICalendarDate((string)$xdt[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($dtStart) && !is_null($due)) {
|
||||
|
||||
// Comparision from RFC 4791:
|
||||
// ((start < DUE) OR (start <= DTSTART)) AND ((end > DTSTART) OR (end >= DUE))
|
||||
|
||||
if( (is_null($filter['time-range']['start']) || $filter['time-range']['start'] < $due || $filter['time-range']['start'] < $dtstart) &&
|
||||
(is_null($filter['time-range']['end']) || $filter['time-range']['end'] >= $due) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!is_null($dtStart)) {
|
||||
|
||||
// Comparision from RFC 4791
|
||||
// (start <= DTSTART) AND (end > DTSTART)
|
||||
if ( (is_null($filter['time-range']['start']) || $filter['time-range']['start'] <= $dtStart) &&
|
||||
(is_null($filter['time-range']['end']) || $filter['time-range']['end'] > $dtStart) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!is_null($due)) {
|
||||
|
||||
// Comparison from RFC 4791
|
||||
// (start < DUE) AND (end >= DUE)
|
||||
if ( (is_null($filter['time-range']['start']) || $filter['time-range']['start'] < $due) &&
|
||||
(is_null($filter['time-range']['end']) || $filter['time-range']['end'] >= $due) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
// Need to grab the COMPLETED property
|
||||
$xdt = $xml->xpath($currentXPath.'/c:completed');
|
||||
if (count($xdt)) {
|
||||
$completed = Sabre_CalDAV_XMLUtil::parseICalendarDateTime((string)$xdt[0]);
|
||||
}
|
||||
// Need to grab the CREATED property
|
||||
$xdt = $xml->xpath($currentXPath.'/c:created');
|
||||
if (count($xdt)) {
|
||||
$created = Sabre_CalDAV_XMLUtil::parseICalendarDateTime((string)$xdt[0]);
|
||||
}
|
||||
|
||||
if (!is_null($completed) && !is_null($created)) {
|
||||
// Comparison from RFC 4791
|
||||
// ((start <= CREATED) OR (start <= COMPLETED)) AND ((end >= CREATED) OR (end >= COMPLETED))
|
||||
if( (is_null($filter['time-range']['start']) || $filter['time-range']['start'] <= $created || $filter['time-range']['start'] <= $completed) &&
|
||||
(is_null($filter['time-range']['end']) || $filter['time-range']['end'] >= $created || $filter['time-range']['end'] >= $completed)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($completed)) {
|
||||
// Comparison from RFC 4791
|
||||
// (start <= COMPLETED) AND (end >= COMPLETED)
|
||||
if( (is_null($filter['time-range']['start']) || $filter['time-range']['start'] <= $completed) &&
|
||||
(is_null($filter['time-range']['end']) || $filter['time-range']['end'] >= $completed)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($created)) {
|
||||
// Comparison from RFC 4791
|
||||
// (end > CREATED)
|
||||
if( (is_null($filter['time-range']['end']) || $filter['time-range']['end'] > $created) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything else is TRUE
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Principal collection
|
||||
*
|
||||
* This is an alternative collection to the standard ACL principal collection.
|
||||
* This collection adds support for the calendar-proxy-read and
|
||||
* calendar-proxy-write sub-principals, as defined by the caldav-proxy
|
||||
* specification.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Principal_Collection extends Sabre_DAVACL_AbstractPrincipalCollection {
|
||||
|
||||
/**
|
||||
* Returns a child object based on principal information
|
||||
*
|
||||
* @param array $principalInfo
|
||||
* @return Sabre_CalDAV_Principal_User
|
||||
*/
|
||||
public function getChildForPrincipal(array $principalInfo) {
|
||||
|
||||
return new Sabre_CalDAV_Principal_User($this->principalBackend, $principalInfo);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ProxyRead principal
|
||||
*
|
||||
* This class represents a principal group, hosted under the main principal.
|
||||
* This is needed to implement 'Calendar delegation' support. This class is
|
||||
* instantiated by Sabre_CalDAV_Principal_User.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Principal_ProxyRead implements Sabre_DAVACL_IPrincipal {
|
||||
|
||||
/**
|
||||
* Principal information from the parent principal.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $principalInfo;
|
||||
|
||||
/**
|
||||
* Principal backend
|
||||
*
|
||||
* @var Sabre_DAVACL_IPrincipalBackend
|
||||
*/
|
||||
protected $principalBackend;
|
||||
|
||||
/**
|
||||
* Creates the object.
|
||||
*
|
||||
* Note that you MUST supply the parent principal information.
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param array $principalInfo
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, array $principalInfo) {
|
||||
|
||||
$this->principalInfo = $principalInfo;
|
||||
$this->principalBackend = $principalBackend;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this principals name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return 'calendar-proxy-read';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification time
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the current node
|
||||
*
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to delete node');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the node
|
||||
*
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @param string $name The new name
|
||||
* @return void
|
||||
*/
|
||||
public function setName($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to rename file');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of altenative urls for a principal
|
||||
*
|
||||
* This can for example be an email address, or ldap url.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAlternateUriSet() {
|
||||
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full principal url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPrincipalUrl() {
|
||||
|
||||
return $this->principalInfo['uri'] . '/' . $this->getName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of group members
|
||||
*
|
||||
* If this principal is a group, this function should return
|
||||
* all member principal uri's for the group.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupMemberSet() {
|
||||
|
||||
return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of groups this principal is member of
|
||||
*
|
||||
* If this principal is a member of a (list of) groups, this function
|
||||
* should return a list of principal uri's for it's members.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupMembership() {
|
||||
|
||||
return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a list of group members
|
||||
*
|
||||
* If this principal is a group, this method sets all the group members.
|
||||
* The list of members is always overwritten, never appended to.
|
||||
*
|
||||
* This method should throw an exception if the members could not be set.
|
||||
*
|
||||
* @param array $principals
|
||||
* @return void
|
||||
*/
|
||||
public function setGroupMemberSet(array $principals) {
|
||||
|
||||
$this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the displayname
|
||||
*
|
||||
* This should be a human readable name for the principal.
|
||||
* If none is available, return the nodename.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName() {
|
||||
|
||||
return $this->getName();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ProxyWrite principal
|
||||
*
|
||||
* This class represents a principal group, hosted under the main principal.
|
||||
* This is needed to implement 'Calendar delegation' support. This class is
|
||||
* instantiated by Sabre_CalDAV_Principal_User.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Principal_ProxyWrite implements Sabre_DAVACL_IPrincipal {
|
||||
|
||||
/**
|
||||
* Parent principal information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $principalInfo;
|
||||
|
||||
/**
|
||||
* Principal Backend
|
||||
*
|
||||
* @var Sabre_DAVACL_IPrincipalBackend
|
||||
*/
|
||||
protected $principalBackend;
|
||||
|
||||
/**
|
||||
* Creates the object
|
||||
*
|
||||
* Note that you MUST supply the parent principal information.
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param array $principalInfo
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, array $principalInfo) {
|
||||
|
||||
$this->principalInfo = $principalInfo;
|
||||
$this->principalBackend = $principalBackend;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this principals name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return 'calendar-proxy-write';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification time
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the current node
|
||||
*
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to delete node');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the node
|
||||
*
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @param string $name The new name
|
||||
* @return void
|
||||
*/
|
||||
public function setName($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to rename file');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of altenative urls for a principal
|
||||
*
|
||||
* This can for example be an email address, or ldap url.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAlternateUriSet() {
|
||||
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full principal url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPrincipalUrl() {
|
||||
|
||||
return $this->principalInfo['uri'] . '/' . $this->getName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of group members
|
||||
*
|
||||
* If this principal is a group, this function should return
|
||||
* all member principal uri's for the group.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupMemberSet() {
|
||||
|
||||
return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of groups this principal is member of
|
||||
*
|
||||
* If this principal is a member of a (list of) groups, this function
|
||||
* should return a list of principal uri's for it's members.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupMembership() {
|
||||
|
||||
return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a list of group members
|
||||
*
|
||||
* If this principal is a group, this method sets all the group members.
|
||||
* The list of members is always overwritten, never appended to.
|
||||
*
|
||||
* This method should throw an exception if the members could not be set.
|
||||
*
|
||||
* @param array $principals
|
||||
* @return void
|
||||
*/
|
||||
public function setGroupMemberSet(array $principals) {
|
||||
|
||||
$this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the displayname
|
||||
*
|
||||
* This should be a human readable name for the principal.
|
||||
* If none is available, return the nodename.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName() {
|
||||
|
||||
return $this->getName();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* CalDAV principal
|
||||
*
|
||||
* This is a standard user-principal for CalDAV. This principal is also a
|
||||
* collection and returns the caldav-proxy-read and caldav-proxy-write child
|
||||
* principals.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Principal_User extends Sabre_DAVACL_Principal implements Sabre_DAV_ICollection {
|
||||
|
||||
/**
|
||||
* Creates a new file in the directory
|
||||
*
|
||||
* @param string $name Name of the file
|
||||
* @param resource $data Initial payload, passed as a readable stream resource.
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($name, $data = null) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to create file (filename ' . $name . ')');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new subdirectory
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to create directory');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific child node, referenced by its name
|
||||
*
|
||||
* @param string $name
|
||||
* @return Sabre_DAV_INode
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
if ($name === 'calendar-proxy-read')
|
||||
return new Sabre_CalDAV_Principal_ProxyRead($this->principalBackend, $this->principalProperties);
|
||||
|
||||
if ($name === 'calendar-proxy-write')
|
||||
return new Sabre_CalDAV_Principal_ProxyWrite($this->principalBackend, $this->principalProperties);
|
||||
|
||||
throw new Sabre_DAV_Exception_FileNotFound('Node with name ' . $name . ' was not found');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all the child nodes
|
||||
*
|
||||
* @return Sabre_DAV_INode[]
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
return array(
|
||||
new Sabre_CalDAV_Principal_ProxyRead($this->principalBackend, $this->principalProperties),
|
||||
new Sabre_CalDAV_Principal_ProxyWrite($this->principalBackend, $this->principalProperties),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a child-node with the specified name exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function childExists($name) {
|
||||
|
||||
return $name === 'calendar-proxy-read' || $name === 'calendar-proxy-write';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => '{DAV:}read',
|
||||
'principal' => $this->principalProperties['uri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-read',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Supported component set property
|
||||
*
|
||||
* This property is a representation of the supported-calendar_component-set
|
||||
* property in the CalDAV namespace. It simply requires an array of components,
|
||||
* such as VEVENT, VTODO
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Property_SupportedCalendarComponentSet extends Sabre_DAV_Property {
|
||||
|
||||
/**
|
||||
* List of supported components, such as "VEVENT, VTODO"
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $components;
|
||||
|
||||
/**
|
||||
* Creates the property
|
||||
*
|
||||
* @param array $components
|
||||
*/
|
||||
public function __construct(array $components) {
|
||||
|
||||
$this->components = $components;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of supported components
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValue() {
|
||||
|
||||
return $this->components;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the property in a DOMDocument
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $node) {
|
||||
|
||||
$doc = $node->ownerDocument;
|
||||
foreach($this->components as $component) {
|
||||
|
||||
$xcomp = $doc->createElement('cal:comp');
|
||||
$xcomp->setAttribute('name',$component);
|
||||
$node->appendChild($xcomp);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserializes the DOMElement back into a Property class.
|
||||
*
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
static function unserialize(DOMElement $node) {
|
||||
|
||||
$components = array();
|
||||
foreach($node->childNodes as $childNode) {
|
||||
if (Sabre_DAV_XMLUtil::toClarkNotation($childNode)==='{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}comp') {
|
||||
$components[] = $childNode->getAttribute('name');
|
||||
}
|
||||
}
|
||||
return new self($components);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Supported-calendar-data property
|
||||
*
|
||||
* This property is a representation of the supported-calendar-data property
|
||||
* in the CalDAV namespace. SabreDAV only has support for text/calendar;2.0
|
||||
* so the value is currently hardcoded.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Property_SupportedCalendarData extends Sabre_DAV_Property {
|
||||
|
||||
/**
|
||||
* Serializes the property in a DOMDocument
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $node) {
|
||||
|
||||
$doc = $node->ownerDocument;
|
||||
|
||||
$prefix = isset($server->xmlNamespaces[Sabre_CalDAV_Plugin::NS_CALDAV])?$server->xmlNamespaces[Sabre_CalDAV_Plugin::NS_CALDAV]:'cal';
|
||||
|
||||
$caldata = $doc->createElement($prefix . ':calendar-data');
|
||||
$caldata->setAttribute('content-type','text/calendar');
|
||||
$caldata->setAttribute('version','2.0');
|
||||
|
||||
$node->appendChild($caldata);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* supported-collation-set property
|
||||
*
|
||||
* This property is a representation of the supported-collation-set property
|
||||
* in the CalDAV namespace.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Property_SupportedCollationSet extends Sabre_DAV_Property {
|
||||
|
||||
/**
|
||||
* Serializes the property in a DOM document
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $node) {
|
||||
|
||||
$doc = $node->ownerDocument;
|
||||
|
||||
$prefix = $node->lookupPrefix('urn:ietf:params:xml:ns:caldav');
|
||||
if (!$prefix) $prefix = 'cal';
|
||||
|
||||
$node->appendChild(
|
||||
$doc->createElement($prefix . ':supported-collation','i;ascii-casemap')
|
||||
);
|
||||
$node->appendChild(
|
||||
$doc->createElement($prefix . ':supported-collation','i;octet')
|
||||
);
|
||||
$node->appendChild(
|
||||
$doc->createElement($prefix . ':supported-collation','i;unicode-casemap')
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* CalDAV server
|
||||
*
|
||||
* This script is a convenience script. It quickly sets up a WebDAV server
|
||||
* with caldav and ACL support, and it creates the root 'principals' and
|
||||
* 'calendars' collections.
|
||||
*
|
||||
* Note that if you plan to do anything moderately complex, you are advised to
|
||||
* not subclass this server, but use Sabre_DAV_Server directly instead. This
|
||||
* class is nothing more than an 'easy setup'.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Server extends Sabre_DAV_Server {
|
||||
|
||||
/**
|
||||
* The authentication realm
|
||||
*
|
||||
* Note that if this changes, the hashes in the auth backend must also
|
||||
* be recalculated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $authRealm = 'SabreDAV';
|
||||
|
||||
/**
|
||||
* Sets up the object. A PDO object must be passed to setup all the backends.
|
||||
*
|
||||
* @param PDO $pdo
|
||||
*/
|
||||
public function __construct(PDO $pdo) {
|
||||
|
||||
/* Backends */
|
||||
$authBackend = new Sabre_DAV_Auth_Backend_PDO($pdo);
|
||||
$calendarBackend = new Sabre_CalDAV_Backend_PDO($pdo);
|
||||
$principalBackend = new Sabre_DAVACL_PrincipalBackend_PDO($pdo);
|
||||
|
||||
/* Directory structure */
|
||||
$tree = array(
|
||||
new Sabre_CalDAV_Principal_Collection($principalBackend),
|
||||
new Sabre_CalDAV_CalendarRootNode($principalBackend, $calendarBackend),
|
||||
);
|
||||
|
||||
/* Initializing server */
|
||||
parent::__construct($tree);
|
||||
|
||||
/* Server Plugins */
|
||||
$authPlugin = new Sabre_DAV_Auth_Plugin($authBackend,$this->authRealm);
|
||||
$this->addPlugin($authPlugin);
|
||||
|
||||
$aclPlugin = new Sabre_DAVACL_Plugin();
|
||||
$this->addPlugin($aclPlugin);
|
||||
|
||||
$caldavPlugin = new Sabre_CalDAV_Plugin();
|
||||
$this->addPlugin($caldavPlugin);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The UserCalenders class contains all calendars associated to one user
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* Principal backend
|
||||
*
|
||||
* @var Sabre_DAVACL_IPrincipalBackend
|
||||
*/
|
||||
protected $principalBackend;
|
||||
|
||||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* Principal information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $principalInfo;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param mixed $userUri
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_Abstract $caldavBackend, $userUri) {
|
||||
|
||||
$this->principalBackend = $principalBackend;
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->principalInfo = $principalBackend->getPrincipalByPath($userUri);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
list(,$name) = Sabre_DAV_URLUtil::splitPath($this->principalInfo['uri']);
|
||||
return $name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the name of this object
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function setName($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new file under this object.
|
||||
*
|
||||
* This is currently not allowed
|
||||
*
|
||||
* @param string $filename
|
||||
* @param resource $data
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($filename, $data=null) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Creating new files in this collection is not supported');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new directory under this object.
|
||||
*
|
||||
* This is currently not allowed.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($filename) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Creating new collections in this collection is not supported');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single calendar, by name
|
||||
*
|
||||
* @param string $name
|
||||
* @todo needs optimizing
|
||||
* @return Sabre_CalDAV_Calendar
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
foreach($this->getChildren() as $child) {
|
||||
if ($name==$child->getName())
|
||||
return $child;
|
||||
|
||||
}
|
||||
throw new Sabre_DAV_Exception_FileNotFound('Calendar with name \'' . $name . '\' could not be found');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a calendar exists.
|
||||
*
|
||||
* @param string $name
|
||||
* @todo needs optimizing
|
||||
* @return bool
|
||||
*/
|
||||
public function childExists($name) {
|
||||
|
||||
foreach($this->getChildren() as $child) {
|
||||
if ($name==$child->getName())
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of calendars
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']);
|
||||
$objs = array();
|
||||
foreach($calendars as $calendar) {
|
||||
$objs[] = new Sabre_CalDAV_Calendar($this->principalBackend, $this->caldavBackend, $calendar);
|
||||
}
|
||||
return $objs;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $properties
|
||||
* @return void
|
||||
*/
|
||||
public function createExtendedCollection($name, array $resourceType, array $properties) {
|
||||
|
||||
if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar',$resourceType) || count($resourceType)!==2) {
|
||||
throw new Sabre_DAV_Exception_InvalidResourceType('Unknown resourceType for this collection');
|
||||
}
|
||||
$this->caldavBackend->createCalendar($this->principalInfo['uri'], $name, $properties);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->principalInfo['uri'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => '{DAV:}read',
|
||||
'principal' => $this->principalInfo['uri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->principalInfo['uri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-read',
|
||||
'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 Sabre_DAV_Exception_MethodNotAllowed('Changing ACL is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This class contains the Sabre_CalDAV version constants.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Version {
|
||||
|
||||
/**
|
||||
* Full version number
|
||||
*/
|
||||
const VERSION = '1.5.7';
|
||||
|
||||
/**
|
||||
* Stability : alpha, beta, stable
|
||||
*/
|
||||
const STABILITY = 'stable';
|
||||
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* XML utilities for CalDAV
|
||||
*
|
||||
* This class contains a few static methods used for parsing certain CalDAV
|
||||
* requests.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_XMLUtil {
|
||||
|
||||
/**
|
||||
* This function parses the calendar-query report request body
|
||||
*
|
||||
* The body is quite complicated, so we're turning it into a PHP
|
||||
* array.
|
||||
*
|
||||
* The resulting associative array has xpath expressions as keys.
|
||||
* By default the xpath expressions should simply be checked for existance
|
||||
* The xpath expressions can point to elements or attributes.
|
||||
*
|
||||
* The array values can contain a number of items, which alters the query
|
||||
* filter.
|
||||
*
|
||||
* * time-range. Must also check if the todo or event falls within the
|
||||
* specified timerange. How this is interpreted depends on
|
||||
* the type of object (VTODO, VEVENT, VJOURNAL, etc)
|
||||
* * is-not-defined
|
||||
* Instead of checking if the attribute or element exist,
|
||||
* we must check if it doesn't.
|
||||
* * text-match
|
||||
* Checks if the value of the attribute or element matches
|
||||
* the specified value. This is actually another array with
|
||||
* the 'collation', 'value' and 'negate-condition' items.
|
||||
*
|
||||
* Refer to the CalDAV spec for more information.
|
||||
*
|
||||
* @param DOMNode $domNode
|
||||
* @param string $basePath used for recursive calls.
|
||||
* @param array $filters used for recursive calls.
|
||||
* @return array
|
||||
*/
|
||||
static public function parseCalendarQueryFilters($domNode,$basePath = '/c:iCalendar', &$filters = array()) {
|
||||
|
||||
foreach($domNode->childNodes as $child) {
|
||||
|
||||
switch(Sabre_DAV_XMLUtil::toClarkNotation($child)) {
|
||||
|
||||
case '{urn:ietf:params:xml:ns:caldav}comp-filter' :
|
||||
case '{urn:ietf:params:xml:ns:caldav}prop-filter' :
|
||||
|
||||
$filterName = $basePath . '/' . 'c:' . strtolower($child->getAttribute('name'));
|
||||
$filters[$filterName] = array();
|
||||
|
||||
self::parseCalendarQueryFilters($child, $filterName,$filters);
|
||||
break;
|
||||
|
||||
case '{urn:ietf:params:xml:ns:caldav}time-range' :
|
||||
|
||||
if ($start = $child->getAttribute('start')) {
|
||||
$start = self::parseICalendarDateTime($start);
|
||||
} else {
|
||||
$start = null;
|
||||
}
|
||||
if ($end = $child->getAttribute('end')) {
|
||||
$end = self::parseICalendarDateTime($end);
|
||||
} else {
|
||||
$end = null;
|
||||
}
|
||||
|
||||
if (!is_null($start) && !is_null($end) && $end <= $start) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The end-date must be larger than the start-date in the time-range filter');
|
||||
}
|
||||
|
||||
$filters[$basePath]['time-range'] = array(
|
||||
'start' => $start,
|
||||
'end' => $end
|
||||
);
|
||||
break;
|
||||
|
||||
case '{urn:ietf:params:xml:ns:caldav}is-not-defined' :
|
||||
$filters[$basePath]['is-not-defined'] = true;
|
||||
break;
|
||||
|
||||
case '{urn:ietf:params:xml:ns:caldav}param-filter' :
|
||||
|
||||
$filterName = $basePath . '/@' . strtolower($child->getAttribute('name'));
|
||||
$filters[$filterName] = array();
|
||||
self::parseCalendarQueryFilters($child, $filterName, $filters);
|
||||
break;
|
||||
|
||||
case '{urn:ietf:params:xml:ns:caldav}text-match' :
|
||||
|
||||
$collation = $child->getAttribute('collation');
|
||||
if (!$collation) $collation = 'i;ascii-casemap';
|
||||
|
||||
$filters[$basePath]['text-match'] = array(
|
||||
'collation' => ($collation == 'default'?'i;ascii-casemap':$collation),
|
||||
'negate-condition' => $child->getAttribute('negate-condition')==='yes',
|
||||
'value' => $child->nodeValue,
|
||||
);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $filters;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an iCalendar (rfc5545) formatted datetime and returns a DateTime object
|
||||
*
|
||||
* Specifying a reference timezone is optional. It will only be used
|
||||
* if the non-UTC format is used. The argument is used as a reference, the
|
||||
* returned DateTime object will still be in the UTC timezone.
|
||||
*
|
||||
* @param string $dt
|
||||
* @param DateTimeZone $tz
|
||||
* @return DateTime
|
||||
*/
|
||||
static public function parseICalendarDateTime($dt,DateTimeZone $tz = null) {
|
||||
|
||||
// Format is YYYYMMDD + "T" + hhmmss
|
||||
$result = preg_match('/^([1-3][0-9]{3})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/',$dt,$matches);
|
||||
|
||||
if (!$result) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar datetime value is incorrect: ' . $dt);
|
||||
}
|
||||
|
||||
if ($matches[7]==='Z' || is_null($tz)) {
|
||||
$tz = new DateTimeZone('UTC');
|
||||
}
|
||||
$date = new DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] .':' . $matches[6], $tz);
|
||||
|
||||
// Still resetting the timezone, to normalize everything to UTC
|
||||
$date->setTimeZone(new DateTimeZone('UTC'));
|
||||
return $date;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an iCalendar (rfc5545) formatted datetime and returns a DateTime object
|
||||
*
|
||||
* @param string $date
|
||||
* @param DateTimeZone $tz
|
||||
* @return DateTime
|
||||
*/
|
||||
static public function parseICalendarDate($date) {
|
||||
|
||||
// Format is YYYYMMDD
|
||||
$result = preg_match('/^([1-3][0-9]{3})([0-1][0-9])([0-3][0-9])$/',$date,$matches);
|
||||
|
||||
if (!$result) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar date value is incorrect: ' . $date);
|
||||
}
|
||||
|
||||
$date = new DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3], new DateTimeZone('UTC'));
|
||||
return $date;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an iCalendar (RFC5545) formatted duration and returns a string suitable
|
||||
* for strtotime or DateTime::modify.
|
||||
*
|
||||
* NOTE: When we require PHP 5.3 this can be replaced by the DateTimeInterval object, which
|
||||
* supports ISO 8601 Intervals, which is a superset of ICalendar durations.
|
||||
*
|
||||
* For now though, we're just gonna live with this messy system
|
||||
*
|
||||
* @param string $duration
|
||||
* @return string
|
||||
*/
|
||||
static public function parseICalendarDuration($duration) {
|
||||
|
||||
$result = preg_match('/^(?P<plusminus>\+|-)?P((?P<week>\d+)W)?((?P<day>\d+)D)?(T((?P<hour>\d+)H)?((?P<minute>\d+)M)?((?P<second>\d+)S)?)?$/', $duration, $matches);
|
||||
if (!$result) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar duration value is incorrect: ' . $duration);
|
||||
}
|
||||
|
||||
$parts = array(
|
||||
'week',
|
||||
'day',
|
||||
'hour',
|
||||
'minute',
|
||||
'second',
|
||||
);
|
||||
|
||||
$newDur = '';
|
||||
foreach($parts as $part) {
|
||||
if (isset($matches[$part]) && $matches[$part]) {
|
||||
$newDur.=' '.$matches[$part] . ' ' . $part . 's';
|
||||
}
|
||||
}
|
||||
|
||||
$newDur = ($matches['plusminus']==='-'?'-':'+') . trim($newDur);
|
||||
return $newDur;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The AddressBook class represents a CardDAV addressbook, owned by a specific user
|
||||
*
|
||||
* The AddressBook can contain multiple vcards
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_CardDAV_IAddressBook, Sabre_DAV_IProperties, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* This is an array with addressbook information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $addressBookInfo;
|
||||
|
||||
/**
|
||||
* CardDAV backend
|
||||
*
|
||||
* @var Sabre_CardDAV_Backend_Abstract
|
||||
*/
|
||||
private $carddavBackend;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CardDAV_Backend_Abstract $carddavBackend
|
||||
* @param array $addressBookInfo
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Sabre_CardDAV_Backend_Abstract $carddavBackend,array $addressBookInfo) {
|
||||
|
||||
$this->carddavBackend = $carddavBackend;
|
||||
$this->addressBookInfo = $addressBookInfo;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the addressbook
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return $this->addressBookInfo['uri'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a card
|
||||
*
|
||||
* @param string $name
|
||||
* @return Sabre_DAV_Card
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'],$name);
|
||||
if (!$obj) throw new Sabre_DAV_Exception_FileNotFound('Card not found');
|
||||
return new Sabre_CardDAV_Card($this->carddavBackend,$this->addressBookInfo,$obj);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full list of cards
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$objs = $this->carddavBackend->getCards($this->addressBookInfo['id']);
|
||||
$children = array();
|
||||
foreach($objs as $obj) {
|
||||
$children[] = new Sabre_CardDAV_Card($this->carddavBackend,$this->addressBookInfo,$obj);
|
||||
}
|
||||
return $children;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new directory
|
||||
*
|
||||
* We actually block this, as subdirectories are not allowed in addressbooks.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Creating collections in addressbooks is not allowed');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new file
|
||||
*
|
||||
* The contents of the new file must be a valid VCARD
|
||||
*
|
||||
* @param string $name
|
||||
* @param resource $vcardData
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($name,$vcardData = null) {
|
||||
|
||||
$vcardData = stream_get_contents($vcardData);
|
||||
// Converting to UTF-8, if needed
|
||||
$vcardData = Sabre_DAV_StringUtil::ensureUTF8($vcardData);
|
||||
|
||||
$this->carddavBackend->createCard($this->addressBookInfo['id'],$name,$vcardData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entire addressbook.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
$this->carddavBackend->deleteAddressBook($this->addressBookInfo['id']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the addressbook
|
||||
*
|
||||
* @param string $newName
|
||||
* @return void
|
||||
*/
|
||||
public function setName($newName) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Renaming addressbooks is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date as a unix timestamp.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties on this node,
|
||||
*
|
||||
* The properties 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 can be returned.
|
||||
* If the operation failed, false can be returned.
|
||||
*
|
||||
* Deletion of a non-existant property is always succesful.
|
||||
*
|
||||
* Lastly, it is optional to return detailed information about any
|
||||
* failures. In this case an array should be returned with the following
|
||||
* structure:
|
||||
*
|
||||
* array(
|
||||
* 403 => array(
|
||||
* '{DAV:}displayname' => null,
|
||||
* ),
|
||||
* 424 => array(
|
||||
* '{DAV:}owner' => null,
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* In this example it was forbidden to update {DAV:}displayname.
|
||||
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
|
||||
* (424 Failed Dependency) because the request needs to be atomic.
|
||||
*
|
||||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateProperties($mutations) {
|
||||
|
||||
return $this->carddavBackend->updateAddressBook($this->addressBookInfo['id'], $mutations);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of properties for this nodes.
|
||||
*
|
||||
* The properties list is a list of propertynames the client requested,
|
||||
* encoded in clark-notation {xmlnamespace}tagname
|
||||
*
|
||||
* If the array is empty, it means 'all properties' were requested.
|
||||
*
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function getProperties($properties) {
|
||||
|
||||
$response = array();
|
||||
foreach($properties as $propertyName) {
|
||||
|
||||
if (isset($this->addressBookInfo[$propertyName])) {
|
||||
|
||||
$response[$propertyName] = $this->addressBookInfo[$propertyName];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->addressBookInfo['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' => '{DAV:}read',
|
||||
'principal' => $this->addressBookInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->addressBookInfo['principaluri'],
|
||||
'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 Sabre_DAV_Exception_MethodNotAllowed('Changing ACL is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Parses the addressbook-query report request body.
|
||||
*
|
||||
* Whoever designed this format, and the CalDAV equavalent even more so,
|
||||
* has no feel for design.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_AddressBookQueryParser {
|
||||
|
||||
const TEST_ANYOF = 'anyof';
|
||||
const TEST_ALLOF = 'allof';
|
||||
|
||||
/**
|
||||
* List of requested properties the client wanted
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $requestedProperties;
|
||||
|
||||
/**
|
||||
* The number of results the client wants
|
||||
*
|
||||
* null means it wasn't specified, which in most cases means 'all results'.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
public $limit;
|
||||
|
||||
/**
|
||||
* List of property filters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $filters;
|
||||
|
||||
/**
|
||||
* Either TEST_ANYOF or TEST_ALLOF
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $test;
|
||||
|
||||
/**
|
||||
* DOM Document
|
||||
*
|
||||
* @var DOMDocument
|
||||
*/
|
||||
protected $dom;
|
||||
|
||||
/**
|
||||
* DOM XPath object
|
||||
*
|
||||
* @var DOMXPath
|
||||
*/
|
||||
protected $xpath;
|
||||
|
||||
/**
|
||||
* Creates the parser
|
||||
*
|
||||
* @param DOMNode $dom
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(DOMDocument $dom) {
|
||||
|
||||
$this->dom = $dom;
|
||||
|
||||
$this->xpath = new DOMXPath($dom);
|
||||
$this->xpath->registerNameSpace('card',Sabre_CardDAV_Plugin::NS_CARDDAV);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the request.
|
||||
*
|
||||
* @param DOMNode $dom
|
||||
* @return void
|
||||
*/
|
||||
public function parse() {
|
||||
|
||||
$filterNode = null;
|
||||
|
||||
$limit = $this->xpath->evaluate('number(/card:addressbook-query/card:limit/card:nresults)');
|
||||
if (is_nan($limit)) $limit = null;
|
||||
|
||||
$filter = $this->xpath->query('/card:addressbook-query/card:filter');
|
||||
if ($filter->length !== 1) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Only one filter element is allowed');
|
||||
}
|
||||
|
||||
$filter = $filter->item(0);
|
||||
$test = $this->xpath->evaluate('string(@test)', $filter);
|
||||
if (!$test) $test = self::TEST_ANYOF;
|
||||
if ($test !== self::TEST_ANYOF && $test !== self::TEST_ALLOF) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The test attribute must either hold "anyof" or "allof"');
|
||||
}
|
||||
|
||||
$propFilters = array();
|
||||
|
||||
$propFilterNodes = $this->xpath->query('card:prop-filter', $filter);
|
||||
for($ii=0; $ii < $propFilterNodes->length; $ii++) {
|
||||
|
||||
$propFilters[] = $this->parsePropFilterNode($propFilterNodes->item($ii));
|
||||
|
||||
|
||||
}
|
||||
|
||||
$this->filters = $propFilters;
|
||||
$this->limit = $limit;
|
||||
$this->requestedProperties = array_keys(Sabre_DAV_XMLUtil::parseProperties($this->dom->firstChild));
|
||||
$this->test = $test;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the prop-filter xml element
|
||||
*
|
||||
* @param DOMElement $propFilterNode
|
||||
* @return array
|
||||
*/
|
||||
protected function parsePropFilterNode(DOMElement $propFilterNode) {
|
||||
|
||||
$propFilter = array();
|
||||
$propFilter['name'] = $propFilterNode->getAttribute('name');
|
||||
$propFilter['test'] = $propFilterNode->getAttribute('test');
|
||||
if (!$propFilter['test']) $propFilter['test'] = 'anyof';
|
||||
|
||||
$propFilter['is-not-defined'] = $this->xpath->query('card:is-not-defined', $propFilterNode)->length>0;
|
||||
|
||||
$paramFilterNodes = $this->xpath->query('card:param-filter', $propFilterNode);
|
||||
|
||||
$propFilter['param-filters'] = array();
|
||||
|
||||
|
||||
for($ii=0;$ii<$paramFilterNodes->length;$ii++) {
|
||||
|
||||
$propFilter['param-filters'][] = $this->parseParamFilterNode($paramFilterNodes->item($ii));
|
||||
|
||||
}
|
||||
$propFilter['text-matches'] = array();
|
||||
$textMatchNodes = $this->xpath->query('card:text-match', $propFilterNode);
|
||||
|
||||
for($ii=0;$ii<$textMatchNodes->length;$ii++) {
|
||||
|
||||
$propFilter['text-matches'][] = $this->parseTextMatchNode($textMatchNodes->item($ii));
|
||||
|
||||
}
|
||||
|
||||
return $propFilter;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the param-filter element
|
||||
*
|
||||
* @param DOMElement $paramFilterNode
|
||||
* @return array
|
||||
*/
|
||||
public function parseParamFilterNode(DOMElement $paramFilterNode) {
|
||||
|
||||
$paramFilter = array();
|
||||
$paramFilter['name'] = $paramFilterNode->getAttribute('name');
|
||||
$paramFilter['is-not-defined'] = $this->xpath->query('card:is-not-defined', $paramFilterNode)->length>0;
|
||||
$paramFilter['text-match'] = null;
|
||||
|
||||
$textMatch = $this->xpath->query('card:text-match', $paramFilterNode);
|
||||
if ($textMatch->length>0) {
|
||||
$paramFilter['text-match'] = $this->parseTextMatchNode($textMatch->item(0));
|
||||
}
|
||||
|
||||
return $paramFilter;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Text match
|
||||
*
|
||||
* @param DOMElement $textMatchNode
|
||||
* @return void
|
||||
*/
|
||||
public function parseTextMatchNode(DOMElement $textMatchNode) {
|
||||
|
||||
$matchType = $textMatchNode->getAttribute('match-type');
|
||||
if (!$matchType) $matchType = 'contains';
|
||||
|
||||
if (!in_array($matchType, array('contains', 'equals', 'starts-with', 'ends-with'))) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Unknown match-type: ' . $matchType);
|
||||
}
|
||||
|
||||
$negateCondition = $textMatchNode->getAttribute('negate-condition');
|
||||
$negateCondition = $negateCondition==='yes';
|
||||
$collation = $textMatchNode->getAttribute('collation');
|
||||
if (!$collation) $collation = 'i;unicode-casemap';
|
||||
|
||||
return array(
|
||||
'negate-condition' => $negateCondition,
|
||||
'collation' => $collation,
|
||||
'match-type' => $matchType,
|
||||
'value' => $textMatchNode->nodeValue
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* AddressBook rootnode
|
||||
*
|
||||
* This object lists a collection of users, which can contain addressbooks.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_AddressBookRoot extends Sabre_DAVACL_AbstractPrincipalCollection {
|
||||
|
||||
/**
|
||||
* Principal Backend
|
||||
*
|
||||
* @var Sabre_DAVACL_IPrincipalBackend
|
||||
*/
|
||||
protected $principalBackend;
|
||||
|
||||
/**
|
||||
* CardDAV backend
|
||||
*
|
||||
* @var Sabre_CardDAV_Backend_Abstract
|
||||
*/
|
||||
protected $carddavBackend;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* This constructor needs both a principal and a carddav backend.
|
||||
*
|
||||
* By default this class will show a list of addressbook collections for
|
||||
* principals in the 'principals' collection. If your main principals are
|
||||
* actually located in a different path, use the $principalPrefix argument
|
||||
* to override this.
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CardDAV_Backend_Abstract $carddavBackend
|
||||
* @param string $principalPrefix
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend,Sabre_CardDAV_Backend_Abstract $carddavBackend, $principalPrefix = 'principals') {
|
||||
|
||||
$this->carddavBackend = $carddavBackend;
|
||||
parent::__construct($principalBackend, $principalPrefix);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the node
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return Sabre_CardDAV_Plugin::ADDRESSBOOK_ROOT;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a node for a principal.
|
||||
*
|
||||
* The passed array contains principal information, and is guaranteed to
|
||||
* at least contain a uri item. Other properties may or may not be
|
||||
* supplied by the authentication backend.
|
||||
*
|
||||
* @param array $principal
|
||||
* @return Sabre_DAV_INode
|
||||
*/
|
||||
public function getChildForPrincipal(array $principal) {
|
||||
|
||||
return new Sabre_CardDAV_UserAddressBooks($this->carddavBackend, $principal['uri']);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Abstract Backend class
|
||||
*
|
||||
* This class serves as a base-class for addressbook backends
|
||||
*
|
||||
* Note that there are references to 'addressBookId' scattered throughout the
|
||||
* class. The value of the addressBookId is completely up to you, it can be any
|
||||
* arbitrary value you can use as an unique identifier.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_CardDAV_Backend_Abstract {
|
||||
|
||||
/**
|
||||
* Returns the list of addressbooks for a specific user.
|
||||
*
|
||||
* Every addressbook should have the following properties:
|
||||
* id - an arbitrary unique id
|
||||
* uri - the 'basename' part of the url
|
||||
* principaluri - Same as the passed parameter
|
||||
*
|
||||
* Any additional clark-notation property may be passed besides this. Some
|
||||
* common ones are :
|
||||
* {DAV:}displayname
|
||||
* {urn:ietf:params:xml:ns:carddav}addressbook-description
|
||||
* {http://calendarserver.org/ns/}getctag
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public abstract function getAddressBooksForUser($principalUri);
|
||||
|
||||
/**
|
||||
* Updates an addressbook's properties
|
||||
*
|
||||
* See Sabre_DAV_IProperties for a description of the mutations array, as
|
||||
* well as the return value.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param array $mutations
|
||||
* @see Sabre_DAV_IProperties::updateProperties
|
||||
* @return bool|array
|
||||
*/
|
||||
public abstract function updateAddressBook($addressBookId, array $mutations);
|
||||
|
||||
/**
|
||||
* Creates a new address book
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $url Just the 'basename' of the url.
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
abstract public function createAddressBook($principalUri, $url, array $properties);
|
||||
|
||||
/**
|
||||
* Deletes an entire addressbook and all its contents
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @return void
|
||||
*/
|
||||
abstract public function deleteAddressBook($addressBookId);
|
||||
|
||||
/**
|
||||
* Returns all cards for a specific addressbook id.
|
||||
*
|
||||
* This method should return the following properties for each card:
|
||||
* * carddata - raw vcard data
|
||||
* * uri - Some unique url
|
||||
* * lastmodified - A unix timestamp
|
||||
|
||||
* @param mixed $addressbookId
|
||||
* @return array
|
||||
*/
|
||||
public abstract function getCards($addressbookId);
|
||||
|
||||
/**
|
||||
* Returns a specfic card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @return void
|
||||
*/
|
||||
public abstract function getCard($addressBookId, $cardUri);
|
||||
|
||||
/**
|
||||
* Creates a new card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $cardData
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function createCard($addressBookId, $cardUri, $cardData);
|
||||
|
||||
/**
|
||||
* Updates a card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $cardData
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function updateCard($addressBookId, $cardUri, $cardData);
|
||||
|
||||
/**
|
||||
* Deletes a card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function deleteCard($addressBookId, $cardUri);
|
||||
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PDO CardDAV backend
|
||||
*
|
||||
* This CardDAV backend uses PDO to store addressbooks
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
|
||||
|
||||
/**
|
||||
* PDO connection
|
||||
*
|
||||
* @var PDO
|
||||
*/
|
||||
protected $pdo;
|
||||
|
||||
/**
|
||||
* The PDO table name used to store addressbooks
|
||||
*/
|
||||
protected $addressBooksTableName;
|
||||
|
||||
/**
|
||||
* The PDO table name used to store cards
|
||||
*/
|
||||
protected $cardsTableName;
|
||||
|
||||
/**
|
||||
* Sets up the object
|
||||
*
|
||||
* @param PDO $pdo
|
||||
*/
|
||||
public function __construct(PDO $pdo, $addressBooksTableName = 'addressbooks', $cardsTableName = 'cards') {
|
||||
|
||||
$this->pdo = $pdo;
|
||||
$this->addressBooksTableName = $addressBooksTableName;
|
||||
$this->cardsTableName = $cardsTableName;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of addressbooks for a specific user.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getAddressBooksForUser($principalUri) {
|
||||
|
||||
$stmt = $this->pdo->prepare('SELECT id, uri, displayname, principaluri, description, ctag FROM `'.$this->addressBooksTableName.'` WHERE principaluri = ?');
|
||||
$result = $stmt->execute(array($principalUri));
|
||||
|
||||
$addressBooks = array();
|
||||
|
||||
foreach($stmt->fetchAll() as $row) {
|
||||
|
||||
$addressBooks[] = array(
|
||||
'id' => $row['id'],
|
||||
'uri' => $row['uri'],
|
||||
'principaluri' => $row['principaluri'],
|
||||
'{DAV:}displayname' => $row['displayname'],
|
||||
'{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
|
||||
'{http://calendarserver.org/ns/}getctag' => $row['ctag'],
|
||||
'{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}supported-address-data' =>
|
||||
new Sabre_CardDAV_Property_SupportedAddressData(),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $addressBooks;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates an addressbook's properties
|
||||
*
|
||||
* See Sabre_DAV_IProperties for a description of the mutations array, as
|
||||
* well as the return value.
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param array $mutations
|
||||
* @see Sabre_DAV_IProperties::updateProperties
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateAddressBook($addressBookId, array $mutations) {
|
||||
|
||||
$updates = array();
|
||||
|
||||
foreach($mutations as $property=>$newValue) {
|
||||
|
||||
switch($property) {
|
||||
case '{DAV:}displayname' :
|
||||
$updates['displayname'] = $newValue;
|
||||
break;
|
||||
case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' :
|
||||
$updates['description'] = $newValue;
|
||||
break;
|
||||
default :
|
||||
// If any unsupported values were being updated, we must
|
||||
// let the entire request fail.
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// No values are being updated?
|
||||
if (!$updates) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = 'UPDATE `' . $this->addressBooksTableName . '` SET ctag = ctag + 1 ';
|
||||
foreach($updates as $key=>$value) {
|
||||
$query.=', `' . $key . '` = :' . $key . ' ';
|
||||
}
|
||||
$query.=' WHERE id = :addressbookid';
|
||||
|
||||
$stmt = $this->pdo->prepare($query);
|
||||
$updates['addressbookid'] = $addressBookId;
|
||||
|
||||
$stmt->execute($updates);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new address book
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $url Just the 'basename' of the url.
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function createAddressBook($principalUri, $url, array $properties) {
|
||||
|
||||
$values = array(
|
||||
'displayname' => null,
|
||||
'description' => null,
|
||||
'principaluri' => $principalUri,
|
||||
'uri' => $url,
|
||||
);
|
||||
|
||||
foreach($properties as $property=>$newValue) {
|
||||
|
||||
switch($property) {
|
||||
case '{DAV:}displayname' :
|
||||
$values['displayname'] = $newValue;
|
||||
break;
|
||||
case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' :
|
||||
$values['description'] = $newValue;
|
||||
break;
|
||||
default :
|
||||
throw new Sabre_DAV_Exception_BadRequest('Unknown property: ' . $property);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$query = 'INSERT INTO `' . $this->addressBooksTableName . '` (uri, displayname, description, principaluri, ctag) VALUES (:uri, :displayname, :description, :principaluri, 1)';
|
||||
$stmt = $this->pdo->prepare($query);
|
||||
$stmt->execute($values);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entire addressbook and all its contents
|
||||
*
|
||||
* @param int $addressBookId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteAddressBook($addressBookId) {
|
||||
|
||||
$stmt = $this->pdo->prepare('DELETE FROM `' . $this->cardsTableName . '` WHERE addressbookid = ?');
|
||||
$stmt->execute(array($addressBookId));
|
||||
|
||||
$stmt = $this->pdo->prepare('DELETE FROM `' . $this->addressBooksTableName . '` WHERE id = ?');
|
||||
$stmt->execute(array($addressBookId));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all cards for a specific addressbook id.
|
||||
*
|
||||
* @param mixed $addressbookId
|
||||
* @return array
|
||||
*/
|
||||
public function getCards($addressbookId) {
|
||||
|
||||
$stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM `' . $this->cardsTableName . '` WHERE addressbookid = ?');
|
||||
$stmt->execute(array($addressbookId));
|
||||
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* Returns a specfic card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCard($addressBookId, $cardUri) {
|
||||
|
||||
$stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM `' . $this->cardsTableName . '` WHERE addressbookid = ? AND uri = ? LIMIT 1');
|
||||
$stmt->execute(array($addressBookId, $cardUri));
|
||||
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
return (count($result)>0?$result[0]:false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $cardData
|
||||
* @return bool
|
||||
*/
|
||||
public function createCard($addressBookId, $cardUri, $cardData) {
|
||||
|
||||
$stmt = $this->pdo->prepare('INSERT INTO `' . $this->cardsTableName . '` (carddata, uri, lastmodified, addressbookid) VALUES (?, ?, ?, ?)');
|
||||
|
||||
$result = $stmt->execute(array($cardData, $cardUri, time(), $addressBookId));
|
||||
|
||||
$stmt2 = $this->pdo->prepare('UPDATE `' . $this->addressBooksTableName . '` SET ctag = ctag + 1 WHERE id = ?');
|
||||
$stmt2->execute(array($addressBookId));
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @param string $cardData
|
||||
* @return bool
|
||||
*/
|
||||
public function updateCard($addressBookId, $cardUri, $cardData) {
|
||||
|
||||
$stmt = $this->pdo->prepare('UPDATE `' . $this->cardsTableName . '` SET carddata = ?, lastmodified = ? WHERE uri = ? AND addressbookid =?');
|
||||
$result = $stmt->execute(array($cardData, time(), $cardUri, $addressBookId));
|
||||
|
||||
$stmt2 = $this->pdo->prepare('UPDATE `' . $this->addressBooksTableName . '` SET ctag = ctag + 1 WHERE id = ?');
|
||||
$stmt2->execute(array($addressBookId));
|
||||
|
||||
return $stmt->rowCount()===1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a card
|
||||
*
|
||||
* @param mixed $addressBookId
|
||||
* @param string $cardUri
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteCard($addressBookId, $cardUri) {
|
||||
|
||||
$stmt = $this->pdo->prepare('DELETE FROM `' . $this->cardsTableName . '` WHERE addressbookid = ? AND uri = ?');
|
||||
$stmt->execute(array($addressBookId, $cardUri));
|
||||
|
||||
$stmt2 = $this->pdo->prepare('UPDATE `' . $this->addressBooksTableName . '` SET ctag = ctag + 1 WHERE id = ?');
|
||||
$stmt2->execute(array($addressBookId));
|
||||
|
||||
return $stmt->rowCount()===1;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The Card object represents a single Card from an addressbook
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_Card extends Sabre_DAV_File implements Sabre_CardDAV_ICard, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* CardDAV backend
|
||||
*
|
||||
* @var Sabre_CardDAV_Backend_Abstract
|
||||
*/
|
||||
private $carddavBackend;
|
||||
|
||||
/**
|
||||
* Array with information about this Card
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cardData;
|
||||
|
||||
/**
|
||||
* Array with information about the containing addressbook
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $addressBookInfo;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CardDAV_Backend_Abstract $carddavBackend
|
||||
* @param array $addressBookInfo
|
||||
* @param array $cardData
|
||||
*/
|
||||
public function __construct(Sabre_CardDAV_Backend_Abstract $carddavBackend,array $addressBookInfo,array $cardData) {
|
||||
|
||||
$this->carddavBackend = $carddavBackend;
|
||||
$this->addressBookInfo = $addressBookInfo;
|
||||
$this->cardData = $cardData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uri for this object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return $this->cardData['uri'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the VCard-formatted object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get() {
|
||||
|
||||
// Pre-populating 'carddata' is optional. If we don't yet have it
|
||||
// already, we fetch it from the backend.
|
||||
if (!isset($this->cardData['carddata'])) {
|
||||
$this->cardData = $this->carddavBackend->getCard($this->addressBookInfo['id'], $this->cardData['uri']);
|
||||
}
|
||||
return $this->cardData['carddata'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the VCard-formatted object
|
||||
*
|
||||
* @param string $cardData
|
||||
* @return void
|
||||
*/
|
||||
public function put($cardData) {
|
||||
|
||||
if (is_resource($cardData))
|
||||
$cardData = stream_get_contents($cardData);
|
||||
|
||||
// Converting to UTF-8, if needed
|
||||
$cardData = Sabre_DAV_StringUtil::ensureUTF8($cardData);
|
||||
|
||||
$this->carddavBackend->updateCard($this->addressBookInfo['id'],$this->cardData['uri'],$cardData);
|
||||
$this->cardData['carddata'] = $cardData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the card
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
$this->carddavBackend->deleteCard($this->addressBookInfo['id'],$this->cardData['uri']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime content-type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContentType() {
|
||||
|
||||
return 'text/x-vcard';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ETag for this object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getETag() {
|
||||
|
||||
if (isset($this->cardData['etag'])) {
|
||||
return $this->cardData['etag'];
|
||||
} else {
|
||||
return '"' . md5($this->get()) . '"';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date as a unix timestamp
|
||||
*
|
||||
* @return time
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return isset($this->cardData['lastmodified'])?$this->cardData['lastmodified']:null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of this object in bytes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() {
|
||||
|
||||
return strlen($this->get());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->addressBookInfo['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' => '{DAV:}read',
|
||||
'principal' => $this->addressBookInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->addressBookInfo['principaluri'],
|
||||
'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 Sabre_DAV_Exception_MethodNotAllowed('Changing ACL is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* AddressBook interface
|
||||
*
|
||||
* Implement this interface to allow a node to be recognized as an addressbook.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CardDAV_IAddressBook extends Sabre_DAV_ICollection {
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Card interface
|
||||
*
|
||||
* Extend the ICard interface to allow your custom nodes to be picked up as
|
||||
* 'Cards'.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CardDAV_ICard extends Sabre_DAV_IFile {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* IDirectory interface
|
||||
*
|
||||
* Implement this interface to have an addressbook marked as a 'directory'. A
|
||||
* directory is an (often) global addressbook.
|
||||
*
|
||||
* A full description can be found in the IETF draft:
|
||||
* - draft-daboo-carddav-directory-gateway
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_CardDAV_IDirectory extends Sabre_CardDAV_IAddressBook {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,463 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* CardDAV plugin
|
||||
*
|
||||
* The CardDAV plugin adds CardDAV functionality to the WebDAV server
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
||||
|
||||
/**
|
||||
* Url to the addressbooks
|
||||
*/
|
||||
const ADDRESSBOOK_ROOT = 'addressbooks';
|
||||
|
||||
/**
|
||||
* xml namespace for CardDAV elements
|
||||
*/
|
||||
const NS_CARDDAV = 'urn:ietf:params:xml:ns:carddav';
|
||||
|
||||
/**
|
||||
* Add urls to this property to have them automatically exposed as
|
||||
* 'directories' to the user.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $directories = array();
|
||||
|
||||
/**
|
||||
* Server class
|
||||
*
|
||||
* @var Sabre_DAV_Server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Initializes the plugin
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
/* Events */
|
||||
$server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
|
||||
$server->subscribeEvent('report', array($this,'report'));
|
||||
|
||||
/* Namespaces */
|
||||
$server->xmlNamespaces[self::NS_CARDDAV] = 'card';
|
||||
|
||||
/* Mapping Interfaces to {DAV:}resourcetype values */
|
||||
$server->resourceTypeMapping['Sabre_CardDAV_IAddressBook'] = '{' . self::NS_CARDDAV . '}addressbook';
|
||||
$server->resourceTypeMapping['Sabre_CardDAV_IDirectory'] = '{' . self::NS_CARDDAV . '}directory';
|
||||
|
||||
/* Adding properties that may never be changed */
|
||||
$server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-address-data';
|
||||
$server->protectedProperties[] = '{' . self::NS_CARDDAV . '}max-resource-size';
|
||||
|
||||
|
||||
$this->server = $server;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of supported features.
|
||||
*
|
||||
* This is used in the DAV: header in the OPTIONS and PROPFIND requests.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFeatures() {
|
||||
|
||||
return array('addressbook');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of reports this plugin supports.
|
||||
*
|
||||
* This will be used in the {DAV:}supported-report-set property.
|
||||
* Note that you still need to subscribe to the 'report' event to actually
|
||||
* implement them
|
||||
*
|
||||
* @param string $uri
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedReportSet($uri) {
|
||||
|
||||
$node = $this->server->tree->getNodeForPath($uri);
|
||||
if ($node instanceof Sabre_CardDAV_IAddressBook || $node instanceof Sabre_CardDAV_ICard) {
|
||||
return array(
|
||||
'{' . self::NS_CARDDAV . '}addressbook-multiget',
|
||||
'{' . self::NS_CARDDAV . '}addressbook-query',
|
||||
);
|
||||
}
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds all CardDAV-specific properties
|
||||
*
|
||||
* @param string $path
|
||||
* @param Sabre_DAV_INode $node
|
||||
* @param array $requestedProperties
|
||||
* @param array $returnedProperties
|
||||
* @return void
|
||||
*/
|
||||
public function beforeGetProperties($path, Sabre_DAV_INode $node, array &$requestedProperties, array &$returnedProperties) {
|
||||
|
||||
if ($node instanceof Sabre_DAVACL_IPrincipal) {
|
||||
|
||||
// calendar-home-set property
|
||||
$addHome = '{' . self::NS_CARDDAV . '}addressbook-home-set';
|
||||
if (in_array($addHome,$requestedProperties)) {
|
||||
$principalId = $node->getName();
|
||||
$addressbookHomePath = self::ADDRESSBOOK_ROOT . '/' . $principalId . '/';
|
||||
unset($requestedProperties[array_search($addHome, $requestedProperties)]);
|
||||
$returnedProperties[200][$addHome] = new Sabre_DAV_Property_Href($addressbookHomePath);
|
||||
}
|
||||
|
||||
$directories = '{' . self::NS_CARDDAV . '}directory-gateway';
|
||||
if ($this->directories && in_array($directories, $requestedProperties)) {
|
||||
unset($requestedProperties[array_search($directories, $requestedProperties)]);
|
||||
$returnedProperties[200][$directories] = new Sabre_DAV_Property_HrefList($this->directories);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($node instanceof Sabre_CardDAV_ICard) {
|
||||
|
||||
// The address-data property is not supposed to be a 'real'
|
||||
// property, but in large chunks of the spec it does act as such.
|
||||
// Therefore we simply expose it as a property.
|
||||
$addressDataProp = '{' . self::NS_CARDDAV . '}address-data';
|
||||
if (in_array($addressDataProp, $requestedProperties)) {
|
||||
unset($requestedProperties[$addressDataProp]);
|
||||
$val = $node->get();
|
||||
if (is_resource($val))
|
||||
$val = stream_get_contents($val);
|
||||
|
||||
// Taking out \r to not screw up the xml output
|
||||
$returnedProperties[200][$addressDataProp] = str_replace("\r","", $val);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This functions handles REPORT requests specific to CardDAV
|
||||
*
|
||||
* @param string $reportName
|
||||
* @param DOMNode $dom
|
||||
* @return bool
|
||||
*/
|
||||
public function report($reportName,$dom) {
|
||||
|
||||
switch($reportName) {
|
||||
case '{'.self::NS_CARDDAV.'}addressbook-multiget' :
|
||||
$this->addressbookMultiGetReport($dom);
|
||||
return false;
|
||||
case '{'.self::NS_CARDDAV.'}addressbook-query' :
|
||||
$this->addressBookQueryReport($dom);
|
||||
return false;
|
||||
default :
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles the addressbook-multiget REPORT.
|
||||
*
|
||||
* This report is used by the client to fetch the content of a series
|
||||
* of urls. Effectively avoiding a lot of redundant requests.
|
||||
*
|
||||
* @param DOMNode $dom
|
||||
* @return void
|
||||
*/
|
||||
public function addressbookMultiGetReport($dom) {
|
||||
|
||||
$properties = array_keys(Sabre_DAV_XMLUtil::parseProperties($dom->firstChild));
|
||||
|
||||
$hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href');
|
||||
$propertyList = array();
|
||||
|
||||
foreach($hrefElems as $elem) {
|
||||
|
||||
$uri = $this->server->calculateUri($elem->nodeValue);
|
||||
list($propertyList[]) = $this->server->getPropertiesForPath($uri,$properties);
|
||||
|
||||
}
|
||||
|
||||
$this->server->httpResponse->sendStatus(207);
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
|
||||
$this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles the addressbook-query REPORT
|
||||
*
|
||||
* This report is used by the client to filter an addressbook based on a
|
||||
* complex query.
|
||||
*
|
||||
* @param DOMNode $dom
|
||||
* @return void
|
||||
*/
|
||||
protected function addressbookQueryReport($dom) {
|
||||
|
||||
$query = new Sabre_CardDAV_AddressBookQueryParser($dom);
|
||||
$query->parse();
|
||||
|
||||
$depth = $this->server->getHTTPDepth(0);
|
||||
|
||||
if ($depth==0) {
|
||||
$candidateNodes = array(
|
||||
$this->server->tree->getNodeForPath($this->server->getRequestUri())
|
||||
);
|
||||
} else {
|
||||
$candidateNodes = $this->server->tree->getChildren($this->server->getRequestUri());
|
||||
}
|
||||
|
||||
$validNodes = array();
|
||||
foreach($candidateNodes as $node) {
|
||||
|
||||
if (!$node instanceof Sabre_CardDAV_ICard)
|
||||
continue;
|
||||
|
||||
$blob = $node->get();
|
||||
if (is_resource($blob)) {
|
||||
$blob = stream_get_contents($blob);
|
||||
}
|
||||
|
||||
if (!$this->validateFilters($blob, $query->filters, $query->test)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$validNodes[] = $node;
|
||||
|
||||
if ($query->limit && $query->limit <= count($validNodes)) {
|
||||
// We hit the maximum number of items, we can stop now.
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach($validNodes as $validNode) {
|
||||
if ($depth==0) {
|
||||
$href = $this->server->getRequestUri();
|
||||
} else {
|
||||
$href = $this->server->getRequestUri() . '/' . $validNode->getName();
|
||||
}
|
||||
|
||||
list($result[]) = $this->server->getPropertiesForPath($href, $query->requestedProperties, 0);
|
||||
|
||||
}
|
||||
|
||||
$this->server->httpResponse->sendStatus(207);
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
|
||||
$this->server->httpResponse->sendBody($this->server->generateMultiStatus($result));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if a vcard makes it throught a list of filters.
|
||||
*
|
||||
* @param string $vcardData
|
||||
* @param array $filters
|
||||
* @param string $test anyof or allof (which means OR or AND)
|
||||
* @return bool
|
||||
*/
|
||||
public function validateFilters($vcardData, array $filters, $test) {
|
||||
|
||||
$vcard = Sabre_VObject_Reader::read($vcardData);
|
||||
|
||||
$success = true;
|
||||
|
||||
foreach($filters as $filter) {
|
||||
|
||||
$isDefined = isset($vcard->{$filter['name']});
|
||||
if ($filter['is-not-defined']) {
|
||||
if ($isDefined) {
|
||||
$success = false;
|
||||
} else {
|
||||
$success = true;
|
||||
}
|
||||
} elseif ((!$filter['param-filters'] && !$filter['text-matches']) || !$isDefined) {
|
||||
|
||||
// We only need to check for existence
|
||||
$success = $isDefined;
|
||||
|
||||
} else {
|
||||
|
||||
$vProperties = $vcard->select($filter['name']);
|
||||
|
||||
$results = array();
|
||||
if ($filter['param-filters']) {
|
||||
$results[] = $this->validateParamFilters($vProperties, $filter['param-filters'], $filter['test']);
|
||||
}
|
||||
if ($filter['text-matches']) {
|
||||
$texts = array();
|
||||
foreach($vProperties as $vProperty)
|
||||
$texts[] = $vProperty->value;
|
||||
|
||||
$results[] = $this->validateTextMatches($texts, $filter['text-matches'], $filter['test']);
|
||||
}
|
||||
|
||||
if (count($results)===1) {
|
||||
$success = $results[0];
|
||||
} else {
|
||||
if ($filter['test'] === 'anyof') {
|
||||
$success = $results[0] || $results[1];
|
||||
} else {
|
||||
$success = $results[0] && $results[1];
|
||||
}
|
||||
}
|
||||
|
||||
} // else
|
||||
|
||||
// There are two conditions where we can already determine wether
|
||||
// or not this filter succeeds.
|
||||
if ($test==='anyof' && $success) {
|
||||
return true;
|
||||
}
|
||||
if ($test==='allof' && !$success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // foreach
|
||||
|
||||
// If we got all the way here, it means we haven't been able to
|
||||
// determine early if the test failed or not.
|
||||
//
|
||||
// This implies for 'anyof' that the test failed, and for 'allof' that
|
||||
// we succeeded. Sounds weird, but makes sense.
|
||||
return $test==='allof';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if a param-filter can be applied to a specific property.
|
||||
*
|
||||
* @todo currently we're only validating the first parameter of the passed
|
||||
* property. Any subsequence parameters with the same name are
|
||||
* ignored.
|
||||
* @param Sabre_VObject_Property $vProperty
|
||||
* @param array $filters
|
||||
* @param string $test
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateParamFilters(array $vProperties, array $filters, $test) {
|
||||
|
||||
$success = false;
|
||||
foreach($filters as $filter) {
|
||||
|
||||
$isDefined = false;
|
||||
foreach($vProperties as $vProperty) {
|
||||
$isDefined = isset($vProperty[$filter['name']]);
|
||||
if ($isDefined) break;
|
||||
}
|
||||
|
||||
if ($filter['is-not-defined']) {
|
||||
if ($isDefined) {
|
||||
$success = false;
|
||||
} else {
|
||||
$success = true;
|
||||
}
|
||||
|
||||
// If there's no text-match, we can just check for existence
|
||||
} elseif (!$filter['text-match'] || !$isDefined) {
|
||||
|
||||
$success = $isDefined;
|
||||
|
||||
} else {
|
||||
|
||||
$texts = array();
|
||||
$success = false;
|
||||
foreach($vProperties as $vProperty) {
|
||||
// If we got all the way here, we'll need to validate the
|
||||
// text-match filter.
|
||||
$success = Sabre_DAV_StringUtil::textMatch($vProperty[$filter['name']]->value, $filter['text-match']['value'], $filter['text-match']['collation'], $filter['text-match']['match-type']);
|
||||
if ($success) break;
|
||||
}
|
||||
if ($filter['text-match']['negate-condition']) {
|
||||
$success = !$success;
|
||||
}
|
||||
|
||||
} // else
|
||||
|
||||
// There are two conditions where we can already determine wether
|
||||
// or not this filter succeeds.
|
||||
if ($test==='anyof' && $success) {
|
||||
return true;
|
||||
}
|
||||
if ($test==='allof' && !$success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If we got all the way here, it means we haven't been able to
|
||||
// determine early if the test failed or not.
|
||||
//
|
||||
// This implies for 'anyof' that the test failed, and for 'allof' that
|
||||
// we succeeded. Sounds weird, but makes sense.
|
||||
return $test==='allof';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if a text-filter can be applied to a specific property.
|
||||
*
|
||||
* @param array $texts
|
||||
* @param array $filters
|
||||
* @param string $test
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateTextMatches(array $texts, array $filters, $test) {
|
||||
|
||||
foreach($filters as $filter) {
|
||||
|
||||
$success = false;
|
||||
foreach($texts as $haystack) {
|
||||
$success = Sabre_DAV_StringUtil::textMatch($haystack, $filter['value'], $filter['collation'], $filter['match-type']);
|
||||
|
||||
// Breaking on the first match
|
||||
if ($success) break;
|
||||
}
|
||||
if ($filter['negate-condition']) {
|
||||
$success = !$success;
|
||||
}
|
||||
|
||||
if ($success && $test==='anyof')
|
||||
return true;
|
||||
|
||||
if (!$success && $test=='allof')
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// If we got all the way here, it means we haven't been able to
|
||||
// determine early if the test failed or not.
|
||||
//
|
||||
// This implies for 'anyof' that the test failed, and for 'allof' that
|
||||
// we succeeded. Sounds weird, but makes sense.
|
||||
return $test==='allof';
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Supported-address-data property
|
||||
*
|
||||
* This property is a representation of the supported-address-data property
|
||||
* in the CardDAV namespace.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_Property_SupportedAddressData extends Sabre_DAV_Property {
|
||||
|
||||
/**
|
||||
* supported versions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedData = array();
|
||||
|
||||
/**
|
||||
* Creates the property
|
||||
*
|
||||
* @param array $components
|
||||
*/
|
||||
public function __construct(array $supportedData = null) {
|
||||
|
||||
if (is_null($supportedData)) {
|
||||
$supportedData = array(
|
||||
array('contentType' => 'text/vcard', 'version' => '3.0'),
|
||||
array('contentType' => 'text/vcard', 'version' => '4.0'),
|
||||
);
|
||||
}
|
||||
|
||||
$this->supportedData = $supportedData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the property in a DOMDocument
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $node) {
|
||||
|
||||
$doc = $node->ownerDocument;
|
||||
|
||||
$prefix =
|
||||
isset($server->xmlNamespaces[Sabre_CardDAV_Plugin::NS_CARDDAV]) ?
|
||||
$server->xmlNamespaces[Sabre_CardDAV_Plugin::NS_CARDDAV] :
|
||||
'card';
|
||||
|
||||
foreach($this->supportedData as $supported) {
|
||||
|
||||
$caldata = $doc->createElementNS(Sabre_CardDAV_Plugin::NS_CARDDAV, $prefix . ':address-data-type');
|
||||
$caldata->setAttribute('content-type',$supported['contentType']);
|
||||
$caldata->setAttribute('version',$supported['version']);
|
||||
$node->appendChild($caldata);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* UserAddressBooks class
|
||||
*
|
||||
* The UserAddressBooks collection contains a list of addressbooks associated with a user
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_UserAddressBooks extends Sabre_DAV_Collection implements Sabre_DAV_IExtendedCollection, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* Principal uri
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $principalUri;
|
||||
|
||||
/**
|
||||
* carddavBackend
|
||||
*
|
||||
* @var Sabre_CardDAV_Backend_Abstract
|
||||
*/
|
||||
protected $carddavBackend;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CardDAV_Backend_Abstract $carddavBackend
|
||||
* @param string $principalUri
|
||||
*/
|
||||
public function __construct(Sabre_CardDAV_Backend_Abstract $carddavBackend, $principalUri) {
|
||||
|
||||
$this->carddavBackend = $carddavBackend;
|
||||
$this->principalUri = $principalUri;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
list(,$name) = Sabre_DAV_URLUtil::splitPath($this->principalUri);
|
||||
return $name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the name of this object
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function setName($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last modification date
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new file under this object.
|
||||
*
|
||||
* This is currently not allowed
|
||||
*
|
||||
* @param string $filename
|
||||
* @param resource $data
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($filename, $data=null) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Creating new files in this collection is not supported');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new directory under this object.
|
||||
*
|
||||
* This is currently not allowed.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($filename) {
|
||||
|
||||
throw new Sabre_DAV_Exception_MethodNotAllowed('Creating new collections in this collection is not supported');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single calendar, by name
|
||||
*
|
||||
* @param string $name
|
||||
* @todo needs optimizing
|
||||
* @return Sabre_CardDAV_AddressBook
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
foreach($this->getChildren() as $child) {
|
||||
if ($name==$child->getName())
|
||||
return $child;
|
||||
|
||||
}
|
||||
throw new Sabre_DAV_Exception_FileNotFound('Addressbook with name \'' . $name . '\' could not be found');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of addressbooks
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$addressbooks = $this->carddavBackend->getAddressbooksForUser($this->principalUri);
|
||||
$objs = array();
|
||||
foreach($addressbooks as $addressbook) {
|
||||
$objs[] = new Sabre_CardDAV_AddressBook($this->carddavBackend, $addressbook);
|
||||
}
|
||||
return $objs;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new addressbook
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $resourceType
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function createExtendedCollection($name, array $resourceType, array $properties) {
|
||||
|
||||
if (!in_array('{'.Sabre_CardDAV_Plugin::NS_CARDDAV.'}addressbook',$resourceType) || count($resourceType)!==2) {
|
||||
throw new Sabre_DAV_Exception_InvalidResourceType('Unknown resourceType for this collection');
|
||||
}
|
||||
$this->carddavBackend->createAddressBook($this->principalUri, $name, $properties);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => '{DAV:}read',
|
||||
'principal' => $this->principalUri,
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}write',
|
||||
'principal' => $this->principalUri,
|
||||
'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 Sabre_DAV_Exception_MethodNotAllowed('Changing ACL is not yet supported');
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Version Class
|
||||
*
|
||||
* This class contains the Sabre_CardDAV version information
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_Version {
|
||||
|
||||
/**
|
||||
* Full version number
|
||||
*/
|
||||
const VERSION = '1.5.7';
|
||||
|
||||
/**
|
||||
* Stability : alpha, beta, stable
|
||||
*/
|
||||
const STABILITY = 'stable';
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* HTTP Basic authentication backend class
|
||||
*
|
||||
* This class can be used by authentication objects wishing to use HTTP Basic
|
||||
* Most of the digest logic is handled, implementors just need to worry about
|
||||
* the validateUserPass method.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author James David Low (http://jameslow.com/)
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_Auth_Backend_AbstractBasic implements Sabre_DAV_Auth_IBackend {
|
||||
|
||||
/**
|
||||
* This variable holds the currently logged in username.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Validates a username and password
|
||||
*
|
||||
* This method should return true or false depending on if login
|
||||
* succeeded.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function validateUserPass($username, $password);
|
||||
|
||||
/**
|
||||
* Returns information about the currently logged in username.
|
||||
*
|
||||
* If nobody is currently logged in, this method should return null.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentUser() {
|
||||
return $this->currentUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Authenticates the user based on the current request.
|
||||
*
|
||||
* If authentication is succesful, true must be returned.
|
||||
* If authentication fails, an exception must be thrown.
|
||||
*
|
||||
* @throws Sabre_DAV_Exception_NotAuthenticated
|
||||
* @return bool
|
||||
*/
|
||||
public function authenticate(Sabre_DAV_Server $server,$realm) {
|
||||
|
||||
$auth = new Sabre_HTTP_BasicAuth();
|
||||
$auth->setHTTPRequest($server->httpRequest);
|
||||
$auth->setHTTPResponse($server->httpResponse);
|
||||
$auth->setRealm($realm);
|
||||
$userpass = $auth->getUserPass();
|
||||
if (!$userpass) {
|
||||
$auth->requireLogin();
|
||||
throw new Sabre_DAV_Exception_NotAuthenticated('No basic authentication headers were found');
|
||||
}
|
||||
|
||||
// Authenticates the user
|
||||
if (!$this->validateUserPass($userpass[0],$userpass[1])) {
|
||||
$auth->requireLogin();
|
||||
throw new Sabre_DAV_Exception_NotAuthenticated('Username or password does not match');
|
||||
}
|
||||
$this->currentUser = $userpass[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* HTTP Digest authentication backend class
|
||||
*
|
||||
* This class can be used by authentication objects wishing to use HTTP Digest
|
||||
* Most of the digest logic is handled, implementors just need to worry about
|
||||
* the getDigestHash method
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_Auth_Backend_AbstractDigest implements Sabre_DAV_Auth_IBackend {
|
||||
|
||||
/**
|
||||
* This variable holds the currently logged in username.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Returns a users digest hash based on the username and realm.
|
||||
*
|
||||
* If the user was not known, null must be returned.
|
||||
*
|
||||
* @param string $realm
|
||||
* @param string $username
|
||||
* @return string|null
|
||||
*/
|
||||
abstract public function getDigestHash($realm,$username);
|
||||
|
||||
/**
|
||||
* Authenticates the user based on the current request.
|
||||
*
|
||||
* If authentication is succesful, true must be returned.
|
||||
* If authentication fails, an exception must be thrown.
|
||||
*
|
||||
* @throws Sabre_DAV_Exception_NotAuthenticated
|
||||
* @return bool
|
||||
*/
|
||||
public function authenticate(Sabre_DAV_Server $server,$realm) {
|
||||
|
||||
$digest = new Sabre_HTTP_DigestAuth();
|
||||
|
||||
// Hooking up request and response objects
|
||||
$digest->setHTTPRequest($server->httpRequest);
|
||||
$digest->setHTTPResponse($server->httpResponse);
|
||||
|
||||
$digest->setRealm($realm);
|
||||
$digest->init();
|
||||
|
||||
$username = $digest->getUsername();
|
||||
|
||||
// No username was given
|
||||
if (!$username) {
|
||||
$digest->requireLogin();
|
||||
throw new Sabre_DAV_Exception_NotAuthenticated('No digest authentication headers were found');
|
||||
}
|
||||
|
||||
$hash = $this->getDigestHash($realm, $username);
|
||||
// If this was false, the user account didn't exist
|
||||
if ($hash===false || is_null($hash)) {
|
||||
$digest->requireLogin();
|
||||
throw new Sabre_DAV_Exception_NotAuthenticated('The supplied username was not on file');
|
||||
}
|
||||
if (!is_string($hash)) {
|
||||
throw new Sabre_DAV_Exception('The returned value from getDigestHash must be a string or null');
|
||||
}
|
||||
|
||||
// If this was false, the password or part of the hash was incorrect.
|
||||
if (!$digest->validateA1($hash)) {
|
||||
$digest->requireLogin();
|
||||
throw new Sabre_DAV_Exception_NotAuthenticated('Incorrect username');
|
||||
}
|
||||
|
||||
$this->currentUser = $username;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently logged in username.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentUser() {
|
||||
|
||||
return $this->currentUser;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Apache authenticator
|
||||
*
|
||||
* This authentication backend assumes that authentication has been
|
||||
* conifgured in apache, rather than within SabreDAV.
|
||||
*
|
||||
* Make sure apache is properly configured for this to work.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Auth_Backend_Apache implements Sabre_DAV_Auth_IBackend {
|
||||
|
||||
/**
|
||||
* Current apache user
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $remoteUser;
|
||||
|
||||
/**
|
||||
* Authenticates the user based on the current request.
|
||||
*
|
||||
* If authentication is succesful, true must be returned.
|
||||
* If authentication fails, an exception must be thrown.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authenticate(Sabre_DAV_Server $server,$realm) {
|
||||
|
||||
$remoteUser = $server->httpRequest->getRawServerValue('REMOTE_USER');
|
||||
if (is_null($remoteUser)) {
|
||||
throw new Sabre_DAV_Exception('We did not receive the $_SERVER[REMOTE_USER] property. This means that apache might have been misconfigured');
|
||||
}
|
||||
|
||||
$this->remoteUser = $remoteUser;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about the currently logged in user.
|
||||
*
|
||||
* If nobody is currently logged in, this method should return null.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getCurrentUser() {
|
||||
|
||||
return $this->remoteUser;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This is an authentication backend that uses a file to manage passwords.
|
||||
*
|
||||
* The backend file must conform to Apache's htdigest format
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Auth_Backend_File extends Sabre_DAV_Auth_Backend_AbstractDigest {
|
||||
|
||||
/**
|
||||
* List of users
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $users = array();
|
||||
|
||||
/**
|
||||
* Creates the backend object.
|
||||
*
|
||||
* If the filename argument is passed in, it will parse out the specified file fist.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($filename=null) {
|
||||
|
||||
if (!is_null($filename))
|
||||
$this->loadFile($filename);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an htdigest-formatted file. This method can be called multiple times if
|
||||
* more than 1 file is used.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return void
|
||||
*/
|
||||
public function loadFile($filename) {
|
||||
|
||||
foreach(file($filename,FILE_IGNORE_NEW_LINES) as $line) {
|
||||
|
||||
if (substr_count($line, ":") !== 2)
|
||||
throw new Sabre_DAV_Exception('Malformed htdigest file. Every line should contain 2 colons');
|
||||
|
||||
list($username,$realm,$A1) = explode(':',$line);
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9]{32}$/', $A1))
|
||||
throw new Sabre_DAV_Exception('Malformed htdigest file. Invalid md5 hash');
|
||||
|
||||
$this->users[$realm . ':' . $username] = $A1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a users' information
|
||||
*
|
||||
* @param string $realm
|
||||
* @param string $username
|
||||
* @return string
|
||||
*/
|
||||
public function getDigestHash($realm, $username) {
|
||||
|
||||
return isset($this->users[$realm . ':' . $username])?$this->users[$realm . ':' . $username]:false;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This is an authentication backend that uses a file to manage passwords.
|
||||
*
|
||||
* The backend file must conform to Apache's htdigest format
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Auth_Backend_PDO extends Sabre_DAV_Auth_Backend_AbstractDigest {
|
||||
|
||||
/**
|
||||
* Reference to PDO connection
|
||||
*
|
||||
* @var PDO
|
||||
*/
|
||||
protected $pdo;
|
||||
|
||||
/**
|
||||
* PDO table name we'll be using
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tableName;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the backend object.
|
||||
*
|
||||
* If the filename argument is passed in, it will parse out the specified file fist.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $tableName The PDO table name to use
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(PDO $pdo, $tableName = 'users') {
|
||||
|
||||
$this->pdo = $pdo;
|
||||
$this->tableName = $tableName;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest hash for a user.
|
||||
*
|
||||
* @param string $realm
|
||||
* @param string $username
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDigestHash($realm,$username) {
|
||||
|
||||
$stmt = $this->pdo->prepare('SELECT username, digesta1 FROM `'.$this->tableName.'` WHERE username = ?');
|
||||
$stmt->execute(array($username));
|
||||
$result = $stmt->fetchAll();
|
||||
|
||||
if (!count($result)) return;
|
||||
|
||||
return $result[0]['digesta1'];
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This is the base class for any authentication object.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_DAV_Auth_IBackend {
|
||||
|
||||
/**
|
||||
* Authenticates the user based on the current request.
|
||||
*
|
||||
* If authentication is succesful, true must be returned.
|
||||
* If authentication fails, an exception must be thrown.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function authenticate(Sabre_DAV_Server $server,$realm);
|
||||
|
||||
/**
|
||||
* Returns information about the currently logged in username.
|
||||
*
|
||||
* If nobody is currently logged in, this method should return null.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
function getCurrentUser();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This plugin provides Authentication for a WebDAV server.
|
||||
*
|
||||
* It relies on a Backend object, which provides user information.
|
||||
*
|
||||
* Additionally, it provides support for:
|
||||
* * {DAV:}current-user-principal property from RFC5397
|
||||
* * {DAV:}principal-collection-set property from RFC3744
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Auth_Plugin extends Sabre_DAV_ServerPlugin {
|
||||
|
||||
/**
|
||||
* Reference to main server object
|
||||
*
|
||||
* @var Sabre_DAV_Server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* Authentication backend
|
||||
*
|
||||
* @var Sabre_DAV_Auth_Backend_Abstract
|
||||
*/
|
||||
private $authBackend;
|
||||
|
||||
/**
|
||||
* The authentication realm.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $realm;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* @param Sabre_DAV_Auth_Backend_Abstract $authBackend
|
||||
* @param string $realm
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Sabre_DAV_Auth_IBackend $authBackend, $realm) {
|
||||
|
||||
$this->authBackend = $authBackend;
|
||||
$this->realm = $realm;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the plugin. This function is automatically called by the server
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'),10);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plugin name.
|
||||
*
|
||||
* Using this name other plugins will be able to access other plugins
|
||||
* using Sabre_DAV_Server::getPlugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginName() {
|
||||
|
||||
return 'auth';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current users' principal uri.
|
||||
*
|
||||
* If nobody is logged in, this will return null.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentUser() {
|
||||
|
||||
$userInfo = $this->authBackend->getCurrentUser();
|
||||
if (!$userInfo) return null;
|
||||
|
||||
return $userInfo;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before any HTTP method and forces users to be authenticated
|
||||
*
|
||||
* @param string $method
|
||||
* @throws Sabre_DAV_Exception_NotAuthenticated
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeMethod($method, $uri) {
|
||||
|
||||
$this->authBackend->authenticate($this->server,$this->realm);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* GuessContentType plugin
|
||||
*
|
||||
* A lot of the built-in File objects just return application/octet-stream
|
||||
* as a content-type by default. This is a problem for some clients, because
|
||||
* they expect a correct contenttype.
|
||||
*
|
||||
* There's really no accurate, fast and portable way to determine the contenttype
|
||||
* so this extension does what the rest of the world does, and guesses it based
|
||||
* on the file extension.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Browser_GuessContentType extends Sabre_DAV_ServerPlugin {
|
||||
|
||||
/**
|
||||
* List of recognized file extensions
|
||||
*
|
||||
* Feel free to add more
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $extensionMap = array(
|
||||
|
||||
// images
|
||||
'jpg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
|
||||
// groupware
|
||||
'ics' => 'text/calendar',
|
||||
'vcf' => 'text/x-vcard',
|
||||
|
||||
// text
|
||||
'txt' => 'text/plain',
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
* Initializes the plugin
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
// Using a relatively low priority (200) to allow other extensions
|
||||
// to set the content-type first.
|
||||
$server->subscribeEvent('afterGetProperties',array($this,'afterGetProperties'),200);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for teh afterGetProperties event
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function afterGetProperties($path, &$properties) {
|
||||
|
||||
if (array_key_exists('{DAV:}getcontenttype', $properties[404])) {
|
||||
|
||||
list(, $fileName) = Sabre_DAV_URLUtil::splitPath($path);
|
||||
$contentType = $this->getContentType($fileName);
|
||||
|
||||
if ($contentType) {
|
||||
$properties[200]['{DAV:}getcontenttype'] = $contentType;
|
||||
unset($properties[404]['{DAV:}getcontenttype']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple method to return the contenttype
|
||||
*
|
||||
* @param string $fileName
|
||||
* @return string
|
||||
*/
|
||||
protected function getContentType($fileName) {
|
||||
|
||||
// Just grabbing the extension
|
||||
$extension = strtolower(substr($fileName,strrpos($fileName,'.')+1));
|
||||
if (isset($this->extensionMap[$extension]))
|
||||
return $this->extensionMap[$extension];
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This is a simple plugin that will map any GET request for non-files to
|
||||
* PROPFIND allprops-requests.
|
||||
*
|
||||
* This should allow easy debugging of PROPFIND
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Browser_MapGetToPropFind extends Sabre_DAV_ServerPlugin {
|
||||
|
||||
/**
|
||||
* reference to server class
|
||||
*
|
||||
* @var Sabre_DAV_Server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Initializes the plugin and subscribes to events
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeMethod',array($this,'httpGetInterceptor'));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method intercepts GET requests to non-files, and changes it into an HTTP PROPFIND request
|
||||
*
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
public function httpGetInterceptor($method, $uri) {
|
||||
|
||||
if ($method!='GET') return true;
|
||||
|
||||
$node = $this->server->tree->getNodeForPath($uri);
|
||||
if ($node instanceof Sabre_DAV_IFile) return;
|
||||
|
||||
$this->server->invokeMethod('PROPFIND',$uri);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Browser Plugin
|
||||
*
|
||||
* This plugin provides a html representation, so that a WebDAV server may be accessed
|
||||
* using a browser.
|
||||
*
|
||||
* The class intercepts GET requests to collection resources and generates a simple
|
||||
* html index.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
|
||||
|
||||
/**
|
||||
* reference to server class
|
||||
*
|
||||
* @var Sabre_DAV_Server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* enableEditing
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $enablePost = true;
|
||||
|
||||
/**
|
||||
* Creates the object.
|
||||
*
|
||||
* By default it will allow file creation and uploads.
|
||||
* Specify the first argument as false to disable this
|
||||
*
|
||||
* @param bool $enablePost
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($enablePost=true) {
|
||||
|
||||
$this->enablePost = $enablePost;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the plugin and subscribes to events
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeMethod',array($this,'httpGetInterceptor'));
|
||||
if ($this->enablePost) $this->server->subscribeEvent('unknownMethod',array($this,'httpPOSTHandler'));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method intercepts GET requests to collections and returns the html
|
||||
*
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
public function httpGetInterceptor($method, $uri) {
|
||||
|
||||
if ($method!='GET') return true;
|
||||
|
||||
try {
|
||||
$node = $this->server->tree->getNodeForPath($uri);
|
||||
} catch (Sabre_DAV_Exception_FileNotFound $e) {
|
||||
// We're simply stopping when the file isn't found to not interfere
|
||||
// with other plugins.
|
||||
return;
|
||||
}
|
||||
if ($node instanceof Sabre_DAV_IFile)
|
||||
return;
|
||||
|
||||
$this->server->httpResponse->sendStatus(200);
|
||||
$this->server->httpResponse->setHeader('Content-Type','text/html; charset=utf-8');
|
||||
|
||||
$this->server->httpResponse->sendBody(
|
||||
$this->generateDirectoryIndex($uri)
|
||||
);
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles POST requests for tree operations
|
||||
*
|
||||
* This method is not yet used.
|
||||
*
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
public function httpPOSTHandler($method, $uri) {
|
||||
|
||||
if ($method!='POST') return true;
|
||||
if (isset($_POST['sabreAction'])) switch($_POST['sabreAction']) {
|
||||
|
||||
case 'mkcol' :
|
||||
if (isset($_POST['name']) && trim($_POST['name'])) {
|
||||
// Using basename() because we won't allow slashes
|
||||
list(, $folderName) = Sabre_DAV_URLUtil::splitPath(trim($_POST['name']));
|
||||
$this->server->createDirectory($uri . '/' . $folderName);
|
||||
}
|
||||
break;
|
||||
case 'put' :
|
||||
if ($_FILES) $file = current($_FILES);
|
||||
else break;
|
||||
$newName = trim($file['name']);
|
||||
list(, $newName) = Sabre_DAV_URLUtil::splitPath(trim($file['name']));
|
||||
if (isset($_POST['name']) && trim($_POST['name']))
|
||||
$newName = trim($_POST['name']);
|
||||
|
||||
// Making sure we only have a 'basename' component
|
||||
list(, $newName) = Sabre_DAV_URLUtil::splitPath($newName);
|
||||
|
||||
if (is_uploaded_file($file['tmp_name'])) {
|
||||
$this->server->createFile($uri . '/' . $newName, fopen($file['tmp_name'],'r'));
|
||||
}
|
||||
|
||||
}
|
||||
$this->server->httpResponse->setHeader('Location',$this->server->httpRequest->getUri());
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a string for html.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function escapeHTML($value) {
|
||||
|
||||
return htmlspecialchars($value,ENT_QUOTES,'UTF-8');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the html directory index for a given url
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function generateDirectoryIndex($path) {
|
||||
|
||||
$html = "<html>
|
||||
<head>
|
||||
<title>Index for " . $this->escapeHTML($path) . "/ - SabreDAV " . Sabre_DAV_Version::VERSION . "</title>
|
||||
<style type=\"text/css\"> body { Font-family: arial}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Index for " . $this->escapeHTML($path) . "/</h1>
|
||||
<table>
|
||||
<tr><th>Name</th><th>Type</th><th>Size</th><th>Last modified</th></tr>
|
||||
<tr><td colspan=\"4\"><hr /></td></tr>";
|
||||
|
||||
$files = $this->server->getPropertiesForPath($path,array(
|
||||
'{DAV:}displayname',
|
||||
'{DAV:}resourcetype',
|
||||
'{DAV:}getcontenttype',
|
||||
'{DAV:}getcontentlength',
|
||||
'{DAV:}getlastmodified',
|
||||
),1);
|
||||
|
||||
$parent = $this->server->tree->getNodeForPath($path);
|
||||
|
||||
|
||||
if ($path) {
|
||||
|
||||
list($parentUri) = Sabre_DAV_URLUtil::splitPath($path);
|
||||
$fullPath = Sabre_DAV_URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
|
||||
|
||||
$html.= "<tr>
|
||||
<td><a href=\"{$fullPath}\">..</a></td>
|
||||
<td>[parent]</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>";
|
||||
|
||||
}
|
||||
|
||||
foreach($files as $k=>$file) {
|
||||
|
||||
// This is the current directory, we can skip it
|
||||
if (rtrim($file['href'],'/')==$path) continue;
|
||||
|
||||
list(, $name) = Sabre_DAV_URLUtil::splitPath($file['href']);
|
||||
|
||||
$type = null;
|
||||
|
||||
|
||||
if (isset($file[200]['{DAV:}resourcetype'])) {
|
||||
$type = $file[200]['{DAV:}resourcetype']->getValue();
|
||||
|
||||
// resourcetype can have multiple values
|
||||
if (!is_array($type)) $type = array($type);
|
||||
|
||||
foreach($type as $k=>$v) {
|
||||
|
||||
// Some name mapping is preferred
|
||||
switch($v) {
|
||||
case '{DAV:}collection' :
|
||||
$type[$k] = 'Collection';
|
||||
break;
|
||||
case '{DAV:}principal' :
|
||||
$type[$k] = 'Principal';
|
||||
break;
|
||||
case '{urn:ietf:params:xml:ns:carddav}addressbook' :
|
||||
$type[$k] = 'Addressbook';
|
||||
break;
|
||||
case '{urn:ietf:params:xml:ns:caldav}calendar' :
|
||||
$type[$k] = 'Calendar';
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
$type = implode(', ', $type);
|
||||
}
|
||||
|
||||
// If no resourcetype was found, we attempt to use
|
||||
// the contenttype property
|
||||
if (!$type && isset($file[200]['{DAV:}getcontenttype'])) {
|
||||
$type = $file[200]['{DAV:}getcontenttype'];
|
||||
}
|
||||
if (!$type) $type = 'Unknown';
|
||||
|
||||
$size = isset($file[200]['{DAV:}getcontentlength'])?(int)$file[200]['{DAV:}getcontentlength']:'';
|
||||
$lastmodified = isset($file[200]['{DAV:}getlastmodified'])?$file[200]['{DAV:}getlastmodified']->getTime()->format(DateTime::ATOM):'';
|
||||
|
||||
$fullPath = Sabre_DAV_URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path?$path . '/':'') . $name,'/'));
|
||||
|
||||
$displayName = isset($file[200]['{DAV:}displayname'])?$file[200]['{DAV:}displayname']:$name;
|
||||
|
||||
$name = $this->escapeHTML($name);
|
||||
$displayName = $this->escapeHTML($displayName);
|
||||
$type = $this->escapeHTML($type);
|
||||
|
||||
$html.= "<tr>
|
||||
<td><a href=\"{$fullPath}\">{$displayName}</a></td>
|
||||
<td>{$type}</td>
|
||||
<td>{$size}</td>
|
||||
<td>{$lastmodified}</td>
|
||||
</tr>";
|
||||
|
||||
}
|
||||
|
||||
$html.= "<tr><td colspan=\"4\"><hr /></td></tr>";
|
||||
|
||||
if ($this->enablePost && $parent instanceof Sabre_DAV_ICollection) {
|
||||
$html.= '<tr><td><form method="post" action="">
|
||||
<h3>Create new folder</h3>
|
||||
<input type="hidden" name="sabreAction" value="mkcol" />
|
||||
Name: <input type="text" name="name" /><br />
|
||||
<input type="submit" value="create" />
|
||||
</form>
|
||||
<form method="post" action="" enctype="multipart/form-data">
|
||||
<h3>Upload file</h3>
|
||||
<input type="hidden" name="sabreAction" value="put" />
|
||||
Name (optional): <input type="text" name="name" /><br />
|
||||
File: <input type="file" name="file" /><br />
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</td></tr>';
|
||||
}
|
||||
|
||||
$html.= "</table>
|
||||
<address>Generated by SabreDAV " . Sabre_DAV_Version::VERSION ."-". Sabre_DAV_Version::STABILITY . " (c)2007-2012 <a href=\"http://code.google.com/p/sabredav/\">http://code.google.com/p/sabredav/</a></address>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
return $html;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,431 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SabreDAV DAV client
|
||||
*
|
||||
* This client wraps around Curl to provide a convenient API to a WebDAV
|
||||
* server.
|
||||
*
|
||||
* NOTE: This class is experimental, it's api will likely change in the future.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAVClient
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Client {
|
||||
|
||||
public $propertyMap = array();
|
||||
|
||||
protected $baseUri;
|
||||
protected $userName;
|
||||
protected $password;
|
||||
protected $proxy;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Settings are provided through the 'settings' argument. The following
|
||||
* settings are supported:
|
||||
*
|
||||
* * baseUri
|
||||
* * userName (optional)
|
||||
* * password (optional)
|
||||
* * proxy (optional)
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function __construct(array $settings) {
|
||||
|
||||
if (!isset($settings['baseUri'])) {
|
||||
throw new InvalidArgumentException('A baseUri must be provided');
|
||||
}
|
||||
|
||||
$validSettings = array(
|
||||
'baseUri',
|
||||
'userName',
|
||||
'password',
|
||||
'proxy'
|
||||
);
|
||||
|
||||
foreach($validSettings as $validSetting) {
|
||||
if (isset($settings[$validSetting])) {
|
||||
$this->$validSetting = $settings[$validSetting];
|
||||
}
|
||||
}
|
||||
|
||||
$this->propertyMap['{DAV:}resourcetype'] = 'Sabre_DAV_Property_ResourceType';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a PROPFIND request
|
||||
*
|
||||
* The list of requested properties must be specified as an array, in clark
|
||||
* notation.
|
||||
*
|
||||
* The returned array will contain a list of filenames as keys, and
|
||||
* properties as values.
|
||||
*
|
||||
* The properties array will contain the list of properties. Only properties
|
||||
* that are actually returned from the server (without error) will be
|
||||
* returned, anything else is discarded.
|
||||
*
|
||||
* Depth should be either 0 or 1. A depth of 1 will cause a request to be
|
||||
* made to the server to also return all child resources.
|
||||
*
|
||||
* @param string $url
|
||||
* @param array $properties
|
||||
* @param int $depth
|
||||
* @return array
|
||||
*/
|
||||
public function propFind($url, array $properties, $depth = 0) {
|
||||
|
||||
$body = '<?xml version="1.0"?>' . "\n";
|
||||
$body.= '<d:propfind xmlns:d="DAV:">' . "\n";
|
||||
$body.= ' <d:prop>' . "\n";
|
||||
|
||||
foreach($properties as $property) {
|
||||
|
||||
list(
|
||||
$namespace,
|
||||
$elementName
|
||||
) = Sabre_DAV_XMLUtil::parseClarkNotation($property);
|
||||
|
||||
if ($namespace === 'DAV:') {
|
||||
$body.=' <d:' . $elementName . ' />' . "\n";
|
||||
} else {
|
||||
$body.=" <x:" . $elementName . " xmlns:x=\"" . $namespace . "\"/>\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$body.= ' </d:prop>' . "\n";
|
||||
$body.= '</d:propfind>';
|
||||
|
||||
$response = $this->request('PROPFIND', $url, $body, array(
|
||||
'Depth' => $depth,
|
||||
'Content-Type' => 'application/xml'
|
||||
));
|
||||
|
||||
$result = $this->parseMultiStatus($response['body']);
|
||||
|
||||
// If depth was 0, we only return the top item
|
||||
if ($depth===0) {
|
||||
reset($result);
|
||||
$result = current($result);
|
||||
return $result[200];
|
||||
}
|
||||
|
||||
$newResult = array();
|
||||
foreach($result as $href => $statusList) {
|
||||
|
||||
$newResult[$href] = $statusList[200];
|
||||
|
||||
}
|
||||
|
||||
return $newResult;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a list of properties on the server
|
||||
*
|
||||
* The list of properties must have clark-notation properties for the keys,
|
||||
* and the actual (string) value for the value. If the value is null, an
|
||||
* attempt is made to delete the property.
|
||||
*
|
||||
* @todo Must be building the request using the DOM, and does not yet
|
||||
* support complex properties.
|
||||
* @param string $url
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function propPatch($url, array $properties) {
|
||||
|
||||
$body = '<?xml version="1.0"?>' . "\n";
|
||||
$body.= '<d:propertyupdate xmlns:d="DAV:">' . "\n";
|
||||
|
||||
foreach($properties as $propName => $propValue) {
|
||||
|
||||
list(
|
||||
$namespace,
|
||||
$elementName
|
||||
) = Sabre_DAV_XMLUtil::parseClarkNotation($propName);
|
||||
|
||||
if ($propValue === null) {
|
||||
|
||||
$body.="<d:remove><d:prop>\n";
|
||||
|
||||
if ($namespace === 'DAV:') {
|
||||
$body.=' <d:' . $elementName . ' />' . "\n";
|
||||
} else {
|
||||
$body.=" <x:" . $elementName . " xmlns:x=\"" . $namespace . "\"/>\n";
|
||||
}
|
||||
|
||||
$body.="</d:prop></d:remove>\n";
|
||||
|
||||
} else {
|
||||
|
||||
$body.="<d:set><d:prop>\n";
|
||||
if ($namespace === 'DAV:') {
|
||||
$body.=' <d:' . $elementName . '>';
|
||||
} else {
|
||||
$body.=" <x:" . $elementName . " xmlns:x=\"" . $namespace . "\">";
|
||||
}
|
||||
// Shitty.. i know
|
||||
$body.=htmlspecialchars($propValue, ENT_NOQUOTES, 'UTF-8');
|
||||
if ($namespace === 'DAV:') {
|
||||
$body.='</d:' . $elementName . '>' . "\n";
|
||||
} else {
|
||||
$body.="</x:" . $elementName . ">\n";
|
||||
}
|
||||
$body.="</d:prop></d:set>\n";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$body.= '</d:propertyupdate>';
|
||||
|
||||
$response = $this->request('PROPPATCH', $url, $body, array(
|
||||
'Content-Type' => 'application/xml'
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an HTTP options request
|
||||
*
|
||||
* This method returns all the features from the 'DAV:' header as an array.
|
||||
* If there was no DAV header, or no contents this method will return an
|
||||
* empty array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options() {
|
||||
|
||||
$result = $this->request('OPTIONS');
|
||||
if (!isset($result['headers']['dav'])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$features = explode(',', $result['headers']['dav']);
|
||||
foreach($features as &$v) {
|
||||
$v = trim($v);
|
||||
}
|
||||
return $features;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an actual HTTP request, and returns the result.
|
||||
*
|
||||
* If the specified url is relative, it will be expanded based on the base
|
||||
* url.
|
||||
*
|
||||
* The returned array contains 3 keys:
|
||||
* * body - the response body
|
||||
* * httpCode - a HTTP code (200, 404, etc)
|
||||
* * headers - a list of response http headers. The header names have
|
||||
* been lowercased.
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param string $body
|
||||
* @param array $headers
|
||||
* @return array
|
||||
*/
|
||||
public function request($method, $url = '', $body = null, $headers = array()) {
|
||||
|
||||
$url = $this->getAbsoluteUrl($url);
|
||||
|
||||
$curlSettings = array(
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_POSTFIELDS => $body,
|
||||
// Return headers as part of the response
|
||||
CURLOPT_HEADER => true
|
||||
);
|
||||
|
||||
// Adding HTTP headers
|
||||
$nHeaders = array();
|
||||
foreach($headers as $key=>$value) {
|
||||
|
||||
$nHeaders[] = $key . ': ' . $value;
|
||||
|
||||
}
|
||||
$curlSettings[CURLOPT_HTTPHEADER] = $nHeaders;
|
||||
|
||||
if ($this->proxy) {
|
||||
$curlSettings[CURLOPT_PROXY] = $this->proxy;
|
||||
}
|
||||
|
||||
if ($this->userName) {
|
||||
$curlSettings[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC | CURLAUTH_DIGEST;
|
||||
$curlSettings[CURLOPT_USERPWD] = $this->userName . ':' . $this->password;
|
||||
}
|
||||
|
||||
list(
|
||||
$response,
|
||||
$curlInfo,
|
||||
$curlErrNo,
|
||||
$curlError
|
||||
) = $this->curlRequest($url, $curlSettings);
|
||||
|
||||
$headerBlob = substr($response, 0, $curlInfo['header_size']);
|
||||
$response = substr($response, $curlInfo['header_size']);
|
||||
|
||||
// In the case of 100 Continue, or redirects we'll have multiple lists
|
||||
// of headers for each separate HTTP response. We can easily split this
|
||||
// because they are separated by \r\n\r\n
|
||||
$headerBlob = explode("\r\n\r\n", trim($headerBlob, "\r\n"));
|
||||
|
||||
// We only care about the last set of headers
|
||||
$headerBlob = $headerBlob[count($headerBlob)-1];
|
||||
|
||||
// Splitting headers
|
||||
$headerBlob = explode("\r\n", $headerBlob);
|
||||
|
||||
$headers = array();
|
||||
foreach($headerBlob as $header) {
|
||||
$parts = explode(':', $header, 2);
|
||||
if (count($parts)==2) {
|
||||
$headers[strtolower(trim($parts[0]))] = trim($parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'body' => $response,
|
||||
'statusCode' => $curlInfo['http_code'],
|
||||
'headers' => $headers
|
||||
);
|
||||
|
||||
if ($curlErrNo) {
|
||||
throw new Sabre_DAV_Exception('[CURL] Error while making request: ' . $curlError . ' (error code: ' . $curlErrNo . ')');
|
||||
}
|
||||
|
||||
if ($response['statusCode']>=400) {
|
||||
throw new Sabre_DAV_Exception('HTTP error response. (errorcode ' . $response['statusCode'] . ')');
|
||||
}
|
||||
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for all curl functions.
|
||||
*
|
||||
* The only reason this was split out in a separate method, is so it
|
||||
* becomes easier to unittest.
|
||||
*
|
||||
* @param string $url
|
||||
* @param array $settings
|
||||
* @return
|
||||
*/
|
||||
protected function curlRequest($url, $settings) {
|
||||
|
||||
$curl = curl_init($url);
|
||||
curl_setopt_array($curl, $settings);
|
||||
|
||||
return array(
|
||||
curl_exec($curl),
|
||||
curl_getinfo($curl),
|
||||
curl_errno($curl),
|
||||
curl_error($curl)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full url based on the given url (which may be relative). All
|
||||
* urls are expanded based on the base url as given by the server.
|
||||
*
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
protected function getAbsoluteUrl($url) {
|
||||
|
||||
// If the url starts with http:// or https://, the url is already absolute.
|
||||
if (preg_match('/^http(s?):\/\//', $url)) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
// If the url starts with a slash, we must calculate the url based off
|
||||
// the root of the base url.
|
||||
if (strpos($url,'/') === 0) {
|
||||
$parts = parse_url($this->baseUri);
|
||||
return $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port'])?':' . $parts['port']:'') . $url;
|
||||
}
|
||||
|
||||
// Otherwise...
|
||||
return $this->baseUri . $url;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a WebDAV multistatus response body
|
||||
*
|
||||
* This method returns an array with the following structure
|
||||
*
|
||||
* array(
|
||||
* 'url/to/resource' => array(
|
||||
* '200' => array(
|
||||
* '{DAV:}property1' => 'value1',
|
||||
* '{DAV:}property2' => 'value2',
|
||||
* ),
|
||||
* '404' => array(
|
||||
* '{DAV:}property1' => null,
|
||||
* '{DAV:}property2' => null,
|
||||
* ),
|
||||
* )
|
||||
* 'url/to/resource2' => array(
|
||||
* .. etc ..
|
||||
* )
|
||||
* )
|
||||
*
|
||||
*
|
||||
* @param string $body xml body
|
||||
* @return array
|
||||
*/
|
||||
public function parseMultiStatus($body) {
|
||||
|
||||
$body = Sabre_DAV_XMLUtil::convertDAVNamespace($body);
|
||||
|
||||
$responseXML = simplexml_load_string($body, null, LIBXML_NOBLANKS | LIBXML_NOCDATA);
|
||||
if ($responseXML===false) {
|
||||
throw new InvalidArgumentException('The passed data is not valid XML');
|
||||
}
|
||||
|
||||
$responseXML->registerXPathNamespace('d','DAV:');
|
||||
|
||||
$propResult = array();
|
||||
|
||||
foreach($responseXML->xpath('d:response') as $response) {
|
||||
|
||||
$response->registerXPathNamespace('d','DAV:');
|
||||
$href = $response->xpath('d:href');
|
||||
$href = (string)$href[0];
|
||||
|
||||
$properties = array();
|
||||
|
||||
foreach($response->xpath('d:propstat') as $propStat) {
|
||||
|
||||
$propStat->registerXPathNamespace('d','DAV:');
|
||||
$status = $propStat->xpath('d:status');
|
||||
list($httpVersion, $statusCode, $message) = explode(' ', (string)$status[0],3);
|
||||
|
||||
$properties[$statusCode] = Sabre_DAV_XMLUtil::parseProperties(dom_import_simplexml($propStat), $this->propertyMap);
|
||||
|
||||
}
|
||||
|
||||
$propResult[$href] = $properties;
|
||||
|
||||
}
|
||||
|
||||
return $propResult;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Collection class
|
||||
*
|
||||
* This is a helper class, that should aid in getting collections classes setup.
|
||||
* Most of its methods are implemented, and throw permission denied exceptions
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_Collection extends Sabre_DAV_Node implements Sabre_DAV_ICollection {
|
||||
|
||||
/**
|
||||
* Returns a child object, by its name.
|
||||
*
|
||||
* This method makes use of the getChildren method to grab all the child nodes, and compares the name.
|
||||
* Generally its wise to override this, as this can usually be optimized
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Sabre_DAV_Exception_FileNotFound
|
||||
* @return Sabre_DAV_INode
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
foreach($this->getChildren() as $child) {
|
||||
|
||||
if ($child->getName()==$name) return $child;
|
||||
|
||||
}
|
||||
throw new Sabre_DAV_Exception_FileNotFound('File not found: ' . $name);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks is a child-node exists.
|
||||
*
|
||||
* It is generally a good idea to try and override this. Usually it can be optimized.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function childExists($name) {
|
||||
|
||||
try {
|
||||
|
||||
$this->getChild($name);
|
||||
return true;
|
||||
|
||||
} catch(Sabre_DAV_Exception_FileNotFound $e) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new file in the directory
|
||||
*
|
||||
* @param string $name Name of the file
|
||||
* @param resource $data Initial payload, passed as a readable stream resource.
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($name, $data = null) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to create file (filename ' . $name . ')');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new subdirectory
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($name) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to create directory');
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Directory class
|
||||
*
|
||||
* This class is now deprecated in favor of the Sabre_DAV_Collection class.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @deprecated Use Sabre_DAV_Collection instead
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_Directory extends Sabre_DAV_Collection {
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SabreDAV base exception
|
||||
*
|
||||
* This is SabreDAV's base exception file, use this to implement your own exception.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main Exception class.
|
||||
*
|
||||
* This class defines a getHTTPCode method, which should return the appropriate HTTP code for the Exception occured.
|
||||
* The default for this is 500.
|
||||
*
|
||||
* This class also allows you to generate custom xml data for your exceptions. This will be displayed
|
||||
* in the 'error' element in the failing response.
|
||||
*/
|
||||
class Sabre_DAV_Exception extends Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 500;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additonal information into the WebDAV error response
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the exception to return any extra HTTP response headers.
|
||||
*
|
||||
* The headers must be returned as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHTTPHeaders(Sabre_DAV_Server $server) {
|
||||
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* BadRequest
|
||||
*
|
||||
* The BadRequest is thrown when the user submitted an invalid HTTP request
|
||||
* BadRequest
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_BadRequest extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 400;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Conflict
|
||||
*
|
||||
* A 409 Conflict is thrown when a user tried to make a directory over an existing
|
||||
* file or in a parent directory that doesn't exist.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_Conflict extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 409;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ConflictingLock
|
||||
*
|
||||
* Similar to Exception_Locked, this exception thrown when a LOCK request
|
||||
* was made, on a resource which was already locked
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_ConflictingLock extends Sabre_DAV_Exception_Locked {
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additonal information into the WebDAV error response
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
if ($this->lock) {
|
||||
$error = $errorNode->ownerDocument->createElementNS('DAV:','d:no-conflicting-lock');
|
||||
$errorNode->appendChild($error);
|
||||
if (!is_object($this->lock)) var_dump($this->lock);
|
||||
$error->appendChild($errorNode->ownerDocument->createElementNS('DAV:','d:href',$this->lock->uri));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* FileNotFound
|
||||
*
|
||||
* This Exception is thrown when a Node couldn't be found. It returns HTTP error code 404
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_FileNotFound extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 404;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Forbidden
|
||||
*
|
||||
* This exception is thrown whenever a user tries to do an operation he's not allowed to
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_Forbidden extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 403;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* InsufficientStorage
|
||||
*
|
||||
* This Exception can be thrown, when for example a harddisk is full or a quota is exceeded
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_InsufficientStorage extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 507;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* InvalidResourceType
|
||||
*
|
||||
* This exception is thrown when the user tried to create a new collection, with
|
||||
* a special resourcetype value that was not recognized by the server.
|
||||
*
|
||||
* See RFC5689 section 3.3
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_InvalidResourceType extends Sabre_DAV_Exception_Forbidden {
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additonal information into the WebDAV error response
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
$error = $errorNode->ownerDocument->createElementNS('DAV:','d:valid-resourcetype');
|
||||
$errorNode->appendChild($error);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* LockTokenMatchesRequestUri
|
||||
*
|
||||
* This exception is thrown by UNLOCK if a supplied lock-token is invalid
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_LockTokenMatchesRequestUri extends Sabre_DAV_Exception_Conflict {
|
||||
|
||||
/**
|
||||
* Creates the exception
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
$this->message = 'The locktoken supplied does not match any locks on this entity';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additonal information into the WebDAV error response
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
$error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-matches-request-uri');
|
||||
$errorNode->appendChild($error);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Locked
|
||||
*
|
||||
* The 423 is thrown when a client tried to access a resource that was locked, without supplying a valid lock token
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_Locked extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Lock information
|
||||
*
|
||||
* @var Sabre_DAV_Locks_LockInfo
|
||||
*/
|
||||
protected $lock;
|
||||
|
||||
/**
|
||||
* Creates the exception
|
||||
*
|
||||
* A LockInfo object should be passed if the user should be informed
|
||||
* which lock actually has the file locked.
|
||||
*
|
||||
* @param Sabre_DAV_Locks_LockInfo $lock
|
||||
*/
|
||||
public function __construct(Sabre_DAV_Locks_LockInfo $lock = null) {
|
||||
|
||||
$this->lock = $lock;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 423;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additonal information into the WebDAV error response
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
if ($this->lock) {
|
||||
$error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-submitted');
|
||||
$errorNode->appendChild($error);
|
||||
if (!is_object($this->lock)) var_dump($this->lock);
|
||||
$error->appendChild($errorNode->ownerDocument->createElementNS('DAV:','d:href',$this->lock->uri));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* MethodNotAllowed
|
||||
*
|
||||
* The 405 is thrown when a client tried to create a directory on an already existing directory
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_MethodNotAllowed extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 405;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the exception to return any extra HTTP response headers.
|
||||
*
|
||||
* The headers must be returned as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHTTPHeaders(Sabre_DAV_Server $server) {
|
||||
|
||||
$methods = $server->getAllowedMethods($server->getRequestUri());
|
||||
|
||||
return array(
|
||||
'Allow' => strtoupper(implode(', ',$methods)),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* NotAuthenticated
|
||||
*
|
||||
* This exception is thrown when the client did not provide valid
|
||||
* authentication credentials.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_NotAuthenticated extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 401;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* NotImplemented
|
||||
*
|
||||
* This exception is thrown when the client tried to call an unsupported HTTP method or other feature
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_NotImplemented extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 501;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PreconditionFailed
|
||||
*
|
||||
* This exception is normally thrown when a client submitted a conditional request,
|
||||
* like for example an If, If-None-Match or If-Match header, which caused the HTTP
|
||||
* request to not execute (the condition of the header failed)
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_PreconditionFailed extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* When this exception is thrown, the header-name might be set.
|
||||
*
|
||||
* This allows the exception-catching code to determine which HTTP header
|
||||
* caused the exception.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $header = null;
|
||||
|
||||
/**
|
||||
* Create the exception
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $header
|
||||
*/
|
||||
public function __construct($message, $header=null) {
|
||||
|
||||
parent::__construct($message);
|
||||
$this->header = $header;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 412;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additonal information into the WebDAV error response
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
if ($this->header) {
|
||||
$prop = $errorNode->ownerDocument->createElement('s:header');
|
||||
$prop->nodeValue = $this->header;
|
||||
$errorNode->appendChild($prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ReportNotImplemented
|
||||
*
|
||||
* This exception is thrown when the client requested an unknown report through the REPORT method
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_ReportNotImplemented extends Sabre_DAV_Exception_NotImplemented {
|
||||
|
||||
/**
|
||||
* This method allows the exception to include additonal information into the WebDAV error response
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
$error = $errorNode->ownerDocument->createElementNS('DAV:','d:supported-report');
|
||||
$errorNode->appendChild($error);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* RequestedRangeNotSatisfiable
|
||||
*
|
||||
* This exception is normally thrown when the user
|
||||
* request a range that is out of the entity bounds.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_RequestedRangeNotSatisfiable extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* returns the http statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 416;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* UnSupportedMediaType
|
||||
*
|
||||
* The 415 Unsupported Media Type status code is generally sent back when the client
|
||||
* tried to call an HTTP method, with a body the server didn't understand
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Exception_UnsupportedMediaType extends Sabre_DAV_Exception {
|
||||
|
||||
/**
|
||||
* returns the http statuscode for this exception
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHTTPCode() {
|
||||
|
||||
return 415;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Directory class
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_FS_Directory extends Sabre_DAV_FS_Node implements Sabre_DAV_ICollection, Sabre_DAV_IQuota {
|
||||
|
||||
/**
|
||||
* Creates a new file in the directory
|
||||
*
|
||||
* data is a readable stream resource
|
||||
*
|
||||
* @param string $name Name of the file
|
||||
* @param resource $data Initial payload
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($name, $data = null) {
|
||||
|
||||
$newPath = $this->path . '/' . $name;
|
||||
file_put_contents($newPath,$data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new subdirectory
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($name) {
|
||||
|
||||
$newPath = $this->path . '/' . $name;
|
||||
mkdir($newPath);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific child node, referenced by its name
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Sabre_DAV_Exception_FileNotFound
|
||||
* @return Sabre_DAV_INode
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
$path = $this->path . '/' . $name;
|
||||
|
||||
if (!file_exists($path)) throw new Sabre_DAV_Exception_FileNotFound('File with name ' . $path . ' could not be located');
|
||||
|
||||
if (is_dir($path)) {
|
||||
|
||||
return new Sabre_DAV_FS_Directory($path);
|
||||
|
||||
} else {
|
||||
|
||||
return new Sabre_DAV_FS_File($path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all the child nodes
|
||||
*
|
||||
* @return Sabre_DAV_INode[]
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$nodes = array();
|
||||
foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node);
|
||||
return $nodes;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a child exists.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function childExists($name) {
|
||||
|
||||
$path = $this->path . '/' . $name;
|
||||
return file_exists($path);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all files in this directory, and then itself
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
foreach($this->getChildren() as $child) $child->delete();
|
||||
rmdir($this->path);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns available diskspace information
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getQuotaInfo() {
|
||||
|
||||
return array(
|
||||
disk_total_space($this->path)-disk_free_space($this->path),
|
||||
disk_free_space($this->path)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* File class
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_FS_File extends Sabre_DAV_FS_Node implements Sabre_DAV_IFile {
|
||||
|
||||
/**
|
||||
* Updates the data
|
||||
*
|
||||
* @param resource $data
|
||||
* @return void
|
||||
*/
|
||||
public function put($data) {
|
||||
|
||||
file_put_contents($this->path,$data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get() {
|
||||
|
||||
return fopen($this->path,'r');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the current file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
unlink($this->path);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the node, in bytes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() {
|
||||
|
||||
return filesize($this->path);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ETag for a file
|
||||
*
|
||||
* An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
|
||||
* The ETag is an arbritrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getETag() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime-type for a file
|
||||
*
|
||||
* If null is returned, we'll assume application/octet-stream
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getContentType() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Base node-class
|
||||
*
|
||||
* The node class implements the method used by both the File and the Directory classes
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_FS_Node implements Sabre_DAV_INode {
|
||||
|
||||
/**
|
||||
* The path to the current node
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Sets up the node, expects a full path name
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($path) {
|
||||
|
||||
$this->path = $path;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the node
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
list(, $name) = Sabre_DAV_URLUtil::splitPath($this->path);
|
||||
return $name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the node
|
||||
*
|
||||
* @param string $name The new name
|
||||
* @return void
|
||||
*/
|
||||
public function setName($name) {
|
||||
|
||||
list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path);
|
||||
list(, $newName) = Sabre_DAV_URLUtil::splitPath($name);
|
||||
|
||||
$newPath = $parentPath . '/' . $newName;
|
||||
rename($this->path,$newPath);
|
||||
|
||||
$this->path = $newPath;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the last modification time, as a unix timestamp
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLastModified() {
|
||||
|
||||
return filemtime($this->path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Directory class
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_FSExt_Directory extends Sabre_DAV_FSExt_Node implements Sabre_DAV_ICollection, Sabre_DAV_IQuota {
|
||||
|
||||
/**
|
||||
* Creates a new file in the directory
|
||||
*
|
||||
* @param string $name Name of the file
|
||||
* @param resource $data Initial payload
|
||||
* @return void
|
||||
*/
|
||||
public function createFile($name, $data = null) {
|
||||
|
||||
// We're not allowing dots
|
||||
if ($name=='.' || $name=='..') throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..');
|
||||
$newPath = $this->path . '/' . $name;
|
||||
file_put_contents($newPath,$data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new subdirectory
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($name) {
|
||||
|
||||
// We're not allowing dots
|
||||
if ($name=='.' || $name=='..') throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..');
|
||||
$newPath = $this->path . '/' . $name;
|
||||
mkdir($newPath);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific child node, referenced by its name
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Sabre_DAV_Exception_FileNotFound
|
||||
* @return Sabre_DAV_INode
|
||||
*/
|
||||
public function getChild($name) {
|
||||
|
||||
$path = $this->path . '/' . $name;
|
||||
|
||||
if (!file_exists($path)) throw new Sabre_DAV_Exception_FileNotFound('File could not be located');
|
||||
if ($name=='.' || $name=='..') throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..');
|
||||
|
||||
if (is_dir($path)) {
|
||||
|
||||
return new Sabre_DAV_FSExt_Directory($path);
|
||||
|
||||
} else {
|
||||
|
||||
return new Sabre_DAV_FSExt_File($path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a child exists.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function childExists($name) {
|
||||
|
||||
if ($name=='.' || $name=='..')
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..');
|
||||
|
||||
$path = $this->path . '/' . $name;
|
||||
return file_exists($path);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all the child nodes
|
||||
*
|
||||
* @return Sabre_DAV_INode[]
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$nodes = array();
|
||||
foreach(scandir($this->path) as $node) if($node!='.' && $node!='..' && $node!='.sabredav') $nodes[] = $this->getChild($node);
|
||||
return $nodes;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all files in this directory, and then itself
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
// Deleting all children
|
||||
foreach($this->getChildren() as $child) $child->delete();
|
||||
|
||||
// Removing resource info, if its still around
|
||||
if (file_exists($this->path . '/.sabredav')) unlink($this->path . '/.sabredav');
|
||||
|
||||
// Removing the directory itself
|
||||
rmdir($this->path);
|
||||
|
||||
return parent::delete();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns available diskspace information
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getQuotaInfo() {
|
||||
|
||||
return array(
|
||||
disk_total_space($this->path)-disk_free_space($this->path),
|
||||
disk_free_space($this->path)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* File class
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_FSExt_File extends Sabre_DAV_FSExt_Node implements Sabre_DAV_IFile {
|
||||
|
||||
/**
|
||||
* Updates the data
|
||||
*
|
||||
* data is a readable stream resource.
|
||||
*
|
||||
* @param resource $data
|
||||
* @return void
|
||||
*/
|
||||
public function put($data) {
|
||||
|
||||
file_put_contents($this->path,$data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get() {
|
||||
|
||||
return fopen($this->path,'r');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the current file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
|
||||
unlink($this->path);
|
||||
return parent::delete();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ETag for a file
|
||||
*
|
||||
* An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
|
||||
* The ETag is an arbritrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*/
|
||||
public function getETag() {
|
||||
|
||||
return '"' . md5_file($this->path). '"';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime-type for a file
|
||||
*
|
||||
* If null is returned, we'll assume application/octet-stream
|
||||
*/
|
||||
public function getContentType() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the file, in bytes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() {
|
||||
|
||||
return filesize($this->path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,276 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Base node-class
|
||||
*
|
||||
* The node class implements the method used by both the File and the Directory classes
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_DAV_ILockable, Sabre_DAV_IProperties {
|
||||
|
||||
/**
|
||||
* Returns all the locks on this node
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getLocks() {
|
||||
|
||||
$resourceData = $this->getResourceData();
|
||||
$locks = $resourceData['locks'];
|
||||
foreach($locks as $k=>$lock) {
|
||||
if (time() > $lock->timeout + $lock->created) unset($locks[$k]);
|
||||
}
|
||||
return $locks;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks this node
|
||||
*
|
||||
* @param Sabre_DAV_Locks_LockInfo $lockInfo
|
||||
* @return void
|
||||
*/
|
||||
function lock(Sabre_DAV_Locks_LockInfo $lockInfo) {
|
||||
|
||||
// We're making the lock timeout 30 minutes
|
||||
$lockInfo->timeout = 1800;
|
||||
$lockInfo->created = time();
|
||||
|
||||
$resourceData = $this->getResourceData();
|
||||
if (!isset($resourceData['locks'])) $resourceData['locks'] = array();
|
||||
$current = null;
|
||||
foreach($resourceData['locks'] as $k=>$lock) {
|
||||
if ($lock->token === $lockInfo->token) $current = $k;
|
||||
}
|
||||
if (!is_null($current)) $resourceData['locks'][$current] = $lockInfo;
|
||||
else $resourceData['locks'][] = $lockInfo;
|
||||
|
||||
$this->putResourceData($resourceData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a lock from this node
|
||||
*
|
||||
* @param Sabre_DAV_Locks_LockInfo $lockInfo
|
||||
* @return bool
|
||||
*/
|
||||
function unlock(Sabre_DAV_Locks_LockInfo $lockInfo) {
|
||||
|
||||
//throw new Sabre_DAV_Exception('bla');
|
||||
$resourceData = $this->getResourceData();
|
||||
foreach($resourceData['locks'] as $k=>$lock) {
|
||||
|
||||
if ($lock->token === $lockInfo->token) {
|
||||
|
||||
unset($resourceData['locks'][$k]);
|
||||
$this->putResourceData($resourceData);
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties on this node,
|
||||
*
|
||||
* @param array $mutations
|
||||
* @see Sabre_DAV_IProperties::updateProperties
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateProperties($properties) {
|
||||
|
||||
$resourceData = $this->getResourceData();
|
||||
|
||||
$result = array();
|
||||
|
||||
foreach($properties as $propertyName=>$propertyValue) {
|
||||
|
||||
// If it was null, we need to delete the property
|
||||
if (is_null($propertyValue)) {
|
||||
if (isset($resourceData['properties'][$propertyName])) {
|
||||
unset($resourceData['properties'][$propertyName]);
|
||||
}
|
||||
} else {
|
||||
$resourceData['properties'][$propertyName] = $propertyValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->putResourceData($resourceData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of properties for this nodes.;
|
||||
*
|
||||
* The properties list is a list of propertynames the client requested, encoded as xmlnamespace#tagName, for example: http://www.example.org/namespace#author
|
||||
* If the array is empty, all properties should be returned
|
||||
*
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
function getProperties($properties) {
|
||||
|
||||
$resourceData = $this->getResourceData();
|
||||
|
||||
// if the array was empty, we need to return everything
|
||||
if (!$properties) return $resourceData['properties'];
|
||||
|
||||
$props = array();
|
||||
foreach($properties as $property) {
|
||||
if (isset($resourceData['properties'][$property])) $props[$property] = $resourceData['properties'][$property];
|
||||
}
|
||||
|
||||
return $props;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the resource file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getResourceInfoPath() {
|
||||
|
||||
list($parentDir) = Sabre_DAV_URLUtil::splitPath($this->path);
|
||||
return $parentDir . '/.sabredav';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the stored resource information
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getResourceData() {
|
||||
|
||||
$path = $this->getResourceInfoPath();
|
||||
if (!file_exists($path)) return array('locks'=>array(), 'properties' => array());
|
||||
|
||||
// opening up the file, and creating a shared lock
|
||||
$handle = fopen($path,'r');
|
||||
flock($handle,LOCK_SH);
|
||||
$data = '';
|
||||
|
||||
// Reading data until the eof
|
||||
while(!feof($handle)) {
|
||||
$data.=fread($handle,8192);
|
||||
}
|
||||
|
||||
// We're all good
|
||||
fclose($handle);
|
||||
|
||||
// Unserializing and checking if the resource file contains data for this file
|
||||
$data = unserialize($data);
|
||||
if (!isset($data[$this->getName()])) {
|
||||
return array('locks'=>array(), 'properties' => array());
|
||||
}
|
||||
|
||||
$data = $data[$this->getName()];
|
||||
if (!isset($data['locks'])) $data['locks'] = array();
|
||||
if (!isset($data['properties'])) $data['properties'] = array();
|
||||
return $data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the resource information
|
||||
*
|
||||
* @param array $newData
|
||||
* @return void
|
||||
*/
|
||||
protected function putResourceData(array $newData) {
|
||||
|
||||
$path = $this->getResourceInfoPath();
|
||||
|
||||
// opening up the file, and creating a shared lock
|
||||
$handle = fopen($path,'a+');
|
||||
flock($handle,LOCK_EX);
|
||||
$data = '';
|
||||
|
||||
rewind($handle);
|
||||
|
||||
// Reading data until the eof
|
||||
while(!feof($handle)) {
|
||||
$data.=fread($handle,8192);
|
||||
}
|
||||
|
||||
// Unserializing and checking if the resource file contains data for this file
|
||||
$data = unserialize($data);
|
||||
$data[$this->getName()] = $newData;
|
||||
ftruncate($handle,0);
|
||||
rewind($handle);
|
||||
|
||||
fwrite($handle,serialize($data));
|
||||
fclose($handle);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the node
|
||||
*
|
||||
* @param string $name The new name
|
||||
* @return void
|
||||
*/
|
||||
public function setName($name) {
|
||||
|
||||
list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path);
|
||||
list(, $newName) = Sabre_DAV_URLUtil::splitPath($name);
|
||||
$newPath = $parentPath . '/' . $newName;
|
||||
|
||||
// We're deleting the existing resourcedata, and recreating it
|
||||
// for the new path.
|
||||
$resourceData = $this->getResourceData();
|
||||
$this->deleteResourceData();
|
||||
|
||||
rename($this->path,$newPath);
|
||||
$this->path = $newPath;
|
||||
$this->putResourceData($resourceData);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function deleteResourceData() {
|
||||
|
||||
// When we're deleting this node, we also need to delete any resource information
|
||||
$path = $this->getResourceInfoPath();
|
||||
if (!file_exists($path)) return true;
|
||||
|
||||
// opening up the file, and creating a shared lock
|
||||
$handle = fopen($path,'a+');
|
||||
flock($handle,LOCK_EX);
|
||||
$data = '';
|
||||
|
||||
rewind($handle);
|
||||
|
||||
// Reading data until the eof
|
||||
while(!feof($handle)) {
|
||||
$data.=fread($handle,8192);
|
||||
}
|
||||
|
||||
// Unserializing and checking if the resource file contains data for this file
|
||||
$data = unserialize($data);
|
||||
if (isset($data[$this->getName()])) unset($data[$this->getName()]);
|
||||
ftruncate($handle,0);
|
||||
rewind($handle);
|
||||
fwrite($handle,serialize($data));
|
||||
fclose($handle);
|
||||
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
|
||||
return $this->deleteResourceData();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* File class
|
||||
*
|
||||
* This is a helper class, that should aid in getting file classes setup.
|
||||
* Most of its methods are implemented, and throw permission denied exceptions
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_File extends Sabre_DAV_Node implements Sabre_DAV_IFile {
|
||||
|
||||
/**
|
||||
* Updates the data
|
||||
*
|
||||
* data is a readable stream resource.
|
||||
*
|
||||
* @param resource $data
|
||||
* @return void
|
||||
*/
|
||||
public function put($data) {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to change data');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data
|
||||
*
|
||||
* This method may either return a string or a readable stream resource
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get() {
|
||||
|
||||
throw new Sabre_DAV_Exception_Forbidden('Permission denied to read this file');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the file, in bytes.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ETag for a file
|
||||
*
|
||||
* An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
|
||||
* The ETag is an arbritrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*/
|
||||
public function getETag() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime-type for a file
|
||||
*
|
||||
* If null is returned, we'll assume application/octet-stream
|
||||
*/
|
||||
public function getContentType() {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The ICollection Interface
|
||||
*
|
||||
* This interface should be implemented by each class that represents a collection
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_DAV_ICollection extends Sabre_DAV_INode {
|
||||
|
||||
/**
|
||||
* Creates a new file in the directory
|
||||
*
|
||||
* data is a readable stream resource
|
||||
*
|
||||
* @param string $name Name of the file
|
||||
* @param resource $data Initial payload
|
||||
* @return void
|
||||
*/
|
||||
function createFile($name, $data = null);
|
||||
|
||||
/**
|
||||
* Creates a new subdirectory
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
function createDirectory($name);
|
||||
|
||||
/**
|
||||
* Returns a specific child node, referenced by its name
|
||||
*
|
||||
* @param string $name
|
||||
* @return Sabre_DAV_INode
|
||||
*/
|
||||
function getChild($name);
|
||||
|
||||
/**
|
||||
* Returns an array with all the child nodes
|
||||
*
|
||||
* @return Sabre_DAV_INode[]
|
||||
*/
|
||||
function getChildren();
|
||||
|
||||
/**
|
||||
* Checks if a child-node with the specified name exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function childExists($name);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The IExtendedCollection interface.
|
||||
*
|
||||
* This interface can be used to create special-type of collection-resources
|
||||
* as defined by RFC 5689.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_DAV_IExtendedCollection extends Sabre_DAV_ICollection {
|
||||
|
||||
/**
|
||||
* Creates a new collection
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $resourceType
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
function createExtendedCollection($name, array $resourceType, array $properties);
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue