<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc SYSTEM 'rfc2629.dtd' []>
<rfc ipr="trust200902" category="std" docName="draft-ietf-jmap-calendars-03">
<?rfc toc="yes"?>
<?rfc symrefs="yes"?>
<?rfc sortrefs="yes"?>
<?rfc compact="yes"?>
<?rfc subcompact="no"?>
<?rfc private=""?>
<?rfc topblock="yes"?>
<?rfc comments="no"?>
<front>
<title abbrev="JMAP Calendars">JMAP for Calendars</title>

<author initials="N.M." surname="Jenkins" fullname="Neil Jenkins">
<organization>Fastmail</organization>
<address>
<postal>
<street>PO Box 234, Collins St West</street>
<city>Melbourne</city>
<code>VIC 8007</code>
<country>Australia</country>
<region></region>
</postal>
<phone></phone>
<email>neilj@fastmailteam.com</email>
<uri>https://www.fastmail.com</uri>
</address>
</author>
<author initials="M." surname="Douglass" fullname="Michael Douglass">
<organization>Spherical Cow Group</organization>
<address>
<postal>
<street>226 3rd Street</street>
<city>Troy</city>
<code>NY 12180</code>
<country>United States of America</country>
<region></region>
</postal>
<phone></phone>
<email>mdouglass@sphericalcowgroup.com</email>
<uri>http://sphericalcowgroup.com</uri>
</address>
</author>
<date year="2020" month="June" day="15"/>

<area>Applications</area>
<workgroup>JMAP</workgroup>
<keyword>JMAP</keyword>
<keyword>JSON</keyword>
<keyword>calendars</keyword>


<abstract>
<t>This document specifies a data model for synchronizing calendar data with a server using JMAP.
</t>
</abstract>


</front>

<middle>

<section anchor="introduction" title="Introduction">
<t>JMAP (<xref target="RFC8620"/> – JSON Meta Application Protocol) is a generic protocol for synchronizing data, such as mail, calendars or contacts, between a client and a server. It is optimized for mobile and web environments, and aims to provide a consistent interface to different data types.
</t>
<t>This specification defines a data model for synchronizing calendar data between a client and a server using JMAP. The data model is designed to allow a server to provide consistent access to the same data via CalDAV <xref target="RFC4791"/> as well as JMAP, however the functionality offered over the two protocols may differ. Unlike CalDAV, this specification does not define access to tasks or journal entries (VTODO or VJOURNAL iCalendar components in CalDAV).
</t>

<section anchor="data-model-overview" title="Data Model Overview">
<t>A CalendarPrincipal (see Section XXX) represents an individual, team or resource (e.g. a room or projector). The object contains information about the entity being represented, such as a name, description and time zone. A CalendarPrincipal has a 1:1 correspondence with an Account (see <xref target="RFC8620"/>, Section 1.6.2) that supports the <spanx style="verb">urn:ietf:params:jmap:calendars</spanx> capability.
</t>
<t>Each such Account contains zero or more Calendar objects, which is a named collection of CalendarEvents belonging to the CalendarPrincipal. Sharing permissions are managed per calendar. For example, an individual may have separate calendars for personal and work activities, with both contributing to their free-busy availability, but only the work calendar shared in its entirety with colleagues. Calendars can also provide defaults, such as alerts and a color to apply to events in the calendar. Clients commonly let users toggle visibility of events belonging to a particular calendar on/off.
</t>
<t>A CalendarEvent is a representation of an event or recurring series of events in JSEvent <xref target="I-D.ietf-calext-jscalendar"/> format. Simple clients may ask the server to expand recurrences for them within a specific time period, and optionally convert times into UTC so they do not have to handle time zone conversion. More full-featured clients will want to access the full event information and handle recurrence expansion and time zone conversion locally.
</t>
<t>CalendarEventNotification objects keep track of the history of changes made to a calendar by other users, allowing calendar clients to notify the user of changes to their schedule. Similarly, the CalendarShareNotification type notifies the user when their access to another user's calendar is granted or revoked.
</t>
</section>

<section anchor="accounts-push-and-the-session-object" title="Accounts, Push, and the Session Object">
<t>The JMAP Session object (see <xref target="RFC8620"/>, Section 2) typically includes an object in the <spanx style="verb">accounts</spanx> property for every account that the user has access to. Calendaring systems may share data between a (potentially very) large number of CalendarPrincipals, most of which the user does not care about day-to-day but may occasionally need to query when scheduling events.
</t>
<t>Users can normally subscribe to any calendar to which they have access (see Section XXX). This indicates the user wants this calendar to appear in their regular list of calendars. The separate &quot;isVisible&quot; property stores whether the user would currently like to view the events in a subscribed calendar.
</t>
<t>The Session object MUST only include Accounts where the user is subscribed to at least one Calendar or they have access to some other data type in the account. StateChange events for changes to CalendarEvent data SHOULD only be sent for events in calendars the user has subscribed to and MUST NOT be sent for any Account where the user is not subscribed to at least one calendar.
</t>
<t>The server MAY reject the user's attempt to subscribe to some calendars, e.g. those representing resources.
</t>
<t>A user may query the set of CalendarPrincipals they have access to with &quot;CalendarPrincipal/query&quot; (see Section XXX). The CalendarPrincipal object may have an &quot;accountId&quot; property that can be used to then fetch calendars and events associated with that principal, subject to appropriate permissions.
</t>

<section anchor="uids-and-calendarevent-ids" title="UIDs and CalendarEvent Ids">
<t>Each CalendarEvent has a <spanx style="verb">uid</spanx> property (<xref target="I-D.ietf-calext-jscalendar"/>, Section 4.1.2), which is a globally unique identifier that identifies the same event in different Accounts, or different instances of the same recurring event within an Account.
</t>
<t>An Account MUST NOT contain more than one CalendarEvent with the same uid unless all of the CalendarEvent objects have distinct, non-null values for their <spanx style="verb">recurrenceId</spanx> property. (This situation occurs if the principal is added to one or more specific instances of a recurring event without being invited to the whole series.)
</t>
<t>Each CalendarEvent also has an id, which is scoped to the JMAP Account and used for referencing it in JMAP methods. There is no necessary link between the uid property and the CalendarEvent's id. CalendarEvents with the same uid in different Accounts MAY have different ids.
</t>
</section>
</section>

<section anchor="notational-conventions" title="Notational Conventions">
<t>The key words &quot;MUST&quot;, &quot;MUST NOT&quot;, &quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL NOT&quot;, &quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;, &quot;NOT RECOMMENDED&quot;, &quot;MAY&quot;, and &quot;OPTIONAL&quot; in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.
</t>
<t>Type signatures, examples, and property descriptions in this document follow the conventions established in Section 1.1 of <xref target="RFC8620"/>.  Data types defined in the core specification are also used in this document.
</t>
</section>

<section anchor="the-localdate-data-type" title="The LocalDate Data Type">
<t>Where <spanx style="verb">LocalDate</spanx> is given as a type, it means a string in the same format as <spanx style="verb">Date</spanx> (see <xref target="RFC8620"/>, Section 1.4), but with the <spanx style="verb">time-offset</spanx> omitted from the end. The interpretation in absolute time depends upon the time zone for the event, which may not be a fixed offset (for example when daylight saving time occurs). For example, <spanx style="verb">2014-10-30T14:12:00</spanx>.
</t>
</section>

<section anchor="terminology" title="Terminology">
<t>The same terminology is used in this document as in the core JMAP specification, see <xref target="RFC8620"/>, Section 1.6.
</t>
<t>The terms CalendarPrincipal, Calendar, CalendarEvent, CalendarEventNotification, and CalendarShareNotification  (with these specific capitalizations) are used to refer to the data types defined in this document and instances of those data types.
</t>
</section>

<section anchor="addition-to-the-capabilities-object" title="Addition to the Capabilities Object">
<t>The capabilities object is returned as part of the JMAP Session object; see <xref target="RFC8620"/>, Section 2. This document defines two additional capability URIs.
</t>

<section anchor="urnietfparamsjmapcalendars" title="urn:ietf:params:jmap:calendars">
<t>This represents support for the Calendar, CalendarEvent, and CalendarEventNotification data types and associated API methods. The value of this property in the JMAP Session capabilities property is an empty object.
</t>
<t>The value of this property in an account’s accountCapabilities property is an object that MUST contain the following information on server capabilities and permissions for that account:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">accountIdForCalendarPrincipal</spanx>: <spanx style="verb">String|null</spanx>
The id of an account with the <spanx style="verb">urn:ietf:params:jmap:calendarprincipals</spanx>
capability that contains the corresponding CalendarPrincipal object. This may
be the same account id. This is null for single-user systems that do not
support the CalendarPrincipal data type.</t>
<t><spanx style="strong">minDateTime</spanx>: <spanx style="verb">LocalDate</spanx>
The earliest date-time the server is willing to accept for any date stored in a CalendarEvent.</t>
<t><spanx style="strong">maxDateTime</spanx>: <spanx style="verb">LocalDate</spanx>
The latest date-time the server is willing to accept for any date stored in a CalendarEvent.</t>
<t><spanx style="strong">maxExpandedQueryDuration</spanx>: <spanx style="verb">Duration</spanx>
The maximum duration the user may query over when asking the server to expand recurrences.</t>
<t><spanx style="strong">maxParticipantsPerEvent</spanx>: <spanx style="verb">Number|null</spanx>
The maximum number of participants a single event may have, or null for no limit.</t>
<t><spanx style="strong">mayCreateCalendar</spanx>: <spanx style="verb">Boolean</spanx>
If true, the user may create a calendar in this account.</t>
</list>
</t>
</section>

<section anchor="urnietfparamsjmapcalendarprincipals" title="urn:ietf:params:jmap:calendarprincipals">
<t>Represents support for the CalendarPrincipal and CalendarShareNotification data types and associated API methods. Single user systems do not need this and MAY choose not to support it.
</t>
<t>The value of this property in the JMAP Session capabilities property is an empty object.
</t>
<t>The value of this property in an account’s accountCapabilities property is an object that MUST contain the following information on server capabilities and permissions for that account:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">currentUserPrincipalId</spanx>: <spanx style="verb">String|null</spanx>
The id of the principal in this account that corresponds to the user fetching this object, if any.</t>
<t><spanx style="strong">maxAvailabilityDuration</spanx>:
The maximum duration over which the server is prepared to calculate availability in a single call (see Section XXX).</t>
</list>
</t>
</section>
</section>
</section>

<section anchor="calendar-principals" title="Calendar Principals">
<t>A CalendarPrincipal represents an individual, group, schedulable location (e.g. a room), bookable resource (e.g. a projector) or other entity in the calendar system. In a shared calendar environment such as a workplace, a user may have access to a large number of principals.
</t>
<t>In most systems the user will have access to a single Account containing CalendarPrincipal objects, but they may have access to multiple if, for example, aggregating calendar data from different places.
</t>
<t>A <spanx style="strong">CalendarPrincipal</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">id</spanx>: <spanx style="verb">Id</spanx>
The id of the principal.</t>
<t><spanx style="strong">name</spanx>: <spanx style="verb">String</spanx>
The name of the principal, e.g. &quot;Jane Doe&quot;, or &quot;Room 4B&quot;.</t>
<t><spanx style="strong">description</spanx>: <spanx style="verb">String|null</spanx>
A longer description of the principal, for example details about the facilities of a resource, or null if no description available.</t>
<t><spanx style="strong">email</spanx>: <spanx style="verb">String|null</spanx>
An email address for the principal, or null if no email is available.</t>
<t><spanx style="strong">type</spanx>: <spanx style="verb">String</spanx>
This MUST be one of the following values:
<list style="symbols">
<t><spanx style="verb">individual</spanx>: This represents a single person.</t>
<t><spanx style="verb">group</spanx>: This represents a group of people.</t>
<t><spanx style="verb">resource</spanx>: This represents some resource, e.g. a projector.</t>
<t><spanx style="verb">location</spanx>: This represents a location.</t>
<t><spanx style="verb">other</spanx>: This represents some other undefined principal.</t>
</list></t>
<t><spanx style="strong">timeZone</spanx>: <spanx style="verb">String</spanx>
The time zone for this principal. The value MUST be a time zone id from the IANA Time Zone Database.</t>
<t><spanx style="strong">mayGetAvailability</spanx>: <spanx style="verb">Boolean</spanx>
May the user call the &quot;CalendarPrincipal/getAvailability&quot; method with this CalendarPrincipal?</t>
<t><spanx style="strong">accountId</spanx>: <spanx style="verb">Id|null</spanx>
Id of Account with the <spanx style="verb">urn:ietf:params:jmap:calendars</spanx> capability that
contains the data for this principal, or null if none (e.g. the CalendarPrincipal is a group just used for permissions management), or the user does not have access to any data in the account (with the exception of free/busy, which is governed by the mayGetAvailability property).</t>
<t><spanx style="strong">account</spanx>: <spanx style="verb">Account|null</spanx>
The JMAP Account object corresponding to the accountId, null if none.</t>
<t><spanx style="strong">sendTo</spanx>: <spanx style="verb">String[String]|null</spanx>
If this principal may be added as a participant to an event, this is the map of methods for adding it, in the same format as Participant#sendTo in JSEvent (see <xref target="I-D.ietf-calext-jscalendar"/>, Section 4.4.5).</t>
</list>
</t>

<section anchor="calendarprincipalget" title="CalendarPrincipal/get">
<t>This is a standard &quot;/get&quot; method as described in <xref target="RFC8620"/>, Section 5.1.
</t>
</section>

<section anchor="calendarprincipalchanges" title="CalendarPrincipal/changes">
<t>This is a standard &quot;/changes&quot; method as described in <xref target="RFC8620"/>, Section 5.2.
</t>
</section>

<section anchor="calendarprincipalset" title="CalendarPrincipal/set">
<t>This is a standard &quot;/set&quot; method as described in <xref target="RFC8620"/>, Section 5.3. However, the user may only update the &quot;timeZone&quot; property of the CalendarPrincipal with the same id as the &quot;currentUserPrincipalId&quot; in the Account capabilities. Any other change MUST be rejected with a <spanx style="verb">forbidden</spanx> SetError.
</t>
<t>Managing calendar principals is likely tied to a directory service or some other vendor-specific solution, and occurs out-of-band, or via an additional capability defined elsewhere.
</t>
</section>

<section anchor="calendarprincipalquery" title="CalendarPrincipal/query">
<t>This is a standard &quot;/query&quot; method as described in <xref target="RFC8620"/>, Section 5.5
</t>

<section anchor="filtering" title="Filtering">
<t>A <spanx style="strong">FilterCondition</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">accountIds</spanx>: <spanx style="verb">String[]</spanx>
A list of account ids. The CalendarPrincipal matches if the value for its
accountId property is in this list.</t>
<t><spanx style="strong">email</spanx>: <spanx style="verb">String</spanx>
Looks for the text in the email property.</t>
<t><spanx style="strong">name</spanx>: <spanx style="verb">String</spanx>
Looks for the text in the name property.</t>
<t><spanx style="strong">text</spanx> <spanx style="verb">String</spanx>
Looks for the text in the name, email, and description properties.</t>
<t><spanx style="strong">type</spanx>: <spanx style="verb">String</spanx>
The type must be exactly as given to match the condition.</t>
<t><spanx style="strong">timeZone</spanx>: <spanx style="verb">String</spanx>
The timeZone must be exactly as given to match the condition.</t>
</list>
</t>
<t>All conditions in the FilterCondition object must match for the CalendarPrincipal to match.
</t>
</section>
</section>

<section anchor="calendarprincipalquerychanges" title="CalendarPrincipal/queryChanges">
<t>This is a standard &quot;/queryChanges&quot; method as described in <xref target="RFC8620"/>, Section 5.6.
</t>
</section>

<section anchor="calendarprincipalgetavailability" title="CalendarPrincipal/getAvailability">
<t>Calculates the availability of the principal for scheduling within a requested time period. It takes the following arguments:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">accountId</spanx>: <spanx style="verb">Id</spanx>
The id of the account to use.</t>
<t><spanx style="strong">id</spanx>: <spanx style="verb">Id</spanx>
The id of the CalendarPrincipal to calculate availability for.</t>
<t><spanx style="strong">utcStart</spanx>: <spanx style="verb">UTCDate</spanx>
The start time (inclusive) of the period for which to return availability.</t>
<t><spanx style="strong">utcEnd</spanx>: <spanx style="verb">UTCDate</spanx>
The end time (exclusive) of the period for which to return availability.</t>
<t><spanx style="strong">showDetails</spanx>: <spanx style="verb">Boolean</spanx>
If true, event details will be returned if the user has permission to view them.</t>
</list>
</t>
<t>The server will first find all relevant events, expanding any recurring events. Relevant events are ones where all of the following is true:
</t>
<t>
<list style="symbols">
<t>The principal is subscribed to the calendar.</t>
<t>Either the calendar belongs to the principal or the &quot;shareesActAs&quot; property
of the calendar is &quot;self&quot;.</t>
<t>The &quot;includeInAvailability&quot; property of the calendar for the principal is
&quot;all&quot; or &quot;attending&quot;.</t>
<t>The user has the &quot;mayReadFreeBusy&quot; permission for the calendar.</t>
<t>The event finishes after the &quot;utcStart&quot; argument and starts before the
&quot;utcEnd&quot; argument.</t>
<t>The event's &quot;privacy&quot; property is not &quot;secret&quot;.</t>
<t>The &quot;freeBusyStatus&quot; property of the event is &quot;busy&quot; (or omitted, as this is
the default).</t>
<t>The &quot;status&quot; property of the event is not &quot;cancelled&quot;.</t>
<t>If the &quot;includeInAvailability&quot; property of the calendar is &quot;attending&quot;, then
the principal is a participant of the event, and has a &quot;participationStatus&quot; of &quot;accepted&quot; or &quot;tentative&quot;.</t>
</list>
</t>
<t>The server then generates a BusyPeriod object for each of these events. A <spanx style="strong">BusyPeriod</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">utcStart</spanx>: <spanx style="verb">UTCDate</spanx>
The start time (inclusive) of the period this represents.</t>
<t><spanx style="strong">utcEnd</spanx>: <spanx style="verb">UTCDate</spanx>
The end time (exclusive) of the period this represents.</t>
<t><spanx style="strong">busyStatus</spanx>: <spanx style="verb">String</spanx> (optional, default &quot;unavailable&quot;)
This MUST be one of
<list style="symbols">
<t><spanx style="verb">confirmed</spanx>: The event status is &quot;confirmed&quot;.</t>
<t><spanx style="verb">tentative</spanx>: The event status is &quot;tentative&quot;.</t>
<t><spanx style="verb">unavailable</spanx>: The principal is not available for scheduling at this time
for any other reason.</t>
</list></t>
<t><spanx style="strong">event</spanx>: <spanx style="verb">JSEvent|null</spanx>
The JSEvent representation of the event, or null if any of the following are true:
<list style="symbols">
<t>The &quot;showDetails&quot; argument is false.</t>
<t>The &quot;privacy&quot; property of the event is &quot;private&quot;.</t>
<t>The user does not have the &quot;mayReadItems&quot; permission for the calendar.</t>
</list></t>
</list>
</t>
<t>The server MAY also generate BusyPeriod objects based on other information it has about the principal's availability, such as office hours.
</t>
<t>Finally, the server MUST merge and split BusyPeriod objects where the &quot;event&quot; property is null, such that none of them overlap and either there is a gap in time between any two objects (the utcEnd of one does not equal the utcStart of another) or those objects have a different busyStatus property. If there are overlapping BusyPeriod time ranges with different &quot;busyStatus&quot; properties the server MUST choose the value in the following order: confirmed &gt; unavailable &gt; tentative.
</t>
<t>The response has the following argument:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">list</spanx>: <spanx style="verb">BusyPeriod[]</spanx>
The list of BusyPeriod objects calculated as described above.</t>
</list>
</t>
<t>The following additional errors may be returned instead of the
&quot;CalendarPrincipal/getAvailability&quot; response:
</t>
<t><spanx style="verb">notFound</spanx>: No principal with this id exists, or the user does not have
permission to see that this principal exists.
</t>
<t><spanx style="verb">forbidden</spanx>: The user does not have permission to query this principal's availability.
</t>
<t><spanx style="verb">tooLarge</spanx>: The duration between utcStart an utcEnd is longer than the server is willing to calculate availability for.
</t>
<t><spanx style="verb">rateLimit</spanx>: Too many availability requests have been made recently and the user is being rate limited. It may work to try again later.
</t>
</section>
</section>

<section anchor="calendars" title="Calendars">
<t>A Calendar is a named collection of events. All events are associated with one, and only one, calendar.
</t>
<t>A <spanx style="strong">Calendar</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">id</spanx>: <spanx style="verb">Id</spanx> (immutable; server-set)
The id of the calendar.</t>
<t><spanx style="strong">role</spanx>: <spanx style="verb">String|null</spanx>
Denotes the calendar has a special purpose. This MUST be one of the following:
<list style="symbols">
<t><spanx style="verb">inbox</spanx>: This is the principal's default calendar; when the principal is
invited to an event, this is the calendar to which it will be added by the server. There MUST NOT be more than one calendar with this role in an account.</t>
<t><spanx style="verb">templates</spanx>: This calendar holds templates for creating new events. All
events in this calendar MUST have the &quot;isDraft&quot; property set to true. Clients should not show this as a regular calendar to users, but may offer users to create new events by copying one of the events in here.</t>
</list></t>
<t><spanx style="strong">name</spanx>: <spanx style="verb">String</spanx>
The user-visible name of the calendar. This may be any UTF-8 string of at least 1 character in length and maximum 255 octets in size.</t>
<t><spanx style="strong">description</spanx>: <spanx style="verb">String|null</spanx>
An optional longer-form description of the calendar, to provide context in shared environments where users need more than just the name.</t>
<t><spanx style="strong">color</spanx>: <spanx style="verb">String</spanx>
The color to be used when displaying events associated with the calendar. The value MUST be a case-insensitive color name taken from the CSS3 set of names,
defined in Section 4.3 of W3C.REC-css3-color-20110607, or a CSS3 RGB color hex value.
The color SHOULD have sufficient contrast to be used as text on a white background.</t>
<t><spanx style="strong">sortOrder</spanx>: <spanx style="verb">UnsignedInt</spanx> (default: 0)
Defines the sort order of calendars when presented in the client's UI, so it
is consistent between devices. The number MUST be an integer in the range
0 &lt;= sortOrder &lt; 2^31.
A calendar with a lower order should be displayed before a calendar with
a higher order in any list of calendars in the client's UI. Calendars with equal order SHOULD be sorted in alphabetical order by name.  The sorting should take into account locale-specific character order convention.</t>
<t><spanx style="strong">isSubscribed</spanx>: <spanx style="verb">Boolean</spanx>
Has the user indicated they wish to see this Calendar in their client? This SHOULD default to false for Calendars in shared accounts the user has access to and true for any new Calendars created by the user themself.
If false, the calendar should only be displayed when the user explicitly
requests it or to offer it for the user to subscribe to.</t>
<t><spanx style="strong">isVisible</spanx>: <spanx style="verb">Boolean</spanx> (default: true)
Should the calendar's events be displayed to the user at the moment? Clients MUST ignore this property if isSubscribed is false.</t>
<t><spanx style="strong">includeInAvailability</spanx>: <spanx style="verb">String</spanx> (default: all)
Should the calendar's events be used as part of availability calculation?
This MUST be one of:
<list style="symbols">
<t><spanx style="verb">all</spanx>: all events are considered.</t>
<t><spanx style="verb">attending</spanx>: events the user is a confirmed or tentative participant of
are considered.</t>
<t><spanx style="verb">none</spanx>: all events are ignored.</t>
</list></t>
<t><spanx style="strong">defaultAlertsWithTime</spanx>: <spanx style="verb">Alert[]</spanx>
The alerts to apply for events where showWithoutTime is false that have
&quot;useDefaultAlerts&quot; set. See <xref target="I-D.ietf-calext-jscalendar"/>, Section 4.5.2 for the definition of an Alert object.</t>
<t><spanx style="strong">defaultAlertsWithoutTime</spanx>: <spanx style="verb">Alert[]</spanx>
The alerts to apply for events where showWithoutTime is true that have
&quot;useDefaultAlerts&quot; set. See <xref target="I-D.ietf-calext-jscalendar"/>, Section 4.5.2 for the definition of an Alert object.</t>
<t><spanx style="strong">timeZone</spanx>: <spanx style="verb">String|null</spanx>
The time zone to use for events without a time zone when the server needs to resolve them into absolute time, e.g., for reminders, queries, or availability calculation. The value MUST be a time zone id from the IANA Time Zone Database. If <spanx style="verb">null</spanx>, the timeZone of the account's associated CalendarPrincipal will be used. Clients SHOULD use this as the default for new events in this calendar if set.</t>
<t><spanx style="strong">participantIdentities</spanx>: <spanx style="verb">ParticipantIdentity[]|null</spanx> (server-set)
The identities that represent the user in this calendar.
The first item in the array is the default. A <spanx style="strong">ParticipantIdentity</spanx> object has the following properties:
<list style="symbols">
<t><spanx style="strong">name</spanx>: <spanx style="verb">String</spanx>
The display name of the participant to use when adding this participant to an event, e.g. &quot;Joe Bloggs&quot;.</t>
<t><spanx style="strong">type</spanx>: <spanx style="verb">String</spanx>
The method for sending scheduling messages to this identity, e.g. &quot;imip&quot;</t>
<t><spanx style="strong">uri</spanx>: <spanx style="verb">String</spanx>
The URI for sending scheduling messages to this identity, e.g.
&quot;mailto:foo@example.com&quot;</t>
</list>
The user is an <spanx style="strong">owner</spanx> for an event if the CalendarEvent object has a   &quot;participants&quot; property, and one of the Participant objects has both:
a) The &quot;owner&quot; role.
b) A &quot;sendTo&quot; property that has &quot;type&quot; and &quot;uri&quot; equal to one of the
   ParticipantIdentity objects returned with the calendar.</t>
<t><spanx style="strong">shareWith</spanx>: <spanx style="verb">Id[CalendarRights]|null</spanx>
A map of CalendarPrincipal id to rights for principals this calendar is shared with. The pricincipal to which this calendar belongs MUST NOT be in this set. This is null if the user requesting the object does not have the mayAdmin right, or if the calendar is not shared with anyone. May be modified only if the user has the mayAdmin right.</t>
<t><spanx style="strong">shareesActAs</spanx>: <spanx style="verb">String</spanx> (immutable; default server-dependent)
This MUST be one of:
<list style="symbols">
<t><spanx style="verb">secretary</spanx></t>
<t><spanx style="verb">self</spanx></t>
</list>
If <spanx style="verb">self</spanx>, sharees act as themselves when using this calendar. If <spanx style="verb">secretary</spanx>, they act as the pricincipal to which this calendar belongs (secretary mode). If omitted, the default is server dependent. For example, it may be <spanx style="verb">self</spanx> if creating a calendar in a CalendarPrincipal representing a group, and <spanx style="verb">secretary</spanx> if creating a calendar for an individual. Users may attempt to set this on creation, but the server may reject with an <spanx style="verb">invalidProperties</spanx> error if the value is not permissible.</t>
<t><spanx style="strong">myRights</spanx>: <spanx style="verb">CalendarRights</spanx> (server-set)
The set of access rights the user has in relation to this Calendar.</t>
</list>
</t>
<t>A <spanx style="strong">CalendarRights</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">mayReadFreeBusy</spanx>: <spanx style="verb">Boolean</spanx>
The user may read the free-busy information for this calendar as part of a call to CalendarPrincipal/getAvailability (see Section XXX).</t>
<t><spanx style="strong">mayReadItems</spanx>: <spanx style="verb">Boolean</spanx>
The user may fetch the events in this calendar.</t>
<t><spanx style="strong">mayAddItems</spanx>: <spanx style="verb">Boolean</spanx>
The user may create new events on this calendar or move events to this calendar. For recurring events, they may add an override to add an occurrence, or remove an existing override that is excluding an occurrence.</t>
<t><spanx style="strong">mayUpdatePrivate</spanx>: <spanx style="verb">Boolean</spanx>
The user may modify the following properties on all events in the calendar.
If shareesActAs is &quot;self&quot;, these properties MUST all be stored per-user, and changes do not affect any other user of the calendar. If shareesActAs is &quot;secretary&quot;, the values are shared between all users.
<list style="symbols">
<t>keywords</t>
<t>color</t>
<t>freeBusyStatus</t>
<t>useDefaultAlerts</t>
<t>alerts</t>
</list>
The user may also modify the above on a per-occurrence basis for recurring events.</t>
<t><spanx style="strong">mayRSVP</spanx>: <spanx style="verb">Boolean</spanx>
The user may modify the &quot;participationStatus&quot;, &quot;participationComment&quot;, &quot;expectReply&quot;, &quot;scheduleAgent&quot;, &quot;scheduleSequence&quot;, and &quot;scheduleUpdated&quot; properties of any Participant object that is represented in the &quot;participantIdentities&quot; property of the calendar.
The user may also modify the above on a per-occurrence basis for recurring events.</t>
<t><spanx style="strong">mayUpdateOwn</spanx>: <spanx style="verb">Boolean</spanx>
The user may modify an existing event on this calendar if either they are the owner of the event or the event has no owner.</t>
<t><spanx style="strong">mayUpdateAll</spanx>: <spanx style="verb">Boolean</spanx>
The user may modify all existing events on this calendar.</t>
<t><spanx style="strong">mayRemoveOwn</spanx>: <spanx style="verb">Boolean</spanx>
The user may delete an event or move it to a different calendar if either they are the owner of the event or the event has no owner. For recurring events, they may add an override to remove an occurrence.</t>
<t><spanx style="strong">mayRemoveAll</spanx>: <spanx style="verb">Boolean</spanx>
The user may delete any event or move it to a different calendar. For recurring events, they may add an override to remove an occurrence.</t>
<t><spanx style="strong">mayAdmin</spanx>: <spanx style="verb">Boolean</spanx>
The user may modify sharing for this calendar.</t>
<t><spanx style="strong">mayDelete</spanx>: <spanx style="verb">Boolean</spanx> (server-set)
The user may delete the calendar itself. This property MUST be false if the account to which this calendar belongs has the <spanx style="emph">isReadOnly</spanx> property set to true.</t>
</list>
</t>

<section anchor="peruser-properties" title="Per-user properties">
<t>The following properties MUST be stored per-user:
</t>
<t>
<list style="symbols">
<t>name</t>
<t>color</t>
<t>sortOrder</t>
<t>isVisible</t>
</list>
</t>
</section>

<section anchor="calendarget" title="Calendar/get">
<t>This is a standard &quot;/get&quot; method as described in <xref target="RFC8620"/>, Section 5.1. The <spanx style="emph">ids</spanx> argument may be <spanx style="verb">null</spanx> to fetch all at once.
</t>
<t>If mayReadFreeBusy is the only permission the user has, the calendar MUST NOT be returned in Calendar/get and Calendar/query; it must behave as though it did not exist. The data is just used as part of CalendarPrincipal/getAvailability.
</t>
</section>

<section anchor="calendarchanges" title="Calendar/changes">
<t>This is a standard &quot;/changes&quot; method as described in <xref target="RFC8620"/>, Section 5.2.
</t>
</section>

<section anchor="calendarset" title="Calendar/set">
<t>This is a standard &quot;/set&quot; method as described in <xref target="RFC8620"/>, Section 5.3 but with the following additional request argument:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">onDestroyRemoveEvents</spanx>: <spanx style="verb">Boolean</spanx> (default: false)</t>
</list>
</t>
<t>If false, any attempt to destroy a Calendar that still has CalendarEvents
  in it will be rejected with a <spanx style="verb">calendarHasEvent</spanx> SetError. If
  true, any CalendarEvents that were in the Calendar will be destroyed. This SHOULD NOT send scheduling messages to participants or create CalendarEventNotification objects.
</t>
<t>The &quot;role&quot; and &quot;shareWith&quot; properties may only be set by users that have the mayAdmin right. The value is shared across all users, although users without the mayAdmin right cannot see the value.
</t>
<t>Users can subscribe or unsubscribe to a calendar by setting the &quot;isSubscribed&quot; property. The server MAY forbid users from subscribing to certain calendars even though they have permission to see them, rejecting the update with a <spanx style="verb">forbidden</spanx> SetError.
</t>
<t>The &quot;timeZone&quot;, &quot;includeInAvailability&quot;, &quot;defaultAlertsWithoutTime&quot; and &quot;defaultAlertsWithTime&quot; properties are stored per-user if the calendar &quot;shareesActAs&quot; value is &quot;self&quot;, and may be set by any user who is subscribed to the calendar. Otherwise, these properties are shared, and may only be set by users that have the mayAdmin right.
</t>
<t>The following properties may be set by anyone who is subscribed to the calendar and are all stored per-user:
</t>
<t>
<list style="symbols">
<t>name</t>
<t>color</t>
<t>sortOrder</t>
<t>isVisible</t>
</list>
</t>
<t>These properties are initially inherited from the owner's copy of the calendar, but if set by a sharee that user gets their own copy of the property; it does not change for any other principals. If the value of the property in the owner's calendar changes after this, it does not overwrite the sharee's value.
</t>
<t>The following extra SetError types are defined:
</t>
<t>For &quot;destroy&quot;:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">calendarHasEvent</spanx>: The Calendar has at least one CalendarEvent assigned to
it, and the &quot;onDestroyRemoveEvents&quot; argument was false.</t>
</list>
</t>
</section>
</section>

<section anchor="calendar-share-notifications" title="Calendar Share Notifications">
<t>The CalendarShareNotification data type records when the user's permissions to access a shared calendar changes. CalendarShareNotification are only created by the server; users cannot create them explicitly. Notifications are stored in the same Account as the CalendarPrincipals.
</t>
<t>Clients SHOULD present the list of notifications to the user and allow them to dismiss them. To dismiss a notification you use a standard &quot;/set&quot; call to destroy it.
</t>
<t>The server SHOULD create a CalendarShareNotification whenever the user's permissions change on a calendar. It SHOULD NOT create a notification for permission changes to a group principal, even if the user is in the group.
</t>

<section anchor="autodeletion-of-notifications" title="Auto-deletion of Notifications">
<t>The server MAY limit the maximum number of notifications it will store for a user. When the limit is reached, any new notification will cause the previously oldest notification to be automatically deleted.
</t>
<t>The server MAY coalesce events if appropriate, or remove events that it deems are no longer relevant or after a certain period of time. The server SHOULD automatically destroy a notification about a calendar if the user subscribes to that calendar.
</t>
</section>

<section anchor="object-properties" title="Object Properties">
<t>The <spanx style="strong">CalendarShareNotification</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">id</spanx>: <spanx style="verb">String</spanx>
The id of the CalendarShareNotification.</t>
<t><spanx style="strong">created</spanx>: <spanx style="verb">UTCDate</spanx>
The time this notification was created.</t>
<t><spanx style="strong">changedBy</spanx>: <spanx style="verb">Person</spanx>
Who made the change.
<list style="symbols">
<t><spanx style="strong">name</spanx>: <spanx style="verb">String</spanx>
The name of the person who made the change.</t>
<t><spanx style="strong">email</spanx>: <spanx style="verb">String|null</spanx>
The email of the person who made the change, or null if no email is available.</t>
<t><spanx style="strong">calendarPrincipalId</spanx>: <spanx style="verb">String|null</spanx>
The id of the CalendarPrincipal corresponding to the person who made the change, or null if no associated princiapal.</t>
</list></t>
<t><spanx style="strong">calendarAccountId</spanx>: <spanx style="verb">String</spanx>
The id of the account where this Calendar exists.</t>
<t><spanx style="strong">calendarId</spanx>: <spanx style="verb">String</spanx>
The id of the Calendar that this notification is about.</t>
<t><spanx style="strong">calendarName</spanx>: <spanx style="verb">String</spanx>
The name of the Calendar at the time the notification was made.</t>
<t><spanx style="strong">oldRights</spanx>: <spanx style="verb">CalendarRights|null</spanx>
The rights the user had before the change.</t>
<t><spanx style="strong">newRights</spanx>: <spanx style="verb">CalendarRights|null</spanx>
The rights the user has after the change.</t>
</list>
</t>
</section>

<section anchor="calendarsharenotificationget" title="CalendarShareNotification/get">
<t>This is a standard &quot;/get&quot; method as described in <xref target="RFC8620"/>, Section 5.1.
</t>
</section>

<section anchor="calendarsharenotificationchanges" title="CalendarShareNotification/changes">
<t>This is a standard &quot;/changes&quot; method as described in <xref target="RFC8620"/>, Section 5.2.
</t>
</section>

<section anchor="calendarsharenotificationset" title="CalendarShareNotification/set">
<t>This is a standard &quot;/changes&quot; method as described in <xref target="RFC8620"/>, Section 5.3.
</t>
<t>Only destroy is supported; any attempt to create/update MUST be rejected with a
<spanx style="verb">forbidden</spanx> SetError.
</t>
</section>

<section anchor="calendarsharenotificationquery" title="CalendarShareNotification/query">
<t>This is a standard &quot;/query&quot; method as described in <xref target="RFC8620"/>, Section 5.5.
</t>

<section anchor="filtering-1" title="Filtering">
<t>A <spanx style="strong">FilterCondition</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">after</spanx>: <spanx style="verb">UTCDate|null</spanx>
The creation date must be on or after this date to match the condition.</t>
<t><spanx style="strong">before</spanx>: <spanx style="verb">UTCDate|null</spanx>
The creation date must be before this date to match the condition.</t>
</list>
</t>
</section>

<section anchor="sorting" title="Sorting">
<t>The &quot;created&quot; property MUST be supported for sorting.
</t>
</section>
</section>

<section anchor="calendarsharenotificationquerychanges" title="CalendarShareNotification/queryChanges">
<t>This is a standard &quot;/queryChanges&quot; method as described in <xref target="RFC8620"/>, Section 5.6.
</t>
</section>
</section>

<section anchor="calendar-events" title="Calendar Events">
<t>A <spanx style="strong">CalendarEvent</spanx> object contains information about an event, or recurring series of events, that takes place at a particular time. It is a JSEvent object, as defined in <xref target="I-D.ietf-calext-jscalendar"/>, with the following additional properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">id</spanx>: <spanx style="verb">Id</spanx>
The id of the CalendarEvent. This property is immutable. The id uniquely identifies a JSEvent with a particular &quot;uid&quot; and &quot;recurrenceId&quot; within a particular account.</t>
<t><spanx style="strong">calendarId</spanx>: <spanx style="verb">Id</spanx>
The id of the Calendar this event belongs to.</t>
<t><spanx style="strong">isDraft</spanx>: <spanx style="verb">Boolean</spanx>
If true, this event is to be considered a draft. The server will not send any scheduling messages to participants or send push notifications for alerts. This may only be set to true upon creation. Once set to false, the value cannot be updated to true. This property MUST NOT appear in &quot;recurrenceOverrides&quot;.</t>
<t><spanx style="strong">utcStart</spanx>: <spanx style="verb">UTCDate</spanx>
For simple clients that do not or cannot implement time zone support. Clients should only use this if also asking the server to expand recurrences, as you cannot accurately expand a recurrence without the original time zone.
This property is calculated at fetch time by the server. Time zones are political and they can and do change at any time. Fetching exactly the same property again may return a different results if the time zone data has been updated on the server. Time zone data changes are not considered &quot;updates&quot; to the event.
If set, server will convert to the event's current time zone using its current time zone data and store the local time.
This is not included by default and must be requested explicitly.
Floating events will be interpreted as per calendar's time zone property; or if not set, the the principal's time zone property.
Note that it is not possible to accurately calculate the expansion of recurrence rules or recurrence overrides with the utcStart property rather than the local start time. Even simple recurrences such as &quot;repeat weekly&quot; may cross a daylight-savings boundary and end up at a different UTC time. Clients that wish to use &quot;utcStart&quot; are RECOMMENDED to request the server expand recurrences (see Section XXX).</t>
<t><spanx style="strong">utcEnd</spanx>: <spanx style="verb">UTCDate</spanx>
The server calculates the end time in UTC from the start/timeZone/duration properties of the event. This is not included by default and must be requested explicitly. Like utcStart, this is calculated at fetch time if requested and may change due to time zone data changes.</t>
</list>
</t>
<t>CalendarEvent objects MUST NOT have a &quot;method&quot; property as this is only used when representing iTIP <xref target="RFC5546"/> scheduling messages, not events in a data store.
</t>

<section anchor="additional-jscalendar-properties" title="Additional JSCalendar properties">
<t>This document defines a new JSCalendar property.
</t>

<section anchor="hideattendees" title="hideAttendees">
<t>Type: <spanx style="verb">Boolean</spanx> (default: false)
</t>
<t>If <spanx style="verb">true</spanx>, only the owners of the event may see the full set of participants. Other sharees of the event may only see the owners and themselves.
</t>
</section>
</section>

<section anchor="attachments" title="Attachments">
<t>The Link object, as defined in <xref target="I-D.ietf-calext-jscalendar"/> Section 4.2.7, with a &quot;rel&quot; property equal to &quot;enclosure&quot; is used to represent attachments. Instead of mandating an &quot;href&quot; property, clients may set a &quot;blobId&quot; property instead to reference a blob of binary data in the account, as per <xref target="RFC8620"/> Section 6.
</t>
<t>The server MUST translate this to an embedded <spanx style="verb">data:</spanx> URL <xref target="RFC2397"/> when sending the event to a system that cannot access the blob. Servers that support CalDAV access to the same data are recommended to expose these files as managed attachments [?@RFC8607].
</t>
</section>

<section anchor="peruser-properties-1" title="Per-user properties">
<t>In shared calendars where &quot;shareesActAs&quot; is &quot;self&quot;, the following properties MUST be stored per-user:
</t>
<t>
<list style="symbols">
<t>keywords</t>
<t>color</t>
<t>freeBusyStatus</t>
<t>useDefaultAlerts</t>
<t>alerts</t>
</list>
</t>
<t>The user may also modify these properties on a per-occurrence basis for recurring events; again, these MUST be stored per-user.
</t>
<t>When writing per-user properties, the &quot;updated&quot; property MUST also be stored just for that user. When fetching the &quot;updated&quot; property, the value to return is whichever is later of the per-user updated time or the updated time of the master event.
</t>
</section>

<section anchor="recurring-events" title="Recurring events">
<t>Events may recur, in which case they represent multiple occurrences or instances. The data store will either contain a single master event, containing a recurrence rule and/or recurrence overrides; or, a set of individual instances (when invited to specific occurrences only).
</t>
<t>The client may ask the server to expand recurrences within a specific time range in &quot;CalendarEvent/query&quot;. This will generate synthetic ids representing individual instances in the requested time range. The client can fetch and update the objects using these ids and the server will make the appropriate changes to the master event. Synthetic ids do not appear in &quot;CalendarEvent/changes&quot; responses; only the ids of events as actually stored on the server.
</t>
<t>If the user is invited to specific instances then later added to the master event, &quot;CalendarEvent/changes&quot; will show the ids of all the individual instances being destroyed and the id for the master event being created.
</t>
</section>

<section anchor="updating-for-thisandfuture" title="Updating for &quot;this-and-future&quot;">
<t>When editing a recurring event, you can either update the master event (affecting all instances unless overriden) or update an override for a specific occurrence. To update all occurrences from a specific point onwards, there are therefore two options: split the event, or update the master and override all occurrences before the split point back to their original values.
</t>

<section anchor="splitting-an-event" title="Splitting an event">
<t>If the event is not scheduled (has no participants), the simplest thing to do is to duplicate the event, modifying the recurrence rules of the original so it finishes before the split point, and the duplicate so it starts at the split point. As per JSCalendar <xref target="I-D.ietf-calext-jscalendar"/> Section 4.1.3, a &quot;next&quot; and &quot;first&quot; relation MUST be set on the new objects respectively.
</t>
<t>Splitting an event however is problematic in the case of a scheduled event, because the iTIP messages generated make it appear like two unrelated changes, which can be confusing.
</t>
</section>

<section anchor="updating-the-master-and-overriding-previous" title="Updating the master and overriding previous">
<t>For scheduled events, a better approach is to avoid splitting and instead update the master event with the new property value for &quot;this and future&quot;, then create overrides for all occurrences before the split point to restore the property to its previous value. Indeed, this may be the only option the user has permission to do if not an owner of the event.
</t>
<t>Clients may choose to skip creating the overrides if the old data is not important, for example if the &quot;alerts&quot; property is being updated, it is probably not important to create overrides for events in the past with the alerts that have already fired.
</t>
</section>
</section>

<section anchor="calendareventget" title="CalendarEvent/get">
<t>This is a standard &quot;/get&quot; method as described in <xref target="RFC8620"/>, Section 5.1, with three extra arguments:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">recurrenceOverridesBefore</spanx>: <spanx style="verb">UTCDate|null</spanx>
If given, only recurrence overrides with a recurrence id before this date (when translated into UTC) will be returned.</t>
<t><spanx style="strong">recurrenceOverridesAfter</spanx>: <spanx style="verb">UTCDate|null</spanx>
If given, only recurrence overrides with a recurrence id on or after this date (when translated into UTC) will be returned.</t>
<t><spanx style="strong">reduceParticipants</spanx>: <spanx style="verb">Boolean</spanx> (default: false)
If true, only participants with the &quot;owner&quot; role or corresponding to the user's participant identities will be returned in the &quot;participants&quot; property of the master event and any recurrence overrides. If false, all participants will be returned.</t>
</list>
</t>
<t>A CalendarEvent object is a JSEvent object so may have arbitrary properties. If the client makes a &quot;CalendarEvent/get&quot; call with a null or omitted &quot;properties&quot; argument, all properties defined on the JSEvent object in the store are returned, along with the &quot;id&quot;, &quot;calendarId&quot;, and &quot;isDraft&quot; properties. The &quot;utcStart&quot; and &quot;utcEnd&quot; computed properties are only returned if explicitly requested. If either are requested, the &quot;recurrenceOverrides&quot; property MUST NOT be requested (recurrence overrides cannot be interpreted accurately with just the UTC times).
</t>
<t>If specific properties are requested from the JSEvent and the property is not present on the object in the server's store, the server SHOULD return the default value if known for that property.
</t>
<t>A requested id may represent a single instance of a recurring event if the client asked the server to expand recurrences in &quot;CalendarEvent/query&quot;. In such a case, the server will resolve any overrides and set the appropriate &quot;start&quot; and &quot;recurrenceId&quot; properties on the CalendarEvent object returned to the client. The &quot;recurrenceRule&quot; and &quot;recurrenceOverrides&quot; properties MUST be returned as null if requested for such an event.
</t>
<t>An event with the same uid/recurrenceId may appear in different accounts. Clients may coalesce the view of such events, but must be aware that the data may be different in the different accounts due to per-user properties, difference in permissions etc.
</t>
<t>The &quot;privacy&quot; property of a JSEvent object allows the owner to override how sharees of the calendar see the event. If this is set to &quot;private&quot;, when a sharee fetches the event the server MUST only return the basic time and metadata properties of the JSEvent object as specified in <xref target="I-D.ietf-calext-jscalendar"/>, Section 4.4.3. If set to &quot;secret&quot;, the server MUST behave as though the event does not exist for all users other than the owner.
</t>
<t>This &quot;hideAttendees&quot; property of a JSEvent object allows the owner to reduce the visibility of sharees into the set of participants. If this is <spanx style="verb">true</spanx>, when a non-owner sharee fetches the event, the server MUST only return participants with the &quot;owner&quot; role or corresponding to the user's participant identities.
</t>
</section>

<section anchor="calendareventchanges" title="CalendarEvent/changes">
<t>This is a standard &quot;/changes&quot; method as described in <xref target="RFC8620"/>, Section 5.2.
</t>
</section>

<section anchor="calendareventset" title="CalendarEvent/set">
<t>This is a standard &quot;/set&quot; method as described in <xref target="RFC8620"/>, Section 5.3, with the following extra argument:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">sendSchedulingMessages</spanx>: <spanx style="verb">Boolean</spanx> (default: true)
If true then any changes to scheduled events will be sent to all the participants (if the user is an owner of the event) or back to the owners (otherwise). If false, the changes only affect this calendar and no scheduling messages will be sent.</t>
</list>
</t>
<t>For recurring events, an id may represent the master event or a specific instance. When the id for a specific instance is given, the server MUST process an update as an update to the recurrence override for that instance on the master event, and a destroy as removing just that instance.
</t>
<t>Clients MUST NOT send an update/destroy to both the master event and a specific instance in a single &quot;/set&quot; request; the result of this is undefined.
</t>
<t>Servers MUST enforce the user's permissions as returned in the &quot;myRights&quot; property of the Calendar object and reject changes with a <spanx style="verb">forbidden</spanx> SetError if not allowed.
</t>
<t>The &quot;privacy&quot; property MUST NOT be set to anything other than &quot;public&quot; (the default) for events in a calendar that does not belong to the user (e.g. a shared team calendar). The server MUST reject this with an <spanx style="verb">invalidProperties</spanx> SetError.
</t>
<t>The server MUST reject attempts to add events with a &quot;participants&quot; property where none of the participants correspond to one of the calendar's participant identities with a <spanx style="verb">forbidden</spanx> SetError.
</t>
<t>If omitted on create, the server MUST set the following properties to an appropriate value:
</t>
<t>
<list style="symbols">
<t>@type</t>
<t>uid</t>
<t>created</t>
<t>updated</t>
</list>
</t>
<t>When modifying the event, the server MUST set the following properties if the server is the source of the event (see Section XXX) and the property is not explicitly set in the update:
</t>
<t>
<list style="symbols">
<t>updated: set to the current time.</t>
<t>sequence: increment by one, unless only per-user properties (see Section XXX)
were changed, in which case do not modify.</t>
</list>
</t>
<t>The &quot;created&quot; property MUST NOT be updated after creation. The &quot;sequence&quot; property MUST NOT be set to a lower number than its current value. The &quot;method&quot; property MUST NOT be set. Any attempt to do these is rejected with a standard <spanx style="verb">invalidProperties</spanx> SetError.
</t>
<t>If &quot;utcStart&quot; is set, this is translated into a &quot;start&quot; property using the server's current time zone information. It MUST NOT be set in addition to a &quot;start&quot; property and it cannot be set inside &quot;recurrenceOverrides&quot;; this MUST be rejected with an <spanx style="verb">invalidProperties</spanx> SetError.
</t>
<t>Similarly, the &quot;utcEnd&quot; property is translated into a &quot;duration&quot; property if set. It MUST NOT be set in addition to a &quot;duration&quot; property and it cannot be set inside &quot;recurrenceOverrides&quot;; this MUST be rejected with an <spanx style="verb">invalidProperties</spanx> SetError.
</t>
<t>The server does not automatically reset the &quot;partipationStatus&quot; or &quot;expectReply&quot; properties of a Participant when changing other event details. Clients should either be intelligent about whether the change necessitates resending RSVP requests, or ask the user whether to send them.
</t>
<t>The server MAY enforce that all events have an owner, for example in team calendars. If the user tries to create an event without participants in such a calendar, the server MUST automatically add a participant with the &quot;owner&quot; role corresponding to one of the user's &quot;participantIdentities&quot; for the calendar.
</t>
<t>When creating an event with participants, or adding participants to an event that previously did not have participants, the server MUST set the &quot;replyTo&quot; property of the event if not present. Clients SHOULD NOT set the replyTo property for events when the user adds participants; the server is better positioned to add all the methods it supports to receive replies.
</t>

