arnaudq's blog
Group event example using implicit scheduling
The iTIP specification (RFC 2446 or its Calsify successor) contains a group event example showing an initial invitation, a reply and an update to a group event.
The example only shows the messages that are exchanged between the different calendar clients. It does not show what each client would store in the actual calendars of the participants after each step. This is for good reason since iTIP defines only messages between CUAs and also because an iTIP aware client does not necessarily store the actual calendar in iCalendar format (might be a proprietary format).
But in any case, iTIP aware clients have to deal with 2 types of objects:
- iTIP messages (invitations, responses,...).
- calendar resources (the event and tasks that users see in their calendar).
Using the new CalDAV Scheduling model, this becomes much simpler since clients do need to worry only about their copy of the event. I'll try to show that by turning the above mentioned iTIP example into a CalDAV Scheduling example.
Organizer A invites B, C, D, and E (See 4.2.1 A Group Event Request in iTIP):
To initiate the group event , the organizer (A) simply creates a regular calendar resource in any of his calendar collections:
>> Request << PUT /home/A/calendar/qwue23489.ics HTTP/1.1 If-None-Match: * Host: cal.example.com Content-Type: text/calendar Content-Length: xxxx BEGIN:VCALENDAR PRODID:-//ACME/DesktopCalendar//EN VERSION:2.0 BEGIN:VEVENT ORGANIZER:Mailto:A@example.com ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=BIG A:Mailto:A@example.com ATTENDEE;RSVP=TRUE;TYPE=INDIVIDUAL;CN=B:Mailto:B@example.com ATTENDEE;RSVP=TRUE;TYPE=INDIVIDUAL;CN=C:Mailto:C@example.com ATTENDEE;RSVP=TRUE;TYPE=INDIVIDUAL;CN=Hal:Mailto:D@example.com ATTENDEE;RSVP=FALSE;TYPE=ROOM:conf_Big@example.com ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:Mailto:E@example.com DTSTAMP:20090611T190000Z DTSTART:20090701T200000Z DTEND:20090701T2000000Z SUMMARY:Conference UID:calsrv.example.com-873970198738777@example.com SEQUENCE:0 STATUS:CONFIRMED END:VEVENT END:VCALENDAR >> Response << HTTP/1.1 201 Created Content-Length: 0 Date: Thu, 11 Jun 2009 09:32:12 GMT
On storing this calendar resource, the server notices that it is a scheduling resource:
- the organizer is the owner of the calendar collection,
- the resource has attendees without a SCHEDULE-AGENT=CLIENT parameter.
As a consequence, the server will automatically deliver a copy of the same event in each attendee's calendar (and put a corresponding iTIP message in their scheduling inbox).
The Organizer client can check whether the delivery succeeded by doing a GET on the just created resource and checking the SCHEDULE-STATUS of each attendee:
>> Request << GET /home/A/calendar/qwue23489.ics HTTP/1.1 Host: cal.example.com >> Response << HTTP/1.1 200 OK Content-Type: text/calendar Content-Length: XXX Date: Thu, 11 Jun 2009 09:32:24 GMT ETag: "123456789-000-111" Schedule-Tag: "123456789-000-111" BEGIN:VCALENDAR PRODID:-//ACME/DesktopCalendar//EN VERSION:2.0 BEGIN:VEVENT ORGANIZER:Mailto:A@example.com ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=BIG A:Mailto:A@example.com ATTENDEE;SCHEDULE-STATUS="1.2";TYPE=INDIVIDUAL;CN=B:Mailto:B@example.com ATTENDEE;SCHEDULE-STATUS="1.2";TYPE=INDIVIDUAL;CN=C:Mailto:C@example.com ATTENDEE;SCHEDULE-STATUS="1.2";TYPE=INDIVIDUAL;CN=Hal:Mailto:D@example.com ATTENDEE;SCHEDULE-STATUS="1.2";TYPE=ROOM:conf_Big@example.com ATTENDEE;SCHEDULE-STATUS="1.2";ROLE=NON-PARTICIPANT:Mailto:E@example.com DTSTAMP:20090611T190000Z DTSTART:20090701T200000Z DTEND:20090701T2000000Z SUMMARY:Conference UID:calsrv.example.com-873970198738777@example.com SEQUENCE:0 STATUS:CONFIRMED END:VEVENT END:VCALENDAR
Reply from attendee B (See 4.2.2 Reply To A Group Event Request in iTIP. )
The calendar client of user B does a synchronization between its local cache and the default calendar collection of user B and fetches the event.
>> Request << GET /home/B/calendar/bzyw23492.ics HTTP/1.1 Host: cal.example.com >> Response << HTTP/1.1 200 OK Content-Type: text/calendar Content-Length: XXX Date: Thu, 11 Jun 2009 09:34:24 GMT ETag: "123456789-000-112" Schedule-Tag: "123456789-000-112" BEGIN:VCALENDAR PRODID:-//ACME/DesktopCalendar//EN VERSION:2.0 BEGIN:VEVENT ORGANIZER:Mailto:A@example.com ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=BIG A:Mailto:A@example.com ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;TYPE=INDIVIDUAL;CN=B:Mailto:B@example.com ATTENDEE;TYPE=INDIVIDUAL;CN=C:Mailto:C@example.com ATTENDEE;TYPE=INDIVIDUAL;CN=Hal:Mailto:D@example.com ATTENDEE;TYPE=ROOM:conf_Big@example.com ATTENDEE;ROLE=NON-PARTICIPANT:Mailto:E@example.com DTSTAMP:20090611T190000Z DTSTART:20090701T200000Z DTEND:20090701T2000000Z SUMMARY:Conference UID:calsrv.example.com-873970198738777@example.com SEQUENCE:0 STATUS:CONFIRMED END:VEVENT END:VCALENDAR
Attendee B accepts the invitation. The CUA simply does so by issuing a PUT on the same (attendee's) calendar resource, with an updated PARTSTAT for Attendee B. It makes use of the conditional If-Schedule-Tag-Match header to avoid minor update by other attendees conflicting with its own change:
>> Request << PUT /home/B/calendar/bzyw23492.ics HTTP/1.1 If-Schedule-Tag-Match: "123456789-000-112" Host: cal.example.com Content-Type: text/calendar Content-Length: xxxx BEGIN:VCALENDAR PRODID:-//ACME/DesktopCalendar//EN VERSION:2.0 BEGIN:VEVENT ORGANIZER:Mailto:A@example.com ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=BIG A:Mailto:A@example.com ATTENDEE;PARTSTAT=ACCEPTED;TYPE=INDIVIDUAL;CN=B:Mailto:B@example.com ATTENDEE;TYPE=INDIVIDUAL;CN=C:Mailto:C@example.com ATTENDEE;TYPE=INDIVIDUAL;CN=Hal:Mailto:D@example.com ATTENDEE;TYPE=ROOM:conf_Big@example.com ATTENDEE;ROLE=NON-PARTICIPANT:Mailto:E@example.com DTSTAMP:20090611T190000Z DTSTART:20090701T200000Z DTEND:20090701T2000000Z SUMMARY:Conference UID:calsrv.example.com-873970198738777@example.com SEQUENCE:0 STATUS:CONFIRMED END:VEVENT END:VCALENDAR>> Response << HTTP/1.1 204 No Content Content-Length: 0 Date: Thu, 11 Jun 2009 09:34:30 GMT
The server will then automatically process the reply and update the Organizer's copy accordingly.
Organizer receives the reply from Attendee B
The Organizer's CUA fetches the new version of the group meeting:
>> Request << GET /home/A/calendar/qwue23489.ics HTTP/1.1 Host: cal.example.com >> Response << HTTP/1.1 200 OK Content-Type: text/calendar Content-Length: XXX Date: Thu, 11 Jun 2009 09:40:24 GMT ETag: "123456789-000-333" Schedule-Tag: "123456789-000-333" BEGIN:VCALENDAR PRODID:-//ACME/DesktopCalendar//EN VERSION:2.0 BEGIN:VEVENT ORGANIZER:Mailto:A@example.com ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=BIG A:Mailto:A@example.com ATTENDEE;SCHEDULE-STATUS="2.0";PARTSTAT=ACCEPTED;TYPE=INDIVIDUAL;CN=B:Mailto:B@example.com ATTENDEE;SCHEDULE-STATUS="1.2";TYPE=INDIVIDUAL;CN=C:Mailto:C@example.com ATTENDEE;SCHEDULE-STATUS="1.2";TYPE=INDIVIDUAL;CN=Hal:Mailto:D@example.com ATTENDEE;SCHEDULE-STATUS="1.2";TYPE=ROOM:conf_Big@example.com ATTENDEE;SCHEDULE-STATUS="1.2";ROLE=NON-PARTICIPANT:Mailto:E@example.com DTSTAMP:20090611T190000Z DTSTART:20090701T200000Z DTEND:20090701T2000000Z SUMMARY:Conference UID:calsrv.example.com-873970198738777@example.com SEQUENCE:0 STATUS:CONFIRMED END:VEVENT END:VCALENDAR
Of course, this example is only scratching the surface of what it takes to create a good scheduling aware client but it shows that minimal scheduling processing can be achieved at a very low cost.
Posted at 05:44PM May 07, 2009 by arnaudq in CalDAV | Comments[2]
URI encoding in DAV:href element
The DAV:href xml element, defined in the WebDAV specification is used in many request/response payloads and DAV properties. It is important to note that the element value is a URI as defined in RFC3986.
As such, this value must be percent encoded if it contains characters outside the allowed range. When clients and server misinterpret this requirement, things can get messy. Here is some illustration:
If a calendar client knows about the principal collection of a user, it can retrieve the CalDAV calendar-home-set property of the user:
PROPFIND /dav/principals/johnd/ HTTP/1.1 host: dav.example.com content-type: text/xml content-lengh: xxx depth: 0 <?xml version="1.0" encoding="utf-8"?> <D:propfind xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:D="DAV:"> <D:prop> <C:calendar-home-set/> </D:prop> </D:propfind>
In this case, the calendar home was identified internally as '/dav/home/John.Doe@example.com/'. Our server was sending the following response:
HTTP/1.1 207 Multistatus
Date: xxx
Content-Type: application/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="UTF-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:response>
<D:href>/dav/principals/johnd/</D:href>
<D:propstat>
<D:prop>
<C:calendar-home-set><D:href>/dav/home/John.Doe%40example.com/</D:href></C:calendar-home-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
(Once percent encoded, the '@' character becomes '%40').
Using the returned calendar-home-set, the client would then get the list of calendars under this calendar home by issuing a Depth=1 PROPFIND query. But it would re encode the returned URI, resulting in a:
PROPFIND /dav/home/John.Doe%2540example.com/ HTTP/1.1
The client encoded '%' as '%25' and the server was interpreting the request as targeting a collection identified internally as /dav/home/John.Doe%40example.com/ which of course did not exist.
As it turned out, the '@' character is a reserved character but it is one of the few reserved characters allowed in the path component of a URI. So our server probably should not have encoded it in the first place.
But given that the URI was already encoded, the client should have either send it as is (i.e. without the need to either decode or reencode it):
PROPFIND /dav/home/John.Doe%40example.com/ HTTP/1.1
or with the '@' character decoded:
PROPFIND /dav/home/John.Doe@example.com/ HTTP/1.1
It looks like there are other cases of client/server misinterpreting those URIs.
Posted at 11:31AM Mar 13, 2009 by arnaudq in CalDAV | Comments[1]
VTODO with DUE date in other clients
To finish on the VTODO with DUE date topic, I've looked at some "not yet CalDAV enabled" clients.
Microsoft Outlook
In Outlook (more precisely, in Outlook 2003), you can create a task with a start and/or due date (no time). This task can have an associated alarm, which is specified as a date and time. This removes the ambiguity of using relative alarms, found in both Apple iCal and Lightning. It also allows to have a task with no start or due date and just an alarm.
eM Client
Using the eM Client , you can also create tasks. Both start and due date/time must be specified. This task can have an associated alarm, specified as a date and time.
Note: the eM client is CalDAV enabled for VEVENT but not yet for VTODOs.
Evolution
Evolution offers all combinations of start/due, using either date or date and time. Nevertheless, I could not find a way to set an alarm which is quite strange.
Note: Evolution is CalDAV enabled for VEVENT but not for VTODOs.
Sun Convergence
The Sun Convergence web client exposes only an optional due date (or date time). The associated email or sms alarm can be either relative or absolute ("On Date" in the pulldown below):

Posted at 03:05PM Mar 12, 2009 by arnaudq in CalDAV | Comments[0]
Convergence web client
A nice video showing the calendar capabilities of our new web client.
Posted at 06:46PM Mar 05, 2009 by arnaudq in CalDAV | Comments[0]
VTODO with DUE date in Lightning
Lightning 0.9 also let you create VTODOs (Tasks) and store them on a CalDAV Server. By default those tasks have no associated dates but one can add a due date + time:
Here is how such a task is stored on the CalDAV server:
... DUE;TZID=Europe/Paris:20090129T160000 ...
The VTODO component has a correct DUE property and no DTSTART.
If one tries to add an alarm to this task (trigger -15 minutes before), the start time of the task which was unset becomes auto selected and can not be removed (although it can be changed):
Here is how the VTODO is stored on the CalDAV Server:
... DTSTART;TZID=Europe/Paris:20090129T160000 DUE;TZID=Europe/Paris:20090129T160000 BEGIN:VALARM TRIGGER;VALUE=DURATION:-PT15M DESCRIPTION:Mozilla Alarm: New Task ACTION:DISPLAY END:VALARM ...
Here again, the TRIGGER property is missing a RELATED=END parameter to indicate that the alarm is relative to the due date. Instead, a DTSTART was added, "without the user's consent".
In addition, given that the DTSTART value is equal to the DUE value, this component is valid per RFC2445 but invalid per the new calsify spec where the DUE value must be later in time than the value of the DTSTART.
I should have started by stating that I'm not trying to put any judgment on the quality of one implementation over another but rather to see how todos with due date are used by clients, how they can interoperate, and maybe help future client implementations.
Posted at 06:48PM Jan 30, 2009 by arnaudq in CalDAV | Comments[0]