RFC 4791
Calendaring Extensions to WebDAV (CalDAV)
RFC 4791: Calendaring Extensions to WebDAV (CalDAV) ๐ฆ
okay bestie, this one is the CalDAV spec, and it's giving calendar-sync main character energy โจ. It's a Standards Track document from March 2007. The authors are C. Daboo (Apple), B. Desruisseaux (Oracle), and L. Dusseault (CommerceNet). The header doesn't list any RFCs it obsoletes or updates, so it's a fresh start ๐ธ.
Status of This Memo ๐
ok so this doc is an Internet standards track protocol for the Internet community ๐ . It's basically asking everyone to talk about it and send over ideas for making it better ๐ซถ. For the current standardization state and status, check the latest version of the "Internet Official Protocol Standards" (STD 1) ๐. And distribution of this memo is totally unlimited ๐.
Copyright Notice ยฉ๏ธ
The IETF Trust holds the copyright, dated 2007 ๐.
Abstract ๐
so the main idea is this ๐: it takes WebDAV, which is the web-based authoring and versioning protocol, and adds extensions so you can access, manage, and share calendar and scheduling info in a standard way. The data is based on the iCalendar format ๐ . It also defines the "calendar-access" feature of CalDAV, which is the core of the whole thing ๐.
Table of Contents ๐๏ธ
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1. Notational Conventions . . . . . . . . . . . . . . . . . . 5
1.2. XML Namespaces and Processing . . . . . . . . . . . . . . 5
1.3. Method Preconditions and Postconditions . . . . . . . . . 6
2. Requirements Overview . . . . . . . . . . . . . . . . . . . . 6
3. Calendaring Data Model . . . . . . . . . . . . . . . . . . . . 7
3.1. Calendar Server . . . . . . . . . . . . . . . . . . . . . 7
3.2. Recurrence and the Data Model . . . . . . . . . . . . . . 8
4. Calendar Resources . . . . . . . . . . . . . . . . . . . . . . 9
4.1. Calendar Object Resources . . . . . . . . . . . . . . . . 9
4.2. Calendar Collection . . . . . . . . . . . . . . . . . . . 10
5. Calendar Access Feature . . . . . . . . . . . . . . . . . . . 11
5.1. Calendar Access Support . . . . . . . . . . . . . . . . . 11
5.1.1. Example: Using OPTIONS for the Discovery of
Calendar Access Support . . . . . . . . . . . . . . . 12
5.2. Calendar Collection Properties . . . . . . . . . . . . . . 12
5.2.1. CALDAV:calendar-description Property . . . . . . . . . 12
5.2.2. CALDAV:calendar-timezone Property . . . . . . . . . . 13
5.2.3. CALDAV:supported-calendar-component-set Property . . . 14
5.2.4. CALDAV:supported-calendar-data Property . . . . . . . 15
5.2.5. CALDAV:max-resource-size Property . . . . . . . . . . 16
5.2.6. CALDAV:min-date-time Property . . . . . . . . . . . . 17
5.2.7. CALDAV:max-date-time Property . . . . . . . . . . . . 18
5.2.8. CALDAV:max-instances Property . . . . . . . . . . . . 19
5.2.9. CALDAV:max-attendees-per-instance Property . . . . . . 19
5.2.10. Additional Precondition for PROPPATCH . . . . . . . . 20
5.3. Creating Resources . . . . . . . . . . . . . . . . . . . . 20
5.3.1. MKCALENDAR Method . . . . . . . . . . . . . . . . . . 20
5.3.1.1. Status Codes . . . . . . . . . . . . . . . . . . . 22
5.3.1.2. Example: Successful MKCALENDAR Request . . . . . . 23
5.3.2. Creating Calendar Object Resources . . . . . . . . . . 25
5.3.2.1. Additional Preconditions for PUT, COPY, and
MOVE . . . . . . . . . . . . . . . . . . . . . . . 26
5.3.3. Non-Standard Components, Properties, and Parameters . 28
5.3.4. Calendar Object Resource Entity Tag . . . . . . . . . 28
6. Calendaring Access Control . . . . . . . . . . . . . . . . . . 29
6.1. Calendaring Privilege . . . . . . . . . . . . . . . . . . 29
6.1.1. CALDAV:read-free-busy Privilege . . . . . . . . . . . 29
6.2. Additional Principal Property . . . . . . . . . . . . . . 30
6.2.1. CALDAV:calendar-home-set Property . . . . . . . . . . 30
7. Calendaring Reports . . . . . . . . . . . . . . . . . . . . . 31
7.1. REPORT Method . . . . . . . . . . . . . . . . . . . . . . 31
7.2. Ordinary Collections . . . . . . . . . . . . . . . . . . . 31
7.3. Date and Floating Time . . . . . . . . . . . . . . . . . . 32
7.4. Time Range Filtering . . . . . . . . . . . . . . . . . . . 32
7.5. Searching Text: Collations . . . . . . . . . . . . . . . . 33
7.5.1. CALDAV:supported-collation-set Property . . . . . . . 34
7.6. Partial Retrieval . . . . . . . . . . . . . . . . . . . . 34
7.7. Non-Standard Components, Properties, and Parameters . . . 35
7.8. CALDAV:calendar-query REPORT . . . . . . . . . . . . . . . 36
7.8.1. Example: Partial Retrieval of Events by Time Range . . 38
7.8.2. Example: Partial Retrieval of Recurring Events . . . . 42
7.8.3. Example: Expanded Retrieval of Recurring Events . . . 45
7.8.4. Example: Partial Retrieval of Stored Free Busy
Components . . . . . . . . . . . . . . . . . . . . . . 48
7.8.5. Example: Retrieval of To-Dos by Alarm Time Range . . . 50
7.8.6. Example: Retrieval of Event by UID . . . . . . . . . . 51
7.8.7. Example: Retrieval of Events by PARTSTAT . . . . . . . 53
7.8.8. Example: Retrieval of Events Only . . . . . . . . . . 55
7.8.9. Example: Retrieval of All Pending To-Dos . . . . . . . 59
7.8.10. Example: Attempt to Query Unsupported Property . . . . 62
7.9. CALDAV:calendar-multiget REPORT . . . . . . . . . . . . . 63
7.9.1. Example: Successful CALDAV:calendar-multiget REPORT . 64
7.10. CALDAV:free-busy-query REPORT . . . . . . . . . . . . . . 66
7.10.1. Example: Successful CALDAV:free-busy-query REPORT . . 68
8. Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . 69
8.1. Client-to-Client Interoperability . . . . . . . . . . . . 69
8.2. Synchronization Operations . . . . . . . . . . . . . . . . 69
8.2.1. Use of Reports . . . . . . . . . . . . . . . . . . . . 69
8.2.1.1. Restrict the Time Range . . . . . . . . . . . . . 69
8.2.1.2. Synchronize by Time Range . . . . . . . . . . . . 70
8.2.1.3. Synchronization Process . . . . . . . . . . . . . 70
8.2.2. Restrict the Properties Returned . . . . . . . . . . . 72
8.3. Use of Locking . . . . . . . . . . . . . . . . . . . . . . 72
8.4. Finding Calendars . . . . . . . . . . . . . . . . . . . . 72
8.5. Storing and Using Attachments . . . . . . . . . . . . . . 74
8.5.1. Inline Attachments . . . . . . . . . . . . . . . . . . 74
8.5.2. External Attachments . . . . . . . . . . . . . . . . . 75
8.6. Storing and Using Alarms . . . . . . . . . . . . . . . . . 76
9. XML Element Definitions . . . . . . . . . . . . . . . . . . . 77
9.1. CALDAV:calendar XML Element . . . . . . . . . . . . . . . 77
9.2. CALDAV:mkcalendar XML Element . . . . . . . . . . . . . . 77
9.3. CALDAV:mkcalendar-response XML Element . . . . . . . . . . 78
9.4. CALDAV:supported-collation XML Element . . . . . . . . . . 78
9.5. CALDAV:calendar-query XML Element . . . . . . . . . . . . 78
9.6. CALDAV:calendar-data XML Element . . . . . . . . . . . . . 79
9.6.1. CALDAV:comp XML Element . . . . . . . . . . . . . . . 80
9.6.2. CALDAV:allcomp XML Element . . . . . . . . . . . . . . 81
9.6.3. CALDAV:allprop XML Element . . . . . . . . . . . . . . 81
9.6.4. CALDAV:prop XML Element . . . . . . . . . . . . . . . 82
9.6.5. CALDAV:expand XML Element . . . . . . . . . . . . . . 82
9.6.6. CALDAV:limit-recurrence-set XML Element . . . . . . . 83
9.6.7. CALDAV:limit-freebusy-set XML Element . . . . . . . . 84
9.7. CALDAV:filter XML Element . . . . . . . . . . . . . . . . 85
9.7.1. CALDAV:comp-filter XML Element . . . . . . . . . . . . 85
9.7.2. CALDAV:prop-filter XML Element . . . . . . . . . . . . 86
9.7.3. CALDAV:param-filter XML Element . . . . . . . . . . . 87
9.7.4. CALDAV:is-not-defined XML Element . . . . . . . . . . 88
9.7.5. CALDAV:text-match XML Element . . . . . . . . . . . . 88
9.8. CALDAV:timezone XML Element . . . . . . . . . . . . . . . 89
9.9. CALDAV:time-range XML Element . . . . . . . . . . . . . . 90
9.10. CALDAV:calendar-multiget XML Element . . . . . . . . . . . 94
9.11. CALDAV:free-busy-query XML Element . . . . . . . . . . . . 95
10. Internationalization Considerations . . . . . . . . . . . . . 95
11. Security Considerations . . . . . . . . . . . . . . . . . . . 95
12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 96
12.1. Namespace Registration . . . . . . . . . . . . . . . . . . 96
13. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 96
14. References . . . . . . . . . . . . . . . . . . . . . . . . . . 97
14.1. Normative References . . . . . . . . . . . . . . . . . . . 97
14.2. Informative References . . . . . . . . . . . . . . . . . . 98
Appendix A. CalDAV Method Privilege Table (Normative) . . . . . . 99
Appendix B. Calendar Collections Used in the Examples . . . . . . 99
1. Introduction ๐ธ
okay so using HTTP [RFC2616] and WebDAV [RFC2518] as the base for a calendar access protocol is not a new idea at all ๐. People were talking about it in the IETF CALSCH working group way back in 1997 or 1998. Lots of companies built calendar access protocols that used HTTP to upload and download iCalendar [RFC2445] objects and used WebDAV to list resources ๐ . The problem is they didn't play nicely with each other ๐, because there are SO many small and big choices to make about how calendar data gets modeled as WebDAV resources, and how to build the features WebDAV doesn't already have. This document is the answer ๐: it proposes a way to model calendar data in WebDAV and adds the extra features needed for a calendar access protocol that actually interoperates โจ.
1.1. 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 read as described in [RFC2119] ๐ฅ. These are the official BCP 14 vibes, so pay attention to them ๐ซถ.
The term "protected" shows up in the Conformance field of property definitions, and it's defined in Section 1.4.2 of [RFC3253] ๐ .
When XML element types from the namespaces "DAV:" and "urn:ietf:params:xml:ns:caldav" get mentioned outside of an XML fragment, the strings DAV: and CALDAV: get stuck on the front of the element type names, respectively ๐ง.
1.2. XML Namespaces and Processing โจ
okay so the XML elements in this doc are defined with XML element type declarations (the kind you find in XML Document Type Declarations), described in Section 3.2 of [W3C.REC-xml-20060816] ๐ง
The namespace urn:ietf:params:xml:ns:caldav is reserved for the XML elements defined in this spec, its revisions, and related CalDAV specs ๐. XML elements defined by individual implementations MUST NOT use the urn:ietf:params:xml:ns:caldav namespace, and instead should use a namespace that they control ๐ซถ.
heads up: the XML declarations in this doc don't include namespace info ๐. So implementers must not treat them as the only way to make valid CalDAV properties or to validate CalDAV XML element types. Some of the declarations point at XML elements from WebDAV [RFC2518], which use the DAV: namespace, so wherever those show up they get the DAV: prefix to avoid confusion ๐
.
also, some CalDAV XML element names are identical to WebDAV element names, even though their namespaces are different. Be careful not to mix the two sets up ๐ญ.
Processing of XML by CalDAV clients and servers MUST follow the rules described in [RFC2518]; in particular, Section 14 and Appendix 3 of that specification ๐.
1.3. Method Preconditions and Postconditions ๐ธ
a "precondition" of a method describes the state of the server that must be true for that method to be performed ๐ซง. a "postcondition" describes the state of the server that must be true after the method has been completed. If a method precondition or postcondition for a request isn't satisfied, the response status of the request MUST either be 403 (Forbidden), if the request shouldn't be repeated because it will always fail, or 409 (Conflict), if the user might be able to resolve the conflict and resubmit the request ๐ โโ๏ธ.
To help clients handle 403 and 409 responses better, every method precondition and postcondition gets its own distinct XML element type ๐. When a particular precondition isn't satisfied or a particular postcondition can't be achieved, the appropriate XML element MUST be returned as the child of a top-level DAV:error element in the response body, unless otherwise negotiated by the request โจ.
2. Requirements Overview โญ
this section lists what functionality is required of a CalDAV server ๐. To advertise support for CalDAV, a server:
- MUST support iCalendar [RFC2445] as a media type for the calendar object resource format;
- MUST support WebDAV Class 1 [RFC2518] (note that [rfc2518bis] describes clarifications to [RFC2518] that aid interoperability);
- MUST support WebDAV ACL [RFC3744] with the additional privilege defined in Section 6.1 of this document;
- MUST support transport over TLS [RFC2246] as defined in [RFC2818] (note that [RFC2246] has been obsoleted by [RFC4346]);
- MUST support ETags [RFC2616] with additional requirements specified in Section 5.3.4 of this document;
- MUST support all calendaring reports defined in Section 7 of this document; and
- MUST advertise support on all calendar collections and calendar object resources for the calendaring reports in the
DAV:supported-report-setproperty, as defined in Versioning Extensions to WebDAV [RFC3253].
In addition, a server:
- SHOULD support the MKCALENDAR method defined in Section 5.3.1 of this document.
3. Calendaring Data Model ๐ฆ
one of the features that has made WebDAV a successful protocol is its firm data model ๐. That makes it a useful framework for other apps, like calendaring. This spec follows the same pattern: every feature is built on a well-described data model ๐ง .
as a quick overview, a CalDAV calendar is modeled as a WebDAV collection with a defined structure. Each calendar collection holds a bunch of resources, each one representing a calendar object, as its direct child resources ๐ . Each resource that represents a calendar object (an event, a to-do, a journal entry, or other calendar components) is called a "calendar object resource" ๐๏ธ. Each calendar object resource and each calendar collection can be individually locked and can have individual WebDAV properties ๐. The requirements that come from this model are in Section 4.1 and Section 4.2.
3.1. Calendar Server
a CalDAV server is a calendaring-aware engine combined with a WebDAV repository ๐ฅ๏ธ. A WebDAV repository is a set of WebDAV collections, containing other WebDAV resources, all inside one unified URL namespace. For example, the repository "http://www.example.com/webdav/" may contain WebDAV collections and resources, and all of them have URLs beginning with "http://www.example.com/webdav/" ๐. Note that the root URL, "http://www.example.com/", may not itself be a WebDAV repository (for example, if the WebDAV support is implemented through a servlet or other Web server extension) ๐ค.
A WebDAV repository MAY include calendar data in some parts of its URL namespace, and non-calendaring data in other parts ๐๏ธ.
A WebDAV repository can advertise itself as a CalDAV server if it supports the functionality defined in this specification at any point within the root of the repository ๐ฃ. That might mean calendar data is spread throughout the repository and mixed with non-calendar data in nearby collections (e.g., calendar data may be found in /home/lisa/calendars/ as well as in /home/bernard/calendars/, and non-calendar data in /home/lisa/contacts/) ๐. Or it might mean calendar data can only be found in certain sections of the repository (e.g., /calendar/) ๐. Calendaring features are only required in the repository sections that are or contain calendar object resources ๐
. So a repository confining calendar data to the /calendar/ collection would only need to support the CalDAV required features within that collection ๐ซถ.
The CalDAV server or repository is the canonical location for calendar data and state information ๐. Clients may submit requests to change data or download data. Clients may store calendar objects offline and attempt to synchronize at a later time ๐ด. However, clients MUST be prepared for calendar data on the server to change between the time of last synchronization and when attempting an update, because calendar collections may be shared and accessible via multiple clients ๐ฏโโ๏ธ. Entity tags and other features make this possible ๐ท๏ธ.
3.2. Recurrence and the Data Model ๐
recurrence is a big part of the data model because it governs how many resources are expected to exist ๐งฎ. This spec models a recurring calendar component and its recurrence exceptions as a single resource ๐. In this model, recurrence rules, recurrence dates, exception rules, and exception dates are all part of the data in one single calendar object resource. This avoids problems like limiting how many recurrence instances to store in the repository, how to keep recurrence instances in sync with the recurring calendar component, and how to link recurrence exceptions with the recurring calendar component ๐. It also means less data to synchronize between client and server, and it makes it easier to change all recurrence instances or a recurrence rule ๐ช. It's also easier to create a recurring calendar component and to delete all recurrence instances ๐๏ธ.
Clients aren't forced to retrieve info about all recurrence instances of a recurring component ๐ฅฐ. The CALDAV:calendar-query and CALDAV:calendar-multiget reports defined in this document let clients retrieve only the recurrence instances that overlap a given time range โฐ.
4. Calendar Resources ๐
4.1. Calendar Object Resources
calendar object resources contained in calendar collections MUST NOT contain more than one type of calendar component (e.g., VEVENT, VTODO, VJOURNAL, VFREEBUSY, etc.) with the exception of VTIMEZONE components, which MUST be specified for each unique TZID parameter value specified in the iCalendar object ๐งฉ. For instance, a calendar object resource can contain one VEVENT component and one VTIMEZONE component, but it cannot contain one VEVENT component and one VTODO component. Instead, the VEVENT and VTODO components would have to be stored in separate calendar object resources in the same collection ๐ โโ๏ธ.
calendar object resources contained in calendar collections MUST NOT specify the iCalendar METHOD property ๐ซ.
The UID property value of the calendar components contained in a calendar object resource MUST be unique in the scope of the calendar collection they're stored in ๐.
calendar components in a calendar collection that have different UID property values MUST be stored in separate calendar object resources ๐.
calendar components with the same UID property value, in a given calendar collection, MUST be contained in the same calendar object resource ๐. This makes sure all components in a recurrence "set" live in the same calendar object resource. It's possible for a calendar object resource to contain just components that represent "overridden" instances (ones that modify the behavior of a regular instance, and so include a RECURRENCE-ID property) without also including the "master" recurring component (the one that defines the recurrence "set" and does not contain any RECURRENCE-ID property) ๐ฆ.
for example, given the following iCalendar object:
BEGIN:VCALENDAR
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VEVENT
UID:1@example.com
SUMMARY:One-off Meeting
DTSTAMP:20041210T183904Z
DTSTART:20041207T120000Z
DTEND:20041207T130000Z
END:VEVENT
BEGIN:VEVENT
UID:2@example.com
SUMMARY:Weekly Meeting
DTSTAMP:20041210T183838Z
DTSTART:20041206T120000Z
DTEND:20041206T130000Z
RRULE:FREQ=WEEKLY
END:VEVENT
BEGIN:VEVENT
UID:2@example.com
SUMMARY:Weekly Meeting
RECURRENCE-ID:20041213T120000Z
DTSTAMP:20041210T183838Z
DTSTART:20041213T130000Z
DTEND:20041213T140000Z
END:VEVENT
END:VCALENDAR
the VEVENT component with the UID value "1@example.com" would be stored in its own calendar object resource ๐. The two VEVENT components with the UID value "2@example.com", which represent a recurring event where one recurrence instance has been overridden, would be stored in the same calendar object resource ๐โจ.
4.2. Calendar Collection
okay so a calendar collection is basically the folder that holds your calendar object resources, which are the calendar components living inside a calendar ๐โจ Clients see it as a WebDAV resource collection with its own URL. A calendar collection MUST report both the DAV:collection and CALDAV:calendar XML elements in the value of its DAV:resourcetype property. The element type declaration for CALDAV:calendar is:
<!ELEMENT calendar EMPTY>
bestie, there are two ways a calendar collection can show up ๐ It can be created through provisioning, meaning it's made automatically when a user's account gets provisioned. Or it can be made with the MKCALENDAR method (see Section 5.3.1). This is super handy for making extra calendars like a soccer schedule, or for sharing one, like team events or conference rooms ๐ธ BUT (and this is important) this document does NOT define what extra calendar collections are actually for ๐ So users have to rely on non-standard cues to figure it out, or use the CALDAV:calendar-description property from Section 5.2.1 to leave a little hint.
Now the rules for what lives inside a calendar collection, no cap, these are strict ๐
a. Calendar collections MUST only contain calendar object resources and collections that are not calendar collections. So the only "top-level" non-collection resources allowed are calendar object resources. This keeps calendar clients from having to deal with non-calendar data ๐ง They still have to tell calendar object resources apart from collections when they use standard WebDAV techniques to look inside a collection, though.
b. Collections sitting inside calendar collections MUST NOT contain calendar collections at any depth. So no nesting calendar collections inside other calendar collections, no matter how deep ๐ โโ๏ธ This spec also doesn't say how those inner collections get used or how they connect to the calendar object resources in the calendar collection, so that's on the implementers ๐
Multiple calendar collections MAY be children of the same collection. Mix and match, it's giving organized ๐
5. Calendar Access Feature ๐ฆ
5.1. Calendar Access Support
A server that supports the features in this document MUST include calendar-access as a field in the DAV response header from an OPTIONS request on any resource that supports any calendar properties, reports, method, or privilege. A DAV response header value of calendar-access MUST indicate that the server supports all MUST level requirements in this document. So if you see that token, it's a promise that the server has the full MUST-level package ๐ฅ
5.1.1. Example: Using OPTIONS for the Discovery of Calendar Access Support
Here's the vibe check ๐
>> Request <<
OPTIONS /home/bernard/calendars/ HTTP/1.1
Host: cal.example.com
>> Response <<
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE
Allow: PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL
DAV: 1, 2, access-control, calendar-access
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Length: 0
In this example, the OPTIONS method comes back with calendar-access in the DAV response header, which tells us the collection /home/bernard/calendars/ supports the properties, reports, method, or privilege defined in this spec. Iconic discovery moment โจ
5.2. Calendar Collection Properties
okay so this section defines the properties for calendar collections ๐
5.2.1. CALDAV:calendar-description Property
Name: calendar-description
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Gives a human-readable description of the calendar collection ๐
Conformance: This property MAY be defined on any calendar collection. If it's defined, it MAY be protected, and it SHOULD NOT be returned by a PROPFIND DAV:allprop request (as defined in Section 12.14.1 of [RFC2518]). An xml:lang attribute that says what human language the description is in SHOULD be set for this property, either by clients or through server provisioning. Servers MUST return any xml:lang attribute that's set for the property. Language tags matter, periodt ๐
Description: If it's present, the property holds a description of the calendar collection that's fine to show to a user. If it's not present, the client should assume there's no description for the calendar collection ๐ซถ
Definition:
<!ELEMENT calendar-description (#PCDATA)>
PCDATA value: string
Example:
<C:calendar-description xml:lang="fr-CA"
xmlns:C="urn:ietf:params:xml:ns:caldav"
>Calendrier de Mathilde Desruisseaux</C:calendar-description>
5.2.2. CALDAV:calendar-timezone Property
Name: calendar-timezone
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies a time zone on a calendar collection ๐
Conformance: This property SHOULD be defined on all calendar collections. If it's defined, it SHOULD NOT be returned by a PROPFIND DAV:allprop request (as defined in Section 12.14.1 of [RFC2518]).
Description: The CALDAV:calendar-timezone property tells the server which time zone to rely on when it resolves "date" values and "date with local time" values (aka floating time) into "date with UTC time" values. This matters SO much. The server needs this info to figure out whether a calendar component scheduled with "date" or "date with local time" values overlaps a CALDAV:time-range in a CALDAV:calendar-query REPORT. The server also needs it to work out the right FREEBUSY time period as "date with UTC time" in the VFREEBUSY component that comes back in a response to a CALDAV:free-busy-query REPORT request that includes calendar components scheduled with "date" or "date with local time" values ๐ If this property isn't there, the server MAY rely on whichever time zone it wants.
Note: The iCalendar data embedded inside the CALDAV:calendar-timezone XML element MUST follow the standard XML character data encoding rules. That includes using entity encoding like <, >, & etc., or using a <![CDATA[ ... ]]> construct. If you go the CDATA route, the iCalendar data can't contain the character sequence ]]>, because that's the end delimiter for the CDATA section ๐
Definition:
<!ELEMENT calendar-timezone (#PCDATA)>
PCDATA value: an iCalendar object with exactly one VTIMEZONE
component.
Example:
<C:calendar-timezone
xmlns:C="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:US-Eastern
LAST-MODIFIED:19870101T000000Z
BEGIN:STANDARD
DTSTART:19671029T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:Eastern Standard Time (US & Canada)
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19870405T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:Eastern Daylight Time (US & Canada)
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
</C:calendar-timezone>
5.2.3. CALDAV:supported-calendar-component-set Property
Name: supported-calendar-component-set
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies which calendar component types (like VEVENT, VTODO, etc.) calendar object resources can hold in the calendar collection ๐๏ธ
Conformance: This property MAY be defined on any calendar collection. If it's defined, it MUST be protected, and it SHOULD NOT be returned by a PROPFIND DAV:allprop request (as defined in Section 12.14.1 of [RFC2518]).
Description: The CALDAV:supported-calendar-component-set property puts restrictions on which calendar component types calendar object resources are allowed to contain in a calendar collection ๐ซ If a client tries to store a calendar object resource with a component type that isn't listed here (and the property exists), it MUST result in an error, with the CALDAV:supported-calendar-component precondition (Section 5.3.2.1) being violated. Since this property is protected, clients can't change it with a PROPPATCH request. BUT clients CAN set its initial value when they make a new calendar collection with MKCALENDAR ๐ The empty-element tag <C:comp name="VTIMEZONE"/> MUST only be specified if support for calendar object resources that only contain VTIMEZONE components is provided or wanted. Support for VTIMEZONE components inside calendar object resources that contain VEVENT or VTODO components is always assumed, so you don't have to list it for those. If this property isn't there, the server MUST accept all component types, and the client can assume that every component type is accepted ๐
Definition:
<!ELEMENT supported-calendar-component-set (comp+)>
Example:
<C:supported-calendar-component-set
xmlns:C="urn:ietf:params:xml:ns:caldav">
<C:comp name="VEVENT"/>
<C:comp name="VTODO"/>
</C:supported-calendar-component-set>
5.2.4. CALDAV:supported-calendar-data Property
Name: supported-calendar-data
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies which media types are allowed for calendar object resources in a calendar collection ๐ฆ
Conformance: This property MAY be defined on any calendar collection. If it's defined, it MUST be protected, and it SHOULD NOT be returned by a PROPFIND DAV:allprop request (as defined in Section 12.14.1 of [RFC2518]).
Description: The CALDAV:supported-calendar-data property says which media type is supported for the calendar object resources in a given calendar collection (for example, iCalendar version 2.0) ๐ If a client tries to store a calendar object resource with a media type that isn't listed here, it MUST result in an error, with the CALDAV:supported-calendar-data precondition (Section 5.3.2.1) being violated. If this property isn't there, the server MUST only accept data with the media type text/calendar and iCalendar version 2.0, and clients can assume the server will only accept that data. Clear rules, no drama ๐
Definition:
<!ELEMENT supported-calendar-data (calendar-data+)>
Example:
<C:supported-calendar-data
xmlns:C="urn:ietf:params:xml:ns:caldav">
<C:calendar-data content-type="text/calendar" version="2.0"/>
</C:supported-calendar-data>
5.2.5. CALDAV:max-resource-size Property ๐ฆโจ
Name: max-resource-size Namespace: urn:ietf:params:xml:ns:caldav
Purpose: okay so this one is the size limit ๐ . It gives a number in octets for the biggest calendar object resource the server will accept when you store one in a calendar collection ๐ฆ
Conformance: this property MAY be defined on any calendar collection ๐. If it's defined, it MUST be protected ๐, and it SHOULD NOT show up in a PROPFIND DAV:allprop request (see Section 12.14.1 of [RFC2518]) ๐
Description: the CALDAV:max-resource-size is how the server says "this is the biggest thing I'll take" ๐. If you try to store a calendar object resource over that size, you MUST get an error, and the CALDAV:max-resource-size precondition (Section 5.3.2.1) gets violated ๐. If this property isn't there at all, the client can just assume the server will take a resource of any reasonable size ๐ธ
Definition:
<!ELEMENT max-resource-size (#PCDATA)>
PCDATA value: a numeric value (positive integer)
Example:
<C:max-resource-size xmlns:C="urn:ietf:params:xml:ns:caldav"
>102400</C:max-resource-size>
5.2.6. CALDAV:min-date-time Property ๐๏ธ๐
Name: min-date-time Namespace: urn:ietf:params:xml:ns:caldav
Purpose: this one gives a DATE-TIME value (in UTC โฐ) for the earliest date and time the server is willing to take for any DATE or DATE-TIME value in a calendar object resource stored in a calendar collection ๐ง
Conformance: this property MAY be defined on any calendar collection ๐. If it's defined, it MUST be protected ๐, and it SHOULD NOT show up in a PROPFIND DAV:allprop request (see Section 12.14.1 of [RFC2518]) ๐
Description: the CALDAV:min-date-time is an iCalendar DATE-TIME value in UTC that marks the earliest inclusive date the server accepts for any explicit DATE or DATE-TIME value in a calendar object resource stored in a calendar collection ๐
. Any attempt to store a resource using a DATE or DATE-TIME earlier than this MUST result in an error, and the CALDAV:min-date-time precondition (Section 5.3.2.1) gets violated ๐ญ. Now the plot twist: servers MUST accept recurring components that have instances past this limit, as long as none of those instances have been overridden ๐. In that case the server MAY just ignore the instances outside the acceptable range when it processes reports on that calendar object resource ๐ซถ. If this property isn't there, the client can assume any valid iCalendar date may be used at least up to the CALDAV:max-date-time value, if that one's defined โจ
Definition:
<!ELEMENT min-date-time (#PCDATA)>
PCDATA value: an iCalendar format DATE-TIME value in UTC
Example:
<C:min-date-time xmlns:C="urn:ietf:params:xml:ns:caldav"
>19000101T000000Z</C:min-date-time>
5.2.7. CALDAV:max-date-time Property ๐๐ฎ
Name: max-date-time Namespace: urn:ietf:params:xml:ns:caldav
Purpose: the mirror image of the last one ๐ช. It gives a DATE-TIME value (in UTC) for the latest date and time the server will accept for any DATE or DATE-TIME value in a calendar object resource stored in a calendar collection ๐
Conformance: this property MAY be defined on any calendar collection ๐. If it's defined, it MUST be protected ๐, and it SHOULD NOT show up in a PROPFIND DAV:allprop request (see Section 12.14.1 of [RFC2518]) ๐
Description: the CALDAV:max-date-time is an iCalendar DATE-TIME value in UTC that marks the inclusive latest date the server will take for any date or time value in a calendar object resource stored in a calendar collection ๐๏ธ. Storing a resource with a DATE or DATE-TIME later than this MUST result in an error, with the CALDAV:max-date-time precondition (Section 5.3.2.1) getting violated ๐. Same deal as before: servers MUST accept recurring components that specify instances beyond this limit, as long as none of those instances have been overridden ๐. The server MAY simply ignore those out-of-range instances when processing reports on the calendar object resource ๐ซถ. If this property isn't there, the client can assume any valid iCalendar date may be used at least down to the CALDAV:min-date-time value, if that one's defined ๐ง
Definition:
<!ELEMENT max-date-time (#PCDATA)>
PCDATA value: an iCalendar format DATE-TIME value in UTC
Example:
<C:max-date-time xmlns:C="urn:ietf:params:xml:ns:caldav"
>20491231T235959Z</C:max-date-time>
5.2.8. CALDAV:max-instances Property ๐๐
Name: max-instances Namespace: urn:ietf:params:xml:ns:caldav
Purpose: this is the cap on how many recurrence instances a calendar object resource stored in a calendar collection can generate ๐. It's a number, so no drama there ๐
Conformance: this property MAY be defined on any calendar collection ๐. If it's defined, it MUST be protected ๐, and it SHOULD NOT show up in a PROPFIND DAV:allprop request (see Section 12.14.1 of [RFC2518]) ๐
Description: the CALDAV:max-instances is a numeric value for the maximum number of recurrence instances that a calendar object resource stored in a calendar collection can generate ๐. If you try to store a resource with a recurrence pattern that makes more instances than this, you MUST get an error, and the CALDAV:max-instances precondition (Section 5.3.2.1) gets violated ๐ญ. If the property isn't there, the client can assume the server has no limits on how many recurrence instances it can handle or expand ๐
Definition:
<!ELEMENT max-instances (#PCDATA)>
PCDATA value: a numeric value (integer greater than zero)
Example:
<C:max-instances xmlns:C="urn:ietf:params:xml:ns:caldav"
>100</C:max-instances>
5.2.9. CALDAV:max-attendees-per-instance Property ๐ฏโโ๏ธ๐
Name: max-attendees-per-instance Namespace: urn:ietf:params:xml:ns:caldav
Purpose: this one gives the maximum number of ATTENDEE properties allowed in any single instance of a calendar object resource stored in a calendar collection ๐๏ธ
Conformance: this property MAY be defined on any calendar collection ๐. If it's defined, it MUST be protected ๐, and it SHOULD NOT show up in a PROPFIND DAV:allprop request (see Section 12.14.1 of [RFC2518]) ๐
Description: the CALDAV:max-attendees-per-instance is a numeric value for the maximum number of iCalendar ATTENDEE properties on any one instance of a calendar object resource stored in a calendar collection ๐ฅณ. If you try to store a resource with more ATTENDEE properties per instance than this, you MUST get an error, and the CALDAV:max-attendees-per-instance precondition (Section 5.3.2.1) gets violated ๐. If the property isn't there, the client can assume the server can handle any number of ATTENDEE properties in a calendar component ๐
Definition:
<!ELEMENT max-attendees-per-instance (#PCDATA)>
PCDATA value: a numeric value (integer greater than zero)
Example:
<C:max-attendees-per-instance
xmlns:C="urn:ietf:params:xml:ns:caldav"
>25</C:max-attendees-per-instance>
5.2.10. Additional Precondition for PROPPATCH ๐งพโจ
This specification adds an extra precondition for the PROPPATCH method ๐ . It's called:
CALDAV:valid-calendar-data: the time zone specified in the CALDAV:calendar-timezone property MUST be a valid iCalendar object containing a single valid VTIMEZONE component ๐
5.3. Creating Resources ๐๐๏ธ
Calendar collections and calendar object resources can be created by either a CalDAV client or a CalDAV server ๐ซถ. This specification defines the restrictions and the data model that both clients and servers MUST adhere to when they manipulate calendar data ๐
5.3.1. MKCALENDAR Method ๐ ๐
An HTTP request using the MKCALENDAR method creates a new calendar collection resource ๐ฆ. A server MAY restrict calendar collection creation to particular collections ๐ช
Supporting MKCALENDAR on the server is only RECOMMENDED, not REQUIRED ๐คทโโ๏ธ. Some calendar stores only support one calendar per user (or principal), and those are usually pre-created for each account ๐ผ. Still, servers and clients are strongly encouraged to support MKCALENDAR whenever possible so users can make multiple calendar collections and organize their stuff better ๐๏ธโจ
Clients SHOULD use the DAV:displayname property for a human-readable name for the calendar ๐ท๏ธ. They can either put the DAV:displayname value in the MKCALENDAR request body, or send a PROPPATCH request right after the MKCALENDAR request to change DAV:displayname to the right value ๐ . Clients SHOULD NOT set DAV:displayname to be the same as any other calendar collection at the same URI "level" ๐ โโ๏ธ. When they show calendar collections to users, clients SHOULD check DAV:displayname and use that value as the calendar's name ๐. If DAV:displayname is empty, the client MAY use the last part of the calendar collection URI as the name instead, but that path segment may be "opaque" and not mean anything human-readable ๐
If a MKCALENDAR request fails, the server state from before the request MUST be restored โช
Marshalling:
If there's a request body, it MUST be a CALDAV:mkcalendar XML element ๐งฉ. Instructions MUST get processed in the order they arrive (top to bottom) ๐. They MUST either all get executed or none get executed ๐ซฃ. So if anything goes wrong mid-processing, every instruction that already ran MUST be undone, and you get a proper error result ๐. The details for processing instructions are in the DAV:set instruction definition in Section 12.13.2 of [RFC2518] ๐
<!ELEMENT mkcalendar (DAV:set)>
If a successful request has a response body, it MUST be a CALDAV:mkcalendar-response XML element ๐
<!ELEMENT mkcalendar-response ANY>
The response MUST include a Cache-Control:no-cache header ๐ง
Preconditions:
DAV:resource-must-be-null: a resource MUST NOT exist at the Request-URI ๐ซCALDAV:calendar-collection-location-ok: the Request-URI MUST identify a location where a calendar collection can be created ๐CALDAV:valid-calendar-data: the time zone specified in the CALDAV:calendar-timezone property MUST be a valid iCalendar object containing a single valid VTIMEZONE component ๐DAV:needs-privilege: the DAV:bind privilege MUST be granted to the current user on the parent collection of the Request-URI ๐
Postconditions:
CALDAV:initialize-calendar-collection: a new calendar collection exists at the Request-URI ๐. The DAV:resourcetype of the calendar collection MUST contain both DAV:collection and CALDAV:calendar XML elements ๐
Okay, we're getting closer to the good stuff, bestie ๐โจ
5.3.1.1. Status Codes
okay so these are the response codes you'd totally expect to see back from a MKCALENDAR request ๐ BUT this list is not the whole story, so don't treat it like the full menu ๐ซถ
201(Created) - the calendar collection resource got created in its entirety ๐207(Multi-Status) - the calendar collection resource was NOT created because one or more DAV:set instructions in the request body couldn't be processed successfully ๐ญ the ones you'd expect inside a 207 in this situation are:403(Forbidden) - the client, for reasons the server chooses not to spell out, can't change one of the properties ๐409(Conflict) - the client gave a value whose meaning doesn't fit the property. This includes trying to set read-only properties ๐424(Failed Dependency) - the DAV:set instruction on that resource would've worked if it weren't for another DAV:set instruction in the same request body failing ๐ฅบ423(Locked) - the resource is locked and the client either isn't a lock owner, or the lock type needs a lock token and the client didn't send one ๐507(Insufficient Storage) - the server didn't have enough space to record the property ๐ซ
403(Forbidden) - this covers at least one of two things: 1) the server doesn't allow calendar collections to be created at that location in its namespace, or 2) the parent collection of the Request-URI exists but can't accept members ๐ซ409(Conflict) - a collection can't be made at the Request-URI until one or more intermediate collections have been created first ๐งฑ415(Unsupported Media Type) - the server doesn't support the request body's type ๐ฆ507(Insufficient Storage) - the resource doesn't have enough space to record its state after this method runs ๐พ
5.3.1.2. Example: Successful MKCALENDAR Request
ok this example makes a calendar collection called /home/lisa/calendars/events/ on the server cal.example.com ๐ธ it sets some specific values for DAV:displayname, CALDAV:calendar-description, CALDAV:supported-calendar-component-set, and CALDAV:calendar-timezone. so cute, Lisa is really organized ๐๏ธโจ
>> Request <<
MKCALENDAR /home/lisa/calendars/events/ HTTP/1.1
Host: cal.example.com
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:mkcalendar xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:set>
<D:prop>
<D:displayname>Lisa's Events</D:displayname>
<C:calendar-description xml:lang="en"
>Calendar restricted to events.</C:calendar-description>
<C:supported-calendar-component-set>
<C:comp name="VEVENT"/>
</C:supported-calendar-component-set>
<C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:US-Eastern
LAST-MODIFIED:19870101T000000Z
BEGIN:STANDARD
DTSTART:19671029T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:Eastern Standard Time (US & Canada)
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19870405T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:Eastern Daylight Time (US & Canada)
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
]]></C:calendar-timezone>
</D:prop>
</D:set>
</C:mkcalendar>
>> Response <<
HTTP/1.1 201 Created
Cache-Control: no-cache
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Length: 0
5.3.2. Creating Calendar Object Resources
okay so clients fill calendar collections up with calendar object resources ๐ฆ the URL for each one is totally arbitrary and doesn't have to match anything in its iCalendar properties or other metadata, so no pressure on naming ๐ new calendar object resources MUST be created with a PUT request aimed at an unmapped URI ๐ฏ a PUT aimed at a mapped URI just updates a calendar object resource that already exists.
servers picking unmapped URIs for new resources? easy peasy ๐ clients have it a bit harder, because a client might not want to scan every resource in the collection, and it might not want to lock the whole collection just to dodge a name collision ๐ฉ BUT there's an HTTP feature that helps with this ๐ if the client wants to create a new non-collection resource, like a new VEVENT, it SHOULD send the HTTP request header "If-None-Match: *" on the PUT request. the Request-URI on that PUT MUST include the target collection where the resource is going, plus the name of the resource in the last path segment ๐ and that "If-None-Match: *" header means the client won't accidentally overwrite an existing resource if that last path segment already happens to be taken ๐ก๏ธ
>> Request <<
PUT /home/lisa/calendars/events/qwue23489.ics HTTP/1.1
If-None-Match: *
Host: cal.example.com
Content-Type: text/calendar
Content-Length: xxxx
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
UID:20010712T182145Z-123401@example.com
DTSTAMP:20060712T182145Z
DTSTART:20060714T170000Z
DTEND:20060715T040000Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR
>> Response <<
HTTP/1.1 201 Created
Content-Length: 0
Date: Sat, 11 Nov 2006 09:32:12 GMT
ETag: "123456789-000-111"
changing an existing event works the same way, except you send a specific ETag in the "If-Match" header instead of "If-None-Match" ๐โจ
as noted in Section 3.10 of [RFC2445], the URL of calendar object resources holding (an arbitrary set of) calendaring and scheduling information may end in ".ics", and the URL of calendar object resources holding free or busy time information may end in ".ifb" ๐
5.3.2.1. Additional Preconditions for PUT, COPY, and MOVE
this spec adds extra Preconditions for PUT, COPY, and MOVE ๐ they kick in when a calendar object resource gets PUT into a calendar collection, when a calendar object resource gets COPYed or MOVEd into a calendar collection, or when a COPY or MOVE happens on a calendar collection itself ๐ง
the new preconditions are:
(CALDAV:supported-calendar-data): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST be a supported media type (i.e., iCalendar) for calendar object resources ๐(CALDAV:valid-calendar-data): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST be valid data for the media type being specified (i.e., MUST contain valid iCalendar data) โ(CALDAV:valid-calendar-object-resource): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST obey all restrictions specified in Section 4.1 (e.g., calendar object resources MUST NOT contain more than one type of calendar component, calendar object resources MUST NOT specify the iCalendar METHOD property, etc.) ๐(CALDAV:supported-calendar-component): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST contain a type of calendar component that is supported in the targeted calendar collection ๐งฉ(CALDAV:no-uid-conflict): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST NOT specify an iCalendar UID property value already in use in the targeted calendar collection, or overwrite an existing calendar object resource with one that has a different UID property value. Servers SHOULD report the URL of the resource that is already using the same UID property value in the DAV:href element ๐จ
<!ELEMENT no-uid-conflict (DAV:href)>
(CALDAV:calendar-collection-location-ok): in a COPY or MOVE request, when the Request-URI is a calendar collection, the Destination-URI MUST identify a location where a calendar collection can be created ๐(CALDAV:max-resource-size): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST have an octet size less than or equal to the value of the CALDAV:max-resource-size property value (Section 5.2.5) on the calendar collection where the resource will be stored โ๏ธ(CALDAV:min-date-time): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST have all of its iCalendar DATE or DATE-TIME property values (for each recurring instance) greater than or equal to the value of the CALDAV:min-date-time property value (Section 5.2.6) on the calendar collection where the resource will be stored ๐(CALDAV:max-date-time): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST have all of its iCalendar DATE or DATE-TIME property values (for each recurring instance) less than the value of the CALDAV:max-date-time property value (Section 5.2.7) on the calendar collection where the resource will be stored ๐๏ธ(CALDAV:max-instances): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST generate a number of recurring instances less than or equal to the value of the CALDAV:max-instances property value (Section 5.2.8) on the calendar collection where the resource will be stored ๐(CALDAV:max-attendees-per-instance): the resource submitted in the PUT request, or targeted by a COPY or MOVE request, MUST have a number of ATTENDEE properties on any one instance less than or equal to the value of the CALDAV:max-attendees-per-instance property value (Section 5.2.9) on the calendar collection where the resource will be stored ๐ฅ
5.3.3. Non-Standard Components, Properties, and Parameters
iCalendar has a "standard mechanism for doing non-standard things" ๐จ this extension support lets implementers use non-standard components, properties, and parameters whose names start with the text "X-" ๐
servers MUST support non-standard components, properties, and parameters in calendar object resources stored via the PUT method ๐
servers may need to enforce rules for their own "private" components, properties, or parameters, so servers MAY reject any attempt by the client to change those or to use values for those outside of any restrictions the server may have ๐ servers SHOULD make sure any "private" components, properties, or parameters they use follow the convention of including a vendor id in the "X-" name, as described in Section 4.2 of [RFC2445], e.g., "X-ABC-PRIVATE" ๐ท๏ธโจ
5.3.4. Calendar Object Resource Entity Tag โจ
okay so the DAV:getetag property MUST be defined and set to a strong entity tag on every single calendar object resource ๐
no exceptions bestie
when a GET request targets a calendar object resource, the response MUST include an ETag response header field that shows the current value of that strong entity tag ๐
servers SHOULD send back a strong entity tag (the ETag header) in the PUT response when the stored calendar object resource is octet-for-octet identical to the body of the PUT request ๐ซถ this is so clients can actually trust that tag for syncing. like, the client can do a PROPFIND on the resource, get the DAV:getetag back, and compare it to the tag from the PUT response. if they match, the resource on the server hasn't changed. iconic ๐ง
now if the server stores something from a PUT that is NOT octet-identical to what was sent, the spec doesn't say what the ETag header does, with one big catch: a strong entity tag MUST NOT be returned in that response ๐ญ so clients might need to fetch the modified resource (and its ETag) and use that as the starting point for more changes, instead of the copy they sent with the PUT
6. Calendaring Access Control ๐
6.1. Calendaring Privilege ๐
CalDAV servers MUST support and adhere to the requirements of WebDAV ACL [RFC3744]. basically WebDAV ACL gives you a framework for a whole extensible set of privileges that can be slapped onto WebDAV collections and ordinary resources ๐ธ on top of that, CalDAV servers MUST also support the calendaring privilege defined in this section
6.1.1. CALDAV:read-free-busy Privilege ๐ฆ
okay this one is so relatable. calendar users often want to let other people see when they're busy, but NOT the juicy details like location, summary, or attendees ๐ it keeps a lot of privacy while still letting people book meetings at times you're probably free. main character privacy energy
the CALDAV:read-free-busy privilege controls which calendar collections, regular collections, and calendar object resources get looked at when a CALDAV:free-busy-query REPORT request is processed (see Section 7.10). this privilege can be granted on calendar collections, regular collections, or calendar object resources ๐
servers MUST support this privilege on all calendar collections, regular collections, and calendar object resources โจ
<!ELEMENT read-free-busy EMPTY>
the CALDAV:read-free-busy privilege MUST be aggregated in the DAV:read privilege ๐ servers MUST allow CALDAV:read-free-busy to be granted without DAV:read being granted too
heads up: if onlyCALDAV:read-free-busyhas been granted on a resource, that does NOT imply access to GET, HEAD, OPTIONS, or PROPFIND on it. those are governed by theDAV:readprivilege, so clients should keep that in mind ๐
6.2. Additional Principal Property ๐
this section adds one more property for WebDAV principal resources, as defined in [RFC3744] ๐
6.2.1. CALDAV:calendar-home-set Property ๐ก
- Name:
calendar-home-set - Namespace:
urn:ietf:params:xml:ns:caldav - Purpose: it tells you the URL of any WebDAV collections that hold calendar collections owned by the principal resource ๐ง
- Conformance: this property SHOULD be defined on a principal resource. if it's defined, it MAY be protected, and it SHOULD NOT be returned by a PROPFIND
DAV:allproprequest (as defined in Section 12.14.1 of [RFC2518]) ๐ - Description: the whole point of
CALDAV:calendar-home-setis to help users find the calendar collections owned by the principal, super easily ๐ usually people group all their calendar collections under one shared collection. this property gives the URL of collections that are either calendar collections or ordinary collections with child or descendant calendar collections owned by the principal โจ - Definition:
<!ELEMENT calendar-home-set (DAV:href*)>
- Example:
<C:calendar-home-set xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:href>http://cal.example.com/home/bernard/calendars/</D:href>
</C:calendar-home-set>
7. Calendaring Reports ๐
this section defines the reports that CalDAV servers MUST support on calendar collections and calendar object resources ๐ซถ
CalDAV servers MUST advertise support for these reports on all calendar collections and calendar object resources using the DAV:supported-report-set property, defined in Section 3.1.5 of [RFC3253]. CalDAV servers MAY also advertise support for these reports on ordinary collections ๐
some of these reports let calendar data (from possibly multiple resources) come back to you ๐ฆ
7.1. REPORT Method ๐จ
the REPORT method (defined in Section 3.6 of [RFC3253]) is an extensible way to get info about one or more resources ๐ง unlike PROPFIND, which gives you the value of one or more named properties, REPORT can do way more complex processing. it's super useful when the server has everything it needs to handle a complex request (like a query), and the client would otherwise need a bunch of separate requests to get the same info ๐ฅ
CalDAV servers MUST support the DAV:expand-property REPORT defined in Section 3.8 of [RFC3253] ๐
7.2. Ordinary Collections ๐
servers MAY support the reports defined in this document on ordinary collections (collections that aren't calendar collections), on top of calendar collections or calendar object resources ๐ when computing responses to these reports on ordinary collections, servers MUST only consider calendar object resources contained in the calendar collections targeted by the REPORT request, based on the value of the Depth request header ๐
7.3. Date and Floating Time ๐
iCalendar lets you specify DATE and DATE-TIME values that aren't tied to any particular time zone ๐ these are called "floating date" and "floating time". they mean the same day, hour, minute, and second no matter which time zone is being observed. for example, the DATE value "20051111" is November 11, 2005 in no specific time zone, and the DATE-TIME value "20051111T111100" is November 11, 2005 at 11:11 A.M. in no specific time zone โฐ
CalDAV servers may need to convert "floating date" and "floating time" values into date with UTC time values while processing calendaring REPORT requests ๐
for the CALDAV:calendar-query REPORT, CalDAV servers MUST rely on the value of the CALDAV:timezone XML element, if it's in the request body, to do the proper conversion of "floating date" and "floating time" values into date with UTC time values ๐ if the CALDAV:timezone XML element isn't in the request body, CalDAV servers MUST rely on the value of the CALDAV:calendar-timezone property, if it's defined. if that's not defined either, CalDAV servers MAY rely on whatever time zone they choose ๐คทโโ๏ธ
for the CALDAV:free-busy-query REPORT, CalDAV servers MUST rely on the value of the CALDAV:calendar-timezone property, if it's defined, to work out the proper FREEBUSY time period value as date with UTC time for calendar components scheduled with "floating date" or "floating time" ๐ฆ if CALDAV:calendar-timezone isn't defined, CalDAV servers MAY rely on the time zone of their choice ๐
7.4. Time Range Filtering โณ
some reports in this section can include a time range filter, which limits the calendar object resources returned to only the ones that overlap the requested time range โจ the filter can apply to a calendar component as a whole, or to specific calendar component properties with DATE or DATE-TIME value types ๐ซง
to figure out if a calendar object resource matches the time range filter element, the start and end times of the targeted component or property are worked out and then compared to the requested time range. if there's any overlap, the resource matches the filter element ๐ the rules in [RFC2445] for finding the actual start and end times of calendar components MUST be used, and they're fully listed in Section 9.9 of this document ๐
when you're doing time range filtering, recurring calendar components like VEVENT and VTODO need special care ๐ the server MUST expand recurring components to check whether any recurrence instances overlap the specified time range. if one or more recurrence instances overlap it, the calendar object resource matches the filter element ๐
7.5. Searching Text: Collations ๐ค
some reports in this section do text matches on character strings the client gives you, and compare them against stored calendar data ๐ iCalendar data is UTF-8 by default and can include non-US-ASCII characters in some property and parameter values, so text matching needs well-defined rules, no cap ๐ญ
to handle that, this spec uses the IANA Collation Registry defined in [RFC4790] to specify collations for text comparison with a well-defined rule ๐
all the comparisons in CalDAV are "substring" matches, as per Section 4.2 of [RFC4790]. collations the server supports MUST support "substring" match operations ๐
CalDAV servers are REQUIRED to support the "i;ascii-casemap" and "i;octet" collations, as described in [RFC4790], and they MAY support other collations too ๐ธ
servers MUST advertise the collations they support via the CALDAV:supported-collation-set property, defined on any resource that supports reports using collations ๐ซถ
clients MUST only use collations from the list the server advertises ๐ โโ๏ธ
if the client doesn't explicitly specify a collation, or specifies the "default" collation identifier (as defined in Section 3.1 of [RFC4790]), the server MUST default to using "i;ascii-casemap" as the collation ๐ง
wildcards (as defined in Section 3.2 of [RFC4790]) MUST NOT be used in the collation identifier ๐ซ
and if the client picks a collation the server doesn't support, the server MUST respond with a CALDAV:supported-collation precondition error response ๐
7.5.1. CALDAV:supported-collation-set Property ๐
Name: supported-collation-set ๐
Namespace: urn:ietf:params:xml:ns:caldav โจ
Purpose: This is the server's little list of collations it can actually handle for text matching ๐ It identifies the set of collations the server supports for text matching operations.
Conformance: This one is not optional, bestie ๐ญ This property MUST be defined on any resource that supports a report that does text matching. If it is defined, it MUST be protected, and it SHOULD NOT be returned by a PROPFIND DAV:allprop request (as defined in Section 12.14.1 of [RFC2518]) ๐
Description: The CALDAV:supported-collation-set property holds zero or more CALDAV:supported-collation elements. Each one names a collection identifier for a collation the server supports ๐
Definition:
<!ELEMENT supported-collation-set (supported-collation*)>
<!ELEMENT supported-collation (#PCDATA)>
Example:
<C:supported-collation-set
xmlns:C="urn:ietf:params:xml:ns:caldav">
<C:supported-collation>i;ascii-casemap</C:supported-collation>
<C:supported-collation>i;octet</C:supported-collation>
</C:supported-collation-set>
7.6. Partial Retrieval ๐ฆ
Okay so some calendaring reports in this document let you grab only part of a calendar object resource, which is honestly so smart ๐ง A CalDAV client can say exactly what it wants back in the body of a calendaring REPORT request.
A CalDAV client can ask for particular WebDAV property values, all of them, or just a list of the names of the resource's WebDAV properties. It can also ask for calendar data to come back, and it can pick whether it wants every component and property or only specific ones. Check out CALDAV:calendar-data in Section 9.6 for the details ๐
By default, the returned calendar data includes the component that defines the recurrence set, which is called the "master component," along with the components that define exceptions to that recurrence set, called the "overridden components" ๐ธ
A CalDAV client that only cares about recurrence instances overlapping a certain time range can ask for just the "master component," plus any "overridden components" that affect that time range. That way the server sends much less data (see CALDAV:limit-recurrence-set in Section 9.6.6) ๐ฅ An overridden component affects a time range if its current start and end times overlap it. It also counts if the original start and end times (the ones that would have been used if the instance weren't overridden) overlap it, or if it changes other instances that overlap it.
A CalDAV client with no support for recurrence properties (EXDATE, EXRULE, RDATE, and RRULE) and possibly VTIMEZONE components, or a client that isn't up for doing recurrence expansion because its processing power is limited, can ask for only the recurrence instances overlapping a time range. Each one comes back as its own separate calendar component that defines exactly one recurrence instance (see CALDAV:expand in Section 9.6.5) โญ
Last but not least, for VFREEBUSY components, a CalDAV client can ask to receive only the FREEBUSY property values that overlap a specified time range (see CALDAV:limit-freebusy-set in Section 9.6.7) ๐ง
7.7. Non-Standard Components, Properties, and Parameters ๐
Servers MUST support non-standard component, property, or parameter names inside the CALDAV:calendar-data XML element in calendaring REPORT requests. This lets clients ask for non-standard components, properties, and parameters to be included in the calendar data in the response ๐ซถ
Servers MAY also support non-standard component, property, or parameter names in the CALDAV:comp-filter, CALDAV:prop-filter, and CALDAV:param-filter XML elements that sit inside the CALDAV:filter XML element of calendaring REPORT requests ๐ฆ
Servers MUST fail with the CALDAV:supported-filter precondition if a calendaring REPORT request uses a CALDAV:comp-filter, CALDAV:prop-filter, or CALDAV:param-filter XML element that points at a non-standard component, property, or parameter name the server doesn't support queries on. This one is serious ๐
7.8. CALDAV:calendar-query REPORT ๐
The CALDAV:calendar-query REPORT searches for every calendar object resource that matches a given filter ๐ The response includes all the WebDAV properties and calendar object resource data that the request asked for. When it comes to CALDAV:calendar-data, you can explicitly say which calendar components and properties should come back in the data for matching resources ๐
This report is modeled on the PROPFIND method, so it uses many of the same XML elements. The request can ask for WebDAV properties to be returned too. When it does, the response should behave the same way PROPFIND does with the DAV:multistatus response elements that return specific property results. For example, asking for the value of a property that doesn't exist is an error, and it MUST be noted with a response XML element containing a 404 (Not Found) status value ๐
Support for the CALDAV:calendar-query REPORT is REQUIRED. No cap, it's not a suggestion ๐ฅ
Marshalling:
The request body MUST be a CALDAV:calendar-query XML element, as defined in Section 9.5 ๐
The request MAY include a Depth header. If there's no Depth header, Depth:0 is assumed โจ
For a successful request, the response body MUST be a DAV:multistatus XML element. In other words, it uses the same format as a PROPFIND response. If there are no response elements, the returned DAV:multistatus XML element is empty ๐ธ
For a successful CALDAV:calendar-query REPORT request, the response body MUST contain a DAV:response element for each iCalendar object that matched the search filter. The calendar data comes back in the CALDAV:calendar-data XML element inside the DAV:propstat XML element ๐ง
Preconditions:
(CALDAV:supported-calendar-data): The "content-type" and "version" attributes of the CALDAV:calendar-data XML element (see Section 9.6) specify a media type the server supports for calendar object resources ๐
(CALDAV:valid-filter): The CALDAV:filter XML element (see Section 9.7) in the REPORT request MUST be valid. For instance, a CALDAV:filter cannot nest a <C:comp name="VEVENT"> element inside a <C:comp name="VTODO"> element, and it cannot nest a <C:time-range start="..." end="..."> element inside a <C:prop name="SUMMARY"> element. Not me trying to nest a VEVENT inside a VTODO ๐
(CALDAV:supported-filter): The CALDAV:comp-filter (see Section 9.7.1), CALDAV:prop-filter (see Section 9.7.2), and CALDAV:param-filter (see Section 9.7.3) XML elements inside the CALDAV:filter XML element (see Section 9.7) of the REPORT request only reference components, properties, and parameters that the server supports querying. In other words, if the CALDAV:filter element tries to reference an unsupported component, property, or parameter, this precondition is violated. Servers SHOULD report the CALDAV:comp-filter, CALDAV:prop-filter, or CALDAV:param-filter that they don't support ๐
<!ELEMENT supported-filter (comp-filter*,
prop-filter*,
param-filter*)>
(CALDAV:valid-calendar-data): The time zone specified in the REPORT request MUST be a valid iCalendar object containing a single valid VTIMEZONE component ๐
(CALDAV:min-date-time): Any XML element that specifies a range of time MUST have its start or end DATE or DATE-TIME values greater than or equal to the CALDAV:min-date-time property value (Section 5.2.6) on the calendar collections the REPORT request targets. ๐
(CALDAV:max-date-time): Any XML element that specifies a range of time MUST have its start or end DATE or DATE-TIME values less than or equal to the CALDAV:max-date-time property value (Section 5.2.7) on the calendar collections the REPORT request targets. ๐
(CALDAV:supported-collation): Any XML attribute that specifies a collation MUST specify a collation the server supports, as described in Section 7.5 ๐ซถ
Postconditions:
(DAV:number-of-matches-within-limits): The number of matching calendar object resources must fall within server-specific, predefined limits. For example, this condition might be triggered if a search would return an extremely large number of responses ๐ญ
7.8.1. Example: Partial Retrieval of Events by Time Range โจ
okay so this example is giving main character energy ๐ The client asks the server for certain components and properties of the VEVENT components that overlap the time range from January 4, 2006, at 00:00:00 UTC to January 5, 2006, at 00:00:00 UTC ๐ธ It also asks for DAV:getetag, and that comes back in the response too.
Here's the tea ๐ซ The first calendar object is a recurring event whose first instance sits outside the requested range, but its third instance does overlap. Because of the CALDAV:calendar-data element restrictions, the DTSTAMP property in the VEVENT components doesn't get returned, and the only property that shows up in the VCALENDAR object is VERSION ๐
See Appendix B for the calendar data this example is targeting ๐
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data>
<C:comp name="VCALENDAR">
<C:prop name="VERSION"/>
<C:comp name="VEVENT">
<C:prop name="SUMMARY"/>
<C:prop name="UID"/>
<C:prop name="DTSTART"/>
<C:prop name="DTEND"/>
<C:prop name="DURATION"/>
<C:prop name="RRULE"/>
<C:prop name="RDATE"/>
<C:prop name="EXRULE"/>
<C:prop name="EXDATE"/>
<C:prop name="RECURRENCE-ID"/>
</C:comp>
<C:comp name="VTIMEZONE"/>
</C:comp>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20060104T000000Z"
end="20060105T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
>> Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd2"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=US/Eastern:20060102T120000
DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=5
SUMMARY:Event #2
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=US/Eastern:20060104T140000
DURATION:PT1H
RECURRENCE-ID;TZID=US/Eastern:20060104T120000
SUMMARY:Event #2 bis
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=US/Eastern:20060106T140000
DURATION:PT1H
RECURRENCE-ID;TZID=US/Eastern:20060106T120000
SUMMARY:Event #2 bis bis
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd3"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=US/Eastern:20060104T100000
DURATION:PT1H
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.2. Example: Partial Retrieval of Recurring Events ๐ฆ
this one's all about asking for VEVENT components that overlap the time range from January 3, 2006, at 00:00:00 UTC to January 5, 2006, at 00:00:00 UTC ๐ The CALDAV:limit-recurrence-set element is the star here. It tells the server to only send back overridden recurrence components that overlap the range in that element, or that affect other instances overlapping the range (like with a THISANDFUTURE behavior) โจ In this example, the first overridden component in the matching resource comes back, but the second one gets left out ๐ซถ
See Appendix B for the calendar data this example is targeting ๐
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?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>
<C:limit-recurrence-set start="20060103T000000Z"
end="20060105T000000Z"/>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20060103T000000Z"
end="20060105T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
>> Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd2"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART;TZID=US/Eastern:20060102T120000
DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=5
SUMMARY:Event #2
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART;TZID=US/Eastern:20060104T140000
DURATION:PT1H
RECURRENCE-ID;TZID=US/Eastern:20060104T120000
SUMMARY:Event #2 bis
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd3"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
DTSTART;TZID=US/Eastern:20060104T100000
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.3. Example: Expanded Retrieval of Recurring Events โจ
okay so bestie, this one is giving "give me every single occurrence, but make it readable" ๐ฆ The client asks the server for VEVENTs that overlap the window from January 2, 2006, at 00:00:00 A.M. UTC to January 5, 2006, at 00:00:00 A.M. UTC. It also wants recurring components expanded into individual recurrence instance components, which is what CALDAV:expand does ๐
Also, the server only returns overridden recurrence instances that overlap the time range given in that expand element. Iconic restraint ๐
See Appendix B for the calendar data being targeted by this example. ๐ง
Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?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>
<C:expand start="20060103T000000Z"
end="20060105T000000Z"/>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20060103T000000Z"
end="20060105T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd2"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART:20060103T170000
DURATION:PT1H
RECURRENCE-ID:20060103T170000
SUMMARY:Event #2
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART:20060104T190000
DURATION:PT1H
RECURRENCE-ID:20060104T170000
SUMMARY:Event #2 bis
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd3"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
DTSTART:20060104T150000
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.4. Example: Partial Retrieval of Stored Free Busy Components ๐ซถ
in this one the client wants the VFREEBUSY components with free busy info overlapping January 2, 2006, at 00:00:00 A.M. UTC (inclusive) up to January 3, 2006, at 00:00:00 A.M. UTC (exclusive) ๐
CALDAV:limit-freebusy-set tells the server to only send back the FREEBUSY property values that overlap that range. Also, and this matters ๐, this is not an example of figuring out when the calendar owner is busy. It's just retrieving what's stored.
See Appendix B for the calendar data being targeted by this example. ๐ธ
Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?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>
<C:limit-freebusy-set start="20060102T000000Z"
end="20060103T000000Z"/>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VFREEBUSY">
<C:time-range start="20060102T000000Z"
end="20060103T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd8.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd8"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VFREEBUSY
ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
UID:76ef34-54a3d2@example.com
DTSTAMP:20050530T123421Z
DTSTART:20060101T100000Z
DTEND:20060108T100000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
END:VFREEBUSY
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.5. Example: Retrieval of To-Dos by Alarm Time Range โฐ
here the client asks for VTODO components with an alarm trigger scheduled inside the given time range. Main character energy for your reminders ๐
See Appendix B for the calendar data being targeted by this example. ๐
Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VTODO">
<C:comp-filter name="VALARM">
<C:time-range start="20060106T100000Z"
end="20060107T100000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd4.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd4"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
DTSTAMP:20060205T235300Z
DUE;TZID=US/Eastern:20060106T120000
LAST-MODIFIED:20060205T235308Z
SEQUENCE:1
STATUS:NEEDS-ACTION
SUMMARY:Task #2
UID:E10BA47467C5C69BB74E8720@example.com
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
END:VALARM
END:VTODO
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.6. Example: Retrieval of Event by UID ๐
last one in this bunch, and it's so clean โจ The client asks for the VEVENT whose UID property is set to "DC6C50A017428C5216A2F1CD@example.com". Just one event, no drama ๐
See Appendix B for the calendar data being targeted by this example. ๐
Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:prop-filter name="UID">
<C:text-match collation="i;octet"
>DC6C50A017428C5216A2F1CD@example.com</C:text-match>
</C:prop-filter>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd3"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
DTSTART;TZID=US/Eastern:20060104T100000
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.7. Example: Retrieval of Events by PARTSTAT โจ
okay so in this example, the client asks the server for the VEVENT components where the ATTENDEE property is mailto:lisa@example.com and the PARTSTAT parameter is NEEDS-ACTION. lisa still needs to respond, so this is her to-do list ๐
๐
See Appendix B for the calendar data being targeted by this example. ๐ฆ
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:prop-filter name="ATTENDEE">
<C:text-match collation="i;ascii-casemap"
>mailto:lisa@example.com</C:text-match>
<C:param-filter name="PARTSTAT">
<C:text-match collation="i;ascii-casemap"
>NEEDS-ACTION</C:text-match>
</C:param-filter>
</C:prop-filter>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
>> Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd3"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
DTSTART;TZID=US/Eastern:20060104T100000
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.8. Example: Retrieval of Events Only ๐ธ
in this one, the client asks the server to hand back every single VEVENT component. no filtering drama, just all the events ๐ฅฐ
See Appendix B for the calendar data being targeted by this example. ๐ฆ
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT"/>
</C:comp-filter>
</C:filter>
</C:calendar-query>
>> Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd1.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd1"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20060206T001102Z
DTSTART;TZID=US/Eastern:20060102T100000
DURATION:PT1H
SUMMARY:Event #1
Description:Go Steelers!
UID:74855313FA803DA593CD579A@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd2"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART;TZID=US/Eastern:20060102T120000
DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=5
SUMMARY:Event #2
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART;TZID=US/Eastern:20060104T140000
DURATION:PT1H
RECURRENCE-ID;TZID=US/Eastern:20060104T120000
SUMMARY:Event #2 bis
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART;TZID=US/Eastern:20060106T140000
DURATION:PT1H
RECURRENCE-ID;TZID=US/Eastern:20060106T120000
SUMMARY:Event #2 bis bis
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd3"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
DTSTART;TZID=US/Eastern:20060104T100000
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.9. Example: Retrieval of All Pending To-Dos ๐
so here the client wants every VTODO that has no COMPLETED property and whose STATUS value isn't CANCELLED. in other words, the tasks that are still waiting to get done. the not-finished-yet crew ๐๐
See Appendix B for the calendar data being targeted by this example. ๐ฆ
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VTODO">
<C:prop-filter name="COMPLETED">
<C:is-not-defined/>
</C:prop-filter>
<C:prop-filter name="STATUS">
<C:text-match
negate-condition="yes">CANCELLED</C:text-match>
</C:prop-filter>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
>> Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd4.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd4"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
DTSTAMP:20060205T235335Z
DUE;VALUE=DATE:20060104
STATUS:NEEDS-ACTION
SUMMARY:Task #1
UID:DDDEEB7915FA61233B861457@example.com
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
END:VALARM
END:VTODO
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd5.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd5"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
DTSTAMP:20060205T235300Z
DUE;VALUE=DATE:20060106
LAST-MODIFIED:20060205T235308Z
SEQUENCE:1
STATUS:NEEDS-ACTION
SUMMARY:Task #2
UID:E10BA47467C5C69BB74E8720@example.com
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
END:VALARM
END:VTODO
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.8.10. Example: Attempt to Query Unsupported Property
Okay bestie, this one is a little oops moment ๐. The client asks the server for every VEVENT that has an X-ABC-GUID property with a value matching "ABC" ๐ . Plot twist: the server doesn't support querying that non-standard property, so it sends back an error instead ๐.
Peek at Appendix B for the calendar data this example is targeting ๐ฆ.
Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:prop-filter name="X-ABC-GUID">
<C:text-match>ABC</C:text-match>
</C:prop-filter>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Response <<
HTTP/1.1 403 Forbidden
Date: Sat, 11 Nov 2005 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:error>
<C:supported-filter>
<C:prop-filter name="X-ABC-GUID"/>
</C:supported-filter>
</D:error>
7.9. CALDAV:calendar-multiget REPORT
The CALDAV:calendar-multiget REPORT is the "grab these exact ones" move ๐. It pulls specific calendar object resources out of a collection (if the Request-URI is a collection), or fetches one specific calendar object resource (if the Request-URI is a calendar object resource). It's basically a cousin of the CALDAV:calendar-query REPORT (see Section 7.8), except instead of a CALDAV:filter element, it takes a list of DAV:href elements to decide what comes back ๐ธ.
Support for the CALDAV:calendar-multiget REPORT is REQUIRED. No skipping this one, periodt ๐ .
Marshalling:
- The request body MUST be a CALDAV:calendar-multiget XML element (see Section 9.10). If the Request-URI is a collection resource, the DAV:href elements MUST refer to calendar object resources within that collection, and they MAY refer to calendar object resources at any depth within the collection. Because of that, the "Depth" header MUST be ignored by the server and SHOULD NOT be sent by the client ๐. If the Request-URI refers to a non-collection resource, there MUST be a single DAV:href element that is equivalent to the Request-URI.
- The response body for a successful request MUST be a DAV:multistatus XML element.
- The response body for a successful CALDAV:calendar-multiget REPORT request MUST contain a DAV:response element for each calendar object resource referenced by the provided set of DAV:href elements. The calendar data comes back in the CALDAV:calendar-data element inside the DAV:prop element โจ.
- If there's an error accessing any of the provided DAV:href resources, the server MUST return the appropriate error status code in the DAV:status element of the corresponding DAV:response element.
Preconditions:
- (CALDAV:supported-calendar-data): The "content-type" and "version" attributes of the CALDAV:calendar-data XML elements (see Section 9.6) have to specify a media type the server supports for calendar object resources ๐.
- (CALDAV:min-date-time): Any XML element specifying a range of time MUST have its start or end DATE or DATE-TIME values greater than or equal to the CALDAV:min-date-time property value (Section 5.2.6) on the calendar collections being targeted by the REPORT request โฐ.
- (CALDAV:max-date-time): Any XML element specifying a range of time MUST have its start or end DATE or DATE-TIME values less than or equal to the CALDAV:max-date-time property value (Section 5.2.7) on the calendar collections being targeted by the REPORT request โณ.
Postconditions:
None. Nothing extra to check after the fact ๐ฆ.
7.9.1. Example: Successful CALDAV:calendar-multiget REPORT
In this one, the client asks for specific properties of the VEVENT components at two specific URIs ๐. It also requests DAV:getetag, which comes back in the response too. Heads up: the resource at http://cal.example.com/bernard/work/mtg1.ics doesn't exist, so that one gets an error status ๐ญ.
Check Appendix B for the calendar data being targeted here ๐.
Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-multiget xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data/>
</D:prop>
<D:href>/bernard/work/abcd1.ics</D:href>
<D:href>/bernard/work/mtg1.ics</D:href>
</C:calendar-multiget>
Response <<
HTTP/1.1 207 Multi-Status
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd1.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd1"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20060206T001102Z
DTSTART;TZID=US/Eastern:20060102T100000
DURATION:PT1H
SUMMARY:Event #1
Description:Go Steelers!
UID:74855313FA803DA593CD579A@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/mtg1.ics</D:href>
<D:status>HTTP/1.1 404 Not Found</D:status>
</D:response>
</D:multistatus>
7.10. CALDAV:free-busy-query REPORT
The CALDAV:free-busy-query REPORT makes a VFREEBUSY component that shows the free/busy info for every calendar object resource the request targets, as long as the current user has the CALDAV:read-free-busy or DAV:read privilege on it ๐ฆ. It's the "when is everyone actually free" query, and it's giving scheduling superpowers โจ.
Only VEVENT components without a TRANSP property, or with TRANSP set to OPAQUE, count here. VFREEBUSY components SHOULD be considered too when generating the free busy time info ๐ธ.
For VEVENT components, the free or busy time type (FBTYPE) of the FREEBUSY properties in the returned VFREEBUSY component SHOULD be derived from the TRANSP and STATUS properties, following this table ๐:
+---------------------------++------------------+
| VEVENT || VFREEBUSY |
+-------------+-------------++------------------+
| TRANSP | STATUS || FBTYPE |
+=============+=============++==================+
| | CONFIRMED || BUSY |
| | (default) || |
| OPAQUE +-------------++------------------+
| (default) | CANCELLED || FREE |
| +-------------++------------------+
| | TENTATIVE || BUSY-TENTATIVE |
| +-------------++------------------+
| | x-name || BUSY or |
| | || x-name |
+-------------+-------------++------------------+
| | CONFIRMED || |
| TRANSPARENT | CANCELLED || FREE |
| | TENTATIVE || |
| | x-name || |
+-------------+-------------++------------------+
Duplicate busy time periods with the same FBTYPE parameter value SHOULD NOT be specified in the returned VFREEBUSY component. Servers SHOULD coalesce consecutive or overlapping busy time periods of the same type ๐ง. Busy time periods with different FBTYPE parameter values MAY overlap.
Support for the CALDAV:free-busy-query REPORT is REQUIRED. Non-negotiable ๐.
Marshalling:
- The request body MUST be a CALDAV:free-busy-query XML element (see Section 9.11), which MUST contain exactly one CALDAV:time-range XML element, as defined in Section 9.9 โฐ.
- The request MAY include a Depth header. If no Depth header is included, Depth:0 is assumed.
- The response body for a successful request MUST be an iCalendar object containing exactly one VFREEBUSY component. That component describes the busy time intervals for the calendar object resources containing VEVENT, or VFREEBUSY components, that satisfy the Depth value and for which the current user is at least granted the CALDAV:read-free-busy privilege. If no calendar object resources are found to satisfy these conditions, a VFREEBUSY component with no FREEBUSY property MUST be returned. This report only returns busy time information. Free time can be inferred from the busy time info returned ๐ซถ.
- If the current user isn't granted the CALDAV:read-free-busy or DAV:read privileges on the Request-URI, the CALDAV:free-busy-query REPORT request MUST fail and return a 404 (Not Found) status value. This restriction stops users from discovering URLs of resources they only have the CALDAV:read-free-busy privilege for ๐.
- The CALDAV:free-busy-query REPORT request can only be run against a collection (either a regular collection or a calendar collection). An attempt to run the report on a calendar object resource MUST fail and return a 403 (Forbidden) status value ๐ซ.
Preconditions:
None.
Postconditions:
- (DAV:number-of-matches-within-limits): The number of matching calendar object resources has to fall within server-specific, predefined limits. For example, this postcondition might fail if the specified CALDAV:time-range would cause an extremely large number of calendar object resources to be considered in computing the response ๐.
7.10.1. Example: Successful CALDAV:free-busy-query REPORT ๐
okay so this example is giving free busy lookup done right ๐
Bernard's client wants to know when he's booked on his work calendar collection /bernard/work/. The window is 9:00 A.M. to 5:00 P.M. EST, which is 2:00 P.M. to 10:00 P.M. UTC, on January 4, 2006. The server comes back saying there are two one-hour busy blocks in there, and one of them is only tentative ๐ฆ
Check Appendix B for the calendar data this example is hitting ๐ง
>> Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<C:time-range start="20060104T140000Z"
end="20060105T220000Z"/>
</C:free-busy-query>
>> Response <<
HTTP/1.1 200 OK
Date: Sat, 11 Nov 2006 09:32:12 GMT
Content-Type: text/calendar
Content-Length: xxxx
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Server//EN
BEGIN:VFREEBUSY
DTSTAMP:20050125T090000Z
DTSTART:20060104T140000Z
DTEND:20060105T220000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060104T150000Z/PT1H
FREEBUSY:20060104T190000Z/PT1H
END:VFREEBUSY
END:VCALENDAR
8. Guidelines ๐ธ
8.1. Client-to-Client Interoperability ๐ซถ
ngl there are a bunch of things clients can do that are still legal, meaning the server won't throw errors ๐ญ But they can totally wreck interoperability with other client apps poking at the same data ๐ Like, swapping a recurrence rule for a pile of recurrence dates, splitting one recurring event into a separate resource for every single occurrence, or translating start and end times from the original time zone into a different one. Honestly this is just iCalendar interoperability best practice, not a CalDAV-only thing, but the problems show up way more in CalDAV use cases ๐
8.2. Synchronization Operations ๐
WebDAV already has what you need to sync a collection (or a bunch of them), make changes offline, and resolve conflicts neatly when you reconnect โจ ETags are the secret sauce here, but not every WebDAV server has them, so it's not a free pass. Offline stuff matters way more for calendar apps than for a lot of other WebDAV apps, so CalDAV servers MUST support ETags, as specified in Section 5.3.4. no exceptions bestie ๐
8.2.1. Use of Reports ๐
8.2.1.1. Restrict the Time Range โฐ
The CalDAV reports are how clients save bandwidth and don't overwork the local machine ๐ง That's a huge deal on phones and handhelds with limited capacity, but it's still super relevant on desktops when a calendar collection is stuffed with tons of data ๐ฉ
Clients usually show calendar data in views covering a finite stretch of time, so whenever possible they should only pull components from the server with a CALDAV:calendar-query REPORT plus a CALDAV:time-range element. That way only the stuff needed to fill the current view comes back ๐
8.2.1.2. Synchronize by Time Range ๐ฆ
In a calendar, historical stuff (events, to-dos, etc. that finished before today) basically never changes, though it might get deleted ๐ So a client can speed up sync by only caring about the present and the future up to some reasonable limit, like a week or a month. If the user then wanders off to look at a part of the calendar outside what's been synced, the client just runs another sync on that new interval. This "just-in-time" sync keeps bandwidth low for the stuff people actually do all day ๐
8.2.1.3. Synchronization Process ๐ฅ
If a client wants to support calendar data sync (instead of downloading everything every time it's needed), it has to cache each calendar object resource's URI and ETag, along with the actual calendar data. The URI stays the same for the whole life of the resource, but the ETag changes with every single change to it ๐ So to sync the local cache with the server, the client can first fetch the URI/ETag pairs for the time interval it cares about, then compare those with what it cached. Any cached component whose ETag doesn't match the server's needs to be refreshed ๐ซถ
To detect changes between the server and client data properly, the client needs to keep track of which calendar object resources have been created, changed, or deleted since the last sync operation so it can reconcile those changes with the server ๐ง
Here's an example of how to do that ๐
The client sends a CALDAV:calendar-query REPORT for a specific time range and only asks for the DAV:getetag property back:
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20040902T000000Z"
end="20040903T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
The client then uses those results to figure out which calendar object resources changed, got created, or got deleted on the server, and how that lines up with the locally cached ones that might have changed, been created, or been deleted too ๐ง If there are calendar object resources on the server that need fetching, the client sends a CALDAV:calendar-multiget REPORT to grab its calendar data:
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-multiget xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data/>
</D:prop>
<D:href>/bernard/work/abcd1.ics</D:href>
<D:href>/bernard/work/mtg1.ics</D:href>
</C:calendar-multiget>
8.2.2. Restrict the Properties Returned โ๏ธ
Clients don't always need every single property of a calendar object resource to show the user what's up ๐ Some property values can be huge (ATTACH and ATTENDEE, I'm looking at you ๐), so a client can limit the properties returned in a calendaring REPORT to just the ones it knows it'll use ๐ธ
BUT here's the catch ๐ If a client needs to change a calendar object resource, the only way is to PUT the entire resource. There's currently no way to incrementally change a set of calendar properties. So the client has to fetch the whole calendar object resource being changed anyway ๐ญ
8.3. Use of Locking ๐
WebDAV locks keep two clients editing the same resource from overwriting each other's changes (ETags can also solve that one) or wasting time on changes that are going to conflict with someone else's ๐ In a multi-user calendar system, an interactive client can lock an event while the user is editing it, then unlock it when they finish or cancel. Locks are also useful for stopping changes while data is being reorganized. For example, a calendar client might lock two calendar collections before moving a bunch of calendar resources from one to the other ๐ง
Clients are responsible for asking for a lock timeout that fits the use case ๐ซถ When the user deliberately wants to reserve a resource and block other changes, a long timeout can make sense. But when the client locks something automatically, the timeout should be short, and the client can always refresh the lock if it needs to ๐ฆ A short timeout also means that if the client can't remove the lock, other calendar users aren't stuck locked out of making changes ๐
8.4. Finding Calendars โจ
Most of the time, a calendar client (or agent) finds a new calendar by being handed the URL directly ๐. Like, a user types their calendar location into the client config, or copies a URL out of an email and pastes it into the app. The client only needs to confirm that the URL points to a calendar collection. It might also be able to browse WebDAV collections to find calendar collections ๐ง
Calendar object resources use plain HTTP URLs, which keeps them backward compatible with existing software ๐. The downside is that existing software doesn't usually know to check the OPTIONS response for that URL to see what it can do with it ๐. That's kind of a barrier for WebDAV usage and for CalDAV usage too. This specification doesn't really fix that, other than making the info available in the OPTIONS response if someone asks for it.
For calendar sharing and scheduling, you might want to find another user's calendar ๐. If that user has a calendar in the same repository, you can find it through the principal namespace that WebDAV ACL support requires. For everything else, the authors don't have a universal answer. Implementers can think about using vCard [RFC2426] or LDAP [RFC4511] together with calendar attributes [RFC2739] ๐
Since CalDAV requires servers to support WebDAV ACL [RFC3744], principal namespaces included, plus the CALDAV:calendar-home-set property, CalDAV clients have a couple of ways to find your own calendar or someone else's ๐ธ
Here, a DAV:principal-match REPORT is used to look up a named property (CALDAV:calendar-home-set) on the current user's Principal-URL ๐. With that, a WebDAV client can figure out "who am I" and "where are my calendars" ๐ฆ The REPORT request body looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<D:principal-match xmlns:D="DAV:">
<D:self/>
<D:prop>
<C:calendar-home-set
xmlns:C="urn:ietf:params:xml:ns:caldav"/>
</D:prop>
</D:principal-match>
To find other users' calendars, the DAV:principal-property-search REPORT can filter on some properties and return others ๐. Say you want a calendar owned by someone named "Laurie". The REPORT request body would look like this:
<?xml version="1.0" encoding="utf-8" ?>
<D:principal-property-search xmlns:D="DAV:">
<D:property-search>
<D:prop>
<D:displayname/>
</D:prop>
<D:match>Laurie</D:match>
</D:property-search>
<D:prop>
<C:calendar-home-set
xmlns:C="urn:ietf:params:xml:ns:caldav"/>
<D:displayname/>
</D:prop>
</D:principal-property-search>
The server does a case-sensitive or caseless search for a matching string subset of "Laurie" inside the DAV:displayname property ๐ซถ. So it might return "Laurie Dusseault", "Laurier Desruisseaux", or "Wilfrid Laurier" as matches, and then hand back the calendars for each of them ๐ญ
8.5. Storing and Using Attachments ๐
CalDAV clients MAY create attachments in calendar components, either inline or external ๐ . This section has some guidelines for making and managing attachments, so read on bestie ๐ง
8.5.1. Inline Attachments
CalDAV clients MUST support inline attachments as specified in iCalendar [RFC2445] ๐ซถ. CalDAV servers MUST support inline attachments too, so clients can count on being able to attach stuff this way ๐. BUT inline attachments come with some drawbacks, ngl ๐:
- Servers MAY impose limits on the size of calendar object resources (for example, refusing PUT requests for very large iCalendar objects). Servers that impose these limits MUST use the CALDAV:max-resource-size property on a calendar collection to tell the client what the limit is (see Section 5.2.5) ๐
- Servers MAY impose storage quota limitations on calendar collections (See [RFC4331]) ๐พ
- Any change to a calendar object resource containing an inline attachment means the entire inline attachment has to be re-uploaded ๐ฉ
- Clients synchronizing a changed calendar object resource have to download the entire calendar object resource, even when the attachment hasn't changed ๐
8.5.2. External Attachments
CalDAV clients SHOULD support downloading external attachments referenced by arbitrary URI schemes. They can either process them directly, or pass the attachment URI to a suitable "helper application" for processing, if one exists ๐งฉ CalDAV clients MUST support downloading external attachments referenced by the "http" or "https" URI schemes ๐ An external attachment could be:
- In a collection inside the calendar collection that contains the calendar object resource ๐
- Somewhere else in the same repository that hosts the calendar collection ๐
- On an HTTP or FTP server somewhere else ๐
CalDAV servers MAY provide support for child collections in calendar collections. CalDAV servers MAY allow the MKCOL method to create child collections in calendar collections. Child collections of calendar collections MAY contain any type of resource, EXCEPT calendar collections, which they MUST NOT contain ๐ โโ๏ธ Some CalDAV servers won't allow child collections in calendar collections. On those servers, it may be possible to discover other places where attachments can be stored ๐
Clients are fully responsible for keeping references consistent with the calendar components that link to external attachments ๐. So a client that deletes a calendar component with an external attachment might also delete the attachment, if that's appropriate. But appropriateness is super hard to figure out ๐ตโ๐ซ A new component could easily reference some existing Web resource that's meant to exist independently of the calendar component (the "attachment" might be a big proposal being discussed in a meeting, for example) ๐ Best practices will probably emerge and should probably get documented, but for now, clients should be wary of aggressive "cleanup" of external attachments ๐งน A client could involve the user in deciding which unreferenced documents to remove, or it could be conservative and only delete attachments it created itself ๐ซง
Clients are also responsible for keeping permissions consistent when using external attachments ๐. One reason servers should support storing attachments in child collections of calendar collections is that ACL inheritance might make it easier to grant the same permissions to attachments that are granted on the calendar collection. Otherwise, it gets really hard to keep permissions synced ๐ค With attachments stored in separate repositories, it can be impossible to keep permissions consistent, because the two repositories may not support the same permissions or have the same set of principals ๐ Some systems have used tickets or other anonymous access control mechanisms to get partially working solutions to these kinds of problems ๐๏ธ
8.6. Storing and Using Alarms โฐ
Heads up, all CalDAV calendar collections (including the ones users treat as public or group calendars) can contain alarm info on events and to-dos ๐ . Users can sync a calendar across multiple devices and decide to have alarms go off on a different device than the one that made the alarm ๐ฑ๐ป. Not every alarm action type is fully interoperable (for example, the ones that name a sound file to play) ๐
When the action is AUDIO and the client is set up to execute the alarm, the client SHOULD play the suggested sound if it's available, or play another sound. It SHOULD NOT rewrite the alarm just to swap in a locally available sound ๐ต
When the action is DISPLAY and the client is set up to execute the alarm, the client SHOULD execute a display alarm by showing the suggested description or some reasonable replacement. It SHOULD NOT rewrite the alarm for its own convenience ๐ฅ๏ธ
When the action is EMAIL and the client is incapable of sending email, it SHOULD ignore the alarm, but it MUST continue to synchronize the alarm itself ๐ง
This specification makes no recommendations about executing alarms of type PROCEDURE, except to note that clients are advised to take care to avoid creating security holes by executing these โ ๏ธ
Non-interoperable alarm info (say somebody defines a color to use in a display alarm) should go in non-standard properties inside the VALARM component. That keeps the basic alarm usable on all devices ๐
Clients that allow changes to calendar object resources MUST synchronize the alarm data that already exists in those resources ๐ซถ
Clients MAY execute alarms downloaded this way, maybe based on user preference ๐โโ๏ธ If a client is only doing read operations on a calendar, and there's no risk of losing alarm info, then the client MAY discard alarm info ๐๏ธ
This specification makes no attempt to provide multi-user alarms on group calendars, or to figure out who an alarm is intended for ๐คทโโ๏ธ Addressing those issues might need extensions to iCalendar. For example, to store alarms per user, or to indicate which user a VALARM was intended for ๐ In the meantime, clients might maximize interoperability by generally not uploading alarm info to public, group, or resource calendars ๐ง
9. XML Element Definitions ๐
9.1. CALDAV:calendar XML Element
Name: calendar
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies the resource type of a calendar collection ๐๏ธ
Description: See Section 4.2.
Definition:
<!ELEMENT calendar EMPTY>
9.2. CALDAV:mkcalendar XML Element
Name: mkcalendar
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies a request that includes the WebDAV property values to be set for a calendar collection resource when it's created ๐ ๏ธ
Description: See Section 5.3.1.
Definition:
<!ELEMENT mkcalendar (DAV:set)>
9.3. CALDAV:mkcalendar-response XML Element
Name: mkcalendar-response
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies a response body for a successful MKCALENDAR request ๐
Description: See Section 5.3.1.
Definition:
<!ELEMENT mkcalendar-response ANY>
9.4. CALDAV:supported-collation XML Element
Name: supported-collation
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Identifies a single collation via its collation identifier, as defined by [RFC4790] ๐ค
Description: The CALDAV:supported-collation contains the text of a collation identifier, as described in Section 7.5.1.
Definition:
<!ELEMENT supported-collation (#PCDATA)>
PCDATA value: collation identifier
9.5. CALDAV:calendar-query XML Element
Name: calendar-query
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Defines a report for querying calendar object resources ๐
Description: See Section 7.8.
Definition:
<!ELEMENT calendar-query ((DAV:allprop |
DAV:propname |
DAV:prop)?, filter, timezone?)>
9.6. CALDAV:calendar-data XML Element โจ
Name: calendar-data ๐
Namespace: urn:ietf:params:xml:ns:caldav ๐ธ
Purpose: okay, this element is a total multitasker ๐ It can do one of three jobs:
- It lists a supported media type for calendar object resources when it's nested inside the CALDAV:supported-calendar-data property ๐
- It says which parts of a calendar object resource should come back from a calendaring report ๐
- It carries the actual content of a calendar object resource in a calendaring report response ๐
Description: when it's nested in CALDAV:supported-calendar-data, it's basically the server saying "hey, I speak this media type for calendar object resources" ๐ฆ
When it shows up in a calendaring REPORT request, it tells the server which parts of the calendar object resources to send back ๐ง If there's no CALDAV:comp element inside it, the server just returns the whole calendar object resources, no edits, full send ๐โโ๏ธ
When it's in a calendaring REPORT response, it holds the content of a calendar object resource. Here's the fun part: XML parsers turn the two-character CRLF sequence (US-ASCII decimal 13 and US-ASCII decimal 10) into a single LF character (US-ASCII decimal 10). So the CR character (US-ASCII decimal 13) MAY be omitted in calendar object resources inside this element ๐ Also, calendar object resources in this element MAY be invalid per their media type specification if the calendaring REPORT request's calendar-data part didn't ask for required properties (like UID, DTSTAMP, etc.), or if it had a CALDAV:prop element with the "novalue" attribute set to "yes". Not me being shady, that's just how it works ๐ญ
Note: this one's a little bit of a trickster. It's written in requests and responses inside the DAV:prop element as if it were a WebDAV property. But it is NOT a WebDAV property ๐ โโ๏ธ so it doesn't show up in PROPFIND responses, and you can't use it in PROPPATCH requests. Bestie, don't be fooled ๐ฅน
Note: the iCalendar data inside CALDAV:calendar-data MUST follow the standard XML character data encoding rules. That means using entity encoding like <, >, & etc., or wrapping it in a <![CDATA[ ... ]]> construct. If you go the CDATA route, the iCalendar data can't contain the character sequence ]]>, because that's the CDATA section's end delimiter. Super important, so don't skip it ๐
Definition:
<!ELEMENT calendar-data EMPTY>
when nested in the CALDAV:supported-calendar-data property
to specify a supported media type for calendar object
resources;
<!ELEMENT calendar-data (comp?,
(expand | limit-recurrence-set)?,
limit-freebusy-set?)>
when nested in the DAV:prop XML element in a calendaring
REPORT request to specify which parts of calendar object
resources should be returned in the response;
<!ELEMENT calendar-data (#PCDATA)>
PCDATA value: iCalendar object
when nested in the DAV:prop XML element in a calendaring
REPORT response to specify the content of a returned
calendar object resource.
<!ATTLIST calendar-data content-type CDATA "text/calendar"
version CDATA "2.0">
content-type value: a MIME media type
version value: a version string
attributes can be used on all three variants of the
CALDAV:calendar-data XML element.
9.6.1. CALDAV:comp XML Element
Name: comp ๐ง
Namespace: urn:ietf:params:xml:ns:caldav ๐
Purpose: this one picks which component types to return ๐ฏ
Description: the name value is a calendar component name, like VEVENT ๐
Definition:
<!ELEMENT comp ((allprop | prop*), (allcomp | comp*))>
<!ATTLIST comp name CDATA #REQUIRED>
name value: a calendar component name
Note: the CALDAV:prop and CALDAV:allprop elements have the same names as the DAV:prop and DAV:allprop elements from [RFC2518]. The difference is that they live in the "urn:ietf:params:xml:ns:caldav" namespace instead of "DAV:" ๐
9.6.2. CALDAV:allcomp XML Element
Name: allcomp ๐ฆ
Namespace: urn:ietf:params:xml:ns:caldav ๐ธ
Purpose: says that every component should be returned ๐
Description: the CALDAV:allcomp element is for when the client wants every type of component back from a calendaring REPORT request. Main character energy ๐
Definition:
<!ELEMENT allcomp EMPTY>
9.6.3. CALDAV:allprop XML Element
Name: allprop ๐
Namespace: urn:ietf:params:xml:ns:caldav โจ
Purpose: says that every property should be returned ๐
Description: the CALDAV:allprop element is for when the client wants all the properties of components back from a calendaring REPORT request. Give me everything ๐
Definition:
<!ELEMENT allprop EMPTY>
Note: the CALDAV:allprop element has the same name as the DAV:allprop element from [RFC2518], but it's in the "urn:ietf:params:xml:ns:caldav" namespace instead of "DAV:" ๐ง
9.6.4. CALDAV:prop XML Element
Name: prop ๐
Namespace: urn:ietf:params:xml:ns:caldav ๐ซถ
Purpose: defines which properties to send back in the response ๐ฆ
Description: the "name" attribute names the calendar property to return, like ATTENDEE ๐ The "novalue" attribute lets clients ask that the actual value NOT be returned, but only when "novalue" is set to "yes". In that case, the server returns just the iCalendar property name, any iCalendar parameters, and a trailing ":" with no value after it. Like a sneak peek without the spoiler ๐
Definition:
<!ELEMENT prop EMPTY>
<!ATTLIST prop name CDATA #REQUIRED
novalue (yes | no) "no">
name value: a calendar property name
novalue value: "yes" or "no"
Note: the CALDAV:prop element has the same name as the DAV:prop element from [RFC2518], but it lives in the "urn:ietf:params:xml:ns:caldav" namespace instead of "DAV:" ๐ท
9.6.5. CALDAV:expand XML Element
Name: expand ๐ฅ
Namespace: urn:ietf:params:xml:ns:caldav ๐
Purpose: forces the server to break recurring components apart into individual recurrence instances ๐ช
Description: this is the element where the server gets told to expand. For a given calendaring REPORT request, the server MUST expand the recurrence set into calendar components that each define exactly one recurrence instance. It MUST return only the ones whose scheduled time intersects a specified time range. Serving precision ๐
The "start" attribute is the inclusive start of that time range, and the "end" attribute is the non-inclusive end. Both are written as a date with UTC time value. The value of "end" MUST be greater than the value of "start". No cap, that's just basic logic ๐ง
The server MUST use the same logic as defined for CALDAV:time-range to figure out whether a recurrence instance intersects the specified time range ๐ฏ
Recurring components other than the initial instance MUST include a RECURRENCE-ID property, so everyone knows which instance they refer to ๐
The returned calendar components MUST NOT use recurrence properties (that's EXDATE, EXRULE, RDATE, and RRULE) and MUST NOT have any reference to, or include, VTIMEZONE components. Date and local time that references time zone information MUST be converted into date with UTC time. Timezones are NOT the vibe here ๐๐ซ
Definition:
<!ELEMENT expand EMPTY>
<!ATTLIST expand start CDATA #REQUIRED
end CDATA #REQUIRED>
start value: an iCalendar "date with UTC time"
end value: an iCalendar "date with UTC time"
9.6.6. CALDAV:limit-recurrence-set XML Element
Name: limit-recurrence-set ๐
Namespace: urn:ietf:params:xml:ns:caldav ๐
Purpose: sets a time range that limits which "overridden components" the server sends back ๐ง
Description: for a given calendaring REPORT request, the server MUST return, in addition to the "master component", only the "overridden components" that actually affect a specified time range. An overridden component counts if its current start and end times overlap the time range, or if its original start and end times (the ones it would have had if it weren't overridden) overlap it. Sneaky overlaps count too ๐
The "start" attribute is the inclusive start of the time range, and "end" is the non-inclusive end. Both are written as a date with UTC time value. The value of "end" MUST be greater than the value of "start" ๐
The server MUST use the same logic as defined for CALDAV:time-range to determine whether the current or original scheduled time of an "overridden" recurrence instance intersects the specified time range ๐
Here's the drama ๐ญ Overridden components with a RANGE parameter on their RECURRENCE-ID property can point at one or more instances in the recurrence set. Some of those instances might fall inside the time range, or might have originally fallen inside it before being overridden. If that's the case, the overridden component MUST be included in the results, because it changes how the instances in that time range get interpreted. Non-negotiable โจ
Definition:
<!ELEMENT limit-recurrence-set EMPTY>
<!ATTLIST limit-recurrence-set start CDATA #REQUIRED
end CDATA #REQUIRED>
start value: an iCalendar "date with UTC time"
end value: an iCalendar "date with UTC time"
9.6.7. CALDAV:limit-freebusy-set XML Element
Name: limit-freebusy-set ๐ซง
Namespace: urn:ietf:params:xml:ns:caldav ๐ธ
Purpose: sets a time range that limits which FREEBUSY values the server returns ๐ฐ๏ธ
Description: for a given calendaring REPORT request, the server MUST only return the FREEBUSY property values of a VFREEBUSY component that intersect a specified time range. Only the tea that's relevant gets spilled โ
The "start" attribute is the inclusive start of the time range, and "end" is the non-inclusive end. Both are written as a "date with UTC time" value. The value of "end" MUST be greater than the value of "start" ๐
The server MUST use the same logic as defined for CALDAV:time-range to determine whether a FREEBUSY property value intersects the specified time range ๐งโโ๏ธ
Definition:
<!ELEMENT limit-freebusy-set EMPTY>
<!ATTLIST limit-freebusy-set start CDATA #REQUIRED
end CDATA #REQUIRED>
start value: an iCalendar "date with UTC time"
end value: an iCalendar "date with UTC time"
9.7. CALDAV:filter XML Element โจ
Name: filter
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies a filter to limit the set of calendar components returned by the server. ๐
Description: Okay so CALDAV:filter is the search filter that decides which calendar components come back from a calendaring REPORT request. It's the bouncer at the door, bestie ๐ชโจ
Definition:
<!ELEMENT filter (comp-filter)>
9.7.1. CALDAV:comp-filter XML Element ๐ฆ
Name: comp-filter
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies search criteria on calendar components. ๐
Description: The CALDAV:comp-filter element is aimed at either the calendar object (that's the VCALENDAR) or one specific component type, like VEVENT. Its scope is the whole calendar object when it sits under CALDAV:filter, and the enclosing calendar component when it sits under another CALDAV:comp-filter. A CALDAV:comp-filter counts as a match in any of these cases:
- The
CALDAV:comp-filterelement is empty and the calendar object or calendar component type named in the"name"attribute exists in the current scope;
or:
- The
CALDAV:comp-filterelement contains aCALDAV:is-not-definedelement and the calendar object or calendar component type named in the"name"attribute does not exist in the current scope;
or:
- The
CALDAV:comp-filterelement contains aCALDAV:time-rangeelement, at least one recurrence instance in the targeted calendar component is scheduled to overlap that time range, and every specifiedCALDAV:prop-filterandCALDAV:comp-filterchild element also matches the targeted calendar component;
or:
- The
CALDAV:comp-filterelement only containsCALDAV:prop-filterandCALDAV:comp-filterchild elements, and every one of them matches the targeted calendar component.
Definition:
<!ELEMENT comp-filter (is-not-defined | (time-range?,
prop-filter*, comp-filter*))>
<!ATTLIST comp-filter name CDATA #REQUIRED>
name value: a calendar object or calendar component
type (e.g., VEVENT)
9.7.2. CALDAV:prop-filter XML Element ๐
Name: prop-filter
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies search criteria on calendar properties. ๐ธ
Description: The CALDAV:prop-filter element is a query aimed at one calendar property (like CATEGORIES) inside the enclosing calendar component. A calendar property counts as a match for a CALDAV:prop-filter in these cases:
- The
CALDAV:prop-filterelement is empty and a property of the type named in the"name"attribute exists in the enclosing calendar component;
or:
- The
CALDAV:prop-filterelement contains aCALDAV:is-not-definedelement and no property of the type named in the"name"attribute exists in the enclosing calendar component;
or:
- The
CALDAV:prop-filterelement contains aCALDAV:time-rangeelement, the property value overlaps the specified time range, and every specifiedCALDAV:param-filterchild element also matches the targeted property;
or:
- The
CALDAV:prop-filterelement contains aCALDAV:text-matchelement, the property value matches it, and every specifiedCALDAV:param-filterchild element also matches the targeted property.
Definition:
<!ELEMENT prop-filter (is-not-defined |
((time-range | text-match)?,
param-filter*))>
<!ATTLIST prop-filter name CDATA #REQUIRED>
name value: a calendar property name (e.g., ATTENDEE)
9.7.3. CALDAV:param-filter XML Element ๐ง
Name: param-filter
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Limits the search to specific parameter values. ๐
Description: The CALDAV:param-filter element is a query aimed at one calendar property parameter (like PARTSTAT) inside the calendar property it's defined on. A calendar property parameter counts as a match for a CALDAV:param-filter in these cases:
- The
CALDAV:param-filterelement is empty and a parameter of the type named in the"name"attribute exists on the calendar property being examined;
or:
- The
CALDAV:param-filterelement contains aCALDAV:is-not-definedelement and no parameter of the type named in the"name"attribute exists on the calendar property being examined.
Definition:
<!ELEMENT param-filter (is-not-defined | text-match?)>
<!ATTLIST param-filter name CDATA #REQUIRED>
name value: a property parameter name (e.g., PARTSTAT)
9.7.4. CALDAV:is-not-defined XML Element ๐
Name: is-not-defined
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies that a match should occur if the enclosing component, property, or parameter does not exist. ๐ซถ
Description: The CALDAV:is-not-defined element says there's a match when the enclosing component, property, or parameter value named in a calendaring REPORT request is not present in the calendar data being tested. It's the "ghost check" ๐ป
Definition:
<!ELEMENT is-not-defined EMPTY>
9.7.5. CALDAV:text-match XML Element ๐ฅ
Name: text-match
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies a substring match on a property or parameter value. ๐
Description: The CALDAV:text-match element carries the text used for a substring match against the property or parameter value named in a calendaring REPORT request.
The "collation" attribute picks the collation the server MUST use for character string matching. If that attribute isn't there, the server MUST use the "i;ascii-casemap" collation. The server really has to do this, no exceptions ๐
โโ๏ธ
The "negate-condition" attribute flips the result. Set it to "no" and you get a match when the text matches. Set it to "yes" and you get a match when the text does not match. For example, this can be used to match components with a STATUS property not set to CANCELLED. ๐
Definition:
<!ELEMENT text-match (#PCDATA)>
PCDATA value: string
<!ATTLIST text-match collation CDATA "i;ascii-casemap"
negate-condition (yes | no) "no">
9.8. CALDAV:timezone XML Element ๐
Name: timezone
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies the time zone component to use when determining the results of a report. ๐บ๏ธ
Description: For a given calendaring REPORT request, the server MUST rely on the VTIMEZONE component you give in CALDAV:timezone instead of the CALDAV:calendar-timezone property on the calendar collection that holds the calendar object resource. It's used to turn "date" values and "date with local time" values (aka floating time) into "date with UTC time" values. The server needs that info to figure out whether a component scheduled with "date" or "date with local time" values overlaps a CALDAV:time-range in a CALDAV:calendar-query REPORT. Time zones matter, bestie โฐ
Note: The iCalendar data inside theCALDAV:timezoneelement MUST follow the standard XML character data encoding rules, including entity encoding such as<,>,&, etc., or the use of a<![CDATA[ ... ]]>construct. If you go with the CDATA option, the iCalendar data cannot contain the character sequence"]]>", since that's the end delimiter for the CDATA section.
Definition:
<!ELEMENT timezone (#PCDATA)>
PCDATA value: an iCalendar object with exactly one VTIMEZONE
9.9. CALDAV:time-range XML Element โฐ
Name: time-range
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: Specifies a time range to limit the set of calendar components returned by the server.
Description: okay so CALDAV:time-range is basically a date window ๐๏ธ For a calendaring REPORT request, the server MUST only return the calendar object resources that, depending on the context, have a component or property whose value intersects the specified time range. Main character energy for the calendar data, fr fr ๐
The start attribute is the inclusive start of the range, and the end attribute is the non-inclusive end. Both attributes MUST be specified as "date with UTC time" value. You can leave one end open by only including one attribute, but at least one attribute MUST always be present in the CALDAV:time-range element. If start or end is missing, it's treated as -infinity or +infinity respectively ๐ And if both are there, the value of the end attribute MUST be greater than the value of the start attribute, no exceptions ๐
โโ๏ธ
Time range tests MUST consider every recurrence instance when testing the time range condition. If any one instance matches, the test returns true โจ Checking recurrence instances means the server has to infer an effective value for DTSTART, DTEND, DURATION, and DUE properties for each instance, based on the recurrence patterns and any overrides. It's a lot, bestie, but the server is literally doing its best ๐ซถ
Now the tables, which are the spicy part ๐ฅ A VEVENT overlaps a given time range if the condition for its component state (shown below) is satisfied. Note that, as specified in [RFC2445], the DTSTART property is REQUIRED in the VEVENT component. The conditions depend on whether DTEND and DURATION are present. Also, the value of the DTEND property MUST be later in time than the value of the DTSTART property ๐ A VEVENT with no DTEND and no DURATION lasts 1 day (+P1D) when DTSTART is a DATE value, and 0 seconds when DTSTART is a DATE-TIME value.
+---------------------------------------------------------------+
| VEVENT has the DTEND property? |
| +-----------------------------------------------------------+
| | VEVENT has the DURATION property? |
| | +-------------------------------------------------------+
| | | DURATION property value is greater than 0 seconds? |
| | | +---------------------------------------------------+
| | | | DTSTART property is a DATE-TIME value? |
| | | | +-----------------------------------------------+
| | | | | Condition to evaluate |
+---+---+---+---+-----------------------------------------------+
| Y | N | N | * | (start < DTEND AND end > DTSTART) |
+---+---+---+---+-----------------------------------------------+
| N | Y | Y | * | (start < DTSTART+DURATION AND end > DTSTART) |
| | +---+---+-----------------------------------------------+
| | | N | * | (start <= DTSTART AND end > DTSTART) |
+---+---+---+---+-----------------------------------------------+
| N | N | N | Y | (start <= DTSTART AND end > DTSTART) |
+---+---+---+---+-----------------------------------------------+
| N | N | N | N | (start < DTSTART+P1D AND end > DTSTART) |
+---+---+---+---+-----------------------------------------------+
A VTODO overlaps a given time range if the condition for its component state (also below) is satisfied. This one depends on DTSTART, DURATION, DUE, COMPLETED, and CREATED being present or not ๐งฉ Note that, as specified in [RFC2445], the DUE value MUST be a DATE-TIME value equal to or after the DTSTART value, if DTSTART is specified.
+-------------------------------------------------------------------+
| VTODO has the DTSTART property? |
| +---------------------------------------------------------------+
| | VTODO has the DURATION property? |
| | +-----------------------------------------------------------+
| | | VTODO has the DUE property? |
| | | +-------------------------------------------------------+
| | | | VTODO has the COMPLETED property? |
| | | | +---------------------------------------------------+
| | | | | VTODO has the CREATED property? |
| | | | | +-----------------------------------------------+
| | | | | | Condition to evaluate |
+---+---+---+---+---+-----------------------------------------------+
| Y | Y | N | * | * | (start <= DTSTART+DURATION) AND |
| | | | | | ((end > DTSTART) OR |
| | | | | | (end >= DTSTART+DURATION)) |
+---+---+---+---+---+-----------------------------------------------+
| Y | N | Y | * | * | ((start < DUE) OR (start <= DTSTART)) |
| | | | | | AND |
| | | | | | ((end > DTSTART) OR (end >= DUE)) |
+---+---+---+---+---+-----------------------------------------------+
| Y | N | N | * | * | (start <= DTSTART) AND (end > DTSTART) |
+---+---+---+---+---+-----------------------------------------------+
| N | N | Y | * | * | (start < DUE) AND (end >= DUE) |
+---+---+---+---+---+-----------------------------------------------+
| N | N | N | Y | Y | ((start <= CREATED) OR (start <= COMPLETED))|
| | | | | | AND |
| | | | | | ((end >= CREATED) OR (end >= COMPLETED))|
+---+---+---+---+---+-----------------------------------------------+
| N | N | N | Y | N | (start <= COMPLETED) AND (end >= COMPLETED) |
+---+---+---+---+---+-----------------------------------------------+
| N | N | N | N | Y | (end > CREATED) |
+---+---+---+---+---+-----------------------------------------------+
| N | N | N | N | N | TRUE |
+---+---+---+---+---+-----------------------------------------------+
A VJOURNAL overlaps a given time range if the condition for its component state (see the table) is satisfied. It depends on whether DTSTART is there, and whether that DTSTART is a DATE-TIME or a DATE value ๐ The effective "duration" of a VJOURNAL is 1 day (+P1D) when DTSTART is a DATE value, and 0 seconds when DTSTART is a DATE-TIME value.
+----------------------------------------------------+
| VJOURNAL has the DTSTART property? |
| +------------------------------------------------+
| | DTSTART property is a DATE-TIME value? |
| | +--------------------------------------------+
| | | Condition to evaluate |
+---+---+--------------------------------------------+
| Y | Y | (start <= DTSTART) AND (end > DTSTART) |
+---+---+--------------------------------------------+
| Y | N | (start < DTSTART+P1D) AND (end > DTSTART) |
+---+---+--------------------------------------------+
| N | * | FALSE |
+---+---+--------------------------------------------+
A VFREEBUSY overlaps a given time range if the condition for its component state (table below) is satisfied. This one looks at whether DTSTART and DTEND are both there, and at any FREEBUSY properties when they're not ๐ฆ Any DURATION property is ignored, since it means something special inside a VFREEBUSY component. When only FREEBUSY properties are used, each period in each FREEBUSY property gets compared against the time range, no matter what kind of free busy information it represents (free, busy, busy-tentative, busy-unavailable).
+------------------------------------------------------+
| VFREEBUSY has both the DTSTART and DTEND properties? |
| +--------------------------------------------------+
| | VFREEBUSY has the FREEBUSY property? |
| | +----------------------------------------------+
| | | Condition to evaluate |
+---+---+----------------------------------------------+
| Y | * | (start <= DTEND) AND (end > DTSTART) |
+---+---+----------------------------------------------+
| N | Y | (start < freebusy-period-end) AND |
| | | (end > freebusy-period-start) |
+---+---+----------------------------------------------+
| N | N | FALSE |
+---+---+----------------------------------------------+
A VALARM overlaps a given time range if this holds: (start <= trigger-time) AND (end > trigger-time) โฐ
A VALARM can also be set up to trigger repeatedly ๐ In that case, it overlaps the time range if at least one of its triggers overlaps the time range.
The calendar properties COMPLETED, CREATED, DTEND, DTSTAMP, DTSTART, DUE, and LAST-MODIFIED overlap a given time range if this holds: (start <= date-time) AND (end > date-time) ๐
Heads up, bestie: if DTEND is not present in a VEVENT but DURATION is, the test should instead use the 'effective' DTEND, which is DTSTART+DURATION. Same deal for a VTODO with no DUE but with DTSTART and DURATION: use the 'effective' DUE, which is DTSTART+DURATION ๐จ
The semantic of CALDAV:time-range is not defined for any other calendar components and properties, so don't go there ๐
Definition:
<!ELEMENT time-range EMPTY>
<!ATTLIST time-range start CDATA #IMPLIED
end CDATA #IMPLIED>
start value: an iCalendar "date with UTC time"
end value: an iCalendar "date with UTC time"
9.10. CALDAV:calendar-multiget XML Element ๐ธ
Name: calendar-multiget
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: CalDAV report used to retrieve specific calendar object resources.
Description: Literally just see Section 7.9. It's the same story, babe ๐
Definition:
<!ELEMENT calendar-multiget ((DAV:allprop |
DAV:propname |
DAV:prop)?, DAV:href+)>
9.11. CALDAV:free-busy-query XML Element ๐ฆ
Name: free-busy-query
Namespace: urn:ietf:params:xml:ns:caldav
Purpose: CalDAV report used to generate a VFREEBUSY to determine busy time over a specific time range ๐ซง
Description: See Section 7.10. Go check it out, it's giving full free-busy energy โจ
Definition:
<!ELEMENT free-busy-query (time-range)>
10. Internationalization Considerations ๐
okay so CalDAV lets you store and fetch internationalized strings for the description of calendar collections ๐โจ (see Section 5.2.1). so your calendar can be named and described in whatever language or script you want, periodt ๐
the CALDAV:calendar-query REPORT (Section 7.8) has a text searching option ๐ that's controlled by the CALDAV:text-match element, and the nitty gritty of how characters get handled lives in that element's description (see Section 9.7.5). go read it, it's giving detail ๐ง
11. Security Considerations ๐
okay this section is serious bestie, so listen up ๐ซถ HTTP transactions travel in the clear over the network unless you've negotiated protection from snooping. you can fix that with TLS, as defined in [RFC2818]. and especially: HTTP Basic authentication MUST NOT be used unless TLS is in effect ๐ซ๐ no plain Basic auth over open wifi, I'm begging you ๐ญ
servers MUST take adequate precautions so that malicious clients can't eat up excessive server resources (CPU, memory, disk, etc.) through carefully crafted reports ๐ like, imagine a client uploads an event with a recurrence rule saying it repeats every single second for the next 100 years. that's approximately 3 x 10^9 instances!!! ๐ฑ a report that asks for those recurrences to be expanded over that whole range would likely count as a denial-of-service attack on the server. not it ๐ โโ๏ธ
when clients create new resources (including calendar collections), they MUST make sure the resource name (the last path segment of the resource URI) doesn't expose any data from inside the iCalendar resource itself, or info about what kind of calendar collection it is ๐คซ this is required so that nobody can guess whether a specific iCalendar component, or what types of components, live in a collection just by reading the resource name. privacy main character energy ๐
when rolling up free-busy information, more info about a user's events gets exposed if busy periods overlap or are adjacent ๐ (this tells the client asking for the free-busy info that the calendar owner has at least two events, instead of only knowing that the owner has one or more events during the busy period). so a conservative approach to calendar data privacy would be for servers to always coalesce busy periods when they're the same type ๐ซง
procedure alarms are a known security risk for clients or servers to handle, especially when the alarm was created by another agent ๐จ clients and servers are not required to execute such procedure alarms. bye alarm ๐
security considerations described in iCalendar [RFC2445] and iTIP [RFC2446] also apply to CalDAV ๐ and beyond those, CalDAV doesn't raise any security considerations that aren't already present in HTTP [RFC2616] and WebDAV [RFC2518], [RFC3253], [RFC3744]. so no surprise plot twists, it's giving continuity ๐
12. IANA Considerations ๐
this document uses one new URN to identify a new XML namespace โจ and the URN follows a registry mechanism described in [RFC3688]. very organized, very iconic ๐
12.1. Namespace Registration
okay here's the registration request for the CalDAV namespace ๐ฆ
- URI:
urn:ietf:params:xml:ns:caldav - Registrant Contact: See the "Authors' Addresses" section of this document.
- XML: None. Namespace URIs do not represent an XML specification.
13. Acknowledgements ๐ซถ๐ธ
the authors want to thank these lovely people for contributing their ideas and support while writing this spec ๐ Michael Arick, Mario Bonin, Chris Bryant, Scott Carr, Andre Courtemanche, Mike Douglass, Ted Hardie, Marten den Haring, Jeffrey Harris, Sam Hartman, Helge Hess, Jeff McCullough, Alexey Melnikov, Dan Mosedale, Brian Moseley, Francois Perrault, Kervin L. Pierre, Julian F. Reschke, Wilfredo Sanchez Vega, Mike Shaver, Jari Urpalainen, Simon Vaillancourt, and Jim Whitehead. the big squad ๐ฅน
the authors would also like to thank the Calendaring and Scheduling Consortium for advice on this spec, and for organizing interoperability testing events that helped refine it ๐๐ง
14. References ๐
14.1. Normative References
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
- [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.
- [RFC2445] Dawson, F. and Stenerson, D., "Internet Calendaring and Scheduling Core Object Specification (iCalendar)", RFC 2445, November 1998.
- [RFC2446] Silverberg, S., Mansour, S., Dawson, F., and R. Hopson, "iCalendar Transport-Independent Interoperability Protocol (iTIP) Scheduling Events, BusyTime, To-dos and Journal Entries", RFC 2446, November 1998.
- [RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D. Jensen, "HTTP Extensions for Distributed Authoring -- WEBDAV", RFC 2518, February 1999.
- [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.
- [RFC2818] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.
- [RFC3253] Clemm, G., Amsden, J., Ellison, T., Kaler, C., and J. Whitehead, "Versioning Extensions to WebDAV (Web Distributed Authoring and Versioning)", RFC 3253, March 2002.
- [RFC3688] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.
- [RFC3744] Clemm, G., Reschke, J., Sedlar, E., and J. Whitehead, "Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol", RFC 3744, May 2004.
- [RFC4346] Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.1", RFC 4346, April 2006.
- [RFC4790] Newman, C., Duerst, M., and A. Gulbrandsen, "Internet Application Protocol Collation Registry", RFC 4790, March 2007.
- [W3C.REC-xml-20060816] Paoli, J., Maler, E., Yergeau, F., Sperberg-McQueen, C., and T. Bray, "Extensible Markup Language (XML) 1.0 (Fourth Edition)", World Wide Web Consortium Recommendation REC-xml-20060816, August 2006,
http://www.w3.org/TR/2006/REC-xml-20060816.
14.2. Informative References
- [RFC2426] Dawson, F. and T. Howes, "vCard MIME Directory Profile", RFC 2426, September 1998.
- [RFC2739] Small, T., Hennessy, D., and F. Dawson, "Calendar Attributes for vCard and LDAP", RFC 2739, January 2000.
- [RFC4331] Korver, B. and L. Dusseault, "Quota and Size Properties for Distributed Authoring and Versioning (DAV) Collections", RFC 4331, February 2006.
- [RFC4511] Sermersheim, J., "Lightweight Directory Access Protocol (LDAP): The Protocol", RFC 4511, June 2006.
- [rfc2518bis] Dusseault, L., "HTTP Extensions for Distributed Authoring - WebDAV", Work in Progress, December 2006.
Appendix A. CalDAV Method Privilege Table (Normative) ๐
the table below extends the WebDAV Method Privilege Table from Appendix B of [RFC3744] ๐ท it's normative, so it's not optional vibes ๐ซก
+------------+------------------------------------------------------+
| METHOD | PRIVILEGES |
+------------+------------------------------------------------------+
| MKCALENDAR | DAV:bind |
| REPORT | DAV:read or CALDAV:read-free-busy (on all referenced |
| | resources) |
+------------+------------------------------------------------------+
Appendix B. Calendar Collections Used in the Examples โจ
okay so this appendix is the big reveal ๐ it shows the actual calendar object resources sitting inside the calendar collection that every example in this document has been querying. bestie, it's giving receipts ๐
the collection is shown as if it came back from a CALDAV:calendar-query REPORT that asks for everything in the collection. so we get the request first, then the response, and the response is a whole pile of 207 Multi-Status goodness ๐ฆ
Request <<
REPORT /bernard/work/ HTTP/1.1
Host: cal.example.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR"/>
</C:filter>
</C:calendar-query>
Response <<
HTTP/1.1 207 Multi-Status
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd1.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd1"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20060206T001102Z
DTSTART;TZID=US/Eastern:20060102T100000
DURATION:PT1H
SUMMARY:Event #1
Description:Go Steelers!
UID:74855313FA803DA593CD579A@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd2"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART;TZID=US/Eastern:20060102T120000
DURATION:PT1H
RRULE:FREQ=DAILY;COUNT=5
SUMMARY:Event #2
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20060206T001121Z
DTSTART;TZID=US/Eastern:20060104T140000
DURATION:PT1H
RECURRENCE-ID;TZID=US/Eastern:20060104T120000
SUMMARY:Event #2 bis
UID:00959BC664CA650E933C892C@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd3"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
DTSTART;TZID=US/Eastern:20060104T100000
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd4.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd4"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
DTSTAMP:20060205T235335Z
DUE;VALUE=DATE:20060104
STATUS:NEEDS-ACTION
SUMMARY:Task #1
UID:DDDEEB7915FA61233B861457@example.com
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
END:VALARM
END:VTODO
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd5.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd5"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
DTSTAMP:20060205T235300Z
DUE;VALUE=DATE:20060106
LAST-MODIFIED:20060205T235308Z
SEQUENCE:1
STATUS:NEEDS-ACTION
SUMMARY:Task #2
UID:E10BA47467C5C69BB74E8720@example.com
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
END:VALARM
END:VTODO
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd6.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd6"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
COMPLETED:20051223T122322Z
DTSTAMP:20060205T235400Z
DUE;VALUE=DATE:20051225
LAST-MODIFIED:20060205T235308Z
SEQUENCE:1
STATUS:COMPLETED
SUMMARY:Task #3
UID:E10BA47467C5C69BB74E8722@example.com
END:VTODO
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd7.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd7"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTODO
DTSTAMP:20060205T235600Z
DUE;VALUE=DATE:20060101
LAST-MODIFIED:20060205T235308Z
SEQUENCE:1
STATUS:CANCELLED
SUMMARY:Task #4
UID:E10BA47467C5C69BB74E8725@example.com
END:VTODO
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://cal.example.com/bernard/work/abcd8.ics</D:href>
<D:propstat>
<D:prop>
<D:getetag>"fffff-abcd8"</D:getetag>
<C:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VFREEBUSY
ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
UID:76ef34-54a3d2@example.com
DTSTAMP:20050530T123421Z
DTSTART:20060101T000000Z
DTEND:20060108T000000Z
FREEBUSY:20050531T230000Z/20050601T010000Z
FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
FREEBUSY:20060103T100000Z/20060103T120000Z
FREEBUSY:20060104T100000Z/20060104T120000Z
FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20060105T100000Z/20060105T120000Z
FREEBUSY:20060106T100000Z/20060106T120000Z
END:VFREEBUSY
END:VCALENDAR
</C:calendar-data>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
Authors' Addresses ๐ง
Cyrus Daboo ๐ Apple Inc. 1 Infinite Loop Cupertino, CA 95014 USA
EMail: cyrus@daboo.name URI: http://www.apple.com/
Bernard Desruisseaux ๐ธ Oracle Corporation 600 Blvd. de Maisonneuve West Suite 1900 Montreal, QC H3A 3J2 CANADA
EMail: bernard.desruisseaux@oracle.com URI: http://www.oracle.com/
Lisa Dusseault ๐ CommerceNet 169 University Ave. Palo Alto, CA 94301 USA
EMail: ldusseault@commerce.net URI: http://commerce.net/
Full Copyright Statement ๐
Copyright (C) The IETF Trust (2007).
This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.
This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property ๐ฅ
The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79.
Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.
The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.
Acknowledgement ๐
Funding for the RFC Editor function is currently provided by the Internet Society.
๐ฆ where this page comes from
- ietf: rfc4791 2007-03
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms