Merge branch 'master' into tasks

This commit is contained in:
Bart Visscher 2012-05-04 17:04:11 +02:00
commit 1e47156226
951 changed files with 69920 additions and 27352 deletions

2
.gitignore vendored
View File

@ -2,6 +2,8 @@
data
owncloud
config/config.php
config/mount.php
apps/inc.php
# just sane ignores
.*.sw[po]

View File

@ -1,5 +1,9 @@
ErrorDocument 403 /core/templates/403.php
ErrorDocument 404 /core/templates/404.php
Redirect 301 /apps/calendar/caldav.php /remote/caldav.php
Redirect 301 /apps/contacts/carddav.php /remote/carddav.php
Redirect 301 /apps/files/webdav.php /remote/webdav.php
Redirect 301 /files/webdav.php /remote/webdav.php
<IfModule mod_php5.c>
php_value upload_max_filesize 512M
php_value post_max_size 512M
@ -10,6 +14,10 @@ php_value memory_limit 512M
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteRule ^.well-known/carddav /remote/carddav.php [R]
RewriteRule ^.well-known/caldav /remote/caldav.php [R]
RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]
</IfModule>
Options -Indexes

View File

@ -3,125 +3,24 @@
/**
* Library include file
*
* This file is deprecated, don't use it!
* Instead, use the specific includes files that are in the sub-packages.
*
* Sabre/DAV/includes.php
* Sabre/HTTP/includes.php
*
* etc..
*
* This file contains all includes to the rest of the SabreDAV library
* Make sure the lib/ directory is in PHP's include_path
* Make sure the lib/ directory is in PHP's include_path.
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @deprecated Don't use this file, it will be remove in a future version
* @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';
/* 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';
include 'Sabre/HTTP/includes.php';
include 'Sabre/DAV/includes.php';

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -19,7 +19,7 @@ abstract class Sabre_CalDAV_Backend_Abstract {
* 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. 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
@ -56,7 +56,7 @@ abstract class Sabre_CalDAV_Backend_Abstract {
* 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.
* Deletion of a non-existent property is always successful.
*
* Lastly, it is optional to return detailed information about any
* failures. In this case an array should be returned with the following
@ -98,12 +98,13 @@ abstract class Sabre_CalDAV_Backend_Abstract {
*
* 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
* * calendardata - The iCalendar-compatible calendar 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.
* * size - The size of the calendar objects, in bytes.
*
* Note that the etag is optional, but it's highly encouraged to return for
* speed reasons.
@ -112,6 +113,10 @@ abstract class Sabre_CalDAV_Backend_Abstract {
* 'getCalendarObject' will be called later, which *is* expected to return
* calendardata.
*
* If neither etag or size are specified, the calendardata will be
* used/fetched to determine these numbers. If both are specified the
* amount of times this is needed is reduced by a great degree.
*
* @param string $calendarId
* @return array
*/

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -54,6 +54,8 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
* Creates the backend
*
* @param PDO $pdo
* @param string $calendarTableName
* @param string $calendarObjectTableName
*/
public function __construct(PDO $pdo, $calendarTableName = 'calendars', $calendarObjectTableName = 'calendarobjects') {
@ -71,7 +73,7 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
* 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. 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
@ -91,13 +93,16 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
// Making fields a comma-delimited list
$fields = implode(', ', $fields);
$stmt = $this->pdo->prepare("SELECT " . $fields . " FROM `".$this->calendarTableName."` WHERE principaluri = ?");
$stmt = $this->pdo->prepare("SELECT " . $fields . " FROM ".$this->calendarTableName." WHERE principaluri = ? ORDER BY calendarorder ASC");
$stmt->execute(array($principalUri));
$calendars = array();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$components = array();
if ($row['components']) {
$components = explode(',',$row['components']);
}
$calendar = array(
'id' => $row['id'],
@ -129,6 +134,7 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
* @param string $principalUri
* @param string $calendarUri
* @param array $properties
* @return string
*/
public function createCalendar($principalUri, $calendarUri, array $properties) {
@ -158,13 +164,12 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
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 = $this->pdo->prepare("INSERT INTO ".$this->calendarTableName." (".implode(', ', $fieldNames).") VALUES (".implode(', ',array_keys($values)).")");
$stmt->execute($values);
return $this->pdo->lastInsertId();
@ -184,7 +189,7 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
* 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.
* Deletion of a non-existent property is always successful.
*
* Lastly, it is optional to return detailed information about any
* failures. In this case an array should be returned with the following
@ -258,7 +263,7 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
}
$valuesSql[] = 'ctag = ctag + 1';
$stmt = $this->pdo->prepare("UPDATE `" . $this->calendarTableName . "` SET " . implode(', ',$valuesSql) . " WHERE id = ?");
$stmt = $this->pdo->prepare("UPDATE " . $this->calendarTableName . " SET " . implode(', ',$valuesSql) . " WHERE id = ?");
$newValues['id'] = $calendarId;
$stmt->execute(array_values($newValues));
@ -274,10 +279,10 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
*/
public function deleteCalendar($calendarId) {
$stmt = $this->pdo->prepare('DELETE FROM `'.$this->calendarObjectTableName.'` WHERE 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 = $this->pdo->prepare('DELETE FROM '.$this->calendarTableName.' WHERE id = ?');
$stmt->execute(array($calendarId));
}
@ -287,12 +292,13 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
*
* 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
* * calendardata - The iCalendar-compatible calendar 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.
* * size - The size of the calendar objects, in bytes.
*
* Note that the etag is optional, but it's highly encouraged to return for
* speed reasons.
@ -301,12 +307,16 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
* 'getCalendarObject' will be called later, which *is* expected to return
* calendardata.
*
* If neither etag or size are specified, the calendardata will be
* used/fetched to determine these numbers. If both are specified the
* amount of times this is needed is reduced by a great degree.
*
* @param string $calendarId
* @return array
*/
public function getCalendarObjects($calendarId) {
$stmt = $this->pdo->prepare('SELECT * FROM `'.$this->calendarObjectTableName.'` WHERE calendarid = ?');
$stmt = $this->pdo->prepare('SELECT * FROM '.$this->calendarObjectTableName.' WHERE calendarid = ?');
$stmt->execute(array($calendarId));
return $stmt->fetchAll();
@ -326,7 +336,7 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
*/
public function getCalendarObject($calendarId,$objectUri) {
$stmt = $this->pdo->prepare('SELECT * FROM `'.$this->calendarObjectTableName.'` WHERE calendarid = ? AND uri = ?');
$stmt = $this->pdo->prepare('SELECT * FROM '.$this->calendarObjectTableName.' WHERE calendarid = ? AND uri = ?');
$stmt->execute(array($calendarId, $objectUri));
return $stmt->fetch();
@ -342,9 +352,9 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
*/
public function createCalendarObject($calendarId,$objectUri,$calendarData) {
$stmt = $this->pdo->prepare('INSERT INTO `'.$this->calendarObjectTableName.'` (calendarid, uri, calendardata, lastmodified) VALUES (?,?,?,?)');
$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 = $this->pdo->prepare('UPDATE '.$this->calendarTableName.' SET ctag = ctag + 1 WHERE id = ?');
$stmt->execute(array($calendarId));
}
@ -359,9 +369,9 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
*/
public function updateCalendarObject($calendarId,$objectUri,$calendarData) {
$stmt = $this->pdo->prepare('UPDATE `'.$this->calendarObjectTableName.'` SET calendardata = ?, lastmodified = ? WHERE calendarid = ? AND uri = ?');
$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 = $this->pdo->prepare('UPDATE '.$this->calendarTableName.' SET ctag = ctag + 1 WHERE id = ?');
$stmt->execute(array($calendarId));
}
@ -375,9 +385,9 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
*/
public function deleteCalendarObject($calendarId,$objectUri) {
$stmt = $this->pdo->prepare('DELETE FROM `'.$this->calendarObjectTableName.'` WHERE calendarid = ? AND uri = ?');
$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 = $this->pdo->prepare('UPDATE '. $this->calendarTableName .' SET ctag = ctag + 1 WHERE id = ?');
$stmt->execute(array($calendarId));
}

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -38,9 +38,9 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
/**
* Constructor
*
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
* @param array $calendarInfo
* @return void
*/
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_Abstract $caldavBackend, $calendarInfo) {
@ -77,7 +77,7 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
/**
* Returns the list of properties
*
* @param array $properties
* @param array $requestedProperties
* @return array
*/
public function getProperties($requestedProperties) {
@ -115,7 +115,7 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
public function getChild($name) {
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'],$name);
if (!$obj) throw new Sabre_DAV_Exception_FileNotFound('Calendar object not found');
if (!$obj) throw new Sabre_DAV_Exception_NotFound('Calendar object not found');
return new Sabre_CalDAV_CalendarObject($this->caldavBackend,$this->calendarInfo,$obj);
}
@ -173,23 +173,14 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
*
* @param string $name
* @param resource $calendarData
* @return void
* @return string|null
*/
public function createFile($name,$calendarData = null) {
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->createCalendarObject($this->calendarInfo['id'],$name,$calendarData);
return $this->caldavBackend->createCalendarObject($this->calendarInfo['id'],$name,$calendarData);
}
@ -294,6 +285,11 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
'protected' => true,
),
array(
'privilege' => '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}read-free-busy',
'principal' => '{DAV:}authenticated',
'protected' => true,
),
);
@ -313,6 +309,35 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
}
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
public function getSupportedPrivilegeSet() {
$default = Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet();
// We need to inject 'read-free-busy' in the tree, aggregated under
// {DAV:}read.
foreach($default['aggregates'] as &$agg) {
if ($agg['privilege'] !== '{DAV:}read') continue;
$agg['aggregates'][] = array(
'privilege' => '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}read-free-busy',
);
}
return $default;
}
}

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -90,22 +90,14 @@ class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV
*/
public function put($calendarData) {
if (is_resource($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);
$etag = $this->caldavBackend->updateCalendarObject($this->calendarInfo['id'],$this->objectData['uri'],$calendarData);
$this->objectData['calendardata'] = $calendarData;
$this->objectData['etag'] = $etag;
return $etag;
}
@ -134,7 +126,7 @@ class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV
/**
* Returns an ETag for this object.
*
* The ETag is an arbritrary string, but MUST be surrounded by double-quotes.
* The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
*
* @return string
*/
@ -166,7 +158,11 @@ class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV
*/
public function getSize() {
return strlen($this->objectData['calendardata']);
if (array_key_exists('size',$this->objectData)) {
return $this->objectData['size'];
} else {
return strlen($this->get());
}
}
@ -255,6 +251,23 @@ class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV
}
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
public function getSupportedPrivilegeSet() {
return null;
}
}

View File

@ -0,0 +1,296 @@
<?php
/**
* Parses the calendar-query report request body.
*
* Whoever designed this format, and the CalDAV equivalent even more so,
* has no feel for design.
*
* @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_CalendarQueryParser {
/**
* List of requested properties the client wanted
*
* @var array
*/
public $requestedProperties;
/**
* List of property/component filters.
*
* @var array
*/
public $filters;
/**
* This property will contain null if CALDAV:expand was not specified,
* otherwise it will contain an array with 2 elements (start, end). Each
* contain a DateTime object.
*
* If expand is specified, recurring calendar objects are to be expanded
* into their individual components, and only the components that fall
* within the specified time-range are to be returned.
*
* For more details, see rfc4791, section 9.6.5.
*
* @var null|array
*/
public $expand;
/**
* DOM Document
*
* @var DOMDocument
*/
protected $dom;
/**
* DOM XPath object
*
* @var DOMXPath
*/
protected $xpath;
/**
* Creates the parser
*
* @param DOMDocument $dom
*/
public function __construct(DOMDocument $dom) {
$this->dom = $dom;
$this->xpath = new DOMXPath($dom);
$this->xpath->registerNameSpace('cal',Sabre_CalDAV_Plugin::NS_CALDAV);
$this->xpath->registerNameSpace('dav','urn:DAV');
}
/**
* Parses the request.
*
* @return void
*/
public function parse() {
$filterNode = null;
$filter = $this->xpath->query('/cal:calendar-query/cal:filter');
if ($filter->length !== 1) {
throw new Sabre_DAV_Exception_BadRequest('Only one filter element is allowed');
}
$compFilters = $this->parseCompFilters($filter->item(0));
if (count($compFilters)!==1) {
throw new Sabre_DAV_Exception_BadRequest('There must be exactly 1 top-level comp-filter.');
}
$this->filters = $compFilters[0];
$this->requestedProperties = array_keys(Sabre_DAV_XMLUtil::parseProperties($this->dom->firstChild));
$expand = $this->xpath->query('/cal:calendar-query/dav:prop/cal:calendar-data/cal:expand');
if ($expand->length>0) {
$this->expand = $this->parseExpand($expand->item(0));
}
}
/**
* Parses all the 'comp-filter' elements from a node
*
* @param DOMElement $parentNode
* @return array
*/
protected function parseCompFilters(DOMElement $parentNode) {
$compFilterNodes = $this->xpath->query('cal:comp-filter', $parentNode);
$result = array();
for($ii=0; $ii < $compFilterNodes->length; $ii++) {
$compFilterNode = $compFilterNodes->item($ii);
$compFilter = array();
$compFilter['name'] = $compFilterNode->getAttribute('name');
$compFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $compFilterNode)->length>0;
$compFilter['comp-filters'] = $this->parseCompFilters($compFilterNode);
$compFilter['prop-filters'] = $this->parsePropFilters($compFilterNode);
$compFilter['time-range'] = $this->parseTimeRange($compFilterNode);
if ($compFilter['time-range'] && !in_array($compFilter['name'],array(
'VEVENT',
'VTODO',
'VJOURNAL',
'VFREEBUSY',
'VALARM',
))) {
throw new Sabre_DAV_Exception_BadRequest('The time-range filter is not defined for the ' . $compFilter['name'] . ' component');
};
$result[] = $compFilter;
}
return $result;
}
/**
* Parses all the prop-filter elements from a node
*
* @param DOMElement $parentNode
* @return array
*/
protected function parsePropFilters(DOMElement $parentNode) {
$propFilterNodes = $this->xpath->query('cal:prop-filter', $parentNode);
$result = array();
for ($ii=0; $ii < $propFilterNodes->length; $ii++) {
$propFilterNode = $propFilterNodes->item($ii);
$propFilter = array();
$propFilter['name'] = $propFilterNode->getAttribute('name');
$propFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $propFilterNode)->length>0;
$propFilter['param-filters'] = $this->parseParamFilters($propFilterNode);
$propFilter['text-match'] = $this->parseTextMatch($propFilterNode);
$propFilter['time-range'] = $this->parseTimeRange($propFilterNode);
$result[] = $propFilter;
}
return $result;
}
/**
* Parses the param-filter element
*
* @param DOMElement $parentNode
* @return array
*/
protected function parseParamFilters(DOMElement $parentNode) {
$paramFilterNodes = $this->xpath->query('cal:param-filter', $parentNode);
$result = array();
for($ii=0;$ii<$paramFilterNodes->length;$ii++) {
$paramFilterNode = $paramFilterNodes->item($ii);
$paramFilter = array();
$paramFilter['name'] = $paramFilterNode->getAttribute('name');
$paramFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $paramFilterNode)->length>0;
$paramFilter['text-match'] = $this->parseTextMatch($paramFilterNode);
$result[] = $paramFilter;
}
return $result;
}
/**
* Parses the text-match element
*
* @param DOMElement $parentNode
* @return array|null
*/
protected function parseTextMatch(DOMElement $parentNode) {
$textMatchNodes = $this->xpath->query('cal:text-match', $parentNode);
if ($textMatchNodes->length === 0)
return null;
$textMatchNode = $textMatchNodes->item(0);
$negateCondition = $textMatchNode->getAttribute('negate-condition');
$negateCondition = $negateCondition==='yes';
$collation = $textMatchNode->getAttribute('collation');
if (!$collation) $collation = 'i;ascii-casemap';
return array(
'negate-condition' => $negateCondition,
'collation' => $collation,
'value' => $textMatchNode->nodeValue
);
}
/**
* Parses the time-range element
*
* @param DOMElement $parentNode
* @return array|null
*/
protected function parseTimeRange(DOMElement $parentNode) {
$timeRangeNodes = $this->xpath->query('cal:time-range', $parentNode);
if ($timeRangeNodes->length === 0) {
return null;
}
$timeRangeNode = $timeRangeNodes->item(0);
if ($start = $timeRangeNode->getAttribute('start')) {
$start = Sabre_VObject_DateTimeParser::parseDateTime($start);
} else {
$start = null;
}
if ($end = $timeRangeNode->getAttribute('end')) {
$end = Sabre_VObject_DateTimeParser::parseDateTime($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');
}
return array(
'start' => $start,
'end' => $end,
);
}
/**
* Parses the CALDAV:expand element
*
* @param DOMElement $parentNode
* @return void
*/
protected function parseExpand(DOMElement $parentNode) {
$start = $parentNode->getAttribute('start');
if(!$start) {
throw new Sabre_DAV_Exception_BadRequest('The "start" attribute is required for the CALDAV:expand element');
}
$start = Sabre_VObject_DateTimeParser::parseDateTime($start);
$end = $parentNode->getAttribute('end');
if(!$end) {
throw new Sabre_DAV_Exception_BadRequest('The "end" attribute is required for the CALDAV:expand element');
}
$end = Sabre_VObject_DateTimeParser::parseDateTime($end);
if ($end <= $start) {
throw new Sabre_DAV_Exception_BadRequest('The end-date must be larger than the start-date in the expand element.');
}
return array(
'start' => $start,
'end' => $end,
);
}
}

View File

@ -0,0 +1,347 @@
<?php
/**
* CalendarQuery Validator
*
* This class is responsible for checking if an iCalendar object matches a set
* of filters. The main function to do this is 'validate'.
*
* This is used to determine which icalendar objects should be returned for a
* calendar-query REPORT request.
*
* @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_CalendarQueryValidator {
/**
* Verify if a list of filters applies to the calendar data object
*
* The list of filters must be formatted as parsed by Sabre_CalDAV_CalendarQueryParser
*
* @param Sabre_VObject_Component $vObject
* @param array $filters
* @return bool
*/
public function validate(Sabre_VObject_Component $vObject,array $filters) {
// The top level object is always a component filter.
// We'll parse it manually, as it's pretty simple.
if ($vObject->name !== $filters['name']) {
return false;
}
return
$this->validateCompFilters($vObject, $filters['comp-filters']) &&
$this->validatePropFilters($vObject, $filters['prop-filters']);
}
/**
* This method checks the validity of comp-filters.
*
* A list of comp-filters needs to be specified. Also the parent of the
* component we're checking should be specified, not the component to check
* itself.
*
* @param Sabre_VObject_Component $parent
* @param array $filters
* @return bool
*/
protected function validateCompFilters(Sabre_VObject_Component $parent, array $filters) {
foreach($filters as $filter) {
$isDefined = isset($parent->$filter['name']);
if ($filter['is-not-defined']) {
if ($isDefined) {
return false;
} else {
continue;
}
}
if (!$isDefined) {
return false;
}
if ($filter['time-range']) {
foreach($parent->$filter['name'] as $subComponent) {
if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
continue 2;
}
}
return false;
}
if (!$filter['comp-filters'] && !$filter['prop-filters']) {
continue;
}
// If there are sub-filters, we need to find at least one component
// for which the subfilters hold true.
foreach($parent->$filter['name'] as $subComponent) {
if (
$this->validateCompFilters($subComponent, $filter['comp-filters']) &&
$this->validatePropFilters($subComponent, $filter['prop-filters'])) {
// We had a match, so this comp-filter succeeds
continue 2;
}
}
// If we got here it means there were sub-comp-filters or
// sub-prop-filters and there was no match. This means this filter
// needs to return false.
return false;
}
// If we got here it means we got through all comp-filters alive so the
// filters were all true.
return true;
}
/**
* This method checks the validity of prop-filters.
*
* A list of prop-filters needs to be specified. Also the parent of the
* property we're checking should be specified, not the property to check
* itself.
*
* @param Sabre_VObject_Component $parent
* @param array $filters
* @return bool
*/
protected function validatePropFilters(Sabre_VObject_Component $parent, array $filters) {
foreach($filters as $filter) {
$isDefined = isset($parent->$filter['name']);
if ($filter['is-not-defined']) {
if ($isDefined) {
return false;
} else {
continue;
}
}
if (!$isDefined) {
return false;
}
if ($filter['time-range']) {
foreach($parent->$filter['name'] as $subComponent) {
if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
continue 2;
}
}
return false;
}
if (!$filter['param-filters'] && !$filter['text-match']) {
continue;
}
// If there are sub-filters, we need to find at least one property
// for which the subfilters hold true.
foreach($parent->$filter['name'] as $subComponent) {
if(
$this->validateParamFilters($subComponent, $filter['param-filters']) &&
(!$filter['text-match'] || $this->validateTextMatch($subComponent, $filter['text-match']))
) {
// We had a match, so this prop-filter succeeds
continue 2;
}
}
// If we got here it means there were sub-param-filters or
// text-match filters and there was no match. This means the
// filter needs to return false.
return false;
}
// If we got here it means we got through all prop-filters alive so the
// filters were all true.
return true;
}
/**
* This method checks the validity of param-filters.
*
* A list of param-filters needs to be specified. Also the parent of the
* parameter we're checking should be specified, not the parameter to check
* itself.
*
* @param Sabre_VObject_Property $parent
* @param array $filters
* @return bool
*/
protected function validateParamFilters(Sabre_VObject_Property $parent, array $filters) {
foreach($filters as $filter) {
$isDefined = isset($parent[$filter['name']]);
if ($filter['is-not-defined']) {
if ($isDefined) {
return false;
} else {
continue;
}
}
if (!$isDefined) {
return false;
}
if (!$filter['text-match']) {
continue;
}
// If there are sub-filters, we need to find at least one parameter
// for which the subfilters hold true.
foreach($parent[$filter['name']] as $subParam) {
if($this->validateTextMatch($subParam,$filter['text-match'])) {
// We had a match, so this param-filter succeeds
continue 2;
}
}
// If we got here it means there was a text-match filter and there
// were no matches. This means the filter needs to return false.
return false;
}
// If we got here it means we got through all param-filters alive so the
// filters were all true.
return true;
}
/**
* This method checks the validity of a text-match.
*
* A single text-match should be specified as well as the specific property
* or parameter we need to validate.
*
* @param Sabre_VObject_Node $parent
* @param array $textMatch
* @return bool
*/
protected function validateTextMatch(Sabre_VObject_Node $parent, array $textMatch) {
$value = (string)$parent;
$isMatching = Sabre_DAV_StringUtil::textMatch($value, $textMatch['value'], $textMatch['collation']);
return ($textMatch['negate-condition'] xor $isMatching);
}
/**
* Validates if a component matches the given time range.
*
* This is all based on the rules specified in rfc4791, which are quite
* complex.
*
* @param Sabre_VObject_Node $component
* @param DateTime $start
* @param DateTime $end
* @return bool
*/
protected function validateTimeRange(Sabre_VObject_Node $component, $start, $end) {
if (is_null($start)) {
$start = new DateTime('1900-01-01');
}
if (is_null($end)) {
$end = new DateTime('3000-01-01');
}
switch($component->name) {
case 'VEVENT' :
case 'VTODO' :
case 'VJOURNAL' :
return $component->isInTimeRange($start, $end);
case 'VALARM' :
// If the valarm is wrapped in a recurring event, we need to
// expand the recursions, and validate each.
//
// Our datamodel doesn't easily allow us to do this straight
// in the VALARM component code, so this is a hack, and an
// expensive one too.
if ($component->parent->name === 'VEVENT' && $component->parent->RRULE) {
// Fire up the iterator!
$it = new Sabre_VObject_RecurrenceIterator($component->parent->parent, (string)$component->parent->UID);
while($it->valid()) {
$expandedEvent = $it->getEventObject();
// We need to check from these expanded alarms, which
// one is the first to trigger. Based on this, we can
// determine if we can 'give up' expanding events.
$firstAlarm = null;
foreach($expandedEvent->VALARM as $expandedAlarm) {
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
if (!$firstAlarm || $effectiveTrigger < $firstAlarm) {
$firstAlarm = $effectiveTrigger;
}
if ($expandedAlarm->isInTimeRange($start, $end)) {
return true;
}
}
if ($firstAlarm > $end) {
return false;
}
$it->next();
}
return false;
} else {
return $component->isInTimeRange($start, $end);
}
case 'VFREEBUSY' :
throw new Sabre_DAV_Exception_NotImplemented('time-range filters are currently not supported on ' . $component->name . ' components');
case 'COMPLETED' :
case 'CREATED' :
case 'DTEND' :
case 'DTSTAMP' :
case 'DTSTART' :
case 'DUE' :
case 'LAST-MODIFIED' :
return ($start <= $component->getDateTime() && $end >= $component->getDateTime());
default :
throw new Sabre_DAV_Exception_BadRequest('You cannot create a time-range filter on a ' . $component->name . ' component');
}
}
}

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -48,7 +48,7 @@ class Sabre_CalDAV_CalendarRootNode extends Sabre_DAVACL_AbstractPrincipalCollec
* We're overriding this, because the default will be the 'principalPrefix',
* and we want it to be Sabre_CalDAV_Plugin::CALENDAR_ROOT
*
* @return void
* @return string
*/
public function getName() {

View File

@ -1,18 +0,0 @@
<?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-2011 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 {
}

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -41,7 +41,7 @@ class Sabre_CalDAV_ICSExportPlugin extends Sabre_DAV_ServerPlugin {
*
* @param string $method
* @param string $uri
* @return void
* @return bool
*/
public function beforeMethod($method, $uri) {
@ -55,9 +55,19 @@ class Sabre_CalDAV_ICSExportPlugin extends Sabre_DAV_ServerPlugin {
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);
$this->server->httpResponse->sendBody($this->generateICS($this->server->tree->getChildren($uri)));
$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;
@ -68,13 +78,17 @@ class Sabre_CalDAV_ICSExportPlugin extends Sabre_DAV_ServerPlugin {
* Merges all calendar objects, and builds one big ics export
*
* @param array $nodes
* @return void
* @return string
*/
public function generateICS(array $nodes) {
$calendar = new Sabre_VObject_Component('vcalendar');
$calendar->version = '2.0';
if (Sabre_DAV_Server::$exposeVersion) {
$calendar->prodid = '-//SabreDAV//SabreDAV ' . Sabre_DAV_Version::VERSION . '//EN';
} else {
$calendar->prodid = '-//SabreDAV//SabreDAV//EN';
}
$calendar->calscale = 'GREGORIAN';
$collectedTimezones = array();
@ -84,7 +98,11 @@ class Sabre_CalDAV_ICSExportPlugin extends Sabre_DAV_ServerPlugin {
foreach($nodes as $node) {
$nodeData = $node->get();
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) {
@ -105,13 +123,10 @@ class Sabre_CalDAV_ICSExportPlugin extends Sabre_DAV_ServerPlugin {
$collectedTimezones[] = $child->TZID;
break;
}
}
}
foreach($timezones as $tz) $calendar->add($tz);

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -10,7 +10,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -1,157 +0,0 @@
<?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-2011 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;
}
}

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -47,6 +47,33 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
*/
private $server;
/**
* The email handler for invites and other scheduling messages.
*
* @var Sabre_CalDAV_Schedule_IMip
*/
protected $imipHandler;
/**
* Sets the iMIP handler.
*
* iMIP = The email transport of iCalendar scheduling messages. Setting
* this is optional, but if you want the server to allow invites to be sent
* out, you must set a handler.
*
* Specifically iCal will plain assume that the server supports this. If
* the server doesn't, iCal will display errors when inviting people to
* events.
*
* @param Sabre_CalDAV_Schedule_IMip $imipHandler
* @return void
*/
public function setIMipHandler(Sabre_CalDAV_Schedule_IMip $imipHandler) {
$this->imipHandler = $imipHandler;
}
/**
* Use this method to tell the server this plugin defines additional
* HTTP methods.
@ -68,7 +95,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
if ($node instanceof Sabre_DAV_IExtendedCollection) {
try {
$node->getChild($name);
} catch (Sabre_DAV_Exception_FileNotFound $e) {
} catch (Sabre_DAV_Exception_NotFound $e) {
return array('MKCALENDAR');
}
}
@ -114,13 +141,16 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
public function getSupportedReportSet($uri) {
$node = $this->server->tree->getNodeForPath($uri);
$reports = array();
if ($node instanceof Sabre_CalDAV_ICalendar || $node instanceof Sabre_CalDAV_ICalendarObject) {
return array(
'{' . self::NS_CALDAV . '}calendar-multiget',
'{' . self::NS_CALDAV . '}calendar-query',
);
$reports[] = '{' . self::NS_CALDAV . '}calendar-multiget';
$reports[] = '{' . self::NS_CALDAV . '}calendar-query';
}
return array();
if ($node instanceof Sabre_CalDAV_ICalendar) {
$reports[] = '{' . self::NS_CALDAV . '}free-busy-query';
}
return $reports;
}
@ -133,10 +163,15 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
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->subscribeEvent('onHTMLActionsPanel', array($this,'htmlActionsPanel'));
$server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction'));
$server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent'));
$server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile'));
$server->xmlNamespaces[self::NS_CALDAV] = 'cal';
$server->xmlNamespaces[self::NS_CALENDARSERVER] = 'cs';
@ -144,6 +179,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
$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_Schedule_IOutbox'] = '{urn:ietf:params:xml:ns:caldav}schedule-outbox';
$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';
@ -161,7 +197,10 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
'{' . self::NS_CALDAV . '}calendar-data',
// scheduling extension
'{' . self::NS_CALDAV . '}schedule-inbox-URL',
'{' . self::NS_CALDAV . '}schedule-outbox-URL',
'{' . self::NS_CALDAV . '}calendar-user-address-set',
'{' . self::NS_CALDAV . '}calendar-user-type',
// CalendarServer extensions
'{' . self::NS_CALENDARSERVER . '}getctag',
@ -175,15 +214,31 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
* This function handles support for the MKCALENDAR method
*
* @param string $method
* @param string $uri
* @return bool
*/
public function unknownMethod($method, $uri) {
if ($method!=='MKCALENDAR') return;
switch ($method) {
case 'MKCALENDAR' :
$this->httpMkCalendar($uri);
// false is returned to stop the unknownMethod event
// false is returned to stop the propagation of the
// unknownMethod event.
return false;
case 'POST' :
// Checking if we're talking to an outbox
try {
$node = $this->server->tree->getNodeForPath($uri);
} catch (Sabre_DAV_Exception_NotFound $e) {
return;
}
if (!$node instanceof Sabre_CalDAV_Schedule_IOutbox)
return;
$this->outboxRequest($node);
return false;
}
}
@ -203,6 +258,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
case '{'.self::NS_CALDAV.'}calendar-query' :
$this->calendarQueryReport($dom);
return false;
case '{'.self::NS_CALDAV.'}free-busy-query' :
$this->freeBusyQueryReport($dom);
return false;
}
@ -276,6 +334,15 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
$returnedProperties[200][$calHome] = new Sabre_DAV_Property_Href($calendarHomePath);
}
// schedule-outbox-URL property
$scheduleProp = '{' . self::NS_CALDAV . '}schedule-outbox-URL';
if (in_array($scheduleProp,$requestedProperties)) {
$principalId = $node->getName();
$outboxPath = self::CALENDAR_ROOT . '/' . $principalId . '/outbox';
unset($requestedProperties[$scheduleProp]);
$returnedProperties[200][$scheduleProp] = new Sabre_DAV_Property_Href($outboxPath);
}
// calendar-user-address-set property
$calProp = '{' . self::NS_CALDAV . '}calendar-user-address-set';
if (in_array($calProp,$requestedProperties)) {
@ -357,11 +424,45 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
public function calendarMultiGetReport($dom) {
$properties = array_keys(Sabre_DAV_XMLUtil::parseProperties($dom->firstChild));
$hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href');
$xpath = new DOMXPath($dom);
$xpath->registerNameSpace('cal',Sabre_CalDAV_Plugin::NS_CALDAV);
$xpath->registerNameSpace('dav','urn:DAV');
$expand = $xpath->query('/cal:calendar-multiget/dav:prop/cal:calendar-data/cal:expand');
if ($expand->length>0) {
$expandElem = $expand->item(0);
$start = $expandElem->getAttribute('start');
$end = $expandElem->getAttribute('end');
if(!$start || !$end) {
throw new Sabre_DAV_Exception_BadRequest('The "start" and "end" attributes are required for the CALDAV:expand element');
}
$start = Sabre_VObject_DateTimeParser::parseDateTime($start);
$end = Sabre_VObject_DateTimeParser::parseDateTime($end);
if ($end <= $start) {
throw new Sabre_DAV_Exception_BadRequest('The end-date must be larger than the start-date in the expand element.');
}
$expand = true;
} else {
$expand = false;
}
foreach($hrefElems as $elem) {
$uri = $this->server->calculateUri($elem->nodeValue);
list($objProps) = $this->server->getPropertiesForPath($uri,$properties);
if ($expand && isset($objProps[200]['{' . self::NS_CALDAV . '}calendar-data'])) {
$vObject = Sabre_VObject_Reader::read($objProps[200]['{' . self::NS_CALDAV . '}calendar-data']);
$vObject->expand($start, $end);
$objProps[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
}
$propertyList[]=$objProps;
}
@ -383,17 +484,14 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
*/
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));
$parser = new Sabre_CalDAV_CalendarQueryParser($dom);
$parser->parse();
$requestedCalendarData = true;
$requestedProperties = $parser->requestedProperties;
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';
@ -403,20 +501,32 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
}
// These are the list of nodes that potentially match the requirement
$candidateNodes = $this->server->getPropertiesForPath($this->server->getRequestUri(),$requestedProperties,$this->server->getHTTPDepth(0));
$candidateNodes = $this->server->getPropertiesForPath(
$this->server->getRequestUri(),
$requestedProperties,
$this->server->getHTTPDepth(0)
);
$verifiedNodes = array();
$validator = new Sabre_CalDAV_CalendarQueryValidator();
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 (!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)) {
$vObject = Sabre_VObject_Reader::read($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
if ($validator->validate($vObject,$parser->filters)) {
if (!$requestedCalendarData) {
unset($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
}
if ($parser->expand) {
$vObject->expand($parser->expand['start'], $parser->expand['end']);
$node[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
}
$verifiedNodes[] = $node;
}
@ -428,360 +538,291 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
}
/**
* Verify if a list of filters applies to the calendar data object
* This method is responsible for parsing the request and generating the
* response for the CALDAV:free-busy-query REPORT.
*
* 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
* @param DOMNode $dom
* @return void
*/
private function validateTimeRangeFilterForEvent(SimpleXMLElement $xml,$currentXPath,array $currentFilter) {
protected function freeBusyQueryReport(DOMNode $dom) {
// 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');
$start = null;
$end = null;
foreach($dom->firstChild->childNodes as $childNode) {
$clark = Sabre_DAV_XMLUtil::toClarkNotation($childNode);
if ($clark == '{' . self::NS_CALDAV . '}time-range') {
$start = $childNode->getAttribute('start');
$end = $childNode->getAttribute('end');
break;
}
// The dtstart can be both a date, or datetime property
if ((string)$xdtstart[0]['value']==='DATE' || strlen((string)$xdtstart[0])===8) {
$isDateTime = false;
}
if ($start) {
$start = Sabre_VObject_DateTimeParser::parseDateTime($start);
}
if ($end) {
$end = Sabre_VObject_DateTimeParser::parseDateTime($end);
}
if (!$start && !$end) {
throw new Sabre_DAV_Exception_BadRequest('The freebusy report must have a time-range filter');
}
$acl = $this->server->getPlugin('acl');
if (!$acl) {
throw new Sabre_DAV_Exception('The ACL plugin must be loaded for free-busy queries to work');
}
$uri = $this->server->getRequestUri();
$acl->checkPrivileges($uri,'{' . self::NS_CALDAV . '}read-free-busy');
$calendar = $this->server->tree->getNodeForPath($uri);
if (!$calendar instanceof Sabre_CalDAV_ICalendar) {
throw new Sabre_DAV_Exception_NotImplemented('The free-busy-query REPORT is only implemented on calendars');
}
$objects = array_map(function($child) {
$obj = $child->get();
if (is_resource($obj)) {
$obj = stream_get_contents($obj);
}
return $obj;
}, $calendar->getChildren());
$generator = new Sabre_VObject_FreeBusyGenerator();
$generator->setObjects($objects);
$generator->setTimeRange($start, $end);
$result = $generator->getResult();
$result = $result->serialize();
$this->server->httpResponse->sendStatus(200);
$this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
$this->server->httpResponse->setHeader('Content-Length', strlen($result));
$this->server->httpResponse->sendBody($result);
}
/**
* This method is triggered before a file gets updated with new content.
*
* This plugin uses this method to ensure that CalDAV objects receive
* valid calendar data.
*
* @param string $path
* @param Sabre_DAV_IFile $node
* @param resource $data
* @return void
*/
public function beforeWriteContent($path, Sabre_DAV_IFile $node, &$data) {
if (!$node instanceof Sabre_CalDAV_ICalendarObject)
return;
$this->validateICalendar($data);
}
/**
* This method is triggered before a new file is created.
*
* This plugin uses this method to ensure that newly created calendar
* objects contain valid calendar data.
*
* @param string $path
* @param resource $data
* @param Sabre_DAV_ICollection $parentNode
* @return void
*/
public function beforeCreateFile($path, &$data, Sabre_DAV_ICollection $parentNode) {
if (!$parentNode instanceof Sabre_CalDAV_Calendar)
return;
$this->validateICalendar($data);
}
/**
* Checks if the submitted iCalendar data is in fact, valid.
*
* An exception is thrown if it's not.
*
* @param resource|string $data
* @return void
*/
protected function validateICalendar(&$data) {
// If it's a stream, we convert it to a string first.
if (is_resource($data)) {
$data = stream_get_contents($data);
}
// Converting the data to unicode, if needed.
$data = Sabre_DAV_StringUtil::ensureUTF8($data);
try {
$vobj = Sabre_VObject_Reader::read($data);
} catch (Sabre_VObject_ParseException $e) {
throw new Sabre_DAV_Exception_UnsupportedMediaType('This resource only supports valid iCalendar 2.0 data. Parse error: ' . $e->getMessage());
}
}
/**
* This method handles POST requests to the schedule-outbox
*
* @param Sabre_CalDAV_Schedule_IOutbox $outboxNode
* @return void
*/
public function outboxRequest(Sabre_CalDAV_Schedule_IOutbox $outboxNode) {
$originator = $this->server->httpRequest->getHeader('Originator');
$recipients = $this->server->httpRequest->getHeader('Recipient');
if (!$originator) {
throw new Sabre_DAV_Exception_BadRequest('The Originator: header must be specified when making POST requests');
}
if (!$recipients) {
throw new Sabre_DAV_Exception_BadRequest('The Recipient: header must be specified when making POST requests');
}
if (!preg_match('/^mailto:(.*)@(.*)$/', $originator)) {
throw new Sabre_DAV_Exception_BadRequest('Originator must start with mailto: and must be valid email address');
}
$originator = substr($originator,7);
$recipients = explode(',',$recipients);
foreach($recipients as $k=>$recipient) {
$recipient = trim($recipient);
if (!preg_match('/^mailto:(.*)@(.*)$/', $recipient)) {
throw new Sabre_DAV_Exception_BadRequest('Recipients must start with mailto: and must be valid email address');
}
$recipient = substr($recipient, 7);
$recipients[$k] = $recipient;
}
// We need to make sure that 'originator' matches one of the email
// addresses of the selected principal.
$principal = $outboxNode->getOwner();
$props = $this->server->getProperties($principal,array(
'{' . self::NS_CALDAV . '}calendar-user-address-set',
));
$addresses = array();
if (isset($props['{' . self::NS_CALDAV . '}calendar-user-address-set'])) {
$addresses = $props['{' . self::NS_CALDAV . '}calendar-user-address-set']->getHrefs();
}
if (!in_array('mailto:' . $originator, $addresses)) {
throw new Sabre_DAV_Exception_Forbidden('The addresses specified in the Originator header did not match any addresses in the owners calendar-user-address-set header');
}
try {
$vObject = Sabre_VObject_Reader::read($this->server->httpRequest->getBody(true));
} catch (Sabre_VObject_ParseException $e) {
throw new Sabre_DAV_Exception_BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage());
}
// Checking for the object type
$componentType = null;
foreach($vObject->getComponents() as $component) {
if ($component->name !== 'VTIMEZONE') {
$componentType = $component->name;
break;
}
}
if (is_null($componentType)) {
throw new Sabre_DAV_Exception_BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component');
}
// Validating the METHOD
$method = strtoupper((string)$vObject->METHOD);
if (!$method) {
throw new Sabre_DAV_Exception_BadRequest('A METHOD property must be specified in iTIP messages');
}
if (in_array($method, array('REQUEST','REPLY','ADD','CANCEL')) && $componentType==='VEVENT') {
$this->iMIPMessage($originator, $recipients, $vObject);
$this->server->httpResponse->sendStatus(200);
$this->server->httpResponse->sendBody('Messages sent');
} 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);
throw new Sabre_DAV_Exception_NotImplemented('This iTIP method is currently not implemented');
}
}
if (is_null($dtend)) {
// The DTEND property was not found. We will first see if the event has a duration
// property
/**
* Sends an iMIP message by email.
*
* @param string $originator
* @param array $recipients
* @param Sabre_VObject_Component $vObject
* @return void
*/
protected function iMIPMessage($originator, array $recipients, Sabre_VObject_Component $vObject) {
$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 (!$this->imipHandler) {
throw new Sabre_DAV_Exception_NotImplemented('No iMIP handler is setup on this server.');
}
}
}
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) return false;
if (!is_null($currentFilter['time-range']['end']) && $currentFilter['time-range']['end'] <= $dtstart && !$hasRrule) return false;
return true;
$this->imipHandler->sendMessage($originator, $recipients, $vObject);
}
private function validateTimeRangeFilterForTodo(SimpleXMLElement $xml,$currentXPath,array $filter) {
/**
* This method is used to generate HTML output for the
* Sabre_DAV_Browser_Plugin. This allows us to generate an interface users
* can use to create new calendars.
*
* @param Sabre_DAV_INode $node
* @param string $output
* @return bool
*/
public function htmlActionsPanel(Sabre_DAV_INode $node, &$output) {
// Gathering all relevant elements
if (!$node instanceof Sabre_CalDAV_UserCalendars)
return;
$dtStart = null;
$duration = null;
$due = null;
$completed = null;
$created = null;
$output.= '<tr><td colspan="2"><form method="post" action="">
<h3>Create new calendar</h3>
<input type="hidden" name="sabreAction" value="mkcalendar" />
<label>Name (uri):</label> <input type="text" name="name" /><br />
<label>Display name:</label> <input type="text" name="{DAV:}displayname" /><br />
<input type="submit" value="create" />
</form>
</td></tr>';
$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]);
}
}
/**
* This method allows us to intercept the 'mkcalendar' sabreAction. This
* action enables the user to create new calendars from the browser plugin.
*
* @param string $uri
* @param string $action
* @param array $postVars
* @return bool
*/
public function browserPostAction($uri, $action, array $postVars) {
if (!is_null($dtStart) && !is_null($due)) {
if ($action!=='mkcalendar')
return;
// 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 {
$resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:caldav}calendar');
$properties = array();
if (isset($postVars['{DAV:}displayname'])) {
$properties['{DAV:}displayname'] = $postVars['{DAV:}displayname'];
}
$this->server->createCollection($uri . '/' . $postVars['name'],$resourceType,$properties);
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;
}

View File

@ -10,7 +10,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -93,7 +93,7 @@ class Sabre_CalDAV_Principal_ProxyRead implements Sabre_DAVACL_IPrincipal {
/**
* Returns a list of altenative urls for a principal
* Returns a list of alternative urls for a principal
*
* This can for example be an email address, or ldap url.
*

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -93,7 +93,7 @@ class Sabre_CalDAV_Principal_ProxyWrite implements Sabre_DAVACL_IPrincipal {
/**
* Returns a list of altenative urls for a principal
* Returns a list of alternative urls for a principal
*
* This can for example be an email address, or ldap url.
*

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -50,13 +50,17 @@ class Sabre_CalDAV_Principal_User extends Sabre_DAVACL_Principal implements Sabr
*/
public function getChild($name) {
$principal = $this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/' . $name);
if (!$principal) {
throw new Sabre_DAV_Exception_NotFound('Node with name ' . $name . ' was not found');
}
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');
throw new Sabre_DAV_Exception_NotFound('Node with name ' . $name . ' was not found');
}
@ -67,21 +71,32 @@ class Sabre_CalDAV_Principal_User extends Sabre_DAVACL_Principal implements Sabr
*/
public function getChildren() {
return array(
new Sabre_CalDAV_Principal_ProxyRead($this->principalBackend, $this->principalProperties),
new Sabre_CalDAV_Principal_ProxyWrite($this->principalBackend, $this->principalProperties),
);
$r = array();
if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-read')) {
$r[] = new Sabre_CalDAV_Principal_ProxyRead($this->principalBackend, $this->principalProperties);
}
if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-write')) {
$r[] = new Sabre_CalDAV_Principal_ProxyWrite($this->principalBackend, $this->principalProperties);
}
return $r;
}
/**
* Checks if a child-node with the specified name exists
* Returns whether or not the child node exists
*
* @param string $name
* @return bool
*/
public function childExists($name) {
return $name === 'calendar-proxy-read' || $name === 'calendar-proxy-write';
try {
$this->getChild($name);
return true;
} catch (Sabre_DAV_Exception_NotFound $e) {
return false;
}
}
@ -99,23 +114,18 @@ class Sabre_CalDAV_Principal_User extends Sabre_DAVACL_Principal implements Sabr
*/
public function getACL() {
return array(
array(
'privilege' => '{DAV:}read',
'principal' => $this->principalProperties['uri'],
'protected' => true,
),
array(
$acl = parent::getACL();
$acl[] = array(
'privilege' => '{DAV:}read',
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-read',
'protected' => true,
),
array(
);
$acl[] = array(
'privilege' => '{DAV:}read',
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-write',
'protected' => true,
),
);
return $acl;
}

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -68,7 +68,7 @@ class Sabre_CalDAV_Property_SupportedCalendarComponentSet extends Sabre_DAV_Prop
* Unserializes the DOMElement back into a Property class.
*
* @param DOMElement $node
* @return void
* @return Sabre_CalDAV_Property_SupportedCalendarComponentSet
*/
static function unserialize(DOMElement $node) {

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

104
3rdparty/Sabre/CalDAV/Schedule/IMip.php vendored Normal file
View File

@ -0,0 +1,104 @@
<?php
/**
* iMIP handler.
*
* This class is responsible for sending out iMIP messages. iMIP is the
* email-based transport for iTIP. iTIP deals with scheduling operations for
* iCalendar objects.
*
* If you want to customize the email that gets sent out, you can do so by
* extending this class and overriding the sendMessage 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_Schedule_IMip {
/**
* Email address used in From: header.
*
* @var string
*/
protected $senderEmail;
/**
* Creates the email handler.
*
* @param string $senderEmail. The 'senderEmail' is the email that shows up
* in the 'From:' address. This should
* generally be some kind of no-reply email
* address you own.
*/
public function __construct($senderEmail) {
$this->senderEmail = $senderEmail;
}
/**
* Sends one or more iTip messages through email.
*
* @param string $originator
* @param array $recipients
* @param Sabre_VObject_Component $vObject
* @return void
*/
public function sendMessage($originator, array $recipients, Sabre_VObject_Component $vObject) {
foreach($recipients as $recipient) {
$to = $recipient;
$replyTo = $originator;
$subject = 'SabreDAV iTIP message';
switch(strtoupper($vObject->METHOD)) {
case 'REPLY' :
$subject = 'Response for: ' . $vObject->VEVENT->SUMMARY;
break;
case 'REQUEST' :
$subject = 'Invitation for: ' .$vObject->VEVENT->SUMMARY;
break;
case 'CANCEL' :
$subject = 'Cancelled event: ' . $vObject->VEVENT->SUMMARY;
break;
}
$headers = array();
$headers[] = 'Reply-To: ' . $replyTo;
$headers[] = 'From: ' . $this->senderEmail;
$headers[] = 'Content-Type: text/calendar; method=' . (string)$vObject->method . '; charset=utf-8';
if (Sabre_DAV_Server::$exposeVersion) {
$headers[] = 'X-Sabre-Version: ' . Sabre_DAV_Version::VERSION . '-' . Sabre_DAV_Version::STABILITY;
}
$vcalBody = $vObject->serialize();
$this->mail($to, $subject, $vcalBody, $headers);
}
}
/**
* This function is reponsible for sending the actual email.
*
* @param string $to Recipient email address
* @param string $subject Subject of the email
* @param string $body iCalendar body
* @param array $headers List of headers
* @return void
*/
protected function mail($to, $subject, $body, array $headers) {
mail($to, $subject, $body, implode("\r\n", $headers));
}
}
?>

View File

@ -0,0 +1,16 @@
<?php
/**
* Implement this interface to have a node be recognized as a CalDAV scheduling
* outbox.
*
* @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_Schedule_IOutbox extends Sabre_DAV_ICollection, Sabre_DAVACL_IACL {
}

View File

@ -0,0 +1,152 @@
<?php
/**
* The CalDAV scheduling outbox
*
* The outbox is mainly used as an endpoint in the tree for a client to do
* free-busy requests. This functionality is completely handled by the
* Scheduling plugin, so this object is actually mostly static.
*
* @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_Schedule_Outbox extends Sabre_DAV_Directory implements Sabre_CalDAV_Schedule_IOutbox {
/**
* The principal Uri
*
* @var string
*/
protected $principalUri;
/**
* Constructor
*
* @param string $principalUri
*/
public function __construct($principalUri) {
$this->principalUri = $principalUri;
}
/**
* Returns the name of the node.
*
* This is used to generate the url.
*
* @return string
*/
public function getName() {
return 'outbox';
}
/**
* Returns an array with all the child nodes
*
* @return Sabre_DAV_INode[]
*/
public function getChildren() {
return array();
}
/**
* 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' => '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}schedule-query-freebusy',
'principal' => $this->getOwner(),
'protected' => true,
),
array(
'privilege' => '{DAV:}read',
'principal' => $this->getOwner(),
'protected' => true,
),
);
}
/**
* Updates the ACL
*
* This method will receive a list of new ACE's.
*
* @param array $acl
* @return void
*/
public function setACL(array $acl) {
throw new Sabre_DAV_Exception_MethodNotAllowed('You\'re not allowed to update the ACL');
}
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
public function getSupportedPrivilegeSet() {
$default = Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet();
$default['aggregates'][] = array(
'privilege' => '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}schedule-query-freebusy',
);
return $default;
}
}

View File

@ -3,6 +3,8 @@
/**
* CalDAV server
*
* Deprecated! Warning: This class is now officially deprecated
*
* 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.
@ -13,7 +15,8 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @deprecated Don't use this class anymore, it will be removed in version 1.7.
* @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
*/

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -136,7 +136,7 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
return $child;
}
throw new Sabre_DAV_Exception_FileNotFound('Calendar with name \'' . $name . '\' could not be found');
throw new Sabre_DAV_Exception_NotFound('Calendar with name \'' . $name . '\' could not be found');
}
@ -170,6 +170,7 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
foreach($calendars as $calendar) {
$objs[] = new Sabre_CalDAV_Calendar($this->principalBackend, $this->caldavBackend, $calendar);
}
$objs[] = new Sabre_CalDAV_Schedule_Outbox($this->principalInfo['uri']);
return $objs;
}
@ -178,7 +179,8 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
* Creates a new calendar
*
* @param string $name
* @param string $properties
* @param array $resourceType
* @param array $properties
* @return void
*/
public function createExtendedCollection($name, array $resourceType, array $properties) {
@ -275,6 +277,22 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
}
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
public function getSupportedPrivilegeSet() {
return null;
}
}

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage CalDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -14,7 +14,7 @@ class Sabre_CalDAV_Version {
/**
* Full version number
*/
const VERSION = '1.5.3';
const VERSION = '1.6.2';
/**
* Stability : alpha, beta, stable

View File

@ -1,208 +0,0 @@
<?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-2011 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;
}
}

43
3rdparty/Sabre/CalDAV/includes.php vendored Normal file
View File

@ -0,0 +1,43 @@
<?php
/**
* Sabre_CalDAV includes file
*
* Including this file will automatically include all files from the
* Sabre_CalDAV package.
*
* This often allows faster loadtimes, as autoload-speed is often quite slow.
*
* @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
*/
// Begin includes
include __DIR__ . '/Backend/Abstract.php';
include __DIR__ . '/Backend/PDO.php';
include __DIR__ . '/CalendarQueryParser.php';
include __DIR__ . '/CalendarQueryValidator.php';
include __DIR__ . '/CalendarRootNode.php';
include __DIR__ . '/ICalendar.php';
include __DIR__ . '/ICalendarObject.php';
include __DIR__ . '/ICSExportPlugin.php';
include __DIR__ . '/Plugin.php';
include __DIR__ . '/Principal/Collection.php';
include __DIR__ . '/Principal/ProxyRead.php';
include __DIR__ . '/Principal/ProxyWrite.php';
include __DIR__ . '/Principal/User.php';
include __DIR__ . '/Property/SupportedCalendarComponentSet.php';
include __DIR__ . '/Property/SupportedCalendarData.php';
include __DIR__ . '/Property/SupportedCollationSet.php';
include __DIR__ . '/Schedule/IMip.php';
include __DIR__ . '/Schedule/IOutbox.php';
include __DIR__ . '/Schedule/Outbox.php';
include __DIR__ . '/Server.php';
include __DIR__ . '/UserCalendars.php';
include __DIR__ . '/Version.php';
include __DIR__ . '/Calendar.php';
include __DIR__ . '/CalendarObject.php';
// End includes

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -32,7 +32,6 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
*
* @param Sabre_CardDAV_Backend_Abstract $carddavBackend
* @param array $addressBookInfo
* @return void
*/
public function __construct(Sabre_CardDAV_Backend_Abstract $carddavBackend, array $addressBookInfo) {
@ -61,7 +60,7 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
public function getChild($name) {
$obj = $this->carddavBackend->getCard($this->addressBookInfo['id'],$name);
if (!$obj) throw new Sabre_DAV_Exception_FileNotFound('Card not found');
if (!$obj) throw new Sabre_DAV_Exception_NotFound('Card not found');
return new Sabre_CardDAV_Card($this->carddavBackend,$this->addressBookInfo,$obj);
}
@ -99,11 +98,13 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
/**
* Creates a new file
*
* The contents of the new file must be a valid VCARD
* The contents of the new file must be a valid VCARD.
*
* This method may return an ETag.
*
* @param string $name
* @param resource $vcardData
* @return void
* @return void|null
*/
public function createFile($name,$vcardData = null) {
@ -111,7 +112,7 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
// Converting to UTF-8, if needed
$vcardData = Sabre_DAV_StringUtil::ensureUTF8($vcardData);
$this->carddavBackend->createCard($this->addressBookInfo['id'],$name,$vcardData);
return $this->carddavBackend->createCard($this->addressBookInfo['id'],$name,$vcardData);
}
@ -162,7 +163,7 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
* 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.
* Deletion of a non-existent property is always successful.
*
* Lastly, it is optional to return detailed information about any
* failures. In this case an array should be returned with the following
@ -199,7 +200,7 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
* If the array is empty, it means 'all properties' were requested.
*
* @param array $properties
* @return void
* @return array
*/
public function getProperties($properties) {
@ -288,6 +289,22 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
}
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
public function getSupportedPrivilegeSet() {
return null;
}
}

View File

@ -3,12 +3,12 @@
/**
* Parses the addressbook-query report request body.
*
* Whoever designed this format, and the CalDAV equavalent even more so,
* Whoever designed this format, and the CalDAV equivalent even more so,
* has no feel for design.
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -64,8 +64,7 @@ class Sabre_CardDAV_AddressBookQueryParser {
/**
* Creates the parser
*
* @param DOMNode $dom
* @return void
* @param DOMDocument $dom
*/
public function __construct(DOMDocument $dom) {
@ -79,7 +78,6 @@ class Sabre_CardDAV_AddressBookQueryParser {
/**
* Parses the request.
*
* @param DOMNode $dom
* @return void
*/
public function parse() {
@ -182,7 +180,7 @@ class Sabre_CardDAV_AddressBookQueryParser {
* Text match
*
* @param DOMElement $textMatchNode
* @return void
* @return array
*/
public function parseTextMatchNode(DOMElement $textMatchNode) {

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -11,7 +11,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -74,38 +74,83 @@ abstract class Sabre_CardDAV_Backend_Abstract {
* * carddata - raw vcard data
* * uri - Some unique url
* * lastmodified - A unix timestamp
*
* It's recommended to also return the following properties:
* * etag - A unique etag. This must change every time the card changes.
* * size - The size of the card in bytes.
*
* If these last two properties are provided, less time will be spent
* calculating them. If they are specified, you can also ommit carddata.
* This may speed up certain requests, especially with large cards.
*
* @param mixed $addressbookId
* @return array
*/
public abstract function getCards($addressbookId);
/**
* Returns a specfic card
* Returns a specfic card.
*
* The same set of properties must be returned as with getCards. The only
* exception is that 'carddata' is absolutely required.
*
* @param mixed $addressBookId
* @param string $cardUri
* @return void
* @return array
*/
public abstract function getCard($addressBookId, $cardUri);
/**
* Creates a new card
* Creates a new card.
*
* The addressbook id will be passed as the first argument. This is the
* same id as it is returned from the getAddressbooksForUser method.
*
* The cardUri is a base uri, and doesn't include the full path. The
* cardData argument is the vcard body, and is passed as a string.
*
* It is possible to return an ETag from this method. This ETag is for the
* newly created resource, and must be enclosed with double quotes (that
* is, the string itself must contain the double quotes).
*
* You should only return the ETag if you store the carddata as-is. If a
* subsequent GET request on the same card does not have the same body,
* byte-by-byte and you did return an ETag here, clients tend to get
* confused.
*
* If you don't return an ETag, you can just return null.
*
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
* @return bool
* @return string|null
*/
abstract public function createCard($addressBookId, $cardUri, $cardData);
/**
* Updates a card
* Updates a card.
*
* The addressbook id will be passed as the first argument. This is the
* same id as it is returned from the getAddressbooksForUser method.
*
* The cardUri is a base uri, and doesn't include the full path. The
* cardData argument is the vcard body, and is passed as a string.
*
* It is possible to return an ETag from this method. This ETag should
* match that of the updated resource, and must be enclosed with double
* quotes (that is: the string itself must contain the actual quotes).
*
* You should only return the ETag if you store the carddata as-is. If a
* subsequent GET request on the same card does not have the same body,
* byte-by-byte and you did return an ETag here, clients tend to get
* confused.
*
* If you don't return an ETag, you can just return null.
*
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
* @return bool
* @return string|null
*/
abstract public function updateCard($addressBookId, $cardUri, $cardData);

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -34,6 +34,8 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
* Sets up the object
*
* @param PDO $pdo
* @param string $addressBooksTableName
* @param string $cardsTableName
*/
public function __construct(PDO $pdo, $addressBooksTableName = 'addressbooks', $cardsTableName = 'cards') {
@ -51,8 +53,8 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
*/
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));
$stmt = $this->pdo->prepare('SELECT id, uri, displayname, principaluri, description, ctag FROM '.$this->addressBooksTableName.' WHERE principaluri = ?');
$stmt->execute(array($principalUri));
$addressBooks = array();
@ -113,7 +115,7 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
return false;
}
$query = 'UPDATE `' . $this->addressBooksTableName . '` SET ctag = ctag + 1 ';
$query = 'UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 ';
foreach($updates as $key=>$value) {
$query.=', `' . $key . '` = :' . $key . ' ';
}
@ -160,7 +162,7 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
}
$query = 'INSERT INTO `' . $this->addressBooksTableName . '` (uri, displayname, description, principaluri, ctag) VALUES (:uri, :displayname, :description, :principaluri, 1)';
$query = 'INSERT INTO ' . $this->addressBooksTableName . ' (uri, displayname, description, principaluri, ctag) VALUES (:uri, :displayname, :description, :principaluri, 1)';
$stmt = $this->pdo->prepare($query);
$stmt->execute($values);
@ -174,10 +176,10 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
*/
public function deleteAddressBook($addressBookId) {
$stmt = $this->pdo->prepare('DELETE FROM `' . $this->cardsTableName . '` WHERE 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 = $this->pdo->prepare('DELETE FROM ' . $this->addressBooksTableName . ' WHERE id = ?');
$stmt->execute(array($addressBookId));
}
@ -185,20 +187,37 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
/**
* 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
*
* It's recommended to also return the following properties:
* * etag - A unique etag. This must change every time the card changes.
* * size - The size of the card in bytes.
*
* If these last two properties are provided, less time will be spent
* calculating them. If they are specified, you can also ommit carddata.
* This may speed up certain requests, especially with large cards.
*
* @param mixed $addressbookId
* @return array
*/
public function getCards($addressbookId) {
$stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM `' . $this->cardsTableName . '` WHERE 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
* Returns a specfic card.
*
* The same set of properties must be returned as with getCards. The only
* exception is that 'carddata' is absolutely required.
*
* @param mixed $addressBookId
* @param string $cardUri
@ -206,7 +225,7 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
*/
public function getCard($addressBookId, $cardUri) {
$stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM `' . $this->cardsTableName . '` WHERE addressbookid = ? AND uri = ? LIMIT 1');
$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);
@ -216,43 +235,77 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
}
/**
* Creates a new card
* Creates a new card.
*
* The addressbook id will be passed as the first argument. This is the
* same id as it is returned from the getAddressbooksForUser method.
*
* The cardUri is a base uri, and doesn't include the full path. The
* cardData argument is the vcard body, and is passed as a string.
*
* It is possible to return an ETag from this method. This ETag is for the
* newly created resource, and must be enclosed with double quotes (that
* is, the string itself must contain the double quotes).
*
* You should only return the ETag if you store the carddata as-is. If a
* subsequent GET request on the same card does not have the same body,
* byte-by-byte and you did return an ETag here, clients tend to get
* confused.
*
* If you don't return an ETag, you can just return null.
*
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
* @return bool
* @return string|null
*/
public function createCard($addressBookId, $cardUri, $cardData) {
$stmt = $this->pdo->prepare('INSERT INTO `' . $this->cardsTableName . '` (carddata, uri, lastmodified, addressbookid) VALUES (?, ?, ?, ?)');
$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 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
$stmt2->execute(array($addressBookId));
return $result;
return '"' . md5($cardData) . '"';
}
/**
* Updates a card
* Updates a card.
*
* The addressbook id will be passed as the first argument. This is the
* same id as it is returned from the getAddressbooksForUser method.
*
* The cardUri is a base uri, and doesn't include the full path. The
* cardData argument is the vcard body, and is passed as a string.
*
* It is possible to return an ETag from this method. This ETag should
* match that of the updated resource, and must be enclosed with double
* quotes (that is: the string itself must contain the actual quotes).
*
* You should only return the ETag if you store the carddata as-is. If a
* subsequent GET request on the same card does not have the same body,
* byte-by-byte and you did return an ETag here, clients tend to get
* confused.
*
* If you don't return an ETag, you can just return null.
*
* @param mixed $addressBookId
* @param string $cardUri
* @param string $cardData
* @return bool
* @return string|null
*/
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));
$stmt = $this->pdo->prepare('UPDATE ' . $this->cardsTableName . ' SET carddata = ?, lastmodified = ? WHERE uri = ? AND addressbookid =?');
$stmt->execute(array($cardData, time(), $cardUri, $addressBookId));
$stmt2 = $this->pdo->prepare('UPDATE `' . $this->addressBooksTableName . '` SET ctag = ctag + 1 WHERE id = ?');
$stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
$stmt2->execute(array($addressBookId));
return $stmt->rowCount()===1;
return '"' . md5($cardData) . '"';
}
@ -265,10 +318,10 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
*/
public function deleteCard($addressBookId, $cardUri) {
$stmt = $this->pdo->prepare('DELETE FROM `' . $this->cardsTableName . '` WHERE addressbookid = ? AND uri = ?');
$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 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
$stmt2->execute(array($addressBookId));
return $stmt->rowCount()===1;

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -65,11 +65,12 @@ class Sabre_CardDAV_Card extends Sabre_DAV_File implements Sabre_CardDAV_ICard,
*/
public function get() {
$cardData = $this->cardData['carddata'];
$s = fopen('php://temp','r+');
fwrite($s, $cardData);
rewind($s);
return $s;
// 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'];
}
@ -87,8 +88,11 @@ class Sabre_CardDAV_Card extends Sabre_DAV_File implements Sabre_CardDAV_ICard,
// Converting to UTF-8, if needed
$cardData = Sabre_DAV_StringUtil::ensureUTF8($cardData);
$this->carddavBackend->updateCard($this->addressBookInfo['id'],$this->cardData['uri'],$cardData);
$etag = $this->carddavBackend->updateCard($this->addressBookInfo['id'],$this->cardData['uri'],$cardData);
$this->cardData['carddata'] = $cardData;
$this->cardData['etag'] = $etag;
return $etag;
}
@ -121,7 +125,11 @@ class Sabre_CardDAV_Card extends Sabre_DAV_File implements Sabre_CardDAV_ICard,
*/
public function getETag() {
return '"' . md5($this->cardData['carddata']) . '"';
if (isset($this->cardData['etag'])) {
return $this->cardData['etag'];
} else {
return '"' . md5($this->get()) . '"';
}
}
@ -143,7 +151,11 @@ class Sabre_CardDAV_Card extends Sabre_DAV_File implements Sabre_CardDAV_ICard,
*/
public function getSize() {
return strlen($this->cardData['carddata']);
if (array_key_exists('size', $this->cardData)) {
return $this->cardData['size'];
} else {
return strlen($this->get());
}
}
@ -216,5 +228,23 @@ class Sabre_CardDAV_Card extends Sabre_DAV_File implements Sabre_CardDAV_ICard,
}
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
public function getSupportedPrivilegeSet() {
return null;
}
}

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -11,7 +11,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -48,7 +48,10 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
/* Events */
$server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
$server->subscribeEvent('updateProperties', array($this, 'updateProperties'));
$server->subscribeEvent('report', array($this,'report'));
$server->subscribeEvent('onHTMLActionsPanel', array($this,'htmlActionsPanel'));
$server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction'));
/* Namespaces */
$server->xmlNamespaces[self::NS_CARDDAV] = 'card';
@ -60,7 +63,10 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
/* Adding properties that may never be changed */
$server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-address-data';
$server->protectedProperties[] = '{' . self::NS_CARDDAV . '}max-resource-size';
$server->protectedProperties[] = '{' . self::NS_CARDDAV . '}addressbook-home-set';
$server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-collation-set';
$server->propertyMap['{http://calendarserver.org/ns/}me-card'] = 'Sabre_DAV_Property_Href';
$this->server = $server;
@ -151,6 +157,77 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
}
}
if ($node instanceof Sabre_CardDAV_UserAddressBooks) {
$meCardProp = '{http://calendarserver.org/ns/}me-card';
if (in_array($meCardProp, $requestedProperties)) {
$props = $this->server->getProperties($node->getOwner(), array('{http://sabredav.org/ns}vcard-url'));
if (isset($props['{http://sabredav.org/ns}vcard-url'])) {
$returnedProperties[200][$meCardProp] = new Sabre_DAV_Property_Href(
$props['{http://sabredav.org/ns}vcard-url']
);
$pos = array_search($meCardProp, $requestedProperties);
unset($requestedProperties[$pos]);
}
}
}
}
/**
* This event is triggered when a PROPPATCH method is executed
*
* @param array $mutations
* @param array $result
* @param Sabre_DAV_INode $node
* @return void
*/
public function updateProperties(&$mutations, &$result, $node) {
if (!$node instanceof Sabre_CardDAV_UserAddressBooks) {
return true;
}
$meCard = '{http://calendarserver.org/ns/}me-card';
// The only property we care about
if (!isset($mutations[$meCard]))
return true;
$value = $mutations[$meCard];
unset($mutations[$meCard]);
if ($value instanceof Sabre_DAV_Property_IHref) {
$value = $value->getHref();
$value = $this->server->calculateUri($value);
} elseif (!is_null($value)) {
$result[400][$meCard] = null;
return false;
}
$innerResult = $this->server->updateProperties(
$node->getOwner(),
array(
'{http://sabredav.org/ns}vcard-url' => $value,
)
);
$closureResult = false;
foreach($innerResult as $status => $props) {
if (is_array($props) && array_key_exists('{http://sabredav.org/ns}vcard-url', $props)) {
$result[$status][$meCard] = null;
$closureResult = ($status>=200 && $status<300);
}
}
return $result;
}
/**
@ -256,6 +333,7 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
$result = array();
foreach($validNodes as $validNode) {
if ($depth==0) {
$href = $this->server->getRequestUri();
} else {
@ -284,8 +362,6 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
$vcard = Sabre_VObject_Reader::read($vcardData);
$success = true;
foreach($filters as $filter) {
$isDefined = isset($vcard->{$filter['name']});
@ -328,7 +404,7 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
} // else
// There are two conditions where we can already determine wether
// There are two conditions where we can already determine whether
// or not this filter succeeds.
if ($test==='anyof' && $success) {
return true;
@ -354,14 +430,13 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
* @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 $vProperties
* @param array $filters
* @param string $test
* @return bool
*/
protected function validateParamFilters(array $vProperties, array $filters, $test) {
$success = false;
foreach($filters as $filter) {
$isDefined = false;
@ -384,7 +459,6 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
} else {
$texts = array();
$success = false;
foreach($vProperties as $vProperty) {
// If we got all the way here, we'll need to validate the
@ -398,7 +472,7 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
} // else
// There are two conditions where we can already determine wether
// There are two conditions where we can already determine whether
// or not this filter succeeds.
if ($test==='anyof' && $success) {
return true;
@ -459,5 +533,55 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
}
/**
* This method is used to generate HTML output for the
* Sabre_DAV_Browser_Plugin. This allows us to generate an interface users
* can use to create new calendars.
*
* @param Sabre_DAV_INode $node
* @param string $output
* @return bool
*/
public function htmlActionsPanel(Sabre_DAV_INode $node, &$output) {
if (!$node instanceof Sabre_CardDAV_UserAddressBooks)
return;
$output.= '<tr><td colspan="2"><form method="post" action="">
<h3>Create new address book</h3>
<input type="hidden" name="sabreAction" value="mkaddressbook" />
<label>Name (uri):</label> <input type="text" name="name" /><br />
<label>Display name:</label> <input type="text" name="{DAV:}displayname" /><br />
<input type="submit" value="create" />
</form>
</td></tr>';
return false;
}
/**
* This method allows us to intercept the 'mkcalendar' sabreAction. This
* action enables the user to create new calendars from the browser plugin.
*
* @param string $uri
* @param string $action
* @param array $postVars
* @return bool
*/
public function browserPostAction($uri, $action, array $postVars) {
if ($action!=='mkaddressbook')
return;
$resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:carddav}addressbook');
$properties = array();
if (isset($postVars['{DAV:}displayname'])) {
$properties['{DAV:}displayname'] = $postVars['{DAV:}displayname'];
}
$this->server->createCollection($uri . '/' . $postVars['name'],$resourceType,$properties);
return false;
}
}

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -24,7 +24,7 @@ class Sabre_CardDAV_Property_SupportedAddressData extends Sabre_DAV_Property {
/**
* Creates the property
*
* @param array $components
* @param array|null $supportedData
*/
public function __construct(array $supportedData = null) {

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -129,7 +129,7 @@ class Sabre_CardDAV_UserAddressBooks extends Sabre_DAV_Collection implements Sab
return $child;
}
throw new Sabre_DAV_Exception_FileNotFound('Addressbook with name \'' . $name . '\' could not be found');
throw new Sabre_DAV_Exception_NotFound('Addressbook with name \'' . $name . '\' could not be found');
}
@ -236,5 +236,22 @@ class Sabre_CardDAV_UserAddressBooks extends Sabre_DAV_Collection implements Sab
}
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See Sabre_DAVACL_Plugin::getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
public function getSupportedPrivilegeSet() {
return null;
}
}

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage CardDAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -16,7 +16,7 @@ class Sabre_CardDAV_Version {
/**
* Full version number
*/
const VERSION = '1.5.3';
const VERSION = '1.6.1';
/**
* Stability : alpha, beta, stable

32
3rdparty/Sabre/CardDAV/includes.php vendored Normal file
View File

@ -0,0 +1,32 @@
<?php
/**
* Sabre_CardDAV includes file
*
* Including this file will automatically include all files from the
* Sabre_CardDAV package.
*
* This often allows faster loadtimes, as autoload-speed is often quite slow.
*
* @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
*/
// Begin includes
include __DIR__ . '/AddressBookQueryParser.php';
include __DIR__ . '/AddressBookRoot.php';
include __DIR__ . '/Backend/Abstract.php';
include __DIR__ . '/Backend/PDO.php';
include __DIR__ . '/IAddressBook.php';
include __DIR__ . '/ICard.php';
include __DIR__ . '/IDirectory.php';
include __DIR__ . '/Plugin.php';
include __DIR__ . '/Property/SupportedAddressData.php';
include __DIR__ . '/UserAddressBooks.php';
include __DIR__ . '/Version.php';
include __DIR__ . '/AddressBook.php';
include __DIR__ . '/Card.php';
// End includes

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
@ -28,6 +28,8 @@ abstract class Sabre_DAV_Auth_Backend_AbstractBasic implements Sabre_DAV_Auth_IB
* This method should return true or false depending on if login
* succeeded.
*
* @param string $username
* @param string $password
* @return bool
*/
abstract protected function validateUserPass($username, $password);
@ -47,9 +49,11 @@ abstract class Sabre_DAV_Auth_Backend_AbstractBasic implements Sabre_DAV_Auth_IB
/**
* Authenticates the user based on the current request.
*
* If authentication is succesful, true must be returned.
* If authentication is successful, true must be returned.
* If authentication fails, an exception must be thrown.
*
* @param Sabre_DAV_Server $server
* @param string $realm
* @throws Sabre_DAV_Exception_NotAuthenticated
* @return bool
*/

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -36,9 +36,11 @@ abstract class Sabre_DAV_Auth_Backend_AbstractDigest implements Sabre_DAV_Auth_I
/**
* Authenticates the user based on the current request.
*
* If authentication is succesful, true must be returned.
* If authentication is successful, true must be returned.
* If authentication fails, an exception must be thrown.
*
* @param Sabre_DAV_Server $server
* @param string $realm
* @throws Sabre_DAV_Exception_NotAuthenticated
* @return bool
*/

View File

@ -4,13 +4,13 @@
* Apache authenticator
*
* This authentication backend assumes that authentication has been
* conifgured in apache, rather than within SabreDAV.
* configured in apache, rather than within SabreDAV.
*
* Make sure apache is properly configured for this to work.
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -26,9 +26,11 @@ class Sabre_DAV_Auth_Backend_Apache implements Sabre_DAV_Auth_IBackend {
/**
* Authenticates the user based on the current request.
*
* If authentication is succesful, true must be returned.
* If authentication is successful, true must be returned.
* If authentication fails, an exception must be thrown.
*
* @param Sabre_DAV_Server $server
* @param string $realm
* @return bool
*/
public function authenticate(Sabre_DAV_Server $server, $realm) {

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -25,8 +25,7 @@ class Sabre_DAV_Auth_Backend_File extends Sabre_DAV_Auth_Backend_AbstractDigest
*
* If the filename argument is passed in, it will parse out the specified file fist.
*
* @param string $filename
* @return void
* @param string|null $filename
*/
public function __construct($filename=null) {

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -33,9 +33,8 @@ class Sabre_DAV_Auth_Backend_PDO extends Sabre_DAV_Auth_Backend_AbstractDigest {
*
* If the filename argument is passed in, it will parse out the specified file fist.
*
* @param string $filename
* @param PDO $pdo
* @param string $tableName The PDO table name to use
* @return void
*/
public function __construct(PDO $pdo, $tableName = 'users') {
@ -53,7 +52,7 @@ class Sabre_DAV_Auth_Backend_PDO extends Sabre_DAV_Auth_Backend_AbstractDigest {
*/
public function getDigestHash($realm,$username) {
$stmt = $this->pdo->prepare('SELECT username, digesta1 FROM `'.$this->tableName.'` WHERE username = ?');
$stmt = $this->pdo->prepare('SELECT username, digesta1 FROM '.$this->tableName.' WHERE username = ?');
$stmt->execute(array($username));
$result = $stmt->fetchAll();

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -14,9 +14,11 @@ interface Sabre_DAV_Auth_IBackend {
/**
* Authenticates the user based on the current request.
*
* If authentication is succesful, true must be returned.
* If authentication is successful, true must be returned.
* If authentication fails, an exception must be thrown.
*
* @param Sabre_DAV_Server $server
* @param string $realm
* @return bool
*/
function authenticate(Sabre_DAV_Server $server,$realm);

View File

@ -11,7 +11,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -27,7 +27,7 @@ class Sabre_DAV_Auth_Plugin extends Sabre_DAV_ServerPlugin {
/**
* Authentication backend
*
* @var Sabre_DAV_Auth_Backend_Abstract
* @var Sabre_DAV_Auth_IBackend
*/
private $authBackend;
@ -41,9 +41,8 @@ class Sabre_DAV_Auth_Plugin extends Sabre_DAV_ServerPlugin {
/**
* __construct
*
* @param Sabre_DAV_Auth_Backend_Abstract $authBackend
* @param Sabre_DAV_Auth_IBackend $authBackend
* @param string $realm
* @return void
*/
public function __construct(Sabre_DAV_Auth_IBackend $authBackend, $realm) {
@ -99,6 +98,7 @@ class Sabre_DAV_Auth_Plugin extends Sabre_DAV_ServerPlugin {
* This method is called before any HTTP method and forces users to be authenticated
*
* @param string $method
* @param string $uri
* @throws Sabre_DAV_Exception_NotAuthenticated
* @return bool
*/

View File

@ -13,7 +13,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -37,6 +37,7 @@ class Sabre_DAV_Browser_MapGetToPropFind extends Sabre_DAV_ServerPlugin {
* This method intercepts GET requests to non-files, and changes it into an HTTP PROPFIND request
*
* @param string $method
* @param string $uri
* @return bool
*/
public function httpGetInterceptor($method, $uri) {

View File

@ -11,12 +11,39 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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 {
/**
* List of default icons for nodes.
*
* This is an array with class / interface names as keys, and asset names
* as values.
*
* The evaluation order is reversed. The last item in the list gets
* precendence.
*
* @var array
*/
public $iconMap = array(
'Sabre_DAV_IFile' => 'icons/file',
'Sabre_DAV_ICollection' => 'icons/collection',
'Sabre_DAVACL_IPrincipal' => 'icons/principal',
'Sabre_CalDAV_ICalendar' => 'icons/calendar',
'Sabre_CardDAV_IAddressBook' => 'icons/addressbook',
'Sabre_CardDAV_ICard' => 'icons/card',
);
/**
* The file extension used for all icons
*
* @var string
*/
public $iconExtension = '.png';
/**
* reference to server class
*
@ -25,12 +52,21 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
protected $server;
/**
* enableEditing
* enablePost turns on the 'actions' panel, which allows people to create
* folders and upload files straight from a browser.
*
* @var bool
*/
protected $enablePost = true;
/**
* By default the browser plugin will generate a favicon and other images.
* To turn this off, set this property to false.
*
* @var bool
*/
protected $enableAssets = true;
/**
* Creates the object.
*
@ -38,11 +74,12 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
* Specify the first argument as false to disable this
*
* @param bool $enablePost
* @return void
* @param bool $enableAssets
*/
public function __construct($enablePost=true) {
public function __construct($enablePost=true, $enableAssets = true) {
$this->enablePost = $enablePost;
$this->enableAssets = $enableAssets;
}
@ -56,6 +93,7 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
$this->server = $server;
$this->server->subscribeEvent('beforeMethod',array($this,'httpGetInterceptor'));
$this->server->subscribeEvent('onHTMLActionsPanel', array($this, 'htmlActionsPanel'),200);
if ($this->enablePost) $this->server->subscribeEvent('unknownMethod',array($this,'httpPOSTHandler'));
}
@ -63,15 +101,26 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
* This method intercepts GET requests to collections and returns the html
*
* @param string $method
* @param string $uri
* @return bool
*/
public function httpGetInterceptor($method, $uri) {
if ($method!='GET') return true;
if ($method !== 'GET') return true;
// We're not using straight-up $_GET, because we want everything to be
// unit testable.
$getVars = array();
parse_str($this->server->httpRequest->getQueryString(), $getVars);
if (isset($getVars['sabreAction']) && $getVars['sabreAction'] === 'asset' && isset($getVars['assetName'])) {
$this->serveAsset($getVars['assetName']);
return false;
}
try {
$node = $this->server->tree->getNodeForPath($uri);
} catch (Sabre_DAV_Exception_FileNotFound $e) {
} catch (Sabre_DAV_Exception_NotFound $e) {
// We're simply stopping when the file isn't found to not interfere
// with other plugins.
return;
@ -91,44 +140,58 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
}
/**
* Handles POST requests for tree operations
*
* This method is not yet used.
* Handles POST requests for tree operations.
*
* @param string $method
* @param string $uri
* @return bool
*/
public function httpPOSTHandler($method, $uri) {
if ($method!='POST') return true;
if (isset($_POST['sabreAction'])) switch($_POST['sabreAction']) {
if ($method!='POST') return;
$contentType = $this->server->httpRequest->getHeader('Content-Type');
list($contentType) = explode(';', $contentType);
if ($contentType !== 'application/x-www-form-urlencoded' &&
$contentType !== 'multipart/form-data') {
return;
}
$postVars = $this->server->httpRequest->getPostVars();
if (!isset($postVars['sabreAction']))
return;
if ($this->server->broadcastEvent('onBrowserPostAction', array($uri, $postVars['sabreAction'], $postVars))) {
switch($postVars['sabreAction']) {
case 'mkcol' :
if (isset($_POST['name']) && trim($_POST['name'])) {
if (isset($postVars['name']) && trim($postVars['name'])) {
// Using basename() because we won't allow slashes
list(, $folderName) = Sabre_DAV_URLUtil::splitPath(trim($_POST['name']));
list(, $folderName) = Sabre_DAV_URLUtil::splitPath(trim($postVars['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']);
if (isset($postVars['name']) && trim($postVars['name']))
$newName = trim($postVars['name']);
// Making sure we only have a 'basename' component
list(, $newName) = Sabre_DAV_URLUtil::splitPath($newName);
if (is_uploaded_file($file['tmp_name'])) {
$parent = $this->server->tree->getNodeForPath(trim($uri,'/'));
$parent->createFile($newName,fopen($file['tmp_name'],'r'));
$this->server->createFile($uri . '/' . $newName, fopen($file['tmp_name'],'r'));
}
break;
}
}
$this->server->httpResponse->setHeader('Location',$this->server->httpRequest->getUri());
$this->server->httpResponse->sendStatus(302);
return false;
}
@ -137,7 +200,7 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
* Escapes a string for html.
*
* @param string $value
* @return void
* @return string
*/
public function escapeHTML($value) {
@ -153,16 +216,30 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
*/
public function generateDirectoryIndex($path) {
$version = '';
if (Sabre_DAV_Server::$exposeVersion) {
$version = Sabre_DAV_Version::VERSION ."-". Sabre_DAV_Version::STABILITY;
}
$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>
<title>Index for " . $this->escapeHTML($path) . "/ - SabreDAV " . $version . "</title>
<style type=\"text/css\">
body { Font-family: arial}
h1 { font-size: 150% }
</style>
";
if ($this->enableAssets) {
$html.='<link rel="shortcut icon" href="'.$this->getAssetUrl('favicon.ico').'" type="image/vnd.microsoft.icon" />';
}
$html .= "</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>";
<tr><th width=\"24\"></th><th>Name</th><th>Type</th><th>Size</th><th>Last modified</th></tr>
<tr><td colspan=\"5\"><hr /></td></tr>";
$files = $this->server->getPropertiesForPath($path,array(
'{DAV:}displayname',
@ -180,7 +257,9 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
list($parentUri) = Sabre_DAV_URLUtil::splitPath($path);
$fullPath = Sabre_DAV_URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
$icon = $this->enableAssets?'<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="Parent" /></a>':'';
$html.= "<tr>
<td>$icon</td>
<td><a href=\"{$fullPath}\">..</a></td>
<td>[parent]</td>
<td></td>
@ -189,7 +268,7 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
}
foreach($files as $k=>$file) {
foreach($files as $file) {
// This is the current directory, we can skip it
if (rtrim($file['href'],'/')==$path) continue;
@ -221,6 +300,18 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
case '{urn:ietf:params:xml:ns:caldav}calendar' :
$type[$k] = 'Calendar';
break;
case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' :
$type[$k] = 'Schedule Inbox';
break;
case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' :
$type[$k] = 'Schedule Outbox';
break;
case '{http://calendarserver.org/ns/}calendar-proxy-read' :
$type[$k] = 'Proxy-Read';
break;
case '{http://calendarserver.org/ns/}calendar-proxy-write' :
$type[$k] = 'Proxy-Write';
break;
}
}
@ -241,11 +332,27 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
$displayName = isset($file[200]['{DAV:}displayname'])?$file[200]['{DAV:}displayname']:$name;
$name = $this->escapeHTML($name);
$displayName = $this->escapeHTML($displayName);
$type = $this->escapeHTML($type);
$icon = '';
if ($this->enableAssets) {
$node = $parent->getChild($name);
foreach(array_reverse($this->iconMap) as $class=>$iconName) {
if ($node instanceof $class) {
$icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24" /></a>';
break;
}
}
}
$html.= "<tr>
<td>$icon</td>
<td><a href=\"{$fullPath}\">{$displayName}</a></td>
<td>{$type}</td>
<td>{$size}</td>
@ -254,10 +361,47 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
}
$html.= "<tr><td colspan=\"4\"><hr /></td></tr>";
$html.= "<tr><td colspan=\"5\"><hr /></td></tr>";
if ($this->enablePost && $parent instanceof Sabre_DAV_ICollection) {
$html.= '<tr><td><form method="post" action="">
$output = '';
if ($this->enablePost) {
$this->server->broadcastEvent('onHTMLActionsPanel',array($parent, &$output));
}
$html.=$output;
$html.= "</table>
<address>Generated by SabreDAV " . $version . " (c)2007-2012 <a href=\"http://code.google.com/p/sabredav/\">http://code.google.com/p/sabredav/</a></address>
</body>
</html>";
return $html;
}
/**
* This method is used to generate the 'actions panel' output for
* collections.
*
* This specifically generates the interfaces for creating new files, and
* creating new directories.
*
* @param Sabre_DAV_INode $node
* @param mixed $output
* @return void
*/
public function htmlActionsPanel(Sabre_DAV_INode $node, &$output) {
if (!$node instanceof Sabre_DAV_ICollection)
return;
// We also know fairly certain that if an object is a non-extended
// SimpleCollection, we won't need to show the panel either.
if (get_class($node)==='Sabre_DAV_SimpleCollection')
return;
$output.= '<tr><td colspan="2"><form method="post" action="">
<h3>Create new folder</h3>
<input type="hidden" name="sabreAction" value="mkcol" />
Name: <input type="text" name="name" /><br />
@ -271,14 +415,74 @@ class Sabre_DAV_Browser_Plugin extends Sabre_DAV_ServerPlugin {
<input type="submit" value="upload" />
</form>
</td></tr>';
}
$html.= "</table>
<address>Generated by SabreDAV " . Sabre_DAV_Version::VERSION ."-". Sabre_DAV_Version::STABILITY . " (c)2007-2011 <a href=\"http://code.google.com/p/sabredav/\">http://code.google.com/p/sabredav/</a></address>
</body>
</html>";
/**
* This method takes a path/name of an asset and turns it into url
* suiteable for http access.
*
* @param string $assetName
* @return string
*/
protected function getAssetUrl($assetName) {
return $html;
return $this->server->getBaseUri() . '?sabreAction=asset&assetName=' . urlencode($assetName);
}
/**
* This method returns a local pathname to an asset.
*
* @param string $assetName
* @return string
*/
protected function getLocalAssetPath($assetName) {
// Making sure people aren't trying to escape from the base path.
$assetSplit = explode('/', $assetName);
if (in_array('..',$assetSplit)) {
throw new Sabre_DAV_Exception('Incorrect asset path');
}
$path = __DIR__ . '/assets/' . $assetName;
return $path;
}
/**
* This method reads an asset from disk and generates a full http response.
*
* @param string $assetName
* @return void
*/
protected function serveAsset($assetName) {
$assetPath = $this->getLocalAssetPath($assetName);
if (!file_exists($assetPath)) {
throw new Sabre_DAV_Exception_NotFound('Could not find an asset with this name');
}
// Rudimentary mime type detection
switch(strtolower(substr($assetPath,strpos($assetPath,'.')+1))) {
case 'ico' :
$mime = 'image/vnd.microsoft.icon';
break;
case 'png' :
$mime = 'image/png';
break;
default:
$mime = 'application/octet-stream';
break;
}
$this->server->httpResponse->setHeader('Content-Type', $mime);
$this->server->httpResponse->setHeader('Content-Length', filesize($assetPath));
$this->server->httpResponse->setHeader('Cache-Control', 'public, max-age=1209600');
$this->server->httpResponse->sendStatus(200);
$this->server->httpResponse->sendBody(fopen($assetPath,'r'));
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -10,7 +10,7 @@
*
* @package Sabre
* @subpackage DAVClient
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -189,7 +189,7 @@ class Sabre_DAV_Client {
$body.= '</d:propertyupdate>';
$response = $this->request('PROPPATCH', $url, $body, array(
$this->request('PROPPATCH', $url, $body, array(
'Content-Type' => 'application/xml'
));
@ -243,12 +243,35 @@ class Sabre_DAV_Client {
$curlSettings = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $body,
// Return headers as part of the response
CURLOPT_HEADER => true
CURLOPT_HEADER => true,
CURLOPT_POSTFIELDS => $body,
// Automatically follow redirects
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
);
switch ($method) {
case 'PUT':
$curlSettings[CURLOPT_PUT] = true;
break;
case 'HEAD' :
// do not read body with HEAD requests (this is neccessary because cURL does not ignore the body with HEAD
// requests when the Content-Length header is given - which in turn is perfectly valid according to HTTP
// specs...) cURL does unfortunately return an error in this case ("transfer closed transfer closed with
// ... bytes remaining to read") this can be circumvented by explicitly telling cURL to ignore the
// response body
$curlSettings[CURLOPT_NOBODY] = true;
$curlSettings[CURLOPT_CUSTOMREQUEST] = 'HEAD';
break;
default:
$curlSettings[CURLOPT_CUSTOMREQUEST] = $method;
break;
}
// Adding HTTP headers
$nHeaders = array();
foreach($headers as $key=>$value) {
@ -307,8 +330,15 @@ class Sabre_DAV_Client {
}
if ($response['statusCode']>=400) {
switch ($response['statusCode']) {
case 404:
throw new Sabre_DAV_Exception_NotFound('Resource ' . $url . ' not found.');
break;
default:
throw new Sabre_DAV_Exception('HTTP error response. (errorcode ' . $response['statusCode'] . ')');
}
}
return $response;
@ -322,7 +352,7 @@ class Sabre_DAV_Client {
*
* @param string $url
* @param array $settings
* @return
* @return array
*/
protected function curlRequest($url, $settings) {
@ -398,13 +428,12 @@ class Sabre_DAV_Client {
throw new InvalidArgumentException('The passed data is not valid XML');
}
$responseXML->registerXPathNamespace('d','DAV:');
$responseXML->registerXPathNamespace('d', 'urn:DAV');
$propResult = array();
foreach($responseXML->xpath('d:response') as $response) {
$response->registerXPathNamespace('d','DAV:');
$response->registerXPathNamespace('d', 'urn:DAV');
$href = $response->xpath('d:href');
$href = (string)$href[0];
@ -412,7 +441,7 @@ class Sabre_DAV_Client {
foreach($response->xpath('d:propstat') as $propStat) {
$propStat->registerXPathNamespace('d','DAV:');
$propStat->registerXPathNamespace('d', 'urn:DAV');
$status = $propStat->xpath('d:status');
list($httpVersion, $statusCode, $message) = explode(' ', (string)$status[0],3);

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -21,7 +21,7 @@ abstract class Sabre_DAV_Collection extends Sabre_DAV_Node implements Sabre_DAV_
* Generally its wise to override this, as this can usually be optimized
*
* @param string $name
* @throws Sabre_DAV_Exception_FileNotFound
* @throws Sabre_DAV_Exception_NotFound
* @return Sabre_DAV_INode
*/
public function getChild($name) {
@ -31,7 +31,7 @@ abstract class Sabre_DAV_Collection extends Sabre_DAV_Node implements Sabre_DAV_
if ($child->getName()==$name) return $child;
}
throw new Sabre_DAV_Exception_FileNotFound('File not found: ' . $name);
throw new Sabre_DAV_Exception_NotFound('File not found: ' . $name);
}
@ -50,7 +50,7 @@ abstract class Sabre_DAV_Collection extends Sabre_DAV_Node implements Sabre_DAV_
$this->getChild($name);
return true;
} catch(Sabre_DAV_Exception_FileNotFound $e) {
} catch(Sabre_DAV_Exception_NotFound $e) {
return false;
@ -61,10 +61,26 @@ abstract class Sabre_DAV_Collection extends Sabre_DAV_Node implements Sabre_DAV_
/**
* Creates a new file in the directory
*
* Data will either be supplied as a stream resource, or in certain cases
* as a string. Keep in mind that you may have to support either.
*
* After succesful creation of the file, you may choose to return the ETag
* of the new file here.
*
* The returned ETag must be surrounded by double-quotes (The quotes should
* be part of the actual string).
*
* If you cannot accurately determine the ETag, you should not return it.
* If you don't store the file exactly as-is (you're transforming it
* somehow) you should also not return an ETag.
*
* This means that if a subsequent GET to this new file does not exactly
* return the same contents of what was submitted here, you are strongly
* recommended to omit the ETag.
*
* @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
* @param resource|string $data Initial payload
* @return null|string
*/
public function createFile($name, $data = null) {

View File

@ -8,7 +8,7 @@
* @package Sabre
* @subpackage DAV
* @deprecated Use Sabre_DAV_Collection instead
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -15,7 +15,7 @@
/**
* Main Exception class.
*
* This class defines a getHTTPCode method, which should return the appropriate HTTP code for the Exception occured.
* This class defines a getHTTPCode method, which should return the appropriate HTTP code for the Exception occurred.
* The default for this is 500.
*
* This class also allows you to generate custom xml data for your exceptions. This will be displayed
@ -35,7 +35,7 @@ class Sabre_DAV_Exception extends Exception {
}
/**
* This method allows the exception to include additonal information into the WebDAV error response
* This method allows the exception to include additional information into the WebDAV error response
*
* @param Sabre_DAV_Server $server
* @param DOMElement $errorNode
@ -51,6 +51,7 @@ class Sabre_DAV_Exception extends Exception {
*
* The headers must be returned as an array.
*
* @param Sabre_DAV_Server $server
* @return array
*/
public function getHTTPHeaders(Sabre_DAV_Server $server) {

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -8,14 +8,14 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
* This method allows the exception to include additional information into the WebDAV error response
*
* @param Sabre_DAV_Server $server
* @param DOMElement $errorNode

View File

@ -3,26 +3,17 @@
/**
* FileNotFound
*
* This Exception is thrown when a Node couldn't be found. It returns HTTP error code 404
* Deprecated: Warning, this class is deprecated and will be removed in a
* future version of SabreDAV. Please use Sabre_DAV_Exception_NotFound instead.
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
* @author Evert Pot (http://www.rooftopsolutions.nl/)
* @deprecated Use Sabre_DAV_Exception_NotFound instead
* @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;
}
class Sabre_DAV_Exception_FileNotFound extends Sabre_DAV_Exception_NotFound {
}

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -10,14 +10,14 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
* This method allows the exception to include additional information into the WebDAV error response
*
* @param Sabre_DAV_Server $server
* @param DOMElement $errorNode

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -23,7 +23,7 @@ class Sabre_DAV_Exception_LockTokenMatchesRequestUri extends Sabre_DAV_Exception
}
/**
* This method allows the exception to include additonal information into the WebDAV error response
* This method allows the exception to include additional information into the WebDAV error response
*
* @param Sabre_DAV_Server $server
* @param DOMElement $errorNode

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -46,7 +46,7 @@ class Sabre_DAV_Exception_Locked extends Sabre_DAV_Exception {
}
/**
* This method allows the exception to include additonal information into the WebDAV error response
* This method allows the exception to include additional information into the WebDAV error response
*
* @param Sabre_DAV_Server $server
* @param DOMElement $errorNode

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -29,6 +29,7 @@ class Sabre_DAV_Exception_MethodNotAllowed extends Sabre_DAV_Exception {
*
* The headers must be returned as an array.
*
* @param Sabre_DAV_Server $server
* @return array
*/
public function getHTTPHeaders(Sabre_DAV_Server $server) {

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -0,0 +1,28 @@
<?php
/**
* NotFound
*
* 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_NotFound extends Sabre_DAV_Exception {
/**
* Returns the HTTP statuscode for this exception
*
* @return int
*/
public function getHTTPCode() {
return 404;
}
}

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -0,0 +1,28 @@
<?php
/**
* Payment Required
*
* The PaymentRequired exception may be thrown in a case where a user must pay
* to access a certain resource or operation.
*
* @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_PaymentRequired extends Sabre_DAV_Exception {
/**
* Returns the HTTP statuscode for this exception
*
* @return int
*/
public function getHTTPCode() {
return 402;
}
}

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -50,7 +50,7 @@ class Sabre_DAV_Exception_PreconditionFailed extends Sabre_DAV_Exception {
}
/**
* This method allows the exception to include additonal information into the WebDAV error response
* This method allows the exception to include additional information into the WebDAV error response
*
* @param Sabre_DAV_Server $server
* @param DOMElement $errorNode

View File

@ -7,14 +7,14 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
* This method allows the exception to include additional information into the WebDAV error response
*
* @param Sabre_DAV_Server $server
* @param DOMElement $errorNode

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -14,11 +14,26 @@ class Sabre_DAV_FS_Directory extends Sabre_DAV_FS_Node implements Sabre_DAV_ICol
/**
* Creates a new file in the directory
*
* data is a readable stream resource
* Data will either be supplied as a stream resource, or in certain cases
* as a string. Keep in mind that you may have to support either.
*
* After succesful creation of the file, you may choose to return the ETag
* of the new file here.
*
* The returned ETag must be surrounded by double-quotes (The quotes should
* be part of the actual string).
*
* If you cannot accurately determine the ETag, you should not return it.
* If you don't store the file exactly as-is (you're transforming it
* somehow) you should also not return an ETag.
*
* This means that if a subsequent GET to this new file does not exactly
* return the same contents of what was submitted here, you are strongly
* recommended to omit the ETag.
*
* @param string $name Name of the file
* @param resource $data Initial payload
* @return void
* @param resource|string $data Initial payload
* @return null|string
*/
public function createFile($name, $data = null) {
@ -44,14 +59,14 @@ class Sabre_DAV_FS_Directory extends Sabre_DAV_FS_Node implements Sabre_DAV_ICol
* Returns a specific child node, referenced by its name
*
* @param string $name
* @throws Sabre_DAV_Exception_FileNotFound
* @throws Sabre_DAV_Exception_NotFound
* @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 (!file_exists($path)) throw new Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located');
if (is_dir($path)) {

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -60,7 +60,7 @@ class Sabre_DAV_FS_File extends Sabre_DAV_FS_Node implements Sabre_DAV_IFile {
* 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.
* The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
*
* Return null if the ETag can not effectively be determined
*

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -24,7 +24,6 @@ abstract class Sabre_DAV_FS_Node implements Sabre_DAV_INode {
* Sets up the node, expects a full path name
*
* @param string $path
* @return void
*/
public function __construct($path) {

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -14,9 +14,26 @@ class Sabre_DAV_FSExt_Directory extends Sabre_DAV_FSExt_Node implements Sabre_DA
/**
* Creates a new file in the directory
*
* Data will either be supplied as a stream resource, or in certain cases
* as a string. Keep in mind that you may have to support either.
*
* After succesful creation of the file, you may choose to return the ETag
* of the new file here.
*
* The returned ETag must be surrounded by double-quotes (The quotes should
* be part of the actual string).
*
* If you cannot accurately determine the ETag, you should not return it.
* If you don't store the file exactly as-is (you're transforming it
* somehow) you should also not return an ETag.
*
* This means that if a subsequent GET to this new file does not exactly
* return the same contents of what was submitted here, you are strongly
* recommended to omit the ETag.
*
* @param string $name Name of the file
* @param resource $data Initial payload
* @return void
* @param resource|string $data Initial payload
* @return null|string
*/
public function createFile($name, $data = null) {
@ -25,6 +42,8 @@ class Sabre_DAV_FSExt_Directory extends Sabre_DAV_FSExt_Node implements Sabre_DA
$newPath = $this->path . '/' . $name;
file_put_contents($newPath,$data);
return '"' . md5_file($newPath) . '"';
}
/**
@ -46,14 +65,14 @@ class Sabre_DAV_FSExt_Directory extends Sabre_DAV_FSExt_Node implements Sabre_DA
* Returns a specific child node, referenced by its name
*
* @param string $name
* @throws Sabre_DAV_Exception_FileNotFound
* @throws Sabre_DAV_Exception_NotFound
* @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 (!file_exists($path)) throw new Sabre_DAV_Exception_NotFound('File could not be located');
if ($name=='.' || $name=='..') throw new Sabre_DAV_Exception_Forbidden('Permission denied to . and ..');
if (is_dir($path)) {
@ -100,7 +119,7 @@ class Sabre_DAV_FSExt_Directory extends Sabre_DAV_FSExt_Node implements Sabre_DA
/**
* Deletes all files in this directory, and then itself
*
* @return void
* @return bool
*/
public function delete() {

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -22,6 +22,7 @@ class Sabre_DAV_FSExt_File extends Sabre_DAV_FSExt_Node implements Sabre_DAV_IFi
public function put($data) {
file_put_contents($this->path,$data);
return '"' . md5_file($this->path) . '"';
}
@ -39,7 +40,7 @@ class Sabre_DAV_FSExt_File extends Sabre_DAV_FSExt_Node implements Sabre_DAV_IFi
/**
* Delete the current file
*
* @return void
* @return bool
*/
public function delete() {
@ -52,9 +53,11 @@ class Sabre_DAV_FSExt_File extends Sabre_DAV_FSExt_Node implements Sabre_DAV_IFi
* 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.
* The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
*
* Return null if the ETag can not effectively be determined
*
* @return string|null
*/
public function getETag() {
@ -66,6 +69,8 @@ class Sabre_DAV_FSExt_File extends Sabre_DAV_FSExt_Node implements Sabre_DAV_IFi
* Returns the mime-type for a file
*
* If null is returned, we'll assume application/octet-stream
*
* @return string|null
*/
public function getContentType() {

View File

@ -7,81 +7,16 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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;
}
abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_DAV_IProperties {
/**
* Updates properties on this node,
*
* @param array $mutations
* @param array $properties
* @see Sabre_DAV_IProperties::updateProperties
* @return bool|array
*/
@ -89,8 +24,6 @@ abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_D
$resourceData = $this->getResourceData();
$result = array();
foreach($properties as $propertyName=>$propertyValue) {
// If it was null, we need to delete the property
@ -115,7 +48,7 @@ abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_D
* If the array is empty, all properties should be returned
*
* @param array $properties
* @return void
* @return array
*/
function getProperties($properties) {
@ -153,7 +86,7 @@ abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_D
protected function getResourceData() {
$path = $this->getResourceInfoPath();
if (!file_exists($path)) return array('locks'=>array(), 'properties' => array());
if (!file_exists($path)) return array('properties' => array());
// opening up the file, and creating a shared lock
$handle = fopen($path,'r');
@ -171,11 +104,10 @@ abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_D
// 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());
return array('properties' => array());
}
$data = $data[$this->getName()];
if (!isset($data['locks'])) $data['locks'] = array();
if (!isset($data['properties'])) $data['properties'] = array();
return $data;
@ -238,6 +170,9 @@ abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_D
}
/**
* @return bool
*/
public function deleteResourceData() {
// When we're deleting this node, we also need to delete any resource information
@ -264,6 +199,7 @@ abstract class Sabre_DAV_FSExt_Node extends Sabre_DAV_FS_Node implements Sabre_D
fwrite($handle,serialize($data));
fclose($handle);
return true;
}
public function delete() {

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -56,9 +56,11 @@ abstract class Sabre_DAV_File extends Sabre_DAV_Node implements Sabre_DAV_IFile
* 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.
* The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
*
* Return null if the ETag can not effectively be determined
*
* @return string|null
*/
public function getETag() {
@ -70,6 +72,8 @@ abstract class Sabre_DAV_File extends Sabre_DAV_Node implements Sabre_DAV_IFile
* Returns the mime-type for a file
*
* If null is returned, we'll assume application/octet-stream
*
* @return string|null
*/
public function getContentType() {

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -16,11 +16,26 @@ interface Sabre_DAV_ICollection extends Sabre_DAV_INode {
/**
* Creates a new file in the directory
*
* data is a readable stream resource
* Data will either be supplied as a stream resource, or in certain cases
* as a string. Keep in mind that you may have to support either.
*
* After succesful creation of the file, you may choose to return the ETag
* of the new file here.
*
* The returned ETag must be surrounded by double-quotes (The quotes should
* be part of the actual string).
*
* If you cannot accurately determine the ETag, you should not return it.
* If you don't store the file exactly as-is (you're transforming it
* somehow) you should also not return an ETag.
*
* This means that if a subsequent GET to this new file does not exactly
* return the same contents of what was submitted here, you are strongly
* recommended to omit the ETag.
*
* @param string $name Name of the file
* @param resource $data Initial payload
* @return void
* @param resource|string $data Initial payload
* @return null|string
*/
function createFile($name, $data = null);
@ -50,6 +65,7 @@ interface Sabre_DAV_ICollection extends Sabre_DAV_INode {
/**
* Checks if a child-node with the specified name exists
*
* @param string $name
* @return bool
*/
function childExists($name);

View File

@ -8,7 +8,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -1,13 +1,15 @@
<?php
/**
* This interface represents a file or leaf in the tree.
* This interface represents a file in the directory tree
*
* The nature of a file is, as you might be aware of, that it doesn't contain sub-nodes and has contents
* A file is a bit of a broad definition. In general it implies that on
* this specific node a PUT or GET method may be performed, to either update,
* or retrieve the contents of the file.
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -18,8 +20,20 @@ interface Sabre_DAV_IFile extends Sabre_DAV_INode {
*
* The data argument is a readable stream resource.
*
* After a succesful put operation, you may choose to return an ETag. The
* etag must always be surrounded by double-quotes. These quotes must
* appear in the actual string you're returning.
*
* Clients may use the ETag from a PUT request to later on make sure that
* when they update the file, the contents haven't changed in the mean
* time.
*
* If you don't plan to store the file byte-by-byte, and you return a
* different object on a subsequent GET you are strongly recommended to not
* return an ETag, and just return null.
*
* @param resource $data
* @return void
* @return string|null
*/
function put($data);

View File

@ -1,38 +0,0 @@
<?php
/**
* Implement this class to support locking
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 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_ILockable extends Sabre_DAV_INode {
/**
* Returns an array with locks currently on the node
*
* @return Sabre_DAV_Locks_LockInfo[]
*/
function getLocks();
/**
* Creates a new lock on the file.
*
* @param Sabre_DAV_Locks_LockInfo $lockInfo The lock information
* @return void
*/
function lock(Sabre_DAV_Locks_LockInfo $lockInfo);
/**
* Unlocks a file
*
* @param Sabre_DAV_Locks_LockInfo $lockInfo The lock information
* @return void
*/
function unlock(Sabre_DAV_Locks_LockInfo $lockInfo);
}

View File

@ -5,7 +5,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -19,7 +19,9 @@ interface Sabre_DAV_INode {
function delete();
/**
* Returns the name of the node
* Returns the name of the node.
*
* This is used to generate the url.
*
* @return string
*/

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/
@ -26,7 +26,7 @@ interface Sabre_DAV_IProperties extends Sabre_DAV_INode {
* 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.
* Deletion of a non-existent property is always successful.
*
* Lastly, it is optional to return detailed information about any
* failures. In this case an array should be returned with the following

View File

@ -9,7 +9,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

View File

@ -7,7 +7,7 @@
*
* @package Sabre
* @subpackage DAV
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @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
*/

Some files were not shown because too many files have changed in this diff Show More