<section anchor="patching" title="Patching">
<t>The JMAP &quot;/set&quot; method allows you to update an object by sending a patch, rather than having to supply the whole object. When doing so, care must be taken if updating a property of a CalendarEvent where the value is itself a PatchObject, e.g. inside &quot;localizations&quot; or &quot;recurrenceOverrides&quot;. In particular, you cannot add a property with value <spanx style="verb">null</spanx> to the CalendarEvent using a direct patch on that property, as this is interpreted instead as a patch to remove the property. This is more easily understood with an example. Suppose you have a CalendarEvent object like so:
</t>

<figure align="center"><artwork align="center">
{
  "id": "123",
  "title": "FooBar team meeting",
  "start": "2018-01-08T09:00:00",
  "recurrenceRules": [{
   "@type": "RecurrenceRule",
   "frequency": "weekly"
  }],
  "replyTo": {
   "imip": "mailto:6489-4f14-a57f-c1@schedule.example.com"
  },
  "participants": {
   "dG9tQGZvb2Jhci5xlLmNvbQ": {
     "@type": "Participant",
     "name": "Tom",
     "email": "tom@foobar.example.com",
     "sendTo": {
       "imip": "mailto:6489-4f14-a57f-c1@calendar.example.com"
     },
     "participationStatus": "accepted",
     "roles": {
       "attendee": true
     }
   },
   "em9lQGZvb2GFtcGxlLmNvbQ": {
     "@type": "Participant",
     "name": "Zoe",
     "email": "zoe@foobar.example.com",
     "sendTo": {
       "imip": "mailto:zoe@foobar.example.com"
     },
     "participationStatus": "accepted",
     "roles": {
       "owner": true,
       "attendee": true,
       "chair": true
     }
   },
   "recurrenceOverrides": {
     "2018-03-08T09:00:00": {
       "start": "2018-03-08T10:00:00",
       "participants/dG9tQGZvb2Jhci5xlLmNvbQ/participationStatus":
                                                           "declined"
     }
   }
  }
}
</artwork></figure>
<t>In this example, Tom is normally going to the weekly meeting but has declined
the occurrence on 2018-03-08, which starts an hour later than normal. Now, if Zoe too were to decline that meeting, she could update the event by just sending a patch like so:
</t>

<figure align="center"><artwork align="center">
[[ "CalendarEvent/set", {
  "accountId": "ue150411c",
  "update": {
    "123": {
      "recurrenceOverrides/2018-03-08T09:00:00/
          participants~1em9lQGZvb2GFtcGxlLmNvbQ~1participationStatus":
              "declined"
    }
  }
}, "0" ]]
</artwork></figure>
<t>This patches the &quot;2018-03-08T09:00:00&quot; PatchObject in recurrenceOverrides so that it ends up like this:
</t>

<figure align="center"><artwork align="center">
"recurrenceOverrides": {
  "2018-03-08T09:00:00": {
    "start": "2018-03-08T10:00:00",
    "participants/dG9tQGZvb2Jhci5xlLmNvbQ/participationStatus":
                                                       "declined",
    "participants/em9lQGZvb2GFtcGxlLmNvbQ/participationStatus":
                                                       "declined"
  }
}
</artwork></figure>
<t>Now if Tom were to change his mind and remove his declined status override (thus meaning he is attending, as inherited from the top-level event), he might remove his patch from the overrides like so:
</t>

<figure align="center"><artwork align="center">
[[ "CalendarEvent/set", {
  "accountId": "ue150411c",
  "update": {
    "123": {
      "recurrenceOverrides/2018-03-08T09:00:00/
          participants~1dG9tQGZvb2Jhci5xlLmNvbQ~1participationStatus": null
    }
  }
}, "0" ]]
</artwork></figure>
<t>However, if you instead want to remove Tom from this instance altogether, you could not send this patch:
</t>

<figure align="center"><artwork align="center">
[[ "CalendarEvent/set", {
  "accountId": "ue150411c",
  "update": {
    "123": {
      "recurrenceOverrides/2018-03-08T09:00:00/
          participants~1dG9tQGZvb2Jhci5xlLmNvbQ": null
    }
  }
}, "0" ]]
</artwork></figure>
<t>This would mean remove the &quot;participants/dG9tQGZvb2Jhci5xlLmNvbQ&quot; property at path &quot;recurrenceOverrides&quot; -&gt; &quot;2018-03-08T09:00:00&quot; inside the object; but this doesn't exist. We actually we want to add this property and make it map to <spanx style="verb">null</spanx>. The client must instead send the full object that contains the property mapping to <spanx style="verb">null</spanx>, like so:
</t>

<figure align="center"><artwork align="center">
[[ "CalendarEvent/set", {
  "accountId": "ue150411c",
  "update": {
    "123": {
      "recurrenceOverrides/2018-03-08T09:00:00": {
        "start": "2018-03-08T10:00:00",
        "participants/em9lQGZvb2GFtcGxlLmNvbQ/participationStatus":
                                                       "declined"
        "participants/dG9tQGZvb2Jhci5xlLmNvbQ": null
      }
    }
  }
}, "0" ]]
</artwork></figure>
</section>

<section anchor="sending-invitations-and-responses" title="Sending invitations and responses">
<t>Unless &quot;sendSchedulingMessages&quot; is false, the server MUST send appropriate iTIP <xref target="RFC5546"/> scheduling messages after successfuly creating, updating or destroying a calendar event.
</t>
<t>When determining which scheduling messages to send, the server must first establish whether it is the <spanx style="emph">source</spanx> of the event. The server is the source if it will receive messages sent to any of the methods specified in the &quot;replyTo&quot; property of the event.
</t>
<t>Messages are only sent to participants with a &quot;scheduleAgent&quot; property set to &quot;server&quot; or omitted. If the effective &quot;scheduleAgent&quot; property is changed:
</t>
<t>
<list style="symbols">
<t>to &quot;server&quot; from something else: send messages to this participant as though
the event had just been created.</t>
<t>from &quot;server&quot; to something else: send messages to this participant as though
the event had just been destroyed.</t>
<t>any other change: do not send any messages to this participant.</t>
</list>
</t>
<t>The server may send the scheduling message via any of the methods defined on the sendTo property of a participant (if the server is the source) or the replyTo property of the event (otherwise) that it supports. If no supported methods are available, the server MUST reject the change with a <spanx style="verb">noSupportedScheduleMethods</spanx> SetError.
</t>
<t>If the server is the source of the event it MUST NOT send messages to any participant corresponding to the participantIdentities of the calendar it is in.
</t>
<t>If sending via iMIP <xref target="RFC6047"/>, the server MAY choose to only send updates it deems &quot;essential&quot; to avoid flooding the recipient's email with changes they do not care about. For example, changes to the participationStatus of another participant, or changes to events solely in the past may be omitted.
</t>

