<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>calendar &amp;mdash; Jerry of the Week</title>
    <link>https://write.in0rdr.ch/tag:calendar</link>
    <description>ˈdʒɛri - Individual who sends life against the grain no matter the consequences</description>
    <pubDate>Thu, 16 Apr 2026 04:46:13 +0000</pubDate>
    <item>
      <title>CalDav calendar discovery</title>
      <link>https://write.in0rdr.ch/caldav-calendar-discovery</link>
      <description>&lt;![CDATA[I found myself in the unfortunate situation to discover a CalDav uri using different providers. In this short post I guide you through a generic example flow which should work for most calendar providers.&#xA;&#xA;#caldav #scripting #calendar&#xA;!--more--&#xA;&#xA;The discovery process can be described as follows:&#xA;&#xA;Get user principal&#xA;Find home set of user principal&#xA;Get calendar from home set&#xA;Fetch all events from calendar&#xA;&#xA;The individual steps can be tested with curl commands. These curl commands depict the request flow and should work with any provider.&#xA;&#xA;1. Get principal&#xA;&#xA;First, read the principal:&#xA;cat &lt;&lt;EOF | curl -s -d @- -XPROPFIND \&#xA;  -H &#34;Content-Type: application/xml&#34; \&#xA;  -H &#34;Depth: 0&#34; -u &#39;$USER:$PASSWORD&#39; -L $CALDAVHOST \&#xA;  | xmllint --format -&#xA;d:propfind xmlns:d=&#34;DAV:&#34;&#xA; d:prop&#xA;  d:current-user-principal /&#xA; /d:prop&#xA;/d:propfind&#xA;EOF&#xA;The principal path ($PRINCIPAL) is returned in the XML response tag&#xA;DAV:current-user-principal.&#xA;&#xA;2. Find home set&#xA;&#xA;Get calendar home set for the principal:&#xA;cat &lt;&lt;EOF | curl -s -d @- -XPROPFIND \&#xA;  -H &#34;Content-Type: application/xml&#34; \&#xA;  -H &#34;Depth: 0&#34; -u &#39;$USER:$PASSWORD&#39; $CALDAVHOST/$PRINCIPAL \&#xA;  | xmllint --format -&#xA;d:propfind xmlns:d=&#34;DAV:&#34; xmlns:c=&#34;urn:ietf:params:xml:ns:caldav&#34;&#xA; d:prop&#xA;  c:calendar-home-set /&#xA; /d:prop&#xA;/d:propfind&#xA;EOF&#xA;The users calendar home set $HOMESET is returned in the&#xA;calendar-home-set XML tag.&#xA;&#xA;3. Get calendar&#xA;&#xA;This home set contains all calendars of the user. Finally, to list the&#xA;calendars:&#xA;cat &lt;&lt;EOF | curl -s -d @- -XPROPFIND \&#xA;  -H &#34;Content-Type: application/xml&#34; \&#xA;  -H &#34;Depth: 1&#34; -u &#39;$USER:$PASSWORD&#39; $CALDAVHOST/$HOMESET \&#xA;  | xmllint --format -&#xA;d:propfind xmlns:d=&#34;DAV:&#34; xmlns:cs=&#34;http://calendarserver.org/ns/&#34; xmlns:c=&#34;urn:ietf:params:xml:ns:caldav&#34;&#xA; d:prop&#xA;  d:resourcetype /&#xA;  d:displayname /&#xA;  cs:getctag /&#xA;  c:supported-calendar-component-set /&#xA; /d:prop&#xA;/d:propfind&#xA;EOF&#xA;Choose a calendar CalDav URI to sync with a particular calendar. The DAV:href path in the response is referenced with $CALENDAR below for illustration purposes.&#xA;&#xA;4. Fetch all events&#xA;&#xA;This part is specific to your application. An example to fetch all events:&#xA;cat &lt;&lt;EOF | curl -s -d @- -XREPORT -H &#34;Content-Type: application/xml&#34; \&#xA;  -H &#34;Depth: 1&#34; -u &#39;$USER:$PASSWORD&#39; $CALDAVHOST/$CALENDAR \&#xA;  | xmllint --format -&#xA;c:calendar-query xmlns:d=&#34;DAV:&#34; xmlns:c=&#34;urn:ietf:params:xml:ns:caldav&#34;&#xA; d:prop&#xA;  d:getetag /&#xA;  c:calendar-data /&#xA; /d:prop&#xA; c:filter&#xA;  c:comp-filter name=&#34;VCALENDAR&#34;&#xA;   c:comp-filter name=&#34;VEVENT&#34; /&#xA;  /c:comp-filter&#xA; /c:filter&#xA;/c:calendar-query&#xA;EOF&#xA;&#xA;I hope this post helps you to discover user principals and calendar home sets for your specific calendar use case. If the post was too short and concise for you, read this 🤓. I can also suggest to read Building a CalDAV client on sabre.io to get started with your own client.&#xA;&#xA;div style=&#34;text-align:center; font-size: 0.8em&#34;&#xD;&#xA;a href=&#34;https://write.in0rdr.ch/feed&#34;&amp;#128732; RSS/a | a href=&#34;https://m.in0rdr.ch/in0rdr&#34;&amp;#128024; Fediverse/a | a href=&#34;https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch&#34;&amp;#128172; XMPP/a&#xD;&#xA;/div]]&gt;</description>
      <content:encoded><![CDATA[<p>I found myself in the unfortunate situation to discover a CalDav uri using different providers. In this short post I guide you through a generic example flow which should work for most calendar providers.</p>

<p><a href="https://write.in0rdr.ch/tag:caldav" class="hashtag"><span>#</span><span class="p-category">caldav</span></a> <a href="https://write.in0rdr.ch/tag:scripting" class="hashtag"><span>#</span><span class="p-category">scripting</span></a> <a href="https://write.in0rdr.ch/tag:calendar" class="hashtag"><span>#</span><span class="p-category">calendar</span></a>
</p>

<p>The discovery process can be described as follows:</p>
<ol><li>Get user principal</li>
<li>Find home set of user principal</li>
<li>Get calendar from home set</li>
<li>Fetch all events from calendar</li></ol>

<p>The individual steps can be tested with curl commands. These curl commands depict the request flow and should work with any provider.</p>

<h2 id="1-get-principal">1. Get principal</h2>

<p>First, read the principal:</p>

<pre><code class="language-bash">cat &lt;&lt;EOF | curl -s -d @- -XPROPFIND \
  -H &#34;Content-Type: application/xml&#34; \
  -H &#34;Depth: 0&#34; -u &#39;$USER:$PASSWORD&#39; -L $CALDAV_HOST \
  | xmllint --format -
&lt;d:propfind xmlns:d=&#34;DAV:&#34;&gt;
 &lt;d:prop&gt;
  &lt;d:current-user-principal /&gt;
 &lt;/d:prop&gt;
&lt;/d:propfind&gt;
EOF
</code></pre>

<p>The principal path (<code>$PRINCIPAL</code>) is returned in the XML response tag
<code>&lt;DAV:current-user-principal&gt;</code>.</p>

<h2 id="2-find-home-set">2. Find home set</h2>

<p>Get calendar home set for the principal:</p>

<pre><code class="language-bash">cat &lt;&lt;EOF | curl -s -d @- -XPROPFIND \
  -H &#34;Content-Type: application/xml&#34; \
  -H &#34;Depth: 0&#34; -u &#39;$USER:$PASSWORD&#39; $CALDAV_HOST/$PRINCIPAL \
  | xmllint --format -
&lt;d:propfind xmlns:d=&#34;DAV:&#34; xmlns:c=&#34;urn:ietf:params:xml:ns:caldav&#34;&gt;
 &lt;d:prop&gt;
  &lt;c:calendar-home-set /&gt;
 &lt;/d:prop&gt;
&lt;/d:propfind&gt;
EOF
</code></pre>

<p>The users calendar home set <code>$HOME_SET</code> is returned in the
<code>&lt;calendar-home-set&gt;</code> XML tag.</p>

<h2 id="3-get-calendar">3. Get calendar</h2>

<p>This home set contains all calendars of the user. Finally, to list the
calendars:</p>

<pre><code class="language-bash">cat &lt;&lt;EOF | curl -s -d @- -XPROPFIND \
  -H &#34;Content-Type: application/xml&#34; \
  -H &#34;Depth: 1&#34; -u &#39;$USER:$PASSWORD&#39; $CALDAV_HOST/$HOME_SET \
  | xmllint --format -
&lt;d:propfind xmlns:d=&#34;DAV:&#34; xmlns:cs=&#34;http://calendarserver.org/ns/&#34; xmlns:c=&#34;urn:ietf:params:xml:ns:caldav&#34;&gt;
 &lt;d:prop&gt;
  &lt;d:resourcetype /&gt;
  &lt;d:displayname /&gt;
  &lt;cs:getctag /&gt;
  &lt;c:supported-calendar-component-set /&gt;
 &lt;/d:prop&gt;
&lt;/d:propfind&gt;
EOF
</code></pre>

<p>Choose a calendar CalDav URI to sync with a particular calendar. The <code>&lt;DAV:href&gt;</code> path in the response is referenced with <code>$CALENDAR</code> below for illustration purposes.</p>

<h2 id="4-fetch-all-events">4. Fetch all events</h2>

<p>This part is specific to your application. An example to fetch all events:</p>

<pre><code class="language-bash">cat &lt;&lt;EOF | curl -s -d @- -XREPORT -H &#34;Content-Type: application/xml&#34; \
  -H &#34;Depth: 1&#34; -u &#39;$USER:$PASSWORD&#39; $CALDAV_HOST/$CALENDAR \
  | xmllint --format -
&lt;c:calendar-query xmlns:d=&#34;DAV:&#34; xmlns:c=&#34;urn:ietf:params:xml:ns:caldav&#34;&gt;
 &lt;d:prop&gt;
  &lt;d:getetag /&gt;
  &lt;c:calendar-data /&gt;
 &lt;/d:prop&gt;
 &lt;c:filter&gt;
  &lt;c:comp-filter name=&#34;VCALENDAR&#34;&gt;
   &lt;c:comp-filter name=&#34;VEVENT&#34; /&gt;
  &lt;/c:comp-filter&gt;
 &lt;/c:filter&gt;
&lt;/c:calendar-query&gt;
EOF
</code></pre>

<p>I hope this post helps you to discover user principals and calendar home sets for your specific calendar use case. If the post was too short and concise for you, read <a href="https://datatracker.ietf.org/doc/html/rfc4791">this</a> 🤓. I can also suggest to read <a href="https://sabre.io/dav/building-a-caldav-client">Building a CalDAV client</a> on sabre.io to get started with your own client.</p>

<div style="text-align:center; font-size: 0.8em">
<a href="https://write.in0rdr.ch/feed">🛜 RSS</a> | <a href="https://m.in0rdr.ch/in0rdr">🐘 Fediverse</a> | <a href="https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch">💬 XMPP</a>
</div>
]]></content:encoded>
      <guid>https://write.in0rdr.ch/caldav-calendar-discovery</guid>
      <pubDate>Sun, 16 Jun 2024 09:23:49 +0000</pubDate>
    </item>
  </channel>
</rss>