forked from friendica/friendica-addons
Merge remote branch 'upstream/master'
This commit is contained in:
commit
47396b1d28
145 changed files with 8731 additions and 14229 deletions
|
@ -1,3 +1,11 @@
|
|||
v0.2.0
|
||||
======
|
||||
[FEATURE] Multiple private Calendars can be created. Each calendar can have its own default color; single events of a calendar can override this setting.
|
||||
[FEATURE] Support for recurring events.
|
||||
[FEATURE] ICS files can be imported to and exported from a calendar.
|
||||
[FEATURE] Notification by e-mail is supported.
|
||||
[COMPATIBILITY] When creating or updating an event using CalDAV, the etag is returned.
|
||||
|
||||
v0.1.1
|
||||
======
|
||||
[FEATURE] A "New Event" Button in the navigation bar of the calendar is added.
|
||||
|
@ -5,6 +13,6 @@ v0.1.1
|
|||
[BUGFIX] When editing a event, the start time cannot be set befor the end time anymore.
|
||||
[BUGFIX] Fixed some problems with Magic Quotes
|
||||
|
||||
v0.1
|
||||
v0.1.0
|
||||
======
|
||||
Initial Release
|
|
@ -6,10 +6,15 @@ It's still in a very early stage, so expect major bugs. Please feel free to repo
|
|||
At the moment, the calendar system supports the following features:
|
||||
- A web-based drag&drop interface for managing events
|
||||
- All-Day-Events, Multi-Day-Events, and time-based events
|
||||
- Access to the events using CalDAV (using iPhone, Thunderbird Lightning etc., see below)
|
||||
- read-only access to the friendica-native events (also using CalDAV)
|
||||
- The friendica-contacts are made available using CardDAV (confirmed to work with iOS)
|
||||
- Giving the subject, a description, a location and a color for the event (the color is not available through CalDAV, though)
|
||||
- Recurrences (not the whole set of options given in the iCalendar spec, but the most important ones)
|
||||
- Notification by e-mail. Multiple notifications can be set per event
|
||||
- Multiple calendars per user
|
||||
- Access to the events using CalDAV (using iPhone, Thunderbird Lightning etc., see below)
|
||||
- Read-only access to the friendica-native events (also using CalDAV)
|
||||
- The friendica-contacts are made available using CardDAV (confirmed to work with iOS)
|
||||
- The events of a calendar can be exported as ICS file. ICS files can be imported into a calendar
|
||||
|
||||
|
||||
Internationalization:
|
||||
- At the moment, settings for the US and the german systems are selectable (regarding the date format and the first day of the week). More will be added on request.
|
||||
|
@ -17,8 +22,10 @@ Internationalization:
|
|||
|
||||
CalDAV device compatibility:
|
||||
- iOS (iPhone/iPodTouch) works
|
||||
- Thunderbird Lightning should work, not tested yet
|
||||
- Android: http://dmfs.org/caldav/ seems to work, not much tested yet, though
|
||||
- Thunderbird Lightning works
|
||||
- Android:
|
||||
- aCal (http://andrew.mcmillan.net.nz/projects/aCal) works, available in F-Droid and Google Play
|
||||
- CalDAV-Sync (http://dmfs.org/caldav/) works, non-free
|
||||
|
||||
Installation
|
||||
After activating, serveral tables in the database have to be created. The admin-interface of the plugin will try to do this automatically.
|
||||
|
@ -26,12 +33,10 @@ In case of errors, the SQL-statement to create the tables manually are shown in
|
|||
|
||||
|
||||
Functuality missing: (a.k.a. "Roadmap")
|
||||
- Recurrence of events (this is only supported using the CalDAV-interface; recurring events saved using CalDAV will appear correctly multiple times in the web-based frontend; hovever those events will be read-only at the web-based frondend)
|
||||
- Sharing events; all events are private at the moment, therefore this system is not yet a complete replacement for the friendica-native events
|
||||
- Sharing events; all events are private at the moment, therefore this system is not a complete replacement for the friendica-native events
|
||||
- Attendees / Collaboration
|
||||
|
||||
|
||||
|
||||
Used libraries
|
||||
|
||||
SabreDAV
|
||||
|
@ -46,10 +51,6 @@ jQueryUI
|
|||
http://jqueryui.com/
|
||||
Dual-licenced: MIT and GPL licenses
|
||||
|
||||
iCalCreator
|
||||
http://kigkonsult.se/iCalcreator/
|
||||
GNU Lesser General Public License
|
||||
|
||||
TimePicker
|
||||
http://www.texotela.co.uk/code/jquery/timepicker/
|
||||
Dual-licenced: MIT and GPL licenses
|
||||
|
|
|
@ -1,31 +1,63 @@
|
|||
1.7.0-alpha (2012-??-??)
|
||||
* BC Break: The calendarobjects database table has a bunch of new fields,
|
||||
and a migration script is required to ensure everything will keep
|
||||
working. Read the wiki for more details.
|
||||
* BC Break: The calendarobjects database table has a bunch of new
|
||||
fields, and a migration script is required to ensure everything will
|
||||
keep working. Read the wiki for more details.
|
||||
* BC Break: The iCalendar interface now has a new method: calendarQuery.
|
||||
* BC Break: In this version a number of classes have been deleted, that
|
||||
have been previously deprecated. Namely:
|
||||
- Sabre_DAV_Directory (now: Sabre_DAV_Collection)
|
||||
- Sabre_DAV_SimpleDirectory (now: Sabre_DAV_SimpleCollection)
|
||||
- Sabre_VObject_Element_DateTime (now: Sabre_VObject_Property_DateTime)
|
||||
- Sabre_VObject_Element_MultiDateTime (now .._Property_MultiDateTime)
|
||||
- Sabre_VObject_Element_DateTime (now: .._Property_DateTime)
|
||||
- Sabre_VObject_Element_MultiDateTime (-> .._Property_MultiDateTime)
|
||||
* BC Break: Sabre_CalDAV_Schedule_IMip::sendMessage now has an extra
|
||||
argument. If you extended this class, you should fix this method. It's
|
||||
only used for informational purposes.
|
||||
* Changed: Responsibility for dealing with the calendar-query is now moved
|
||||
from the CalDAV plugin to the CalDAV backends. This allows for heavy
|
||||
optimizations.
|
||||
* Changed: The CalDAV PDO backend is now a lot faster for common calendar
|
||||
queries.
|
||||
* Fixed: Marking both the text/calendar and text/x-vcard as UTF-8 encoded.
|
||||
* BC Break: The DAV: namespace is no longer converted to urn:DAV. This was
|
||||
a workaround for a bug in older PHP versions (pre-5.3).
|
||||
* New feature: Support for caldav notifications!
|
||||
* Changed: Responsibility for dealing with the calendar-query is now
|
||||
moved from the CalDAV plugin to the CalDAV backends. This allows for
|
||||
heavy optimizations.
|
||||
* Changed: The CalDAV PDO backend is now a lot faster for common
|
||||
calendar queries.
|
||||
* Fixed: Marking both the text/calendar and text/x-vcard as UTF-8
|
||||
encoded.
|
||||
* Fixed: Workaround for the SOGO connector, as it doesn't understand
|
||||
receiving "text/x-vcard; charset=utf-8" for a contenttype.
|
||||
* Added: Sabre_DAV_Client now throws more specific exceptions in cases
|
||||
where we already has an exception class.
|
||||
* Added: Sabre_DAV_PartialUpdate. This plugin allows you to use the PATCH
|
||||
method to update parts of a file.
|
||||
* Added: Sabre_DAV_PartialUpdate. This plugin allows you to use the
|
||||
PATCH method to update parts of a file.
|
||||
* Added: Tons of timezone name mappings for Microsoft Exchange.
|
||||
* Added: Support for an 'exception' event.
|
||||
* Fixed: Uploaded VCards without a UID are now rejected. (thanks Dominik!)
|
||||
* Fixed: Rejecting calendar objects if they are not in the
|
||||
supported-calendar-component list. (thanks Armin!)
|
||||
* Fixed: Workaround for 10.8 Mountain Lion vCards, as it needs \r line
|
||||
endings to parse them correctly.
|
||||
* Fixed: Issue 219: serialize() now reorders correctly.
|
||||
* Fixed: Sabre_DAV_XMLUtil no longer returns empty $dom->childNodes
|
||||
if there is whitespace in $dom.
|
||||
|
||||
1.6.3-stable (2012-??-??)
|
||||
1.6.4-stable (2012-??-??)
|
||||
* Fixed: Issue 220: Calendar-query filters may fail when filtering on
|
||||
alarms, if an overridden event has it's alarm removed.
|
||||
* Fixed: Compatibility for OS/X 10.8 iCal in the IMipHandler.
|
||||
* Fixed: Issue 222: beforeWriteContent shouldn't be called for lock
|
||||
requests.
|
||||
* Fixed: Problem with POST requests to the outbox if mailto: was not lower
|
||||
cased.
|
||||
* Fixed: Yearly recurrence rule expansion on leap-days no behaves
|
||||
correctly.
|
||||
* Fixed: Correctly checking if recurring, all-day events with no dtstart
|
||||
fall in a timerange if the start of the time-range exceeds the start of
|
||||
the instance of an event, but not the end.
|
||||
* Fixed: All-day recurring events wouldn't match if an occurence ended
|
||||
exactly on the start of a time-range.
|
||||
* Fixed: HTTP basic auth did not correctly deal with passwords containing
|
||||
colons on some servers.
|
||||
|
||||
1.6.3-stable (2012-06-12)
|
||||
* Added: It's now possible to specify in Sabre_DAV_Client which type of
|
||||
authentication is to be used.
|
||||
* Fixed: Issue 206: Sabre_DAV_Client PUT requests are fixed.
|
||||
|
@ -43,6 +75,7 @@
|
|||
compatibility.
|
||||
* Fixed: Added a workaround for a bug in KDE 4.8.2 contact syncing. See
|
||||
https://bugs.kde.org/show_bug.cgi?id=300047
|
||||
* Fixed: Issue 217: Sabre_DAV_Tree_FileSystem was pretty broken.
|
||||
|
||||
1.6.2-stable (2012-04-16)
|
||||
* Fixed: Sabre_VObject_Node::$parent should have been public.
|
||||
|
|
42
dav/SabreDAV/README.md
Normal file
42
dav/SabreDAV/README.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
# What is SabreDAV
|
||||
|
||||
SabreDAV allows you to easily add WebDAV support to a PHP application. SabreDAV is meant to cover the entire standard, and attempts to allow integration using an easy to understand API.
|
||||
|
||||
### Feature list:
|
||||
|
||||
* Fully WebDAV compliant
|
||||
* Supports Windows XP, Windows Vista, Mac OS/X, DavFSv2, Cadaver, Netdrive, Open Office, and probably more.
|
||||
* Passing all Litmus tests.
|
||||
* Supporting class 1, 2 and 3 Webdav servers.
|
||||
* Locking support.
|
||||
* Custom property support.
|
||||
* CalDAV (tested with [Evolution](http://code.google.com/p/sabredav/wiki/Evolution), [iCal](http://code.google.com/p/sabredav/wiki/ICal), [iPhone](http://code.google.com/p/sabredav/wiki/IPhone) and [Lightning](http://code.google.com/p/sabredav/wiki/Lightning)).
|
||||
* CardDAV (tested with [OS/X addressbook](http://code.google.com/p/sabredav/wiki/OSXAddressbook), the [iOS addressbook](http://code.google.com/p/sabredav/wiki/iOSCardDAV) and [Evolution](http://code.google.com/p/sabredav/wiki/Evolution)).
|
||||
* Over 97% unittest code coverage.
|
||||
|
||||
### Supported RFC's:
|
||||
|
||||
* [RFC2617](http://www.ietf.org/rfc/rfc2617.txt): Basic/Digest auth.
|
||||
* [RFC2518](http://www.ietf.org/rfc/rfc2518.txt): First WebDAV spec.
|
||||
* [RFC3744](http://www.ietf.org/rfc/rfc3744.txt): ACL (some features missing).
|
||||
* [RFC4709](http://www.ietf.org/rfc/rfc4709.txt): [DavMount](http://code.google.com/p/sabredav/wiki/DavMount).
|
||||
* [RFC4791](http://www.ietf.org/rfc/rfc4791.txt): CalDAV.
|
||||
* [RFC4918](http://www.ietf.org/rfc/rfc4918.txt): WebDAV revision.
|
||||
* [RFC5397](http://www.ietf.org/rfc/rfc5689.txt): current-user-principal.
|
||||
* [RFC5689](http://www.ietf.org/rfc/rfc5689.txt): Extended MKCOL.
|
||||
* [RFC5789](http://tools.ietf.org/html/rfc5789): PATCH method for HTTP.
|
||||
* [RFC6352](http://www.ietf.org/rfc/rfc6352.txt): CardDAV
|
||||
* [draft-daboo-carddav-directory-gateway](http://tools.ietf.org/html/draft-daboo-carddav-directory-gateway): CardDAV directory gateway
|
||||
* CalDAV ctag, CalDAV-proxy.
|
||||
|
||||
## Live Demo
|
||||
|
||||
### Head over to:
|
||||
|
||||
* Url: [http://demo.sabredav.org/public/](http://demo.sabredav.org/public/)
|
||||
* Username: testuser
|
||||
* Password: test
|
||||
|
||||
**Please note:** Due to the webserver stack (nginx with varnish) some clients will not work correctly. At the very least this includes Finder and Cyberduck. Any client using chunked transfer encoding or expect *100-Continue* will fail.
|
||||
|
||||
The demo site is kindly hosted by sourceforge, so take it easy with the diskspace. It's limited!
|
|
@ -95,7 +95,12 @@ foreach($fields17 as $field) {
|
|||
if ($found === 0) {
|
||||
echo "The database had the 1.6 schema. Table will now be altered.\n";
|
||||
echo "This may take some time for large tables\n";
|
||||
$pdo->exec(<<<SQL
|
||||
|
||||
switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
|
||||
|
||||
case 'mysql' :
|
||||
|
||||
$pdo->exec(<<<SQL
|
||||
ALTER TABLE calendarobjects
|
||||
ADD etag VARCHAR(32),
|
||||
ADD size INT(11) UNSIGNED,
|
||||
|
@ -103,7 +108,20 @@ ADD componenttype VARCHAR(8),
|
|||
ADD firstoccurence INT(11) UNSIGNED,
|
||||
ADD lastoccurence INT(11) UNSIGNED
|
||||
SQL
|
||||
);
|
||||
);
|
||||
break;
|
||||
case 'sqlite' :
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD etag text');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD size integer');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD componenttype TEXT');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD firstoccurence integer');
|
||||
$pdo->exec('ALTER TABLE calendarobjects ADD lastoccurence integer');
|
||||
break;
|
||||
|
||||
default :
|
||||
die('This upgrade script does not support this driver (' . $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) . ")\n");
|
||||
|
||||
}
|
||||
echo "Database schema upgraded.\n";
|
||||
|
||||
} elseif ($found === 5) {
|
||||
|
@ -205,7 +223,7 @@ function getDenormalizedData($calendarData) {
|
|||
}
|
||||
} else {
|
||||
$it = new Sabre_VObject_RecurrenceIterator($vObject, (string)$component->UID);
|
||||
$maxDate = new DateTime(self::MAX_DATE);
|
||||
$maxDate = new DateTime(Sabre_CalDAV_Backend_PDO::MAX_DATE);
|
||||
if ($it->isInfinite()) {
|
||||
$lastOccurence = $maxDate->getTimeStamp();
|
||||
} else {
|
||||
|
|
1568
dav/SabreDAV/docs/caldav-notifications.txt
Normal file
1568
dav/SabreDAV/docs/caldav-notifications.txt
Normal file
File diff suppressed because it is too large
Load diff
224
dav/SabreDAV/docs/caldav-sharing-02.txt
Normal file
224
dav/SabreDAV/docs/caldav-sharing-02.txt
Normal file
File diff suppressed because one or more lines are too long
451
dav/SabreDAV/docs/rfc5785.txt
Normal file
451
dav/SabreDAV/docs/rfc5785.txt
Normal file
|
@ -0,0 +1,451 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Internet Engineering Task Force (IETF) M. Nottingham
|
||||
Request for Comments: 5785 E. Hammer-Lahav
|
||||
Updates: 2616, 2818 April 2010
|
||||
Category: Standards Track
|
||||
ISSN: 2070-1721
|
||||
|
||||
|
||||
Defining Well-Known Uniform Resource Identifiers (URIs)
|
||||
|
||||
Abstract
|
||||
|
||||
This memo defines a path prefix for "well-known locations",
|
||||
"/.well-known/", in selected Uniform Resource Identifier (URI)
|
||||
schemes.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This is an Internet Standards Track document.
|
||||
|
||||
This document is a product of the Internet Engineering Task Force
|
||||
(IETF). It represents the consensus of the IETF community. It has
|
||||
received public review and has been approved for publication by the
|
||||
Internet Engineering Steering Group (IESG). Further information on
|
||||
Internet Standards is available in Section 2 of RFC 5741.
|
||||
|
||||
Information about the current status of this document, any errata,
|
||||
and how to provide feedback on it may be obtained at
|
||||
http://www.rfc-editor.org/info/rfc5785.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2010 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info) in effect on the date of
|
||||
publication of this document. Please review these documents
|
||||
carefully, as they describe your rights and restrictions with respect
|
||||
to this document. Code Components extracted from this document must
|
||||
include Simplified BSD License text as described in Section 4.e of
|
||||
the Trust Legal Provisions and are provided without warranty as
|
||||
described in the Simplified BSD License.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 1]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
1.1. Appropriate Use of Well-Known URIs . . . . . . . . . . . . 3
|
||||
2. Notational Conventions . . . . . . . . . . . . . . . . . . . . 3
|
||||
3. Well-Known URIs . . . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
4. Security Considerations . . . . . . . . . . . . . . . . . . . . 4
|
||||
5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
5.1. The Well-Known URI Registry . . . . . . . . . . . . . . . . 4
|
||||
5.1.1. Registration Template . . . . . . . . . . . . . . . . . 5
|
||||
6. References . . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
6.1. Normative References . . . . . . . . . . . . . . . . . . . 5
|
||||
6.2. Informative References . . . . . . . . . . . . . . . . . . 5
|
||||
Appendix A. Acknowledgements . . . . . . . . . . . . . . . . . . . 7
|
||||
Appendix B. Frequently Asked Questions . . . . . . . . . . . . . . 7
|
||||
|
||||
1. Introduction
|
||||
|
||||
It is increasingly common for Web-based protocols to require the
|
||||
discovery of policy or other information about a host ("site-wide
|
||||
metadata") before making a request. For example, the Robots
|
||||
Exclusion Protocol <http://www.robotstxt.org/> specifies a way for
|
||||
automated processes to obtain permission to access resources;
|
||||
likewise, the Platform for Privacy Preferences [W3C.REC-P3P-20020416]
|
||||
tells user-agents how to discover privacy policy beforehand.
|
||||
|
||||
While there are several ways to access per-resource metadata (e.g.,
|
||||
HTTP headers, WebDAV's PROPFIND [RFC4918]), the perceived overhead
|
||||
(either in terms of client-perceived latency and/or deployment
|
||||
difficulties) associated with them often precludes their use in these
|
||||
scenarios.
|
||||
|
||||
When this happens, it is common to designate a "well-known location"
|
||||
for such data, so that it can be easily located. However, this
|
||||
approach has the drawback of risking collisions, both with other such
|
||||
designated "well-known locations" and with pre-existing resources.
|
||||
|
||||
To address this, this memo defines a path prefix in HTTP(S) URIs for
|
||||
these "well-known locations", "/.well-known/". Future specifications
|
||||
that need to define a resource for such site-wide metadata can
|
||||
register their use to avoid collisions and minimise impingement upon
|
||||
sites' URI space.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 2]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
1.1. Appropriate Use of Well-Known URIs
|
||||
|
||||
There are a number of possible ways that applications could use Well-
|
||||
known URIs. However, in keeping with the Architecture of the World-
|
||||
Wide Web [W3C.REC-webarch-20041215], well-known URIs are not intended
|
||||
for general information retrieval or establishment of large URI
|
||||
namespaces on the Web. Rather, they are designed to facilitate
|
||||
discovery of information on a site when it isn't practical to use
|
||||
other mechanisms; for example, when discovering policy that needs to
|
||||
be evaluated before a resource is accessed, or when using multiple
|
||||
round-trips is judged detrimental to performance.
|
||||
|
||||
As such, the well-known URI space was created with the expectation
|
||||
that it will be used to make site-wide policy information and other
|
||||
metadata available directly (if sufficiently concise), or provide
|
||||
references to other URIs that provide such metadata.
|
||||
|
||||
2. Notational Conventions
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
3. Well-Known URIs
|
||||
|
||||
A well-known URI is a URI [RFC3986] whose path component begins with
|
||||
the characters "/.well-known/", and whose scheme is "HTTP", "HTTPS",
|
||||
or another scheme that has explicitly been specified to use well-
|
||||
known URIs.
|
||||
|
||||
Applications that wish to mint new well-known URIs MUST register
|
||||
them, following the procedures in Section 5.1.
|
||||
|
||||
For example, if an application registers the name 'example', the
|
||||
corresponding well-known URI on 'http://www.example.com/' would be
|
||||
'http://www.example.com/.well-known/example'.
|
||||
|
||||
Registered names MUST conform to the segment-nz production in
|
||||
[RFC3986].
|
||||
|
||||
Note that this specification defines neither how to determine the
|
||||
authority to use for a particular context, nor the scope of the
|
||||
metadata discovered by dereferencing the well-known URI; both should
|
||||
be defined by the application itself.
|
||||
|
||||
Typically, a registration will reference a specification that defines
|
||||
the format and associated media type to be obtained by dereferencing
|
||||
the well-known URI.
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 3]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
It MAY also contain additional information, such as the syntax of
|
||||
additional path components, query strings and/or fragment identifiers
|
||||
to be appended to the well-known URI, or protocol-specific details
|
||||
(e.g., HTTP [RFC2616] method handling).
|
||||
|
||||
Note that this specification does not define a format or media-type
|
||||
for the resource located at "/.well-known/" and clients should not
|
||||
expect a resource to exist at that location.
|
||||
|
||||
4. Security Considerations
|
||||
|
||||
This memo does not specify the scope of applicability of metadata or
|
||||
policy obtained from a well-known URI, and does not specify how to
|
||||
discover a well-known URI for a particular application. Individual
|
||||
applications using this mechanism must define both aspects.
|
||||
|
||||
Applications minting new well-known URIs, as well as administrators
|
||||
deploying them, will need to consider several security-related
|
||||
issues, including (but not limited to) exposure of sensitive data,
|
||||
denial-of-service attacks (in addition to normal load issues), server
|
||||
and client authentication, vulnerability to DNS rebinding attacks,
|
||||
and attacks where limited access to a server grants the ability to
|
||||
affect how well-known URIs are served.
|
||||
|
||||
5. IANA Considerations
|
||||
|
||||
5.1. The Well-Known URI Registry
|
||||
|
||||
This document establishes the well-known URI registry.
|
||||
|
||||
Well-known URIs are registered on the advice of one or more
|
||||
Designated Experts (appointed by the IESG or their delegate), with a
|
||||
Specification Required (using terminology from [RFC5226]). However,
|
||||
to allow for the allocation of values prior to publication, the
|
||||
Designated Expert(s) may approve registration once they are satisfied
|
||||
that such a specification will be published.
|
||||
|
||||
Registration requests should be sent to the
|
||||
wellknown-uri-review@ietf.org mailing list for review and comment,
|
||||
with an appropriate subject (e.g., "Request for well-known URI:
|
||||
example").
|
||||
|
||||
Before a period of 14 days has passed, the Designated Expert(s) will
|
||||
either approve or deny the registration request, communicating this
|
||||
decision both to the review list and to IANA. Denials should include
|
||||
an explanation and, if applicable, suggestions as to how to make the
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 4]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
request successful. Registration requests that are undetermined for
|
||||
a period longer than 21 days can be brought to the IESG's attention
|
||||
(using the iesg@iesg.org mailing list) for resolution.
|
||||
|
||||
5.1.1. Registration Template
|
||||
|
||||
URI suffix: The name requested for the well-known URI, relative to
|
||||
"/.well-known/"; e.g., "example".
|
||||
|
||||
Change controller: For Standards-Track RFCs, state "IETF". For
|
||||
others, give the name of the responsible party. Other details
|
||||
(e.g., postal address, e-mail address, home page URI) may also be
|
||||
included.
|
||||
|
||||
Specification document(s): Reference to the document that specifies
|
||||
the field, preferably including a URI that can be used to retrieve
|
||||
a copy of the document. An indication of the relevant sections
|
||||
may also be included, but is not required.
|
||||
|
||||
Related information: Optionally, citations to additional documents
|
||||
containing further relevant information.
|
||||
|
||||
6. References
|
||||
|
||||
6.1. Normative References
|
||||
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
|
||||
Resource Identifier (URI): Generic Syntax", STD 66,
|
||||
RFC 3986, January 2005.
|
||||
|
||||
[RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an
|
||||
IANA Considerations Section in RFCs", BCP 26, RFC 5226,
|
||||
May 2008.
|
||||
|
||||
6.2. Informative References
|
||||
|
||||
[RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter,
|
||||
L., Leach, P., and T. Berners-Lee, "Hypertext Transfer
|
||||
Protocol -- HTTP/1.1", RFC 2616, June 1999.
|
||||
|
||||
[RFC4918] Dusseault, L., "HTTP Extensions for Web Distributed
|
||||
Authoring and Versioning (WebDAV)", RFC 4918, June 2007.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 5]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
[W3C.REC-P3P-20020416]
|
||||
Marchiori, M., "The Platform for Privacy Preferences 1.0
|
||||
(P3P1.0) Specification", World Wide Web Consortium
|
||||
Recommendation REC-P3P-20020416, April 2002,
|
||||
<http://www.w3.org/TR/2002/ REC-P3P-20020416>.
|
||||
|
||||
[W3C.REC-webarch-20041215]
|
||||
Jacobs, I. and N. Walsh, "Architecture of the World Wide
|
||||
Web, Volume One", World Wide Web Consortium
|
||||
Recommendation REC- webarch-20041215, December 2004,
|
||||
<http:// www.w3.org/TR/2004/REC-webarch-20041215>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 6]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
Appendix A. Acknowledgements
|
||||
|
||||
We would like to acknowledge the contributions of everyone who
|
||||
provided feedback and use cases for this document; in particular,
|
||||
Phil Archer, Dirk Balfanz, Adam Barth, Tim Bray, Brian Eaton, Brad
|
||||
Fitzpatrick, Joe Gregorio, Paul Hoffman, Barry Leiba, Ashok Malhotra,
|
||||
Breno de Medeiros, John Panzer, and Drummond Reed. However, they are
|
||||
not responsible for errors and omissions.
|
||||
|
||||
Appendix B. Frequently Asked Questions
|
||||
|
||||
1. Aren't well-known locations bad for the Web?
|
||||
|
||||
They are, but for various reasons -- both technical and social --
|
||||
they are commonly used and their use is increasing. This memo
|
||||
defines a "sandbox" for them, to reduce the risks of collision and
|
||||
to minimise the impact upon pre-existing URIs on sites.
|
||||
|
||||
2. Why /.well-known?
|
||||
|
||||
It's short, descriptive, and according to search indices, not
|
||||
widely used.
|
||||
|
||||
3. What impact does this have on existing mechanisms, such as P3P and
|
||||
robots.txt?
|
||||
|
||||
None, until they choose to use this mechanism.
|
||||
|
||||
4. Why aren't per-directory well-known locations defined?
|
||||
|
||||
Allowing every URI path segment to have a well-known location
|
||||
(e.g., "/images/.well-known/") would increase the risks of
|
||||
colliding with a pre-existing URI on a site, and generally these
|
||||
solutions are found not to scale well, because they're too
|
||||
"chatty".
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 7]
|
||||
|
||||
RFC 5785 Defining Well-Known URIs April 2010
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
Mark Nottingham
|
||||
|
||||
EMail: mnot@mnot.net
|
||||
URI: http://www.mnot.net/
|
||||
|
||||
|
||||
Eran Hammer-Lahav
|
||||
|
||||
EMail: eran@hueniverse.com
|
||||
URI: http://hueniverse.com/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Nottingham & Hammer-Lahav Standards Track [Page 8]
|
||||
|
|
@ -6,5 +6,8 @@ CREATE TABLE locks (
|
|||
token VARCHAR(100),
|
||||
scope TINYINT,
|
||||
depth TINYINT,
|
||||
uri text
|
||||
uri VARCHAR(1000),
|
||||
INDEX(token),
|
||||
INDEX(uri)
|
||||
);
|
||||
|
||||
|
|
|
@ -7,27 +7,27 @@
|
|||
# settings as well.
|
||||
<VirtualHost *:*>
|
||||
|
||||
# Don't forget to change the server name
|
||||
# ServerName dav.example.org
|
||||
# Don't forget to change the server name
|
||||
# ServerName dav.example.org
|
||||
|
||||
# The DocumentRoot is also required
|
||||
# The DocumentRoot is also required
|
||||
# DocumentRoot /home/sabredav/
|
||||
|
||||
RewriteEngine On
|
||||
# This makes every request go to server.php
|
||||
RewriteRule ^/(.*)$ /server.php [L]
|
||||
RewriteEngine On
|
||||
# This makes every request go to server.php
|
||||
RewriteRule ^/(.*)$ /server.php [L]
|
||||
|
||||
# Output buffering needs to be off, to prevent high memory usage
|
||||
php_flag output_buffering off
|
||||
# Output buffering needs to be off, to prevent high memory usage
|
||||
php_flag output_buffering off
|
||||
|
||||
# This is also to prevent high memory usage
|
||||
php_flag always_populate_raw_post_data off
|
||||
# This is also to prevent high memory usage
|
||||
php_flag always_populate_raw_post_data off
|
||||
|
||||
# This is almost a given, but magic quotes is *still* on on some
|
||||
# linux distributions
|
||||
php_flag magic_quotes_gpc off
|
||||
# This is almost a given, but magic quotes is *still* on on some
|
||||
# linux distributions
|
||||
php_flag magic_quotes_gpc off
|
||||
|
||||
# SabreDAV is not compatible with mbstring function overloading
|
||||
php_flag mbstring.func_overload off
|
||||
# SabreDAV is not compatible with mbstring function overloading
|
||||
php_flag mbstring.func_overload off
|
||||
|
||||
</VirtualHost *:*>
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
# This configuration assumes CGI or FastCGI is used.
|
||||
<VirtualHost *:*>
|
||||
|
||||
# Don't forget to change the server name
|
||||
# ServerName dav.example.org
|
||||
# Don't forget to change the server name
|
||||
# ServerName dav.example.org
|
||||
|
||||
# The DocumentRoot is also required
|
||||
# The DocumentRoot is also required
|
||||
# DocumentRoot /home/sabredav/
|
||||
|
||||
# This makes every request go to server.php. This also makes sure
|
||||
# the Authentication information is available. If your server script is
|
||||
# not called server.php, be sure to change it.
|
||||
RewriteEngine On
|
||||
RewriteRule ^/(.*)$ /server.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
# This makes every request go to server.php. This also makes sure
|
||||
# the Authentication information is available. If your server script is
|
||||
# not called server.php, be sure to change it.
|
||||
RewriteEngine On
|
||||
RewriteRule ^/(.*)$ /server.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
|
||||
</VirtualHost *:*>
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -16,8 +16,13 @@ class Sabre_CalDAV_Backend_PDO extends Sabre_CalDAV_Backend_Abstract {
|
|||
|
||||
/**
|
||||
* We need to specify a max date, because we need to stop *somewhere*
|
||||
*
|
||||
* On 32 bit system the maximum for a signed integer is 2147483647, so
|
||||
* MAX_DATE cannot be higher than date('Y-m-d', 2147483647) which results
|
||||
* in 2038-01-19 to avoid problems when the date is converted
|
||||
* to a unix timestamp.
|
||||
*/
|
||||
const MAX_DATE = '2040-01-01';
|
||||
const MAX_DATE = '2038-01-01';
|
||||
|
||||
/**
|
||||
* pdo
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ class Sabre_CalDAV_CalendarQueryParser {
|
|||
|
||||
$this->xpath = new DOMXPath($dom);
|
||||
$this->xpath->registerNameSpace('cal',Sabre_CalDAV_Plugin::NS_CALDAV);
|
||||
$this->xpath->registerNameSpace('dav','urn:DAV');
|
||||
$this->xpath->registerNameSpace('dav','DAV:');
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
@ -414,11 +442,11 @@ 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');
|
||||
$hrefElems = $dom->getElementsByTagNameNS('DAV:','href');
|
||||
|
||||
$xpath = new DOMXPath($dom);
|
||||
$xpath->registerNameSpace('cal',Sabre_CalDAV_Plugin::NS_CALDAV);
|
||||
$xpath->registerNameSpace('dav','urn:DAV');
|
||||
$xpath->registerNameSpace('dav','DAV:');
|
||||
|
||||
$expand = $xpath->query('/cal:calendar-multiget/dav:prop/cal:calendar-data/cal:expand');
|
||||
if ($expand->length>0) {
|
||||
|
@ -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.
|
||||
|
|
|
@ -154,8 +154,7 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
if (is_resource($val))
|
||||
$val = stream_get_contents($val);
|
||||
|
||||
// Taking out \r to not screw up the xml output
|
||||
$returnedProperties[200][$addressDataProp] = str_replace("\r","", $val);
|
||||
$returnedProperties[200][$addressDataProp] = $val;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +269,7 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
$properties = array_keys(Sabre_DAV_XMLUtil::parseProperties($dom->firstChild));
|
||||
|
||||
$hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href');
|
||||
$hrefElems = $dom->getElementsByTagNameNS('DAV:','href');
|
||||
$propertyList = array();
|
||||
|
||||
foreach($hrefElems as $elem) {
|
||||
|
@ -358,6 +357,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 +443,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']});
|
||||
|
|
|
@ -485,19 +485,17 @@ class Sabre_DAV_Client {
|
|||
*/
|
||||
public function parseMultiStatus($body) {
|
||||
|
||||
$body = Sabre_DAV_XMLUtil::convertDAVNamespace($body);
|
||||
|
||||
$responseXML = simplexml_load_string($body, null, LIBXML_NOBLANKS | LIBXML_NOCDATA);
|
||||
if ($responseXML===false) {
|
||||
throw new InvalidArgumentException('The passed data is not valid XML');
|
||||
}
|
||||
|
||||
$responseXML->registerXPathNamespace('d', 'urn:DAV');
|
||||
$responseXML->registerXPathNamespace('d', 'DAV:');
|
||||
|
||||
$propResult = array();
|
||||
|
||||
foreach($responseXML->xpath('d:response') as $response) {
|
||||
$response->registerXPathNamespace('d', 'urn:DAV');
|
||||
$response->registerXPathNamespace('d', 'DAV:');
|
||||
$href = $response->xpath('d:href');
|
||||
$href = (string)$href[0];
|
||||
|
||||
|
@ -505,7 +503,7 @@ class Sabre_DAV_Client {
|
|||
|
||||
foreach($response->xpath('d:propstat') as $propStat) {
|
||||
|
||||
$propStat->registerXPathNamespace('d', 'urn:DAV');
|
||||
$propStat->registerXPathNamespace('d', 'DAV:');
|
||||
$status = $propStat->xpath('d:status');
|
||||
list($httpVersion, $statusCode, $message) = explode(' ', (string)$status[0],3);
|
||||
|
||||
|
|
|
@ -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,9 +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 function serialize(Sabre_DAV_Server $server, DOMElement $prop);
|
||||
abstract class Sabre_DAV_Property implements Sabre_DAV_PropertyInterface {
|
||||
|
||||
static function unserialize(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.
|
||||
|
@ -1995,7 +1999,7 @@ class Sabre_DAV_Server {
|
|||
if (!$body) return array();
|
||||
|
||||
$dom = Sabre_DAV_XMLUtil::loadDOMDocument($body);
|
||||
$elem = $dom->getElementsByTagNameNS('urn:DAV','propfind')->item(0);
|
||||
$elem = $dom->getElementsByTagNameNS('DAV:','propfind')->item(0);
|
||||
return array_keys(Sabre_DAV_XMLUtil::parseProperties($elem));
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,6 @@ class Sabre_DAV_XMLUtil {
|
|||
* {http://www.example.org}myelem
|
||||
*
|
||||
* This format is used throughout the SabreDAV sourcecode.
|
||||
* Elements encoded with the urn:DAV namespace will
|
||||
* be returned as if they were in the DAV: namespace. This is to avoid
|
||||
* compatibility problems.
|
||||
*
|
||||
* This function will return null if a nodetype other than an Element is passed.
|
||||
*
|
||||
|
@ -33,8 +30,7 @@ class Sabre_DAV_XMLUtil {
|
|||
|
||||
if ($dom->nodeType !== XML_ELEMENT_NODE) return null;
|
||||
|
||||
// Mapping back to the real namespace, in case it was dav
|
||||
if ($dom->namespaceURI=='urn:DAV') $ns = 'DAV:'; else $ns = $dom->namespaceURI;
|
||||
$ns = $dom->namespaceURI;
|
||||
|
||||
// Mapping to clark notation
|
||||
return '{' . $ns . '}' . $dom->localName;
|
||||
|
@ -64,29 +60,11 @@ class Sabre_DAV_XMLUtil {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes an XML document (as string) and converts all instances of the
|
||||
* DAV: namespace to urn:DAV
|
||||
*
|
||||
* This is unfortunately needed, because the DAV: namespace violates the xml namespaces
|
||||
* spec, and causes the DOM to throw errors
|
||||
*
|
||||
* @param string $xmlDocument
|
||||
* @return array|string|null
|
||||
*/
|
||||
static function convertDAVNamespace($xmlDocument) {
|
||||
|
||||
// This is used to map the DAV: namespace to urn:DAV. This is needed, because the DAV:
|
||||
// namespace is actually a violation of the XML namespaces specification, and will cause errors
|
||||
return preg_replace("/xmlns(:[A-Za-z0-9_]*)?=(\"|\')DAV:(\\2)/","xmlns\\1=\\2urn:DAV\\2",$xmlDocument);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method provides a generic way to load a DOMDocument for WebDAV use.
|
||||
*
|
||||
* This method throws a Sabre_DAV_Exception_BadRequest exception for any xml errors.
|
||||
* It does not preserve whitespace, and it converts the DAV: namespace to urn:DAV.
|
||||
* It does not preserve whitespace.
|
||||
*
|
||||
* @param string $xml
|
||||
* @throws Sabre_DAV_Exception_BadRequest
|
||||
|
@ -118,11 +96,12 @@ class Sabre_DAV_XMLUtil {
|
|||
libxml_clear_errors();
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML(self::convertDAVNamespace($xml),LIBXML_NOWARNING | LIBXML_NOERROR);
|
||||
|
||||
// We don't generally care about any whitespace
|
||||
$dom->preserveWhiteSpace = false;
|
||||
|
||||
$dom->loadXML($xml,LIBXML_NOWARNING | LIBXML_NOERROR);
|
||||
|
||||
if ($error = libxml_get_last_error()) {
|
||||
libxml_clear_errors();
|
||||
throw new Sabre_DAV_Exception_BadRequest('The request body had an invalid XML body. (message: ' . $error->message . ', errorcode: ' . $error->code . ', line: ' . $error->line . ')');
|
||||
|
|
|
@ -88,11 +88,11 @@ class Sabre_DAVACL_Property_Acl extends Sabre_DAV_Property {
|
|||
static public function unserialize(DOMElement $dom) {
|
||||
|
||||
$privileges = array();
|
||||
$xaces = $dom->getElementsByTagNameNS('urn:DAV','ace');
|
||||
$xaces = $dom->getElementsByTagNameNS('DAV:','ace');
|
||||
for($ii=0; $ii < $xaces->length; $ii++) {
|
||||
|
||||
$xace = $xaces->item($ii);
|
||||
$principal = $xace->getElementsByTagNameNS('urn:DAV','principal');
|
||||
$principal = $xace->getElementsByTagNameNS('DAV:','principal');
|
||||
if ($principal->length !== 1) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Each {DAV:}ace element must have one {DAV:}principal element');
|
||||
}
|
||||
|
@ -116,17 +116,17 @@ class Sabre_DAVACL_Property_Acl extends Sabre_DAV_Property {
|
|||
|
||||
$protected = false;
|
||||
|
||||
if ($xace->getElementsByTagNameNS('urn:DAV','protected')->length > 0) {
|
||||
if ($xace->getElementsByTagNameNS('DAV:','protected')->length > 0) {
|
||||
$protected = true;
|
||||
}
|
||||
|
||||
$grants = $xace->getElementsByTagNameNS('urn:DAV','grant');
|
||||
$grants = $xace->getElementsByTagNameNS('DAV:','grant');
|
||||
if ($grants->length < 1) {
|
||||
throw new Sabre_DAV_Exception_NotImplemented('Every {DAV:}ace element must have a {DAV:}grant element. {DAV:}deny is not yet supported');
|
||||
}
|
||||
$grant = $grants->item(0);
|
||||
|
||||
$xprivs = $grant->getElementsByTagNameNS('urn:DAV','privilege');
|
||||
$xprivs = $grant->getElementsByTagNameNS('DAV:','privilege');
|
||||
for($jj=0; $jj<$xprivs->length; $jj++) {
|
||||
|
||||
$xpriv = $xprivs->item($jj);
|
||||
|
|
|
@ -46,7 +46,7 @@ class Sabre_HTTP_BasicAuth extends Sabre_HTTP_AbstractAuth {
|
|||
|
||||
if (strpos(strtolower($auth),'basic')!==0) return false;
|
||||
|
||||
return explode(':', base64_decode(substr($auth, 6)));
|
||||
return explode(':', base64_decode(substr($auth, 6)),2);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class Sabre_HTTP_Version {
|
|||
/**
|
||||
* Full version number
|
||||
*/
|
||||
const VERSION = '1.6.2';
|
||||
const VERSION = '1.6.4';
|
||||
|
||||
/**
|
||||
* Stability : alpha, beta, stable
|
||||
|
|
|
@ -30,7 +30,7 @@ class Sabre_VObject_Component extends Sabre_VObject_Element {
|
|||
public $children = array();
|
||||
|
||||
/**
|
||||
* If coponents are added to this map, they will be automatically mapped
|
||||
* If components are added to this map, they will be automatically mapped
|
||||
* to their respective classes, if parsed by the reader or constructed with
|
||||
* the 'create' method.
|
||||
*
|
||||
|
@ -94,40 +94,54 @@ class Sabre_VObject_Component extends Sabre_VObject_Element {
|
|||
*
|
||||
* This is solely used by the childrenSort method.
|
||||
*
|
||||
* A higher score means the item will be higher in the list
|
||||
* A higher score means the item will be lower in the list.
|
||||
* To avoid score collisions, each "score category" has a reasonable
|
||||
* space to accomodate elements. The $key is added to the $score to
|
||||
* preserve the original relative order of elements.
|
||||
*
|
||||
* @param Sabre_VObject_Node $n
|
||||
* @param int $key
|
||||
* @param Sabre_VObject $array
|
||||
* @return int
|
||||
*/
|
||||
$sortScore = function($n) {
|
||||
$sortScore = function($key, $array) {
|
||||
|
||||
if ($n instanceof Sabre_VObject_Component) {
|
||||
if ($array[$key] instanceof Sabre_VObject_Component) {
|
||||
// We want to encode VTIMEZONE first, this is a personal
|
||||
// preference.
|
||||
if ($n->name === 'VTIMEZONE') {
|
||||
return 1;
|
||||
if ($array[$key]->name === 'VTIMEZONE') {
|
||||
$score=300000000;
|
||||
return $score+$key;
|
||||
} else {
|
||||
return 0;
|
||||
$score=400000000;
|
||||
return $score+$key;
|
||||
}
|
||||
} else {
|
||||
// Properties get encoded first
|
||||
// VCARD version 4.0 wants the VERSION property to appear first
|
||||
if ($n->name === 'VERSION') {
|
||||
return 3;
|
||||
} else {
|
||||
return 2;
|
||||
if ($array[$key] instanceof Sabre_VObject_Property) {
|
||||
if ($array[$key]->name === 'VERSION') {
|
||||
$score=100000000;
|
||||
return $score+$key;
|
||||
} else {
|
||||
// All other properties
|
||||
$score=200000000;
|
||||
return $score+$key;
|
||||
}
|
||||
}
|
||||
}
|
||||
next($children);
|
||||
|
||||
};
|
||||
|
||||
usort($this->children, function($a, $b) use ($sortScore) {
|
||||
$tmp = $this->children;
|
||||
uksort($this->children, function($a, $b) use ($sortScore, $tmp) {
|
||||
|
||||
$sA = $sortScore($a);
|
||||
$sB = $sortScore($b);
|
||||
$sA = $sortScore($a, $tmp);
|
||||
$sB = $sortScore($b, $tmp);
|
||||
|
||||
if ($sA === $sB) return 0;
|
||||
|
||||
return ($sA > $sB) ? -1 : 1;
|
||||
return ($sA < $sB) ? -1 : 1;
|
||||
|
||||
});
|
||||
|
||||
|
@ -250,6 +264,27 @@ class Sabre_VObject_Component extends Sabre_VObject_Element {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
* An array is returned with warnings.
|
||||
*
|
||||
* Every item in the array has the following properties:
|
||||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate() {
|
||||
|
||||
$result = array();
|
||||
foreach($this->children as $child) {
|
||||
$result = array_merge($result, $child->validate());
|
||||
}
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/* Magic property accessors {{{ */
|
||||
|
||||
/**
|
||||
|
|
|
@ -129,5 +129,110 @@ class Sabre_VObject_Component_VCalendar extends Sabre_VObject_Component {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
* An array is returned with warnings.
|
||||
*
|
||||
* Every item in the array has the following properties:
|
||||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate() {
|
||||
|
||||
$warnings = array();
|
||||
|
||||
$version = $this->select('VERSION');
|
||||
if (count($version)!==1) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
|
||||
'node' => $this,
|
||||
);
|
||||
} else {
|
||||
if ((string)$this->VERSION !== '2.0') {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
}
|
||||
$version = $this->select('PRODID');
|
||||
if (count($version)!==1) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
if (count($this->CALSCALE) > 1) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The CALSCALE property must not be specified more than once.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
if (count($this->METHOD) > 1) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The METHOD property must not be specified more than once.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
|
||||
$allowedComponents = array(
|
||||
'VEVENT',
|
||||
'VTODO',
|
||||
'VJOURNAL',
|
||||
'VFREEBUSY',
|
||||
'VTIMEZONE',
|
||||
);
|
||||
$allowedProperties = array(
|
||||
'PRODID',
|
||||
'VERSION',
|
||||
'CALSCALE',
|
||||
'METHOD',
|
||||
);
|
||||
$componentsFound = 0;
|
||||
foreach($this->children as $child) {
|
||||
if($child instanceof Sabre_VObject_Component) {
|
||||
$componentsFound++;
|
||||
if (!in_array($child->name, $allowedComponents)) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($child instanceof Sabre_VObject_Property) {
|
||||
if (!in_array($child->name, $allowedProperties)) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($componentsFound===0) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'An iCalendar object must have at least 1 component.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
$warnings,
|
||||
parent::validate()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,23 @@ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Cou
|
|||
*/
|
||||
public $parent = null;
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
* An array is returned with warnings.
|
||||
*
|
||||
* Every item in the array has the following properties:
|
||||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate() {
|
||||
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/* {{{ IteratorAggregator interface */
|
||||
|
||||
/**
|
||||
|
|
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);
|
||||
|
||||
|
|
|
@ -337,6 +337,8 @@ class Sabre_VObject_RecurrenceIterator implements Iterator {
|
|||
$this->endDate = clone $this->startDate;
|
||||
if (isset($this->baseEvent->DURATION)) {
|
||||
$this->endDate->add(Sabre_VObject_DateTimeParser::parse($this->baseEvent->DURATION->value));
|
||||
} elseif ($this->baseEvent->DTSTART->getDateType()===Sabre_VObject_Property_DateTime::DATE) {
|
||||
$this->endDate->modify('+1 day');
|
||||
}
|
||||
}
|
||||
$this->currentDate = clone $this->startDate;
|
||||
|
@ -565,7 +567,7 @@ class Sabre_VObject_RecurrenceIterator implements Iterator {
|
|||
*/
|
||||
public function fastForward(DateTime $dt) {
|
||||
|
||||
while($this->valid() && $this->getDTEnd() < $dt) {
|
||||
while($this->valid() && $this->getDTEnd() <= $dt) {
|
||||
$this->next();
|
||||
}
|
||||
|
||||
|
@ -838,9 +840,40 @@ class Sabre_VObject_RecurrenceIterator implements Iterator {
|
|||
*/
|
||||
protected function nextYearly() {
|
||||
|
||||
$currentMonth = $this->currentDate->format('n');
|
||||
$currentYear = $this->currentDate->format('Y');
|
||||
$currentDayOfMonth = $this->currentDate->format('j');
|
||||
|
||||
// No sub-rules, so we just advance by year
|
||||
if (!$this->byMonth) {
|
||||
|
||||
// Unless it was a leap day!
|
||||
if ($currentMonth==2 && $currentDayOfMonth==29) {
|
||||
|
||||
$counter = 0;
|
||||
do {
|
||||
$counter++;
|
||||
// Here we increase the year count by the interval, until
|
||||
// we hit a date that's also in a leap year.
|
||||
//
|
||||
// We could just find the next interval that's dividable by
|
||||
// 4, but that would ignore the rule that there's no leap
|
||||
// year every year that's dividable by a 100, but not by
|
||||
// 400. (1800, 1900, 2100). So we just rely on the datetime
|
||||
// functions instead.
|
||||
$nextDate = clone $this->currentDate;
|
||||
$nextDate->modify('+ ' . ($this->interval*$counter) . ' years');
|
||||
} while ($nextDate->format('n')!=2);
|
||||
$this->currentDate = $nextDate;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// The easiest form
|
||||
$this->currentDate->modify('+' . $this->interval . ' years');
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
$currentMonth = $this->currentDate->format('n');
|
||||
|
@ -892,8 +925,8 @@ class Sabre_VObject_RecurrenceIterator implements Iterator {
|
|||
|
||||
} else {
|
||||
|
||||
// no byDay or byMonthDay, so we can just loop through the
|
||||
// months.
|
||||
// These are the 'byMonth' rules, if there are no byDay or
|
||||
// byMonthDay sub-rules.
|
||||
do {
|
||||
|
||||
$currentMonth++;
|
||||
|
@ -903,6 +936,7 @@ class Sabre_VObject_RecurrenceIterator implements Iterator {
|
|||
}
|
||||
} while (!in_array($currentMonth, $this->byMonth));
|
||||
$this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
|
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());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@ class Sabre_VObject_Version {
|
|||
/**
|
||||
* Full version number
|
||||
*/
|
||||
const VERSION = '1.3.3';
|
||||
const VERSION = '1.3.4';
|
||||
|
||||
/**
|
||||
* Stability : alpha, beta, stable
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
<?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)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_VObject_WindowsTimezoneMap {
|
||||
|
||||
protected 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',
|
||||
);
|
||||
|
||||
static public function lookup($tzid) {
|
||||
return isset(self::$map[$tzid]) ? self::$map[$tzid] : null;
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
||||
class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract implements Sabre_CalDAV_Backend_NotificationSupport {
|
||||
|
||||
private $calendarData;
|
||||
private $calendars;
|
||||
private $notifications;
|
||||
|
||||
function __construct(array $calendars, array $calendarData) {
|
||||
function __construct(array $calendars, array $calendarData, array $notifications = array()) {
|
||||
|
||||
$this->calendars = $calendars;
|
||||
$this->calendarData = $calendarData;
|
||||
$this->notifications = $notifications;
|
||||
|
||||
}
|
||||
|
||||
|
@ -58,7 +60,15 @@ class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
|||
*/
|
||||
function createCalendar($principalUri,$calendarUri,array $properties) {
|
||||
|
||||
throw new Exception('Not implemented');
|
||||
$id = Sabre_DAV_UUIDUtil::getUUID();
|
||||
$this->calendars[] = array_merge(array(
|
||||
'id' => $id,
|
||||
'principaluri' => $principalUri,
|
||||
'uri' => $calendarUri,
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array('VEVENT','VTODO')),
|
||||
), $properties);
|
||||
|
||||
return $id;
|
||||
|
||||
}
|
||||
|
||||
|
@ -112,7 +122,11 @@ class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
|||
*/
|
||||
public function deleteCalendar($calendarId) {
|
||||
|
||||
throw new Exception('Not implemented');
|
||||
foreach($this->calendars as $k=>$calendar) {
|
||||
if ($calendar['id'] === $calendarId) {
|
||||
unset($this->calendars[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -227,4 +241,37 @@ class Sabre_CalDAV_Backend_Mock extends Sabre_CalDAV_Backend_Abstract {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
if (isset($this->notifications[$principalUri])) {
|
||||
return $this->notifications[$principalUri];
|
||||
}
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
throw new Sabre_DAV_Exception_NotImplemented('This doesn\'t work!');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -343,6 +343,14 @@ DURATION:PT1H
|
|||
RRULE:FREQ=YEARLY
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
yow;
|
||||
$blob33 = <<<yow
|
||||
BEGIN:VCALENDAR
|
||||
BEGIN:VEVENT
|
||||
DTSTART;VALUE=DATE:20120628
|
||||
RRULE:FREQ=DAILY
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
yow;
|
||||
|
||||
$filter1 = array(
|
||||
|
@ -604,8 +612,16 @@ yow;
|
|||
'time-range' => null,
|
||||
);
|
||||
|
||||
// Time-range with RRULE
|
||||
|
||||
$filter38 = array(
|
||||
'name' => 'VEVENT',
|
||||
'comp-filters' => array(),
|
||||
'prop-filters' => array(),
|
||||
'is-not-defined' => false,
|
||||
'time-range' => array(
|
||||
'start' => new DateTime('2012-07-01 00:00:00', new DateTimeZone('UTC')),
|
||||
'end' => new DateTime('2012-08-01 00:00:00', new DateTimeZone('UTC')),
|
||||
)
|
||||
);
|
||||
|
||||
return array(
|
||||
// Component check
|
||||
|
@ -741,6 +757,9 @@ yow;
|
|||
array($blob31, $filter20, 1),
|
||||
array($blob32, $filter20, 0),
|
||||
|
||||
// Bug reported on mailing list, related to all-day events.
|
||||
array($blob33, $filter38, 1),
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -55,6 +55,56 @@ class Sabre_CalDAV_ICSExportPluginTest extends PHPUnit_Framework_TestCase {
|
|||
$this->assertEquals(1,count($obj->VERSION));
|
||||
$this->assertEquals(1,count($obj->CALSCALE));
|
||||
$this->assertEquals(1,count($obj->PRODID));
|
||||
$this->assertTrue(strpos((string)$obj->PRODID, Sabre_DAV_Version::VERSION)!==false);
|
||||
$this->assertEquals(1,count($obj->VTIMEZONE));
|
||||
$this->assertEquals(1,count($obj->VEVENT));
|
||||
|
||||
}
|
||||
function testBeforeMethodNoVersion() {
|
||||
|
||||
if (!SABRE_HASSQLITE) $this->markTestSkipped('SQLite driver is not available');
|
||||
$cbackend = Sabre_CalDAV_TestUtil::getBackend();
|
||||
$pbackend = new Sabre_DAVACL_MockPrincipalBackend();
|
||||
|
||||
$props = array(
|
||||
'uri'=>'UUID-123467',
|
||||
'principaluri' => 'admin',
|
||||
'id' => 1,
|
||||
);
|
||||
$tree = array(
|
||||
new Sabre_CalDAV_Calendar($pbackend,$cbackend,$props),
|
||||
);
|
||||
|
||||
$p = new Sabre_CalDAV_ICSExportPlugin();
|
||||
|
||||
$s = new Sabre_DAV_Server($tree);
|
||||
|
||||
$s->addPlugin($p);
|
||||
$s->addPlugin(new Sabre_CalDAV_Plugin());
|
||||
|
||||
$h = new Sabre_HTTP_Request(array(
|
||||
'QUERY_STRING' => 'export',
|
||||
));
|
||||
|
||||
$s->httpRequest = $h;
|
||||
$s->httpResponse = new Sabre_HTTP_ResponseMock();
|
||||
|
||||
Sabre_DAV_Server::$exposeVersion = false;
|
||||
$this->assertFalse($p->beforeMethod('GET','UUID-123467?export'));
|
||||
Sabre_DAV_Server::$exposeVersion = true;
|
||||
|
||||
$this->assertEquals('HTTP/1.1 200 OK',$s->httpResponse->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'text/calendar',
|
||||
), $s->httpResponse->headers);
|
||||
|
||||
$obj = Sabre_VObject_Reader::read($s->httpResponse->body);
|
||||
|
||||
$this->assertEquals(5,count($obj->children()));
|
||||
$this->assertEquals(1,count($obj->VERSION));
|
||||
$this->assertEquals(1,count($obj->CALSCALE));
|
||||
$this->assertEquals(1,count($obj->PRODID));
|
||||
$this->assertFalse(strpos((string)$obj->PRODID, Sabre_DAV_Version::VERSION)!==false);
|
||||
$this->assertEquals(1,count($obj->VTIMEZONE));
|
||||
$this->assertEquals(1,count($obj->VEVENT));
|
||||
|
||||
|
|
96
dav/SabreDAV/tests/Sabre/CalDAV/Issue220Test.php
Normal file
96
dav/SabreDAV/tests/Sabre/CalDAV/Issue220Test.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This unittest is created to check for an endless loop in Sabre_CalDAV_CalendarQueryValidator
|
||||
*
|
||||
*
|
||||
* @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_Issue220Test extends Sabre_DAVServerTest {
|
||||
|
||||
protected $setupCalDAV = true;
|
||||
|
||||
protected $caldavCalendars = array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'name' => 'Calendar',
|
||||
'principaluri' => 'principals/user1',
|
||||
'uri' => 'calendar1',
|
||||
)
|
||||
);
|
||||
|
||||
protected $caldavCalendarObjects = array(
|
||||
1 => array(
|
||||
'event.ics' => array(
|
||||
'calendardata' => 'BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=Europe/Berlin:20120601T180000
|
||||
SUMMARY:Brot backen
|
||||
RRULE:FREQ=DAILY;INTERVAL=1;WKST=MO
|
||||
TRANSP:OPAQUE
|
||||
DURATION:PT20M
|
||||
LAST-MODIFIED:20120601T064634Z
|
||||
CREATED:20120601T064634Z
|
||||
DTSTAMP:20120601T064634Z
|
||||
UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd
|
||||
BEGIN:VALARM
|
||||
TRIGGER;VALUE=DURATION:-PT5M
|
||||
ACTION:DISPLAY
|
||||
DESCRIPTION:Default Event Notification
|
||||
X-WR-ALARMUID:cd952c1b-b3d6-41fb-b0a6-ec3a1a5bdd58
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=Europe/Berlin:20120606T180000
|
||||
SUMMARY:Brot backen
|
||||
TRANSP:OPAQUE
|
||||
STATUS:CANCELLED
|
||||
DTEND;TZID=Europe/Berlin:20120606T182000
|
||||
LAST-MODIFIED:20120605T094310Z
|
||||
SEQUENCE:1
|
||||
RECURRENCE-ID:20120606T160000Z
|
||||
UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
function testIssue220() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'REPORT',
|
||||
'HTTP_CONTENT_TYPE' => 'application/xml',
|
||||
'REQUEST_URI' => '/calendars/user1/calendar1',
|
||||
'HTTP_DEPTH' => '1',
|
||||
));
|
||||
|
||||
$request->setBody('<?xml version="1.0" encoding="utf-8" ?>
|
||||
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
|
||||
<D:prop>
|
||||
<C:calendar-data/>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
<C:filter>
|
||||
<C:comp-filter name="VCALENDAR">
|
||||
<C:comp-filter name="VEVENT">
|
||||
<C:comp-filter name="VALARM">
|
||||
<C:time-range start="20120607T161646Z" end="20120612T161646Z"/>
|
||||
</C:comp-filter>
|
||||
</C:comp-filter>
|
||||
</C:comp-filter>
|
||||
</C:filter>
|
||||
</C:calendar-query>');
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertFalse(strpos($response->body, '<s:exception>PHPUnit_Framework_Error_Warning</s:exception>'), 'Error Warning occurred: ' . $response->body);
|
||||
$this->assertFalse(strpos($response->body, 'Invalid argument supplied for foreach()'), 'Invalid argument supplied for foreach(): ' . $response->body);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Notifications_CollectionTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testGetChildren() {
|
||||
|
||||
$principalUri = 'principals/user1';
|
||||
|
||||
$systemStatus = new Sabre_CalDAV_Notifications_Notification_SystemStatus(1);
|
||||
|
||||
$caldavBackend = new Sabre_CalDAV_Backend_Mock(array(),array(), array(
|
||||
'principals/user1' => array(
|
||||
$systemStatus
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
$col = new Sabre_CalDAV_Notifications_Collection($caldavBackend, $principalUri);
|
||||
$this->assertEquals('notifications', $col->getName());
|
||||
|
||||
$this->assertEquals(array(
|
||||
new Sabre_CalDAV_Notifications_Node($caldavBackend, $systemStatus)
|
||||
), $col->getChildren());
|
||||
|
||||
}
|
||||
|
||||
}
|
23
dav/SabreDAV/tests/Sabre/CalDAV/Notifications/NodeTest.php
Normal file
23
dav/SabreDAV/tests/Sabre/CalDAV/Notifications/NodeTest.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Notifications_NodeTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testGetId() {
|
||||
|
||||
$principalUri = 'principals/user1';
|
||||
|
||||
$systemStatus = new Sabre_CalDAV_Notifications_Notification_SystemStatus(1);
|
||||
|
||||
$caldavBackend = new Sabre_CalDAV_Backend_Mock(array(),array(), array(
|
||||
'principals/user1' => array(
|
||||
$systemStatus
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
$node = new Sabre_CalDAV_Notifications_Node($caldavBackend, $systemStatus);
|
||||
$this->assertEquals($systemStatus->getId(), $node->getName());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Notifications_Notification extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
function testSerializers($notification, $expected1, $expected2) {
|
||||
|
||||
$this->assertEquals('foo', $notification->getId());
|
||||
|
||||
|
||||
$dom = new DOMDocument('1.0','UTF-8');
|
||||
$elem = $dom->createElement('cs:root');
|
||||
$elem->setAttribute('xmlns:cs',Sabre_CalDAV_Plugin::NS_CALENDARSERVER);
|
||||
$dom->appendChild($elem);
|
||||
$notification->serialize(new Sabre_DAV_Server(), $elem);
|
||||
$this->assertEquals($expected1, $dom->saveXML());
|
||||
|
||||
$dom = new DOMDocument('1.0','UTF-8');
|
||||
$elem = $dom->createElement('cs:root');
|
||||
$elem->setAttribute('xmlns:cs',Sabre_CalDAV_Plugin::NS_CALENDARSERVER);
|
||||
$dom->appendChild($elem);
|
||||
$notification->serializeBody(new Sabre_DAV_Server(), $elem);
|
||||
$this->assertEquals($expected2, $dom->saveXML());
|
||||
|
||||
|
||||
}
|
||||
|
||||
function dataProvider() {
|
||||
|
||||
return array(
|
||||
|
||||
array(
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo'),
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="high"/></cs:root>' . "\n",
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="high"/></cs:root>' . "\n",
|
||||
),
|
||||
|
||||
array(
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo',Sabre_CalDAV_Notifications_Notification_SystemStatus::TYPE_MEDIUM,'bar'),
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="medium"/></cs:root>' . "\n",
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="medium"><cs:description>bar</cs:description></cs:systemstatus></cs:root>' . "\n",
|
||||
),
|
||||
|
||||
array(
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo',Sabre_CalDAV_Notifications_Notification_SystemStatus::TYPE_LOW,null,'http://example.org/'),
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="low"/></cs:root>' . "\n",
|
||||
'<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<cs:root xmlns:cs="http://calendarserver.org/ns/"><cs:systemstatus type="low"><d:href>http://example.org/</d:href></cs:systemstatus></cs:root>' . "\n",
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -191,7 +191,17 @@ class Sabre_CalDAV_OutboxPostTest extends Sabre_DAVServerTest {
|
|||
|
||||
$req->setBody(implode("\r\n",$body));
|
||||
|
||||
$this->assertHTTPStatus(501, $req);
|
||||
|
||||
$response = $this->request($req);
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $response->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $response->headers);
|
||||
|
||||
// Lazily checking the body for a few expected values.
|
||||
$this->assertTrue(strpos($response->body, '5.2;')!==false);
|
||||
$this->assertTrue(strpos($response->body,'user2@example.org')!==false);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -218,7 +228,66 @@ class Sabre_CalDAV_OutboxPostTest extends Sabre_DAVServerTest {
|
|||
$handler = new Sabre_CalDAV_Schedule_IMip_Mock('server@example.org');
|
||||
|
||||
$this->caldavPlugin->setIMIPhandler($handler);
|
||||
$this->assertHTTPStatus(200, $req);
|
||||
|
||||
$response = $this->request($req);
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $response->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $response->headers);
|
||||
|
||||
// Lazily checking the body for a few expected values.
|
||||
$this->assertTrue(strpos($response->body, '2.0;')!==false);
|
||||
$this->assertTrue(strpos($response->body,'user2@example.org')!==false);
|
||||
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
'to' => 'user2@example.org',
|
||||
'subject' => 'Invitation for: An invitation',
|
||||
'body' => implode("\r\n", $body) . "\r\n",
|
||||
'headers' => array(
|
||||
'Reply-To: user1.sabredav@sabredav.org',
|
||||
'From: server@example.org',
|
||||
'Content-Type: text/calendar; method=REQUEST; charset=utf-8',
|
||||
'X-Sabre-Version: ' . Sabre_DAV_Version::VERSION . '-' . Sabre_DAV_Version::STABILITY,
|
||||
),
|
||||
)
|
||||
), $handler->getSentEmails());
|
||||
|
||||
}
|
||||
|
||||
function testSuccessRequestUpperCased() {
|
||||
|
||||
$req = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'POST',
|
||||
'REQUEST_URI' => '/calendars/user1/outbox',
|
||||
'HTTP_ORIGINATOR' => 'MAILTO:user1.sabredav@sabredav.org',
|
||||
'HTTP_RECIPIENT' => 'MAILTO:user2@example.org',
|
||||
));
|
||||
|
||||
$body = array(
|
||||
'BEGIN:VCALENDAR',
|
||||
'METHOD:REQUEST',
|
||||
'BEGIN:VEVENT',
|
||||
'SUMMARY:An invitation',
|
||||
'END:VEVENT',
|
||||
'END:VCALENDAR',
|
||||
);
|
||||
|
||||
$req->setBody(implode("\r\n",$body));
|
||||
|
||||
$handler = new Sabre_CalDAV_Schedule_IMip_Mock('server@example.org');
|
||||
|
||||
$this->caldavPlugin->setIMIPhandler($handler);
|
||||
|
||||
$response = $this->request($req);
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $response->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $response->headers);
|
||||
|
||||
// Lazily checking the body for a few expected values.
|
||||
$this->assertTrue(strpos($response->body, '2.0;')!==false);
|
||||
$this->assertTrue(strpos($response->body,'user2@example.org')!==false);
|
||||
|
||||
$this->assertEquals(array(
|
||||
array(
|
||||
|
|
|
@ -23,8 +23,34 @@ class Sabre_CalDAV_PluginTest extends PHPUnit_Framework_TestCase {
|
|||
|
||||
function setup() {
|
||||
|
||||
if (!SABRE_HASSQLITE) $this->markTestSkipped('No PDO SQLite support');
|
||||
$this->caldavBackend = Sabre_CalDAV_TestUtil::getBackend();
|
||||
$this->caldavBackend = new Sabre_CalDAV_Backend_Mock(array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'uri' => 'UUID-123467',
|
||||
'principaluri' => 'principals/user1',
|
||||
'{DAV:}displayname' => 'user1 calendar',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
|
||||
'{http://apple.com/ns/ical/}calendar-order' => '1',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array('VEVENT','VTODO')),
|
||||
),
|
||||
array(
|
||||
'id' => 2,
|
||||
'uri' => 'UUID-123468',
|
||||
'principaluri' => 'principals/user1',
|
||||
'{DAV:}displayname' => 'user1 calendar2',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description',
|
||||
'{http://apple.com/ns/ical/}calendar-order' => '1',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet(array('VEVENT','VTODO')),
|
||||
)
|
||||
), array(
|
||||
1 => array(
|
||||
'UUID-2345' => array(
|
||||
'calendardata' => Sabre_CalDAV_TestUtil::getTestCalendarData(),
|
||||
)
|
||||
)
|
||||
));
|
||||
$principalBackend = new Sabre_DAVACL_MockPrincipalBackend();
|
||||
$principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-read',array('principals/user1'));
|
||||
$principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-write',array('principals/user1'));
|
||||
|
@ -398,6 +424,7 @@ END:VCALENDAR';
|
|||
'{urn:ietf:params:xml:ns:caldav}calendar-user-address-set',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}calendar-proxy-read-for',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}calendar-proxy-write-for',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}notification-URL',
|
||||
));
|
||||
|
||||
$this->assertArrayHasKey(0,$props);
|
||||
|
@ -414,6 +441,12 @@ END:VCALENDAR';
|
|||
$this->assertTrue($prop instanceof Sabre_DAV_Property_Href);
|
||||
$this->assertEquals('calendars/user1/outbox',$prop->getHref());
|
||||
|
||||
$this->assertArrayHasKey('{'.Sabre_CalDAV_Plugin::NS_CALENDARSERVER .'}notification-URL',$props[0][200]);
|
||||
$prop = $props[0][200]['{'.Sabre_CalDAV_Plugin::NS_CALENDARSERVER .'}notification-URL'];
|
||||
$this->assertTrue($prop instanceof Sabre_DAV_Property_Href);
|
||||
$this->assertEquals('calendars/user1/notifications/',$prop->getHref());
|
||||
|
||||
|
||||
$this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-address-set',$props[0][200]);
|
||||
$prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set'];
|
||||
$this->assertTrue($prop instanceof Sabre_DAV_Property_HrefList);
|
||||
|
@ -429,6 +462,7 @@ END:VCALENDAR';
|
|||
$this->assertInstanceOf('Sabre_DAV_Property_HrefList', $prop);
|
||||
$this->assertEquals(array('principals/admin'), $prop->getHrefs());
|
||||
|
||||
|
||||
}
|
||||
|
||||
function testSupportedReportSetPropertyNonCalendar() {
|
||||
|
@ -502,9 +536,9 @@ END:VCALENDAR';
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
|
||||
|
||||
$xml = simplexml_load_string(Sabre_DAV_XMLUtil::convertDAVNamespace($this->response->body));
|
||||
$xml = simplexml_load_string($this->response->body);
|
||||
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
|
||||
|
||||
$check = array(
|
||||
|
@ -564,9 +598,9 @@ END:VCALENDAR';
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
|
||||
|
||||
$xml = simplexml_load_string(Sabre_DAV_XMLUtil::convertDAVNamespace($this->response->body));
|
||||
$xml = simplexml_load_string($this->response->body);
|
||||
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
|
||||
|
||||
$check = array(
|
||||
|
@ -629,9 +663,9 @@ END:VCALENDAR';
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
|
||||
|
||||
$xml = simplexml_load_string(Sabre_DAV_XMLUtil::convertDAVNamespace($this->response->body));
|
||||
$xml = simplexml_load_string($this->response->body);
|
||||
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
|
||||
|
||||
$check = array(
|
||||
|
@ -688,9 +722,9 @@ END:VCALENDAR';
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
|
||||
|
||||
$xml = simplexml_load_string(Sabre_DAV_XMLUtil::convertDAVNamespace($this->response->body));
|
||||
$xml = simplexml_load_string($this->response->body);
|
||||
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
|
||||
|
||||
$check = array(
|
||||
|
@ -777,9 +811,9 @@ END:VCALENDAR';
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
|
||||
|
||||
$xml = simplexml_load_string(Sabre_DAV_XMLUtil::convertDAVNamespace($this->response->body));
|
||||
$xml = simplexml_load_string($this->response->body);
|
||||
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
|
||||
|
||||
$check = array(
|
||||
|
@ -837,9 +871,9 @@ END:VCALENDAR';
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body);
|
||||
|
||||
$xml = simplexml_load_string(Sabre_DAV_XMLUtil::convertDAVNamespace($this->response->body));
|
||||
$xml = simplexml_load_string($this->response->body);
|
||||
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav');
|
||||
|
||||
$check = array(
|
||||
|
@ -991,4 +1025,60 @@ END:VCALENDAR';
|
|||
$this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body);
|
||||
|
||||
}
|
||||
|
||||
function testNotificationProperties() {
|
||||
|
||||
$request = array(
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}notificationtype',
|
||||
);
|
||||
$result = array();
|
||||
$notification = new Sabre_CalDAV_Notifications_Node(
|
||||
$this->caldavBackend,
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo')
|
||||
);
|
||||
$this->plugin->beforeGetProperties('foo', $notification, $request, $result);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
200 => array(
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}notificationtype' => $notification->getNotificationType()
|
||||
)
|
||||
), $result);
|
||||
|
||||
}
|
||||
|
||||
function testNotificationGet() {
|
||||
|
||||
$notification = new Sabre_CalDAV_Notifications_Node(
|
||||
$this->caldavBackend,
|
||||
new Sabre_CalDAV_Notifications_Notification_SystemStatus('foo')
|
||||
);
|
||||
|
||||
$server = new Sabre_DAV_Server(array($notification));
|
||||
$caldav = new Sabre_CalDAV_Plugin();
|
||||
|
||||
$httpResponse = new Sabre_HTTP_ResponseMock();
|
||||
$server->httpResponse = $httpResponse;
|
||||
|
||||
$server->addPlugin($caldav);
|
||||
|
||||
$caldav->beforeMethod('GET','foo');
|
||||
|
||||
$this->assertEquals('HTTP/1.1 200 OK', $httpResponse->status);
|
||||
$this->assertEquals(array(
|
||||
'Content-Type' => 'application/xml',
|
||||
), $httpResponse->headers);
|
||||
|
||||
$expected =
|
||||
'<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cs:notification xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
|
||||
<cs:systemstatus type="high"/>
|
||||
</cs:notification>
|
||||
';
|
||||
|
||||
$this->assertEquals($expected, $httpResponse->body);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,13 @@ class Sabre_CalDAV_ValidateICalTest extends PHPUnit_Framework_TestCase {
|
|||
'id' => 'calendar1',
|
||||
'principaluri' => 'principals/admin',
|
||||
'uri' => 'calendar1',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet( array('VEVENT','VTODO','VJOURNAL') ),
|
||||
),
|
||||
array(
|
||||
'id' => 'calendar2',
|
||||
'principaluri' => 'principals/admin',
|
||||
'uri' => 'calendar2',
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet( array('VTODO','VJOURNAL') ),
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -207,4 +214,33 @@ class Sabre_CalDAV_ValidateICalTest extends PHPUnit_Framework_TestCase {
|
|||
$this->assertEquals($expected, $this->calBackend->getCalendarObject('calendar1','blabla.ics'));
|
||||
|
||||
}
|
||||
|
||||
function testCreateFileInvalidComponent() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics',
|
||||
));
|
||||
$request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 403 Forbidden', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
|
||||
}
|
||||
|
||||
function testUpdateFileInvalidComponent() {
|
||||
|
||||
$this->calBackend->createCalendarObject('calendar2','blabla.ics','foo');
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics',
|
||||
));
|
||||
$request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 403 Forbidden', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,20 +65,35 @@ class Sabre_CardDAV_ValidateVCardTest extends PHPUnit_Framework_TestCase {
|
|||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf',
|
||||
));
|
||||
$request->setBody("BEGIN:VCARD\r\nEND:VCARD\r\n");
|
||||
$request->setBody("BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 201 Created', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
$expected = array(
|
||||
'uri' => 'blabla.vcf',
|
||||
'carddata' => "BEGIN:VCARD\r\nEND:VCARD\r\n",
|
||||
'carddata' => "BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n",
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $this->cardBackend->getCard('addressbook1','blabla.vcf'));
|
||||
|
||||
}
|
||||
|
||||
function testCreateFileNoUID() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf',
|
||||
));
|
||||
$request->setBody("BEGIN:VCARD\r\nEND:VCARD\r\n");
|
||||
|
||||
$response = $this->request($request);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Incorrect status returned! Full response body: ' . $response->body);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function testCreateFileVCalendar() {
|
||||
|
||||
$request = new Sabre_HTTP_Request(array(
|
||||
|
@ -114,7 +129,7 @@ class Sabre_CardDAV_ValidateVCardTest extends PHPUnit_Framework_TestCase {
|
|||
'REQUEST_METHOD' => 'PUT',
|
||||
'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf',
|
||||
));
|
||||
$body = "BEGIN:VCARD\r\nEND:VCARD\r\n";
|
||||
$body = "BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n";
|
||||
$request->setBody($body);
|
||||
|
||||
$response = $this->request($request);
|
||||
|
|
|
@ -92,9 +92,9 @@ class Sabre_DAV_Locks_PluginTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
$this->assertEquals('HTTP/1.1 200 OK',$this->response->status,'Got an incorrect status back. Response body: ' . $this->response->body);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
|
||||
$elements = array(
|
||||
'/d:prop',
|
||||
|
|
|
@ -60,7 +60,7 @@ class Sabre_DAV_Property_HrefListTest extends PHPUnit_Framework_TestCase {
|
|||
function testUnserialize() {
|
||||
|
||||
$xml = '<?xml version="1.0"?>
|
||||
<d:anything xmlns:d="urn:DAV"><d:href>/bla/foo</d:href><d:href>/bla/bar</d:href></d:anything>
|
||||
<d:anything xmlns:d="DAV:"><d:href>/bla/foo</d:href><d:href>/bla/bar</d:href></d:anything>
|
||||
';
|
||||
|
||||
$dom = new DOMDocument();
|
||||
|
@ -74,7 +74,7 @@ class Sabre_DAV_Property_HrefListTest extends PHPUnit_Framework_TestCase {
|
|||
function testUnserializeIncompatible() {
|
||||
|
||||
$xml = '<?xml version="1.0"?>
|
||||
<d:anything xmlns:d="urn:DAV"><d:href2>/bla/foo</d:href2></d:anything>
|
||||
<d:anything xmlns:d="DAV:"><d:href2>/bla/foo</d:href2></d:anything>
|
||||
';
|
||||
|
||||
$dom = new DOMDocument();
|
||||
|
|
|
@ -60,7 +60,7 @@ class Sabre_DAV_Property_HrefTest extends PHPUnit_Framework_TestCase {
|
|||
function testUnserialize() {
|
||||
|
||||
$xml = '<?xml version="1.0"?>
|
||||
<d:anything xmlns:d="urn:DAV"><d:href>/bla/path</d:href></d:anything>
|
||||
<d:anything xmlns:d="DAV:"><d:href>/bla/path</d:href></d:anything>
|
||||
';
|
||||
|
||||
$dom = new DOMDocument();
|
||||
|
@ -74,7 +74,7 @@ class Sabre_DAV_Property_HrefTest extends PHPUnit_Framework_TestCase {
|
|||
function testUnserializeIncompatible() {
|
||||
|
||||
$xml = '<?xml version="1.0"?>
|
||||
<d:anything xmlns:d="urn:DAV"><d:href2>/bla/path</d:href2></d:anything>
|
||||
<d:anything xmlns:d="DAV:"><d:href2>/bla/path</d:href2></d:anything>
|
||||
';
|
||||
|
||||
$dom = new DOMDocument();
|
||||
|
|
|
@ -37,9 +37,9 @@ class Sabre_DAV_Property_SupportedReportSetTest extends Sabre_DAV_AbstractServer
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'We expected a multi-status response. Full response body: ' . $this->response->body);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
|
||||
$data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop');
|
||||
$this->assertEquals(1,count($data),'We expected 1 \'d:prop\' element');
|
||||
|
@ -74,9 +74,9 @@ class Sabre_DAV_Property_SupportedReportSetTest extends Sabre_DAV_AbstractServer
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'We expected a multi-status response. Full response body: ' . $this->response->body);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('x','http://www.rooftopsolutions.nl/testnamespace');
|
||||
|
||||
$data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop');
|
||||
|
|
|
@ -6,6 +6,8 @@ class Sabre_DAV_ServerEventsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
private $tempPath;
|
||||
|
||||
private $exception;
|
||||
|
||||
function testAfterBind() {
|
||||
|
||||
$this->server->subscribeEvent('afterBind',array($this,'afterBindHandler'));
|
||||
|
@ -47,5 +49,25 @@ class Sabre_DAV_ServerEventsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
}
|
||||
|
||||
function testException() {
|
||||
|
||||
$this->server->subscribeEvent('exception', array($this, 'exceptionHandler'));
|
||||
|
||||
$req = new Sabre_HTTP_Request(array(
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'REQUEST_URI' => '/not/exisitng',
|
||||
));
|
||||
$this->server->httpRequest = $req;
|
||||
$this->server->exec();
|
||||
|
||||
$this->assertInstanceOf('Sabre_DAV_Exception_NotFound', $this->exception);
|
||||
|
||||
}
|
||||
|
||||
function exceptionHandler(Exception $exception) {
|
||||
|
||||
$this->exception = $exception;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -192,7 +192,6 @@ class Sabre_DAV_ServerMKCOLTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testMKCOLIncorrectResourceType2
|
||||
*/
|
||||
|
@ -224,6 +223,38 @@ class Sabre_DAV_ServerMKCOLTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testMKCOLIncorrectResourceType2
|
||||
*/
|
||||
function testMKCOLWhiteSpaceResourceType() {
|
||||
|
||||
$serverVars = array(
|
||||
'REQUEST_URI' => '/testcol',
|
||||
'REQUEST_METHOD' => 'MKCOL',
|
||||
'HTTP_CONTENT_TYPE' => 'application/xml',
|
||||
);
|
||||
|
||||
$request = new Sabre_HTTP_Request($serverVars);
|
||||
$request->setBody('<?xml version="1.0"?>
|
||||
<mkcol xmlns="DAV:">
|
||||
<set>
|
||||
<prop>
|
||||
<resourcetype>
|
||||
<collection />
|
||||
</resourcetype>
|
||||
</prop>
|
||||
</set>
|
||||
</mkcol>');
|
||||
$this->server->httpRequest = ($request);
|
||||
$this->server->exec();
|
||||
|
||||
$this->assertEquals(array(
|
||||
'Content-Length' => '0',
|
||||
),$this->response->headers);
|
||||
|
||||
$this->assertEquals('HTTP/1.1 201 Created',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testMKCOLIncorrectResourceType2
|
||||
|
|
|
@ -58,9 +58,9 @@ class Sabre_DAV_ServerPropsTest extends Sabre_DAV_AbstractServer {
|
|||
$this->response->headers
|
||||
);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
|
||||
list($data) = $xml->xpath('/d:multistatus/d:response/d:href');
|
||||
$this->assertEquals('/',(string)$data,'href element should have been /');
|
||||
|
@ -81,9 +81,9 @@ class Sabre_DAV_ServerPropsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
$this->sendRequest($xml);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
|
||||
$data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry');
|
||||
$this->assertEquals(2,count($data),'We expected two \'d:lockentry\' tags');
|
||||
|
@ -115,9 +115,9 @@ class Sabre_DAV_ServerPropsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
$this->sendRequest($xml);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
|
||||
$data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:lockdiscovery');
|
||||
$this->assertEquals(1,count($data),'We expected a \'d:lockdiscovery\' tag');
|
||||
|
@ -134,9 +134,9 @@ class Sabre_DAV_ServerPropsTest extends Sabre_DAV_AbstractServer {
|
|||
</d:propfind>';
|
||||
|
||||
$this->sendRequest($xml);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$pathTests = array(
|
||||
'/d:multistatus',
|
||||
'/d:multistatus/d:response',
|
||||
|
@ -312,9 +312,9 @@ class Sabre_DAV_ServerPropsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
$this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'We got the wrong status. Full XML response: ' . $this->response->body);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('bla','http://www.rooftopsolutions.nl/testnamespace');
|
||||
|
||||
$data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop');
|
||||
|
@ -345,9 +345,9 @@ class Sabre_DAV_ServerPropsTest extends Sabre_DAV_AbstractServer {
|
|||
|
||||
$this->sendRequest($xml);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
$xml->registerXPathNamespace('bla','http://www.rooftopsolutions.nl/testnamespace');
|
||||
|
||||
$xpath='//bla:someprop';
|
||||
|
|
|
@ -233,9 +233,9 @@ class Sabre_DAV_TemporaryFileFilterTest extends Sabre_DAV_AbstractServer {
|
|||
'Content-Type' => 'application/xml; charset=utf-8',
|
||||
),$this->response->headers);
|
||||
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body);
|
||||
$body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"DAV:\"",$this->response->body);
|
||||
$xml = simplexml_load_string($body);
|
||||
$xml->registerXPathNamespace('d','urn:DAV');
|
||||
$xml->registerXPathNamespace('d','DAV:');
|
||||
|
||||
list($data) = $xml->xpath('/d:multistatus/d:response/d:href');
|
||||
$this->assertEquals('/._testput.txt',(string)$data,'href element should have been /._testput.txt');
|
||||
|
|
|
@ -37,6 +37,8 @@ class Sabre_DAV_Tree_FilesystemTest extends PHPUnit_Framework_TestCase {
|
|||
$fs = new Sabre_DAV_Tree_Filesystem(SABRE_TEMPDIR);
|
||||
$node = $fs->getNodeForPath('dir');
|
||||
$this->assertTrue($node instanceof Sabre_DAV_FS_Directory);
|
||||
$this->assertEquals('dir', $node->getName());
|
||||
$this->assertInternalType('array', $node->getChildren());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class Sabre_DAV_XMLUtilTest extends PHPUnit_Framework_TestCase {
|
|||
function testToClarkNotationDAVNamespace() {
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML('<?xml version="1.0"?><s:test1 xmlns:s="urn:DAV">Testdoc</s:test1>');
|
||||
$dom->loadXML('<?xml version="1.0"?><s:test1 xmlns:s="DAV:">Testdoc</s:test1>');
|
||||
|
||||
$this->assertEquals(
|
||||
'{DAV:}test1',
|
||||
|
@ -41,7 +41,7 @@ class Sabre_DAV_XMLUtilTest extends PHPUnit_Framework_TestCase {
|
|||
function testToClarkNotationNoElem() {
|
||||
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML('<?xml version="1.0"?><s:test1 xmlns:s="urn:DAV">Testdoc</s:test1>');
|
||||
$dom->loadXML('<?xml version="1.0"?><s:test1 xmlns:s="DAV:">Testdoc</s:test1>');
|
||||
|
||||
$this->assertNull(
|
||||
Sabre_DAV_XMLUtil::toClarkNotation($dom->firstChild->firstChild)
|
||||
|
@ -49,59 +49,6 @@ class Sabre_DAV_XMLUtilTest extends PHPUnit_Framework_TestCase {
|
|||
|
||||
}
|
||||
|
||||
function testConvertDAVNamespace() {
|
||||
|
||||
$xml='<?xml version="1.0"?><document xmlns="DAV:">blablabla</document>';
|
||||
$this->assertEquals(
|
||||
'<?xml version="1.0"?><document xmlns="urn:DAV">blablabla</document>',
|
||||
Sabre_DAV_XMLUtil::convertDAVNamespace($xml)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testConvertDAVNamespace2() {
|
||||
|
||||
$xml='<?xml version="1.0"?><s:document xmlns:s="DAV:">blablabla</s:document>';
|
||||
$this->assertEquals(
|
||||
'<?xml version="1.0"?><s:document xmlns:s="urn:DAV">blablabla</s:document>',
|
||||
Sabre_DAV_XMLUtil::convertDAVNamespace($xml)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testConvertDAVNamespace3() {
|
||||
|
||||
$xml='<?xml version="1.0"?><s:document xmlns="http://bla" xmlns:s="DAV:" xmlns:z="http://othernamespace">blablabla</s:document>';
|
||||
$this->assertEquals(
|
||||
'<?xml version="1.0"?><s:document xmlns="http://bla" xmlns:s="urn:DAV" xmlns:z="http://othernamespace">blablabla</s:document>',
|
||||
Sabre_DAV_XMLUtil::convertDAVNamespace($xml)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testConvertDAVNamespace4() {
|
||||
|
||||
$xml='<?xml version="1.0"?><document xmlns=\'DAV:\'>blablabla</document>';
|
||||
$this->assertEquals(
|
||||
'<?xml version="1.0"?><document xmlns=\'urn:DAV\'>blablabla</document>',
|
||||
Sabre_DAV_XMLUtil::convertDAVNamespace($xml)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testConvertDAVNamespaceMixedQuotes() {
|
||||
|
||||
$xml='<?xml version="1.0"?><document xmlns=\'DAV:" xmlns="Another attribute\'>blablabla</document>';
|
||||
$this->assertEquals(
|
||||
$xml,
|
||||
Sabre_DAV_XMLUtil::convertDAVNamespace($xml)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testConvertDAVNamespace
|
||||
*/
|
||||
function testLoadDOMDocument() {
|
||||
|
||||
$xml='<?xml version="1.0"?><document></document>';
|
||||
|
@ -121,7 +68,6 @@ class Sabre_DAV_XMLUtilTest extends PHPUnit_Framework_TestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* @depends testConvertDAVNamespace
|
||||
* @expectedException Sabre_DAV_Exception_BadRequest
|
||||
*/
|
||||
function testLoadDOMDocumentInvalid() {
|
||||
|
|
|
@ -60,6 +60,25 @@ class Sabre_HTTP_BasicAuthTest extends PHPUnit_Framework_TestCase {
|
|||
|
||||
}
|
||||
|
||||
function testGetUserPassWithColon() {
|
||||
|
||||
$server = array(
|
||||
'HTTP_AUTHORIZATION' => 'Basic ' . base64_encode('admin:1234:5678'),
|
||||
);
|
||||
|
||||
$request = new Sabre_HTTP_Request($server);
|
||||
$this->basicAuth->setHTTPRequest($request);
|
||||
|
||||
$userPass = $this->basicAuth->getUserPass();
|
||||
|
||||
$this->assertEquals(
|
||||
array('admin','1234:5678'),
|
||||
$userPass,
|
||||
'We did not get the username and password we expected'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testGetUserPassApacheEdgeCase() {
|
||||
|
||||
$server = array(
|
||||
|
|
|
@ -53,9 +53,14 @@ class Sabre_VObject_Component_VEventTest extends PHPUnit_Framework_TestCase {
|
|||
$vevent6->DTEND['VALUE'] = 'DATE';
|
||||
$tests[] = array($vevent6, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true);
|
||||
$tests[] = array($vevent6, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false);
|
||||
// Event with no end date should be treated as lasting the entire day.
|
||||
$tests[] = array($vevent6, new DateTime('2011-12-25 16:00:00'), new DateTime('2011-12-25 17:00:00'), true);
|
||||
|
||||
// Added this test to ensure that recurrence rules with no DTEND also
|
||||
// get checked for the entire day.
|
||||
$vevent7 = clone $vevent;
|
||||
$vevent7->DTSTART = '20120101';
|
||||
$vevent7->DTSTART['VALUE'] = 'DATE';
|
||||
$vevent7->RRULE = 'FREQ=MONTHLY';
|
||||
$tests[] = array($vevent7, new DateTime('2012-02-01 15:00:00'), new DateTime('2012-02-02'), true);
|
||||
return $tests;
|
||||
|
||||
}
|
||||
|
|
|
@ -340,11 +340,14 @@ class Sabre_VObject_ComponentTest extends PHPUnit_Framework_TestCase {
|
|||
new Sabre_VObject_Component('VEVENT'),
|
||||
new Sabre_VObject_Component('VTODO')
|
||||
);
|
||||
$this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $comp->serialize());
|
||||
|
||||
$str = $comp->serialize();
|
||||
|
||||
$this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", $str);
|
||||
|
||||
}
|
||||
|
||||
function testSerializeOrder() {
|
||||
function testSerializeOrderCompAndProp() {
|
||||
|
||||
$comp = new Sabre_VObject_Component('VCALENDAR');
|
||||
$comp->add(new Sabre_VObject_Component('VEVENT'));
|
||||
|
@ -358,4 +361,30 @@ class Sabre_VObject_ComponentTest extends PHPUnit_Framework_TestCase {
|
|||
|
||||
}
|
||||
|
||||
function testAnotherSerializeOrderProp() {
|
||||
|
||||
$prop4s=array('1', '2', '3', '4', '5', '6', '7', '8', '9', '10');
|
||||
|
||||
$comp = new Sabre_VObject_Component('VCARD');
|
||||
$comp->__set('SOMEPROP','FOO');
|
||||
$comp->__set('ANOTHERPROP','FOO');
|
||||
$comp->__set('THIRDPROP','FOO');
|
||||
foreach ($prop4s as $prop4) {
|
||||
$comp->add('PROP4', 'FOO '.$prop4);
|
||||
}
|
||||
$comp->__set('PROPNUMBERFIVE', 'FOO');
|
||||
$comp->__set('PROPNUMBERSIX', 'FOO');
|
||||
$comp->__set('PROPNUMBERSEVEN', 'FOO');
|
||||
$comp->__set('PROPNUMBEREIGHT', 'FOO');
|
||||
$comp->__set('PROPNUMBERNINE', 'FOO');
|
||||
$comp->__set('PROPNUMBERTEN', 'FOO');
|
||||
$comp->__set('VERSION','2.0');
|
||||
$comp->__set('UID', 'FOO');
|
||||
|
||||
$str = $comp->serialize();
|
||||
|
||||
$this->assertEquals("BEGIN:VCARD\r\nVERSION:2.0\r\nSOMEPROP:FOO\r\nANOTHERPROP:FOO\r\nTHIRDPROP:FOO\r\nPROP4:FOO 1\r\nPROP4:FOO 2\r\nPROP4:FOO 3\r\nPROP4:FOO 4\r\nPROP4:FOO 5\r\nPROP4:FOO 6\r\nPROP4:FOO 7\r\nPROP4:FOO 8\r\nPROP4:FOO 9\r\nPROP4:FOO 10\r\nPROPNUMBERFIVE:FOO\r\nPROPNUMBERSIX:FOO\r\nPROPNUMBERSEVEN:FOO\r\nPROPNUMBEREIGHT:FOO\r\nPROPNUMBERNINE:FOO\r\nPROPNUMBERTEN:FOO\r\nUID:FOO\r\nEND:VCARD\r\n", $str);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ class Sabre_VObject_Issue154Test extends PHPUnit_Framework_TestCase {
|
|||
|
||||
$vcard = new Sabre_VObject_Component('VCARD');
|
||||
$vcard->VERSION = '3.0';
|
||||
$vcard->UID = 'foo-bar';
|
||||
$vcard->PHOTO = base64_encode('random_stuff');
|
||||
$vcard->PHOTO->add('BASE64',null);
|
||||
$vcard->UID = 'foo-bar';
|
||||
|
||||
$result = $vcard->serialize();
|
||||
$expected = array(
|
||||
|
|
|
@ -707,6 +707,51 @@ class Sabre_VObject_RecurrenceIteratorTest extends PHPUnit_Framework_TestCase {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testValues
|
||||
*/
|
||||
function testYearlyLeapYear() {
|
||||
|
||||
$ev = new Sabre_VObject_Component('VEVENT');
|
||||
$ev->UID = 'bla';
|
||||
$ev->RRULE = 'FREQ=YEARLY;COUNT=3';
|
||||
$dtStart = new Sabre_VObject_Property_DateTime('DTSTART');
|
||||
$dtStart->setDateTime(new DateTime('2012-02-29'),Sabre_VObject_Property_DateTime::UTC);
|
||||
|
||||
$ev->add($dtStart);
|
||||
|
||||
$vcal = Sabre_VObject_Component::create('VCALENDAR');
|
||||
$vcal->add($ev);
|
||||
|
||||
$it = new Sabre_VObject_RecurrenceIterator($vcal,(string)$ev->uid);
|
||||
|
||||
$this->assertEquals('yearly', $it->frequency);
|
||||
$this->assertEquals(3, $it->count);
|
||||
|
||||
$max = 20;
|
||||
$result = array();
|
||||
foreach($it as $k=>$item) {
|
||||
|
||||
$result[] = $item;
|
||||
$max--;
|
||||
|
||||
if (!$max) break;
|
||||
|
||||
}
|
||||
|
||||
$tz = new DateTimeZone('UTC');
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
new DateTime('2012-02-29', $tz),
|
||||
new DateTime('2016-02-29', $tz),
|
||||
new DateTime('2020-02-29', $tz),
|
||||
),
|
||||
$result
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testValues
|
||||
*/
|
||||
|
|
153
dav/SabreDAV/tests/Sabre/VObject/TimeZoneUtilTest.php
Normal file
153
dav/SabreDAV/tests/Sabre/VObject/TimeZoneUtilTest.php
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
class Sabre_VObject_TimeZoneUtilTest extends PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @dataProvider getMapping
|
||||
*/
|
||||
function testCorrectTZ($timezoneName) {
|
||||
|
||||
$tz = new DateTimeZone($timezoneName);
|
||||
|
||||
}
|
||||
|
||||
function getMapping() {
|
||||
|
||||
// PHPUNit requires an array of arrays
|
||||
return array_map(
|
||||
function($value) {
|
||||
return array($value);
|
||||
},
|
||||
Sabre_VObject_TimeZoneUtil::$map
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function testExchangeMap() {
|
||||
|
||||
$vobj = <<<HI
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:REQUEST
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:foo
|
||||
X-MICROSOFT-CDO-TZID:2
|
||||
BEGIN:STANDARD
|
||||
DTSTART:16010101T030000
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
BEGIN:DAYLIGHT
|
||||
DTSTART:16010101T020000
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:20120416T092149Z
|
||||
DTSTART;TZID="foo":20120418T1
|
||||
00000
|
||||
SUMMARY:Begin Unterhaltsreinigung
|
||||
UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
|
||||
0100000008FECD2E607780649BE5A4C9EE6418CBC
|
||||
DTEND;TZID="Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb":20120418T103
|
||||
000
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
HI;
|
||||
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('foo', Sabre_VObject_Reader::read($vobj));
|
||||
|
||||
$this->assertEquals(new DateTimeZone('Europe/Sarajevo'), $tz);
|
||||
|
||||
}
|
||||
|
||||
function testUnknownExchangeId() {
|
||||
|
||||
$vobj = <<<HI
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:REQUEST
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:foo
|
||||
X-MICROSOFT-CDO-TZID:2000
|
||||
BEGIN:STANDARD
|
||||
DTSTART:16010101T030000
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
BEGIN:DAYLIGHT
|
||||
DTSTART:16010101T020000
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:20120416T092149Z
|
||||
DTSTART;TZID="foo":20120418T1
|
||||
00000
|
||||
SUMMARY:Begin Unterhaltsreinigung
|
||||
UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
|
||||
0100000008FECD2E607780649BE5A4C9EE6418CBC
|
||||
DTEND;TZID="Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb":20120418T103
|
||||
000
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
HI;
|
||||
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('foo', Sabre_VObject_Reader::read($vobj));
|
||||
|
||||
$this->assertEquals(new DateTimeZone(date_default_timezone_get()), $tz);
|
||||
|
||||
}
|
||||
|
||||
function testWindowsTimeZone() {
|
||||
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('Eastern Standard Time');
|
||||
$this->assertEquals(new DateTimeZone('America/New_York'), $tz);
|
||||
|
||||
}
|
||||
|
||||
function testFallBack() {
|
||||
|
||||
$vobj = <<<HI
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:REQUEST
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:foo
|
||||
BEGIN:STANDARD
|
||||
DTSTART:16010101T030000
|
||||
TZOFFSETFROM:+0200
|
||||
TZOFFSETTO:+0100
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
|
||||
END:STANDARD
|
||||
BEGIN:DAYLIGHT
|
||||
DTSTART:16010101T020000
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
|
||||
END:DAYLIGHT
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
DTSTAMP:20120416T092149Z
|
||||
DTSTART;TZID="foo":20120418T1
|
||||
00000
|
||||
SUMMARY:Begin Unterhaltsreinigung
|
||||
UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
|
||||
0100000008FECD2E607780649BE5A4C9EE6418CBC
|
||||
000
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
HI;
|
||||
$tz = Sabre_VObject_TimeZoneUtil::getTimeZone('foo', Sabre_VObject_Reader::read($vobj));
|
||||
|
||||
$this->assertEquals(new DateTimeZone(date_default_timezone_get()), $tz);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
$a = get_app();
|
||||
$uri = parse_url($a->get_baseurl());
|
||||
$a = get_app();
|
||||
$uri = parse_url($a->get_baseurl());
|
||||
$path = "/";
|
||||
if (strlen($uri["path"]) > 1) {
|
||||
if (isset($uri["path"]) && strlen($uri["path"]) > 1) {
|
||||
$path = $uri["path"] . "/";
|
||||
}
|
||||
|
||||
|
@ -12,33 +12,36 @@ define("CALDAV_SQL_PREFIX", "dav_");
|
|||
define("CALDAV_URL_PREFIX", $path . "dav/");
|
||||
|
||||
define("CALDAV_NAMESPACE_PRIVATE", 1);
|
||||
define("CALDAV_NAMESPACE_FRIENDICA_NATIVE", 2);
|
||||
|
||||
define("CALDAV_FRIENDICA_MINE", 1);
|
||||
define("CALDAV_FRIENDICA_CONTACTS", 2);
|
||||
define("CALDAV_FRIENDICA_MINE", "friendica-mine");
|
||||
define("CALDAV_FRIENDICA_CONTACTS", "friendica-contacts");
|
||||
|
||||
$GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"] = array(CALDAV_FRIENDICA_MINE, CALDAV_FRIENDICA_CONTACTS);
|
||||
|
||||
define("CARDDAV_NAMESPACE_COMMUNITYCONTACTS", 1);
|
||||
define("CARDDAV_NAMESPACE_PHONECONTACTS", 2);
|
||||
|
||||
define("CALDAV_DB_VERSION", 1);
|
||||
define("CALDAV_MAX_YEAR", date("Y") + 5);
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
function getCurMicrotime () {
|
||||
list($usec, $sec) = explode(" ", microtime());
|
||||
return sprintf("%14.0f", $sec * 10000 + $usec * 10000);
|
||||
function getCurMicrotime()
|
||||
{
|
||||
list($usec, $sec) = explode(" ", microtime());
|
||||
return sprintf("%14.0f", $sec * 10000 + $usec * 10000);
|
||||
} // function getCurMicrotime
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function debug_time() {
|
||||
$cur = getCurMicrotime();
|
||||
if ($GLOBALS["debug_time_last"] > 0) {
|
||||
echo "Zeit: " . ($cur - $GLOBALS["debug_time_last"]) . "<br>\n";
|
||||
}
|
||||
$GLOBALS["debug_time_last"] = $cur;
|
||||
function debug_time()
|
||||
{
|
||||
$cur = getCurMicrotime();
|
||||
if ($GLOBALS["debug_time_last"] > 0) {
|
||||
echo "Zeit: " . ($cur - $GLOBALS["debug_time_last"]) . "<br>\n";
|
||||
}
|
||||
$GLOBALS["debug_time_last"] = $cur;
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,7 +51,7 @@ function debug_time() {
|
|||
*/
|
||||
function dav_compat_username2id($username = "")
|
||||
{
|
||||
$x = q("SELECT `uid` FROM user WHERE nickname='%s' AND account_removed = 0 AND account_expired = 0", dbesc($username));
|
||||
$x = q("SELECT `uid` FROM `user` WHERE `nickname`='%s' AND `account_removed` = 0 AND `account_expired` = 0", dbesc($username));
|
||||
if (count($x) == 1) return $x[0]["uid"];
|
||||
return null;
|
||||
}
|
||||
|
@ -59,7 +62,7 @@ function dav_compat_username2id($username = "")
|
|||
*/
|
||||
function dav_compat_id2username($id = 0)
|
||||
{
|
||||
$x = q("SELECT `nickname` FROM user WHERE uid = %i AND account_removed = 0 AND account_expired = 0", IntVal($id));
|
||||
$x = q("SELECT `nickname` FROM `user` WHERE `uid` = %i AND `account_removed` = 0 AND `account_expired` = 0", IntVal($id));
|
||||
if (count($x) == 1) return $x[0]["nickname"];
|
||||
return "";
|
||||
}
|
||||
|
@ -67,7 +70,8 @@ function dav_compat_id2username($id = 0)
|
|||
/**
|
||||
* @return int
|
||||
*/
|
||||
function dav_compat_get_curr_user_id() {
|
||||
function dav_compat_get_curr_user_id()
|
||||
{
|
||||
$a = get_app();
|
||||
return IntVal($a->user["uid"]);
|
||||
}
|
||||
|
@ -86,13 +90,38 @@ function dav_compat_principal2uid($principalUri = "")
|
|||
return dav_compat_username2id($username);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $principalUri
|
||||
* @return array|null
|
||||
*/
|
||||
function dav_compat_principal2namespace($principalUri = "")
|
||||
{
|
||||
if (strlen($principalUri) == 0) return null;
|
||||
if ($principalUri[0] == "/") $principalUri = substr($principalUri, 1);
|
||||
|
||||
if (strpos($principalUri, "principals/users/") !== 0) return null;
|
||||
$username = substr($principalUri, strlen("principals/users/"));
|
||||
return array("namespace" => CALDAV_NAMESPACE_PRIVATE, "namespace_id" => dav_compat_username2id($username));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function dav_compat_currentUserPrincipal()
|
||||
{
|
||||
$a = get_app();
|
||||
return "principals/users/" . strtolower($a->user["nickname"]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return null|string
|
||||
*/
|
||||
function dav_compat_getRequestVar($name = "") {
|
||||
if (x($_REQUEST, $name)) return $_REQUEST[$name];
|
||||
function dav_compat_getRequestVar($name = "")
|
||||
{
|
||||
if (isset($_REQUEST[$name])) return $_REQUEST[$name];
|
||||
else return null;
|
||||
}
|
||||
|
||||
|
@ -108,28 +137,73 @@ function dav_compat_parse_text_serverside($text)
|
|||
/**
|
||||
* @param string $uri
|
||||
*/
|
||||
function dav_compat_redirect($uri = "") {
|
||||
function dav_compat_redirect($uri = "")
|
||||
{
|
||||
goaway($uri);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return null|int
|
||||
*/
|
||||
function dav_compat_get_max_private_calendars()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
* @param int $namespace
|
||||
* @param int $namespace_id
|
||||
* @return AnimexxCalSource
|
||||
* @param string $uri
|
||||
* @param array $calendar
|
||||
* @return Sabre_CalDAV_Backend_Common
|
||||
* @throws Exception
|
||||
*/
|
||||
function wdcal_calendar_factory($user_id, $namespace, $namespace_id)
|
||||
function wdcal_calendar_factory($namespace, $namespace_id, $uri, $calendar = null)
|
||||
{
|
||||
switch ($namespace) {
|
||||
case CALDAV_NAMESPACE_PRIVATE:
|
||||
return new AnimexxCalSourcePrivate($user_id, $namespace_id);
|
||||
case CALDAV_NAMESPACE_FRIENDICA_NATIVE:
|
||||
return new FriendicaCalSourceEvents($user_id, $namespace_id);
|
||||
if ($uri == CALDAV_FRIENDICA_MINE || $uri == CALDAV_FRIENDICA_CONTACTS) return Sabre_CalDAV_Backend_Friendica::getInstance();
|
||||
else return Sabre_CalDAV_Backend_Private::getInstance();
|
||||
}
|
||||
throw new Exception("Calendar Namespace not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendar_id
|
||||
* @return Sabre_CalDAV_Backend_Common
|
||||
* @throws Exception
|
||||
*/
|
||||
function wdcal_calendar_factory_by_id($calendar_id)
|
||||
{
|
||||
$calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendar_id);
|
||||
return wdcal_calendar_factory($calendar["namespace"], $calendar["namespace_id"], $calendar["uri"], $calendar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
* @param bool $withcheck
|
||||
* @return array
|
||||
*/
|
||||
function wdcal_create_std_calendars_get_statements($user_id, $withcheck = true)
|
||||
{
|
||||
$stms = array();
|
||||
$a = get_app();
|
||||
$uris = array(
|
||||
'private' => t("Private Calendar"),
|
||||
CALDAV_FRIENDICA_MINE => t("Friendica Events: Mine"),
|
||||
CALDAV_FRIENDICA_CONTACTS => t("Friendica Events: Contacts"),
|
||||
);
|
||||
foreach ($uris as $uri => $name) {
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($uri));
|
||||
if (count($cals) == 0 || !$withcheck) $stms[] =
|
||||
sprintf("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `displayname`, `timezone`, `ctag`, `uri`, `has_vevent`, `has_vtodo`)
|
||||
VALUES (%d, %d, '%s', '%s', 1, '%s', 1, 0)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($user_id), dbesc($name), dbesc($a->timezone), dbesc($uri));
|
||||
}
|
||||
return $stms;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
@ -138,27 +212,9 @@ function wdcal_create_std_calendars()
|
|||
$a = get_app();
|
||||
if (!local_user()) return;
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `uid` = %d AND `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $a->user["uid"], CALDAV_NAMESPACE_PRIVATE);
|
||||
if (count($cals) == 0) {
|
||||
$maxid = q("SELECT MAX(`namespace_id`) maxid FROM %s%scalendars WHERE `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE);
|
||||
if (!$maxid) {
|
||||
notification("Something went wrong when trying to create your calendar.");
|
||||
goaway("/");
|
||||
killme();
|
||||
}
|
||||
$nextid = IntVal($maxid[0]["maxid"]) + 1;
|
||||
q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `uid`, `displayname`, `timezone`, `ctag`) VALUES (%d, %d, %d, '%s', '%s', 1)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $nextid, $a->user["uid"], dbesc(t("Private Calendar")), dbesc($a->timezone)
|
||||
);
|
||||
}
|
||||
$privates = q("SELECT COUNT(*) num FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, IntVal($a->user["uid"]));
|
||||
if ($privates[0]["num"] > 0) return;
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `uid` = %d AND `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $a->user["uid"], CALDAV_NAMESPACE_FRIENDICA_NATIVE);
|
||||
if (count($cals) < 2) {
|
||||
q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `uid`, `displayname`, `timezone`, `ctag`) VALUES (%d, %d, %d, '%s', '%s', 1)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_FRIENDICA_NATIVE, CALDAV_FRIENDICA_MINE, $a->user["uid"], dbesc(t("Friendica Events: Mine")), dbesc($a->timezone)
|
||||
);
|
||||
q("INSERT INTO %s%scalendars (`namespace`, `namespace_id`, `uid`, `displayname`, `timezone`, `ctag`) VALUES (%d, %d, %d, '%s', '%s', 1)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_FRIENDICA_NATIVE, CALDAV_FRIENDICA_CONTACTS, $a->user["uid"], dbesc(t("Friendica Events: Contacts")), dbesc($a->timezone)
|
||||
);
|
||||
}
|
||||
$stms = wdcal_create_std_calendars_get_statements($a->user["uid"]);
|
||||
foreach ($stms as $stmt) q($stmt);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<title>Really Simple Color Picker</title>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<script language="javascript" type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
||||
<script language="javascript" type="text/javascript" src="jquery.colorPicker.min.js"/></script>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="jquery.colorPicker.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
//Run the code when document ready
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
<?php
|
||||
|
||||
|
||||
define("DAV_ACL_READ", "{DAV:}read");
|
||||
define("DAV_ACL_WRITE", "{DAV:}write");
|
||||
define("DAV_DISPLAYNAME", "{DAV:}displayname");
|
||||
define("DAV_CALENDARCOLOR", "{http://apple.com/ns/ical/}calendar-color");
|
||||
|
||||
|
||||
class DAVVersionMismatchException extends Exception {}
|
||||
|
||||
|
||||
class vcard_source_data_email
|
||||
{
|
||||
public $email, $type;
|
||||
|
@ -83,7 +92,7 @@ class vcard_source_data
|
|||
/** @var array|vcard_source_data_email[] $email */
|
||||
public $emails;
|
||||
|
||||
/** @var array|vcard_source_data_addresses[] $addresses */
|
||||
/** @var array|vcard_source_data_address[] $addresses */
|
||||
public $addresses;
|
||||
|
||||
/** @var vcard_source_data_photo */
|
||||
|
@ -136,41 +145,6 @@ function vcard_source_compile($vcardsource)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $start
|
||||
* @param array $end
|
||||
* @param bool $allday
|
||||
* @return vevent
|
||||
*/
|
||||
function dav_create_vevent($start, $end, $allday)
|
||||
{
|
||||
if ($end["year"] < $start["year"] ||
|
||||
($end["year"] == $start["year"] && $end["month"] < $start["month"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] < $start["day"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] == $start["day"] && $end["hour"] < $start["hour"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] == $start["day"] && $end["hour"] == $start["hour"] && $end["minute"] < $start["minute"]) ||
|
||||
($end["year"] == $start["year"] && $end["month"] == $start["month"] && $end["day"] == $start["day"] && $end["hour"] == $start["hour"] && $end["minute"] == $start["minute"] && $end["second"] < $start["second"])
|
||||
) {
|
||||
$end = $start;
|
||||
} // DTEND muss <= DTSTART
|
||||
|
||||
$vevent = new vevent();
|
||||
if ($allday) {
|
||||
$vevent->setDtstart($start["year"], $start["month"], $start["day"], FALSE, FALSE, FALSE, FALSE, array("VALUE"=> "DATE"));
|
||||
$end = IntVal(mktime(0, 0, 0, $end["month"], $end["day"], $end["year"]) + 3600 * 24);
|
||||
|
||||
// If a DST change occurs on the current day
|
||||
$end += IntVal(date("Z", ($end - 3600 * 24)) - date("Z", $end));
|
||||
|
||||
$vevent->setDtend(date("Y", $end), date("m", $end), date("d", $end), FALSE, FALSE, FALSE, FALSE, array("VALUE"=> "DATE"));
|
||||
} else {
|
||||
$vevent->setDtstart($start["year"], $start["month"], $start["day"], $start["hour"], $start["minute"], $start["second"], FALSE, array("VALUE"=> "DATE-TIME"));
|
||||
$vevent->setDtend($end["year"], $end["month"], $end["day"], $end["hour"], $end["minute"], $end["second"], FALSE, array("VALUE"=> "DATE-TIME"));
|
||||
}
|
||||
return $vevent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $phpDate (UTC)
|
||||
* @return string (Lokalzeit)
|
||||
|
@ -213,460 +187,192 @@ function wdcal_mySql2icalTime($myqlDate)
|
|||
*/
|
||||
function icalendar_sanitize_string($str = "")
|
||||
{
|
||||
$str = str_replace("\r\n", "\n", $str);
|
||||
$str = str_replace("\n\r", "\n", $str);
|
||||
$str = str_replace("\r", "\n", $str);
|
||||
return $str;
|
||||
return preg_replace("/[\\r\\n]+/siu", "\r\n", $str);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param DBClass_friendica_calendars $calendar
|
||||
* @param DBClass_friendica_calendarobjects $calendarobject
|
||||
* @return Sabre_CalDAV_AnimexxCalendarRootNode
|
||||
*/
|
||||
function renderCalDavEntry_data(&$calendar, &$calendarobject)
|
||||
function dav_createRootCalendarNode()
|
||||
{
|
||||
$caldavBackend_std = Sabre_CalDAV_Backend_Private::getInstance();
|
||||
$caldavBackend_community = Sabre_CalDAV_Backend_Friendica::getInstance();
|
||||
|
||||
return new Sabre_CalDAV_AnimexxCalendarRootNode(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), array(
|
||||
$caldavBackend_std,
|
||||
$caldavBackend_community,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Sabre_CardDAV_AddressBookRootFriendica
|
||||
*/
|
||||
function dav_createRootContactsNode()
|
||||
{
|
||||
$carddavBackend_std = Sabre_CardDAV_Backend_Std::getInstance();
|
||||
$carddavBackend_community = Sabre_CardDAV_Backend_FriendicaCommunity::getInstance();
|
||||
|
||||
return new Sabre_CardDAV_AddressBookRootFriendica(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), array(
|
||||
$carddavBackend_std,
|
||||
$carddavBackend_community,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $force_authentication
|
||||
* @param bool $needs_caldav
|
||||
* @param bool $needs_carddav
|
||||
* @return Sabre_DAV_Server
|
||||
*/
|
||||
function dav_create_server($force_authentication = false, $needs_caldav = true, $needs_carddav = true)
|
||||
{
|
||||
$arr = array(
|
||||
new Sabre_DAV_SimpleCollection('principals', array(
|
||||
new Sabre_CalDAV_Principal_Collection(Sabre_DAVACL_PrincipalBackend_Std::getInstance(), "principals/users"),
|
||||
)),
|
||||
);
|
||||
if ($needs_caldav) $arr[] = dav_createRootCalendarNode();
|
||||
if ($needs_carddav) $arr[] = dav_createRootContactsNode();
|
||||
|
||||
|
||||
$tree = new Sabre_DAV_SimpleCollection('root', $arr);
|
||||
|
||||
// The object tree needs in turn to be passed to the server class
|
||||
$server = new Sabre_DAV_Server($tree);
|
||||
|
||||
$server->setBaseUri(CALDAV_URL_PREFIX);
|
||||
|
||||
$authPlugin = new Sabre_DAV_Auth_Plugin(Sabre_DAV_Auth_Backend_Std::getInstance(), 'SabreDAV');
|
||||
$server->addPlugin($authPlugin);
|
||||
|
||||
$aclPlugin = new Sabre_DAVACL_Plugin_Friendica();
|
||||
$aclPlugin->defaultUsernamePath = "principals/users";
|
||||
$server->addPlugin($aclPlugin);
|
||||
|
||||
if ($needs_caldav) {
|
||||
$caldavPlugin = new Sabre_CalDAV_Plugin();
|
||||
$server->addPlugin($caldavPlugin);
|
||||
}
|
||||
if ($needs_carddav) {
|
||||
$carddavPlugin = new Sabre_CardDAV_Plugin();
|
||||
$server->addPlugin($carddavPlugin);
|
||||
}
|
||||
|
||||
if ($force_authentication) $server->broadcastEvent('beforeMethod', array("GET", "/")); // Make it authenticate
|
||||
|
||||
return $server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param string $with_privilege
|
||||
* @return array|Sabre_CalDAV_Calendar[]
|
||||
*/
|
||||
function dav_get_current_user_calendars(&$server, $with_privilege = "")
|
||||
{
|
||||
if ($with_privilege == "") $with_privilege = DAV_ACL_READ;
|
||||
|
||||
$a = get_app();
|
||||
$calendar_path = "/calendars/" . strtolower($a->user["nickname"]) . "/";
|
||||
|
||||
/** @var Sabre_CalDAV_AnimexxUserCalendars $tree */
|
||||
$tree = $server->tree->getNodeForPath($calendar_path);
|
||||
/** @var array|Sabre_CalDAV_Calendar[] $calendars */
|
||||
$children = $tree->getChildren();
|
||||
|
||||
$calendars = array();
|
||||
/** @var Sabre_DAVACL_Plugin $aclplugin */
|
||||
$aclplugin = $server->getPlugin("acl");
|
||||
foreach ($children as $child) if (is_a($child, "Sabre_CalDAV_Calendar")) {
|
||||
if ($with_privilege != "") {
|
||||
$caluri = $calendar_path . $child->getName();
|
||||
if ($aclplugin->checkPrivileges($caluri, $with_privilege, Sabre_DAVACL_Plugin::R_PARENT, false)) $calendars[] = $child;
|
||||
} else {
|
||||
$calendars[] = $child;
|
||||
}
|
||||
}
|
||||
return $calendars;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param Sabre_CalDAV_Calendar $calendar
|
||||
* @param string $calendarobject_uri
|
||||
* @param string $with_privilege
|
||||
* @return null|Sabre_VObject_Component_VCalendar
|
||||
*/
|
||||
function dav_get_current_user_calendarobject(&$server, &$calendar, $calendarobject_uri, $with_privilege = "")
|
||||
{
|
||||
$obj = $calendar->getChild($calendarobject_uri);
|
||||
|
||||
if ($with_privilege == "") $with_privilege = DAV_ACL_READ;
|
||||
|
||||
$a = get_app();
|
||||
$uri = "/calendars/" . strtolower($a->user["nickname"]) . "/" . $calendar->getName() . "/" . $calendarobject_uri;
|
||||
|
||||
/** @var Sabre_DAVACL_Plugin $aclplugin */
|
||||
$aclplugin = $server->getPlugin("acl");
|
||||
if (!$aclplugin->checkPrivileges($uri, $with_privilege, Sabre_DAVACL_Plugin::R_PARENT, false)) return null;
|
||||
|
||||
$data = $obj->get();
|
||||
$vObject = Sabre_VObject_Reader::read($data);
|
||||
|
||||
return $vObject;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param int $id
|
||||
* @param string $with_privilege
|
||||
* @return null|Sabre_CalDAV_Calendar
|
||||
*/
|
||||
function dav_get_current_user_calendar_by_id(&$server, $id, $with_privilege = "")
|
||||
{
|
||||
$calendars = dav_get_current_user_calendars($server, $with_privilege);
|
||||
|
||||
$calendar = null;
|
||||
foreach ($calendars as $cal) {
|
||||
$prop = $cal->getProperties(array("id"));
|
||||
if (isset($prop["id"]) && $prop["id"] == $id) $calendar = $cal;
|
||||
}
|
||||
|
||||
return $calendar;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uid
|
||||
* @return Sabre_VObject_Component_VCalendar $vObject
|
||||
*/
|
||||
function dav_create_empty_vevent($uid = "")
|
||||
{
|
||||
$a = get_app();
|
||||
if ($uid == "") $uid = uniqid();
|
||||
return Sabre_VObject_Reader::read("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Friendica//DAV-Plugin//EN\r\nBEGIN:VEVENT\r\nUID:" . $uid . "@" . $a->get_hostname() .
|
||||
"\r\nDTSTAMP:" . date("Ymd") . "T" . date("His") . "Z\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n");
|
||||
}
|
||||
|
||||
$v = new vcalendar();
|
||||
$v->setConfig('unique_id', $a->get_hostname());
|
||||
$v->parse($calendarobject->calendardata);
|
||||
$v->sort();
|
||||
|
||||
$eventArray = $v->selectComponents(2009, 1, 1, date("Y") + 2, 12, 30);
|
||||
|
||||
$start_min = $end_max = "";
|
||||
|
||||
$allday = $summary = $vevent = $rrule = $color = $start = $end = null;
|
||||
$location = $description = "";
|
||||
|
||||
foreach ($eventArray as $yearArray) {
|
||||
foreach ($yearArray as $monthArray) {
|
||||
foreach ($monthArray as $day => $dailyEventsArray) {
|
||||
foreach ($dailyEventsArray as $vevent) {
|
||||
/** @var $vevent vevent */
|
||||
$start = "";
|
||||
$rrule = "NULL";
|
||||
$allday = 0;
|
||||
|
||||
$dtstart = $vevent->getProperty('X-CURRENT-DTSTART');
|
||||
if (is_array($dtstart)) {
|
||||
$start = "'" . $dtstart[1] . "'";
|
||||
if (strpos($dtstart[1], ":") === false) $allday = 1;
|
||||
} else {
|
||||
$dtstart = $vevent->getProperty('dtstart');
|
||||
if (isset($dtstart["day"]) && $dtstart["day"] == $day) { // Mehrtägige Events nur einmal rein
|
||||
if (isset($dtstart["hour"])) $start = "'" . $dtstart["year"] . "-" . $dtstart["month"] . "-" . $dtstart["day"] . " " . $dtstart["hour"] . ":" . $dtstart["minute"] . ":" . $dtstart["secont"] . "'";
|
||||
else {
|
||||
$start = "'" . $dtstart["year"] . "-" . $dtstart["month"] . "-" . $dtstart["day"] . " 00:00:00'";
|
||||
$allday = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dtend = $vevent->getProperty('X-CURRENT-DTEND');
|
||||
if (is_array($dtend)) {
|
||||
$end = "'" . $dtend[1] . "'";
|
||||
if (strpos($dtend[1], ":") === false) $allday = 1;
|
||||
} else {
|
||||
$dtend = $vevent->getProperty('dtend');
|
||||
if (isset($dtend["hour"])) $end = "'" . $dtend["year"] . "-" . $dtend["month"] . "-" . $dtend["day"] . " " . $dtend["hour"] . ":" . $dtend["minute"] . ":" . $dtend["second"] . "'";
|
||||
else {
|
||||
$end = "'" . $dtend["year"] . "-" . $dtend["month"] . "-" . $dtend["day"] . " 00:00:00' - INTERVAL 1 SECOND";
|
||||
$allday = 1;
|
||||
}
|
||||
}
|
||||
$summary = $vevent->getProperty('summary');
|
||||
$description = $vevent->getProperty('description');
|
||||
$location = $vevent->getProperty('location');
|
||||
$rrule_prob = $vevent->getProperty('rrule');
|
||||
if ($rrule_prob != null) {
|
||||
$rrule = $vevent->createRrule();
|
||||
$rrule = "'" . dbesc($rrule) . "'";
|
||||
}
|
||||
$color_ = $vevent->getProperty("X-ANIMEXX-COLOR");
|
||||
$color = (is_array($color_) ? $color_[1] : "NULL");
|
||||
|
||||
if ($start_min == "" || preg_replace("/[^0-9]/", "", $start) < preg_replace("/[^0-9]/", "", $start_min)) $start_min = $start;
|
||||
if ($end_max == "" || preg_replace("/[^0-9]/", "", $end) > preg_replace("/[^0-9]/", "", $start_min)) $end_max = $end;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param Sabre_VObject_Component_VCalendar $vObject
|
||||
* @return Sabre_VObject_Component_VEvent|null
|
||||
*/
|
||||
function dav_get_eventComponent(&$vObject)
|
||||
{
|
||||
$component = null;
|
||||
$componentType = "";
|
||||
foreach ($vObject->getComponents() as $component) {
|
||||
if ($component->name !== 'VTIMEZONE') {
|
||||
$componentType = $component->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($componentType != "VEVENT") return null;
|
||||
|
||||
if ($start_min != "") {
|
||||
|
||||
if ($allday && mb_strlen($end_max) == 12) {
|
||||
$x = explode("-", str_replace("'", "", $end_max));
|
||||
$time = mktime(0, 0, 0, IntVal($x[1]), IntVal($x[2]), IntVal($x[0]));
|
||||
$end_max = date("'Y-m-d H:i:s'", ($time - 1));
|
||||
}
|
||||
|
||||
q("INSERT INTO %s%sjqcalendar (`uid`, `namespace`, `namespace_id`, `ical_uri`, `Subject`, `Location`, `Description`, `StartTime`, `EndTime`, `IsAllDayEvent`, `RecurringRule`, `Color`)
|
||||
VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', %s, %s, %d, '%s', '%s')",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($calendar->uid), IntVal($calendarobject->namespace), IntVal($calendarobject->namespace_id), dbesc($calendarobject->uri), dbesc($summary),
|
||||
dbesc($location), dbesc(str_replace("\\n", "\n", $description)), $start_min, $end_max, IntVal($allday), dbesc($rrule), dbesc($color)
|
||||
);
|
||||
|
||||
foreach ($vevent->components as $comp) {
|
||||
/** @var $comp calendarComponent */
|
||||
$trigger = $comp->getProperty("TRIGGER");
|
||||
$sql_field = ($trigger["relatedStart"] ? $start : $end);
|
||||
$sql_op = ($trigger["before"] ? "DATE_SUB" : "DATE_ADD");
|
||||
$num = "";
|
||||
$rel_type = "";
|
||||
$rel_value = 0;
|
||||
if (isset($trigger["second"])) {
|
||||
$num = IntVal($trigger["second"]) . " SECOND";
|
||||
$rel_type = "second";
|
||||
$rel_value = IntVal($trigger["second"]);
|
||||
}
|
||||
if (isset($trigger["minute"])) {
|
||||
$num = IntVal($trigger["minute"]) . " MINUTE";
|
||||
$rel_type = "minute";
|
||||
$rel_value = IntVal($trigger["minute"]);
|
||||
}
|
||||
if (isset($trigger["hour"])) {
|
||||
$num = IntVal($trigger["hour"]) . " HOUR";
|
||||
$rel_type = "hour";
|
||||
$rel_value = IntVal($trigger["hour"]);
|
||||
}
|
||||
if (isset($trigger["day"])) {
|
||||
$num = IntVal($trigger["day"]) . " DAY";
|
||||
$rel_type = "day";
|
||||
$rel_value = IntVal($trigger["day"]);
|
||||
}
|
||||
if (isset($trigger["week"])) {
|
||||
$num = IntVal($trigger["week"]) . " WEEK";
|
||||
$rel_type = "week";
|
||||
$rel_value = IntVal($trigger["week"]);
|
||||
}
|
||||
if (isset($trigger["month"])) {
|
||||
$num = IntVal($trigger["month"]) . " MONTH";
|
||||
$rel_type = "month";
|
||||
$rel_value = IntVal($trigger["month"]);
|
||||
}
|
||||
if (isset($trigger["year"])) {
|
||||
$num = IntVal($trigger["year"]) . " YEAR";
|
||||
$rel_type = "year";
|
||||
$rel_value = IntVal($trigger["year"]);
|
||||
}
|
||||
if ($trigger["before"]) $rel_value *= -1;
|
||||
|
||||
if ($rel_type != "") {
|
||||
$not_date = "$sql_op($sql_field, INTERVAL $num)";
|
||||
q("INSERT INTO %s%snotifications (`uid`, `ical_uri`, `rel_type`, `rel_value`, `alert_date`, `notified`) VALUES ('%s', '%s', '%s', '%s', %s, IF(%s < NOW(), 1, 0))",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($calendar->uid), dbesc($calendarobject->uri), dbesc($rel_type), IntVal($rel_value), $not_date, $not_date);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $component;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function renderAllCalDavEntries()
|
||||
{
|
||||
q("DELETE FROM %s%sjqcalendar", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
q("DELETE FROM %s%snotifications", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$calendars = q("SELECT * FROM %s%scalendars", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$anz = count($calendars);
|
||||
$i = 0;
|
||||
foreach ($calendars as $calendar) {
|
||||
$cal = new DBClass_friendica_calendars($calendar);
|
||||
$i++;
|
||||
if (($i % 100) == 0) echo "$i / $anz\n";
|
||||
$calobjs = q("SELECT * FROM %s%scalendarobjects WHERE `namespace` = %d AND `namespace_id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendar["namespace"]), IntVal($calendar["namespace_id"]));
|
||||
foreach ($calobjs as $calobj) {
|
||||
$obj = new DBClass_friendica_calendarobjects($calobj);
|
||||
renderCalDavEntry_data($cal, $obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @return bool
|
||||
*/
|
||||
function renderCalDavEntry_uri($uri)
|
||||
{
|
||||
q("DELETE FROM %s%sjqcalendar WHERE `ical_uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
q("DELETE FROM %s%snotifications WHERE `ical_uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
|
||||
$calobj = q("SELECT * FROM %s%scalendarobjects WHERE `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
if (count($calobj) == 0) return false;
|
||||
$cal = new DBClass_friendica_calendarobjects($calobj[0]);
|
||||
$calendars = q("SELECT * FROM %s%scalendars WHERE `namespace`=%d AND `namespace_id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($cal->namespace), IntVal($cal->namespace_id));
|
||||
$calendar = new DBClass_friendica_calendars($calendars[0]);
|
||||
renderCalDavEntry_data($calendar, $cal);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $user_id
|
||||
* @return array|DBClass_friendica_calendars[]
|
||||
*/
|
||||
function dav_getMyCals($user_id)
|
||||
{
|
||||
$d = q("SELECT * FROM %s%scalendars WHERE `uid` = %d ORDER BY `calendarorder` ASC",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($user_id), CALDAV_NAMESPACE_PRIVATE
|
||||
);
|
||||
$cals = array();
|
||||
foreach ($d as $e) $cals[] = new DBClass_friendica_calendars($e);
|
||||
return $cals;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $obj
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_jsonp_encode($obj)
|
||||
{
|
||||
$str = json_encode($obj);
|
||||
if (isset($_REQUEST["callback"])) {
|
||||
$str = $_REQUEST["callback"] . "(" . $str . ")";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $day
|
||||
* @param int $weekstartday
|
||||
* @param int $num_days
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
function wdcal_get_list_range_params($day, $weekstartday, $num_days, $type)
|
||||
{
|
||||
$phpTime = IntVal($day);
|
||||
switch ($type) {
|
||||
case "month":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), 1, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime) + 1, 1, date("Y", $phpTime));
|
||||
break;
|
||||
case "week":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + 1;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + 7, date("Y", $phpTime));
|
||||
break;
|
||||
case "multi_days":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + $weekstartday;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + $num_days, date("Y", $phpTime));
|
||||
break;
|
||||
case "day":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), date("d", $phpTime), date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), date("d", $phpTime) + 1, date("Y", $phpTime));
|
||||
break;
|
||||
default:
|
||||
return array(0, 0);
|
||||
}
|
||||
return array($st, $et);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param string $recurr_uri
|
||||
* @param int $uid
|
||||
* @param string $timezone
|
||||
* @param string $goaway_url
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_postEditPage($uri, $recurr_uri = "", $uid = 0, $timezone = "", $goaway_url = "")
|
||||
{
|
||||
$uid = IntVal($uid);
|
||||
$localization = wdcal_local::getInstanceByUser($uid);
|
||||
|
||||
if (isset($_REQUEST["allday"])) {
|
||||
$start = $localization->date_parseLocal($_REQUEST["start_date"] . " 00:00");
|
||||
$end = $localization->date_parseLocal($_REQUEST["end_date"] . " 20:00");
|
||||
$isallday = true;
|
||||
} else {
|
||||
$start = $localization->date_parseLocal($_REQUEST["start_date"] . " " . $_REQUEST["start_time"]);
|
||||
$end = $localization->date_parseLocal($_REQUEST["end_date"] . " " . $_REQUEST["end_time"]);
|
||||
$isallday = false;
|
||||
}
|
||||
|
||||
if ($uri == "new") {
|
||||
$cals = dav_getMyCals($uid);
|
||||
foreach ($cals as $c) {
|
||||
$cs = wdcal_calendar_factory($uid, $c->namespace, $c->namespace_id);
|
||||
$p = $cs->getPermissionsCalendar($uid);
|
||||
|
||||
if ($p["write"]) try {
|
||||
$cs->addItem($start, $end, dav_compat_getRequestVar("subject"), $isallday, dav_compat_parse_text_serverside("wdcal_desc"),
|
||||
dav_compat_getRequestVar("location"), dav_compat_getRequestVar("color"), $timezone,
|
||||
isset($_REQUEST["notification"]), $_REQUEST["notification_type"], $_REQUEST["notification_value"]);
|
||||
} catch (Exception $e) {
|
||||
notification(t("Error") . ": " . $e);
|
||||
}
|
||||
dav_compat_redirect($goaway_url);
|
||||
}
|
||||
|
||||
} else {
|
||||
$cals = dav_getMyCals($uid);
|
||||
foreach ($cals as $c) {
|
||||
$cs = wdcal_calendar_factory($uid, $c->namespace, $c->namespace_id);
|
||||
$p = $cs->getPermissionsItem($uid, $uri, $recurr_uri);
|
||||
if ($p["write"]) try {
|
||||
$cs->updateItem($uri, $start, $end,
|
||||
dav_compat_getRequestVar("subject"), $isallday, dav_compat_parse_text_serverside("wdcal_desc"),
|
||||
dav_compat_getRequestVar("location"), dav_compat_getRequestVar("color"), $timezone,
|
||||
isset($_REQUEST["notification"]), $_REQUEST["notification_type"], $_REQUEST["notification_value"]);
|
||||
} catch (Exception $e) {
|
||||
notification(t("Error") . ": " . $e);
|
||||
}
|
||||
dav_compat_redirect($goaway_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function wdcal_print_feed($base_path = "")
|
||||
{
|
||||
$user_id = dav_compat_get_curr_user_id();
|
||||
$cals = array();
|
||||
if (isset($_REQUEST["cal"])) foreach ($_REQUEST["cal"] as $c) {
|
||||
$x = explode("-", $c);
|
||||
$calendarSource = wdcal_calendar_factory($user_id, $x[0], $x[1]);
|
||||
$calp = $calendarSource->getPermissionsCalendar($user_id);
|
||||
if ($calp["read"]) $cals[] = $calendarSource;
|
||||
}
|
||||
|
||||
$ret = null;
|
||||
/** @var $cals array|AnimexxCalSource[] */
|
||||
|
||||
$method = $_GET["method"];
|
||||
switch ($method) {
|
||||
case "add":
|
||||
$cs = null;
|
||||
foreach ($cals as $c) if ($cs == null) {
|
||||
$x = $c->getPermissionsCalendar($user_id);
|
||||
if ($x["read"]) $cs = $c;
|
||||
}
|
||||
if ($cs == null) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$start = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarStartTime"]));
|
||||
$end = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarEndTime"]));
|
||||
$newuri = $cs->addItem($start, $end, $_REQUEST["CalendarTitle"], $_REQUEST["IsAllDayEvent"]);
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'add success',
|
||||
'Data' => $newuri,
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$ret = array(
|
||||
'IsSuccess' => false,
|
||||
'Msg' => $e->__toString(),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "list":
|
||||
$weekstartday = (isset($_REQUEST["weekstartday"]) ? IntVal($_REQUEST["weekstartday"]) : 1); // 1 = Monday
|
||||
$num_days = (isset($_REQUEST["num_days"]) ? IntVal($_REQUEST["num_days"]) : 7);
|
||||
$ret = null;
|
||||
|
||||
$date = wdcal_get_list_range_params($_REQUEST["showdate"], $weekstartday, $num_days, $_REQUEST["viewtype"]);
|
||||
$ret = array();
|
||||
$ret['events'] = array();
|
||||
$ret["issort"] = true;
|
||||
$ret["start"] = $date[0];
|
||||
$ret["end"] = $date[1];
|
||||
$ret['error'] = null;
|
||||
|
||||
foreach ($cals as $c) {
|
||||
$events = $c->listItemsByRange($date[0], $date[1], $base_path);
|
||||
$ret["events"] = array_merge($ret["events"], $events);
|
||||
}
|
||||
|
||||
$tmpev = array();
|
||||
foreach ($ret["events"] as $e) {
|
||||
if (!isset($tmpev[$e["start"]])) $tmpev[$e["start"]] = array();
|
||||
$tmpev[$e["start"]][] = $e;
|
||||
}
|
||||
ksort($tmpev);
|
||||
$ret["events"] = array();
|
||||
foreach ($tmpev as $e) foreach ($e as $f) $ret["events"][] = $f;
|
||||
|
||||
break;
|
||||
case "update":
|
||||
$found = false;
|
||||
$start = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarStartTime"]));
|
||||
$end = wdcal_mySql2icalTime(wdcal_php2MySqlTime($_REQUEST["CalendarEndTime"]));
|
||||
foreach ($cals as $c) try {
|
||||
$permissions_item = $c->getPermissionsItem($user_id, $_REQUEST["calendarId"], "");
|
||||
if ($permissions_item["write"]) {
|
||||
$c->updateItem($_REQUEST["calendarId"], $start, $end);
|
||||
$found = true;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
;
|
||||
|
||||
if ($found) {
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} else {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
|
||||
try {
|
||||
} catch (Exception $e) {
|
||||
$ret = array(
|
||||
'IsSuccess' => false,
|
||||
'Msg' => $e->__toString(),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "remove":
|
||||
$found = false;
|
||||
foreach ($cals as $c) try {
|
||||
$permissions_item = $c->getPermissionsItem($user_id, $_REQUEST["calendarId"], "");
|
||||
if ($permissions_item["write"]) $c->removeItem($_REQUEST["calendarId"]);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} else {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
break;
|
||||
}
|
||||
echo wdcal_jsonp_encode($ret);
|
||||
killme();
|
||||
}
|
||||
|
||||
|
|
187
dav/common/calendar_rendering.fnk.php
Normal file
187
dav/common/calendar_rendering.fnk.php
Normal file
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_VObject_Component_VAlarm $alarm
|
||||
* @param Sabre_VObject_Component_VEvent|Sabre_VObject_Component_VTodo $parent
|
||||
* @return DateTime|null
|
||||
* @throws Sabre_DAV_Exception
|
||||
*/
|
||||
function renderCalDavEntry_calcalarm(&$alarm, &$parent)
|
||||
{
|
||||
$trigger = $alarm->__get("TRIGGER");
|
||||
if (!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') {
|
||||
$triggerDuration = Sabre_VObject_DateTimeParser::parseDuration($trigger->value);
|
||||
|
||||
$related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START';
|
||||
|
||||
if ($related === 'START') {
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $parent->__get("DTSTART");
|
||||
$effectiveTrigger = $dtstart->getDateTime();
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
} else {
|
||||
if ($parent->name === 'VTODO') {
|
||||
$endProp = 'DUE';
|
||||
} else {
|
||||
$endProp = 'DTEND';
|
||||
}
|
||||
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $parent->__get("DTSTART");
|
||||
if (isset($parent->$endProp)) {
|
||||
$effectiveTrigger = clone $parent->$endProp->getDateTime();
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
} elseif ($parent->__get("DURATION") != "") {
|
||||
$effectiveTrigger = clone $dtstart->getDateTime();
|
||||
$duration = Sabre_VObject_DateTimeParser::parseDuration($parent->__get("DURATION"));
|
||||
$effectiveTrigger->add($duration);
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
} else {
|
||||
$effectiveTrigger = clone $dtstart->getDateTime();
|
||||
$effectiveTrigger->add($triggerDuration);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ??? @TODO
|
||||
$effectiveTrigger = $trigger->getDateTime();
|
||||
}
|
||||
return $effectiveTrigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $calendar
|
||||
* @param array $calendarobject
|
||||
* @throws Sabre_DAV_Exception_BadRequest
|
||||
* @return void
|
||||
*/
|
||||
function renderCalDavEntry_data(&$calendar, &$calendarobject)
|
||||
{
|
||||
/** @var Sabre_VObject_Component_VCalendar $vObject */
|
||||
$vObject = Sabre_VObject_Reader::read($calendarobject["calendardata"]);
|
||||
$componentType = null;
|
||||
/** @var Sabre_VObject_Component_VEvent $component */
|
||||
$component = null;
|
||||
foreach ($vObject->getComponents() as $component) {
|
||||
if ($component->name !== 'VTIMEZONE') {
|
||||
$componentType = $component->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$componentType) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
|
||||
}
|
||||
|
||||
$timezoneOffset = date("P"); // @TODO Get the actual timezone from the event
|
||||
|
||||
|
||||
if ($componentType !== 'VEVENT') return;
|
||||
|
||||
$event = array(
|
||||
"description" => ($component->__get("DESCRIPTION") ? $component->__get("DESCRIPTION")->value : null),
|
||||
"summary" => ($component->__get("SUMMARY") ? $component->__get("SUMMARY")->value : null),
|
||||
"location" => ($component->__get("LOCATION") ? $component->__get("LOCATION")->value : null),
|
||||
"color" => ($component->__get("X-ANIMEXX-COLOR") ? $component->__get("X-ANIMEXX-COLOR")->value : null),
|
||||
);
|
||||
|
||||
$recurring = ($component->__get("RRULE") ? 1 : 0);
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $component->__get("DTSTART");
|
||||
$allday = ($dtstart->getDateType() == Sabre_VObject_Property_DateTime::DATE ? 1 : 0);
|
||||
|
||||
/** @var array|Sabre_VObject_Component_VAlarm[] $alarms */
|
||||
$alarms = array();
|
||||
foreach ($component->getComponents() as $a_component) if ($a_component->name == "VALARM") {
|
||||
/** var Sabre_VObject_Component_VAlarm $component */
|
||||
$alarms[] = $a_component;
|
||||
}
|
||||
|
||||
$it = new Sabre_VObject_RecurrenceIterator($vObject, (string)$component->__get("UID"));
|
||||
$last_end = 0;
|
||||
$max_ts = mktime(0, 0, 0, 1, 1, CALDAV_MAX_YEAR * 1);
|
||||
$first = true;
|
||||
|
||||
while ($it->valid() && $last_end < $max_ts && ($recurring || $first)) {
|
||||
$first = false;
|
||||
$last_end = $it->getDtEnd()->getTimestamp();
|
||||
$start = $it->getDtStart()->getTimestamp();
|
||||
|
||||
q("INSERT INTO %s%sjqcalendar (`calendar_id`, `calendarobject_id`, `Summary`, `StartTime`, `EndTime`, `IsEditable`, `IsAllDayEvent`, `IsRecurring`, `Color`) VALUES
|
||||
(%d, %d, '%s', CONVERT_TZ('%s', '$timezoneOffset', @@session.time_zone), CONVERT_TZ('%s', '$timezoneOffset', @@session.time_zone), %d, %d, %d, '%s')",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendar["id"]), IntVal($calendarobject["id"]), dbesc($event["summary"]), date("Y-m-d H:i:s", $start),
|
||||
date("Y-m-d H:i:s", $last_end), 1, $allday, $recurring, dbesc(substr($event["color"], 1))
|
||||
);
|
||||
|
||||
foreach ($alarms as $alarm) {
|
||||
$alarm = renderCalDavEntry_calcalarm($alarm, $component);
|
||||
$notified = ($alarm->getTimestamp() < time() ? 1 : 0);
|
||||
q("INSERT INTO %s%snotifications (`calendar_id`, `calendarobject_id`, `alert_date`, `notified`) VALUES (%d, %d, CONVERT_TZ('%s', '$timezoneOffset', @@session.time_zone), %d)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendar["id"]), IntVal($calendarobject["id"]), $alarm->format("Y-m-d H:i:s"), $notified
|
||||
);
|
||||
}
|
||||
|
||||
$it->next();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function renderAllCalDavEntries()
|
||||
{
|
||||
q("DELETE FROM %s%sjqcalendar", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
q("DELETE FROM %s%snotifications", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$calendars = q("SELECT * FROM %s%scalendars", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
$anz = count($calendars);
|
||||
$i = 0;
|
||||
foreach ($calendars as $calendar) {
|
||||
$i++;
|
||||
if (($i % 100) == 0) echo "$i / $anz\n";
|
||||
$calobjs = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendar["id"]));
|
||||
foreach ($calobjs as $calobj) renderCalDavEntry_data($calendar, $calobj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @return bool
|
||||
*/
|
||||
function renderCalDavEntry_uri($uri)
|
||||
{
|
||||
$calobj = q("SELECT * FROM %s%scalendarobjects WHERE `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($uri));
|
||||
if (count($calobj) == 0) return false;
|
||||
|
||||
q("DELETE FROM %s%sjqcalendar WHERE `calendar_id` = %d AND `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]), IntVal($calobj[0]["id"]));
|
||||
q("DELETE FROM %s%snotifications WHERE `calendar_id` = %d AND `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]), IntVal($calobj[0]["id"]));
|
||||
|
||||
$calendars = q("SELECT * FROM %s%scalendars WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]));
|
||||
|
||||
renderCalDavEntry_data($calendars[0], $calobj[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $calobj_id
|
||||
* @return bool
|
||||
*/
|
||||
function renderCalDavEntry_calobj_id($calobj_id)
|
||||
{
|
||||
$calobj_id = IntVal($calobj_id);
|
||||
q("DELETE FROM %s%sjqcalendar WHERE `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calobj_id);
|
||||
q("DELETE FROM %s%snotifications WHERE `calendarobject_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calobj_id);
|
||||
|
||||
$calobj = q("SELECT * FROM %s%scalendarobjects WHERE `id` = '%d'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calobj_id);
|
||||
if (count($calobj) == 0) return false;
|
||||
|
||||
$calendars = q("SELECT * FROM %s%scalendars WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calobj[0]["calendar_id"]));
|
||||
|
||||
renderCalDavEntry_data($calendars[0], $calobj[0]);
|
||||
return true;
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Backend_Std extends Sabre_CalDAV_Backend_Common
|
||||
{
|
||||
|
||||
public function getNamespace()
|
||||
{
|
||||
return CALDAV_NAMESPACE_PRIVATE;
|
||||
}
|
||||
|
||||
public function getCalUrlPrefix()
|
||||
{
|
||||
return "private";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// TODO: Implement createCalendar() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId)
|
||||
{
|
||||
// TODO: Implement deleteCalendar() method.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 string $calendarId
|
||||
* @return array
|
||||
*/
|
||||
function getCalendarObjects($calendarId)
|
||||
{
|
||||
$x = explode("-", $calendarId);
|
||||
$objs = q("SELECT * FROM %s%scalendarobjects WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]));
|
||||
$ret = array();
|
||||
foreach ($objs as $obj) {
|
||||
$ret[] = array(
|
||||
"id" => IntVal($obj["id"]),
|
||||
"calendardata" => $obj["calendardata"],
|
||||
"uri" => $obj["uri"],
|
||||
"lastmodified" => $obj["lastmodified"],
|
||||
"calendarid" => $calendarId,
|
||||
"etag" => $obj["etag"],
|
||||
"size" => IntVal($obj["size"]),
|
||||
);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_FileNotFound
|
||||
* @return array
|
||||
*/
|
||||
function getCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$x = explode("-", $calendarId);
|
||||
|
||||
$o = q("SELECT * FROM %s%scalendarobjects WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($objectUri));
|
||||
if (count($o) > 0) {
|
||||
$o[0]["calendarid"] = $calendarId;
|
||||
$o[0]["calendardata"] = str_ireplace("Europe/Belgrade", "Europe/Berlin", $o[0]["calendardata"]);
|
||||
return $o[0];
|
||||
} else throw new Sabre_DAV_Exception_FileNotFound($calendarId . " / " . $objectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return null|string|void
|
||||
*/
|
||||
function createCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
$x = explode("-", $calendarId);
|
||||
|
||||
q("INSERT INTO %s%scalendarobjects (`namespace`, `namespace_id`, `uri`, `calendardata`, `lastmodified`, `etag`, `size`) VALUES (%d, %d, '%s', '%s', NOW(), '%s', %d)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX,
|
||||
IntVal($x[0]), IntVal($x[1]), dbesc($objectUri), addslashes($calendarData), md5($calendarData), strlen($calendarData)
|
||||
);
|
||||
|
||||
$this->increaseCalendarCtag($x[0], $x[1]);
|
||||
renderCalDavEntry_uri($objectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @return null|string|void
|
||||
*/
|
||||
function updateCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
$x = explode("-", $calendarId);
|
||||
|
||||
q("UPDATE %s%scalendarobjects SET `calendardata` = '%s', `lastmodified` = NOW(), `etag` = '%s', `size` = %d WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($calendarData), md5($calendarData), strlen($calendarData), IntVal($x[0]), IntVal($x[1]), dbesc($objectUri));
|
||||
|
||||
$this->increaseCalendarCtag($x[0], $x[1]);
|
||||
renderCalDavEntry_uri($objectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @return void
|
||||
*/
|
||||
function deleteCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$x = explode("-", $calendarId);
|
||||
|
||||
q("DELETE FROM %s%scalendarobjects WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1]), dbesc($objectUri)
|
||||
);
|
||||
|
||||
$this->increaseCalendarCtag($x[0], $x[1]);
|
||||
renderCalDavEntry_uri($objectUri);
|
||||
}
|
||||
}
|
|
@ -1,76 +1,179 @@
|
|||
<?php
|
||||
|
||||
abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract {
|
||||
abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
||||
{
|
||||
/**
|
||||
* List of CalDAV properties, and how they map to database fieldnames
|
||||
*
|
||||
* Add your own properties by simply adding on to this array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $propertyMap = array(
|
||||
'{DAV:}displayname' => 'displayname',
|
||||
protected $propertyMap = array(
|
||||
'{DAV:}displayname' => 'displayname',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
|
||||
'{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'timezone',
|
||||
'{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
|
||||
'{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
|
||||
'{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNamespace();
|
||||
abstract public function getCalUrlPrefix();
|
||||
|
||||
/**
|
||||
* @param int $namespace
|
||||
* @param int $namespace_id
|
||||
* @static
|
||||
* @abstract
|
||||
* @return string
|
||||
*/
|
||||
protected function increaseCalendarCtag($namespace, $namespace_id) {
|
||||
$namespace = IntVal($namespace);
|
||||
$namespace_id = IntVal($namespace_id);
|
||||
abstract public static function getBackendTypeName();
|
||||
|
||||
q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $namespace, $namespace_id);
|
||||
|
||||
/**
|
||||
* @param int $calendarId
|
||||
* @param string $sd
|
||||
* @param string $ed
|
||||
* @param string $base_path
|
||||
* @return array
|
||||
*/
|
||||
abstract public function listItemsByRange($calendarId, $sd, $ed, $base_path);
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static private $calendarCache = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static private $calendarObjectCache = array();
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $calendarId
|
||||
* @return array
|
||||
*/
|
||||
static public function loadCalendarById($calendarId)
|
||||
{
|
||||
if (!isset(self::$calendarCache[$calendarId])) {
|
||||
$c = q("SELECT * FROM %s%scalendars WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
self::$calendarCache[$calendarId] = $c[0];
|
||||
}
|
||||
return self::$calendarCache[$calendarId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $obj_id
|
||||
* @return array
|
||||
*/
|
||||
static public function loadCalendarobjectById($obj_id)
|
||||
{
|
||||
if (!isset(self::$calendarObjectCache[$obj_id])) {
|
||||
$o = q("SELECT * FROM %s%scalendarobjects WHERE `id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($obj_id)
|
||||
);
|
||||
self::$calendarObjectCache[$obj_id] = $o[0];
|
||||
}
|
||||
return self::$calendarObjectCache[$obj_id];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @static
|
||||
* @param Sabre_VObject_Component_VEvent $component
|
||||
* @return int
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri)
|
||||
public static function getDtEndTimeStamp(&$component)
|
||||
{
|
||||
list(,$name) = Sabre_DAV_URLUtil::splitPath($principalUri);
|
||||
$user_id = dav_compat_username2id($name);
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `uid`=%d AND `namespace` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $user_id, $this->getNamespace());
|
||||
$ret = array();
|
||||
foreach ($cals as $cal) {
|
||||
$dat = array(
|
||||
"id" => $cal["namespace"] . "-" . $cal["namespace_id"],
|
||||
"uri" => $this->getCalUrlPrefix() . "-" . $cal["namespace_id"],
|
||||
"principaluri" => $principalUri,
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $cal['ctag']?$cal['ctag']:'0',
|
||||
"calendar_class" => "Sabre_CalDAV_Calendar",
|
||||
);
|
||||
foreach ($this->propertyMap as $key=>$field) $dat[$key] = $cal[$field];
|
||||
|
||||
$ret[] = $dat;
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $component->__get("DTSTART");
|
||||
if ($component->__get("DTEND")) {
|
||||
/** @var Sabre_VObject_Property_DateTime $dtend */
|
||||
$dtend = $component->__get("DTEND");
|
||||
return $dtend->getDateTime()->getTimeStamp();
|
||||
} elseif ($component->__get("DURATION")) {
|
||||
$endDate = clone $dtstart->getDateTime();
|
||||
$endDate->add(Sabre_VObject_DateTimeParser::parse($component->__get("DURATION")->value));
|
||||
return $endDate->getTimeStamp();
|
||||
} elseif ($dtstart->getDateType() === Sabre_VObject_Property_DateTime::DATE) {
|
||||
$endDate = clone $dtstart->getDateTime();
|
||||
$endDate->modify('+1 day');
|
||||
return $endDate->getTimeStamp();
|
||||
} else {
|
||||
return $dtstart->getDateTime()->getTimeStamp() + 3600;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses some information from calendar objects, used for optimized
|
||||
* calendar-queries.
|
||||
*
|
||||
* Returns an array with the following keys:
|
||||
* * etag
|
||||
* * size
|
||||
* * componentType
|
||||
* * firstOccurence
|
||||
* * lastOccurence
|
||||
*
|
||||
* @param string $calendarData
|
||||
* @throws Sabre_DAV_Exception_BadRequest
|
||||
* @return array
|
||||
*/
|
||||
protected function getDenormalizedData($calendarData)
|
||||
{
|
||||
/** @var Sabre_VObject_Component_VEvent $vObject */
|
||||
$vObject = Sabre_VObject_Reader::read($calendarData);
|
||||
$componentType = null;
|
||||
$component = null;
|
||||
$firstOccurence = null;
|
||||
$lastOccurence = null;
|
||||
|
||||
foreach ($vObject->getComponents() as $component) {
|
||||
if ($component->name !== 'VTIMEZONE') {
|
||||
$componentType = $component->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$componentType) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
|
||||
}
|
||||
if ($componentType === 'VEVENT') {
|
||||
/** @var Sabre_VObject_Component_VEvent $component */
|
||||
/** @var Sabre_VObject_Property_DateTime $dtstart */
|
||||
$dtstart = $component->__get("DTSTART");
|
||||
$firstOccurence = $dtstart->getDateTime()->getTimeStamp();
|
||||
// Finding the last occurence is a bit harder
|
||||
if (!$component->__get("RRULE")) {
|
||||
$lastOccurence = self::getDtEndTimeStamp($component);
|
||||
} else {
|
||||
$it = new Sabre_VObject_RecurrenceIterator($vObject, (string)$component->__get("UID"));
|
||||
$maxDate = new DateTime(CALDAV_MAX_YEAR . "-01-01");
|
||||
if ($it->isInfinite()) {
|
||||
$lastOccurence = $maxDate->getTimeStamp();
|
||||
} else {
|
||||
$end = $it->getDtEnd();
|
||||
while ($it->valid() && $end < $maxDate) {
|
||||
$end = $it->getDtEnd();
|
||||
$it->next();
|
||||
|
||||
}
|
||||
$lastOccurence = $end->getTimeStamp();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'etag' => md5($calendarData),
|
||||
'size' => strlen($calendarData),
|
||||
'componentType' => $componentType,
|
||||
'firstOccurence' => $firstOccurence,
|
||||
'lastOccurence' => $lastOccurence,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,10 +212,11 @@ abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
|||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations) {
|
||||
public function updateCalendar($calendarId, array $mutations)
|
||||
{
|
||||
|
||||
$newValues = array();
|
||||
$result = array(
|
||||
$result = array(
|
||||
200 => array(), // Ok
|
||||
403 => array(), // Forbidden
|
||||
424 => array(), // Failed Dependency
|
||||
|
@ -120,17 +224,17 @@ abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
|||
|
||||
$hasError = false;
|
||||
|
||||
foreach($mutations as $propertyName=>$propertyValue) {
|
||||
foreach ($mutations as $propertyName=> $propertyValue) {
|
||||
|
||||
// We don't know about this property.
|
||||
if (!isset($this->propertyMap[$propertyName])) {
|
||||
$hasError = true;
|
||||
$hasError = true;
|
||||
$result[403][$propertyName] = null;
|
||||
unset($mutations[$propertyName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldName = $this->propertyMap[$propertyName];
|
||||
$fieldName = $this->propertyMap[$propertyName];
|
||||
$newValues[$fieldName] = $propertyValue;
|
||||
|
||||
}
|
||||
|
@ -138,33 +242,46 @@ abstract class Sabre_CalDAV_Backend_Common extends Sabre_CalDAV_Backend_Abstract
|
|||
// If there were any errors we need to fail the request
|
||||
if ($hasError) {
|
||||
// Properties has the remaining properties
|
||||
foreach($mutations as $propertyName=>$propertyValue) {
|
||||
foreach ($mutations as $propertyName=> $propertyValue) {
|
||||
$result[424][$propertyName] = null;
|
||||
}
|
||||
|
||||
// Removing unused statuscodes for cleanliness
|
||||
foreach($result as $status=>$properties) {
|
||||
if (is_array($properties) && count($properties)===0) unset($result[$status]);
|
||||
foreach ($result as $status=> $properties) {
|
||||
if (is_array($properties) && count($properties) === 0) unset($result[$status]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
$x = explode("-", $calendarId);
|
||||
|
||||
$this->increaseCalendarCtag($x[0], $x[1]);
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
|
||||
$valuesSql = array();
|
||||
foreach($newValues as $fieldName=>$value) $valuesSql[] = "`" . $fieldName . "` = '" . dbesc($value) . "'";
|
||||
foreach ($newValues as $fieldName=> $value) $valuesSql[] = "`" . $fieldName . "` = '" . dbesc($value) . "'";
|
||||
if (count($valuesSql) > 0) {
|
||||
q("UPDATE %s%scalendars SET " . implode(", ", $valuesSql) . " WHERE `namespace` = %d AND `namespace_id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($x[0]), IntVal($x[1])
|
||||
);
|
||||
q("UPDATE %s%scalendars SET " . implode(", ", $valuesSql) . " WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendarId
|
||||
*/
|
||||
protected function increaseCalendarCtag($calendarId)
|
||||
{
|
||||
q("UPDATE %s%scalendars SET `ctag` = `ctag` + 1 WHERE `id` = '%d'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
self::$calendarObjectCache = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param int $calendar_id
|
||||
* @param int $calendarobject_id
|
||||
* @return string
|
||||
*/
|
||||
abstract function getItemDetailRedirect($calendar_id, $calendarobject_id);
|
||||
|
||||
}
|
510
dav/common/dav_caldav_backend_private.inc.php
Normal file
510
dav/common/dav_caldav_backend_private.inc.php
Normal file
|
@ -0,0 +1,510 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Backend_Private extends Sabre_CalDAV_Backend_Common
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var null|Sabre_CalDAV_Backend_Private
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_CalDAV_Backend_Private
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (self::$instance == null) {
|
||||
self::$instance = new Sabre_CalDAV_Backend_Private();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return CALDAV_NAMESPACE_PRIVATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return string
|
||||
*/
|
||||
public static function getBackendTypeName()
|
||||
{
|
||||
return t("Private Events");
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete
|
||||
* @param array $calendar
|
||||
* @param int $user
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissionsCalendar($calendar, $user)
|
||||
{
|
||||
if ($calendar["namespace"] == CALDAV_NAMESPACE_PRIVATE && $user == $calendar["namespace_id"]) return array("read"=> true, "write"=> true);
|
||||
return array("read"=> false, "write"=> false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @obsolete
|
||||
* @param array $calendar
|
||||
* @param int $user
|
||||
* @param string $calendarobject_id
|
||||
* @param null|array $item_arr
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissionsItem($calendar, $user, $calendarobject_id, $item_arr = null)
|
||||
{
|
||||
return $this->getPermissionsCalendar($calendar, $user);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
* @param array $calendar
|
||||
* @param string $base_path
|
||||
* @return array
|
||||
*/
|
||||
private function jqcal2wdcal($row, $calendar, $base_path)
|
||||
{
|
||||
$not = q("SELECT COUNT(*) num FROM %s%snotifications WHERE `calendar_id` = %d AND `calendarobject_id` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($row["calendar_id"]), IntVal($row["calendarobject_id"])
|
||||
);
|
||||
$editable = $this->getPermissionsItem($calendar["namespace_id"], $row["calendarobject_id"], $row);
|
||||
|
||||
$end = wdcal_mySql2PhpTime($row["EndTime"]);
|
||||
if ($row["IsAllDayEvent"]) $end -= 1;
|
||||
|
||||
return array(
|
||||
"jq_id" => $row["id"],
|
||||
"ev_id" => $row["calendarobject_id"],
|
||||
"summary" => escape_tags($row["Summary"]),
|
||||
"start" => wdcal_mySql2PhpTime($row["StartTime"]),
|
||||
"end" => $end,
|
||||
"is_allday" => $row["IsAllDayEvent"],
|
||||
"is_moredays" => 0,
|
||||
"is_recurring" => $row["IsRecurring"],
|
||||
"color" => (is_null($row["Color"]) || $row["Color"] == "" ? $calendar["calendarcolor"] : $row["Color"]),
|
||||
"is_editable" => ($editable ? 1 : 0),
|
||||
"is_editable_quick" => ($editable && !$row["IsRecurring"] ? 1 : 0),
|
||||
"location" => "Loc.",
|
||||
"attendees" => '',
|
||||
"has_notification" => ($not[0]["num"] > 0 ? 1 : 0),
|
||||
"url_detail" => $base_path . $row["calendarobject_id"] . "/",
|
||||
"url_edit" => $base_path . $row["calendarobject_id"] . "/edit/",
|
||||
"special_type" => "",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $calendarId
|
||||
* @param string $sd
|
||||
* @param string $ed
|
||||
* @param string $base_path
|
||||
* @return array
|
||||
*/
|
||||
public function listItemsByRange($calendarId, $sd, $ed, $base_path)
|
||||
{
|
||||
$calendar = Sabre_CalDAV_Backend_Common::loadCalendarById($calendarId);
|
||||
$von = wdcal_php2MySqlTime($sd);
|
||||
$bis = wdcal_php2MySqlTime($ed);
|
||||
$timezoneOffset = date("P");
|
||||
|
||||
// @TODO Events, die früher angefangen haben, aber noch andauern
|
||||
$evs = q("SELECT *, CONVERT_TZ(`StartTime`, @@session.time_zone, '$timezoneOffset') StartTime, CONVERT_TZ(`EndTime`, @@session.time_zone, '$timezoneOffset') EndTime
|
||||
FROM %s%sjqcalendar WHERE `calendar_id` = %d AND `StartTime` between '%s' and '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($von), dbesc($bis));
|
||||
|
||||
$events = array();
|
||||
foreach ($evs as $row) $events[] = $this->jqcal2wdcal($row, $calendar, $base_path . $row["calendar_id"] . "/");
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $calendar_id
|
||||
* @param int $calendarobject_id
|
||||
* @return string
|
||||
*/
|
||||
public function getItemDetailRedirect($calendar_id, $calendarobject_id)
|
||||
{
|
||||
return "/dav/wdcal/$calendar_id/$calendarobject_id/edit/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws DAVVersionMismatchException
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarsForUser($principalUri)
|
||||
{
|
||||
$n = dav_compat_principal2namespace($principalUri);
|
||||
if ($n["namespace"] != $this->getNamespace()) return array();
|
||||
|
||||
$cals = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $this->getNamespace(), IntVal($n["namespace_id"]));
|
||||
$ret = array();
|
||||
foreach ($cals as $cal) {
|
||||
if (!isset($cal["uri"])) throw new DAVVersionMismatchException();
|
||||
if (in_array($cal["uri"], $GLOBALS["CALDAV_PRIVATE_SYSTEM_CALENDARS"])) continue;
|
||||
|
||||
$components = array();
|
||||
if ($cal["has_vevent"]) $components[] = "VEVENT";
|
||||
if ($cal["has_vtodo"]) $components[] = "VTODO";
|
||||
|
||||
$dat = array(
|
||||
"id" => $cal["id"],
|
||||
"uri" => $cal["uri"],
|
||||
"principaluri" => $principalUri,
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}getctag' => $cal['ctag'] ? $cal['ctag'] : '0',
|
||||
'{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}supported-calendar-component-set' => new Sabre_CalDAV_Property_SupportedCalendarComponentSet($components),
|
||||
"calendar_class" => "Sabre_CalDAV_Calendar",
|
||||
);
|
||||
foreach ($this->propertyMap as $key=> $field) $dat[$key] = $cal[$field];
|
||||
|
||||
$ret[] = $dat;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws Sabre_DAV_Exception|Sabre_DAV_Exception_Conflict
|
||||
* @return string|void
|
||||
*/
|
||||
public function createCalendar($principalUri, $calendarUri, array $properties)
|
||||
{
|
||||
|
||||
$uid = dav_compat_principal2uid($principalUri);
|
||||
|
||||
$r = q("SELECT * FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $uid, dbesc($calendarUri));
|
||||
if (count($r) > 0) throw new Sabre_DAV_Exception_Conflict("A calendar with this URI already exists");
|
||||
|
||||
$keys = array("`namespace`", "`namespace_id`", "`ctag`", "`uri`");
|
||||
$vals = array(CALDAV_NAMESPACE_PRIVATE, IntVal($uid), 1, "'" . dbesc($calendarUri) . "'");
|
||||
|
||||
// Default value
|
||||
$sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
|
||||
$has_vevent = $has_vtodo = 1;
|
||||
if (isset($properties[$sccs])) {
|
||||
if (!($properties[$sccs] instanceof Sabre_CalDAV_Property_SupportedCalendarComponentSet)) {
|
||||
throw new Sabre_DAV_Exception('The ' . $sccs . ' property must be of type: Sabre_CalDAV_Property_SupportedCalendarComponentSet');
|
||||
}
|
||||
$v = $properties[$sccs]->getValue();
|
||||
$has_vevent = $has_vtodo = 0;
|
||||
foreach ($v as $w) {
|
||||
if (mb_strtolower($w) == "vevent") $has_vevent = 1;
|
||||
if (mb_strtolower($w) == "vtodo") $has_vtodo = 1;
|
||||
}
|
||||
}
|
||||
$keys[] = "`has_vevent`";
|
||||
$keys[] = "`has_vtodo`";
|
||||
$vals[] = $has_vevent;
|
||||
$vals[] = $has_vtodo;
|
||||
|
||||
foreach ($this->propertyMap as $xmlName=> $dbName) {
|
||||
if (isset($properties[$xmlName])) {
|
||||
$keys[] = "`$dbName`";
|
||||
$vals[] = "'" . dbesc($properties[$xmlName]) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
$sql = sprintf("INSERT INTO %s%scalendars (" . implode(', ', $keys) . ") VALUES (" . implode(', ', $vals) . ")", CALDAV_SQL_DB, CALDAV_SQL_PREFIX);
|
||||
|
||||
q($sql);
|
||||
|
||||
$x = q("SELECT id FROM %s%scalendars WHERE `namespace` = %d AND `namespace_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, CALDAV_NAMESPACE_PRIVATE, $uid, $calendarUri
|
||||
);
|
||||
return $x[0]["id"];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 string $calendarId
|
||||
* @param array $mutations
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateCalendar($calendarId, array $mutations)
|
||||
{
|
||||
|
||||
$newValues = array();
|
||||
$result = array(
|
||||
200 => array(), // Ok
|
||||
403 => array(), // Forbidden
|
||||
424 => array(), // Failed Dependency
|
||||
);
|
||||
|
||||
$hasError = false;
|
||||
|
||||
foreach ($mutations as $propertyName=> $propertyValue) {
|
||||
|
||||
// We don't know about this property.
|
||||
if (!isset($this->propertyMap[$propertyName])) {
|
||||
$hasError = true;
|
||||
$result[403][$propertyName] = null;
|
||||
unset($mutations[$propertyName]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldName = $this->propertyMap[$propertyName];
|
||||
$newValues[$fieldName] = $propertyValue;
|
||||
|
||||
}
|
||||
|
||||
// If there were any errors we need to fail the request
|
||||
if ($hasError) {
|
||||
// Properties has the remaining properties
|
||||
foreach ($mutations as $propertyName=> $propertyValue) {
|
||||
$result[424][$propertyName] = null;
|
||||
}
|
||||
|
||||
// Removing unused statuscodes for cleanliness
|
||||
foreach ($result as $status=> $properties) {
|
||||
if (is_array($properties) && count($properties) === 0) unset($result[$status]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
$sql = "`ctag` = `ctag` + 1";
|
||||
foreach ($newValues as $key=> $val) $sql .= ", `" . $key . "` = '" . dbesc($val) . "'";
|
||||
|
||||
$sql = sprintf("UPDATE %s%scalendars SET $sql WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
|
||||
q($sql);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId)
|
||||
{
|
||||
q("DELETE FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
q("DELETE FROM %s%scalendars WHERE `id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($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
|
||||
*/
|
||||
function getCalendarObjects($calendarId)
|
||||
{
|
||||
$objs = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
$ret = array();
|
||||
foreach ($objs as $obj) {
|
||||
$ret[] = array(
|
||||
"id" => IntVal($obj["id"]),
|
||||
"calendardata" => $obj["calendardata"],
|
||||
"uri" => $obj["uri"],
|
||||
"lastmodified" => $obj["lastmodified"],
|
||||
"calendarid" => $calendarId,
|
||||
"etag" => $obj["etag"],
|
||||
"size" => IntVal($obj["size"]),
|
||||
);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return array
|
||||
*/
|
||||
function getCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$o = q("SELECT * FROM %s%scalendarobjects WHERE `calendar_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri));
|
||||
if (count($o) > 0) {
|
||||
$o[0]["calendarid"] = $calendarId;
|
||||
$o[0]["calendardata"] = str_ireplace("Europe/Belgrade", "Europe/Berlin", $o[0]["calendardata"]);
|
||||
return $o[0];
|
||||
} else throw new Sabre_DAV_Exception_NotFound($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
|
||||
*/
|
||||
function createCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
$calendarData = icalendar_sanitize_string($calendarData);
|
||||
|
||||
$extraData = $this->getDenormalizedData($calendarData);
|
||||
|
||||
q("INSERT INTO %s%scalendarobjects (`calendar_id`, `uri`, `calendardata`, `lastmodified`, `componentType`, `firstOccurence`, `lastOccurence`, `etag`, `size`)
|
||||
VALUES (%d, '%s', '%s', NOW(), '%s', '%s', '%s', '%s', %d)",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri), addslashes($calendarData), dbesc($extraData['componentType']),
|
||||
dbesc(wdcal_php2MySqlTime($extraData['firstOccurence'])), dbesc(wdcal_php2MySqlTime($extraData['lastOccurence'])), dbesc($extraData["etag"]), IntVal($extraData["size"])
|
||||
);
|
||||
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
renderCalDavEntry_uri($objectUri);
|
||||
|
||||
return '"' . $extraData['etag'] . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function updateCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
$calendarData = icalendar_sanitize_string($calendarData);
|
||||
|
||||
$extraData = $this->getDenormalizedData($calendarData);
|
||||
|
||||
q("UPDATE %s%scalendarobjects SET `calendardata` = '%s', `lastmodified` = NOW(), `etag` = '%s', `size` = %d, `componentType` = '%s', `firstOccurence` = '%s', `lastOccurence` = '%s'
|
||||
WHERE `calendar_id` = %d AND `uri` = '%s'",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($calendarData), dbesc($extraData["etag"]), IntVal($extraData["size"]), dbesc($extraData["componentType"]),
|
||||
dbesc(wdcal_php2MySqlTime($extraData["firstOccurence"])), dbesc(wdcal_php2MySqlTime($extraData["lastOccurence"])), IntVal($calendarId), dbesc($objectUri));
|
||||
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
renderCalDavEntry_uri($objectUri);
|
||||
|
||||
return '"' . $extraData['etag'] . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return void
|
||||
*/
|
||||
function deleteCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$r = q("SELECT `id` FROM %s%scalendarobjects WHERE `calendar_id` = %d AND `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri));
|
||||
if (count($r) == 0) throw new Sabre_DAV_Exception_NotFound();
|
||||
|
||||
q("DELETE FROM %s%scalendarobjects WHERE `calendar_id` = %d AND `uri` = '%s'", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId), dbesc($objectUri));
|
||||
|
||||
$this->increaseCalendarCtag($calendarId);
|
||||
renderCalDavEntry_calobj_id($r[0]["id"]);
|
||||
}
|
||||
}
|
186
dav/common/dav_caldav_backend_virtual.inc.php
Normal file
186
dav/common/dav_caldav_backend_virtual.inc.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
abstract class Sabre_CalDAV_Backend_Virtual extends Sabre_CalDAV_Backend_Common
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @param int $calendarId
|
||||
* @param string $uri
|
||||
* @return array
|
||||
*/
|
||||
/*
|
||||
abstract public function getItemsByUri($calendarId, $uri);
|
||||
*/
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $uid
|
||||
* @param int $namespace
|
||||
*/
|
||||
static public function invalidateCache($uid = 0, $namespace = 0) {
|
||||
q("DELETE FROM %s%scal_virtual_object_sync WHERE `uid` = %d AND `namespace` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid), IntVal($namespace));
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @param int $calendarId
|
||||
*/
|
||||
static abstract protected function createCache_internal($calendarId);
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $calendarId
|
||||
*/
|
||||
static protected function createCache($calendarId) {
|
||||
$calendarId = IntVal($calendarId);
|
||||
q("DELETE FROM %s%scal_virtual_object_cache WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
static::createCache_internal($calendarId);
|
||||
q("REPLACE INTO %s%scal_virtual_object_sync (`calendar_id`, `date`) VALUES (%d, NOW())", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $calendarId
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObjects($calendarId)
|
||||
{
|
||||
$calendarId = IntVal($calendarId);
|
||||
$r = q("SELECT COUNT(*) n FROM %s%scal_virtual_object_sync WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
|
||||
if ($r[0]["n"] == 0) static::createCache($calendarId);
|
||||
|
||||
$r = q("SELECT * FROM %s%scal_virtual_object_cache WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $calendarId);
|
||||
|
||||
$ret = array();
|
||||
foreach ($r as $obj) {
|
||||
$ret[] = array(
|
||||
"id" => IntVal($obj["data_uri"]),
|
||||
"calendardata" => $obj["calendardata"],
|
||||
"uri" => $obj["data_uri"],
|
||||
"lastmodified" => $obj["date"],
|
||||
"calendarid" => $calendarId,
|
||||
"etag" => $obj["etag"],
|
||||
"size" => IntVal($obj["size"]),
|
||||
);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information from a single calendar object, based on it's object
|
||||
* uri.
|
||||
*
|
||||
* The returned array must have the same keys as getCalendarObjects. The
|
||||
* 'calendardata' object is required here though, while it's not required
|
||||
* for getCalendarObjects.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @return array
|
||||
*/
|
||||
public function getCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
$calendarId = IntVal($calendarId);
|
||||
$r = q("SELECT COUNT(*) n FROM %s%scal_virtual_object_sync WHERE `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($calendarId));
|
||||
|
||||
if ($r[0]["n"] == 0) static::createCache($calendarId);
|
||||
|
||||
$r = q("SELECT * FROM %s%scal_virtual_object_cache WHERE `data_uri` = '%s' AND `calendar_id` = %d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, dbesc($objectUri), IntVal($calendarId));
|
||||
if (count($r) == 0) throw new Sabre_DAV_Exception_NotFound();
|
||||
|
||||
$obj = $r[0];
|
||||
$ret = array(
|
||||
"id" => IntVal($obj["data_uri"]),
|
||||
"calendardata" => $obj["calendardata"],
|
||||
"uri" => $obj["data_uri"],
|
||||
"lastmodified" => $obj["date"],
|
||||
"calendarid" => $calendarId,
|
||||
"etag" => $obj["etag"],
|
||||
"size" => IntVal($obj["size"]),
|
||||
);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function createCalendar($principalUri, $calendarUri, array $properties)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a calendar and all it's objects
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
public function deleteCalendar($calendarId)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return null|string|void
|
||||
*/
|
||||
function createCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing calendarobject, based on it's uri.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @param string $calendarData
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return null|string|void
|
||||
*/
|
||||
function updateCalendarObject($calendarId, $objectUri, $calendarData)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing calendar object.
|
||||
*
|
||||
* @param string $calendarId
|
||||
* @param string $objectUri
|
||||
* @throws Sabre_DAV_Exception_Forbidden
|
||||
* @return void
|
||||
*/
|
||||
function deleteCalendarObject($calendarId, $objectUri)
|
||||
{
|
||||
throw new Sabre_DAV_Exception_Forbidden();
|
||||
}
|
||||
|
||||
|
||||
}
|
44
dav/common/dav_caldav_calendar_virtual.inc.php
Normal file
44
dav/common/dav_caldav_calendar_virtual.inc.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
class Sabre_CalDAV_Calendar_Virtual extends Sabre_CalDAV_Calendar {
|
||||
|
||||
/**
|
||||
* Returns a list of ACE's for this node.
|
||||
*
|
||||
* Each ACE has the following properties:
|
||||
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||
* currently the only supported privileges
|
||||
* * 'principal', a url to the principal who owns the node
|
||||
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||
* be updated.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getACL() {
|
||||
|
||||
return array(
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'],
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{DAV:}read',
|
||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
|
||||
'protected' => true,
|
||||
),
|
||||
array(
|
||||
'privilege' => '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}read-free-busy',
|
||||
'principal' => '{DAV:}authenticated',
|
||||
'protected' => true,
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
}
|
|
@ -14,6 +14,23 @@
|
|||
class Sabre_CardDAV_Backend_Std extends Sabre_CardDAV_Backend_Abstract
|
||||
{
|
||||
|
||||
/**
|
||||
* @var null|Sabre_CardDAV_Backend_Std
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @return Sabre_CardDAV_Backend_Std
|
||||
*/
|
||||
public static function getInstance() {
|
||||
if (self::$instance == null) {
|
||||
self::$instance = new Sabre_CardDAV_Backend_Std();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the object
|
||||
*/
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The UserCalenders class contains all calendars associated to one user
|
||||
*
|
||||
* @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_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection, Sabre_DAVACL_IACL {
|
||||
|
||||
/**
|
||||
|
@ -21,7 +13,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
/**
|
||||
* CalDAV backends
|
||||
*
|
||||
* @var array|Sabre_CalDAV_Backend_Abstract[]
|
||||
* @var array|Sabre_CalDAV_Backend_Common[]
|
||||
*/
|
||||
protected $caldavBackends;
|
||||
|
||||
|
@ -36,7 +28,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
* Constructor
|
||||
*
|
||||
* @param Sabre_DAVACL_IPrincipalBackend $principalBackend
|
||||
* @param array|Sabre_CalDAV_Backend_Abstract $caldavBackends
|
||||
* @param array|Sabre_CalDAV_Backend_Common[] $caldavBackends
|
||||
* @param mixed $userUri
|
||||
*/
|
||||
public function __construct(Sabre_DAVACL_IPrincipalBackend $principalBackend, $caldavBackends, $userUri) {
|
||||
|
@ -130,7 +122,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
* Returns a single calendar, by name
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Sabre_DAV_Exception_FileNotFound
|
||||
* @throws Sabre_DAV_Exception_NotFound
|
||||
* @todo needs optimizing
|
||||
* @return \Sabre_CalDAV_Calendar|\Sabre_DAV_INode
|
||||
*/
|
||||
|
@ -141,7 +133,7 @@ class Sabre_CalDAV_AnimexxUserCalendars implements Sabre_DAV_IExtendedCollection
|
|||
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');
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
# Generated automatically - do not change!
|
||||
|
||||
class DBClass_friendica_calendarobjects extends DBClass_animexx {
|
||||
/** @var $PRIMARY_KEY array */
|
||||
public $PRIMARY_KEY = array("id");
|
||||
|
||||
protected $SRC_TABLE = 'calendarobjects';
|
||||
/** @var $calendardata string|null */
|
||||
/** @var $uri string */
|
||||
/** @var $lastmodified string|null */
|
||||
/** @var $etag string */
|
||||
|
||||
public $calendardata, $uri, $lastmodified, $etag;
|
||||
|
||||
/** @var $id int */
|
||||
/** @var $namespace int */
|
||||
/** @var $namespace_id int */
|
||||
/** @var $size int */
|
||||
|
||||
public $id, $namespace, $namespace_id, $size;
|
||||
|
||||
|
||||
protected $_string_fields = array('calendardata', 'uri', 'lastmodified', 'etag');
|
||||
protected $_int_fields = array('id', 'namespace', 'namespace_id', 'size');
|
||||
protected $_null_fields = array('calendardata', 'lastmodified');
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
# Generated automatically - do not change!
|
||||
|
||||
class DBClass_friendica_calendars extends DBClass_animexx {
|
||||
/** @var $PRIMARY_KEY array */
|
||||
public $PRIMARY_KEY = array("namespace", "namespace_id");
|
||||
|
||||
protected $SRC_TABLE = 'calendars';
|
||||
/** @var $calendarcolor string */
|
||||
/** @var $displayname string */
|
||||
/** @var $timezone string */
|
||||
/** @var $description string */
|
||||
|
||||
public $calendarcolor, $displayname, $timezone, $description;
|
||||
|
||||
/** @var $namespace int */
|
||||
/** @var $namespace_id int */
|
||||
/** @var $uid int */
|
||||
/** @var $calendarorder int */
|
||||
/** @var $ctag int */
|
||||
|
||||
public $namespace, $namespace_id, $uid, $calendarorder, $ctag;
|
||||
|
||||
|
||||
protected $_string_fields = array('calendarcolor', 'displayname', 'timezone', 'description');
|
||||
protected $_int_fields = array('namespace', 'namespace_id', 'uid', 'calendarorder', 'ctag');
|
||||
protected $_null_fields = array();
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
# Generated automatically - do not change!
|
||||
|
||||
class DBClass_friendica_jqcalendar extends DBClass_animexx {
|
||||
/** @var $PRIMARY_KEY array */
|
||||
public $PRIMARY_KEY = array("id");
|
||||
|
||||
protected $SRC_TABLE = 'jqcalendar';
|
||||
/** @var $ical_uri string */
|
||||
/** @var $ical_recurr_uri string */
|
||||
/** @var $Subject string|null */
|
||||
/** @var $Location string|null */
|
||||
/** @var $Description string|null */
|
||||
/** @var $StartTime string|null */
|
||||
/** @var $EndTime string|null */
|
||||
/** @var $Color string|null */
|
||||
/** @var $RecurringRule string|null */
|
||||
|
||||
public $ical_uri, $ical_recurr_uri, $Subject, $Location, $Description, $StartTime, $EndTime, $Color, $RecurringRule;
|
||||
|
||||
/** @var $id int */
|
||||
/** @var $uid int */
|
||||
/** @var $namespace int */
|
||||
/** @var $namespace_id int */
|
||||
/** @var $permission_edit int */
|
||||
/** @var $IsAllDayEvent int */
|
||||
|
||||
public $id, $uid, $namespace, $namespace_id, $permission_edit, $IsAllDayEvent;
|
||||
|
||||
|
||||
protected $_string_fields = array('ical_uri', 'ical_recurr_uri', 'Subject', 'Location', 'Description', 'StartTime', 'EndTime', 'Color', 'RecurringRule');
|
||||
protected $_int_fields = array('id', 'uid', 'namespace', 'namespace_id', 'permission_edit', 'IsAllDayEvent');
|
||||
protected $_null_fields = array('Subject', 'Location', 'Description', 'StartTime', 'EndTime', 'Color', 'RecurringRule');
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
# Generated automatically - do not change!
|
||||
|
||||
class DBClass_friendica_notifications extends DBClass_animexx {
|
||||
/** @var $PRIMARY_KEY array */
|
||||
public $PRIMARY_KEY = array("id");
|
||||
|
||||
protected $SRC_TABLE = 'notifications';
|
||||
/** @var $ical_uri string */
|
||||
/** @var $ical_recurr_uri string */
|
||||
/** @var $alert_date string */
|
||||
/** @var $rel_type string */
|
||||
|
||||
public $ical_uri, $ical_recurr_uri, $alert_date, $rel_type;
|
||||
|
||||
/** @var $id int */
|
||||
/** @var $uid int */
|
||||
/** @var $namespace int */
|
||||
/** @var $namespace_id int */
|
||||
/** @var $rel_value int */
|
||||
/** @var $notified int */
|
||||
|
||||
public $id, $uid, $namespace, $namespace_id, $rel_value, $notified;
|
||||
|
||||
/** @var $REL_TYPE_VALUES array */
|
||||
public static $REL_TYPE_VALUES = array('second', 'minute', 'hour', 'day', 'week', 'month', 'year');
|
||||
public static $REL_TYPE_SECOND = 'second';
|
||||
public static $REL_TYPE_MINUTE = 'minute';
|
||||
public static $REL_TYPE_HOUR = 'hour';
|
||||
public static $REL_TYPE_DAY = 'day';
|
||||
public static $REL_TYPE_WEEK = 'week';
|
||||
public static $REL_TYPE_MONTH = 'month';
|
||||
public static $REL_TYPE_YEAR = 'year';
|
||||
|
||||
|
||||
protected $_string_fields = array('ical_uri', 'ical_recurr_uri', 'alert_date', 'rel_type');
|
||||
protected $_int_fields = array('id', 'uid', 'namespace', 'namespace_id', 'rel_value', 'notified');
|
||||
protected $_null_fields = array();
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
class DBClass_animexx
|
||||
{
|
||||
protected $_string_fields = array();
|
||||
protected $_int_fields = array();
|
||||
protected $_float_fields = array();
|
||||
protected $_null_fields = array();
|
||||
|
||||
public $PRIMARY_KEY = array();
|
||||
protected $SRC_TABLE = "";
|
||||
|
||||
/**
|
||||
* @param $dbarray_or_id
|
||||
* @throws Exception
|
||||
*/
|
||||
function __construct($dbarray_or_id)
|
||||
{
|
||||
if (is_numeric($dbarray_or_id) && count($this->PRIMARY_KEY) == 1) {
|
||||
$dbarray_or_id = q("SELECT * FROM %s%s%s WHERE %s=%d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $this->SRC_TABLE, $this->PRIMARY_KEY[0], IntVal($dbarray_or_id)
|
||||
);
|
||||
if (count($dbarray_or_id) == 0) throw new Exception("Not found");
|
||||
$dbarray_or_id = $dbarray_or_id[0];
|
||||
}
|
||||
if (is_array($dbarray_or_id)) {
|
||||
foreach ($this->_string_fields as $field) {
|
||||
$this->$field = $dbarray_or_id[$field];
|
||||
}
|
||||
foreach ($this->_int_fields as $field) {
|
||||
$this->$field = IntVal($dbarray_or_id[$field]);
|
||||
}
|
||||
foreach ($this->_float_fields as $field) {
|
||||
$this->$field = FloatVal($dbarray_or_id[$field]);
|
||||
}
|
||||
} else throw new Exception("Not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function toArray()
|
||||
{
|
||||
$arr = array();
|
||||
foreach ($this->_string_fields as $field) $arr[$field] = $this->$field;
|
||||
foreach ($this->_int_fields as $field) $arr[$field] = $this->$field;
|
||||
foreach ($this->_float_fields as $field) $arr[$field] = $this->$field;
|
||||
return $arr;
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
abstract class VirtualCalSourceBackend {
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $uid
|
||||
* @param int $namespace
|
||||
*/
|
||||
static public function invalidateCache($uid = 0, $namespace = 0) {
|
||||
q("DELETE FROM %s%scache_synchronized WHERE `uid` = %d AND `namespace` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid), IntVal($namespace));
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @param int $uid
|
||||
* @param int $namespace_id
|
||||
*/
|
||||
static abstract function createCache($uid = 0, $namespace_id = 0);
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param int $uid
|
||||
* @param int $namespace
|
||||
* @return array
|
||||
*/
|
||||
static public function getCachedItems($uid = 0, $namespace = 0) {
|
||||
$uid = IntVal($uid);
|
||||
$namespace = IntVal($namespace);
|
||||
$r = q("SELECT COUNT(*) n FROM %s%scache_synchronized WHERE `uid` = %d AND `namespace` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($uid), $namespace);
|
||||
|
||||
if ($r[0]["n"] == 0) self::createCache();
|
||||
|
||||
$r = q("SELECT * FROM %s%scal_virtual_object_cache WHERE `uid` = %d AND `namespace` = %d",
|
||||
CALDAV_SQL_DB, CALDAV_SQL_PREFIX, $uid, $namespace);
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @param int $uid
|
||||
* @param int $namespace_id
|
||||
* @param string $date_from
|
||||
* @param string $date_to
|
||||
* @return array
|
||||
*/
|
||||
abstract static public function getItemsByTime($uid = 0, $namespace_id = 0, $date_from = "", $date_to = "");
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @abstract
|
||||
* @param int $uid
|
||||
* @param string $uri
|
||||
* @return array
|
||||
*/
|
||||
abstract static public function getItemsByUri($uid = 0, $uri);
|
||||
|
||||
}
|
|
@ -16,16 +16,19 @@ function wdcal_edit_getStartEnd() {
|
|||
|
||||
function wdcal_edit_checktime_startChanged() {
|
||||
"use strict";
|
||||
|
||||
var time = wdcal_edit_getStartEnd();
|
||||
if (time.start.getTime() >= time.end.getTime()) {
|
||||
var newend = new Date(time.start.getTime() + 3600000);
|
||||
$("#cal_end_date").datepicker("setDate", newend);
|
||||
$.timePicker("#cal_end_time").setTime(newend);
|
||||
}
|
||||
wdcal_edit_recur_recalc();
|
||||
}
|
||||
|
||||
function wdcal_edit_checktime_endChanged() {
|
||||
"use strict";
|
||||
|
||||
var time = wdcal_edit_getStartEnd();
|
||||
if (time.start.getTime() >= time.end.getTime()) {
|
||||
var newstart = new Date(time.end.getTime() - 3600000);
|
||||
|
@ -34,10 +37,34 @@ function wdcal_edit_checktime_endChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
function wdcal_edit_init(dateFormat) {
|
||||
function wdcal_edit_recur_recalc() {
|
||||
"use strict";
|
||||
|
||||
var start = $("#cal_start_date").datepicker("getDate");
|
||||
$(".rec_month_name").text($.datepicker._defaults.monthNames[start.getMonth()]);
|
||||
$("#rec_yearly_day option[value=bymonthday]").text($("#rec_yearly_day option[value=bymonthday]").data("orig").replace("#num#", start.getDate()));
|
||||
$("#rec_monthly_day option[value=bymonthday]").text($("#rec_monthly_day option[value=bymonthday]").data("orig").replace("#num#", start.getDate()));
|
||||
var month = new Date(start.getFullYear(), start.getMonth() + 1, 0);
|
||||
var monthlast = month.getDate() - start.getDate() + 1;
|
||||
$("#rec_yearly_day option[value=bymonthday_neg]").text($("#rec_yearly_day option[value=bymonthday_neg]").data("orig").replace("#num#", monthlast));
|
||||
$("#rec_monthly_day option[value=bymonthday_neg]").text($("#rec_monthly_day option[value=bymonthday_neg]").data("orig").replace("#num#", monthlast));
|
||||
var wk = Math.ceil(start.getDate() / 7);
|
||||
var wkname = $.datepicker._defaults.dayNames[start.getDay()];
|
||||
$("#rec_yearly_day option[value=byday]").text($("#rec_yearly_day option[value=byday]").data("orig").replace("#num#", wk).replace("#wkday#", wkname));
|
||||
$("#rec_monthly_day option[value=byday]").text($("#rec_monthly_day option[value=byday]").data("orig").replace("#num#", wk).replace("#wkday#", wkname));
|
||||
var wk_inv = Math.ceil(monthlast / 7);
|
||||
$("#rec_yearly_day option[value=byday_neg]").text($("#rec_yearly_day option[value=byday_neg]").data("orig").replace("#num#", wk_inv).replace("#wkday#", wkname));
|
||||
$("#rec_monthly_day option[value=byday_neg]").text($("#rec_monthly_day option[value=byday_neg]").data("orig").replace("#num#", wk_inv).replace("#wkday#", wkname));
|
||||
}
|
||||
|
||||
function wdcal_edit_init(dateFormat, base_path) {
|
||||
"use strict";
|
||||
|
||||
$("#cal_color").colorPicker();
|
||||
$("#color_override").on("click", function() {
|
||||
if ($("#color_override").prop("checked")) $("#cal_color_holder").show();
|
||||
else $("#cal_color_holder").hide();
|
||||
});
|
||||
|
||||
$("#cal_start_time").timePicker({ step: 15 }).on("change", wdcal_edit_checktime_startChanged);
|
||||
$("#cal_end_time").timePicker().on("change", wdcal_edit_checktime_endChanged);
|
||||
|
@ -49,6 +76,8 @@ function wdcal_edit_init(dateFormat) {
|
|||
"dateFormat": dateFormat
|
||||
}).on("change", wdcal_edit_checktime_endChanged);
|
||||
|
||||
$("#rec_until_date").datepicker({ "dateFormat": dateFormat });
|
||||
|
||||
$("#notification").on("click change", function() {
|
||||
if ($(this).prop("checked")) $("#notification_detail").show();
|
||||
else ($("#notification_detail")).hide();
|
||||
|
@ -58,4 +87,135 @@ function wdcal_edit_init(dateFormat) {
|
|||
if ($(this).prop("checked")) $("#cal_end_time, #cal_start_time").hide();
|
||||
else $("#cal_end_time, #cal_start_time").show();
|
||||
}).change();
|
||||
|
||||
$("#rec_frequency").on("click change", function() {
|
||||
var val = $("#rec_frequency").val();
|
||||
if (val == "") $("#rec_details").hide();
|
||||
else $("#rec_details").show();
|
||||
|
||||
if (val == "daily") $(".rec_daily").show();
|
||||
else $(".rec_daily").hide();
|
||||
|
||||
if (val == "weekly") $(".rec_weekly").show();
|
||||
else $(".rec_weekly").hide();
|
||||
|
||||
if (val == "monthly") $(".rec_monthly").show();
|
||||
else $(".rec_monthly").hide();
|
||||
|
||||
if (val == "yearly") $(".rec_yearly").show();
|
||||
else $(".rec_yearly").hide();
|
||||
}).change();
|
||||
|
||||
$("#rec_until_type").on("click change", function() {
|
||||
var val = $("#rec_until_type").val();
|
||||
|
||||
if (val == "count") $("#rec_until_count").show();
|
||||
else $("#rec_until_count").hide();
|
||||
|
||||
if (val == "date") $("#rec_until_date").show();
|
||||
else $("#rec_until_date").hide();
|
||||
}).change();
|
||||
|
||||
$("#rec_yearly_day option, #rec_monthly_day option").each(function() {
|
||||
$(this).data("orig", $(this).text());
|
||||
});
|
||||
|
||||
$("#new_alarm_adder a").click(function(ev) {
|
||||
$("#new_alarm").val("1");
|
||||
$("#noti_new_row").show();
|
||||
$("#new_alarm_adder").hide();
|
||||
ev.preventDefault();
|
||||
});
|
||||
|
||||
wdcal_edit_recur_recalc();
|
||||
|
||||
$(document).on("click", ".exception_remover", function(ev) {
|
||||
ev.preventDefault();
|
||||
var $this = $(this),
|
||||
$par = $this.parents(".rec_exceptions");
|
||||
$this.parents(".except").remove();
|
||||
if ($par.find(".rec_exceptions_holder").children().length == 0) {
|
||||
$par.find(".rec_exceptions_holder").hide();
|
||||
$par.find(".rec_exceptions_none").show();
|
||||
}
|
||||
});
|
||||
|
||||
$(".exception_adder").click(function(ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
var exceptions = [];
|
||||
$(".rec_exceptions .except input").each(function() {
|
||||
exceptions.push($(this).val());
|
||||
});
|
||||
var rec_weekly_byday = [];
|
||||
$(".rec_weekly_byday:checked").each(function() {
|
||||
rec_weekly_byday.push($(this).val());
|
||||
});
|
||||
var rec_daily_byday = [];
|
||||
$(".rec_daily_byday:checked").each(function() {
|
||||
rec_daily_byday.push($(this).val());
|
||||
});
|
||||
var opts = {
|
||||
"start_date": $("input[name=start_date]").val(),
|
||||
"start_time": $("input[name=start_time]").val(),
|
||||
"end_date": $("input[name=end_date]").val(),
|
||||
"end_time": $("input[name=end_time]").val(),
|
||||
"rec_frequency": $("#rec_frequency").val(),
|
||||
"rec_interval": $("#rec_interval").val(),
|
||||
"rec_until_type": $("#rec_until_type").val(),
|
||||
"rec_until_count": $("#rec_until_count").val(),
|
||||
"rec_until_date": $("#rec_until_date").val(),
|
||||
"rec_weekly_byday": rec_weekly_byday,
|
||||
"rec_daily_byday": rec_daily_byday,
|
||||
"rec_weekly_wkst": $("input[name=rec_weekly_wkst]:checked").val(),
|
||||
"rec_monthly_day": $("#rec_monthly_day").val(),
|
||||
"rec_yearly_day": $("#rec_yearly_day").val(),
|
||||
"rec_exceptions": exceptions
|
||||
};
|
||||
if ($("#cal_allday").prop("checked")) opts["allday"] = 1;
|
||||
var $dial = $("<div id='exception_setter_dialog'>Loading...</div>");
|
||||
$dial.appendTo("body");
|
||||
$dial.dialog({
|
||||
"width": 400,
|
||||
"height": 300,
|
||||
"title": "Exceptions"
|
||||
});
|
||||
$dial.load(base_path + "getExceptionDates/", opts, function() {
|
||||
$dial.find(".exception_selector_link").click(function(ev2) {
|
||||
ev2.preventDefault();
|
||||
var ts = $(this).data("timestamp");
|
||||
var str = $(this).html();
|
||||
var $part = $("<div data-timestamp='" + ts + "' class='except'><input type='hidden' class='rec_exception' name='rec_exceptions[]' value='" + ts + "'><a href='#' class='exception_remover'>[remove]</a> " + str + "</div>");
|
||||
var found = false;
|
||||
$(".rec_exceptions_holder .except").each(function() {
|
||||
if (!found && ts < $(this).data("timestamp")) {
|
||||
found = true;
|
||||
$part.insertBefore(this);
|
||||
}
|
||||
});
|
||||
if (!found) $(".rec_exceptions_holder").append($part);
|
||||
$(".rec_exceptions .rec_exceptions_holder").show();
|
||||
$(".rec_exceptions .rec_exceptions_none").hide();
|
||||
|
||||
$dial.dialog("destroy").remove();
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function wdcal_edit_calendars_start(dateFormat, base_path) {
|
||||
"use strict";
|
||||
|
||||
$(".cal_color").colorPicker();
|
||||
|
||||
$(".delete_cal").click(function(ev) {
|
||||
if (!confirm("Do you really want to delete this calendar? All events will be moved to another private calendar.")) ev.preventDefault();
|
||||
});
|
||||
|
||||
$(".calendar_add_caller").click(function(ev) {
|
||||
$(".cal_add_row").show();
|
||||
$(this).parents("div").hide();
|
||||
ev.preventDefault();
|
||||
});
|
||||
}
|
|
@ -5,8 +5,10 @@
|
|||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
var __WDAY = new Array(i18n.xgcalendar.dateformat.sun, i18n.xgcalendar.dateformat.mon, i18n.xgcalendar.dateformat.tue, i18n.xgcalendar.dateformat.wed, i18n.xgcalendar.dateformat.thu, i18n.xgcalendar.dateformat.fri, i18n.xgcalendar.dateformat.sat);
|
||||
var __MonthName = new Array(i18n.xgcalendar.dateformat.jan, i18n.xgcalendar.dateformat.feb, i18n.xgcalendar.dateformat.mar, i18n.xgcalendar.dateformat.apr, i18n.xgcalendar.dateformat.may, i18n.xgcalendar.dateformat.jun, i18n.xgcalendar.dateformat.jul, i18n.xgcalendar.dateformat.aug, i18n.xgcalendar.dateformat.sep, i18n.xgcalendar.dateformat.oct, i18n.xgcalendar.dateformat.nov, i18n.xgcalendar.dateformat.dec);
|
||||
var __WDAY = $.datepicker._defaults.dayNamesShort;
|
||||
//new Array(i18n.xgcalendar.dateformat.sun, i18n.xgcalendar.dateformat.mon, i18n.xgcalendar.dateformat.tue, i18n.xgcalendar.dateformat.wed, i18n.xgcalendar.dateformat.thu, i18n.xgcalendar.dateformat.fri, i18n.xgcalendar.dateformat.sat);
|
||||
var __MonthName = $.datepicker._defaults.monthNamesShort;
|
||||
//new Array(i18n.xgcalendar.dateformat.jan, i18n.xgcalendar.dateformat.feb, i18n.xgcalendar.dateformat.mar, i18n.xgcalendar.dateformat.apr, i18n.xgcalendar.dateformat.may, i18n.xgcalendar.dateformat.jun, i18n.xgcalendar.dateformat.jul, i18n.xgcalendar.dateformat.aug, i18n.xgcalendar.dateformat.sep, i18n.xgcalendar.dateformat.oct, i18n.xgcalendar.dateformat.nov, i18n.xgcalendar.dateformat.dec);
|
||||
|
||||
|
||||
function dateFormat(format) {
|
||||
|
@ -769,8 +771,8 @@
|
|||
for (i = 0; i < l; i++) {
|
||||
var $col = $container.find(".tgCol" + i);
|
||||
for (var j = 0; j < events[i].length; j++) {
|
||||
if (events[i][j].event["color"] && events[i][j].event["color"].match(/^#[0-9a-f]{6}$/i)) {
|
||||
c = events[i][j].event["color"];
|
||||
if (events[i][j].event["color"] && events[i][j].event["color"].match(/^[0-9a-f]{6}$/i)) {
|
||||
c = "#" + events[i][j].event["color"];
|
||||
}
|
||||
else {
|
||||
c = option.std_color;
|
||||
|
@ -787,7 +789,7 @@
|
|||
function getTitle(event) {
|
||||
var timeshow, eventshow;
|
||||
var showtime = event["is_allday"] != 1;
|
||||
eventshow = event["subject"];
|
||||
eventshow = event["summary"];
|
||||
var startformat = getymformat(event["start"], null, showtime, true);
|
||||
var endformat = getymformat(event["end"], event["start"], showtime, true);
|
||||
timeshow = dateFormat.call(event["start"], startformat) + " - " + dateFormat.call(event["end"], endformat);
|
||||
|
@ -819,7 +821,7 @@
|
|||
var p = { bdcolor:theme[0], bgcolor2:theme[0], bgcolor1:theme[2], width:"70%", icon:"", title:"", data:"" };
|
||||
p.starttime = pZero(e.st.hour) + ":" + pZero(e.st.minute);
|
||||
p.endtime = pZero(e.et.hour) + ":" + pZero(e.et.minute);
|
||||
p.content = e.event["subject"];
|
||||
p.content = e.event["summary"];
|
||||
p.title = getTitle(e.event);
|
||||
var icons = [];
|
||||
if (e.event["has_notification"] == 1) icons.push("<I class=\"cic cic-tmr\"> </I>");
|
||||
|
@ -1146,12 +1148,12 @@
|
|||
var p = { color:theme[2], title:"", extendClass:"", extendHTML:"", data:"" };
|
||||
|
||||
p.title = getTitle(e.event);
|
||||
p.id = "bbit_cal_event_" + e.event["uri"];
|
||||
p.id = "bbit_cal_event_" + e.event["jq_id"];
|
||||
if (option.enableDrag && e.event["is_editable_quick"] == 1) {
|
||||
p.eclass = "drag";
|
||||
}
|
||||
else {
|
||||
p.eclass = "cal_" + e.event["uri"];
|
||||
p.eclass = "cal_" + e.event["jq_id"];
|
||||
}
|
||||
p.eclass += " " + (e.event["is_editable"] ? "editable" : "not_editable");
|
||||
var sp = "<span style=\"cursor: pointer\">{content}</span>";
|
||||
|
@ -1175,10 +1177,10 @@
|
|||
}
|
||||
var cen;
|
||||
if (!e.allday && !sf) {
|
||||
cen = pZero(e.st.hour) + ":" + pZero(e.st.minute) + " " + e.event["subject"];
|
||||
cen = pZero(e.st.hour) + ":" + pZero(e.st.minute) + " " + e.event["summary"];
|
||||
}
|
||||
else {
|
||||
cen = e.event["subject"];
|
||||
cen = e.event["summary"];
|
||||
}
|
||||
var content = [];
|
||||
if (cen.indexOf("Geburtstag:") == 0) {
|
||||
|
@ -1294,7 +1296,7 @@
|
|||
}
|
||||
if (option.eventItems[i]["start"] >= es) {
|
||||
for (var j = 0; j < jl; j++) {
|
||||
if (option.eventItems[i]["uri"] == events[j]["uri"] && option.eventItems[i]["start"] < start) {
|
||||
if (option.eventItems[i]["jq_id"] == events[j]["jq_id"] && option.eventItems[i]["start"] < start) {
|
||||
events.splice(j, 1); //for duplicated event
|
||||
jl--;
|
||||
break;
|
||||
|
@ -1477,7 +1479,7 @@
|
|||
$("#bbit-cs-buddle").css("visibility", "hidden");
|
||||
var calid = $("#bbit-cs-id").val();
|
||||
var param = [
|
||||
{ "name":"calendarId", value:calid },
|
||||
{ "name":"jq_id", value:calid },
|
||||
{ "name":"type", value:type}
|
||||
];
|
||||
var de = rebyKey(calid, true);
|
||||
|
@ -1609,8 +1611,8 @@
|
|||
var location = "";
|
||||
if (data["location"] != "") location = data["location"] + ", ";
|
||||
$("#bbit-cs-buddle-timeshow").html(location + ss.join(""));
|
||||
$bud.find(".bbit-cs-what").html(data["subject"]).attr("href", data["url_detail"]);
|
||||
$("#bbit-cs-id").val(data["uri"]);
|
||||
$bud.find(".bbit-cs-what").html(data["summary"]).attr("href", data["url_detail"]);
|
||||
$("#bbit-cs-id").val(data["jq_id"]);
|
||||
$bud.data("cdata", data);
|
||||
$bud.css({ "visibility":"visible", left:pos.left, top:pos.top });
|
||||
|
||||
|
@ -1684,11 +1686,11 @@
|
|||
return false;
|
||||
}
|
||||
option.isloading = true;
|
||||
var id = data["uri"];
|
||||
var id = data["jq_id"];
|
||||
var os = data["start"];
|
||||
var od = data["end"];
|
||||
var param = [
|
||||
{ "name":"calendarId", value:id },
|
||||
{ "name":"jq_id", value:id },
|
||||
{ "name":"CalendarStartTime", value:Math.floor(start.getTime() / 1000) },
|
||||
{ "name":"CalendarEndTime", value:Math.floor(end.getTime() / 1000) }
|
||||
];
|
||||
|
@ -1744,7 +1746,7 @@
|
|||
temparr.push('<table class="cb-table"><tbody><tr><th class="cb-key">');
|
||||
temparr.push(i18n.xgcalendar.time, ':</th><td class=cb-value><div id="bbit-cal-buddle-timeshow"></div></td></tr><tr><th class="cb-key">');
|
||||
temparr.push(i18n.xgcalendar.content, ':</th><td class="cb-value"><div class="textbox-fill-wrapper"><div class="textbox-fill-mid"><input id="bbit-cal-what" class="textbox-fill-input"/></div></div><div class="cb-example">');
|
||||
temparr.push(i18n.xgcalendar.example, '</div></td></tr></tbody></table><input id="bbit-cal-start" type="hidden"/><input id="bbit-cal-end" type="hidden"/><input id="bbit-cal-allday" type="hidden"/><input id="bbit-cal-quickAddBTN" value="');
|
||||
temparr.push(i18n.xgcalendar.example, '</div></td></tr></tbody></table><input id="bbit-cal-start" type="hidden"/><input id="bbit-cal-end" type="hidden"/><input id="bbit-cal-allday" type="hidden"/><input value="');
|
||||
temparr.push(i18n.xgcalendar.create_event, '" type="submit"/> <a href="" class="lk bbit-cal-editLink">');
|
||||
temparr.push(i18n.xgcalendar.update_detail, ' <StrONG>>></StrONG></SPAN></div></div></div><tr><td><div id="bl1" class="bubble-corner"><div class="bubble-sprite bubble-bl"></div></div><td><div class="bubble-bottom"></div><td><div id="br1" class="bubble-corner"><div class="bubble-sprite bubble-br"></div></div></tr></tbody></table><div id="bubbleClose1" class="bubble-closebutton"></div><div id="prong2" class="prong"><div class=bubble-sprite></div></div></div>');
|
||||
temparr.push('</form>');
|
||||
|
@ -1789,7 +1791,6 @@
|
|||
param[param.length] = option.extParam[pi];
|
||||
}
|
||||
}
|
||||
|
||||
if (option.quickAddHandler && $.isFunction(option.quickAddHandler)) {
|
||||
option.quickAddHandler.call(this, param);
|
||||
$("#bbit-cal-buddle").css("visibility", "hidden");
|
||||
|
@ -1804,8 +1805,9 @@
|
|||
ed = new Date(dateend),
|
||||
diff = DateDiff("d", sd, ed);
|
||||
var newdata = {
|
||||
"uri":"",
|
||||
"subject":what,
|
||||
"jq_id":"",
|
||||
"ev_id":"",
|
||||
"summary":what,
|
||||
"start":sd,
|
||||
"end":ed,
|
||||
"is_allday":(allday == "1" ? 1 : 0),
|
||||
|
@ -1859,15 +1861,19 @@
|
|||
$("#bbit-cal-start").val(start.getTime());
|
||||
$("#bbit-cal-end").val(end.getTime());
|
||||
|
||||
var addurl = option.baseurl + "new/?start=" + Math.floor($("#bbit-cal-start").val() / 1000) + "&end=" + Math.floor($("#bbit-cal-end").val() / 1000) + "&isallday=" + (isallday ? "1" : "0");
|
||||
var addurl = option.baseurl + "new/?start=" + Math.floor($("#bbit-cal-start").val() / 1000) + "&end=" + Math.floor($("#bbit-cal-end").val() / 1000) +
|
||||
"&isallday=" + (isallday ? "1" : "0") + "&title=";
|
||||
buddle.find(".bbit-cal-editLink").attr("href", addurl);
|
||||
|
||||
buddle.css({ "visibility":"visible", left:off.left, top:off.top });
|
||||
calwhat.blur().focus(); //add 2010-01-26 blur() fixed chrome
|
||||
$(document).one("mousedown", function () {
|
||||
$(document).on("mousedown", function () {
|
||||
$("#bbit-cal-buddle").css("visibility", "hidden");
|
||||
releasedragevent();
|
||||
});
|
||||
$(document).on("keyup", "#bbit-cal-what", function() {
|
||||
buddle.find(".bbit-cal-editLink").attr("href", addurl + encodeURIComponent($("#bbit-cal-what").val()));
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1886,7 +1892,7 @@
|
|||
var sl = option.eventItems.length;
|
||||
var i = -1;
|
||||
for (var j = 0; j < sl; j++) {
|
||||
if (option.eventItems[j]["uri"] == key) {
|
||||
if (option.eventItems[j]["jq_id"] == key) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
|
@ -2352,7 +2358,7 @@
|
|||
d.target.hide();
|
||||
ny = gP(gh.sh, gh.sm);
|
||||
d.top = ny;
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], false, false, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], false, false, data["color"]);
|
||||
cpwrap = $("<div class='ca-evpi drag-chip-wrapper' style='top:" + ny + "px'/>").html(tempdata);
|
||||
evid = ".tgOver" + d.target.parent().data("col");
|
||||
$gridcontainer.find(evid).append(cpwrap);
|
||||
|
@ -2389,7 +2395,7 @@
|
|||
//log.info("ny=" + ny);
|
||||
gh = gW(ny, ny + d.h);
|
||||
//log.info("sh=" + gh.sh + ",sm=" + gh.sm);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], false, false, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], false, false, data["color"]);
|
||||
d.cpwrap.css("top", ny + "px").html(tempdata);
|
||||
}
|
||||
d.ny = ny;
|
||||
|
@ -2415,7 +2421,7 @@
|
|||
d.target.hide();
|
||||
ny = gP(gh.sh, gh.sm);
|
||||
d.top = ny;
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], "100%", true, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], "100%", true, data["color"]);
|
||||
cpwrap = $("<div class='ca-evpi drag-chip-wrapper' style='top:" + ny + "px'/>").html(tempdata);
|
||||
evid = ".tgOver" + d.target.parent().data("col");
|
||||
$gridcontainer.find(evid).append(cpwrap);
|
||||
|
@ -2427,7 +2433,7 @@
|
|||
nh = pnh > 1 ? nh - pnh + Math.ceil(option.hour_height / 2) : nh - pnh;
|
||||
if (d.nh != nh) {
|
||||
gh = gW(d.top, d.top + nh);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["subject"], "100%", true, data["color"]);
|
||||
tempdata = buildtempdayevent(gh.sh, gh.sm, gh.eh, gh.em, gh.h, data["summary"], "100%", true, data["color"]);
|
||||
d.cpwrap.html(tempdata);
|
||||
}
|
||||
d.nh = nh;
|
||||
|
|
|
@ -7,26 +7,7 @@ var i18n = $.extend({}, i18n || {}, {
|
|||
"year_index": 2,
|
||||
"month_index": 1,
|
||||
"day_index": 0,
|
||||
"day": "d",
|
||||
"sun": "So",
|
||||
"mon": "Mo",
|
||||
"tue": "Di",
|
||||
"wed": "Mi",
|
||||
"thu": "Do",
|
||||
"fri": "Fr",
|
||||
"sat": "Sa",
|
||||
"jan": "Jan",
|
||||
"feb": "Feb",
|
||||
"mar": "Mär",
|
||||
"apr": "Apr",
|
||||
"may": "Mai",
|
||||
"jun": "Jun",
|
||||
"jul": "Jul",
|
||||
"aug": "Aug",
|
||||
"sep": "Sep",
|
||||
"oct": "Okt",
|
||||
"nov": "Nov",
|
||||
"dec": "Dez"
|
||||
"day": "d"
|
||||
},
|
||||
"no_implemented": "Nicht eingebaut",
|
||||
"to_date_view": "Zum aktuellen Datum gehen",
|
||||
|
|
|
@ -7,26 +7,7 @@ var i18n = $.extend({}, i18n || {}, {
|
|||
"year_index": 2,
|
||||
"month_index": 1,
|
||||
"day_index": 0,
|
||||
"day": "d",
|
||||
"sun": "Su",
|
||||
"mon": "Mo",
|
||||
"tue": "Tu",
|
||||
"wed": "Mi",
|
||||
"thu": "Th",
|
||||
"fri": "Fr",
|
||||
"sat": "Sa",
|
||||
"jan": "Jan",
|
||||
"feb": "Feb",
|
||||
"mar": "Mar",
|
||||
"apr": "Apr",
|
||||
"may": "May",
|
||||
"jun": "Jun",
|
||||
"jul": "Jul",
|
||||
"aug": "Aug",
|
||||
"sep": "Sep",
|
||||
"oct": "Oct",
|
||||
"nov": "Nov",
|
||||
"dec": "Dec"
|
||||
"day": "d"
|
||||
},
|
||||
"no_implemented": "Not implemented",
|
||||
"to_date_view": "Go to today",
|
||||
|
|
238
dav/common/wdcal_backend.inc.php
Normal file
238
dav/common/wdcal_backend.inc.php
Normal file
|
@ -0,0 +1,238 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $obj
|
||||
* @return string
|
||||
*/
|
||||
function wdcal_jsonp_encode($obj)
|
||||
{
|
||||
$str = json_encode($obj);
|
||||
if (isset($_REQUEST["callback"])) {
|
||||
$str = $_REQUEST["callback"] . "(" . $str . ")";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $day
|
||||
* @param int $weekstartday
|
||||
* @param int $num_days
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
function wdcal_get_list_range_params($day, $weekstartday, $num_days, $type)
|
||||
{
|
||||
$phpTime = IntVal($day);
|
||||
switch ($type) {
|
||||
case "month":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), 1, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime) + 1, 1, date("Y", $phpTime));
|
||||
break;
|
||||
case "week":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + 1;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + 7, date("Y", $phpTime));
|
||||
break;
|
||||
case "multi_days":
|
||||
//suppose first day of a week is monday
|
||||
$monday = date("d", $phpTime) - date('N', $phpTime) + $weekstartday;
|
||||
//echo date('N', $phpTime);
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), $monday, date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), $monday + $num_days, date("Y", $phpTime));
|
||||
break;
|
||||
case "day":
|
||||
$st = mktime(0, 0, 0, date("m", $phpTime), date("d", $phpTime), date("Y", $phpTime));
|
||||
$et = mktime(0, 0, -1, date("m", $phpTime), date("d", $phpTime) + 1, date("Y", $phpTime));
|
||||
break;
|
||||
default:
|
||||
return array(0, 0);
|
||||
}
|
||||
return array($st, $et);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @param string $right
|
||||
* @return null|Sabre_CalDAV_Calendar
|
||||
*/
|
||||
function wdcal_print_feed_getCal(&$server, $right)
|
||||
{
|
||||
$cals = dav_get_current_user_calendars($server, $right);
|
||||
$calfound = null;
|
||||
for ($i = 0; $i < count($cals) && $calfound === null; $i++) {
|
||||
$prop = $cals[$i]->getProperties(array("id"));
|
||||
if (isset($prop["id"]) && (!isset($_REQUEST["cal"]) || in_array($prop["id"], $_REQUEST["cal"]))) $calfound = $cals[$i];
|
||||
}
|
||||
return $calfound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function wdcal_print_feed($base_path = "")
|
||||
{
|
||||
$server = dav_create_server(true, true, false);
|
||||
|
||||
$ret = null;
|
||||
|
||||
$method = $_GET["method"];
|
||||
switch ($method) {
|
||||
case "add":
|
||||
$cs = wdcal_print_feed_getCal($server, DAV_ACL_WRITE);
|
||||
if ($cs == null) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$item = dav_create_empty_vevent();
|
||||
$component = dav_get_eventComponent($item);
|
||||
$component->add("SUMMARY", icalendar_sanitize_string(dav_compat_parse_text_serverside("CalendarTitle")));
|
||||
|
||||
if (isset($_REQUEST["allday"])) $type = Sabre_VObject_Property_DateTime::DATE;
|
||||
else $type = Sabre_VObject_Property_DateTime::LOCALTZ;
|
||||
|
||||
$datetime_start = new Sabre_VObject_Property_DateTime("DTSTART");
|
||||
$datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarStartTime"]))), $type);
|
||||
$datetime_end = new Sabre_VObject_Property_DateTime("DTEND");
|
||||
$datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarEndTime"]))), $type);
|
||||
|
||||
$component->add($datetime_start);
|
||||
$component->add($datetime_end);
|
||||
|
||||
$uid = $component->__get("UID");
|
||||
$data = $item->serialize();
|
||||
|
||||
$cs->createFile($uid . ".ics", $data);
|
||||
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'add success',
|
||||
'Data' => $uid . ".ics",
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$ret = array(
|
||||
'IsSuccess' => false,
|
||||
'Msg' => $e->__toString(),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "list":
|
||||
$weekstartday = (isset($_REQUEST["weekstartday"]) ? IntVal($_REQUEST["weekstartday"]) : 1); // 1 = Monday
|
||||
$num_days = (isset($_REQUEST["num_days"]) ? IntVal($_REQUEST["num_days"]) : 7);
|
||||
$ret = null;
|
||||
|
||||
$date = wdcal_get_list_range_params($_REQUEST["showdate"], $weekstartday, $num_days, $_REQUEST["viewtype"]);
|
||||
$ret = array();
|
||||
$ret['events'] = array();
|
||||
$ret["issort"] = true;
|
||||
$ret["start"] = $date[0];
|
||||
$ret["end"] = $date[1];
|
||||
$ret['error'] = null;
|
||||
|
||||
$cals = dav_get_current_user_calendars($server, DAV_ACL_READ);
|
||||
foreach ($cals as $cal) {
|
||||
$prop = $cal->getProperties(array("id"));
|
||||
if (isset($prop["id"]) && (!isset($_REQUEST["cal"]) || in_array($prop["id"], $_REQUEST["cal"]))) {
|
||||
$backend = wdcal_calendar_factory_by_id($prop["id"]);
|
||||
$events = $backend->listItemsByRange($prop["id"], $date[0], $date[1], $base_path);
|
||||
$ret["events"] = array_merge($ret["events"], $events);
|
||||
}
|
||||
}
|
||||
|
||||
$tmpev = array();
|
||||
foreach ($ret["events"] as $e) {
|
||||
if (!isset($tmpev[$e["start"]])) $tmpev[$e["start"]] = array();
|
||||
$tmpev[$e["start"]][] = $e;
|
||||
}
|
||||
ksort($tmpev);
|
||||
$ret["events"] = array();
|
||||
foreach ($tmpev as $e) foreach ($e as $f) $ret["events"][] = $f;
|
||||
|
||||
break;
|
||||
case "update":
|
||||
$r = q("SELECT `calendarobject_id`, `calendar_id` FROM %s%sjqcalendar WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["jq_id"]));
|
||||
if (count($r) != 1) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$cs = dav_get_current_user_calendar_by_id($server, $r[0]["calendar_id"], DAV_ACL_READ);
|
||||
$obj_uri = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($r[0]["calendarobject_id"]);
|
||||
|
||||
$vObject = dav_get_current_user_calendarobject($server, $cs, $obj_uri["uri"], DAV_ACL_WRITE);
|
||||
$component = dav_get_eventComponent($vObject);
|
||||
|
||||
if (!$component) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
|
||||
if (isset($_REQUEST["allday"])) $type = Sabre_VObject_Property_DateTime::DATE;
|
||||
else $type = Sabre_VObject_Property_DateTime::LOCALTZ;
|
||||
|
||||
$datetime_start = new Sabre_VObject_Property_DateTime("DTSTART");
|
||||
$datetime_start->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarStartTime"]))), $type);
|
||||
$datetime_end = new Sabre_VObject_Property_DateTime("DTEND");
|
||||
$datetime_end->setDateTime(new DateTime(date("Y-m-d H:i:s", IntVal($_REQUEST["CalendarEndTime"]))), $type);
|
||||
|
||||
$component->__unset("DTSTART");
|
||||
$component->__unset("DTEND");
|
||||
$component->add($datetime_start);
|
||||
$component->add($datetime_end);
|
||||
|
||||
$data = $vObject->serialize();
|
||||
/** @var Sabre_CalDAV_CalendarObject $child */
|
||||
$child = $cs->getChild($obj_uri["uri"]);
|
||||
$child->put($data);
|
||||
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
break;
|
||||
case "remove":
|
||||
$r = q("SELECT `calendarobject_id`, `calendar_id` FROM %s%sjqcalendar WHERE `id`=%d", CALDAV_SQL_DB, CALDAV_SQL_PREFIX, IntVal($_REQUEST["jq_id"]));
|
||||
if (count($r) != 1) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
try {
|
||||
$cs = dav_get_current_user_calendar_by_id($server, $r[0]["calendar_id"], DAV_ACL_WRITE);
|
||||
$obj_uri = Sabre_CalDAV_Backend_Common::loadCalendarobjectById($r[0]["calendarobject_id"]);
|
||||
$child = $cs->getChild($obj_uri["uri"]);
|
||||
$child->delete();
|
||||
|
||||
$ret = array(
|
||||
'IsSuccess' => true,
|
||||
'Msg' => 'Succefully',
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
echo wdcal_jsonp_encode(array('IsSuccess' => false,
|
||||
'Msg' => t('No access')));
|
||||
killme();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
echo wdcal_jsonp_encode($ret);
|
||||
killme();
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue