RFC 5546
iCalendar Transport-Independent Interoperability Protocol (iTIP)
RFC 5546: iCalendar Transport-Independent Interoperability Protocol (iTIP) ๐
Okay bestie, let's do the paperwork first ๐ This is RFC 5546, the iCalendar Transport-Independent Interoperability Protocol (iTIP), from the Network Working Group. It's a Standards Track doc dated December 2009, written by C. Daboo, Ed. at Apple Inc. It obsoletes RFC 2446 and updates RFC 5545 ๐ฆ
Abstract โจ
Okay so this doc is a protocol that uses the iCalendar object spec to get scheduling to work between different calendar systems ๐ The best part is that it doesn't name one specific transport, so systems can talk to each other in lots of different ways ๐ Future docs will create profiles that pick specific, interoperable ways to communicate, so this one is kind of the foundation ๐งฑ
iTIP basically adds the group scheduling stuff that calendar apps already do, like publishing, scheduling, rescheduling, replying to scheduling requests, negotiating changes, and canceling ๐ It's giving "everyone's calendar, in sync, no drama" ๐
Status of This Memo ๐ธ
This doc is an Internet standards track protocol for the Internet community, and it's asking people to discuss it and suggest improvements ๐ซถ For the current standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1) ๐ Distribution of this memo is unlimited, so share it with everyone ๐ง
Copyright Notice ๐ฅ
Copyright (c) 2009 IETF Trust and the persons identified as the document authors. All rights reserved. ๐
Ngl, this part is a little legal-y, but it's important ๐ญ This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they were in effect on the date this document was published. Please read these documents carefully, because they explain your rights and restrictions for this document ๐ Code Components pulled out of this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come with no warranty, just like the BSD License says โ ๏ธ
Heads up: some of this document may include material from IETF Documents or IETF Contributions that were published or made publicly available before November 10, 2008. The people who control the copyright in some of that material may not have given the IETF Trust permission to allow modifications outside the IETF Standards Process. Unless you get an adequate license from those copyright holders, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process. The exceptions are formatting it for publication as an RFC or translating it into languages other than English ๐
Table of Contents ๐
1. Introduction and Overview .......................................5
1.1. Formatting Conventions .....................................5
1.2. Related Documents ..........................................6
1.3. Roles ......................................................6
1.4. Methods ....................................................7
2. Interoperability Models .........................................9
2.1. Application Protocol ......................................10
2.1.1. Scheduling State ...................................10
2.1.2. Delegation .........................................10
2.1.3. Acting on Behalf of Other Calendar Users ...........11
2.1.4. Component Revisions ................................11
2.1.5. Message Sequencing .................................12
3. Application Protocol Elements ..................................13
3.1. Common Component Restriction Tables .......................15
3.1.1. VCALENDAR ..........................................15
3.1.2. VTIMEZONE ..........................................15
3.1.3. VALARM .............................................17
3.2. Methods for VEVENT Calendar Components ....................17
3.2.1. PUBLISH ............................................18
3.2.2. REQUEST ............................................20
3.2.3. REPLY ..............................................25
3.2.4. ADD ................................................27
3.2.5. CANCEL .............................................29
3.2.6. REFRESH ............................................31
3.2.7. COUNTER ............................................33
3.2.8. DECLINECOUNTER .....................................35
3.3. Methods for VFREEBUSY Components ..........................37
3.3.1. PUBLISH ............................................37
3.3.2. REQUEST ............................................40
3.3.3. REPLY ..............................................42
3.4. Methods for VTODO Components ..............................44
3.4.1. PUBLISH ............................................44
3.4.2. REQUEST ............................................46
3.4.3. REPLY ..............................................51
3.4.4. ADD ................................................53
3.4.5. CANCEL .............................................55
3.4.6. REFRESH ............................................57
3.4.7. COUNTER ............................................59
3.4.8. DECLINECOUNTER .....................................61
3.5. Methods for VJOURNAL Components ...........................62
3.5.1. PUBLISH ............................................63
3.5.2. ADD ................................................64
3.5.3. CANCEL .............................................66
3.6. Status Replies ............................................68
3.7. Implementation Considerations .............................77
3.7.1. Working With Recurrence Instances ..................77
3.7.2. Attendee Property Considerations ...................78
3.7.3. Extension Tokens ...................................79
4. Examples .......................................................79
4.1. Published Event Examples ..................................79
4.1.1. A Minimal Published Event ..........................80
4.1.2. Changing a Published Event .........................80
4.1.3. Canceling a Published Event ........................81
4.1.4. A Rich Published Event .............................81
4.1.5. Anniversaries or Events Attached to Entire Days ....83
4.2. Group Event Examples ......................................83
4.2.1. A Group Event Request ..............................84
4.2.2. Reply to a Group Event Request .....................85
4.2.3. Update an Event ....................................85
4.2.4. Countering an Event Proposal .......................86
4.2.5. Delegating an Event ................................88
4.2.6. Delegate Accepts the Meeting .......................90
4.2.7. Delegate Declines the Meeting ......................91
4.2.8. Forwarding an Event Request ........................92
4.2.9. Cancel a Group Event ...............................92
4.2.10. Removing Attendees ................................93
4.2.11. Replacing the Organizer ...........................95
4.3. Busy Time Examples ........................................96
4.3.1. Publish Busy Time ..................................96
4.3.2. Request Busy Time ..................................96
4.3.3. Reply to a Busy Time Request .......................97
4.4. Recurring Event and Time Zone Examples ....................98
4.4.1. A Recurring Event Spanning Time Zones ..............98
4.4.2. Modify a Recurring Instance ........................99
4.4.3. Cancel an Instance ................................101
4.4.4. Cancel a Recurring Event ..........................101
4.4.5. Change All Future Instances .......................102
4.4.6. Add a New Instance to a Recurring Event ...........102
4.4.7. Add a New Series of Instances to a
Recurring Event ...................................103
4.4.8. Refreshing a Recurring Event ......................104
4.4.9. Counter an Instance of a Recurring Event ..........106
4.4.10. Error Reply to a Request .........................107
4.5. Group To-Do Examples .....................................108
4.5.1. A VTODO Request ...................................109
4.5.2. A VTODO Reply .....................................110
4.5.3. A VTODO Request for Updated Status ................110
4.5.4. A Reply: Percent-Complete .........................111
4.5.5. A Reply: Completed ................................111
4.5.6. An Updated VTODO Request ..........................112
4.5.7. Recurring VTODOs ..................................112
4.6. Journal Examples .........................................113
4.7. Other Examples ...........................................114
4.7.1. Event Refresh .....................................114
4.7.2. Bad RECURRENCE-ID .................................114
5. Application Protocol Fallbacks ................................116
5.1. Partial Implementation ...................................116
5.1.1. Event-Related Fallbacks ...........................117
5.1.2. Free/Busy-Related Fallbacks .......................119
5.1.3. To-Do-Related Fallbacks ...........................120
5.1.4. Journal-Related Fallbacks .........................122
5.2. Latency Issues ...........................................123
5.2.1. Cancellation of an Unknown Calendar Component .....123
5.2.2. Unexpected Reply from an Unknown Delegate .........124
5.3. Sequence Number ..........................................124
6. Security Considerations .......................................124
6.1. Security Threats .........................................124
6.1.1. Spoofing the Organizer ............................124
6.1.2. Spoofing the Attendee .............................124
6.1.3. Unauthorized Replacement of the Organizer .........125
6.1.4. Eavesdropping and Data Integrity ..................125
6.1.5. Flooding a Calendar ...............................125
6.1.6. Unauthorized REFRESH Requests .....................125
6.2. Recommendations ..........................................125
6.2.1. Securing iTIP transactions ........................125
6.2.2. Implementation Controls ...........................126
6.2.3. Access Controls and Filtering .....................126
6.3. Privacy Issues ...........................................126
7. IANA Considerations ...........................................127
7.1. Registration Template for REQUEST-STATUS Values ..........127
7.2. Additions to iCalendar METHOD Registry ...................127
7.3. REQUEST-STATUS Value Registry ............................129
8. Acknowledgments ...............................................130
9. References ....................................................131
9.1. Normative References .....................................131
9.2. Informative References ...................................131
Appendix A. Differences from RFC 2446 ...........................132
A.1. Changed Restrictions .....................................132
A.2. Deprecated Features ......................................133
1. Introduction and Overview โจ
okay so this doc is all about how calendaring systems use iCalendar [RFC5545] objects to talk to each other ๐ like, scheduling events, to-dos, or daily journal entries, and also searching for when people are actually free (aka busy time info) ๐ It does all this in a super general way, so it never says how the messages actually get sent between systems. Future docs will handle the transport bindings, bestie ๐
basically it's all message-based: an originator sends stuff to one or more recipients ๐ For some message types, a recipient can reply to update their status, and can also send back transaction/request status info โจ The originator can modify or cancel the original message (main character energy ๐), and recipients can suggest changes to the originator too ๐ซถ The protocol also defines the user roles for its transactions ๐
and yes, this one obsoletes RFC 2446 ๐ฆ so there's a whole list of big changes in Appendix A. go check it, it's giving receipts ๐
1.1. Formatting Conventions
Okay bestie, let's talk about the vocabulary first ๐ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. Totally essential, no cap ๐
Roles get quoted strings with a capital first letter on each word. So "Organizer" is a role of a "Calendar User" (CU) inside the scheduling protocol. Iconic โจ
Calendar components from [RFC5545] also live in capitalized quoted strings, and they all start with the letter "V" ๐ฆ So VEVENT is the event component, VTODO is the to-do component, and VJOURNAL is the daily journal component. Very organized, very cute.
Scheduling methods get the same treatment. REQUEST is the method for asking that a scheduling calendar component get created or modified ๐ฉ And REPLY is the method a recipient uses to update their status with the "Organizer" of that component. Literally the group chat of calendars ๐ซถ
Properties from [RFC5545] are capitalized quoted strings followed by the word "property". So the ATTENDEE property is the iCalendar property used to convey the calendar address of a "Calendar User" ๐
Property parameters defined by this spec follow the same pattern, but with the word "parameter" at the end. The VALUE parameter is the iCalendar property parameter that overrides the default data type for a property value ๐ง
Enumerated values defined here are capitalized text, either on their own or followed by the word "value" ๐ธ
And in tables, the quoted-string text drops its quotes so the table doesn't get huge ๐
1.2. Related Documents
Implementers need to be familiar with a few other specifications too. Together with this one, they describe the Internet calendaring and scheduling standards ๐ The related documents are:
- [RFC5545] specifies the objects, data types, properties, and property parameters used in the protocols, along with the methods for representing and encoding them.
- [iMIP] specifies an Internet email binding for iTIP.
This specification doesn't try to repeat the concepts or definitions from those other specs. Where possible, it just points straight at them with explicit references ๐
1.3. Roles
Exchanges of iCalendar objects for group calendaring and scheduling happen between "Calendar Users" (CUs). CUs can take on several roles in iTIP, and here's the breakdown ๐
+-----------+-------------------------------------------------------+
| Role | Description |
+-----------+-------------------------------------------------------+
| Organizer | The CU who initiates an exchange takes on the role of |
| | Organizer. For example, the CU who proposes a group |
| | meeting is the Organizer. |
| | |
| Attendee | CUs who are included in the scheduling message as |
| | possible recipients of that scheduling message. For |
| | example, the CUs asked to participate in a group |
| | meeting by the Organizer take on the role of |
| | Attendee. |
| | |
| Other CU | A CU that is not explicitly included in a scheduling |
| | message, i.e., not the Organizer or an Attendee. |
+-----------+-------------------------------------------------------+
Now, a tiny plot twist ๐ ROLE is also a descriptive parameter on the iCalendar ATTENDEE property. It's used to describe an "Attendee" with things like "chair", "required participant", or "non-required participant". It has absolutely nothing to do with the calendaring workflow, so don't mix them up, bestie ๐
1.4. Methods
Here are the iTIP methods. Their usage and semantics are defined in Section 3 of this document ๐
+----------------+--------------------------------------------------+
| Method | Description |
+----------------+--------------------------------------------------+
| PUBLISH | Used to publish an iCalendar object to one or |
| | more "Calendar Users". There is no |
| | interactivity between the publisher and any |
| | other "Calendar User". An example might include |
| | a baseball team publishing its schedule to the |
| | public. |
| | |
| REQUEST | Used to schedule an iCalendar object with other |
| | "Calendar Users". Requests are interactive in |
| | that they require the receiver to respond using |
| | the reply methods. Meeting requests, busy-time |
| | requests, and the assignment of tasks to other |
| | "Calendar Users" are all examples. Requests are |
| | also used by the Organizer to update the status |
| | of an iCalendar object. |
| | |
| REPLY | A reply is used in response to a request to |
| | convey Attendee status to the Organizer. |
| | Replies are commonly used to respond to meeting |
| | and task requests. |
| | |
| ADD | Add one or more new instances to an existing |
| | recurring iCalendar object. |
| | |
| CANCEL | Cancel one or more instances of an existing |
| | iCalendar object. |
| | |
| REFRESH | Used by an Attendee to request the latest |
| | version of an iCalendar object. |
| | |
| COUNTER | Used by an Attendee to negotiate a change in an |
| | iCalendar object. Examples include the request |
| | to change a proposed event time or change the |
| | due date for a task. |
| | |
| DECLINECOUNTER | Used by the Organizer to decline the proposed |
| | counter proposal. |
+----------------+--------------------------------------------------+
Group scheduling in iTIP happens through the "request" and "response" methods above. This next table shows which methods each originator can send ๐
+------------+------------------------------------------------------+
| Originator | Methods |
+------------+------------------------------------------------------+
| Organizer | PUBLISH, REQUEST, ADD, CANCEL, DECLINECOUNTER |
| | |
| Attendee | REPLY, REFRESH, COUNTER, REQUEST (only when |
| | delegating) |
+------------+------------------------------------------------------+
One more thing. For some calendar component types, the allowed methods are a subset of the set above ๐ฆ Also, apart from "VTIMEZONE" iCalendar components, only one component type is allowed in a single iTIP message. Keep it to one component type, bestie ๐
2. Interoperability Models
There are two distinct protocols that matter for interoperability: an "application protocol" and a "transport protocol" ๐ธ The application protocol defines the content of the iCalendar objects sent between sender and receiver to carry out the scheduling transactions listed above. The transport protocol defines how those iCalendar objects actually get sent between the two. This document focuses on the application protocol, and binding documents such as [iMIP] focus on the transport protocol.
The connection between sender and receiver in the diagram below refers to the application protocol. The iCalendar objects passed from sender to receiver are covered in Section 3, "Application Protocol Elements" โจ
+----------+ +----------+
| | iTIP | |
| Sender |<-------------->| Receiver |
| | | |
+----------+ +----------+
Sender and receiver can take on various roles of a "Calendar User Agent" (CUA) or a "Calendar Service" (CS) in several variations of this diagram ๐ง
Here's the iTIP architecture. An application written to this specification may work with bindings for the store-and-forward transport, the real-time transport, or both. iTIP could also be bound to other transports too ๐
+--------------------------------------------------------+
| iTIP Protocol |
+--------------------------------------------------------+
| Transport |
+ - - - - - + - - - - - - + - - - - - +
| Real-Time | Store-and-Forward | Others |
+-----------------+--------------------+-----------------+
2.1. Application Protocol
In the iTIP model, an "Organizer" creates and manages an iCalendar object ๐ The "Organizer" talks to other CUs by sending one or more of the iTIP messages listed above. "Attendees" use the "REPLY" method to share their status.
Here's the spicy bit: "Attendees" never make direct changes to the master iCalendar object ๐ โโ๏ธ They can use the "COUNTER" method to suggest changes to the "Organizer," but in every case, the "Organizer" has complete control over the master iCalendar object. Main character energy, but make it organizer ๐
2.1.1. Scheduling State
There are two separate states that matter for iCalendar objects used in scheduling. One is the overall state of the iCalendar object, and the other is the state of each "Attendee" in that object ๐ฆ
The state of an iCalendar object is defined by the STATUS property, and the "Organizer" controls it. There's no default value for STATUS, so the "Organizer" sets it to the right value for each iCalendar object ๐
The state of a particular "Attendee" for an iCalendar object used in scheduling is defined by the PARTSTAT parameter on that "Attendee's" ATTENDEE property. When an "Organizer" issues the first iCalendar object, the "Attendee's" status is usually unknown ๐ซถ So the "Organizer" marks it by setting PARTSTAT to NEEDS-ACTION. Then each "Attendee" updates their ATTENDEE property's PARTSTAT parameter to an appropriate value as part of a REPLY message sent back to the "Organizer" ๐
2.1.2. Delegation ๐
Okay so delegation is when an "Attendee" hands the right to attend over to another CU (or a few of them!) so they can show up on the Attendee's behalf ๐ฆ The "Organizer" finds out because the delegating "Attendee" tells them directly. The step-by-step details live in the REQUEST method sections for each component, so go check those if you want the full tea ๐
2.1.3. Acting on Behalf of Other Calendar Users ๐ธ
In a lot of orgs, one person acts for someone else to organize and/or respond to meeting requests, and iTIP gives us two mechanisms to make that work ๐ซถ
First, the "Organizer" is treated as its own special entity, separate from the "Attendees". All responses from "Attendees" flow back to the "Organizer", so it's super easy to tell apart the "Calendar User" who's organizing a meeting from the "Calendar Users" who are actually attending ๐ iCalendar also gives each "Attendee" a descriptive role. For example, a role of chair can be given to one or more "Attendees". The "chair" and the "Organizer" may or may not be the same "Calendar User", and this lines up perfectly with the assistant situation, where someone manages the logistics for a person who chairs the meeting. Iconic ๐
Second, a SENT-BY parameter can be set on either the "Organizer" or "Attendee" properties. When it's there, it tells you the responding CU acted on behalf of the specified "Attendee" or "Organizer". Main character energy ๐
2.1.4. Component Revisions โจ
The SEQUENCE property is how the "Organizer" says "hey, this changed" ๐ฅ When the "Organizer" changes any of these properties, the sequence number MUST be incremented:
DTSTARTDTENDDURATIONDUERRULERDATEEXDATESTATUS
Okay, but changes to other properties MAY also require a bump in the sequence number ๐ The "Organizer" CUA MUST increment the sequence number whenever it changes properties in the calendar component that the "Organizer" thinks could jeopardize the participation status of the "Attendees". Like, if you move a meeting from one room to a totally different city, that could seriously mess with who's actually able to participate ๐
Depending on the METHOD, the SEQUENCE property MUST follow these rules in the context of iTIP:
- For the
PUBLISHandREQUESTmethods, theSEQUENCEproperty value is incremented according to the rules stated above. - The
SEQUENCEproperty value MUST be incremented each time the "Organizer" uses theADDorCANCELmethods. - The
SEQUENCEproperty value MUST NOT be incremented when usingREPLY,REFRESH,COUNTER,DECLINECOUNTER, or when sending a delegationREQUEST.
Sometimes the "Organizer" never hears back about the final revision they sent out ๐ญ In that case, they can send an update REQUEST with RSVP=TRUE set for all "Attendees" so they can collect the current responses ๐ง
Heads up: the SEQUENCE value in an "Attendee's" response might not always match the "Organizer's" revision. Implementations can choose to have the CUA tell the CU that the response is for an iCalendar object that's been revised, and then let the CU decide whether to accept it or not ๐
A change in sequence number does signal a big change to something already scheduled, but "Attendee" CUAs SHOULD NOT rely solely on it to spot a significant change ๐ โโ๏ธ Instead, CUAs SHOULD compare the old and new versions of the calendar components, figure out exactly what changed, and then decide (maybe based on "Calendar User" preferences) whether the user actually needs a heads-up about it ๐ซถ
2.1.5. Message Sequencing ๐ฆ
CUAs that handle the iTIP application protocol must often match up a component in their calendar store with a component that shows up in an iTIP message. For example, an event might get updated with a later revision of itself. So a CUA has to correlate the version of the event already in its store with the version sent in the iTIP message ๐ง On top of that, a bunch of things can make iTIP messages arrive out of order. An "Organizer" could get a reply to an earlier revision after already getting a reply to a later one. Chaos, honestly ๐
To keep interop smooth and handle messages that show up out of order, follow these rules:
- The primary key for referencing a particular iCalendar component is the
UIDproperty value. To reference an instance of a recurring component, the primary key is made up of theUIDand theRECURRENCE-IDproperties. - The secondary key for referencing a component is the
SEQUENCEproperty value. For components where theUIDandRECURRENCE-IDproperty values are the same, the component with the highest numeric value for theSEQUENCEproperty obsoletes all other revisions of the component with lower values. - "Attendees" send
REPLYmessages to the "Organizer". For replies where theUIDandRECURRENCE-IDproperty values are the same, the value of theSEQUENCEproperty tells you which revision of the component the "Attendee" is replying to. The reply with the highest numeric value for theSEQUENCEproperty obsoletes all other replies with lower values. - In situations where the
UID,RECURRENCE-ID, andSEQUENCEproperty values all match, theDTSTAMPproperty is the tie-breaker. The component with the latestDTSTAMPoverrides all others. Similarly, for "Attendee" responses where theUID,RECURRENCE-ID, andSEQUENCEproperty values match, the response with the latestDTSTAMPoverrides all others ๐
So CUAs need to persist these component properties to process iTIP messages correctly: UID, RECURRENCE-ID, SEQUENCE, and DTSTAMP. Also, for each ATTENDEE property of a component, "Organizer" CUAs need to persist the SEQUENCE and DTSTAMP values from the "Attendee's" last response. That way, if an earlier response from an "Attendee" shows up late (say, because of a transport delay), it can be discarded properly ๐๏ธโจ
3. Application Protocol Elements ๐
iTIP messages are text/calendar MIME entities that carry calendaring and scheduling information ๐
The particular type of iCalendar message is called the "method type". Each method type is identified by a METHOD property that's specified as part of the text/calendar content type. The table below shows the combinations of calendar components and method types that this specification supports ๐ธ
+----------------+--------+-------+----------+-----------+
| | VEVENT | VTODO | VJOURNAL | VFREEBUSY |
+----------------+--------+-------+----------+-----------+
| PUBLISH | Yes | Yes | Yes | Yes |
| REQUEST | Yes | Yes | No | Yes |
| REFRESH | Yes | Yes | No | No |
| CANCEL | Yes | Yes | Yes | No |
| ADD | Yes | Yes | Yes | No |
| REPLY | Yes | Yes | No | Yes |
| COUNTER | Yes | Yes | No | No |
| DECLINECOUNTER | Yes | Yes | No | No |
+----------------+--------+-------+----------+-----------+
Each method type is defined in terms of its associated components and properties. Some are required, some are optional, and some are excluded entirely. This document describes those restrictions with a simple "restriction table". The first column has the name of a component or property. Properties of the iCalendar object aren't indented, but properties of a component are ๐ซง The second column (the "Presence" column) says whether a component or property should be there and, if so, how many times it can show up. The third column has extra comments to help clarify things ๐
The presence column uses these values to say whether a property is required or optional, and how many times it can appear in the iCalendar object:
+----------------+--------------------------------------------------+
| Presence Value | Description |
+----------------+--------------------------------------------------+
| 1 | One instance MUST be present. |
| 1+ | At least one instance MUST be present. |
| 0 | Instances of this property MUST NOT be present. |
| 0+ | Multiple instances MAY be present. |
| 0 or 1 | Up to 1 instance of this property MAY be |
| | present. |
+----------------+--------------------------------------------------+
The tables also call out IANA-PROPERTY, X-PROPERTY, IANA-COMPONENT, and X-COMPONENT to show where registered and experimental property and component extensions can show up ๐ The tables don't lay out restrictions on property parameters, though. Those are defined in [RFC5545] ๐
3.1. Common Component Restriction Tables ๐ฆ
3.1.1. VCALENDAR ๐
This restriction table applies to properties of the iCalendar object, meaning the properties at the outermost scope ๐
+-----------------------------------------------------+
| Constraints for Properties in a VCALENDAR Component |
+-----------------------------------------------------+
+--------------------+----------+--------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+--------------------+
| CALSCALE | 0 or 1 | |
| PRODID | 1 | |
| VERSION | 1 | Value MUST be 2.0. |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
+--------------------+----------+--------------------+
3.1.2. VTIMEZONE ๐
okay so a VTIMEZONE component can be pointed at by other components through a TZID parameter on a DATETIME value type, which is giving organized ๐
. The table below sets the property restrictions for any VTIMEZONE component that shows up in an iTIP message. Read the Comment column closely, because it's where all the drama is ๐.
+--------------------------------------+
| Constraints for VTIMEZONE Components |
+--------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to timezone. |
| DAYLIGHT | 0+ | MUST be one or more of either |
| | | STANDARD or DAYLIGHT. |
| COMMENT | 0+ | |
| DTSTART | 1 | MUST be local time format. |
| RDATE | 0+ | |
| RRULE | 0 or 1 | |
| TZNAME | 0+ | |
| TZOFFSETFROM | 1 | |
| TZOFFSETTO | 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| LAST-MODIFIED | 0 or 1 | |
| STANDARD | 0+ | MUST be one or more of either |
| | | STANDARD or DAYLIGHT. |
| COMMENT | 0+ | |
| DTSTART | 1 | MUST be local time format. |
| RDATE | 0+ | If present, RRULE MUST NOT be |
| | | present. |
| RRULE | 0 or 1 | If present, RDATE MUST NOT be |
| | | present. |
| TZNAME | 0+ | |
| TZOFFSETFROM | 1 | |
| TZOFFSETTO | 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| TZID | 1 | |
| TZURL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
+--------------------+----------+-----------------------------------+
3.1.3. VALARM โฐ
the VALARM rules are next, and they apply to any VALARM component in an iTIP message ๐. The table below is the vibe check for alarms, so bookmark it ๐.
+-----------------------------------+
| Constraints for VALARM Components |
+-----------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| VALARM | 0+ | |
| ACTION | 1 | |
| ATTACH | 0+ | |
| ATTENDEE | 0+ | |
| DESCRIPTION | 0 or 1 | |
| DURATION | 0 or 1 | If present, REPEAT MUST be |
| | | present. |
| REPEAT | 0 or 1 | If present, DURATION MUST be |
| | | present. |
| SUMMARY | 0 or 1 | |
| TRIGGER | 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
+--------------------+----------+-----------------------------------+
3.2. Methods for VEVENT Calendar Components ๐
this section is where we get into the method types that work with the VEVENT calendar component ๐. Every method has its own table that spells out the property constraints that make it that method, so you always know what you're getting into ๐ง.
here's the full lineup of methods for VEVENT. Some are the main-character requests, some are the supporting cast, and each one has its own energy โจ.
+----------------+--------------------------------------------------+
| Method | Description |
+----------------+--------------------------------------------------+
| PUBLISH | Post notification of an event. Used primarily |
| | as a method of advertising the existence of an |
| | event. |
| | |
| REQUEST | Make a request for an event. This is an |
| | explicit invitation to one or more Attendees. |
| | Event requests are also used to update or change |
| | an existing event. Clients that cannot handle |
| | REQUEST MAY degrade the event to view it as a |
| | PUBLISH. |
| | |
| REPLY | Reply to an event request. Clients may set |
| | their status (PARTSTAT) to ACCEPTED, DECLINED, |
| | TENTATIVE, or DELEGATED. |
| | |
| ADD | Add one or more instances to an existing event. |
| | |
| CANCEL | Cancel one or more instances of an existing |
| | event. |
| | |
| REFRESH | A request is sent to an Organizer by an Attendee |
| | asking for the latest version of an event to be |
| | resent to the requester. |
| | |
| COUNTER | Counter a REQUEST with an alternative proposal. |
| | Sent by an Attendee to the Organizer. |
| | |
| DECLINECOUNTER | Decline a counter proposal. Sent to an Attendee |
| | by the Organizer. |
+----------------+--------------------------------------------------+
3.2.1. PUBLISH ๐
okay so the "PUBLISH" method in a "VEVENT" calendar component is basically an unsolicited posting of an iCalendar object ๐ฎโจ any CU is allowed to add published components to their calendar ๐ the "Organizer" MUST be present in a published iCalendar component, and "Attendees" MUST NOT be present ๐ its expected usage is encapsulating an arbitrary event as an iCalendar object ๐ฆ the "Organizer" may later update it (with another "PUBLISH" method), add instances to it (with an "ADD" method), or cancel it (with a "CANCEL" method) ๐ a previously published "VEVENT" calendar component is giving main character energy, no cap ๐
this method type is an iCalendar object that conforms to the following property constraints ๐ธ
+----------------------------------------------+
| Constraints for a METHOD:PUBLISH of a VEVENT |
+----------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST equal PUBLISH. |
| | | |
| VEVENT | 1+ | |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | |
| SUMMARY | 1 | Can be null. |
| UID | 1 | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| SEQUENCE | 0 or 1 | MUST be present if value is |
| | | greater than 0; MAY be present if |
| | | 0. |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0 or 1 | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null. |
| DTEND | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DTEND MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MAY be one of |
| | | TENTATIVE/CONFIRMED/CANCELLED. |
| TRANSP | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| ATTENDEE | 0 | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0+ | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VTODO | 0 | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
+--------------------+----------+-----------------------------------+
3.2.2. REQUEST ๐
the "REQUEST" method in a "VEVENT" component is the multitasker of the group chat ๐ง it provides these scheduling functions:
- Invite "Attendees" to an event. ๐
- Reschedule an existing event. ๐
- Response to a "REFRESH" request. ๐
- Update the details of an existing event, without rescheduling it. โ๏ธ
- Update the status of "Attendees" of an existing event, without rescheduling it. ๐
- Reconfirm an existing event, without rescheduling it. ๐ซถ
- Forward a "VEVENT" to another uninvited CU. ๐
- For an existing "VEVENT" calendar component, delegate the role of "Attendee" to another CU. ๐ฆ
- For an existing "VEVENT" calendar component, change the role of "Organizer" to another CU. ๐
the "Organizer" originates the "REQUEST" ๐ and the recipients are the CUs invited to the event, the "Attendees" ๐ "Attendees" use the "REPLY" method to convey attendance status to the "Organizer" ๐
the "UID" and "SEQUENCE" properties are how we tell the various uses of the "REQUEST" method apart ๐ฅ if the "UID" property value in the "REQUEST" is not found on the recipient's calendar, then the "REQUEST" is for a new "VEVENT" calendar component โจ if the "UID" property value is found on the recipient's calendar, then the "REQUEST" is for a rescheduling, an update, or a reconfirmation of the "VEVENT" calendar component ๐
for the "REQUEST" method, multiple "VEVENT" components in a single iCalendar object are only permitted for components with the same "UID" property ๐ซถ that's giving series energy: a series of recurring events may have instance-specific information, and in this case multiple "VEVENT" components are needed to express the entire series ๐ธ
this method type is an iCalendar object that conforms to the following property constraints ๐ง
+----------------------------------------------+
| Constraints for a METHOD:REQUEST of a VEVENT |
+----------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REQUEST. |
| | | |
| VEVENT | 1+ | All components MUST have the same |
| | | UID. |
| ATTENDEE | 1+ | |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 0 or 1 | MUST be present if value is |
| | | greater than 0; MAY be present if |
| | | 0. |
| SUMMARY | 1 | Can be null. |
| UID | 1 | |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null. |
| DTEND | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DTEND MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| REQUEST-STATUS | 0 | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MAY be one of |
| | | TENTATIVE/CONFIRMED. |
| TRANSP | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VTODO | 0 | |
+--------------------+----------+-----------------------------------+
3.2.2.1. Rescheduling an Event โจ
okay so REQUEST is the method you use when you wanna reschedule an event ๐๏ธ ๐
That means the time or recurrence intervals are changing, and maybe the location or description too. If the recipient CUA gets a REQUEST and the UID value already exists on their calendar, but the SEQUENCE (or DTSTAMP) property value in that REQUEST is greater than the value for the existing event, then the REQUEST is describing a reschedule. periodt ๐ญ
3.2.2.2. Updating or Reconfirmation of an Event ๐
REQUEST can also be used to update or reconfirm an event ๐ซถ An update is NOT a time or recurrence change. it might not even touch the location or description. If the recipient CUA finds the UID already on the calendar and the SEQUENCE in the REQUEST matches the existing event's value, then the REQUEST is updating the event details but not rescheduling it. lowkey my favourite small detail ๐ฆ
The update REQUEST is the right reply to a REFRESH method that an "Attendee" sends to the "Organizer" ๐ธ
The "Organizer" can also send unsolicited REQUEST methods whenever they want ๐ These can update the event details without rescheduling, update the PARTSTAT parameter of "Attendees", or reconfirm the event โจ
3.2.2.3. Delegating an Event to Another CU ๐ง
okay this one is so iconic ๐ญ some calendar systems let "Attendees" delegate their presence at an event to another "Calendar User", and iTIP supports that with the workflow below ๐
Any "Attendee" can delegate their right to take part in a calendar VEVENT to another CU. The delegate takes part in lieu of the original "Attendee", not in addition to them. The delegator MUST notify the "Organizer" of this action using the steps below ๐ซถ Implementations may support or restrict delegation as they see fit. For example, some implementations may stop a delegate from delegating a REQUEST to another CU ๐
The "Delegator" forwards the existing REQUEST to the "Delegate" ๐ฆ The REQUEST MUST include an ATTENDEE property with the calendar address of the "Delegate" โจ The "Delegator" MUST also send a REPLY method to the "Organizer" with the "Delegator's" ATTENDEE property PARTSTAT parameter value set to DELEGATED ๐ On top of that, the DELEGATED-TO parameter MUST be included with the calendar address of the "Delegate". And a new ATTENDEE property for the "Delegate" MUST be included too, and it must specify the calendar user address that's set in the DELEGATED-TO parameter, same as above ๐
In response to the request, the "Delegate" MUST send a REPLY method to the "Organizer", and optionally to the "Delegator" ๐ The REPLY SHOULD include the ATTENDEE property with the DELEGATED-FROM parameter value set to the "Delegator's" calendar address ๐
The "Delegator" may keep getting updates to the event even though they won't be attending ๐ They do this by setting their role attribute to NON-PARTICIPANT in the REPLY to the "Organizer" ๐ซถ
3.2.2.4. Changing the Organizer ๐ธ
sometimes the "Organizer" of a VEVENT can't do the job anymore and just bounces without handing the role to anyone else ๐ญ When that happens, the "Attendees" of the VEVENT may use out-of-band mechanisms to talk it through and agree on a new "Organizer" ๐ฌ The new "Organizer" should then send out a new REQUEST with a modified version of the VEVENT, where the SEQUENCE number has been incremented and the ORGANIZER property has been changed to the new "Organizer" โจ
3.2.2.5. Sending on Behalf of the Organizer ๐
there are a bunch of situations where a "Calendar User" needs to act for the "Organizer" without actually switching roles ๐ง Like, the CU who's the "Organizer" might be sick or just unable to do the organizer stuff ๐ค iTIP supports one CU acting on behalf of another, so using the SENT-BY parameter, a "Calendar User" could send an updated VEVENT REQUEST ๐ When one CU sends on behalf of another, the "Attendee" responses still go back to the CU that's designated as "Organizer" ๐ฆ
3.2.2.6. Forwarding to an Uninvited CU ๐
an "Attendee" who was invited to a VEVENT calendar component can forward it to a new CU that wasn't previously connected to it ๐ The current "Attendee" does this by forwarding the original REQUEST method to the new CU ๐ซถ The new CU can then send a REPLY to the "Organizer" of the VEVENT calendar component, and that reply includes an ATTENDEE property for the new CU ๐
The "Organizer" is the one who decides whether the new CU joins the event, and they're not obligated to do anything with a REPLY from a new (uninvited) CU ๐ If the "Organizer" doesn't want the new CU in the event, the new ATTENDEE property doesn't get added to the VEVENT calendar component ๐
The "Organizer" MAY send the CU a CANCEL message to say they won't be added to the event ๐ If the "Organizer" does decide to add the new CU, the new ATTENDEE property gets added to the VEVENT calendar component. The "Organizer" is also free to change any ATTENDEE property parameter from the values the new CU supplied to whatever the "Organizer" thinks is appropriate ๐
The "Organizer" SHOULD send the new CU a REQUEST message to let them know they've been added ๐ง
When an "Attendee" forwards a REQUEST to another CU, the forwarding "Attendee" MUST NOT make changes to the original message ๐
3.2.2.7. Updating Attendee Status ๐
the "Organizer" of an event can also ask one or more "Attendees" for an updated status ๐โโ๏ธ The "Organizer" sends a REQUEST method to the "Attendee" and sets the ATTENDEE;RSVP=TRUE property parameter. The SEQUENCE property for the event stays at its previous value. A recipient can tell that the only change in the REQUEST is their RSVP property parameter asking for an updated status ๐ฆ The recipient SHOULD respond with a REPLY method that shows their current status for the REQUEST โจ๐
3.2.3. REPLY โจ
okay so the "REPLY" method in a "VEVENT" calendar component is how you answer a "REQUEST" ๐ (like accepting or declining), and it's also how you reply to a delegation "REQUEST" ๐ฆ. when it's a delegation response, the "Delegator" SHOULD put the calendar address of the "Delegate" on the "DELEGATED-TO" property parameter of the "Delegator's" "ATTENDEE" property ๐. and the "Delegate" SHOULD put the calendar address of the "Delegator" on the "DELEGATED-FROM" property parameter of the "Delegate's" "ATTENDEE" property ๐ซถ
"REPLY" is also used when processing a "REQUEST" fails ๐. depending on what the "REQUEST-STATUS" property says, no scheduling action may have been performed, so check that first ๐ฅ
the "Organizer" can get a "REPLY" from a CU that wasn't in the original "REQUEST" ๐. for example, a "Delegate" might reply to an event. and sometimes a "REPLY" comes from a total stranger, aka a "Party Crasher" ๐. that uninvited "Attendee" can be accepted, or the "Organizer" can cancel the event for them by sending a "CANCEL" method to them. no drama, just vibes ๐
an "Attendee" MAY include a message to the "Organizer" using the "COMMENT" property ๐ธ. like, if someone is tentatively accepting and wants the "Organizer" to know why, that reason can go right in the "COMMENT" property value ๐
the "Organizer" may also get a "REPLY" from one CU on behalf of another ๐ง. just like the situation above, "Attendees" can have another CU respond for them. that's what the "SENT-BY" parameter is for โจ
the optional properties in the table below (the ones marked "0+" or "0 or 1") MUST NOT be changed from the original request ๐ซ if someone wants to change properties, the "COUNTER" message must be used ๐ฆ
this method type is an iCalendar object that follows these property constraints, so here's the full checklist ๐
+--------------------------------------------+
| Constraints for a METHOD:REPLY of a VEVENT |
+--------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REPLY. |
| | | |
| VEVENT | 1+ | All components MUST have the same |
| | | UID. |
| ATTENDEE | 1 | MUST be the address of the |
| | | Attendee replying. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| UID | 1 | MUST be the UID of the original |
| | | REQUEST. |
| SEQUENCE | 0 or 1 | If non-zero, MUST be the sequence |
| | | number of the original REQUEST. |
| | | MAY be present if 0. |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | |
| DTEND | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DTSTART | 0 or 1 | |
| DURATION | 0 or 1 | If present, DTEND MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| REQUEST-STATUS | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | |
| SUMMARY | 0 or 1 | |
| TRANSP | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0 or 1 | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VTODO | 0 | |
+--------------------+----------+-----------------------------------+
3.2.4. ADD โจ
okay so the ADD method is lowkey the cutest little shortcut ๐ฆ It lets the Organizer tack one or more brand new instances onto an existing VEVENT in a single iTIP message. No need to resend the whole event with every single existing instance inside it, which is what you'd have to do with REQUEST. Way less extra baggage, bestie ๐งณ๐
The UID has to be the one from the event that already exists ๐ If the UID in an ADD isn't on the recipient's calendar, the recipient SHOULD send a REFRESH to the Organizer so they can grab the newest version of the VEVENT ๐ And if an Attendee's implementation doesn't support ADD, it should reply with a REQUEST-STATUS value of 3.14 and ask for a REFRESH ๐ (not me being dramatic about it, that's just the vibe ๐)
When an Attendee handles an ADD message, they treat each component in it as if it were pointed to by an RDATE in the main component โจ So the new instances get slotted right in, no drama ๐
This method type is an iCalendar object that follows these property constraints ๐
+------------------------------------------+
| Constraints for a METHOD:ADD of a VEVENT |
+------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be ADD. |
| | | |
| VEVENT | 1 | |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 1 | MUST be greater than 0. |
| SUMMARY | 1 | Can be null. |
| UID | 1 | MUST match that of the original |
| | | event. |
| ATTACH | 0+ | |
| ATTENDEE | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null. |
| DTEND | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DTEND MUST NOT be |
| | | present. |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| STATUS | 0 or 1 | MAY be one of |
| | | TENTATIVE/CONFIRMED. |
| TRANSP | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| EXDATE | 0 | |
| RECURRENCE-ID | 0 | |
| REQUEST-STATUS | 0 | |
| RDATE | 0 | |
| RRULE | 0 | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VTODO | 0 | |
| | | |
| VJOURNAL | 0 | |
+--------------------+----------+-----------------------------------+
3.2.5. CANCEL ๐ซ๐
okay bestie, so the CANCEL method in a VEVENT calendar component is how the Organizer sends a cancellation notice for an event request that already exists, and it goes out to the Attendees who are affected ๐ซถ. The Organizer is the one who sends it, always. โจ
For a recurring event, you can cancel the whole thing or just some of the instances. ๐ To cancel the complete range, the UID property value for the event MUST be specified, and a RECURRENCE-ID MUST NOT be specified in the CANCEL method. ๐ If you want to cancel one single instance instead, the RECURRENCE-ID property value for the event MUST be specified in the CANCEL method. ๐ฆ
There are two ways to cancel a run of instances of a recurring VEVENT calendar component:
a. The RECURRENCE-ID property for an instance in the run MUST be specified with the RANGE property parameter value of THISANDFUTURE, which means cancelling the specified VEVENT calendar component and every instance after it. ๐
b. Individual recurrence instances can be cancelled by specifying multiple VEVENT components, each with a RECURRENCE-ID property matching one of the instances being cancelled. ๐งฉ
The Organizer MUST send a CANCEL message to each Attendee affected by the cancellation. ๐ฌ You can do this with one CANCEL message for everybody, or with several messages that each cover a different subset of the affected Attendees. ๐
When a VEVENT is cancelled, the SEQUENCE property value MUST be incremented as described in Section 2.1.4. ๐ขโจ
This method type is an iCalendar object that follows these property constraints:
+---------------------------------------------+
| Constraints for a METHOD:CANCEL of a VEVENT |
+---------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be CANCEL. |
| | | |
| VEVENT | 1+ | All must have the same UID. |
| ATTENDEE | 0+ | MUST include some or all |
| | | Attendees being removed from the |
| | | event. MUST include some or all |
| | | Attendees if the entire event is |
| | | cancelled. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 1 | |
| UID | 1 | MUST be the UID of the original |
| | | REQUEST. |
| COMMENT | 0+ | |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | |
| DTEND | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DTSTART | 0 or 1 | |
| DURATION | 0 or 1 | If present, DTEND MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MUST be set to CANCELLED to |
| | | cancel the entire event. If |
| | | uninviting specific Attendees, |
| | | then MUST NOT be included. |
| SUMMARY | 0 or 1 | |
| TRANSP | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VTODO | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.2.6. REFRESH ๐๐
so the REFRESH method in a VEVENT calendar component is how Attendees of an existing event ask the event Organizer for an updated description ๐. The REFRESH method must specify the UID property of the event being updated. ๐ If you want one recurrence instance, you can specify the RECURRENCE-ID property matching the associated event. ๐ฆ The Organizer replies with the latest description and version of the event. ๐จโจ
This method type is an iCalendar object that follows these property constraints:
+----------------------------------------------+
| Constraints for a METHOD:REFRESH of a VEVENT |
+----------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REFRESH. |
| | | |
| VEVENT | 1 | |
| ATTENDEE | 1 | MUST be the address of requester. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| UID | 1 | MUST be the UID associated with |
| | | original REQUEST. |
| COMMENT | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| ATTACH | 0 | |
| CATEGORIES | 0 | |
| CLASS | 0 | |
| CONTACT | 0 | |
| CREATED | 0 | |
| DESCRIPTION | 0 | |
| DTEND | 0 | |
| DTSTART | 0 | |
| DURATION | 0 | |
| EXDATE | 0 | |
| GEO | 0 | |
| LAST-MODIFIED | 0 | |
| LOCATION | 0 | |
| PRIORITY | 0 | |
| RDATE | 0 | |
| RELATED-TO | 0 | |
| REQUEST-STATUS | 0 | |
| RESOURCES | 0 | |
| RRULE | 0 | |
| SEQUENCE | 0 | |
| STATUS | 0 | |
| SUMMARY | 0 | |
| TRANSP | 0 | |
| URL | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0+ | |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VTODO | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.2.7. COUNTER โจ
okay so the "COUNTER" method for a "VEVENT" is how an "Attendee" of an existing event says "hmm, what if we did it this other way instead? ๐ซถ" They send it to the "Organizer" of that event. The counter proposal is its own iCalendar object, and its "VEVENT" has the complete description of the alternate event, not just the changes. ๐
The "Organizer" can say no by sending a "DECLINECOUNTER" method back to the "Attendee". Or they can say yes by rescheduling the event as described in Section 3.2.2.1, "Rescheduling an Event" ๐ The "Organizer's" CUA SHOULD send a "REQUEST" message to all "Attendees" affected by any change triggered by an accepted "COUNTER". It's giving "everyone stays in the loop" energy ๐ฆ
This method type is an iCalendar object that conforms to the following property constraints:
+----------------------------------------------+
| Constraints for a METHOD:COUNTER of a VEVENT |
+----------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be COUNTER. |
| | | |
| VEVENT | 1 | |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | MUST be the Organizer of the |
| | | original event. |
| SEQUENCE | 1 | MUST echo the original SEQUENCE |
| | | number. MUST be present if |
| | | non-zero. MAY be present if |
| | | zero. |
| SUMMARY | 1 | Can be null. |
| UID | 1 | MUST be the UID associated with |
| | | the REQUEST being countered. |
| ATTACH | 0+ | |
| ATTENDEE | 0+ | Can also be used to propose other |
| | | Attendees. |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | |
| DTEND | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DTEND MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| REQUEST-STATUS | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | Value must be one of |
| | | CONFIRMED/TENATIVE/CANCELLED. |
| TRANSP | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VTODO | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.2.8. DECLINECOUNTER ๐ โโ๏ธ
the "DECLINECOUNTER" method in a "VEVENT" is the "Organizer" politely saying "nope, not that one" ๐ It's how they reject a counter proposal some "Attendee" sent in. The "Organizer" must send the "DECLINECOUNTER" message to the "Attendee" that sent the "COUNTER" method to the "Organizer". Make sure it goes back to the right person, bestie ๐
This method type is an iCalendar object that conforms to the following property constraints:
+-----------------------------------------------------+
| Constraints for a METHOD:DECLINECOUNTER of a VEVENT |
+-----------------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be DECLINECOUNTER. |
| | | |
| VEVENT | 1+ | All components MUST have the same |
| | | UID. |
| ATTENDEE | 1+ | MUST for all Attendees. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 1 | MUST echo the original SEQUENCE |
| | | number. |
| UID | 1 | MUST echo original UID. |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null. |
| DTSTART | 0 or 1 | |
| DTEND | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DTEND MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| REQUEST-STATUS | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MAY be one of |
| | | TENTATIVE/CONFIRMED. |
| SUMMARY | 0 or 1 | Can be null. |
| TRANSP | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| | | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VALARM | 0 | |
| VFREEBUSY | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VTODO | 0 | |
+--------------------+----------+-----------------------------------+
3.3. Methods for VFREEBUSY Components โจ
okay so this section is where we get into the methods for the VFREEBUSY calendar component ๐
every method gets its own restriction table, which is basically a checklist of what's required, what's optional, and what's a total no-go ๐
first things first, this doc ONLY covers sharing busy time info ๐ฆ if an app wants free time info, it MUST infer that from the busy time it has. no shortcuts, bestie ๐ซถ
The FREEBUSY property value MAY include a list of values, separated by the COMMA character (US-ASCII decimal 44). Or, multiple busy time periods MAY be specified with multiple instances of the FREEBUSY property. Both forms MUST be supported by implementations conforming to this document. Duplicate busy time periods SHOULD NOT be specified in an iCalendar object ๐ however, two different busy time periods MAY overlap, so that's giving flexibility ๐
FREEBUSY properties SHOULD be sorted so their values are in ascending order, based on the start time and then the end time, with the earliest periods first ๐ for example, today's busy time should show up after yesterday's, and the busy time for this half-hour should come after the busy time for earlier today. busy time periods can also span a day boundary, which is so iconic โจ
here's the summary of the methods defined for the VFREEBUSY component ๐
+---------+-------------------------------------+
| Method | Description |
+---------+-------------------------------------+
| PUBLISH | Publish unsolicited busy time data. |
| | |
| REQUEST | Request busy time data. |
| | |
| REPLY | Reply to a busy time request. |
+---------+-------------------------------------+
3.3.1. PUBLISH
okay the PUBLISH method in a VFREEBUSY component is used to publish busy time data ๐ it can be sent from one CU to any other CU. the whole point is to send unsolicited busy time data, meaning it's NOT being sent as a reply to a REQUEST ๐
The ORGANIZER property MUST be specified in the busy time information. Its value is the CU address of the originator of the busy time information ๐
The busy time information inside the iCalendar object MAY be grouped into more than one VFREEBUSY component. this lets you group busy time periods by a common periodicity, like a calendar week, month, or year ๐ when you do that, each VFREEBUSY component MUST include the ORGANIZER, DTSTART, and DTEND properties, so it's clear where the busy time came from and what date and time interval it covers ๐ฅ
this method type is an iCalendar object that follows these property constraints ๐ธ
+-------------------------------------------------+
| Constraints for a METHOD:PUBLISH of a VFREEBUSY |
+-------------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be PUBLISH. |
| | | |
| VFREEBUSY | 1+ | |
| DTSTAMP | 1 | |
| DTSTART | 1 | DateTime values must be in UTC. |
| DTEND | 1 | DateTime values must be in UTC. |
| FREEBUSY | 0+ | MUST be BUSYTIME. Multiple |
| | | instances are allowed. Multiple |
| | | instances SHOULD be sorted in |
| | | ascending order. |
| ORGANIZER | 1 | MUST contain the address of |
| | | originator of busy time data. |
| UID | 1 | |
| COMMENT | 0+ | |
| CONTACT | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| URL | 0 or 1 | Specifies busy time URL. |
| ATTENDEE | 0 | |
| DURATION | 0 | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VTODO | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VTIMEZONE | 0 | |
+--------------------+----------+-----------------------------------+
3.3.2. REQUEST
okay the REQUEST method in a VFREEBUSY component is used to ask a "Calendar User" for their busy time info ๐โโ๏ธ the request can be for busy time bounded by a specific date and time interval โญ
this message ONLY allows requests for busy time info ๐ it's sent from a "Calendar User" asking for the busy time of one or more intended recipients ๐ง
if the originator of the REQUEST method is NOT authorized to make a busy time request on the recipient's calendar system, then an exception message SHOULD be returned in a REPLY method. no busy time data needs to come back though ๐
ngl this is the part where the vibes get a little strict: no auth, no busy time, just an exception message ๐ฅ
this method type is an iCalendar object that follows these property constraints ๐
+-------------------------------------------------+
| Constraints for a METHOD:REQUEST of a VFREEBUSY |
+-------------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REQUEST. |
| | | |
| VFREEBUSY | 1 | |
| ATTENDEE | 1+ | Contains the calendar user |
| | | addresses of the "Calendar Users" |
| | | whose freebusy is being |
| | | requested. |
| DTEND | 1 | DateTime values must be in UTC. |
| DTSTAMP | 1 | |
| DTSTART | 1 | DateTime values must be in UTC. |
| ORGANIZER | 1 | MUST be the request originator's |
| | | address. |
| UID | 1 | |
| COMMENT | 0+ | |
| CONTACT | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| FREEBUSY | 0 | |
| DURATION | 0 | |
| REQUEST-STATUS | 0 | |
| URL | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VTODO | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VTIMEZONE | 0 | |
+--------------------+----------+-----------------------------------+
3.3.3. REPLY ๐
okay bestie, so the REPLY method in a VFREEBUSY calendar component is how you answer a busy time request ๐ซถ It goes from the person who got the request back to whoever sent it. โจ
REPLY can also be used to answer a REQUEST that didn't work out ๐ Depending on the REQUEST-STATUS value, there might not be any busy time info in there at all, so don't be shocked if it's empty ๐
This method type is an iCalendar object, and it follows these property constraints ๐
+-----------------------------------------------+
| Constraints for a METHOD:REPLY of a VFREEBUSY |
+-----------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REPLY. |
| | | |
| VFREEBUSY | 1 | |
| ATTENDEE | 1 | MUST be the address of the |
| | | Attendee replying. |
| DTSTAMP | 1 | |
| DTEND | 1 | DateTime values must be in UTC. |
| DTSTART | 1 | DateTime values must be in UTC. |
| FREEBUSY | 0+ | MUST be BUSYTIME. Multiple |
| | | instances are allowed. Multiple |
| | | instances SHOULD be sorted in |
| | | ascending order. |
| ORGANIZER | 1 | MUST be the request originator's |
| | | address. |
| UID | 1 | MUST be the UID of the original |
| | | REQUEST. |
| COMMENT | 0+ | |
| CONTACT | 0 or 1 | |
| REQUEST-STATUS | 0+ | |
| URL | 0 or 1 | Specifies busy time URL. |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| DURATION | 0 | |
| SEQUENCE | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VTODO | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VTIMEZONE | 0 | |
+--------------------+----------+-----------------------------------+
3.4. Methods for VTODO Components ๐ธ
this section is all about the methods that work with the VTODO calendar component ๐ Each method gets its own restriction table that spells out the property constraints that define it, so you always know exactly what's expected โจ
Here's the quick summary of every method defined for VTODO ๐
+----------------+--------------------------------------------------+
| Method | Description |
+----------------+--------------------------------------------------+
| PUBLISH | Post notification of a VTODO. Used primarily as |
| | a method of advertising the existence of a |
| | VTODO. |
| | |
| REQUEST | Assign a VTODO. This is an explicit assignment |
| | to one or more Calendar Users. The REQUEST |
| | method is also used to update or change an |
| | existing VTODO. Clients that cannot handle |
| | REQUEST MAY degrade the method to treat it as a |
| | PUBLISH. |
| | |
| REPLY | Reply to a VTODO request. Attendees MAY set |
| | PARTSTAT to ACCEPTED, DECLINED, TENTATIVE, |
| | DELEGATED, PARTIAL, and COMPLETED. |
| | |
| ADD | Add one or more instances to an existing to-do. |
| | |
| CANCEL | Cancel one or more instances of an existing |
| | to-do. |
| | |
| REFRESH | A request sent to a VTODO Organizer asking for |
| | the latest version of a VTODO. |
| | |
| COUNTER | Counter a REQUEST with an alternative proposal. |
| | |
| DECLINECOUNTER | Decline a counter proposal by an Attendee. |
+----------------+--------------------------------------------------+
3.4.1. PUBLISH ๐ฃ
the PUBLISH method in a VTODO calendar component doesn't have any response attached ๐
โโ๏ธ It's basically just posting an iCalendar object that people can add to their calendar ๐ It MUST have an "Organizer". It MUST NOT have "Attendees" ๐ซ The main idea is to wrap up an arbitrary VTODO calendar component as an iCalendar object ๐ After that, the Organizer MAY update the published VTODO with another PUBLISH method, add instances with an ADD method, or cancel it with a CANCEL method ๐ฆ
This method type is an iCalendar object, and it follows these property constraints ๐
+---------------------------------------------+
| Constraints for a METHOD:PUBLISH of a VTODO |
+---------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be PUBLISH. |
| | | |
| VTODO | 1+ | |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | |
| PRIORITY | 1 | |
| SEQUENCE | 0 or 1 | MUST be present if value is |
| | | greater than 0; MAY be present if |
| | | 0. |
| SUMMARY | 1 | Can be null. |
| UID | 1 | |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| COMPLETED | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null. |
| DUE | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DUE MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PERCENT-COMPLETE | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MAY be one of |
| | | COMPLETED/NEEDS-ACTION/ |
| | | IN-PROCESS/CANCELLED. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| ATTENDEE | 0 | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VEVENT | 0 | |
| | | |
| VJOURNAL | 0 | |
+--------------------+----------+-----------------------------------+
3.4.2. REQUEST ๐
okay so the "REQUEST" method in a "VTODO" calendar component is basically the queen of to-do scheduling ๐ it does a bunch of stuff:
- Assign a to-do to one or more "Calendar Users" ๐
- Reschedule an existing to-do ๐๏ธ
- Update the details of an existing to-do, without rescheduling it โ๏ธ
- Update the completion status of "Attendees" of an existing to-do, without rescheduling it โ
- Reconfirm an existing to-do, without rescheduling it ๐ซถ
- Delegate/reassign an existing to-do to another "Calendar User" ๐ฆ
the assigned "Calendar Users" get identified in the "VTODO" calendar component by individual ATTENDEE;ROLE=REQ-PARTICIPANT property value sequences. so cute, right? ๐ฅน
typically the one sending a "REQUEST" is the "Organizer" of the to-do, and the one receiving it is the "Calendar User" who got assigned the to-do. then the "Attendee" uses the "REPLY" method to tell the "Organizer" of the "REQUEST" whether they're in and where they're at with completion status ๐
the UID, SEQUENCE, and DTSTAMP properties are the dream team that tells all the different "REQUEST" uses apart ๐ง if the UID value in the "REQUEST" isn't on the recipient's calendar, then it's a brand new to-do โจ if the UID value is already on their calendar, then the "REQUEST" is a rescheduling, an update, or a reconfirmation of that "VTODO" calendar object. iconic sorting energy ๐
โ ๏ธ bestie, if the "Organizer" of the "REQUEST" method isn't authorized to make a to-do request on the "Attendee's" calendar system, then an exception gets returned in the REQUEST-STATUS property of a later "REPLY" method. but no scheduling action happens. no drama, just a polite no ๐
โโ๏ธ
for the "REQUEST" method, you can have multiple "VTODO" components in one iCalendar object, but only if they all have the same UID property. so a series of recurring events can carry instance-specific info, and you need multiple "VTODO" components to express the whole series. it's giving organized ๐๐ธ
this method type is an iCalendar object that follows these property constraints ๐
+---------------------------------------------+
| Constraints for a METHOD:REQUEST of a VTODO |
+---------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REQUEST. |
| | | |
| VTODO | 1+ | All components must have the same |
| | | UID. |
| ATTENDEE | 1+ | |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | |
| PRIORITY | 1 | |
| SEQUENCE | 0 or 1 | MUST be present if value is |
| | | greater than 0; MAY be present if |
| | | 0. |
| SUMMARY | 1 | Can be null. |
| UID | 1 | |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| COMPLETED | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null |
| DUE | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DUE MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PERCENT-COMPLETE | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MAY be one of |
| | | COMPLETED/NEEDS-ACTION/ |
| | | IN-PROCESS. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VJOURNAL | 0 | |
+--------------------+----------+-----------------------------------+
3.4.2.1. REQUEST for Rescheduling a VTODO ๐๏ธ
the "REQUEST" method can be used to reschedule a "VTODO" calendar component ๐ฅฐ
rescheduling a "VTODO" calendar component means changing the existing one in terms of its start or due time, its recurrence intervals, and maybe its description too. so if the recipient CUA of a "REQUEST" method finds that the UID value is already on the calendar, but the SEQUENCE value in the "REQUEST" is higher than the one for the existing "VTODO", then the "REQUEST" is describing a rescheduling of that "VTODO" calendar component. main character glow-up moment โจ
3.4.2.2. REQUEST for Update or Reconfirmation of a VTODO โ๏ธ
the "REQUEST" method can also update or reconfirm a "VTODO" calendar component ๐ซถ reconfirmation is basically just an update to the "Attendee" completion status or the overall "VTODO" calendar component status.
an update to an existing "VTODO" calendar component doesn't touch the start or due time, the recurrence intervals, or (generally) the description. so if the recipient CUA of a "REQUEST" method finds that the UID value is already on the calendar, and the SEQUENCE value in the "REQUEST" is the same as the value for the existing event, then the "REQUEST" is describing an update of the "VTODO" calendar component details, but not a rescheduling ๐
the update "REQUEST" is the right answer to a "REFRESH" method sent from an "Attendee" to the "Organizer" of a "VTODO" calendar component ๐
unsolicited "REQUEST" methods MAY be sent by the "Organizer" of a "VTODO" calendar component ๐ they're used to update the details of the "VTODO" (without rescheduling it or updating the completion status of "Attendees"), or to reconfirm the "VTODO" calendar component itself. no surprises, just vibes ๐
3.4.2.3. REQUEST for Delegating a VTODO ๐ฆ
the "REQUEST" method is also how you delegate or reassign ownership of a "VTODO" calendar component to another "Calendar User" ๐งโโ๏ธ for example, it can delegate an "Attendee's" role (like "chair" or "participant") for a "VTODO" calendar component. the "REQUEST" is sent by one of the "Attendees" of an existing "VTODO" calendar component to some other person.
for this part, the "Attendee" doing the delegating is called the "Delegator" ๐ซก and the "Attendee" getting the delegation request is called the "Delegate" ๐
okay, the rules for delegation are a whole thing, so read carefully bestie ๐
- The "Delegator" of a "VTODO" calendar component MUST forward the existing "REQUEST" method for that "VTODO" calendar component to the "Delegate". ๐จ
- The "VTODO" calendar component description MUST include the "Delegator's" up-to-date "VTODO" calendar component definition. ๐๏ธ
- The "REQUEST" method MUST also include an
ATTENDEEproperty with the calendar address of the "Delegate". ๐ฌ - The "Delegator" MUST also send a "REPLY" method back to the "Organizer", with the "Delegator's"
AttendeepropertyPARTSTATparameter value set toDELEGATED. ๐ - On top of that, the
DELEGATED-TOparameter MUST be included, with the calendar address of the "Delegate". ๐
the response to the delegation "REQUEST" gets sent from the "Delegate" to the "Organizer", and optionally to the "Delegator" ๐ธ the "REPLY" from the "Delegate" SHOULD include the ATTENDEE property with their own calendar address, and the DELEGATED-FROM parameter with the "Delegator's" calendar address. so many little addresses, so much love ๐
one more: the delegation "REQUEST" MUST assign a value for the RSVP property parameter that's associated with the "Delegator's" Attendee property, matching the "Delegate's" ATTENDEE property. for example, if the "Delegator's" ATTENDEE property says RSVP=TRUE, then the "Delegate's" ATTENDEE property MUST specify RSVP=TRUE too ๐ no switching it up mid-delegation, periodt ๐
โโ๏ธโจ
3.4.2.4. REQUEST Forwarded to an Uninvited Calendar User โจ
okay so an "Attendee" who's been assigned a "VTODO" can pass that "VTODO" along to a brand new CU who was never part of it ๐ the current "Attendee" does this by forwarding the original "REQUEST" method to the new CU. then the new CU can send a "REPLY" back to the "Organizer" of the "VTODO", and that reply includes an ATTENDEE property for them ๐ฆ
but here's the tea: the "Organizer" is the one who gets the final say on whether the new CU actually joins the to-do ๐ they don't have to do anything with a "REPLY" from someone uninvited. if they don't want the new CU in, the new ATTENDEE property just doesn't get added to the "VTODO" calendar component. the "Organizer" MAY send that CU a "CANCEL" message to say "nope, you're not in this one" ๐
if the "Organizer" does say yes, the new ATTENDEE property gets added to the "VTODO" calendar component. and the "Organizer" is totally free to tweak any ATTENDEE property parameter from what the new CU sent, switching it to whatever the "Organizer" thinks fits best ๐
once they're in, the "Organizer" SHOULD send the new "Attendee" a "REQUEST" message so they know they've been added ๐
and the forwarding "Attendee" MUST NOT make any changes to the original message while passing it along. no edits, no glitter, nothing! ๐ซถ
3.4.2.5. REQUEST Updated Attendee Status ๐ธ
an "Organizer" of a "VTODO" can ask one or more "Attendees" for an updated status โจ they send a "REQUEST" method with the ATTENDEE;RSVP=TRUE property sequence. the SEQUENCE property for the "VTODO" stays exactly the same as before ๐ง
so how does the recipient know what's going on? they look at the "REQUEST" and see that the only thing that changed is their RSVP property parameter asking for an updated status. that's the whole signal ๐ the recipient SHOULD then answer with a "REPLY" method that shows their current status for that "REQUEST" ๐
3.4.3. REPLY ๐
the "REPLY" method in a "VTODO" calendar component is how you answer a request (like accepting or declining it) or reply to a delegation request ๐ it's also how an "Attendee" updates their completion status, which is lowkey so useful ๐
when a "REPLY" is a delegation response, the "Delegator" MUST put the calendar address of the "Delegate" in the "DELEGATED-TO" parameter of the "Delegator's" ATTENDEE property ๐ซถ and the "Delegate" MUST put the calendar address of the "Delegator" in the "DELEGATED-FROM" parameter of the "Delegate's" ATTENDEE property. it's a whole chain of receipts, bestie ๐งพ
the "REPLY" method MAY also be used to respond to a "VTODO" calendar component "REQUEST" that didn't go through ๐
depending on the REQUEST-STATUS value, it's possible that no scheduling action got performed at all ๐
the "Organizer" of a "VTODO" calendar component MAY get a "REPLY" from a "Calendar User" who wasn't in the original "REQUEST" ๐ฆ for example, a "REPLY" MAY come from a "Delegate" of the "VTODO" calendar component. and a "REPLY" MAY also come from an unknown "Calendar User" who got forwarded the "REQUEST" by an original "Attendee" of the "VTODO" calendar component ๐ that uninvited "Attendee" MAY be accepted, or the "Organizer" MAY cancel the "VTODO" calendar component for them by sending a "CANCEL" method. main character energy from the organizer, honestly ๐
this method type is an iCalendar object that follows these property constraints. here's the whole checklist, no cap ๐
+-------------------------------------------+
| Constraints for a METHOD:REPLY of a VTODO |
+-------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REPLY. |
| | | |
| VTODO | 1+ | All components MUST have the same |
| | | UID. |
| ATTENDEE | 1 | MUST be the address of the |
| | | Attendee replying. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| REQUEST-STATUS | 0+ | |
| UID | 1 | MUST be the UID of the original |
| | | REQUEST. |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| COMPLETED | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | |
| DTSTART | 0 or 1 | |
| DUE | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DUE MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PERCENT-COMPLETE | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| SEQUENCE | 0 or 1 | MUST be the sequence number of |
| | | the original REQUEST if greater |
| | | than 0. MAY be present if 0. |
| STATUS | 0 or 1 | |
| SUMMARY | 0 or 1 | Can be null. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0 or 1 | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.4.4. ADD ๐ฆ
okay so the "ADD" method is giving efficiency ๐ It lets the Organizer tack one or more brand-new instances onto an existing VTODO with a single iTIP message, so they don't have to resend the whole VTODO with all the existing instance data like they would with REQUEST ๐
The UID has to be the one belonging to the existing to-do. ngl, if the UID in an ADD isn't on the recipient's calendar, the recipient SHOULD send a REFRESH to the Organizer so they can get the latest version of the VTODO ๐ฅ And if an Attendee's implementation doesn't support ADD, it should respond with a REQUEST-STATUS value of 3.14 and ask for a REFRESH ๐
When an Attendee handles an ADD, they treat each component in the message as if it were referenced via an RDATE in the main component ๐ง
The SEQUENCE property value gets incremented since the sequence of to-dos has changed ๐ธ
This method type is an iCalendar object that conforms to the following property constraints:
+-----------------------------------------+
| Constraints for a METHOD:ADD of a VTODO |
+-----------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be ADD. |
| | | |
| VTODO | 1 | |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| PRIORITY | 1 | |
| SEQUENCE | 1 | MUST be greater than 0. |
| SUMMARY | 1 | Can be null. |
| UID | 1 | MUST match that of the original |
| | | to-do. |
| ATTACH | 0+ | |
| ATTENDEE | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| COMPLETED | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null. |
| DTSTART | 0 or 1 | |
| DUE | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DUE MUST NOT be |
| | | present. |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PERCENT-COMPLETE | 0 or 1 | |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| STATUS | 0 or 1 | MAY be one of |
| | | COMPLETED/NEEDS-ACTION/ |
| | | IN-PROCESS. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| EXDATE | 0 | |
| RECURRENCE-ID | 0 | |
| REQUEST-STATUS | 0 | |
| RDATE | 0 | |
| RRULE | 0 | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VJOURNAL | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.4.5. CANCEL ๐
okay bestie, the CANCEL method in a VTODO calendar component is how the Organizer tells the affected Attendees that an existing to-do request is cancelled ๐ it's sent by the Organizer of the VTODO to its Attendees, and it's giving very clear "we're not doing this anymore" energy ๐
โโ๏ธ
for a recurring VTODO, you can cancel the whole thing or just some of the instances ๐ to cancel the complete range, the UID value for the VTODO MUST be specified, and a RECURRENCE-ID MUST NOT be specified in the CANCEL method. to cancel one specific instance, the RECURRENCE-ID value for the VTODO MUST be specified in the CANCEL method. so the rule is basically: no RECURRENCE-ID means the whole series, RECURRENCE-ID means one instance ๐
there are two ways to cancel a sequence of instances ๐ธ
- the
RECURRENCE-IDfor an instance in the sequence MUST be specified with theRANGEproperty parameter value ofTHISANDFUTURE, which cancels the specifiedVTODOand all instances after it โจ - individual recurrence instances may be cancelled by specifying multiple
VTODOcomponents, each with aRECURRENCE-IDproperty that matches one of the instances to be cancelled ๐ง
the Organizer MUST send aCANCELmessage to each Attendee affected by the cancellation ๐จ it can be oneCANCELmessage for everyone, or several messages each covering a different subset of the affected Attendees. either way, nobody gets left out!!
when a VTODO is cancelled, the SEQUENCE value MUST be incremented as described in Section 2.1.4 ๐ that's how everyone knows this is the newest version of the story ๐
this method type is an iCalendar object that has to follow these property constraints (no skipping, it's the rules, babe):
+--------------------------------------------+
| Constraints for a METHOD:CANCEL of a VTODO |
+--------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be CANCEL. |
| | | |
| VTODO | 1+ | |
| ATTENDEE | 0+ | MUST include some or all |
| | | Attendees being removed from the |
| | | to-do. MUST include some or all |
| | | Attendees if the entire to-do is |
| | | cancelled. |
| UID | 1 | MUST echo original UID. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 1 | |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| COMPLETED | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | |
| DTSTART | 0 or 1 | |
| DUE | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DUE MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PERCENT-COMPLETE | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| STATUS | 0 or 1 | MUST be set to CANCELLED to |
| | | cancel the entire VTODO. If |
| | | removing specific Attendees, then |
| | | MUST NOT be included. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0 or 1 | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.4.6. REFRESH ๐ฆ
the REFRESH method in a VTODO calendar component is how Attendees of an existing VTODO ask the Organizer for an updated description ๐โโ๏ธ it's basically the "hey, what's the latest tea on this?" message ๐ต the Organizer MAY use this method to ask the Attendees for an updated status too, so it goes both ways ๐ซถ and the REFRESH method MUST specify the UID property that matches the VTODO needing the update.
if you want a refresh for one instance of a recurring VTODO, specify the RECURRENCE-ID property that matches the associated VTODO ๐ the Organizer then responds with the latest description and rendition of the VTODO. most of the time that response is a REQUEST, but if the VTODO has been cancelled, the Organizer MUST send a CANCEL instead ๐ this method is meant to make machine processing of update requests for a VTODO easier to handle ๐คโจ
this method type is an iCalendar object that has to follow these property constraints (again, rules are rules, no cap):
+---------------------------------------------+
| Constraints for a METHOD:REFRESH of a VTODO |
+---------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be REFRESH. |
| | | |
| VTODO | 1 | |
| ATTENDEE | 1 | |
| DTSTAMP | 1 | |
| UID | 1 | MUST echo original UID. |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| ATTACH | 0 | |
| CATEGORIES | 0 | |
| CLASS | 0 | |
| COMMENT | 0 | |
| COMPLETED | 0 | |
| CONTACT | 0 | |
| CREATED | 0 | |
| DESCRIPTION | 0 | |
| DTSTART | 0 | |
| DUE | 0 | |
| DURATION | 0 | |
| EXDATE | 0 | |
| GEO | 0 | |
| LAST-MODIFIED | 0 | |
| LOCATION | 0 | |
| ORGANIZER | 0 | |
| PERCENT-COMPLETE | 0 | |
| PRIORITY | 0 | |
| RDATE | 0 | |
| RELATED-TO | 0 | |
| REQUEST-STATUS | 0 | |
| RESOURCES | 0 | |
| RRULE | 0 | |
| SEQUENCE | 0 | |
| STATUS | 0 | |
| URL | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0+ | |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.4.7. COUNTER ๐
okay so the "COUNTER" method in a "VTODO" calendar component is how an "Attendee" of an existing "VTODO" slides into the "Organizer's" DMs with a counter proposal for that to-do ๐
the counter proposal is an iCalendar object made of a "VTODO" calendar component that fully describes the alternate "VTODO". it's giving complete package ๐
the "Organizer" can say no by sending the "Attendee" a "DECLINECOUNTER" method ๐. or they can say yes by rescheduling the to-do, as described in Section 3.4.2.1, "REQUEST for Rescheduling a To-Do" ๐ฆ. and if they say yes, the "Organizer's" CUA SHOULD send a "REQUEST" message to all "Attendees" affected by any change triggered by an accepted "COUNTER" โจ. that's the glow-up everyone needs to see ๐
this method type is an iCalendar object that follows these property constraints:
+---------------------------------------------+
| Constraints for a METHOD:COUNTER of a VTODO |
+---------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be COUNTER. |
| | | |
| VTODO | 1 | |
| ATTENDEE | 1+ | |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| PRIORITY | 1 | |
| SUMMARY | 1 | Can be null. |
| UID | 1 | |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| COMPLETED | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | Can be null. |
| DTSTART | 0 or 1 | |
| DUE | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DUE MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PERCENT-COMPLETE | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| REQUEST-STATUS | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| SEQUENCE | 0 or 1 | MUST echo the original SEQUENCE |
| | | number. MUST be present if |
| | | non-zero. MAY be present if |
| | | zero. |
| STATUS | 0 or 1 | MAY be one of |
| | | COMPLETED/NEEDS-ACTION/ |
| | | IN-PROCESS/CANCELLED. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0 or 1 | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.4.8. DECLINECOUNTER ๐ โโ๏ธ
the "DECLINECOUNTER" method in a "VTODO" calendar component is used by an "Organizer" of the "VTODO" calendar component to turn down a counter proposal from one of the "Attendees" ๐ . the "Organizer" sends the message to the "Attendee" who sent the "COUNTER" method to the "Organizer" ๐. bye bye, counter ๐
this method type is an iCalendar object that follows these property constraints:
+----------------------------------------------------+
| Constraints for a METHOD:DECLINECOUNTER of a VTODO |
+----------------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be DECLINECOUNTER. |
| | | |
| VTODO | 1 | |
| ATTENDEE | 1+ | MUST for all ATTENDEEs. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 1 | MUST echo the original SEQUENCE |
| | | number. |
| UID | 1 | MUST echo original UID. |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| COMPLETED | 0 or 1 | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | |
| DTSTART | 0 or 1 | |
| DUE | 0 or 1 | If present, DURATION MUST NOT be |
| | | present. |
| DURATION | 0 or 1 | If present, DUE MUST NOT be |
| | | present. |
| EXDATE | 0+ | |
| GEO | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| LOCATION | 0 or 1 | |
| PERCENT-COMPLETE | 0 or 1 | |
| PRIORITY | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| REQUEST-STATUS | 0+ | |
| RESOURCES | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MAY be one of |
| | | COMPLETED/NEEDS-ACTION/ |
| | | IN-PROCESS. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
+--------------------+----------+-----------------------------------+
3.5. Methods for VJOURNAL Components ๐
this section defines the property set for the methods that apply to the "VJOURNAL" calendar component ๐ธ
here's the quick summary of the methods defined for the "VJOURNAL" calendar component. it's the little cheat sheet we all need ๐ง
+---------+---------------------------------------------------------+
| Method | Description |
+---------+---------------------------------------------------------+
| PUBLISH | Post a journal entry. Used primarily as a method of |
| | advertising the existence of a journal entry. |
| | |
| ADD | Add one or more instances to an existing journal entry. |
| | |
| CANCEL | Cancel one or more instances of an existing journal |
| | entry. |
+---------+---------------------------------------------------------+
3.5.1. PUBLISH โจ
okay so PUBLISH for a VJOURNAL is giving "here's a post, no reply needed" ๐ there's no associated response, it's just a posting of an iCalendar object that can get added to someone's calendar ๐ it MUST have an "Organizer" ๐ซถ and it MUST NOT have "Attendees" because it's a solo journal moment ๐ the expected vibe is wrapping up any random journal entry as an iCalendar object ๐ฆ and the "Organizer" MAY later update it with another PUBLISH, or cancel it with a CANCEL method ๐ธ
here's the property checklist for a METHOD:PUBLISH of a VJOURNAL ๐
+------------------------------------------------+
| Constraints for a METHOD:PUBLISH of a VJOURNAL |
+------------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be PUBLISH. |
| | | |
| VJOURNAL | 1+ | |
| DESCRIPTION | 1 | Can be null. |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | |
| UID | 1 | |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| EXDATE | 0+ | |
| LAST-MODIFIED | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| RRULE | 0 or 1 | |
| SEQUENCE | 0 or 1 | MUST be present if non-zero. MAY |
| | | be present if zero. |
| STATUS | 0 or 1 | MAY be one of |
| | | DRAFT/FINAL/CANCELLED. |
| SUMMARY | 0 or 1 | Can be null. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| ATTENDEE | 0 | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VTODO | 0 | |
+--------------------+----------+-----------------------------------+
3.5.2. ADD ๐
the "ADD" method is the Organizer's way of tossing one or more brand-new instances into an existing "VJOURNAL" with a single iTIP message ๐ no need to resend the whole "VJOURNAL" with all the old instance data, which is what you'd have to do with "REQUEST" ๐ซ so much more efficient bestie ๐ง
the "UID" has to be the one from the existing journal entry ๐ and if the "UID" in the "ADD" isn't on the recipient's calendar, the recipient MAY treat the "ADD" as a "PUBLISH" ๐
when an "Attendee" handles an "ADD" message, they treat each component in it as if it were referenced by an "RDATE" in the main component โจ and there's no response going back to the "Organizer", so it's a quiet little drop ๐คซ๐ฆ
here's the property checklist for a METHOD:ADD of a VJOURNAL ๐
+--------------------------------------------+
| Constraints for a METHOD:ADD of a VJOURNAL |
+--------------------------------------------+
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be ADD. |
| | | |
| VJOURNAL | 1 | |
| DESCRIPTION | 1 | Can be null. |
| DTSTAMP | 1 | |
| DTSTART | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 1 | MUST be greater than 0. |
| UID | 1 | MUST match that of the original |
| | | journal. |
| ATTACH | 0+ | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| LAST-MODIFIED | 0 or 1 | |
| RELATED-TO | 0+ | |
| STATUS | 0 or 1 | MAY be one of |
| | | DRAFT/FINAL/CANCELLED. |
| SUMMARY | 0 or 1 | Can be null. |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| ATTENDEE | 0 | |
| EXDATE | 0 | |
| RECURRENCE-ID | 0 | |
| REQUEST-STATUS | 0 | |
| RDATE | 0 | |
| RRULE | 0 | |
| | | |
| VALARM | 0+ | |
| | | |
| VTIMEZONE | 0 or 1 | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VTODO | 0 | |
+--------------------+----------+-----------------------------------+
3.5.3. CANCEL โจ
Okay so the "CANCEL" method in a "VJOURNAL" calendar component is how you send a cancellation notice for a journal entry that already exists ๐ซถ The "Organizer" of that journal entry is the one who sends it. If the entry is recurring, you can cancel the whole thing or just some of its instances, so let's break it down ๐
To cancel the complete range of a recurring journal entry, the "UID" property value for the journal entry MUST be specified and a "RECURRENCE-ID" property MUST NOT be specified in the "CANCEL" method. But if you only want to cancel one individual instance, the "RECURRENCE-ID" property value for the journal entry MUST be specified in the "CANCEL" method ๐
There are two ways to cancel a whole sequence of instances of a recurring "VJOURNAL" calendar component:
- a. The "RECURRENCE-ID" property for an instance in the sequence MUST be specified with the "RANGE" property parameter value of "THISANDFUTURE", which means cancelling the specified "VJOURNAL" calendar component and all the instances after it ๐ฆ
- b. Individual recurrence instances may be cancelled by specifying multiple "VJOURNAL" components, each with a "RECURRENCE-ID" property matching one of the instances you want gone ๐ธ
When a "VJOURNAL" is cancelled, the "SEQUENCE" property value MUST be incremented as described in Section 2.1.4. Don't skip this one, it's a big deal ๐ญ
This method type is an iCalendar object that follows the property constraints below. Here's the little box for it ๐ฆ
+-----------------------------------------------+
| Constraints for a METHOD:CANCEL of a VJOURNAL |
+-----------------------------------------------+
And here's the full table, so you know exactly what's allowed and what's not ๐
+--------------------+----------+-----------------------------------+
| Component/Property | Presence | Comment |
+--------------------+----------+-----------------------------------+
| METHOD | 1 | MUST be CANCEL. |
| | | |
| VJOURNAL | 1+ | All MUST have the same UID. |
| DTSTAMP | 1 | |
| ORGANIZER | 1 | |
| SEQUENCE | 1 | |
| UID | 1 | MUST be the UID of the original |
| | | REQUEST. |
| ATTACH | 0+ | |
| ATTENDEE | 0 | |
| CATEGORIES | 0+ | |
| CLASS | 0 or 1 | |
| COMMENT | 0+ | |
| CONTACT | 0+ | |
| CREATED | 0 or 1 | |
| DESCRIPTION | 0 or 1 | |
| DTSTART | 0 or 1 | |
| EXDATE | 0+ | |
| LAST-MODIFIED | 0 or 1 | |
| RDATE | 0+ | |
| RECURRENCE-ID | 0 or 1 | Only if referring to an instance |
| | | of a recurring calendar |
| | | component. Otherwise, it MUST |
| | | NOT be present. |
| RELATED-TO | 0+ | |
| RRULE | 0 or 1 | |
| STATUS | 0 or 1 | MAY be present; MUST be CANCELLED |
| | | if present. |
| SUMMARY | 0 or 1 | |
| URL | 0 or 1 | |
| IANA-PROPERTY | 0+ | |
| X-PROPERTY | 0+ | |
| REQUEST-STATUS | 0 | |
| | | |
| VALARM | 0 | |
| | | |
| VTIMEZONE | 0+ | MUST be present if any date/time |
| | | refers to a timezone. |
| | | |
| IANA-COMPONENT | 0+ | |
| X-COMPONENT | 0+ | |
| | | |
| VEVENT | 0 | |
| | | |
| VFREEBUSY | 0 | |
| | | |
| VTODO | 0 | |
+--------------------+----------+-----------------------------------+
3.6. Status Replies ๐
Okay, this part is all about the "REQUEST-STATUS" property, which is how you tell people what happened to a "REPLY", "COUNTER", or "DECLINECOUNTER" iTIP message โจ The codes in the table below SHOULD be used. And if the "REQUEST-STATUS" property isn't there at all, a status code of "2.0" (success) MUST be assumed. So no property, no drama ๐
This spec adds a brand new IANA registry for "REQUEST-STATUS" property values, which is defined in Section 7. It also includes a new registration template for spelling out the specific parts of a "REQUEST-STATUS" property value ๐ง Extra codes MAY be used too, as long as they get registered through the process in Section 8.2.1 of [RFC5545].
Multiple "REQUEST-STATUS" properties are allowed in the iCalendar components of the right iTIP messages ๐ But when there are several, these rules apply:
- Within any one component, the "top-level" numeric value of the "short return status code" MUST be the same for all "REQUEST-STATUS" properties. Basically, no mixing a 2.xx and a 5.xx in the same component, bestie ๐
- Across all components in the iTIP message, the following applies:
- A. If any one component would have a 5.xx code, then either all components MUST have a code in that range, or "REQUEST-STATUS" MUST NOT be present in the other components if a 5.xx code is not appropriate for those components.
- B. Otherwise, if any one component would have a 3.xx code, then either all components MUST have a code in that range, or "REQUEST-STATUS" MUST NOT be present in the other components if a 3.xx code is not appropriate for those components.
- C. 2.xx and 4.xx codes can be used in different components, provided that each component follows the restriction in (1) above.
Here are the "REQUEST-STATUS" codes that are defined. Any "Offending Data" MAY be specified in the "REQUEST-STATUS" value as the extdata field ๐
3.6.1. Status Code 2.0 ๐
- Status Code:
2.0 - Status Description: Success.
- Status Exception Data: None.
- Description: iTIP operation succeeded.
Just the classic "everything went perfectly" code ๐
3.6.2. Status Code 2.1 ๐ฆ
- Status Code:
2.1 - Status Description: Success, but fallback taken on one or more property values.
- Status Exception Data: Property name and value MAY be specified.
- Description: iTIP operation succeeded with fallback on one or more property values.
It worked, but something had to fall back, so the property name and value can be named ๐ซถ
3.6.3. Status Code 2.2 ๐ธ
- Status Code:
2.2 - Status Description: Success; invalid property ignored.
- Status Exception Data: Property name MAY be specified.
- Description: iTIP operation succeeded but a property was ignored.
Succeeded, but one property got ghosted because it was invalid ๐ป
3.6.4. Status Code 2.3 ๐
- Status Code:
2.3 - Status Description: Success; invalid property parameter ignored.
- Status Exception Data: Property parameter name and value MAY be specified.
- Description: iTIP operation succeeded but a property parameter was ignored because it was invalid.
Same vibe, except this time it's the parameter that got left on read ๐
3.6.5. Status Code 2.4 ๐ง
- Status Code:
2.4 - Status Description: Success; unknown, non-standard property ignored.
- Status Exception Data: Non-standard property name MAY be specified.
- Description: iTIP operation succeeded but a property parameter was ignored because it was unknown.
When something unknown and non-standard shows up, it gets ignored, but the operation still counts as a win ๐
3.6.6. Status Code 2.5 ๐
- Status Code:
2.5 - Status Description: Success; unknown, non-standard property value ignored.
- Status Exception Data: Property and non-standard value MAY be specified.
- Description: iTIP operation succeeded but a property was ignored because its value was unknown.
Same energy, but this time the value is the mystery ๐ฎ
3.6.7. Status Code 2.6 ๐
- Status Code:
2.6 - Status Description: Success; invalid calendar component ignored.
- Status Exception Data: Calendar component sentinel (e.g.,
BEGIN:ALARM) MAY be specified. - Description: iTIP operation succeeded but a component was ignored because it was invalid.
Okay so a whole component got benched because it was invalid, but the rest went through ๐ฅฒ
3.6.8. Status Code 2.7 ๐ฆข
- Status Code:
2.7 - Status Description: Success; request forwarded to Calendar User.
- Status Exception Data: Original and forwarded calendar user addresses MAY be specified.
- Description: iTIP operation succeeded, and the request was forwarded to another Calendar User.
The request got passed along to someone else, and yes, you can name both addresses ๐
3.6.9. Status Code 2.8 ๐ท
- Status Code:
2.8 - Status Description: Success; repeating event ignored. Scheduled as a single component.
- Status Exception Data: RRULE or RDATE property name and value MAY be specified.
- Description: iTIP operation succeeded but a repeating event was truncated to a single instance.
The repeating event got cut down to one instance. Still a success, just a little shorter ๐ซง
3.6.10. Status Code 2.9 ๐
- Status Code:
2.9 - Status Description: Success; truncated end date time to date boundary.
- Status Exception Data: DTEND property value MAY be specified.
- Description: iTIP operation succeeded but the end time was truncated to a date boundary.
The end time got rounded down to the date boundary. Succeeded, just a bit neater โ๏ธ
3.6.11. Status Code 2.10 ๐ชฉ
- Status Code:
2.10 - Status Description: Success; repeating VTODO ignored. Scheduled as a single VTODO.
- Status Exception Data: RRULE or RDATE property name and value MAY be specified.
- Description: iTIP operation succeeded but a repeating to-do was truncated to a single instance.
Same story as 2.8, but for a to-do instead of an event โ
3.6.12. Status Code 2.11 โญ
- Status Code:
2.11 - Status Description: Success; unbounded RRULE clipped at some finite number of instances.
- Status Exception Data: RRULE property name and value MAY be specified. Number of instances MAY also be specified.
- Description: iTIP operation succeeded but an unbounded repeating object was clipped to a finite number of instances.
An endless repeat got clipped to a set number of instances. Still a success, just with a finish line now ๐
3.6.13. Status Code 3.0 ๐ฅ
- Status Code:
3.0 - Status Description: Invalid property name.
- Status Exception Data: Property name MAY be specified.
- Description: iTIP operation failed because of an invalid property name.
Okay this one is a 3-series code, so it's a failure ๐ The property name was invalid, so the operation didn't go through.
3.6.14. Status Code 3.1 ๐ค
- Status Code:
3.1 - Status Description: Invalid property value.
- Status Exception Data: Property name and value MAY be specified.
- Description: iTIP operation failed because of an invalid property value.
Same failure energy as 3.0, but this time the value is what's wrong ๐ญ The property name and value can be named so the sender knows exactly what went sideways.
3.6.15. Status Code 3.2 โจ
- Status Code:
3.2 - Status Description:
Invalid property parameter. - Status Exception Data:
Property parameter name and value MAY be specified.
Description: okay so the iTIP operation flopped bc one of the property parameters was invalid ๐ not the vibe.
3.6.16. Status Code 3.3 ๐
- Status Code:
3.3 - Status Description:
Invalid property parameter value. - Status Exception Data:
Property parameter name and value MAY be specified.
Description: the iTIP operation failed bc a property parameter had an invalid value (the name was fine, the value was giving chaos) ๐
3.6.17. Status Code 3.4 ๐ฆ
- Status Code:
3.4 - Status Description:
Invalid calendar component sequence. - Status Exception Data:
Calendar component sentinel MAY be specified (e.g., BEGIN:VTIMEZONE).
Description: iTIP operation failed bc a component was invalid. The sentinel, like BEGIN:VTIMEZONE, is allowed to be included if you want to flag it ๐ธ
3.6.18. Status Code 3.5 ๐
- Status Code:
3.5 - Status Description:
Invalid date or time. - Status Exception Data:
Date/time value(s) MAY be specified.
Description: the iTIP operation failed bc a date or time property was not it. Main character energy, but make it valid ๐ฐ๏ธ
3.6.19. Status Code 3.6 ๐
- Status Code:
3.6 - Status Description:
Invalid rule. - Status Exception Data:
RRULE property value MAY be specified.
Description: the iTIP operation failed bc a rule property was invalid. The RRULE value is allowed to be included in the error, so the sender can see what went wrong ๐
3.6.20. Status Code 3.7 ๐ง
- Status Code:
3.7 - Status Description:
Invalid Calendar User. - Status Exception Data:
ATTENDEE property value MAY be specified.
Description: the iTIP operation failed bc the ATTENDEE property was invalid. The ATTENDEE value is allowed to be included so everyone knows who got flagged ๐
3.6.21. Status Code 3.8 ๐
- Status Code:
3.8 - Status Description:
No authority. - Status Exception Data:
METHOD and ATTENDEE property values MAY be specified.
Description: the iTIP operation failed bc an Attendee doesn't have the right privileges for it. Not their lane, bestie ๐ซ The METHOD and ATTENDEE values are allowed to be included in the error.
3.6.22. Status Code 3.9 ๐
- Status Code:
3.9 - Status Description:
Unsupported version. - Status Exception Data:
VERSION property name and value MAY be specified.
Description: the iTIP operation failed bc the calendar data's version isn't supported. Old version, new vibes, no match โจ
3.6.23. Status Code 3.10 ๐
- Status Code:
3.10 - Status Description:
Request entity too large. - Status Exception Data:
None.
Description: the iTIP operation failed bc the calendar data was too big. Girl, that's a lot of data ๐ญ
3.6.24. Status Code 3.11 ๐ธ
- Status Code:
3.11 - Status Description:
Required component or property missing. - Status Exception Data:
Component or property name MAY be specified.
Description: the iTIP operation failed bc the calendar data didn't have a required property or component. Something important was left out, periodt ๐ฆ
3.6.25. Status Code 3.12 ๐ฎ
- Status Code:
3.12 - Status Description:
Unknown component or property found. - Status Exception Data:
Component or property name MAY be specified.
Description: the iTIP operation failed bc the calendar data had an unknown property or component in it. Who invited that? ๐คจ
3.6.26. Status Code 3.13 ๐ฆ
- Status Code:
3.13 - Status Description:
Unsupported component or property found. - Status Exception Data:
Component or property name MAY be specified.
Description: the iTIP operation failed bc the calendar data had an unsupported property or component. Known, but not supported here, so no ๐ โโ๏ธ
3.6.27. Status Code 3.14 ๐
- Status Code:
3.14 - Status Description:
Unsupported capability. - Status Exception Data:
METHOD or action MAY be specified.
Description: the iTIP operation failed bc the operation just isn't supported. The METHOD or action is allowed to be included in the error ๐ ๏ธ
3.6.28. Status Code 4.0 ๐ฅ
- Status Code:
4.0 - Status Description:
Event conflict. Date/time is busy. - Status Exception Data:
DTSTART and DTEND property names and values MAY be specified.
Description: the iTIP operation failed bc the event overlapped the date and time of another event. Double-booked, no cap ๐
The DTSTART and DTEND names and values are allowed to be included.
3.6.29. Status Code 5.0 ๐ท
- Status Code:
5.0 - Status Description:
Request not supported. - Status Exception Data:
METHOD property value MAY be specified.
Description: the iTIP operation failed bc the operation isn't supported. Same energy as 3.14, but this one is about the request itself. The METHOD value is allowed to be included ๐ซถ
3.6.30. Status Code 5.1 ๐
- Status Code:
5.1 - Status Description:
Service unavailable. - Status Exception Data:
ATTENDEE property value MAY be specified.
Description: the iTIP operation failed bc scheduling isn't active right now. The service is just offline rn ๐ด The ATTENDEE value is allowed to be included.
3.6.31. Status Code 5.2 ๐ช
- Status Code:
5.2 - Status Description:
Invalid calendar service. - Status Exception Data:
ATTENDEE property value MAY be specified.
Description: the iTIP operation failed bc there's no scheduling capability there at all. Wrong service, bestie ๐ช The ATTENDEE value is allowed to be included.
3.6.32. Status Code 5.3 ๐
- Status Code:
5.3 - Status Description:
No scheduling support for user. - Status Exception Data:
ATTENDEE property value MAY be specified.
Description: the iTIP operation failed bc scheduling isn't turned on for an Attendee. They're just not enabled yet ๐ The ATTENDEE value is allowed to be included.
3.7. Implementation Considerations ๐ง
3.7.1. Working With Recurrence Instances
okay so iCalendar has a recurrence grammar for repeating events, and it's honestly so smart bc you can represent a whole bunch of events in just one object. But the catch is that individual meeting instances still need to be referenced. Like, an Attendee might decline just the third instance of a recurring Friday event. Or the Organizer might change the time or location for only one instance of that recurring event ๐
Since implementations can choose to store recurring events either as one single event object or as a collection of separate, related event objects, the protocol is designed so that each recurring instance can be both referenced and versioned ๐ฆ So implementations that want to keep per-instance properties (like the PARTSTAT parameter on the ATTENDEE property) can totally do that. But the protocol doesn't require per-instance recognition unless that instance itself has to be renegotiated.
Here are the scenarios for recurrence instance referencing. To keep things simple, a change to an event counts as a "trigger property." That means a property with a real effect on the meeting itself, like start time, location, due date (for VTODO calendar components), and possibly description โจ
"Organizer"-initiated actions:
- deletes or changes a single instance of a recurring event
- makes changes that affect all future instances
- makes changes that affect all previous instances
- deletes or modifies a previously changed instance
"Attendee"-initiated actions:
- changes status for a particular recurrence instance
- sends a
COUNTERfor a particular recurrence instance
An instance of a recurring event gets a unique identifier, the RECURRENCE-ID property, when that instance is renegotiated. Renegotiation might be needed when a big change happens to the event or to-do, like changing the start time, end time, due date, or location ๐ The "Organizer" can point to a specific recurrence instance using RECURRENCE-ID, and its value is the date/time of that instance. If the "Organizer" wants to change the DTSTART, then the original, unmodified DTSTART value of the instance gets used as the RECURRENCE-ID value, and the new DTSTART and DTEND values show the change ๐
3.7.2. Attendee Property Considerations
The ORGANIZER property is required on published events, to-dos, and journal entries, and there are two big reasons. First, only the Organizer is allowed to update and redistribute an event or to-do component. So the ORGANIZER property MUST be present in the event, to-do, or journal entry component so the CUA has a basis for authorizing an update ๐ Second, it's smart to give anyone who gets a published component a point of contact, just in case something goes wrong ๐ซถ
Email addresses that stand for groups of "Calendar Users" could be specified as a mailto: URI [RFC2368] calendar user address. Sending email to one of those addresses means the email goes out to multiple recipients. Such an address can be used as the value of an ATTENDEE property. So it's possible that the recipient of a REQUEST doesn't show up explicitly in the list ๐ฏ
It's recommended that the general approach to finding a "Calendar User" in an Attendee list goes like this:
- Search for the "Calendar User" in the Attendee list where
CUTYPE=INDIVIDUAL - If (1) fails, look for Attendees where
CUTYPE=GROUPorCUTYPE=UNKNOWN. The CUA then figures out whether the "Calendar User" is a member of one of those groups. If so, theREPLYmethod sent to the Organizer MUST contain a newATTENDEEproperty in which:- the
TYPEproperty parameter is set to INDIVIDUAL - the
MEMBERproperty parameter is set to the name of the group
- the
- If (2) fails, the CUA MAY ignore or accept the request, whatever the "Calendar User" wants ๐คทโโ๏ธ
3.7.3. Extension Tokens
To make iCalendar objects extensible, you can use new components, properties, or property parameters. There are two types of extensions defined by [RFC5545]: IANA-registered tokens (iana-token) and experimental use tokens (x-name) ๐งฉ A client SHOULD save "iana-token's" and MAY use them in replies. A client MAY save "x-name's" and MAY use them in replies. When delegating or forwarding messages to other CUs, a client SHOULD include "iana-token's" and "x-names's" ๐
4. Examples ๐
4.1. Published Event Examples
Okay, so publishing is basically a one-way transfer of event info. The people getting published events just add the event to their calendar, and no reply is expected ๐ฎ Individual A publishes an event, and Individual B reads it and adds it to their calendar. Events get published in a bunch of ways, like embedding the event as an object in a web page, emailing it to a distribution list, or posting it to a newsgroup ๐
The table below shows the sequence of events between the publisher and the people consuming the published event:
+----------------+-----------------------+--------------------------+
| Action | Organizer | Receiver |
+----------------+-----------------------+--------------------------+
| Publish an | "A" sends or posts a | "B" reads a published |
| event | PUBLISH message. | event. |
| | | |
| Publish an | "A" sends or posts a | "B" reads the updated |
| updated event | PUBLISH message. | event. |
| | | |
| Cancel a | "A" sends or posts a | "B" reads the canceled |
| published | CANCEL message. | event publication. |
| event | | |
+----------------+-----------------------+--------------------------+
4.1.1. A Minimal Published Event ๐
The iCalendar object below describes a single event that begins on July 1, 1997 at 20:00 UTC. This event has the minimum set of properties for a PUBLISH of a VEVENT calendar component. It's giving clean and simple ๐ฅฐ
BEGIN:VCALENDAR
METHOD:PUBLISH
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
DTSTART:19970701T200000Z
DTSTAMP:19970611T190000Z
SUMMARY:ST. PAUL SAINTS -VS- DULUTH-SUPERIOR DUKES
UID:0981234-1234234-23@example.com
END:VEVENT
END:VCALENDAR
4.1.2. Changing a Published Event ๐ฆ
okay so this one is an update to the event from Section 4.1.1, bestie ๐ the time got moved, an end time got added, and the sequence number got bumped. no cap, it's giving "new version, who dis" ๐
BEGIN:VCALENDAR
METHOD:PUBLISH
VERSION:2.0
PRODID:-//Example/ExampleCalendarClient//EN
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
DTSTAMP:19970612T190000Z
DTSTART:19970701T210000Z
DTEND:19970701T230000Z
SEQUENCE:1
UID:0981234-1234234-23@example.com
SUMMARY:ST. PAUL SAINTS -VS- DULUTH-SUPERIOR DUKES
END:VEVENT
END:VCALENDAR
The UID property is how the client knows which event is which ๐ and the SEQUENCE property tells everyone this is a change to that event โจ The event with a matching UID and sequence number 0 is superseded by this one, so it's a total glow-up ๐
The SEQUENCE property is the reliable way to tell different versions of the same event apart ๐ง Every time an event gets published, its sequence number goes up. If a client gets an event with sequence number 5 and it already has sequence number 2 of that same event, the event SHOULD be updated ๐ but if the client gets sequence number 2 and already has sequence number 5 of the same event, the event MUST NOT be updated ๐
โโ๏ธ the older version does not get to win, periodt ๐
4.1.3. Canceling a Published Event ๐ฅ
this one cancels the event from Section 4.1.1 ๐ญ it cancels the event with SEQUENCE values of 0, 1, and 2, so the whole run is over ๐
BEGIN:VCALENDAR
METHOD:CANCEL
VERSION:2.0
PRODID:-//Example/ExampleCalendarClient//EN
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
COMMENT:DUKES forfeit the game
SEQUENCE:2
UID:0981234-1234234-23@example.com
DTSTAMP:19970613T190000Z
END:VEVENT
END:VCALENDAR
4.1.4. A Rich Published Event ๐
this is the same event as Section 4.1.1, but with the full glam treatment ๐ way more detail, and it's honestly so iconic ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:PUBLISH
SCALE:GREGORIAN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America-Chicago
TZURL:http://example.com/tz/America-Chicago
BEGIN:STANDARD
DTSTART:19671029T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZOFFSETFROM:-0500
TZOFFSETTO:-0600
TZNAME:CST
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19870405T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZOFFSETFROM:-0600
TZOFFSETTO:-0500
TZNAME:CDT
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTACH:http://www.example.com/
CATEGORIES:SPORTS EVENT,ENTERTAINMENT
CLASS:PRIVATE
DESCRIPTION:MIDWAY STADIUM\n
Big time game. MUST see.\n
Expected duration:2 hours\n
DTEND;TZID=America-Chicago:19970701T180000
DTSTART;TZID=America-Chicago:19970702T160000
DTSTAMP:19970614T190000Z
STATUS:CONFIRMED
LOCATION;VALUE=URI:http://stadium.example.com/
PRIORITY:2
RESOURCES:SCOREBOARD
SEQUENCE:3
SUMMARY:ST. PAUL SAINTS -VS- DULUTH-SUPERIOR DUKES
UID:0981234-1234234-23@example.com
RELATED-TO:0981234-1234234-14@example.com
BEGIN:VALARM
TRIGGER:-PT2H
ACTION:DISPLAY
DESCRIPTION:You should be leaving for the game now.
END:VALARM
BEGIN:VALARM
TRIGGER:-PT30M
ACTION:AUDIO
END:VALARM
END:VEVENT
END:VCALENDAR
The RELATED-TO field holds the UID of a related calendar event ๐ and the SEQUENCE value of 3 means this event supersedes versions 0, 1, and 2 โจ main character energy, literally ๐
4.1.5. Anniversaries or Events Attached to Entire Days ๐
this example shows how the VALUE parameter ties a VEVENT to a whole day instead of a specific time ๐
perfect for birthdays and holidays ๐ซ๐ท
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:PUBLISH
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
DTSTAMP:19970614T190000Z
UID:0981234-1234234-23@example.com
DTSTART;VALUE=DATE:19970714
RRULE:FREQ=YEARLY;INTERVAL=1
SUMMARY: Bastille Day
END:VEVENT
END:VCALENDAR
4.2. Group Event Examples ๐ซถ
okay bestie, group events are different from published events because they have "Attendees," and there's actual back-and-forth between the "Attendees" and the "Organizer" ๐ฃ๏ธ here, individual "A" requests a meeting with "A", "B", "C", and "D" ๐จ "B" confirms, "C" declines, and "D" tentatively confirms ๐ the table below shows the message flow, and "A", the CU scheduling the meeting, is the "Organizer" ๐
+--------------+-----------------------+----------------------------+
| Action | "Organizer" | Attendee |
+--------------+-----------------------+----------------------------+
| Initiate a | "A" sends a REQUEST | |
| meeting | message to "B", "C", | |
| request | and "D". | |
| | | |
| Accept the | | "B" sends a REPLY message |
| meeting | | to "A" with its ATTENDEE |
| request | | PARTSTAT parameter set to |
| | | ACCEPTED. |
| | | |
| Decline the | | "C" sends a REPLY message |
| meeting | | to "A" with its ATTENDEE |
| request | | PARTSTAT parameter set to |
| | | DECLINED. |
| | | |
| Tentatively | | "D" sends a REPLY message |
| accept the | | to "A" with its ATTENDEE |
| meeting | | PARTSTAT parameter set to |
| request | | TENTATIVE. |
| | | |
| Confirm | "A" sends a REQUEST | |
| meeting | message to "B" and | |
| status with | "D" with updated | |
| Attendees | information. | |
+--------------+-----------------------+----------------------------+
4.2.1. A Group Event Request ๐ฌ
here "A" sends a meeting request to "B", "C", and "D" โจ "E" gets a copy too, but "E" isn't expected to attend and doesn't need to reply ๐ this shows how CUAs might do an "FYI"-type feature, which is lowkey genius ๐ง check out the ROLE parameter: its default is "REQ-PARTICIPANT" and it doesn't need to be written out ๐
here we use "NON-PARTICIPANT" to say "E" is a non-attending CU ๐ the parameter isn't needed on the other "Attendees" since "PARTICIPANT" is already the default ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=C:mailto:c@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;RSVP=FALSE;CUTYPE=ROOM:conf_big@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.2.2. Reply to a Group Event Request ๐
"Attendee" "B" says yes to the meeting ๐ฅณ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VEVENT
ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
REQUEST-STATUS:2.0;Success
DTSTAMP:19970612T190000Z
END:VEVENT
END:VCALENDAR
"B" could have declined or said tentative by setting the "ATTENDEE" "PARTSTAT" parameter to "DECLINED" or "TENTATIVE", respectively ๐ also, REQUEST-STATUS is not required in successful transactions, so you can chill on that one โจ
4.2.3. Update an Event ๐
the event got moved to a different time โฐ the UID property stays the same and the SEQUENCE gets bumped to 1, and together those two signal the update ๐ฆ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:c@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;
CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
DTSTART:19970701T180000Z
DTEND:19970701T190000Z
SUMMARY:Phone Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:1
DTSTAMP:19970613T190000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.2.4. Countering an Event Proposal ๐
okay so "A" sends a REQUEST to "B" and "C" ๐. then "B" is like "ummm can we do a different time and place??" and makes a counter proposal to "A" to change the time and location ๐
"A" sends the following REQUEST ๐จ:
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:c@example.com
DTSTART:19970701T190000Z
DTEND:19970701T200000Z
SUMMARY:Discuss the Merits of the election results
LOCATION:Green Conference Room
UID:calsrv.example.com-873970198738777a@example.com
SEQUENCE:0
DTSTAMP:19970611T190000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
"B" sends COUNTER to "A" ๐ฆ, asking for changes to the time and place. "B" uses the COMMENT property to explain the reasoning behind the change ๐ซถ. Note that the SEQUENCE property is not incremented on a COUNTER ๐ค
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:COUNTER
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:c@example.com
DTSTART:19970701T160000Z
DTEND:19970701T170000Z
DTSTAMP:19970612T190000Z
SUMMARY:Discuss the Merits of the election results
LOCATION:Blue Conference Room
COMMENT:This time works much better and I think the big conference
room is too big
UID:calsrv.example.com-873970198738777a@example.com
SEQUENCE:0
END:VEVENT
END:VCALENDAR
"A" accepts the changes from "B" ๐ฅฐ. To accept a counter proposal, the "Organizer" sends a new event REQUEST with an incremented sequence number โ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:c@example.com
DTSTAMP:19970613T190000Z
DTSTART:19970701T160000Z
DTEND:19970701T170000Z
SUMMARY:Discuss the Merits of the election results - changed to
meet B's schedule
LOCATION:Blue Conference Room
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:1
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
Or, plot twist: "A" rejects "B's" counter proposal ๐ โโ๏ธ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:DECLINECOUNTER
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
COMMENT:Sorry, I cannot change this meeting time
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
DTSTAMP:19970614T190000Z
END:VEVENT
END:VCALENDAR
4.2.5. Delegating an Event ๐ง
okay this one is so fun ๐คญ when you delegate an event request to another "Calendar User", the "Delegator" must both update the "Organizer" with a REPLY and send a request to the "Delegate". there is currently no protocol limitation to delegation depth, so the original delegate can totally pass the meeting to someone else, and then that person can pass it on too, and so on ๐ when a request gets delegated from one CUA to another, the "Delegator" has a few responsibilities that come with it. The "Delegator" MUST:
- Send a
REPLYto the "Organizer" with the following updates:- A. The "Delegator's"
ATTENDEEpropertyPARTSTATparameter is set toDELEGATED, and theDELEGATED-TOparameter is set to the address of the "Delegate" ๐ซ - B. Add an additional
ATTENDEEproperty for the "Delegate", with theDELEGATED-FROMproperty parameter set to the "Delegator" ๐ซง - C. Indicate whether they want to keep getting updates when the "Organizer" sends out updated versions of the event ๐ Setting the
RSVPproperty parameter toTRUEwill cause the updates to be sent, and setting it toFALSEmeans no further updates get sent. Note that in either case, if the "Delegate" declines the invitation, the "Delegator" will be notified ๐
- A. The "Delegator's"
- The "Delegator" MUST also send a copy of the original
REQUESTmethod to the "Delegate", with changes (A) and (B), as detailed above, applied โจ
If the "Delegate" declines the meeting, the "Organizer" MUST send an update REQUEST to the "Delegator" so that the "Delegator" can choose to delegate the REQUEST to another CUA ๐
Here's the whole flow in one glance ๐
+----------------+-----------------+--------------------------------+
| Action | "Organizer" | Attendee |
+----------------+-----------------+--------------------------------+
| Initiate a | "A" sends a | |
| meeting | REQUEST message | |
| request | to "B" and "C". | |
| | | |
| Delegate: "C" | | "C" sends a REPLY to "A" with |
| delegates to | | the ATTENDEE PARTSTAT |
| "E" | | parameter set to DELEGATED and |
| | | with a new ATTENDEE property |
| | | for "E". "E's" ATTENDEE |
| | | DELEGATED-FROM parameter is |
| | | set to "C". "C's" ATTENDEE |
| | | DELEGATED-TO parameter is set |
| | | to "E". "C" sends REQUEST |
| | | message to "E" with the |
| | | original meeting request |
| | | information. The PARTSTAT |
| | | property parameter for "C" is |
| | | set to DELEGATED and the |
| | | DELEGATED-TO parameter is set |
| | | to the address of "E". An |
| | | ATTENDEE property is added for |
| | | "E" and the DELEGATED-FROM |
| | | parameter is set to the |
| | | address of "C". |
| | | |
| Confirm | | "E" sends REPLY message to |
| meeting | | "A", and optionally to "C", |
| attendance | | with its PARTSTAT property |
| | | parameter set to ACCEPTED. |
| | | |
| Optional: | "A" sends | |
| Redistribute | REQUEST message | |
| meeting to | to "B", "C", | |
| Attendees | and "E". | |
+----------------+-----------------+--------------------------------+
"C" responds to the "Organizer" ๐โโ๏ธ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-
TO="mailto:e@example.com":mailto:c@example.com
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
REQUEST-STATUS:2.0;Success
DTSTAMP:19970611T190000Z
END:VEVENT
END:VCALENDAR
"Attendee" "C" delegates presence at the meeting to "E" ๐ซถ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-
TO="mailto:e@example.com":mailto:c@example.com
ATTENDEE;RSVP=TRUE;
DELEGATED-FROM="mailto:c@example.com":mailto:e@example.com
DTSTART:19970701T180000Z
DTEND:19970701T200000Z
SUMMARY:Phone Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
DTSTAMP:19970611T190000Z
END:VEVENT
END:VCALENDAR
4.2.6. Delegate Accepts the Meeting ๐ฅณ
so when it's time to accept a delegated meeting, the delegate, "E", sends this message to "A" and "C" ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=ACCEPTED;DELEGATED-
FROM="mailto:c@example.com":mailto:e@example.com
ATTENDEE;PARTSTAT=DELEGATED;
DELEGATED-TO="mailto:e@example.com":mailto:c@example.com
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
REQUEST-STATUS:2.0;Success
DTSTAMP:19970614T190000Z
END:VEVENT
END:VCALENDAR
4.2.7. Delegate Declines the Meeting ๐
okay plot twist ๐ญ in this example, the "Delegate" declines the meeting request and sets the ATTENDEE property PARTSTAT parameter to DECLINED. The "Organizer" SHOULD resend the REQUEST to "C" with the PARTSTAT parameter of the "Delegate" set to DECLINED. this lets the "Delegator" know that the "Delegate" said no, and gives them a chance to either accept the request or pass it along to another CU ๐
"E" responds to "A" and "C". Note the COMMENT property that "E" uses to say why the delegation was declined ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=DELEGATED;
DELEGATED-TO="mailto:e@example.com":mailto:c@example.com
ATTENDEE;PARTSTAT=DECLINED;
DELEGATED-FROM="mailto:c@example.com":mailto:e@example.com
COMMENT:Sorry, I will be out of town at that time.
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
REQUEST-STATUS:2.0;Success
DTSTAMP:19970614T190000Z
END:VEVENT
END:VCALENDAR
"A" resends the REQUEST method to "C". "A" may also want to show that the item was delegated, using the COMMENT property ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=DECLINED;
DELEGATED-FROM="mailto:c@example.com":mailto:e@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
SUMMARY:Phone Conference
DTSTART:19970701T180000Z
DTEND:19970701T200000Z
DTSTAMP:19970614T200000Z
COMMENT:DELEGATE (ATTENDEE mailto:e@example.com) DECLINED YOUR
INVITATION
END:VEVENT
END:VCALENDAR
4.2.8. Forwarding an Event Request โจ
Okay bestie, so the protocol doesn't stop an "Attendee" from "forwarding" a "VEVENT" calendar component to other "Calendar Users" ๐. Forwarding is different from delegation because the forwarded "Calendar User" (iconic name: "Party Crasher" ๐) does not replace the person who forwarded it. Implementations are not required to add the "Party Crasher" to the "Attendee" list, so there's no guarantee the "Party Crasher" will get extra updates about the event ๐. The forwarding "Calendar User" SHOULD NOT add the "Party Crasher" to the "Attendee" list. The "Organizer" MAY add the forwarded "Calendar User" to the "Attendee" list ๐ .
4.2.9. Cancel a Group Event ๐ซ
Main character moment: "A" sets up a meeting with "B", "C", and "D" ๐ . Then "B" declines to come ๐ฌ, and "A" decides to cancel the whole thing ๐. The table below shows the messages these four would swap.
Messages related to a previously canceled event ("SEQUENCE" property value is less than the "SEQUENCE" property value of the "CANCEL" message) MUST be ignored ๐. Don't be the one who replies to an old canceled event, periodt ๐ .
+-------------+---------------------+-------------------------------+
| Action | Organizer | Attendee |
+-------------+---------------------+-------------------------------+
| Initiate a | "A" sends a REQUEST | |
| meeting | message to "B", | |
| request | "C", and "D". | |
| | | |
| Decline the | | "B" sends a REPLY message to |
| meeting | | "A" with its PARTSTAT |
| request | | parameter set to DECLINED. |
| | | |
| Cancel the | "A" sends a CANCEL | |
| meeting | message to "B", | |
| | "C", and "D". | |
+-------------+---------------------+-------------------------------+
Here's how "A" cancels the event ๐:
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:CANCEL
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;CUTYPE=INDIVIDUAL;mailto:a@example.com
ATTENDEE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;CUTYPE=INDIVIDUAL:mailto:c@example.com
ATTENDEE;CUTYPE=INDIVIDUAL:mailto:d@example.com
COMMENT:Mr. B cannot attend. It's raining. Lets cancel.
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:1
STATUS:CANCELLED
DTSTAMP:19970613T190000Z
END:VEVENT
END:VCALENDAR
4.2.10. Removing Attendees ๐
"A" wants to remove "B" from the meeting ๐ โโ๏ธ. To do that, "A" sends a "CANCEL" to "B" and takes "B" off the "Attendee" list in the master copy of the event, lowkey a clean exit ๐ง.
+--------------------+-----------------------------------+----------+
| Action | Organizer | Attendee |
+--------------------+-----------------------------------+----------+
| Remove "B" as an | "A" sends a CANCEL message to | |
| Attendee | "B". | |
| | | |
| Update the master | "A" optionally sends the updated | |
| copy of the event | event to the remaining Attendees. | |
+--------------------+-----------------------------------+----------+
The original meeting had "A", "B", "C", and "D" ๐ฏ. In the example below, "A" sends the "CANCEL" to "B". Heads up: the "STATUS" property is left out here ๐. That's used when the meeting itself is cancelled, not when someone is just being removed from the event.
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:CANCEL
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE:mailto:b@example.com
COMMENT:You're off the hook for this meeting
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:19970613T193000Z
SEQUENCE:1
END:VEVENT
END:VCALENDAR
Here's the updated master copy ๐. The "Organizer" MAY resend the updated event to the remaining "Attendees" โจ. Notice that "B" is gone ๐ .
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;CUTYPE=INDIVIDUAL:mailto:c@example.com
ATTENDEE;CUTYPE=INDIVIDUAL:mailto:d@example.com
ATTENDEE;CUTYPE=ROOM:mailto:cr_big@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;
RSVP=FALSE:mailto:e@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T203000Z
SUMMARY:Phone Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:2
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.2.11. Replacing the Organizer ๐
This one's a whole plot ๐ญ. "A" is the "Organizer" for a recurring meeting with "B", "C", and "D". Then "A" gets a new job offer in another country and totally goes dark, leaving no forwarding address and no way to reach them ๐. The other "Attendees" find out what happened through out-of-band communication, and they agree that "B" should take over as the new "Organizer". So "B" sends out a new version of the event and removes "A" from it ๐ซถ.
When the "Organizer" is replaced, the "SEQUENCE" property value MUST be incremented ๐ฅ. No skipping!
Here's the message "B" sends to "C" and "D" ๐ฆ:
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:b@example.com
ATTENDEE;ROLE=CHAIR;STATUS=ACCEPTED:mailto:b@example.com
ATTENDEE;CUTYPE=INDIVIDUAL:mailto:c@example.com
ATTENDEE;CUTYPE=INDIVIDUAL:mailto:d@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T203000Z
RRULE:FREQ=WEEKLY
SUMMARY:Phone Conference
UID:123456@example.com
SEQUENCE:1
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.3. Busy Time Examples ๐
Busy time objects can be used in a few different ways ๐ง . First, a CU can ask another CU for busy time over a specific range of time, and that request can be answered with a busy time "REPLY". Or, a CU can just publish their busy time for a given interval and point other CUs to where it lives ๐. The examples below show both scenarios.
4.3.1. Publish Busy Time ๐ข
Individual "A" publishes busy time for one week ๐๏ธ.
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
METHOD:PUBLISH
BEGIN:VFREEBUSY
DTSTAMP:19980101T124100Z
ORGANIZER:mailto:a@example.com
DTSTART:19980101T124200Z
DTEND:19980108T124200Z
FREEBUSY:19980101T180000Z/19980101T190000Z
FREEBUSY:19980103T020000Z/19980103T050000Z
FREEBUSY:19980107T020000Z/19980107T050000Z
FREEBUSY:19980113T000000Z/19980113T010000Z
FREEBUSY:19980115T190000Z/19980115T200000Z
FREEBUSY:19980115T220000Z/19980115T230000Z
FREEBUSY:19980116T013000Z/19980116T043000Z
END:VFREEBUSY
END:VCALENDAR
4.3.2. Request Busy Time ๐
Individual "A" asks individuals "B" and "C" for their busy time, and both of them reply with busy time data for "A" ๐. The table shows the messages that get swapped.
+---------------------+--------------------+------------------------+
| Action | Organizer | Attendee |
+---------------------+--------------------+------------------------+
| Initiate a busy | "A" sends REQUEST | |
| time request | message to "B" and | |
| | "C". | |
| | | |
| Reply to the BUSY | | "B" sends a REPLY |
| request with BUSY | | message to "A" with |
| time data | | busy time data. |
+---------------------+--------------------+------------------------+
"A" sends a "REQUEST" to "B" and "C" for busy time ๐.
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VFREEBUSY
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
DTSTAMP:19970613T190000Z
DTSTART:19970701T080000Z
DTEND:19970701T200000
UID:calsrv.example.com-873970198738777@example.com
END:VFREEBUSY
END:VCALENDAR
4.3.3. Reply to a Busy Time Request ๐
"B" sends a "REPLY" method type of a "VFREEBUSY" calendar component back to "A" ๐ฆ.
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VFREEBUSY
ORGANIZER:mailto:a@example.com
ATTENDEE:mailto:b@example.com
DTSTART:19970701T080000Z
DTEND:19970701T200000Z
UID:calsrv.example.com-873970198738777@example.com
FREEBUSY:19970701T090000Z/PT1H,19970701T140000Z/PT30M
DTSTAMP:19970613T190030Z
END:VFREEBUSY
END:VCALENDAR
"B" is busy from 09:00 to 10:00 and from 14:00 to 14:30 ๐.
4.4. Recurring Event and Time Zone Examples ๐ธ
4.4.1. A Recurring Event Spanning Time Zones โจ
okay so this one is a weekly phone conference ๐ and the "Attendees" are each in a totally different time zone ๐ bestie, it's giving global squad energy ๐ซถ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America-SanJose
TZURL:http://example.com/tz/America-SanJose
BEGIN:STANDARD
DTSTART:19671029T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
TZNAME:PST
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19870405T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
TZNAME:PDT
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;
CUTYPE=INDIVIDUAL:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:b@example.fr
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:c@example.jp
DTSTAMP:19970613T190030Z
DTSTART;TZID=America-SanJose:19970701T140000
DTEND;TZID=America-SanJose:19970701T150000
RRULE:FREQ=WEEKLY;COUNT=20;WKST=SU;BYDAY=TU
RDATE;TZID=America-SanJose:19970910T140000
EXDATE;TZID=America-SanJose:19970909T140000
EXDATE;TZID=America-SanJose:19971028T140000
SUMMARY:Weekly Phone Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
okay so the first component in this iCalendar object is the time zone component ๐ฐ๏ธ and the "DTSTART" date lines up with the first instance of the "RRULE" property ๐
the recurring meeting is defined in one particular time zone, presumably the originator's ๐ค but each "Attendee"'s client is the one that has to work out the recurrence time in that "Attendee's" time zone. that's on them, not the organizer ๐ซถ
the repeating event kicks off on Tuesday, July 1, 1997 at 2:00pm PDT (UTC-7) ๐ธ "Attendee" B@example.fr is in France, where the local time on this date is 9 hours ahead of PDT, or 23:00 CEST (UTC+2) ๐ฅ and "Attendee" C@example.jp is in Japan, where local time is 16 hours ahead of PDT, or Wednesday, July 2 at 06:00 JST (UTC+9) ๐ฃ the day flip is literally so real ๐ the event repeats weekly on Tuesdays (in PST/PDT). the "RRULE" property results in 20 instances. the last instance falls on Tuesday, November 11, 1997 2:00pm PST. the "RDATE" property adds another instance: WED, 10-SEP-1997 2:00 PM PDT โจ
there are also two exception dates to the recurrence rule ๐ the first one is:
- TUE, 09-SEP-1997 14:00 PDT (UTC-7)
- TUE, 09-SEP-1997 23:00 CEST (UTC+2)
- WED, 10-SEP-1997 06:00 JST (UTC+9)
and the second is:
- TUE, 28-OCT-1997 14:00 PST (UTC-8)
- TUE, 28-OCT-1997 23:00 CET (UTC+1)
- WED, 29-OCT-1997 07:00 JST (UTC+9)
4.4.2. Modify a Recurring Instance ๐ฆ
in this example, the "Organizer" sets up a recurring meeting ๐ later on, the "Organizer" changes one instance of the event by changing the "DTSTART" property. watch the "RECURRENCE-ID" property and the "SEQUENCE" property in the second request, they're the stars here ๐
Original Request:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
SEQUENCE:0
RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970601T210000Z
DTEND:19970601T220000Z
LOCATION:Conference Call
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
the event request below changes the time of one specific instance ๐ it moves the July 1st instance to July 3rd ๐
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID:19970701T210000Z
SEQUENCE:1
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970703T210000Z
DTEND:19970703T220000Z
LOCATION:Conference Call
DTSTAMP:19970626T093000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.4.3. Cancel an Instance ๐ซ
in this example, the "Organizer" of a recurring event deletes the August 1st instance ๐๏ธ just that one, the rest of the series stays put ๐
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
RECURRENCE-ID:19970801T210000Z
SEQUENCE:2
STATUS:CANCELLED
DTSTAMP:19970721T093000Z
END:VEVENT
END:VCALENDAR
4.4.4. Cancel a Recurring Event ๐
in this example, the "Organizer" wants to cancel the entire recurring event, exceptions and all ๐ญ whole series, gone, no notes ๐ซ
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DTSTAMP:19970721T103000Z
STATUS:CANCELLED
SEQUENCE:3
END:VEVENT
END:VCALENDAR
4.4.5. Change All Future Instances ๐
this one is a glow-up for the meeting location ๐๏ธ it moves the meeting from a conference call to Seattle, starting September 1 and carrying on through every future instance ๐
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
SEQUENCE:3
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DESCRIPTION:IETF-C&S Discussion
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970901T210000Z
DTEND:19970901T220000Z
LOCATION:Building 32, Microsoft, Seattle, WA
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.4.6. Add a New Instance to a Recurring Event ๐ง
this example adds a one-time extra instance to the recurring event โจ the "Organizer" adds a second July meeting on the 15th ๐
BEGIN:VCALENDAR
METHOD:ADD
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:4
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970715T210000Z
DTEND:19970715T220000Z
LOCATION:Conference Call
DTSTAMP:19970629T093000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.4.7. Add a New Series of Instances to a Recurring Event ๐ฅ
the setup here is an ongoing meeting that was originally set up to happen every Tuesday ๐ later, the "Organizer" decides the meetings need to be on Tuesdays and Thursdays. main character glow-up ๐
The original event:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:0
RRULE:WKST=SU;BYDAY=TU;FREQ=WEEKLY
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980303T210000Z
DTEND:19980303T220000Z
LOCATION:The White Room
DTSTAMP:19980301T093000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
the whole event can be rescheduled with a "REQUEST" ๐ you do this by using the "UID" of the event you're rescheduling and including the modified "RRULE". heads up though, since this reschedules the entire event, any instance-specific information gets lost ๐ญ unless you explicitly include it with the update "REQUEST" ๐ซถ
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:7
RRULE:WKST=SU;BYDAY=TU,TH;FREQ=WEEKLY
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980303T210000Z
DTEND:19980303T220000Z
DTSTAMP:19980303T193000Z
LOCATION:The White Room
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.4.8. Refreshing a Recurring Event โจ
okay so this section is all about what an "Organizer" does when an "Attendee" sends a "REFRESH" after a bunch of instance-specific edits ๐ to convey every single instance-specific change, the "Organizer" must provide the latest event description and the relevant instances, no skipping ๐ the first three examples show the whole history: the original "VEVENT" request, the instance changes, and then finally the "REFRESH" ๐
Original Request:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:0
RDATE:19980304T180000Z
RDATE:19980311T180000Z
RDATE:19980318T180000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980304T180000Z
DTEND:19980304T200000Z
DTSTAMP:19980303T193000Z
LOCATION:Conference Room A
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
Organizer changes 2nd instance location and time:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:1
RECURRENCE-ID:19980311T180000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980311T160000Z
DTEND:19980311T180000Z
DTSTAMP:19980306T193000Z
LOCATION:The Small conference room
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
Organizer adds a 4th instance of the meeting using the ADD method. ๐ง
BEGIN:VCALENDAR
METHOD:ADD
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:2
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980315T180000Z
DTEND:19980315T200000Z
DTSTAMP:19980307T193000Z
LOCATION:Conference Room A
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
bestie, so when "B" asks for a "REFRESH", "A" replies with this ๐ซถ it captures all the instance-specific data in one go. Both the initial request and an extra "VEVENT" holding the instance-specific data are included. And because they're both the same type (they're both "VEVENTS"), they can ride together in the same iCalendar object. iconic efficiency ๐
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:2
RDATE:19980304T180000Z
RDATE:19980311T160000Z
RDATE:19980315T180000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980304T180000Z
DTEND:19980304T200000Z
DTSTAMP:19980303T193000Z
LOCATION:Conference Room A
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
SEQUENCE:2
UID:123456789@example.com
RECURRENCE-ID:19980311T160000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980311T160000Z
DTEND:19980304T180000Z
DTSTAMP:19980306T193000Z
LOCATION:The Small conference room
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
4.4.9. Counter an Instance of a Recurring Event ๐ธ
in this one, an "Attendee" counters the "DTSTART" property of the proposed second July meeting. it's giving "can we move it?" energy ๐
BEGIN:VCALENDAR
METHOD:COUNTER
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID:19970715T210000Z
SEQUENCE:4
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;RSVP=TRUE:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970715T220000Z
DTEND:19970715T230000Z
LOCATION:Conference Call
COMMENT:May we bump this by an hour? I have a conflict
DTSTAMP:19970629T094000Z
END:VEVENT
END:VCALENDAR
4.4.10. Error Reply to a Request ๐
the following example is a meeting proposal with an unsupported property and a bad property in it. drama ๐ญ
Original Request:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
SEQUENCE:0
RRULE:FREQ=MONTHLY;BYMONTHDAY=1
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970601T210000Z
DTEND:19970601T220000Z
DTSTAMP:19970602T094000Z
LOCATION:Conference Call
STATUS:CONFIRMED
FOO:BAR
END:VEVENT
END:VCALENDAR
"B" replies to say that RRULE isn't supported and that an unrecognized property showed up. ๐
โโ๏ธ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE:mailto:b@example.com
REQUEST-STATUS:3.0;Invalid Property Name;FOO
UID:guid-1@example.com
SEQUENCE:0
DTSTAMP:19970603T094000Z
END:VEVENT
END:VCALENDAR
4.5. Group To-Do Examples ๐
okay so "A" makes a group task that "A", "B", "C", and "D" are all going to work on ๐ง "B" confirms they accepted, "C" declines, and "D" tentatively accepts. the table below shows the messages going back and forth. then "A" sends a "REQUEST" to get everyone's status, and the replies show each "Attendee's" completion status. main character energy ๐
+--------------+------------------------+---------------------------+
| Action | Organizer | Attendee |
+--------------+------------------------+---------------------------+
| Initiate a | "A" sends a REQUEST | |
| to-do | message to "B", "C", | |
| request | and "D". | |
| | | |
| Accept the | | "B" sends a REPLY message |
| to-do | | to "A" with its PARTSTAT |
| request | | parameter set to |
| | | ACCEPTED. |
| | | |
| Decline the | | "C" sends a REPLY message |
| to-do | | to "A" with its PARTSTAT |
| request | | parameter set to |
| | | DECLINED. |
| | | |
| Tentatively | | "D" sends a REPLY message |
| accept the | | to "A" with its PARTSTAT |
| to-do | | parameter set to |
| request | | TENTATIVE. |
| | | |
| Check | "A" sends a REQUEST | |
| Attendee | message to "B" and "D" | |
| completion | with current | |
| status | information. | |
| | | |
| Attendee | | "B" sends a REPLY message |
| indicates | | indicating percent |
| percent | | complete. |
| complete | | |
| | | |
| Attendee | | "D" sends a REPLY message |
| indicates | | indicating completion. |
| completion | | |
+--------------+------------------------+---------------------------+
4.5.1. A VTODO Request ๐
this is a sample "REQUEST" for a "VTODO" calendar component that "A" sends to "B", "C", and "D". โจ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DTSTART:19970701T170000Z
DUE:19970722T170000Z
PRIORITY:1
SUMMARY:Create the requirements document
UID:calsrv.example.com-873970198738777-00@example.com
SEQUENCE:0
DTSTAMP:19970717T200000Z
STATUS:NEEDS-ACTION
END:VTODO
END:VCALENDAR
4.5.2. A VTODO Reply ๐ซถ
"B" accepts the to-do. yay ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
UID:calsrv.example.com-873970198738777-00@example.com
COMMENT:I'll send you my input by email
SEQUENCE:0
DTSTAMP:19970717T203000Z
REQUEST-STATUS:2.0;Success
END:VTODO
END:VCALENDAR
"B" could have declined the "VTODO" or indicated tentative acceptance by setting the "PARTSTAT" property parameter sequence to "DECLINED" or "TENTATIVE", respectively. ๐ฆ
4.5.3. A VTODO Request for Updated Status ๐
"A" requests status from all "Attendees". ๐ฅ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:d@example.com
UID:calsrv.example.com-873970198738777-00@example.com
SUMMARY:Create the requirements document
PRIORITY:1
SEQUENCE:0
STATUS:IN-PROCESS
DTSTART:19970701T170000Z
DTSTAMP:19970717T230000Z
END:VTODO
END:VCALENDAR
4.5.4. A Reply: Percent-Complete ๐
okay so this one is a reply where B tells A which task they're working on and that they're 75% done with their part ๐ฅ. the vibe is "almost there, bestie" โจ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=IN-PROCESS:mailto:b@example.com
PERCENT-COMPLETE:75
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:19970717T233000Z
SEQUENCE:0
END:VTODO
END:VCALENDAR
4.5.5. A Reply: Completed โ
this is giving "D is DONE" ๐ D replies to say their part of the assignment is completed. no notes, just slay.
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=COMPLETED:mailto:d@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:19970717T233000Z
SEQUENCE:0
END:VTODO
END:VCALENDAR
4.5.6. An Updated VTODO Request ๐
so "Organizer" "A" resends the "VTODO" calendar component, and this time A sets the overall completion for the whole to-do at 40% ๐. the main character of this update is clearly the percentage.
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;PARTSTAT=ACCEPTED;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;PARTSTAT=COMPLETED;CUTYPE=INDIVIDUAL:mailto:d@example.com
DTSTART:19970701T170000Z
DUE:19970722T170000Z
PRIORITY:1
SUMMARY:Create the requirements document
UID:calsrv.example.com-873970198738777-00@example.com
SEQUENCE:1
DTSTAMP:19970718T100000Z
STATUS:IN-PROCESS
PERCENT-COMPLETE:40
END:VTODO
END:VCALENDAR
4.5.7. Recurring VTODOs ๐
the next few examples are all about recurring "VTODO" calendar components, so get ready for repeat-mode energy ๐
4.5.7.1. Request for a Recurring VTODO ๐
in this one, "A" sends a recurring "VTODO" calendar component to "B" and "D" ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:d@example.com
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
DTSTART:19980101T100000Z
DUE:19980103T100000Z
SUMMARY:Send Status Reports to Area Managers
UID:calsrv.example.com-873970198738777-00@example.com
SEQUENCE:0
DTSTAMP:19970717T200000Z
STATUS:NEEDS-ACTION
PRIORITY:1
END:VTODO
END:VCALENDAR
4.5.7.2. Replying to an Instance of a Recurring VTODO ๐ฆ
here "B" gives "A" an update on just one instance of the "VTODO" calendar component. one instance, one update, zero drama โจ
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REPLY
VERSION:2.0
BEGIN:VTODO
ATTENDEE;PARTSTAT=IN-PROCESS:mailto:b@example.com
PERCENT-COMPLETE:75
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:19970717T233000Z
RECURRENCE-ID:19980101T170000Z
SEQUENCE:1
END:VTODO
END:VCALENDAR
4.6. Journal Examples ๐
this iCalendar object describes one single journal entry for October 2, 1997 ๐. the "RELATED-TO" property points back at the phone conference event where the minutes were taken, so it's basically a little callback ๐
BEGIN:VCALENDAR
METHOD:PUBLISH
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VJOURNAL
DTSTART:19971002T200000Z
DTSTAMP:19970717T233100Z
ORGANIZER:mailto:a@example.com
SUMMARY:Phone conference minutes
DESCRIPTION:The editors meeting was held on October 1, 1997.
Details are in the attached document.
UID:0981234-1234234-2410@example.com
RELATED-TO:0981234-1234234-2402-35@example.com
ATTACH:ftp://ftp.example.com/pub/ed/minutes100197.txt
END:VJOURNAL
END:VCALENDAR
4.7. Other Examples ๐ง
4.7.1. Event Refresh ๐
here we refresh the event whose "UID" property value is "guid-1-12345@example.com" ๐
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REFRESH
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
UID:guid-1-12345@example.com
DTSTAMP:19970603T094000
END:VEVENT
END:VCALENDAR
4.7.2. Bad RECURRENCE-ID ๐
okay this one is a little spicy, so pay attention ๐. component instances are identified by the combination of "UID", "RECURRENCE-ID", and "SEQUENCE" ๐. when an "Organizer" sends an iTIP message to an "Attendee", there are three cases where an instance can't be found:
- The component with the referenced "UID" and "RECURRENCE-ID" has been found, but the "SEQUENCE" number in the calendar store does not match the one in the iTIP message.
- The component with the referenced "UID" has been found and the "SEQUENCE" numbers match, but the "RECURRENCE-ID" can't be found.
- The "UID" and "SEQUENCE" numbers are found, but the CUA does not support recurrences.
in case (1), two things can happen ๐ค. if the "SEQUENCE" number of the "Attendee's" instance is larger than the one in the "Organizer's" message, then the "Attendee" is getting an out-of-sequence message and MUST ignore it ๐ โโ๏ธ. if the "SEQUENCE" number of the "Attendee's" instance is smaller, then the "Organizer" is sending a newer version of the component, and the "Attendee's" version needs updating. since one or more updates were missed, the "Attendee" SHOULD send a "REFRESH" message to the "Organizer" to get an updated version of the event ๐.
in case (2), something has gone wrong ๐ญ. both the "Organizer" and the "Attendee" should have the same instances, but the "Attendee" doesn't have the referenced instance. in this situation, the "Attendee" SHOULD send a "REFRESH" to the "Organizer" to get an updated version of the event.
in case (3), the CUA's limitations make it impossible to match any instance other than the single instance scheduled ๐ซ . so in this case the "Attendee" need not send a "REFRESH" to the "Organizer".
the example below shows a sequence where an "Attendee" sends a "REFRESH" to the "Organizer" ๐ฌ
+-------------------------+--------------------+--------------------+
| Action | Organizer | Attendee |
+-------------------------+--------------------+--------------------+
| Update an instance | "A" sends REQUEST | |
| request | message to "B". | |
| | | |
| Attendee requests | | "B" sends a |
| refresh because | | REFRESH message to |
| RECURRENCE-ID was not | | "A". |
| found | | |
| | | |
| Refresh the entire | "A" sends the | |
| event | latest copy of the | |
| | event to "B" | |
| | | |
| Attendee handles the | | "B" updates to the |
| request and updates the | | latest copy of the |
| instance | | meeting. |
+-------------------------+--------------------+--------------------+
Request from "A":
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:example-12345@example.com
SEQUENCE:3
RRULE:FREQ=WEEKLY
RDATE;VALUE=PERIOD:19970819T210000Z/199700819T220000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
DESCRIPTION:IETF-C&S Conference Call
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970801T210000Z
DTEND:19970801T220000Z
RECURRENCE-ID:19970809T210000Z
DTSTAMP:19970726T083000
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
"B" has the event with "UID" property "example-12345@example.com", but "B's" "SEQUENCE" property value is "1" and the event doesn't have an instance at the specified recurrence time. so basically "B" has missed at least one update and needs a fresh copy of the event ๐ฉ. "B" asks for the latest copy with this refresh message:
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REFRESH
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE:mailto:b@example.com
UID:example-12345@example.com
DTSTAMP:19970603T094000
END:VEVENT
END:VCALENDAR
5. Application Protocol Fallbacks โจ
5.1. Partial Implementation ๐ซถ
applications that support this specification aren't required to support the entire protocol, and that's totally valid ๐. the following describes how methods and properties SHOULD "fallback" in applications that don't support the complete protocol. if a method or property isn't addressed in this section, it may be ignored ๐ธ.
more parts coming, so stay tuned bestie ๐ฆ
5.1.1. Event-Related Fallbacks โจ
okay bestie, let's start with the event fallbacks ๐ this first table is all about the methods and what to do when you're not fully on board with one ๐
+----------------+--------------------------------------------------+
| Method | Fallback |
+----------------+--------------------------------------------------+
| PUBLISH | Required |
| REQUEST | PUBLISH |
| REPLY | Required |
| ADD | Required if recurrences supported; otherwise, |
| | reply with a REQUEST-STATUS "2.8; Success, |
| | repeating event ignored. Scheduled as a single |
| | component", and schedule as a single component. |
| CANCEL | Required |
| REFRESH | Required |
| COUNTER | Reply with "Not Supported". |
| DECLINECOUNTER | Required if COUNTER is implemented for VEVENTs; |
| | otherwise, reply with "Not Supported". |
+----------------+--------------------------------------------------+
next up are the iCalendar properties ๐ these ones are kinda the basics, so it's giving simple vibes
+-----------------+-------------------------------------------------+
| iCalendar | Fallback |
| Property | |
+-----------------+-------------------------------------------------+
| CALSCALE | Ignore - assume GREGORIAN. |
| PRODID | Ignore |
| METHOD | Required as described in the Method list above. |
| VERSION | Ignore |
+-----------------+-------------------------------------------------+
now the event-related components ๐ง VALARM and VTIMEZONE are the stars of this one, and VTIMEZONE has a little condition attached
+-----------------+-------------------------------------------------+
| Event-Related | Fallback |
| Components | |
+-----------------+-------------------------------------------------+
| VALARM | Reply with "Not Supported". |
| VTIMEZONE | Required if any DateTime value refers to a time |
| | zone. |
+-----------------+-------------------------------------------------+
and last but absolutely not least, the component properties ๐ this is the biggest table and it's literally got everything, from ATTACH to X- properties ๐ซถ the one to watch is RRULE, because the fallback has a MUST in it, so pay attention to that one ๐
+-----------------+-------------------------------------------------+
| Component | Fallback |
| Property | |
+-----------------+-------------------------------------------------+
| ATTACH | Ignore |
| ATTENDEE | Required if METHOD is REQUEST; otherwise, |
| | ignore. |
| CATEGORIES | Ignore |
| CLASS | Ignore |
| COMMENT | Ignore |
| COMPLETED | Ignore |
| CONTACT | Ignore |
| CREATED | Ignore |
| DESCRIPTION | Ignore |
| DURATION | Required |
| DTSTAMP | Required |
| DTSTART | Required |
| DTEND | Required |
| EXDATE | Ignore |
| GEO | Ignore |
| LAST-MODIFIED | Ignore |
| LOCATION | Required |
| ORGANIZER | Required if METHOD is REQUEST; otherwise, |
| | ignore. |
| PRIORITY | Ignore |
| RELATED-TO | Ignore |
| RDATE | Ignore |
| RRULE | Ignore - assume the first instance occurs on |
| | the DTSTART property. If implemented, |
| | VTIMEZONE MUST also be implemented. |
| RECURRENCE-ID | Required if RRULE is implemented; otherwise, |
| | ignore. |
| REQUEST-STATUS | Required |
| RESOURCES | Ignore |
| SEQUENCE | Required |
| STATUS | Ignore |
| SUMMARY | Ignore |
| TRANSP | Required if FREEBUSY is implemented; otherwise, |
| | ignore. |
| URL | Ignore |
| UID | Required |
| X- | Ignore |
+-----------------+-------------------------------------------------+
5.1.2. Free/Busy-Related Fallbacks ๐ฆ
ooh, now we're switching gears to free/busy ๐ this first table covers the methods, and the fallback here is pretty consistent across all three of them
+---------+---------------------------------------------------------+
| Method | Fallback |
+---------+---------------------------------------------------------+
| PUBLISH | Required if freebusy lookups are supported; otherwise, |
| | reply with a REQUEST-STATUS "3.14; Unsupported |
| | capability". |
| REQUEST | Required if freebusy lookups are supported; otherwise, |
| | reply with a REQUEST-STATUS "3.14; Unsupported |
| | capability". |
| REPLY | Required if freebusy lookups are supported; otherwise, |
| | reply with a REQUEST-STATUS "3.14; Unsupported |
| | capability". |
+---------+---------------------------------------------------------+
the iCalendar properties table here is the same as the one we saw earlier, so no new surprises ๐ธ
+-----------------+-------------------------------------------------+
| iCalendar | Fallback |
| Property | |
+-----------------+-------------------------------------------------+
| CALSCALE | Ignore - assume GREGORIAN. |
| PRODID | Ignore |
| METHOD | Required as described in the Method list above. |
| VERSION | Ignore |
+-----------------+-------------------------------------------------+
and finally the component properties for free/busy ๐ notice that DURATION and REQUEST-STATUS are ignored in this one, but FREEBUSY is required, which is so iconic for it ๐ฅ
+-----------------+-------------------------------------------------+
| Component | Fallback |
| Property | |
+-----------------+-------------------------------------------------+
| ATTENDEE | Required if METHOD is REQUEST; otherwise, |
| | ignore. |
| COMMENT | Ignore |
| CONTACT | Ignore |
| DTEND | Required |
| DTSTAMP | Required |
| DTSTART | Required |
| DURATION | Ignore |
| FREEBUSY | Required |
| ORGANIZER | Required if METHOD is REQUEST; otherwise, |
| | ignore. |
| REQUEST-STATUS | Ignore |
| UID | Required |
| URL | Ignore |
| X- | Ignore |
+-----------------+-------------------------------------------------+
5.1.3. To-Do-Related Fallbacks โจ
okay bestie, to-dos get their own fallback table ๐ here's how each METHOD falls back ๐
+----------------+--------------------------------------------------+
| Method | Fallback |
+----------------+--------------------------------------------------+
| PUBLISH | Required |
| REQUEST | PUBLISH |
| REPLY | Required |
| ADD | Required if recurrences supported; otherwise, |
| | reply with a REQUEST-STATUS "2.8; Success, |
| | repeating event ignored. Scheduled as a single |
| | component", and schedule as a single component. |
| CANCEL | Required |
| REFRESH | Required |
| COUNTER | Reply with "Not Supported". |
| DECLINECOUNTER | Required if COUNTER for VTODOs is implemented; |
| | otherwise, reply with "Not Supported". |
+----------------+--------------------------------------------------+
the iCalendar properties are next, and honestly these are pretty chill ๐ธ
+-----------------+-------------------------------------------------+
| iCalendar | Fallback |
| Property | |
+-----------------+-------------------------------------------------+
| CALSCALE | Ignore - assume GREGORIAN. |
| PRODID | Ignore |
| METHOD | Required as described in the Method list above. |
| VERSION | Ignore |
+-----------------+-------------------------------------------------+
then the to-do components, which is giving VALARM and VTIMEZONE vibes ๐ฐ๏ธ
+-----------------+-------------------------------------------------+
| To-Do-Related | Fallback |
| Components | |
+-----------------+-------------------------------------------------+
| VALARM | Reply with "Not Supported". |
| VTIMEZONE | Required if any DateTime value refers to a time |
| | zone. |
+-----------------+-------------------------------------------------+
and last but DEFINITELY not least, the component properties. this one is long bestie, grab a snack ๐ฟ๐ซถ
+------------------+------------------------------------------------+
| Component | Fallback |
| Property | |
+------------------+------------------------------------------------+
| ATTACH | Ignore |
| ATTENDEE | Required if METHOD is REQUEST; otherwise, |
| | ignore. |
| CATEGORIES | Ignore |
| CLASS | Ignore |
| COMMENT | Ignore |
| COMPLETED | Required |
| CONTACT | Ignore |
| CREATED | Ignore |
| DESCRIPTION | Required if METHOD is REQUEST; otherwise, |
| | ignore. |
| DUE | Required |
| DURATION | Required |
| DTSTAMP | Required |
| DTSTART | Required |
| EXDATE | Ignore - reply with "Not Supported". |
| LAST-MODIFIED | Ignore |
| LOCATION | Ignore |
| ORGANIZER | Required if METHOD is REQUEST; otherwise, |
| | ignore. |
| PERCENT-COMPLETE | Ignore |
| PRIORITY | Required |
| RECURRENCE-ID | Required if RRULE is implemented; otherwise, |
| | ignore. |
| RELATED-TO | Ignore |
| REQUEST-STATUS | Ignore |
| RDATE | Ignore |
| RRULE | Ignore - assume the first instance occurs on |
| | the DTSTART property. If implemented, |
| | VTIMEZONE MUST also be implemented. |
| RESOURCES | Ignore |
| SEQUENCE | Required |
| STATUS | Required |
| SUMMARY | Ignore |
| URL | Ignore |
| UID | Required |
| X- | Ignore |
+------------------+------------------------------------------------+
5.1.4. Journal-Related Fallbacks ๐
journals have their own fallback table too, and it's a little more relaxed about METHODs ๐ฆ
+---------+---------------------------------------------------------+
| Method | Fallback |
+---------+---------------------------------------------------------+
| PUBLISH | Implementations MAY ignore the METHOD type. The |
| | REQUEST-STATUS "3.14; Unsupported capability" MUST be |
| | returned. |
| ADD | Implementations MAY ignore the METHOD type. The |
| | REQUEST-STATUS "3.14; Unsupported capability" MUST be |
| | returned. |
| CANCEL | Implementations MAY ignore the METHOD type. The |
| | REQUEST-STATUS "3.14; Unsupported capability" MUST be |
| | returned. |
+---------+---------------------------------------------------------+
the iCalendar properties are the same vibe as before ๐
+-----------------+-------------------------------------------------+
| iCalendar | Fallback |
| Property | |
+-----------------+-------------------------------------------------+
| CALSCALE | Ignore - assume GREGORIAN. |
| PRODID | Ignore |
| METHOD | Required as described in the Method list above. |
| VERSION | Ignore |
+-----------------+-------------------------------------------------+
journal components are pretty minimal, just VTIMEZONE here ๐ฐ๏ธ
+-----------------+-------------------------------------------------+
| Journal-Related | Fallback |
| Components | |
+-----------------+-------------------------------------------------+
| VTIMEZONE | Required if any DateTime value refers to a time |
| | zone. |
+-----------------+-------------------------------------------------+
and the journal component properties, which are mostly ignored except the big requireds ๐
+-----------------+-------------------------------------------------+
| Component | Fallback |
| Property | |
+-----------------+-------------------------------------------------+
| ATTACH | Ignore |
| ATTENDEE | Ignore |
| CATEGORIES | Ignore |
| CLASS | Ignore |
| COMMENT | Ignore |
| CONTACT | Ignore |
| CREATED | Ignore |
| DESCRIPTION | Ignore |
| DTSTAMP | Required |
| DTSTART | Required |
| EXDATE | Ignore |
| LAST-MODIFIED | Ignore |
| ORGANIZER | Ignore |
| RECURRENCE-ID | Required if RRULE is implemented; otherwise, |
| | ignore. |
| RELATED-TO | Ignore |
| RDATE | Ignore |
| RRULE | Ignore - assume the first instance occurs on |
| | the DTSTART property. If implemented, |
| | VTIMEZONE MUST also be implemented. |
| SEQUENCE | Required |
| STATUS | Ignore |
| SUMMARY | Required |
| URL | Ignore |
| UID | Required |
| X- | Ignore |
+-----------------+-------------------------------------------------+
5.2. Latency Issues ๐
okay so with a store-and-forward transport, events can totally show up out of order ๐ญ like a "CANCEL" might land before the "REQUEST" it's cancelling for the calendar component. this section walks through a few of those messy scenarios ๐
5.2.1. Cancellation of an Unknown Calendar Component ๐ป
when a "CANCEL" shows up before the original "REQUEST", the calendar can't match the "UID" property of the cancellation to anything it already has, so it's lost lowkey ๐ the advice is to hold onto messages that can't be correlated and also have non-zero sequence numbers, instead of tossing them. implementations MAY age them out if no other messages arrive with the same "UID" property value and a lower sequence number โณ
5.2.2. Unexpected Reply from an Unknown Delegate ๐ญ
when an "Attendee" delegates an item to someone else, they MUST send a "REPLY" method to the "Organizer" using the "ATTENDEE" properties, so everyone knows the request was delegated and to whom ๐ this means the "Organizer" can get a "REPLY" from a CU who wasn't on the original "Attendees" list, which is a plot twist ๐ณ how to handle that is up to the implementation, but the calendaring software is expected to either accept the reply or hold it until the related "REPLY" method comes in from the "Delegator". if the version of the "REPLY" method is out of date, the "Organizer" SHOULD treat the message as a "REFRESH" message and update the "Delegate" with the correct version, as long as delegating to that delegate is acceptable ๐ซก
5.3. Sequence Number ๐ข
so under some conditions, a CUA might get requests and replies that have the same "SEQUENCE" property value ๐คฏ when that happens, the "DTSTAMP" property is the tie-breaker when two items with the same "SEQUENCE" property value get evaluated. main character tiebreaker energy โจ
6. Security Considerations ๐โจ
okay bestie, iTIP is an abstract transport protocol, which means it's gonna get bound to a real-time transport, a store-and-forward transport, and maybe other transports too ๐. The transport protocol is the one responsible for providing facilities for authentication and encryption, using standard Internet mechanisms that the sender and receiver both understand. so the security glow-up is handled at that layer ๐
6.1. Security Threats ๐ฑ
6.1.1. Spoofing the Organizer
in iTIP, the "Organizer" (or someone acting on the "Organizer's" behalf) is the only person who's allowed to change an existing "VEVENT", "VTODO", or "VJOURNAL" calendar component and republish it or send out updates to the "Attendees" ๐ โโ๏ธ. but someone who isn't the "Organizer" can totally build an iCalendar object that maliciously changes or cancels one of those components, then republish it or send it to the "Attendees." that's a whole villain arc ๐
6.1.2. Spoofing the Attendee
in iTIP, an "Attendee" of a "VEVENT" or "VTODO" calendar component (or someone working on the "Attendee's" behalf) is the only person who can update any parameter tied to their "ATTENDEE" property and send it back to the "Organizer" ๐. however, an iCalendar object that maliciously changes the "ATTENDEE" parameters can be made by someone who isn't the real "Attendee" and then sent to the "Organizer." not the vibe ๐
6.1.3. Unauthorized Replacement of the Organizer
there are gonna be times when "Attendees" of an event or to-do decide, using out-of-band mechanisms, that the "Organizer" has to be replaced ๐. when the new "Organizer" sends out the updated "VEVENT" or "VTODO," the "Attendee's" CUA will notice that the "Organizer" has changed. the problem? it has no way of knowing whether or not that change was actually agreed on by everyone ๐ฌ
6.1.4. Eavesdropping and Data Integrity
the iCalendar object is built out of human-readable clear text ๐. so anything inside an iCalendar object can be read and/or changed by unauthorized people while it's in transit. literally wide open ๐ซฃ
6.1.5. Flooding a Calendar
implementations could give you a way to automatically pull "REQUEST" methods into a calendar ๐. that opens the door for a calendar to get flooded with requests, which basically blocks off all of the calendar's free time. the calendar's whole personality is gone ๐
6.1.6. Unauthorized REFRESH Requests
it's possible for an "Organizer" to get a "REFRESH" request from someone who is not an "Attendee" of an event or to-do ๐. only "Attendees" of an event or to-do are authorized to receive replies to "REFRESH" requests. replying to these requests for anyone who isn't an "Attendee" may be a security problem ๐จ
6.2. Recommendations ๐ซถ
for an application where the information is sensitive or critical, and the network has a high probability of attack, iTIP transactions SHOULD be encrypted and authenticated ๐. this helps mitigate spoofing, eavesdropping, and malicious changes in transit. protect your plans, bestie ๐
6.2.1. Securing iTIP transactions
iTIP transport bindings MUST provide a mechanism to enable authentication of the sender's identity, as well as privacy and integrity of the data being transmitted ๐ก๏ธ. this lets the receiver of a signed iCalendar object verify who the sender is. that sender can then be correlated to an "ATTENDEE" property in the iCalendar object. if the correlation is made and the sender is authorized to make the requested change or update, then the operation may proceed โ . it also lets the message be encrypted so nobody can read the contents in transit. the iTIP transport binding documents go into detail about how this works ๐
6.2.2. Implementation Controls
the threat of unauthorized replacement of the "Organizer" SHOULD be mitigated by a calendar system that uses this protocol. it does that by providing controls or alerts that make "Calendar Users" aware of "Organizer" changes, and by letting them decide whether or not the request should be honored ๐ฆ.
the threat of flooding a calendar SHOULD be mitigated by a calendar system that uses this protocol, by providing controls that limit the acceptable sources for iTIP transactions. it can also limit the size of messages and the volume of traffic, by source ๐งฑ.
the threat of unauthorized "REFRESH" requests SHOULD be mitigated by a calendar system that uses this protocol, by providing controls or alerts that let "Calendar Users" decide whether or not the request should be honored ๐โโ๏ธ. an implementation MAY decide to keep track, for audit or historical purposes, of "Calendar Users" who were part of an "Attendee" list and were later uninvited ๐. similar controls or alerts should be provided when a "REFRESH" request comes in from these "Calendar Users" too โจ
6.2.3. Access Controls and Filtering
in a lot of environments, there could be restrictions on who is allowed to schedule with whom, and on who the allowed delegates are for particular "Calendar Users" ๐๏ธ.
iTIP transport bindings SHOULD provide mechanisms for access controls or filtering, so iTIP transactions only happen between authorized "Calendar Users" ๐. that includes stopping one "Calendar User" from scheduling with another, or stopping one "Calendar User" from delegating to another ๐ซ
6.3. Privacy Issues ๐
the "Organizer" might want to keep "Attendees" from knowing which other "Attendees" are participating in an event or to-do ๐คซ. the "Organizer" gets to choose between sending single iTIP messages with a full list of "Attendees," or sending an iTIP message to each "Attendee" with only that one "Attendee" listed ๐
7. IANA Considerations ๐งพ
7.1. Registration Template for REQUEST-STATUS Values
this specification updates [RFC5545] by adding a "REQUEST-STATUS" value registry to the iCalendar Elements registry ๐ธ.
a "REQUEST-STATUS" value is defined by filling out the following template ๐.
Status Code: Hierarchical, numeric return status code, following
the rules defined in Section 3.8.8.3 of [RFC5545].
Status Description: Textual status description. A short but
clear description of the error.
Status Exception Data: Textual exception data. A short but clear
description of what might appear in this field.
Description: Describe the underlying cause for this status code
value.
7.2. Additions to iCalendar METHOD Registry ๐ซ
this document defines the following values for the iCalendar METHOD property, using the values template from Section 8.2.6 of [RFC5545]. these should be added to the Methods Registry defined in Section 8.3.12 of [RFC5545]:
7.2.1. METHOD:PUBLISH
Value: PUBLISH
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.2.2. METHOD:REQUEST
Value: REQUEST
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.2.3. METHOD:REPLY
Value: REPLY
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.2.4. METHOD:ADD
Value: ADD
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.2.5. METHOD:CANCEL
Value: CANCEL
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.2.6. METHOD:REFRESH
Value: REFRESH
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.2.7. METHOD:COUNTER
Value: COUNTER
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.2.8. METHOD:DECLINECOUNTER
Value: DECLINECOUNTER
Purpose: Standard iTIP METHOD value.
Conformance: Only used with the METHOD property.
Examples: See this RFC.
7.3. REQUEST-STATUS Value Registry ๐
new "REQUEST-STATUS" values can be registered using the process described in Section 8.2.1 of [RFC5545] ๐.
the following table is used to initialize the "REQUEST-STATUS" value registry ๐.
+-------------+---------+--------------------------+
| Status Code | Status | Reference |
+-------------+---------+--------------------------+
| 2.0 | Current | RFC 5546, Section 3.6.1 |
| 2.1 | Current | RFC 5546, Section 3.6.2 |
| 2.2 | Current | RFC 5546, Section 3.6.3 |
| 2.3 | Current | RFC 5546, Section 3.6.4 |
| 2.4 | Current | RFC 5546, Section 3.6.5 |
| 2.5 | Current | RFC 5546, Section 3.6.6 |
| 2.6 | Current | RFC 5546, Section 3.6.7 |
| 2.7 | Current | RFC 5546, Section 3.6.8 |
| 2.8 | Current | RFC 5546, Section 3.6.9 |
| 2.9 | Current | RFC 5546, Section 3.6.10 |
| 2.10 | Current | RFC 5546, Section 3.6.11 |
| 2.11 | Current | RFC 5546, Section 3.6.12 |
| 3.0 | Current | RFC 5546, Section 3.6.13 |
| 3.1 | Current | RFC 5546, Section 3.6.14 |
| 3.2 | Current | RFC 5546, Section 3.6.15 |
| 3.3 | Current | RFC 5546, Section 3.6.16 |
| 3.4 | Current | RFC 5546, Section 3.6.17 |
| 3.5 | Current | RFC 5546, Section 3.6.18 |
| 3.6 | Current | RFC 5546, Section 3.6.19 |
| 3.7 | Current | RFC 5546, Section 3.6.20 |
| 3.8 | Current | RFC 5546, Section 3.6.21 |
| 3.9 | Current | RFC 5546, Section 3.6.22 |
| 3.10 | Current | RFC 5546, Section 3.6.23 |
| 3.11 | Current | RFC 5546, Section 3.6.24 |
| 3.12 | Current | RFC 5546, Section 3.6.25 |
| 3.13 | Current | RFC 5546, Section 3.6.26 |
| 3.14 | Current | RFC 5546, Section 3.6.27 |
| 4.0 | Current | RFC 5546, Section 3.6.28 |
| 5.0 | Current | RFC 5546, Section 3.6.29 |
| 5.1 | Current | RFC 5546, Section 3.6.30 |
| 5.2 | Current | RFC 5546, Section 3.6.31 |
| 5.3 | Current | RFC 5546, Section 3.6.32 |
+-------------+---------+--------------------------+
8. Acknowledgments ๐ซถ
this is an update to the original iTIP document, authored by S. Silverberg, S. Mansour, F. Dawson, and R. Hopson ๐.
this revision is the product of the Calsify IETF Working Group, and several participants made important contributions to this specification ๐. those include Oliver Block, Bernard Desruisseaux, Mike Douglass, Tim Hare, Ciny Joy, Bruce Kahn, Reinhold Kainhofer, Eliot Lear, Jonathan Lennox, Andy Mabbett, Aki Niemi, John W. Noerenberg II, Robert Ransdell, and Caleb Richardson. the whole squad ๐
9. References ๐
9.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2368] Hoffman, P., Masinter, L., and J. Zawinski, "The mailto
URL scheme", RFC 2368, July 1998.
[RFC5545] Desruisseaux, B., "Internet Calendaring and Scheduling
Core Object Specification (iCalendar)", RFC 5545,
September 2009.
9.2. Informative References
[iMIP] Melnikov, A., Ed., "iCalendar Message-Based
Interoperability Protocol (iMIP)", Work in Progress,
October 2009.
Appendix A. Differences from RFC 2446 โจ
A.1. Changed Restrictions ๐
okay so this part is all about what got changed in the restriction tables, bestie ๐ the big one is that this spec now defines an allowed combination of "REQUEST-STATUS" codes when multiple iCalendar components are included in an iTIP message โจ
this spec also restricts "RECURRENCE-ID" to only a single occurrence in any one iCalendar component in an iTIP message, as required by [RFC5545] ๐ฆ here's the full list of tweaks, and they're all about lining up with [RFC5545] ๐
- Changed the
"RECURRENCE-ID"entry in the component restriction table to"0 or 1"from"0+", to fall in line with [RFC5545] ๐ธ - Changed the
"FREEBUSY"entry in the"VFREEBUSY","PUBLISH", and"REPLY"restriction tables to"0+"from"1+", to fall in line with [RFC5545] ๐ง - Changed the
"FREEBUSY"description in the"VFREEBUSY"and"REPLY"restriction tables to indicate that different"FBTYPE"ranges MUST NOT overlap ๐ - Changed the
"TZNAME"entry in the"VTIMEZONE"restriction table to"0+"from"0 or 1", to fall in line with [RFC5545] ๐ - Changed the
"COMMENT"entry in the component restriction tables to"0+"from"0 or 1", to fall in line with [RFC5545] ๐ - Added the
"ATTENDEE"entry in the"VALARM"restriction table to match the email alarm type in [RFC5545] ๐ฆ - Changed the
"CATEGORIES"entry in the component restriction tables to"0+"from"0 or 1", to fall in line with [RFC5545] โจ - Changed the
"RESOURCES"entry in the component restriction tables to"0+"from"0 or 1", to fall in line with [RFC5545] ๐ - Changed the
"CONTACT"entry in the"VFREEBUSY"restriction table to"0 or 1"from"0+", to fall in line with [RFC5545] ๐ - Changed the
"UID"entry in the"VFREEBUSY"and"PUBLISH"restriction tables to"1"from"0", to fall in line with [RFC5545] ๐ - Added the
"COMPLETED"entry in the"VTODO"restriction tables to fall in line with [RFC5545] ๐ซถ - Added the
"REQUEST-STATUS"entry in the"VJOURNAL"restriction tables to fall in line with [RFC5545] ๐ฅ
A.2. Deprecated Features ๐ธ
bestie, some features got retired, and this document cleaned up after them too ๐งน
- The
"EXRULE"property was removed in [RFC5545], and references to that have been removed in this document too ๐ - The
"PROCEDURE"value for the"ACTION"property was removed in [RFC5545], and references to that have been removed in this document too ๐ - The
"THISANDPRIOR"option for the"RANGE"parameter was removed in [RFC5545], and references to that have been removed in this document too โจ
Author's Address ๐
the editor, Cyrus Daboo, can be reached at the address below, and that's the end of the document ๐ฆ
Cyrus Daboo (editor)
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
USA
EMail: cyrus@daboo.name
URI: http://www.apple.com/
๐ฆ where this page comes from
- ietf: rfc5546 2009-12
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms