mirror of
https://git.friendi.ca/friendica/friendica-addons.git
synced 2025-07-07 00:48:55 +00:00
Heavily refactored, including multiple calendars per user and recurring events. Not in an installable state yet, though
This commit is contained in:
parent
4a5e30ec84
commit
fefee23e90
78 changed files with 8026 additions and 1205 deletions
|
@ -3,45 +3,15 @@
|
|||
/**
|
||||
* Abstract Calendaring backend. Extend this class to create your own backends.
|
||||
*
|
||||
* Checkout the BackendInterface for all the methods that must be implemented.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_CalDAV_Backend_Abstract {
|
||||
|
||||
/**
|
||||
* Returns a list of calendars for a principal.
|
||||
*
|
||||
* Every project is an array with the following keys:
|
||||
* * id, a unique id that will be used by other functions to modify the
|
||||
* calendar. This can be the same as the uri or a database key.
|
||||
* * uri, which the basename of the uri with which the calendar is
|
||||
* accessed.
|
||||
* * principaluri. The owner of the calendar. Almost always the same as
|
||||
* principalUri passed to this method.
|
||||
*
|
||||
* Furthermore it can contain webdav properties in clark notation. A very
|
||||
* common one is '{DAV:}displayname'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarsForUser($principalUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar for a principal.
|
||||
*
|
||||
* If the creation was a success, an id must be returned that can be used to reference
|
||||
* this calendar in other methods, such as updateCalendar.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $calendarUri
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
abstract function createCalendar($principalUri,$calendarUri,array $properties);
|
||||
abstract class Sabre_CalDAV_Backend_Abstract implements Sabre_CalDAV_Backend_BackendInterface {
|
||||
|
||||
/**
|
||||
* Updates properties for a calendar.
|
||||
|
@ -85,102 +55,6 @@ abstract class Sabre_CalDAV_Backend_Abstract {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return void
|
||||
*/
|
||||
abstract function deleteCalendar($calendarId);
|
||||
|
||||
/**
|
||||
* Returns all calendar objects within a calendar.
|
||||
*
|
||||
* Every item contains an array with the following keys:
|
||||
* * id - unique identifier which will be used for subsequent updates
|
||||
* * calendardata - The iCalendar-compatible 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.
|
||||
*
|
||||
* The calendardata is also optional. If it's not returned
|
||||
* '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 mixed $calendarId
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarObjects($calendarId);
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array
|
||||
*/
|
||||
abstract function getCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
abstract function createCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
abstract function updateCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
abstract function deleteCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Performs a calendar-query on the contents of this calendar.
|
||||
*
|
||||
|
|
231
dav/SabreDAV/lib/Sabre/CalDAV/Backend/BackendInterface.php
Normal file
231
dav/SabreDAV/lib/Sabre/CalDAV/Backend/BackendInterface.php
Normal file
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Every CalDAV backend must at least implement this interface.
|
||||
*
|
||||
* @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_Backend_BackendInterface {
|
||||
|
||||
/**
|
||||
* Returns a list of calendars for a principal.
|
||||
*
|
||||
* Every project is an array with the following keys:
|
||||
* * id, a unique id that will be used by other functions to modify the
|
||||
* calendar. This can be the same as the uri or a database key.
|
||||
* * uri, which the basename of the uri with which the calendar is
|
||||
* accessed.
|
||||
* * principaluri. The owner of the calendar. Almost always the same as
|
||||
* principalUri passed to this method.
|
||||
*
|
||||
* Furthermore it can contain webdav properties in clark notation. A very
|
||||
* common one is '{DAV:}displayname'.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar for a principal.
|
||||
*
|
||||
* If the creation was a success, an id must be returned that can be used to reference
|
||||
* this calendar in other methods, such as updateCalendar.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param string $calendarUri
|
||||
* @param array $properties
|
||||
* @return void
|
||||
*/
|
||||
public function createCalendar($principalUri,$calendarUri,array $properties);
|
||||
|
||||
/**
|
||||
* Updates properties for a calendar.
|
||||
*
|
||||
* The mutations array uses the propertyName in clark-notation as key,
|
||||
* and the array value for the property value. In the case a property
|
||||
* should be deleted, the property value will be null.
|
||||
*
|
||||
* This method must be atomic. If one property cannot be changed, the
|
||||
* entire operation must fail.
|
||||
*
|
||||
* If the operation was successful, true can be returned.
|
||||
* If the operation failed, false can be returned.
|
||||
*
|
||||
* Deletion of a non-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
|
||||
* structure:
|
||||
*
|
||||
* array(
|
||||
* 403 => array(
|
||||
* '{DAV:}displayname' => null,
|
||||
* ),
|
||||
* 424 => array(
|
||||
* '{DAV:}owner' => null,
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* In this example it was forbidden to update {DAV:}displayname.
|
||||
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
|
||||
* (424 Failed Dependency) because the request needs to be atomic.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations);
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId);
|
||||
|
||||
/**
|
||||
* Returns all calendar objects within a calendar.
|
||||
*
|
||||
* Every item contains an array with the following keys:
|
||||
* * id - unique identifier which will be used for subsequent updates
|
||||
* * calendardata - The iCalendar-compatible 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.
|
||||
*
|
||||
* The calendardata is also optional. If it's not returned
|
||||
* '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 mixed $calendarId
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObjects($calendarId);
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function createCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* It is possible return an etag from this function, which will be used in
|
||||
* the response to this PUT request. Note that the ETag must be surrounded
|
||||
* by double-quotes.
|
||||
*
|
||||
* However, you should only really return this ETag if you don't mangle the
|
||||
* calendar-data. If the result of a subsequent GET to this object is not
|
||||
* the exact same as this request body, you should omit the ETag.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateCalendarObject($calendarId,$objectUri,$calendarData);
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendarObject($calendarId,$objectUri);
|
||||
|
||||
/**
|
||||
* Performs a calendar-query on the contents of this calendar.
|
||||
*
|
||||
* The calendar-query is defined in RFC4791 : CalDAV. Using the
|
||||
* calendar-query it is possible for a client to request a specific set of
|
||||
* object, based on contents of iCalendar properties, date-ranges and
|
||||
* iCalendar component types (VTODO, VEVENT).
|
||||
*
|
||||
* This method should just return a list of (relative) urls that match this
|
||||
* query.
|
||||
*
|
||||
* The list of filters are specified as an array. The exact array is
|
||||
* documented by Sabre_CalDAV_CalendarQueryParser.
|
||||
*
|
||||
* Note that it is extremely likely that getCalendarObject for every path
|
||||
* returned from this method will be called almost immediately after. You
|
||||
* may want to anticipate this to speed up these requests.
|
||||
*
|
||||
* This method provides a default implementation, which parses *all* the
|
||||
* iCalendar objects in the specified calendar.
|
||||
*
|
||||
* This default may well be good enough for personal use, and calendars
|
||||
* that aren't very large. But if you anticipate high usage, big calendars
|
||||
* or high loads, you are strongly adviced to optimize certain paths.
|
||||
*
|
||||
* The best way to do so is override this method and to optimize
|
||||
* specifically for 'common filters'.
|
||||
*
|
||||
* Requests that are extremely common are:
|
||||
* * requests for just VEVENTS
|
||||
* * requests for just VTODO
|
||||
* * requests with a time-range-filter on either VEVENT or VTODO.
|
||||
*
|
||||
* ..and combinations of these requests. It may not be worth it to try to
|
||||
* handle every possible situation and just rely on the (relatively
|
||||
* easy to use) CalendarQueryValidator to handle the rest.
|
||||
*
|
||||
* Note that especially time-range-filters may be difficult to parse. A
|
||||
* time-range filter specified on a VEVENT must for instance also handle
|
||||
* recurrence rules correctly.
|
||||
* A good example of how to interprete all these filters can also simply
|
||||
* be found in Sabre_CalDAV_CalendarQueryFilter. This class is as correct
|
||||
* as possible, so it gives you a good idea on what type of stuff you need
|
||||
* to think of.
|
||||
*
|
||||
* @param mixed $calendarId
|
||||
* @param array $filters
|
||||
* @return array
|
||||
*/
|
||||
public function calendarQuery($calendarId, array $filters);
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Adds caldav notification support to a backend.
|
||||
*
|
||||
* Notifications are defined at:
|
||||
* http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk/doc/Extensions/caldav-notifications.txt
|
||||
*
|
||||
* These notifications are basically a list of server-generated notifications
|
||||
* displayed to the user. Users can dismiss notifications by deleting them.
|
||||
*
|
||||
* The primary usecase is to allow for calendar-sharing.
|
||||
*
|
||||
* @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_Backend_NotificationSupport extends Sabre_CalDAV_Backend_BackendInterface {
|
||||
|
||||
/**
|
||||
* Returns a list of notifications for a given principal url.
|
||||
*
|
||||
* The returned array should only consist of implementations of
|
||||
* Sabre_CalDAV_Notifications_INotificationType.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getNotificationsForPrincipal($principalUri);
|
||||
|
||||
/**
|
||||
* This deletes a specific notifcation.
|
||||
*
|
||||
* This may be called by a client once it deems a notification handled.
|
||||
*
|
||||
* @param string $principalUri
|
||||
* @param Sabre_CalDAV_Notifications_INotificationType $notification
|
||||
* @return void
|
||||
*/
|
||||
public function deleteNotification($principalUri, Sabre_CalDAV_Notifications_INotificationType $notification);
|
||||
|
||||
}
|
|
@ -24,7 +24,7 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
|
|||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
* @var Sabre_CalDAV_Backend_BackendInterface
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
|
@ -39,10 +39,10 @@ class Sabre_CalDAV_Calendar implements Sabre_CalDAV_ICalendar, Sabre_DAV_IProper
|
|||
* Constructor
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param array $calendarInfo
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_Abstract $caldavBackend, $calendarInfo) {
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_BackendInterface $caldavBackend, $calendarInfo) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->principalBackend = $principalBackend;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV_ICalendarObject, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
* Sabre_CalDAV_Backend_Abstract
|
||||
* Sabre_CalDAV_Backend_BackendInterface
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -35,11 +35,11 @@ class Sabre_CalDAV_CalendarObject extends Sabre_DAV_File implements Sabre_CalDAV
|
|||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param array $calendarInfo
|
||||
* @param array $objectData
|
||||
*/
|
||||
public function __construct(Sabre_CalDAV_Backend_Abstract $caldavBackend,array $calendarInfo,array $objectData) {
|
||||
public function __construct(Sabre_CalDAV_Backend_BackendInterface $caldavBackend,array $calendarInfo,array $objectData) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
||||
|
|
|
@ -304,28 +304,29 @@ class Sabre_CalDAV_CalendarQueryValidator {
|
|||
// 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) {
|
||||
if ($expandedEvent->VALARM !== null) {
|
||||
foreach($expandedEvent->VALARM as $expandedAlarm) {
|
||||
|
||||
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
|
||||
if ($expandedAlarm->isInTimeRange($start, $end)) {
|
||||
return true;
|
||||
}
|
||||
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
|
||||
if ($expandedAlarm->isInTimeRange($start, $end)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((string)$expandedAlarm->TRIGGER['VALUE'] === 'DATE-TIME') {
|
||||
// This is an alarm with a non-relative trigger
|
||||
// time, likely created by a buggy client. The
|
||||
// implication is that every alarm in this
|
||||
// recurring event trigger at the exact same
|
||||
// time. It doesn't make sense to traverse
|
||||
// further.
|
||||
} else {
|
||||
// We store the first alarm as a means to
|
||||
// figure out when we can stop traversing.
|
||||
if (!$firstAlarm || $effectiveTrigger < $firstAlarm) {
|
||||
$firstAlarm = $effectiveTrigger;
|
||||
if ((string)$expandedAlarm->TRIGGER['VALUE'] === 'DATE-TIME') {
|
||||
// This is an alarm with a non-relative trigger
|
||||
// time, likely created by a buggy client. The
|
||||
// implication is that every alarm in this
|
||||
// recurring event trigger at the exact same
|
||||
// time. It doesn't make sense to traverse
|
||||
// further.
|
||||
} else {
|
||||
// We store the first alarm as a means to
|
||||
// figure out when we can stop traversing.
|
||||
if (!$firstAlarm || $effectiveTrigger < $firstAlarm) {
|
||||
$firstAlarm = $effectiveTrigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (is_null($firstAlarm)) {
|
||||
// No alarm was found.
|
||||
|
|
|
@ -17,7 +17,7 @@ class Sabre_CalDAV_CalendarRootNode extends Sabre_DAVACL_AbstractPrincipalCollec
|
|||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
* @var Sabre_CalDAV_Backend_BackendInterface
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
|
@ -33,10 +33,10 @@ class Sabre_CalDAV_CalendarRootNode extends Sabre_DAVACL_AbstractPrincipalCollec
|
|||
*
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param string $principalPrefix
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend,Sabre_CalDAV_Backend_Abstract $caldavBackend, $principalPrefix = 'principals') {
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend,Sabre_CalDAV_Backend_BackendInterface $caldavBackend, $principalPrefix = 'principals') {
|
||||
|
||||
parent::__construct($principalBackend, $principalPrefix);
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Sabre_CalDAV_Exception_InvalidComponentType
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage CalDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CalDAV_Exception_InvalidComponentType extends Sabre_DAV_Exception_Forbidden {
|
||||
|
||||
/**
|
||||
* Adds in extra information in the xml response.
|
||||
*
|
||||
* This method adds the {CALDAV:}supported-calendar-component as defined in rfc4791
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $errorNode
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server,DOMElement $errorNode) {
|
||||
|
||||
$doc = $errorNode->ownerDocument;
|
||||
|
||||
$np = $doc->createElementNS(Sabre_CalDAV_Plugin::NS_CALDAV,'cal:supported-calendar-component');
|
||||
$errorNode->appendChild($np);
|
||||
|
||||
}
|
||||
|
||||
}
|
80
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Collection.php
Normal file
80
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Collection.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a list of notifications.
|
||||
*
|
||||
* It provides no additional functionality, but you must implement this
|
||||
* interface to allow the Notifications plugin to mark the collection
|
||||
* as a notifications collection.
|
||||
*
|
||||
* This collection should only return Sabre_CalDAV_Notifications_INode nodes as
|
||||
* its children.
|
||||
*
|
||||
* @package Sabre
|
||||
* @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_Notifications_Collection extends Sabre_DAV_Collection implements Sabre_CalDAV_Notifications_ICollection {
|
||||
|
||||
/**
|
||||
* The notification backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_NotificationSupport
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* Principal uri
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $principalUri;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_NotificationSupport $caldavBackend
|
||||
* @param string $principalUri
|
||||
*/
|
||||
public function __construct(Sabre_CalDAV_Backend_NotificationSupport $caldavBackend, $principalUri) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->principalUri = $principalUri;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all notifications for a principal
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren() {
|
||||
|
||||
$children = array();
|
||||
$notifications = $this->caldavBackend->getNotificationsForPrincipal($this->principalUri);
|
||||
|
||||
foreach($notifications as $notification) {
|
||||
|
||||
$children[] = new Sabre_CalDAV_Notifications_Node(
|
||||
$this->caldavBackend,
|
||||
$notification
|
||||
);
|
||||
}
|
||||
|
||||
return $children;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return 'notifications';
|
||||
|
||||
}
|
||||
|
||||
}
|
22
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/ICollection.php
Normal file
22
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/ICollection.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a list of notifications.
|
||||
*
|
||||
* It provides no additional functionality, but you must implement this
|
||||
* interface to allow the Notifications plugin to mark the collection
|
||||
* as a notifications collection.
|
||||
*
|
||||
* This collection should only return Sabre_CalDAV_Notifications_INode nodes as
|
||||
* its children.
|
||||
*
|
||||
* @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_Notifications_ICollection extends Sabre_DAV_ICollection {
|
||||
|
||||
|
||||
}
|
29
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/INode.php
Normal file
29
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/INode.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a single notification.
|
||||
*
|
||||
* The signature is mostly identical to that of Sabre_DAV_IFile, but the get() method
|
||||
* MUST return an xml document that matches the requirements of the
|
||||
* 'caldav-notifications.txt' spec.
|
||||
*
|
||||
* For a complete example, check out the Notification class, which contains
|
||||
* some helper functions.
|
||||
*
|
||||
* @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_Notifications_INode {
|
||||
|
||||
/**
|
||||
* This method must return an xml element, using the
|
||||
* Sabre_CalDAV_Notifications_INotificationType classes.
|
||||
*
|
||||
* @return Sabre_DAVNotification_INotificationType
|
||||
*/
|
||||
function getNotificationType();
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This interface reflects a single notification type.
|
||||
*
|
||||
* @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_Notifications_INotificationType extends Sabre_DAV_PropertyInterface {
|
||||
|
||||
/**
|
||||
* Serializes the notification as a single property.
|
||||
*
|
||||
* You should usually just encode the single top-level element of the
|
||||
* notification.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
function serialize(Sabre_DAV_Server $server, \DOMElement $node);
|
||||
|
||||
/**
|
||||
* This method serializes the entire notification, as it is used in the
|
||||
* response body.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
function serializeBody(Sabre_DAV_Server $server, \DOMElement $node);
|
||||
|
||||
/**
|
||||
* Returns a unique id for this notification
|
||||
*
|
||||
* This is just the base url. This should generally be some kind of unique
|
||||
* id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getId();
|
||||
|
||||
}
|
68
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Node.php
Normal file
68
dav/SabreDAV/lib/Sabre/CalDAV/Notifications/Node.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This node represents a single notification.
|
||||
*
|
||||
* The signature is mostly identical to that of Sabre_DAV_IFile, but the get() method
|
||||
* MUST return an xml document that matches the requirements of the
|
||||
* 'caldav-notifications.txt' spec.
|
||||
|
||||
* @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_Notifications_Node extends Sabre_DAV_Node implements Sabre_CalDAV_Notifications_INode {
|
||||
|
||||
/**
|
||||
* The notification backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_NotificationSupport
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
/**
|
||||
* The actual notification
|
||||
*
|
||||
* @var Sabre_CalDAV_Notifications_INotificationType
|
||||
*/
|
||||
protected $notification;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Sabre_CalDAV_Backend_NotificationSupport $caldavBackend
|
||||
* @param Sabre_CalDAV_Notifications_INotificationType $notification
|
||||
*/
|
||||
public function __construct(Sabre_CalDAV_Backend_NotificationSupport $caldavBackend, Sabre_CalDAV_Notifications_INotificationType $notification) {
|
||||
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
$this->notification = $notification;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path name for this notification
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public function getName() {
|
||||
|
||||
return $this->notification->getId();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must return an xml element, using the
|
||||
* Sabre_CalDAV_Notifications_INotificationType classes.
|
||||
*
|
||||
* @return Sabre_DAVNotification_INotificationType
|
||||
*/
|
||||
public function getNotificationType() {
|
||||
|
||||
return $this->notification;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SystemStatus notification
|
||||
*
|
||||
* This notification can be used to indicate to the user that the system is
|
||||
* down.
|
||||
*
|
||||
* @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_Notifications_Notification_SystemStatus extends Sabre_DAV_Property implements Sabre_CalDAV_Notifications_INotificationType {
|
||||
|
||||
const TYPE_LOW = 1;
|
||||
const TYPE_MEDIUM = 2;
|
||||
const TYPE_HIGH = 3;
|
||||
|
||||
/**
|
||||
* A unique id
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The type of alert. This should be one of the TYPE_ constants.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* A human-readable description of the problem.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* A url to a website with more information for the user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $href;
|
||||
|
||||
/**
|
||||
* Creates the notification.
|
||||
*
|
||||
* Some kind of unique id should be provided. This is used to generate a
|
||||
* url.
|
||||
*
|
||||
* @param string $id
|
||||
* @param int $type
|
||||
* @param string $description
|
||||
* @param string $href
|
||||
*/
|
||||
public function __construct($id, $type = self::TYPE_HIGH, $description = null, $href = null) {
|
||||
|
||||
$this->id = $id;
|
||||
$this->type = $type;
|
||||
$this->description = $description;
|
||||
$this->href = $href;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the notification as a single property.
|
||||
*
|
||||
* You should usually just encode the single top-level element of the
|
||||
* notification.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serialize(Sabre_DAV_Server $server, \DOMElement $node) {
|
||||
|
||||
switch($this->type) {
|
||||
case self::TYPE_LOW :
|
||||
$type = 'low';
|
||||
break;
|
||||
case self::TYPE_MEDIUM :
|
||||
$type = 'medium';
|
||||
break;
|
||||
default :
|
||||
case self::TYPE_HIGH :
|
||||
$type = 'high';
|
||||
break;
|
||||
}
|
||||
|
||||
$prop = $node->ownerDocument->createElement('cs:systemstatus');
|
||||
$prop->setAttribute('type', $type);
|
||||
|
||||
$node->appendChild($prop);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the entire notification, as it is used in the
|
||||
* response body.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param DOMElement $node
|
||||
* @return void
|
||||
*/
|
||||
public function serializeBody(Sabre_DAV_Server $server, \DOMElement $node) {
|
||||
|
||||
switch($this->type) {
|
||||
case self::TYPE_LOW :
|
||||
$type = 'low';
|
||||
break;
|
||||
case self::TYPE_MEDIUM :
|
||||
$type = 'medium';
|
||||
break;
|
||||
default :
|
||||
case self::TYPE_HIGH :
|
||||
$type = 'high';
|
||||
break;
|
||||
}
|
||||
|
||||
$prop = $node->ownerDocument->createElement('cs:systemstatus');
|
||||
$prop->setAttribute('type', $type);
|
||||
|
||||
if ($this->description) {
|
||||
$text = $node->ownerDocument->createTextNode($this->description);
|
||||
$desc = $node->ownerDocument->createElement('cs:description');
|
||||
$desc->appendChild($text);
|
||||
$prop->appendChild($desc);
|
||||
}
|
||||
if ($this->href) {
|
||||
$text = $node->ownerDocument->createTextNode($this->href);
|
||||
$href = $node->ownerDocument->createElement('d:href');
|
||||
$href->appendChild($text);
|
||||
$prop->appendChild($href);
|
||||
}
|
||||
|
||||
$node->appendChild($prop);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique id for this notification
|
||||
*
|
||||
* This is just the base url. This should generally be some kind of unique
|
||||
* id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId() {
|
||||
|
||||
return $this->id;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -162,6 +162,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction'));
|
||||
$server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent'));
|
||||
$server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile'));
|
||||
$server->subscribeEvent('beforeMethod', array($this,'beforeMethod'));
|
||||
|
||||
$server->xmlNamespaces[self::NS_CALDAV] = 'cal';
|
||||
$server->xmlNamespaces[self::NS_CALENDARSERVER] = 'cs';
|
||||
|
@ -172,6 +173,8 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$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';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Notifications_ICollection'] = '{' . self::NS_CALENDARSERVER . '}notifications';
|
||||
$server->resourceTypeMapping['Sabre_CalDAV_Notifications_INode'] = '{' . self::NS_CALENDARSERVER . '}notification';
|
||||
|
||||
array_push($server->protectedProperties,
|
||||
|
||||
|
@ -195,7 +198,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
// CalendarServer extensions
|
||||
'{' . self::NS_CALENDARSERVER . '}getctag',
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for',
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for'
|
||||
'{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for',
|
||||
'{' . self::NS_CALENDARSERVER . '}notification-URL',
|
||||
'{' . self::NS_CALENDARSERVER . '}notificationtype'
|
||||
|
||||
);
|
||||
}
|
||||
|
@ -380,8 +385,31 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
}
|
||||
|
||||
// notification-URL property
|
||||
$notificationUrl = '{' . self::NS_CALENDARSERVER . '}notification-URL';
|
||||
if (($index = array_search($notificationUrl, $requestedProperties)) !== false) {
|
||||
$principalId = $node->getName();
|
||||
$calendarHomePath = 'calendars/' . $principalId . '/notifications/';
|
||||
unset($requestedProperties[$index]);
|
||||
$returnedProperties[200][$notificationUrl] = new Sabre_DAV_Property_Href($calendarHomePath);
|
||||
}
|
||||
|
||||
} // instanceof IPrincipal
|
||||
|
||||
if ($node instanceof Sabre_CalDAV_Notifications_INode) {
|
||||
|
||||
$propertyName = '{' . self::NS_CALENDARSERVER . '}notificationtype';
|
||||
if (($index = array_search($propertyName, $requestedProperties)) !== false) {
|
||||
|
||||
$returnedProperties[200][$propertyName] =
|
||||
$node->getNotificationType();
|
||||
|
||||
unset($requestedProperties[$index]);
|
||||
|
||||
}
|
||||
|
||||
} // instanceof Notifications_INode
|
||||
|
||||
|
||||
if ($node instanceof Sabre_CalDAV_ICalendarObject) {
|
||||
// The calendar-data property is not supposed to be a 'real'
|
||||
|
@ -648,7 +676,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
if (!$node instanceof Sabre_CalDAV_ICalendarObject)
|
||||
return;
|
||||
|
||||
$this->validateICalendar($data);
|
||||
$this->validateICalendar($data, $path);
|
||||
|
||||
}
|
||||
|
||||
|
@ -668,7 +696,49 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
if (!$parentNode instanceof Sabre_CalDAV_Calendar)
|
||||
return;
|
||||
|
||||
$this->validateICalendar($data);
|
||||
$this->validateICalendar($data, $path);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is triggered before any HTTP request is handled.
|
||||
*
|
||||
* We use this to intercept GET calls to notification nodes, and return the
|
||||
* proper response.
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function beforeMethod($method, $path) {
|
||||
|
||||
if ($method!=='GET') return;
|
||||
|
||||
try {
|
||||
$node = $this->server->tree->getNodeForPath($path);
|
||||
} catch (Sabre_DAV_Exception_NotFound $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node instanceof Sabre_CalDAV_Notifications_INode)
|
||||
return;
|
||||
|
||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
|
||||
$root = $dom->createElement('cs:notification');
|
||||
foreach($this->server->xmlNamespaces as $namespace => $prefix) {
|
||||
$root->setAttribute('xmlns:' . $prefix, $namespace);
|
||||
}
|
||||
|
||||
$dom->appendChild($root);
|
||||
$node->getNotificationType()->serializeBody($this->server, $root);
|
||||
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml');
|
||||
$this->server->httpResponse->sendStatus(200);
|
||||
$this->server->httpResponse->sendBody($dom->saveXML());
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
@ -678,9 +748,10 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
* An exception is thrown if it's not.
|
||||
*
|
||||
* @param resource|string $data
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
protected function validateICalendar(&$data) {
|
||||
protected function validateICalendar(&$data, $path) {
|
||||
|
||||
// If it's a stream, we convert it to a string first.
|
||||
if (is_resource($data)) {
|
||||
|
@ -704,6 +775,11 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
throw new Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support iCalendar objects.');
|
||||
}
|
||||
|
||||
// Get the Supported Components for the target calendar
|
||||
list($parentPath,$object) = Sabre_Dav_URLUtil::splitPath($path);
|
||||
$calendarProperties = $this->server->getProperties($parentPath,array('{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'));
|
||||
$supportedComponents = $calendarProperties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue();
|
||||
|
||||
$foundType = null;
|
||||
$foundUID = null;
|
||||
foreach($vobj->getComponents() as $component) {
|
||||
|
@ -715,6 +791,9 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
case 'VJOURNAL' :
|
||||
if (is_null($foundType)) {
|
||||
$foundType = $component->name;
|
||||
if (!in_array($foundType, $supportedComponents)) {
|
||||
throw new Sabre_CalDAV_Exception_InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType);
|
||||
}
|
||||
if (!isset($component->UID)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Every ' . $component->name . ' component must have an UID');
|
||||
}
|
||||
|
@ -756,7 +835,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
throw new Sabre_DAV_Exception_BadRequest('The Recipient: header must be specified when making POST requests');
|
||||
}
|
||||
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/', $originator)) {
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/i', $originator)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Originator must start with mailto: and must be valid email address');
|
||||
}
|
||||
$originator = substr($originator,7);
|
||||
|
@ -765,7 +844,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
foreach($recipients as $k=>$recipient) {
|
||||
|
||||
$recipient = trim($recipient);
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/', $recipient)) {
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/i', $recipient)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Recipients must start with mailto: and must be valid email address');
|
||||
}
|
||||
$recipient = substr($recipient, 7);
|
||||
|
@ -813,9 +892,10 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
}
|
||||
|
||||
if (in_array($method, array('REQUEST','REPLY','ADD','CANCEL')) && $componentType==='VEVENT') {
|
||||
$this->iMIPMessage($originator, $recipients, $vObject, $principal);
|
||||
$result = $this->iMIPMessage($originator, $recipients, $vObject, $principal);
|
||||
$this->server->httpResponse->sendStatus(200);
|
||||
$this->server->httpResponse->sendBody('Messages sent');
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml');
|
||||
$this->server->httpResponse->sendBody($this->generateScheduleResponse($result));
|
||||
} else {
|
||||
throw new Sabre_DAV_Exception_NotImplemented('This iTIP method is currently not implemented');
|
||||
}
|
||||
|
@ -825,18 +905,81 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
/**
|
||||
* Sends an iMIP message by email.
|
||||
*
|
||||
* This method must return an array with status codes per recipient.
|
||||
* This should look something like:
|
||||
*
|
||||
* array(
|
||||
* 'user1@example.org' => '2.0;Success'
|
||||
* )
|
||||
*
|
||||
* Formatting for this status code can be found at:
|
||||
* https://tools.ietf.org/html/rfc5545#section-3.8.8.3
|
||||
*
|
||||
* A list of valid status codes can be found at:
|
||||
* https://tools.ietf.org/html/rfc5546#section-3.6
|
||||
*
|
||||
* @param string $originator
|
||||
* @param array $recipients
|
||||
* @param Sabre_VObject_Component $vObject
|
||||
* @param string $principal Principal url
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
protected function iMIPMessage($originator, array $recipients, Sabre_VObject_Component $vObject, $principal) {
|
||||
|
||||
if (!$this->imipHandler) {
|
||||
throw new Sabre_DAV_Exception_NotImplemented('No iMIP handler is setup on this server.');
|
||||
$resultStatus = '5.2;This server does not support this operation';
|
||||
} else {
|
||||
$this->imipHandler->sendMessage($originator, $recipients, $vObject, $principal);
|
||||
$resultStatus = '2.0;Success';
|
||||
}
|
||||
$this->imipHandler->sendMessage($originator, $recipients, $vObject, $principal);
|
||||
|
||||
$result = array();
|
||||
foreach($recipients as $recipient) {
|
||||
$result[$recipient] = $resultStatus;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a schedule-response XML body
|
||||
*
|
||||
* The recipients array is a key->value list, containing email addresses
|
||||
* and iTip status codes. See the iMIPMessage method for a description of
|
||||
* the value.
|
||||
*
|
||||
* @param array $recipients
|
||||
* @return string
|
||||
*/
|
||||
public function generateScheduleResponse(array $recipients) {
|
||||
|
||||
$dom = new DOMDocument('1.0','utf-8');
|
||||
$dom->formatOutput = true;
|
||||
$xscheduleResponse = $dom->createElement('cal:schedule-response');
|
||||
$dom->appendChild($xscheduleResponse);
|
||||
|
||||
foreach($this->server->xmlNamespaces as $namespace=>$prefix) {
|
||||
|
||||
$xscheduleResponse->setAttribute('xmlns:' . $prefix, $namespace);
|
||||
|
||||
}
|
||||
|
||||
foreach($recipients as $recipient=>$status) {
|
||||
$xresponse = $dom->createElement('cal:response');
|
||||
|
||||
$xrecipient = $dom->createElement('cal:recipient');
|
||||
$xrecipient->appendChild($dom->createTextNode($recipient));
|
||||
$xresponse->appendChild($xrecipient);
|
||||
|
||||
$xrequestStatus = $dom->createElement('cal:request-status');
|
||||
$xrequestStatus->appendChild($dom->createTextNode($status));
|
||||
$xresponse->appendChild($xrequestStatus);
|
||||
|
||||
$xscheduleResponse->appendChild($xresponse);
|
||||
|
||||
}
|
||||
|
||||
return $dom->saveXML();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
|
|||
/**
|
||||
* CalDAV backend
|
||||
*
|
||||
* @var Sabre_CalDAV_Backend_Abstract
|
||||
* @var Sabre_CalDAV_Backend_BackendInterface
|
||||
*/
|
||||
protected $caldavBackend;
|
||||
|
||||
|
@ -36,10 +36,10 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
|
|||
* Constructor
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param Sabre_CalDAV_Backend_Abstract $caldavBackend
|
||||
* @param Sabre_CalDAV_Backend_BackendInterface $caldavBackend
|
||||
* @param mixed $userUri
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_Abstract $caldavBackend, $userUri) {
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, Sabre_CalDAV_Backend_BackendInterface $caldavBackend, $userUri) {
|
||||
|
||||
$this->principalBackend = $principalBackend;
|
||||
$this->caldavBackend = $caldavBackend;
|
||||
|
@ -171,6 +171,11 @@ class Sabre_CalDAV_UserCalendars implements Sabre_DAV_IExtendedCollection, Sabre
|
|||
$objs[] = new Sabre_CalDAV_Calendar($this->principalBackend, $this->caldavBackend, $calendar);
|
||||
}
|
||||
$objs[] = new Sabre_CalDAV_Schedule_Outbox($this->principalInfo['uri']);
|
||||
|
||||
// We're adding a notifications node, if it's supported by the backend.
|
||||
if ($this->caldavBackend instanceof Sabre_CalDAV_Backend_NotificationSupport) {
|
||||
$objs[] = new Sabre_CalDAV_Notifications_Collection($this->caldavBackend, $this->principalInfo['uri']);
|
||||
}
|
||||
return $objs;
|
||||
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ class Sabre_CardDAV_Backend_PDO extends Sabre_CardDAV_Backend_Abstract {
|
|||
* 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 getCards method.
|
||||
* 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.
|
||||
|
|
|
@ -358,6 +358,10 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
throw new Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support vcard objects.');
|
||||
}
|
||||
|
||||
if (!isset($vobj->UID)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Every vcard must have an UID.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -440,6 +444,8 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
$vcard = Sabre_VObject_Reader::read($vcardData);
|
||||
|
||||
if (!$filters) return true;
|
||||
|
||||
foreach($filters as $filter) {
|
||||
|
||||
$isDefined = isset($vcard->{$filter['name']});
|
||||
|
|
|
@ -293,7 +293,10 @@ class Sabre_DAV_Locks_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$this->server->tree->getNodeForPath($uri);
|
||||
|
||||
// We need to call the beforeWriteContent event for RFC3744
|
||||
$this->server->broadcastEvent('beforeWriteContent',array($uri));
|
||||
// Edit: looks like this is not used, and causing problems now.
|
||||
//
|
||||
// See Issue 222
|
||||
// $this->server->broadcastEvent('beforeWriteContent',array($uri));
|
||||
|
||||
} catch (Sabre_DAV_Exception_NotFound $e) {
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
abstract class Sabre_DAV_Property {
|
||||
abstract class Sabre_DAV_Property implements Sabre_DAV_PropertyInterface {
|
||||
|
||||
abstract function serialize(Sabre_DAV_Server $server, DOMElement $prop);
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ class Sabre_DAV_Property_Response extends Sabre_DAV_Property implements Sabre_DA
|
|||
if (is_scalar($propertyValue)) {
|
||||
$text = $document->createTextNode($propertyValue);
|
||||
$currentProperty->appendChild($text);
|
||||
} elseif ($propertyValue instanceof Sabre_DAV_Property) {
|
||||
} elseif ($propertyValue instanceof Sabre_DAV_PropertyInterface) {
|
||||
$propertyValue->serialize($server,$currentProperty);
|
||||
} elseif (!is_null($propertyValue)) {
|
||||
throw new Sabre_DAV_Exception('Unknown property value type: ' . gettype($propertyValue) . ' for property: ' . $propertyName);
|
||||
|
|
21
dav/SabreDAV/lib/Sabre/DAV/PropertyInterface.php
Normal file
21
dav/SabreDAV/lib/Sabre/DAV/PropertyInterface.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PropertyInterface
|
||||
*
|
||||
* Implement this interface to create new complex properties
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage DAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
interface Sabre_DAV_PropertyInterface {
|
||||
|
||||
public function serialize(Sabre_DAV_Server $server, DOMElement $prop);
|
||||
|
||||
static function unserialize(DOMElement $prop);
|
||||
|
||||
}
|
||||
|
|
@ -207,6 +207,10 @@ class Sabre_DAV_Server {
|
|||
|
||||
} catch (Exception $e) {
|
||||
|
||||
try {
|
||||
$this->broadcastEvent('exception', array($e));
|
||||
} catch (Exception $ignore) {
|
||||
}
|
||||
$DOM = new DOMDocument('1.0','utf-8');
|
||||
$DOM->formatOutput = true;
|
||||
|
||||
|
@ -508,7 +512,7 @@ class Sabre_DAV_Server {
|
|||
|
||||
if (!$this->checkPreconditions(true)) return false;
|
||||
|
||||
if (!($node instanceof Sabre_DAV_IFile)) throw new Sabre_DAV_Exception_NotImplemented('GET is only implemented on File objects');
|
||||
if (!$node instanceof Sabre_DAV_IFile) throw new Sabre_DAV_Exception_NotImplemented('GET is only implemented on File objects');
|
||||
$body = $node->get();
|
||||
|
||||
// Converting string into stream, if needed.
|
||||
|
|
|
@ -42,9 +42,9 @@ class Sabre_DAV_Tree_Filesystem extends Sabre_DAV_Tree {
|
|||
$realPath = $this->getRealPath($path);
|
||||
if (!file_exists($realPath)) throw new Sabre_DAV_Exception_NotFound('File at location ' . $realPath . ' not found');
|
||||
if (is_dir($realPath)) {
|
||||
return new Sabre_DAV_FS_Directory($path);
|
||||
return new Sabre_DAV_FS_Directory($realPath);
|
||||
} else {
|
||||
return new Sabre_DAV_FS_File($path);
|
||||
return new Sabre_DAV_FS_File($realPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
52
dav/SabreDAV/lib/Sabre/VObject/Property/DateTime.php
Executable file → Normal file
52
dav/SabreDAV/lib/Sabre/VObject/Property/DateTime.php
Executable file → Normal file
|
@ -204,49 +204,17 @@ class Sabre_VObject_Property_DateTime extends Sabre_VObject_Property {
|
|||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// tzid an Olson identifier?
|
||||
$tz = new DateTimeZone($tzid->value);
|
||||
} catch (Exception $e) {
|
||||
|
||||
// Not an Olson id, we're going to try to find the information
|
||||
// through the time zone name map.
|
||||
$newtzid = Sabre_VObject_WindowsTimezoneMap::lookup($tzid->value);
|
||||
if (is_null($newtzid)) {
|
||||
|
||||
// Not a well known time zone name either, we're going to try
|
||||
// to find the information through the VTIMEZONE object.
|
||||
|
||||
// First we find the root object
|
||||
$root = $property;
|
||||
while($root->parent) {
|
||||
$root = $root->parent;
|
||||
}
|
||||
|
||||
if (isset($root->VTIMEZONE)) {
|
||||
foreach($root->VTIMEZONE as $vtimezone) {
|
||||
if (((string)$vtimezone->TZID) == $tzid) {
|
||||
if (isset($vtimezone->{'X-LIC-LOCATION'})) {
|
||||
$newtzid = (string)$vtimezone->{'X-LIC-LOCATION'};
|
||||
} else {
|
||||
// No libical location specified. As a last resort we could
|
||||
// try matching $vtimezone's DST rules against all known
|
||||
// time zones returned by DateTimeZone::list*
|
||||
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$tz = new DateTimeZone($newtzid);
|
||||
} catch (Exception $e) {
|
||||
// If all else fails, we use the default PHP timezone
|
||||
$tz = new DateTimeZone(date_default_timezone_get());
|
||||
}
|
||||
// To look up the timezone, we must first find the VCALENDAR component.
|
||||
$root = $property;
|
||||
while($root->parent) {
|
||||
$root = $root->parent;
|
||||
}
|
||||
if ($root->name === 'VCALENDAR') {
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone((string)$tzid, $root);
|
||||
} else {
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone((string)$tzid);
|
||||
}
|
||||
|
||||
$dt = new DateTime($dateStr, $tz);
|
||||
$dt->setTimeZone($tz);
|
||||
|
||||
|
|
351
dav/SabreDAV/lib/Sabre/VObject/TimeZoneUtil.php
Normal file
351
dav/SabreDAV/lib/Sabre/VObject/TimeZoneUtil.php
Normal file
|
@ -0,0 +1,351 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Time zone name translation
|
||||
*
|
||||
* This file translates well-known time zone names into "Olson database" time zone names.
|
||||
*
|
||||
* @package Sabre
|
||||
* @subpackage VObject
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Frank Edelhaeuser (fedel@users.sourceforge.net)
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_VObject_TimeZoneUtil {
|
||||
|
||||
public static $map = array(
|
||||
|
||||
// from http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html
|
||||
// snapshot taken on 2012/01/16
|
||||
|
||||
// windows
|
||||
'AUS Central Standard Time'=>'Australia/Darwin',
|
||||
'AUS Eastern Standard Time'=>'Australia/Sydney',
|
||||
'Afghanistan Standard Time'=>'Asia/Kabul',
|
||||
'Alaskan Standard Time'=>'America/Anchorage',
|
||||
'Arab Standard Time'=>'Asia/Riyadh',
|
||||
'Arabian Standard Time'=>'Asia/Dubai',
|
||||
'Arabic Standard Time'=>'Asia/Baghdad',
|
||||
'Argentina Standard Time'=>'America/Buenos_Aires',
|
||||
'Armenian Standard Time'=>'Asia/Yerevan',
|
||||
'Atlantic Standard Time'=>'America/Halifax',
|
||||
'Azerbaijan Standard Time'=>'Asia/Baku',
|
||||
'Azores Standard Time'=>'Atlantic/Azores',
|
||||
'Bangladesh Standard Time'=>'Asia/Dhaka',
|
||||
'Canada Central Standard Time'=>'America/Regina',
|
||||
'Cape Verde Standard Time'=>'Atlantic/Cape_Verde',
|
||||
'Caucasus Standard Time'=>'Asia/Yerevan',
|
||||
'Cen. Australia Standard Time'=>'Australia/Adelaide',
|
||||
'Central America Standard Time'=>'America/Guatemala',
|
||||
'Central Asia Standard Time'=>'Asia/Almaty',
|
||||
'Central Brazilian Standard Time'=>'America/Cuiaba',
|
||||
'Central Europe Standard Time'=>'Europe/Budapest',
|
||||
'Central European Standard Time'=>'Europe/Warsaw',
|
||||
'Central Pacific Standard Time'=>'Pacific/Guadalcanal',
|
||||
'Central Standard Time'=>'America/Chicago',
|
||||
'Central Standard Time (Mexico)'=>'America/Mexico_City',
|
||||
'China Standard Time'=>'Asia/Shanghai',
|
||||
'Dateline Standard Time'=>'Etc/GMT+12',
|
||||
'E. Africa Standard Time'=>'Africa/Nairobi',
|
||||
'E. Australia Standard Time'=>'Australia/Brisbane',
|
||||
'E. Europe Standard Time'=>'Europe/Minsk',
|
||||
'E. South America Standard Time'=>'America/Sao_Paulo',
|
||||
'Eastern Standard Time'=>'America/New_York',
|
||||
'Egypt Standard Time'=>'Africa/Cairo',
|
||||
'Ekaterinburg Standard Time'=>'Asia/Yekaterinburg',
|
||||
'FLE Standard Time'=>'Europe/Kiev',
|
||||
'Fiji Standard Time'=>'Pacific/Fiji',
|
||||
'GMT Standard Time'=>'Europe/London',
|
||||
'GTB Standard Time'=>'Europe/Istanbul',
|
||||
'Georgian Standard Time'=>'Asia/Tbilisi',
|
||||
'Greenland Standard Time'=>'America/Godthab',
|
||||
'Greenwich Standard Time'=>'Atlantic/Reykjavik',
|
||||
'Hawaiian Standard Time'=>'Pacific/Honolulu',
|
||||
'India Standard Time'=>'Asia/Calcutta',
|
||||
'Iran Standard Time'=>'Asia/Tehran',
|
||||
'Israel Standard Time'=>'Asia/Jerusalem',
|
||||
'Jordan Standard Time'=>'Asia/Amman',
|
||||
'Kamchatka Standard Time'=>'Asia/Kamchatka',
|
||||
'Korea Standard Time'=>'Asia/Seoul',
|
||||
'Magadan Standard Time'=>'Asia/Magadan',
|
||||
'Mauritius Standard Time'=>'Indian/Mauritius',
|
||||
'Mexico Standard Time'=>'America/Mexico_City',
|
||||
'Mexico Standard Time 2'=>'America/Chihuahua',
|
||||
'Mid-Atlantic Standard Time'=>'Etc/GMT+2',
|
||||
'Middle East Standard Time'=>'Asia/Beirut',
|
||||
'Montevideo Standard Time'=>'America/Montevideo',
|
||||
'Morocco Standard Time'=>'Africa/Casablanca',
|
||||
'Mountain Standard Time'=>'America/Denver',
|
||||
'Mountain Standard Time (Mexico)'=>'America/Chihuahua',
|
||||
'Myanmar Standard Time'=>'Asia/Rangoon',
|
||||
'N. Central Asia Standard Time'=>'Asia/Novosibirsk',
|
||||
'Namibia Standard Time'=>'Africa/Windhoek',
|
||||
'Nepal Standard Time'=>'Asia/Katmandu',
|
||||
'New Zealand Standard Time'=>'Pacific/Auckland',
|
||||
'Newfoundland Standard Time'=>'America/St_Johns',
|
||||
'North Asia East Standard Time'=>'Asia/Irkutsk',
|
||||
'North Asia Standard Time'=>'Asia/Krasnoyarsk',
|
||||
'Pacific SA Standard Time'=>'America/Santiago',
|
||||
'Pacific Standard Time'=>'America/Los_Angeles',
|
||||
'Pacific Standard Time (Mexico)'=>'America/Santa_Isabel',
|
||||
'Pakistan Standard Time'=>'Asia/Karachi',
|
||||
'Paraguay Standard Time'=>'America/Asuncion',
|
||||
'Romance Standard Time'=>'Europe/Paris',
|
||||
'Russian Standard Time'=>'Europe/Moscow',
|
||||
'SA Eastern Standard Time'=>'America/Cayenne',
|
||||
'SA Pacific Standard Time'=>'America/Bogota',
|
||||
'SA Western Standard Time'=>'America/La_Paz',
|
||||
'SE Asia Standard Time'=>'Asia/Bangkok',
|
||||
'Samoa Standard Time'=>'Pacific/Apia',
|
||||
'Singapore Standard Time'=>'Asia/Singapore',
|
||||
'South Africa Standard Time'=>'Africa/Johannesburg',
|
||||
'Sri Lanka Standard Time'=>'Asia/Colombo',
|
||||
'Syria Standard Time'=>'Asia/Damascus',
|
||||
'Taipei Standard Time'=>'Asia/Taipei',
|
||||
'Tasmania Standard Time'=>'Australia/Hobart',
|
||||
'Tokyo Standard Time'=>'Asia/Tokyo',
|
||||
'Tonga Standard Time'=>'Pacific/Tongatapu',
|
||||
'US Eastern Standard Time'=>'America/Indianapolis',
|
||||
'US Mountain Standard Time'=>'America/Phoenix',
|
||||
'UTC'=>'Etc/GMT',
|
||||
'UTC+12'=>'Etc/GMT-12',
|
||||
'UTC-02'=>'Etc/GMT+2',
|
||||
'UTC-11'=>'Etc/GMT+11',
|
||||
'Ulaanbaatar Standard Time'=>'Asia/Ulaanbaatar',
|
||||
'Venezuela Standard Time'=>'America/Caracas',
|
||||
'Vladivostok Standard Time'=>'Asia/Vladivostok',
|
||||
'W. Australia Standard Time'=>'Australia/Perth',
|
||||
'W. Central Africa Standard Time'=>'Africa/Lagos',
|
||||
'W. Europe Standard Time'=>'Europe/Berlin',
|
||||
'West Asia Standard Time'=>'Asia/Tashkent',
|
||||
'West Pacific Standard Time'=>'Pacific/Port_Moresby',
|
||||
'Yakutsk Standard Time'=>'Asia/Yakutsk',
|
||||
|
||||
// Microsoft exchange timezones
|
||||
// Source:
|
||||
// http://msdn.microsoft.com/en-us/library/ms988620%28v=exchg.65%29.aspx
|
||||
//
|
||||
// Correct timezones deduced with help from:
|
||||
// http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
'Universal Coordinated Time' => 'UTC',
|
||||
'Casablanca, Monrovia' => 'Africa/Casablanca',
|
||||
'Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London' => 'Europe/Lisbon',
|
||||
'Greenwich Mean Time; Dublin, Edinburgh, London' => 'Europe/London',
|
||||
'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin',
|
||||
'Belgrade, Pozsony, Budapest, Ljubljana, Prague' => 'Europe/Prague',
|
||||
'Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris',
|
||||
'Paris, Madrid, Brussels, Copenhagen' => 'Europe/Paris',
|
||||
'Prague, Central Europe' => 'Europe/Prague',
|
||||
'Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb' => 'Europe/Sarajevo',
|
||||
'West Central Africa' => 'Africa/Luanda', // This was a best guess
|
||||
'Athens, Istanbul, Minsk' => 'Europe/Athens',
|
||||
'Bucharest' => 'Europe/Bucharest',
|
||||
'Cairo' => 'Africa/Cairo',
|
||||
'Harare, Pretoria' => 'Africa/Harare',
|
||||
'Helsinki, Riga, Tallinn' => 'Europe/Helsinki',
|
||||
'Israel, Jerusalem Standard Time' => 'Asia/Jerusalem',
|
||||
'Baghdad' => 'Asia/Baghdad',
|
||||
'Arab, Kuwait, Riyadh' => 'Asia/Kuwait',
|
||||
'Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow',
|
||||
'East Africa, Nairobi' => 'Africa/Nairobi',
|
||||
'Tehran' => 'Asia/Tehran',
|
||||
'Abu Dhabi, Muscat' => 'Asia/Muscat', // Best guess
|
||||
'Baku, Tbilisi, Yerevan' => 'Asia/Baku',
|
||||
'Kabul' => 'Asia/Kabul',
|
||||
'Ekaterinburg' => 'Asia/Yekaterinburg',
|
||||
'Islamabad, Karachi, Tashkent' => 'Asia/Karachi',
|
||||
'Kolkata, Chennai, Mumbai, New Delhi, India Standard Time' => 'Asia/Calcutta',
|
||||
'Kathmandu, Nepal' => 'Asia/Kathmandu',
|
||||
'Almaty, Novosibirsk, North Central Asia' => 'Asia/Almaty',
|
||||
'Astana, Dhaka' => 'Asia/Dhaka',
|
||||
'Sri Jayawardenepura, Sri Lanka' => 'Asia/Colombo',
|
||||
'Rangoon' => 'Asia/Rangoon',
|
||||
'Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok',
|
||||
'Krasnoyarsk' => 'Asia/Krasnoyarsk',
|
||||
'Beijing, Chongqing, Hong Kong SAR, Urumqi' => 'Asia/Shanghai',
|
||||
'Irkutsk, Ulaan Bataar' => 'Asia/Irkutsk',
|
||||
'Kuala Lumpur, Singapore' => 'Asia/Singapore',
|
||||
'Perth, Western Australia' => 'Australia/Perth',
|
||||
'Taipei' => 'Asia/Taipei',
|
||||
'Osaka, Sapporo, Tokyo' => 'Asia/Tokyo',
|
||||
'Seoul, Korea Standard time' => 'Asia/Seoul',
|
||||
'Yakutsk' => 'Asia/Yakutsk',
|
||||
'Adelaide, Central Australia' => 'Australia/Adelaide',
|
||||
'Darwin' => 'Australia/Darwin',
|
||||
'Brisbane, East Australia' => 'Australia/Brisbane',
|
||||
'Canberra, Melbourne, Sydney, Hobart (year 2000 only)' => 'Australia/Sydney',
|
||||
'Guam, Port Moresby' => 'Pacific/Guam',
|
||||
'Hobart, Tasmania' => 'Australia/Hobart',
|
||||
'Vladivostok' => 'Asia/Vladivostok',
|
||||
'Magadan, Solomon Is., New Caledonia' => 'Asia/Magadan',
|
||||
'Auckland, Wellington' => 'Pacific/Auckland',
|
||||
'Fiji Islands, Kamchatka, Marshall Is.' => 'Pacific/Fiji',
|
||||
'Nuku\'alofa, Tonga' => 'Pacific/Tongatapu',
|
||||
'Azores' => 'Atlantic/Azores',
|
||||
'Cape Verde Is.' => 'Atlantic/Cape_Verde',
|
||||
'Mid-Atlantic' => 'America/Noronha',
|
||||
'Brasilia' => 'America/Sao_Paulo', // Best guess
|
||||
'Buenos Aires' => 'America/Argentina/Buenos_Aires',
|
||||
'Greenland' => 'America/Godthab',
|
||||
'Newfoundland' => 'America/St_Johns',
|
||||
'Atlantic Time (Canada)' => 'America/Halifax',
|
||||
'Caracas, La Paz' => 'America/Caracas',
|
||||
'Santiago' => 'America/Santiago',
|
||||
'Bogota, Lima, Quito' => 'America/Bogota',
|
||||
'Eastern Time (US & Canada)' => 'America/New_York',
|
||||
'Indiana (East)' => 'America/Indiana/Indianapolis',
|
||||
'Central America' => 'America/Guatemala',
|
||||
'Central Time (US & Canada)' => 'America/Chicago',
|
||||
'Mexico City, Tegucigalpa' => 'America/Mexico_City',
|
||||
'Saskatchewan' => 'America/Edmonton',
|
||||
'Arizona' => 'America/Phoenix',
|
||||
'Mountain Time (US & Canada)' => 'America/Denver', // Best guess
|
||||
'Pacific Time (US & Canada); Tijuana' => 'America/Los_Angeles', // Best guess
|
||||
'Alaska' => 'America/Anchorage',
|
||||
'Hawaii' => 'Pacific/Honolulu',
|
||||
'Midway Island, Samoa' => 'Pacific/Midway',
|
||||
'Eniwetok, Kwajalein, Dateline Time' => 'Pacific/Kwajalein',
|
||||
|
||||
);
|
||||
|
||||
public static $microsoftExchangeMap = array(
|
||||
0 => 'UTC',
|
||||
31 => 'Africa/Casablanca',
|
||||
2 => 'Europe/Lisbon',
|
||||
1 => 'Europe/London',
|
||||
4 => 'Europe/Berlin',
|
||||
6 => 'Europe/Prague',
|
||||
3 => 'Europe/Paris',
|
||||
69 => 'Africa/Luanda', // This was a best guess
|
||||
7 => 'Europe/Athens',
|
||||
5 => 'Europe/Bucharest',
|
||||
49 => 'Africa/Cairo',
|
||||
50 => 'Africa/Harare',
|
||||
59 => 'Europe/Helsinki',
|
||||
27 => 'Asia/Jerusalem',
|
||||
26 => 'Asia/Baghdad',
|
||||
74 => 'Asia/Kuwait',
|
||||
51 => 'Europe/Moscow',
|
||||
56 => 'Africa/Nairobi',
|
||||
25 => 'Asia/Tehran',
|
||||
24 => 'Asia/Muscat', // Best guess
|
||||
54 => 'Asia/Baku',
|
||||
48 => 'Asia/Kabul',
|
||||
58 => 'Asia/Yekaterinburg',
|
||||
47 => 'Asia/Karachi',
|
||||
23 => 'Asia/Calcutta',
|
||||
62 => 'Asia/Kathmandu',
|
||||
46 => 'Asia/Almaty',
|
||||
71 => 'Asia/Dhaka',
|
||||
66 => 'Asia/Colombo',
|
||||
61 => 'Asia/Rangoon',
|
||||
22 => 'Asia/Bangkok',
|
||||
64 => 'Asia/Krasnoyarsk',
|
||||
45 => 'Asia/Shanghai',
|
||||
63 => 'Asia/Irkutsk',
|
||||
21 => 'Asia/Singapore',
|
||||
73 => 'Australia/Perth',
|
||||
75 => 'Asia/Taipei',
|
||||
20 => 'Asia/Tokyo',
|
||||
72 => 'Asia/Seoul',
|
||||
70 => 'Asia/Yakutsk',
|
||||
19 => 'Australia/Adelaide',
|
||||
44 => 'Australia/Darwin',
|
||||
18 => 'Australia/Brisbane',
|
||||
76 => 'Australia/Sydney',
|
||||
43 => 'Pacific/Guam',
|
||||
42 => 'Australia/Hobart',
|
||||
68 => 'Asia/Vladivostok',
|
||||
41 => 'Asia/Magadan',
|
||||
17 => 'Pacific/Auckland',
|
||||
40 => 'Pacific/Fiji',
|
||||
67 => 'Pacific/Tongatapu',
|
||||
29 => 'Atlantic/Azores',
|
||||
53 => 'Atlantic/Cape_Verde',
|
||||
30 => 'America/Noronha',
|
||||
8 => 'America/Sao_Paulo', // Best guess
|
||||
32 => 'America/Argentina/Buenos_Aires',
|
||||
69 => 'America/Godthab',
|
||||
28 => 'America/St_Johns',
|
||||
9 => 'America/Halifax',
|
||||
33 => 'America/Caracas',
|
||||
65 => 'America/Santiago',
|
||||
35 => 'America/Bogota',
|
||||
10 => 'America/New_York',
|
||||
34 => 'America/Indiana/Indianapolis',
|
||||
55 => 'America/Guatemala',
|
||||
11 => 'America/Chicago',
|
||||
37 => 'America/Mexico_City',
|
||||
36 => 'America/Edmonton',
|
||||
38 => 'America/Phoenix',
|
||||
12 => 'America/Denver', // Best guess
|
||||
13 => 'America/Los_Angeles', // Best guess
|
||||
14 => 'America/Anchorage',
|
||||
15 => 'Pacific/Honolulu',
|
||||
16 => 'Pacific/Midway',
|
||||
39 => 'Pacific/Kwajalein',
|
||||
);
|
||||
|
||||
/**
|
||||
* This method will try to find out the correct timezone for an iCalendar
|
||||
* date-time value.
|
||||
*
|
||||
* You must pass the contents of the TZID parameter, as well as the full
|
||||
* calendar.
|
||||
*
|
||||
* If the lookup fails, this method will return UTC.
|
||||
*
|
||||
* @param string $tzid
|
||||
* @param Sabre_VObject_Component $vcalendar
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
static public function getTimeZone($tzid, Sabre_VObject_Component $vcalendar = null) {
|
||||
|
||||
// First we will just see if the tzid is a support timezone identifier.
|
||||
try {
|
||||
return new DateTimeZone($tzid);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
// Next, we check if the tzid is somewhere in our tzid map.
|
||||
if (isset(self::$map[$tzid])) {
|
||||
return new DateTimeZone(self::$map[$tzid]);
|
||||
}
|
||||
|
||||
if ($vcalendar) {
|
||||
|
||||
// If that didn't work, we will scan VTIMEZONE objects
|
||||
foreach($vcalendar->select('VTIMEZONE') as $vtimezone) {
|
||||
|
||||
if ((string)$vtimezone->TZID === $tzid) {
|
||||
|
||||
// Some clients add 'X-LIC-LOCATION' with the olson name.
|
||||
if (isset($vtimezone->{'X-LIC-LOCATION'})) {
|
||||
try {
|
||||
return new DateTimeZone($vtimezone->{'X-LIC-LOCATION'});
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
}
|
||||
// Microsoft may add a magic number, which we also have an
|
||||
// answer for.
|
||||
if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
|
||||
if (isset(self::$microsoftExchangeMap[(int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value])) {
|
||||
return new DateTimeZone(self::$microsoftExchangeMap[(int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If we got all the way here, we default to UTC.
|
||||
return new DateTimeZone(date_default_timezone_get());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -24,8 +24,8 @@ include __DIR__ . '/Parameter.php';
|
|||
include __DIR__ . '/ParseException.php';
|
||||
include __DIR__ . '/Reader.php';
|
||||
include __DIR__ . '/RecurrenceIterator.php';
|
||||
include __DIR__ . '/TimeZoneUtil.php';
|
||||
include __DIR__ . '/Version.php';
|
||||
include __DIR__ . '/WindowsTimezoneMap.php';
|
||||
include __DIR__ . '/Element.php';
|
||||
include __DIR__ . '/Property.php';
|
||||
include __DIR__ . '/Component.php';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue