CalDAV REPORTメソッドを使ってスケジュール情報を取得する

CalDAV(RFC 4791)とは、iCalendar(RFC 2445)をWebDAV(RFC 4918)上でやり取りするための仕様です。

iCalendarは、スケジュールのカレンダー情報を記述するための仕様で、RSSのカレンダー版といったところでしょうか。そしてCalDAVはiCalendarをWebDAVプロトコルでやり取りするための仕組みです。
CalDAVに対応したクライアントは、MaciCalが一番有名です。あと、SunbirdなどもCalDAVに対応しています。
Google CalendarMaciCalから接続できたりするのは、このCalDAVプロトコルに依るところです。

RFC 2445を始めとするiCalendar関連の仕様は、非常に幅が広くワーキングドラフトまで含めるとPIMに必要な機能がほぼすべて揃っています。
関連仕様の説明と各仕様へのリンクについてはCalDAV HomeStarndardsにまとまっています。

早速、CalDAVで最も良く利用されるREPORTメソッドについて説明します。

REPORTメソッドは、CalDAV固有のメソッドで、iCalファイルを一度に取得するためのメソッドです。
(ちなみに、CalDAV固有のメソッドはもうひとつMKCALENDARメソッドのみです。)

WebDAVでファイルを取得するためのメソッドはGETですが、1月分のスケジュールを表示したいというような場合には、複数のiCalファイルを一度に取得する必要があります。
というのは、通常、CalDAVで扱う1つのファイルにはVCALENDARが1つ入っており、VCALENDARには一つVEVENTが入っています。(例外はあり、繰り返しイベントのようにVCALENDARには複数のVEVENTが入る場合もあります。)

つまり、CalDAVサーバー上には、各イベントが1つのiCalファイルとして扱われます。
REPORTメソッドは、「2010年4月のイベントを取得する」や「未承認のイベントを取得する」、「繰り返しイベントをある期間展開して取得する」など条件に合ったiCalファイルを取得するためのメソッドで、また、取得するデータに含めるプロパティも指定することができSQLのSELECT文と同じ働きをします。

以下は、2010年4月18日から4月24日のイベントを取得するクエリーです。Google Calendarに対して実行してみました。
(Google CalendarのCalDAVにアクセスする方法についてはこちらを参照ください)

REPORT /calendar/dav/hrendoh@gmail.com/events/ HTTP/1.1
Host: www.google.com
Depth: 1
Content-Type: application/xml; charset="utf-8"
Authorization: Basic XXXX
Content-Length: 467

<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:"
                  xmlns:C="urn:ietf:params:xml:ns:caldav">
  <D:prop>
    <D:getetag/>
    <C:calendar-data/>
  </D:prop>
  <C:filter>
    <C:comp-filter name="VCALENDAR">
      <C:comp-filter name="VEVENT">
        <C:time-range start="20060104T000000Z"
                      end="20060105T000000Z"/>
      </C:comp-filter>
    </C:comp-filter>
  </C:filter>
</C:calendar-query>

検索条件はfilter要素に指定します。
filter要素には以下の3種類の条件が指定できます。

  • comp-filter要素: カレンダーのコンポーネントに対する条件文を指定します。comp-filter要素は、time-range要素または、comp-prop要素を指定できます。上記の例はcomp-filterにtime-range要素を指定しています。
  • prop-filter要素: カレンダーのコンポーネントに対する条件文を指定します。子要素にパラメータを条件に指定するparam-filter要素を指定できます。ただし、prop-filterが実装されているサーバーは多くは無いようです。Google CalendarとBedeworkはフィルターが効きませんでした。
  • param-filter要素: カレンダーのコンポーネントのプロパティのパラメータに対する条件文を指定します。

上記のクエリーは以下の結果を返します。

<?xml version="1.0" encoding="UTF-8"?>
<D:multistatus xmlns:D="DAV:">
  <D:response>
    <D:href>/calendar/dav/hrendoh%40gmail.com/events/pocjt9sjnctri32i1auaj8ojao%40google.com.ics</D:href>
    <D:propstat>
      <D:status>HTTP/1.1 200 OK</D:status>
      <D:prop>
        <D:getetag>"63407192760"</D:getetag>
        <C:calendar-data xmlns:C="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
X-WR-CALNAME:Hiroyuki Endoh
X-WR-TIMEZONE:Asia/Tokyo
BEGIN:VTIMEZONE
TZID:Asia/Tokyo
X-LIC-LOCATION:Asia/Tokyo
BEGIN:STANDARD
TZOFFSETFROM:+0900
TZOFFSETTO:+0900
TZNAME:JST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;VALUE=DATE:20100420
DTEND;VALUE=DATE:20100421
DTSTAMP:20100417T130600Z
UID:pocjt9sjnctri32i1auaj8ojao@google.com
CREATED:20100417T130600Z
DESCRIPTION:
LAST-MODIFIED:20100417T130600Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:テスト
TRANSP:TRANSPARENT
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:This is an event reminder
TRIGGER:-P0DT0H10M0S
END:VALARM
END:VEVENT
END:VCALENDAR</C:calendar-data>
      </D:prop>
    </D:propstat>
  </D:response>
</D:multistatus>

上記の例では、カレンダーのプロパティをすべて取得します。
必要なプロパティのみを結果に含める場合には、calendar-data要素にcomp要素を指定します。

また、RRULEプロパティを含む繰り返しイベントは展開して取得することもできます。expand要素に展開する開始日(start属性)と終了日(end属性)を指定します。

以下は、18日から3日間のみ繰り返しを展開するようにexpand要素を指定しています。また、結果が長くなるのでcomp要素により取得するプロパティも絞り込んでいます。

プロパティの指定と、繰り返しイベントの展開は、Google Calendarでは実装されていませんでしたので、以下はBedeworkに対して実行しています。

REPORT http://localhost:8080/ucaldav/user/test1/calendar HTTP/1.1
Host: localhost:8080
Depth: 1
Content-Type: application/xml; charset="utf-8"
Authorization: Basic dGVzdDE6dGVzdA==
Content-Length: 999

<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:"
                  xmlns:C="urn:ietf:params:xml:ns:caldav">
  <D:prop>
    <C:calendar-data>
       <C:comp name="VCALENDAR">
         <C:prop name="VERSION"/>
         <C:comp name="VEVENT">
           <C:prop name="SUMMARY"/>
           <C:prop name="UID"/>
           <C:prop name="DTSTART"/>
           <C:prop name="DTEND"/>
           <C:prop name="DURATION"/>
           <C:prop name="RECURRENCE-ID"/>
         </C:comp>
         <C:comp name="VTIMEZONE"/>
      </C:comp>
      <C:expand  start="20100418T000000Z"
                              end="20100421T000000Z"/>
    </C:calendar-data>
  </D:prop>
  <C:filter>
    <C:comp-filter name="VCALENDAR">
      <C:comp-filter name="VEVENT">
        <C:time-range start="20100418T000000Z"
                      end="20100424T000000Z"/>
      </C:comp-filter>
    </C:comp-filter>
  </C:filter>
</C:calendar-query>

CalDAVサーバーには4月中毎日繰り返すイベントが登録されています。
応答は以下の通り、正しく18日から3日間だけ展開されています。

<?xml version="1.0" encoding="UTF-8" ?>

<multistatus xmlns="DAV:" xmlns:ns2="http://www.w3.org/2002/12/cal/ical#" xmlns:ns1="urn:ietf:params:xml:ns:caldav">
  <response>
    <href>/ucaldav/user/test1/calendar/47a3b8e0-4a2d-11df-bae6-001c23f8c3c1.ics</href>
    <propstat>
      <prop>
        <ns1:calendar-data><![CDATA[BEGIN:VCALENDAR
PRODID:BedeWork V3.5
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20100417T143109Z
SUMMARY:毎日
UID:47a3b8e0-4a2d-11df-bae6-001c23f8c3c1
DTSTART:20100418T020000Z
DTEND:20100418T030000Z
RECURRENCE-ID:20100418T110000Z
END:VEVENT
END:VCALENDAR
]]></ns1:calendar-data>
      </prop>
      <status>HTTP/1.1 200 ok</status>
    </propstat>
  </response>
  <response>
    <href>/ucaldav/user/test1/calendar/47a3b8e0-4a2d-11df-bae6-001c23f8c3c1.ics</href>
    <propstat>
      <prop>
        <ns1:calendar-data><![CDATA[BEGIN:VCALENDAR
PRODID:BedeWork V3.5
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20100417T143109Z
SUMMARY:毎日
UID:47a3b8e0-4a2d-11df-bae6-001c23f8c3c1
DTSTART:20100419T020000Z
DTEND:20100419T030000Z
RECURRENCE-ID:20100419T110000Z
END:VEVENT
END:VCALENDAR
]]></ns1:calendar-data>
      </prop>
      <status>HTTP/1.1 200 ok</status>
    </propstat>
  </response>
  <response>
    <href>/ucaldav/user/test1/calendar/47a3b8e0-4a2d-11df-bae6-001c23f8c3c1.ics</href>
    <propstat>
      <prop>
        <ns1:calendar-data><![CDATA[BEGIN:VCALENDAR
PRODID:BedeWork V3.5
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20100417T143109Z
SUMMARY:毎日
UID:47a3b8e0-4a2d-11df-bae6-001c23f8c3c1
DTSTART:20100420T020000Z
DTEND:20100420T030000Z
RECURRENCE-ID:20100420T110000Z
END:VEVENT
END:VCALENDAR
]]></ns1:calendar-data>
      </prop>
      <status>HTTP/1.1 200 ok</status>
    </propstat>
  </response>
</multistatus>