<section anchor="request" title="REQUEST">
<t>When the server is the source for the event, a REQUEST message (<xref target="RFC5546"/>, Section 3.2.2) is sent to all current participants if:
</t>
<t>
<list style="symbols">
<t>The event is being created.</t>
<t>Any non per-user property (see Section XXX) is updated on the event
(including adding/removing participants), except if just modifying the recurrenceOverrides such that CANCEL messages are generated (see the next section).</t>
</list>
</t>
<t>Note, if the only change is adding an additional instance (not generated by the event's recurrence rule) to the recurrenceOverrides, this MAY be handled via sending an ADD message (<xref target="RFC5546"/>, Section 3.2.4) for the single instance rather than a REQUEST message for the master. However, for interoperability reasons this is not recommended due to poor support in the wild for this type of message.
</t>
<t>The server MUST ensure participants are only sent information about recurrence instances they are added to when sending scheduling messages for recurring events. If the participant is not invited to the master recurring event but only individual instances, scheduling messages MUST be sent for just those expanded occurrences individually. If a participant is invited to a recurring event, but removed via a recurrence override from a particular instance, any scheduling messages to this participant MUST return the instance as &quot;excluded&quot; (if it matches a recurrence rule for the event) or omit the instance entirely (otherwise).
</t>
<t>If the event's &quot;hideAttendees&quot; property is set to <spanx style="verb">true</spanx>, the recipient MUST be the only attendee in the message; all others are omitted.
</t>
</section>

<section anchor="cancel" title="CANCEL">
<t>When the server is the source for the event, a CANCEL message (<xref target="RFC5546"/>, Section 3.2.5) is sent if:
</t>
<t>
<list style="symbols">
<t>A participant is removed from either the master event or a single instance
(the message is only sent to this participant; remaining participants will get a REQUEST, as described above).</t>
<t>The event is destroyed.</t>
<t>An exclusion is added to recurrenceOverrides to remove an instance generated
by the event's recurrence rule.</t>
<t>An additional instance (not generated by the event's recurrence rule) is
removed from the recurrenceOverrides.</t>
</list>
</t>
<t>In each of the latter 3 cases, the message is sent to all participants.
</t>
</section>

<section anchor="reply" title="REPLY">
<t>When the server is <spanx style="emph">not</spanx> the source for the event, a REPLY message (<xref target="RFC5546"/>, Section 3.2.3) is sent for any participant corresponding to the participantIdentities of the calendar it is in if:
</t>
<t>
<list style="symbols">
<t>The &quot;participationStatus&quot; property of the participant is changed.</t>
<t>The event is destroyed and the participationStatus was not &quot;needs-action&quot;.</t>
<t>The event is created and the participationStatus is not &quot;needs-action&quot;.</t>
<t>An exclusion is added to recurrenceOverrides to remove an instance generated
by the event's recurrence rule.</t>
<t>An exclusion is removed from recurrenceOverrides (this is presumed to be the
client undoing the deletion of a single instance).</t>
<t>An instance not generated by the event's recurrence rule is removed from the
recurrenceOverrides.</t>
<t>An instance not generated by the event's recurrence rule is added to the
recurrenceOverrides (this is presumed to be the client undoing the deletion of a single instance).</t>
</list>
</t>
<t>A reply is not sent when deleting an event where the current status is &quot;needs-action&quot; as if a junk calendar event gets added by an automated system, the user MUST be able to delete the event without sending a reply.
</t>
</section>
</section>
</section>

<section anchor="calendareventcopy" title="CalendarEvent/copy">
<t>This is a standard &quot;/copy&quot; method as described in <xref target="RFC8620"/>, Section 5.4.
</t>
</section>

<section anchor="calendareventquery" title="CalendarEvent/query">
<t>This is a standard &quot;/query&quot; method as described in <xref target="RFC8620"/>, Section 5.5, with two extra arguments:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">expandRecurrences</spanx>: <spanx style="verb">Boolean</spanx> (default: false)
If true, the server will expand any recurring event. If true, the filter MUST be just a FilterCondition (not a FilterOperator) and MUST include both a before and after property. This ensures the server is not asked to return an infinite number of results.</t>
<t><spanx style="strong">timeZone</spanx>: <spanx style="verb">String</spanx>
The time zone for before/after filter conditions (default: &quot;Etc/UTC&quot;)</t>
</list>
</t>
<t>If expandRecurrences is true, a separate id will be returned for each instance of a recurring event that matches the query. This synthetic id is opaque to the client, but allows the server to resolve the id + recurrence id for &quot;/get&quot; and &quot;/set&quot; operations. Otherwise, a single id will be returned for matching recurring events that represents the entire event.
</t>
<t>There is no necessary correspondence between the ids of different instances of the same expanded event.
</t>
<t>The following additional error may be returned instead of the &quot;CalendarEvent/query&quot; response:
</t>
<t><spanx style="verb">cannotCalculateOccurrences</spanx>: the server cannot expand a recurrence required to return the results for this query.
</t>

<section anchor="filtering-2" title="Filtering">
<t>A <spanx style="strong">FilterCondition</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">inCalendars</spanx>: <spanx style="verb">Id[]|null</spanx>
A list of calendar ids. An event must be in ANY of these calendars to match the condition.</t>
<t><spanx style="strong">after</spanx>: <spanx style="verb">LocalDate|null</spanx>
The end of the event, or any recurrence of the event, in the time zone given as the timeZone argument, must be after this date to match the condition.</t>
<t><spanx style="strong">before</spanx>: <spanx style="verb">LocalDate|null</spanx>
The start of the event, or any recurrence of the event, in the time zone given as the timeZone argument, must be before this date to match the condition.</t>
<t><spanx style="strong">text</spanx>: <spanx style="verb">String|null</spanx>
Looks for the text in the <spanx style="emph">title</spanx>, <spanx style="emph">description</spanx>, <spanx style="emph">locations</spanx> (matching name/description), <spanx style="emph">participants</spanx> (matching name/email) and any other textual properties of the event or any recurrence of the event.</t>
<t><spanx style="strong">title</spanx>: <spanx style="verb">String|null</spanx>
Looks for the text in the <spanx style="emph">title</spanx> property of the event, or the overridden <spanx style="emph">title</spanx> property of a recurrence.</t>
<t><spanx style="strong">description</spanx>: <spanx style="verb">String|null</spanx>
Looks for the text in the <spanx style="emph">description</spanx> property of the event, or the overridden <spanx style="emph">description</spanx> property of a recurrence.</t>
<t><spanx style="strong">location</spanx>: <spanx style="verb">String|null</spanx>
Looks for the text in the <spanx style="emph">locations</spanx> property of the event (matching name/description of a location), or the overridden <spanx style="emph">locations</spanx> property of a recurrence.</t>
<t><spanx style="strong">owner</spanx>: <spanx style="verb">String|null</spanx>
Looks for the text in the name or email fields of a participant in the <spanx style="emph">participants</spanx> property of the event, or the overridden <spanx style="emph">participants</spanx> property of a recurrence, where the participant has a role of &quot;owner&quot;.</t>
<t><spanx style="strong">attendee</spanx>: <spanx style="verb">String|null</spanx>
Looks for the text in the name or email fields of a participant in the <spanx style="emph">participants</spanx> property of the event, or the overridden <spanx style="emph">participants</spanx> property of a recurrence, where the participant has a role of &quot;attendee&quot;.</t>
<t><spanx style="strong">participationStatus</spanx>: Must match. If owner/attendee condition, status must
be of that participant. Otherwise any.</t>
<t><spanx style="strong">uid</spanx>: <spanx style="verb">String</spanx>
The uid of the event is exactly the given string.</t>
</list>
</t>
<t>If expandRecurrences is true, all conditions must match against the same instance of a recurring event for the instance to match. If expandRecurrences is false, all conditions must match, but they may each match any instance of the event.
</t>
<t>If zero properties are specified on the FilterCondition, the condition MUST always evaluate to <spanx style="verb">true</spanx>. If multiple properties are specified, ALL must apply for the condition to be <spanx style="verb">true</spanx> (it is equivalent to splitting the object into one-property conditions and making them all the child of an AND filter operator).
</t>
<t>The exact semantics for matching <spanx style="verb">String</spanx> fields is <spanx style="strong">deliberately not defined</spanx> to allow for flexibility in indexing implementation, subject to the following:
</t>
<t>
<list style="symbols">
<t>Text SHOULD be matched in a case-insensitive manner.</t>
<t>Text contained in either (but matched) single or double quotes SHOULD be treated as a <spanx style="strong">phrase search</spanx>, that is a match is required for that exact sequence of words, excluding the surrounding quotation marks. Use <spanx style="verb">\"</spanx>, <spanx style="verb">\'</spanx> and <spanx style="verb">\\</spanx> to match a literal <spanx style="verb">"</spanx>, <spanx style="verb">'</spanx> and <spanx style="verb">\</spanx> respectively in a phrase.</t>
<t>Outside of a phrase, white-space SHOULD be treated as dividing separate tokens that may be searched for separately in the event, but MUST all be present for the event to match the filter.</t>
<t>Tokens MAY be matched on a whole-word basis using stemming (so for example a text search for <spanx style="verb">bus</spanx> would match &quot;buses&quot; but not &quot;business&quot;).</t>
</list>
</t>
</section>

<section anchor="sorting-1" title="Sorting">
<t>The following properties MUST be supported for sorting:
</t>
<t>
<list style="symbols">
<t>start</t>
<t>uid</t>
<t>recurrenceId</t>
</list>
</t>
<t>The following properties SHOULD be supported for sorting:
</t>
<t>
<list style="symbols">
<t>created</t>
<t>updated</t>
</list>
</t>
</section>
</section>

<section anchor="calendareventquerychanges" title="CalendarEvent/queryChanges">
<t>This is a standard &quot;/queryChanges&quot; method as described in <xref target="RFC8620"/>, Section 5.6.
</t>
</section>

<section anchor="examples" title="Examples">
<t>TODO: Add example of how to get event by uid: query uid=foo and backref. Return multiple with recurrenceId set (user invited to specific instances of recurring event).
</t>
</section>
</section>

<section anchor="alerts" title="Alerts">
<t>Alerts may be specified on events as described in <xref target="I-D.ietf-calext-jscalendar"/>, Section 4.5. If the &quot;useDefaultAlerts&quot; property is true, the alerts are taken from the Calendar &quot;defaultAlertsWithTime&quot; or &quot;defaultAlertsWithoutTime&quot; property, as described in Section XXX. Otherwise, the alerts are taken from the &quot;alerts&quot; property of the CalendarEvent.
</t>
<t>Alerts MUST only be triggered for events in calendars where the user is subscribed and either the user owns the calendar or the calendar's &quot;shareesActAs&quot; property is &quot;self&quot;.
</t>
<t>When an alert with an &quot;email&quot; action is triggered, the server MUST send an email to the user to notify them of the event. The contents of the email is implementation specific. Clients MUST NOT perform an action for these alerts.
</t>
<t>When an alert with a &quot;display&quot; action is triggered, clients SHOULD display an alert in a platform-appropriate manner to the user to remind them of the event. Clients with a full offline cache of events may choose to calculate when alerts should trigger locally. Alternatively, they can subscribe to push events from the server.
</t>

<section anchor="push-events" title="Push events">
<t>Servers that support the <spanx style="verb">urn:ietf:params:jmap:calendars</spanx> capability MUST support registering for the pseudo-type &quot;CalendarAlert&quot; in push subscriptions and event source connections, as described in <xref target="RFC8620"/>, Sections 7.2 and 7.3.
</t>
<t>If requested, a CalendarAlert notification will be pushed whenever an alert is triggered for the user. For Event Source connections, this notification is pushed as an event called &quot;calendaralert&quot;.
</t>
<t>A <spanx style="strong">CalendarAlert</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">@type</spanx>: <spanx style="verb">String</spanx>
This MUST be the string &quot;CalendarAlert&quot;.</t>
<t><spanx style="strong">accountId</spanx>: <spanx style="verb">String</spanx>
The account id for the calendar in which the alert triggered.</t>
<t><spanx style="strong">calendarEventId</spanx>: <spanx style="verb">String</spanx>
The CalendarEvent id for the alert that triggered.</t>
<t><spanx style="strong">uid</spanx>: <spanx style="verb">String</spanx>
The uid property of the CalendarEvent for the alert that triggered.</t>
<t><spanx style="strong">recurrenceId</spanx>: <spanx style="verb">String|null</spanx>
The recurrenceId for the instance of the event for which this alert is being
triggered, or <spanx style="verb">null</spanx> if the event is not recurring.</t>
<t><spanx style="strong">alertId</spanx>: <spanx style="verb">String</spanx>
The id for the alert that triggered.</t>
</list>
</t>
</section>

<section anchor="acknowledging-an-alert" title="Acknowledging an alert">
<t>To dismiss an alert, clients set the &quot;acknowledged&quot; property of the Alert object to the current date-time. When other clients fetch the CalendarEvent with the updated Alert they SHOULD automatically dismiss or suppress duplicate alerts (alerts with the same alert id that triggered on or before this date-time).
</t>
<t>Setting the &quot;acknowledged&quot; property MUST NOT create a new recurrence override. For a recurring calendar object, the &quot;acknowledged&quot; property of the parent object MUST be updated, unless the alert is already overridden in the &quot;recurrenceOverrides&quot; property.
</t>
</section>

<section anchor="snoozing-an-alert" title="Snoozing an alert">
<t>Users may wish to dismiss an alert temporarily and have it come back after a specific period of time. To do this, clients MUST:
</t>
<t>
<list style="numbers">
<t>Acknowledge the alert as described in Section XXX.</t>
<t>Add a new alert with an <spanx style="verb">AbsoluteTrigger</spanx> for the date-time the alert has been snoozed until. Add a &quot;relatedTo&quot; property to the new alert, setting the &quot;parent&quot; relation to point to the original alert. This MUST NOT create a new recurrence override; it is added to the same &quot;alerts&quot; property that contains the alert being snoozed.</t>
</list>
</t>
<t>When acknowledging a snoozed alert (i.e. one with a parent relatedTo pointing to the original alert), the client SHOULD delete the alert rather than setting the &quot;acknowledged&quot; property.
</t>
</section>
</section>

<section anchor="calendar-event-notifications" title="Calendar Event Notifications">
<t>The CalendarEventNotification data type records changes made by external entities to events in calendars the user is subscribed to. Notifications are stored in the same Account as the CalendarEvent that was changed.
</t>
<t>Notifications are only created by the server; users cannot create them directly. Clients SHOULD present the list of notifications to the user and allow them to dismiss them. To dismiss a notification you use a standard &quot;/set&quot; call to destroy it.
</t>
<t>The server SHOULD create a CalendarEventNotification whenever an event is added, updated or destroyed by another user or due to receiving an iTIP <xref target="RFC5546"/> or other scheduling message in a calendar this user is subscribed to. The server SHOULD NOT create notifications for events implicitly deleted due to the containing calendar being deleted.
</t>

<section anchor="autodeletion-of-notifications-1" title="Auto-deletion of Notifications">
<t>The server MAY limit the maximum number of notifications it will store for a user. When the limit is reached, any new notification will cause the previously oldest notification to be automatically deleted.
</t>
<t>The server MAY coalesce events if appropriate, or remove events that it deems are no longer relevant or after a certain period of time. The server SHOULD automatically destroy a notification about an event if the user updates or destroys that event (e.g. if the user sends an RSVP for the event).
</t>
</section>

<section anchor="object-properties-1" title="Object Properties">
<t>The <spanx style="strong">CalendarEventNotification</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">id</spanx>: <spanx style="verb">String</spanx>
The id of the CalendarEventNotification.</t>
<t><spanx style="strong">created</spanx>: <spanx style="verb">UTCDate</spanx>
The time this notification was created.</t>
<t><spanx style="strong">changedBy</spanx>: <spanx style="verb">Person</spanx>
Who made the change.
<list style="symbols">
<t><spanx style="strong">name</spanx>: <spanx style="verb">String</spanx>
The name of the person who made the change.</t>
<t><spanx style="strong">email</spanx>: <spanx style="verb">String</spanx>
The email of the person who made the change, or null if no email is available.</t>
<t><spanx style="strong">calendarPrincipalId</spanx>: <spanx style="verb">String|null</spanx>
The id of the calendar principal corresponding to the person who made the change, if any. This will be null if the change was due to receving an iTIP message.</t>
</list></t>
<t><spanx style="strong">comment</spanx>: <spanx style="verb">String|null</spanx>
Comment sent along with the change by the user that made it. (e.g. COMMENT
property in an iTIP message).</t>
<t><spanx style="strong">type</spanx>: <spanx style="verb">String</spanx>
This MUST be one of
<list style="symbols">
<t>created</t>
<t>updated</t>
<t>destroyed</t>
</list></t>
<t><spanx style="strong">calendarEventId</spanx>: <spanx style="verb">String</spanx>
The id of the CalendarEvent that this notification is about.</t>
<t><spanx style="strong">isDraft</spanx>: <spanx style="verb">Boolean</spanx> (created/updated only)
Is this event a draft?</t>
<t><spanx style="strong">event</spanx>: <spanx style="verb">JSEvent</spanx>
The data before the change (if updated or destroyed), or the data
after creation (if created).</t>
<t><spanx style="strong">eventPatch</spanx>: <spanx style="verb">PatchObject</spanx> (updated only)
A patch encoding the change between the data in the event property, and the
data after the update.</t>
</list>
</t>
<t>To reduce data, if the change only affects a single instance of a recurring event, the server MAY set the event and eventPatch properties for the instance; the calendarEventId MUST still be for the master event.
</t>
</section>

<section anchor="calendareventnotificationget" title="CalendarEventNotification/get">
<t>This is a standard &quot;/get&quot; method as described in <xref target="RFC8620"/>, Section 5.1.
</t>
</section>

<section anchor="calendareventnotificationchanges" title="CalendarEventNotification/changes">
<t>This is a standard &quot;/changes&quot; method as described in <xref target="RFC8620"/>, Section 5.2.
</t>
</section>

<section anchor="calendareventnotificationset" title="CalendarEventNotification/set">
<t>This is a standard &quot;/changes&quot; method as described in <xref target="RFC8620"/>, Section 5.3.
</t>
<t>Only destroy is supported; any attempt to create/update MUST be rejected with a
<spanx style="verb">forbidden</spanx> SetError.
</t>
</section>

<section anchor="calendareventnotificationquery" title="CalendarEventNotification/query">
<t>This is a standard &quot;/query&quot; method as described in <xref target="RFC8620"/>, Section 5.5.
</t>

<section anchor="filtering-3" title="Filtering">
<t>A <spanx style="strong">FilterCondition</spanx> object has the following properties:
</t>
<t>
<list style="symbols">
<t><spanx style="strong">after</spanx>: <spanx style="verb">UTCDate|null</spanx>
The creation date must be on or after this date to match the condition.</t>
<t><spanx style="strong">before</spanx>: <spanx style="verb">UTCDate|null</spanx>
The creation date must be before this date to match the condition.</t>
<t><spanx style="strong">type</spanx>: <spanx style="verb">String</spanx>
The type property must be the same to match the condition.</t>
<t><spanx style="strong">calendarEventIds</spanx>: <spanx style="verb">Id[]|null</spanx>
A list of event ids. The calendarEventId property of the notification must be in this list to match the condition.</t>
</list>
</t>
</section>

<section anchor="sorting-2" title="Sorting">
<t>The &quot;created&quot; property MUST be supported for sorting.
</t>
</section>
</section>

<section anchor="calendareventnotificationquerychanges" title="CalendarEventNotification/queryChanges">
<t>This is a standard &quot;/queryChanges&quot; method as described in <xref target="RFC8620"/>, Section 5.6.
</t>
</section>
</section>

<section anchor="security-considerations" title="Security Considerations">
<t>All security considerations of JMAP <xref target="RFC8620"/> and JSCalendar <xref target="I-D.ietf-calext-jscalendar"/> apply to this specification. Additional considerations specific to the data types and functionality introduced by this document are described in the following subsections.
</t>

<section anchor="denialofservice-expanding-recurrences" title="Denial-of-service Expanding Recurrences">
<t>Recurrence rules can be crafted to occur as frequently as every second. Servers MUST be careful to not allow resources to be exhausted when expanding. Equally, rules can be generated that never create any occurrences at all. Servers MUST be careful to limit the work spent iterating in search of the next occurrence.
</t>
</section>

<section anchor="privacy" title="Privacy">
<t>TODO.
</t>
</section>
</section>

<section anchor="iana-considerations" title="IANA Considerations">

<section anchor="jmap-capability-registration-for-calendars" title="JMAP Capability Registration for &quot;calendars&quot;">
<t>IANA will register the &quot;calendars&quot; JMAP Capability as follows:
</t>
<t>Capability Name: <spanx style="verb">urn:ietf:params:jmap:calendars</spanx>
</t>
<t>Specification document: this document
</t>
<t>Intended use: common
</t>
<t>Change Controller: IETF
</t>
<t>Security and privacy considerations: this document, Section XXX
</t>
</section>

<section anchor="jscalendar-property-registrations" title="JSCalendar Property Registrations">
<t>IANA will register the following additional properties in the JSCalendar Properties Registry.
</t>

<section anchor="id" title="id">
<t>Property Name: id
</t>
<t>Property Type: <spanx style="verb">Id</spanx>
</t>
<t>Property Context: JSEvent, JSTask
</t>
<t>Intended Use: Reserved
</t>
</section>

<section anchor="calendarid" title="calendarId">
<t>Property Name: calendarId
</t>
<t>Property Type: <spanx style="verb">Id</spanx>
</t>
<t>Property Context: JSEvent, JSTask
</t>
<t>Intended Use: Reserved
</t>
</section>

<section anchor="isdraft" title="isDraft">
<t>Property Name: isDraft
</t>
<t>Property Type: <spanx style="verb">Boolean</spanx>
</t>
<t>Property Context: JSEvent, JSTask
</t>
<t>Intended Use: Reserved
</t>
</section>

<section anchor="utcstart" title="utcStart">
<t>Property Name: utcStart
</t>
<t>Property Type: <spanx style="verb">UTCDateTime</spanx>
</t>
<t>Property Context: JSEvent, JSTask
</t>
<t>Intended Use: Reserved
</t>
</section>

<section anchor="utcend" title="utcEnd">
<t>Property Name: utcEnd
</t>
<t>Property Type: <spanx style="verb">UTCDateTime</spanx>
</t>
<t>Property Context: JSEvent, JSTask
</t>
<t>Intended Use: Reserved
</t>
</section>

<section anchor="hideattendees-1" title="hideAttendees">
<t>Property Name: hideAttendees
</t>
<t>Property Type: <spanx style="verb">Boolean</spanx> (default: false)
</t>
<t>Property Context: JSEvent, JSTask
</t>
<t>Reference: This document, Section XXX.
</t>
<t>Intended Use: Common
</t>
</section>
</section>
</section>

</middle>
<back>
<references title="Normative References">
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-calext-jscalendar.xml"?>
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"?>
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2397.xml"?>
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5546.xml"?>
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"?>
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8620.xml"?>
</references>
<references title="Informative References">
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4791.xml"?>
<?rfc include="http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6047.xml"?>
</references>

</back>
</rfc>
