Display upcoming events in the Nextcloud calendar using a text-based terminal emulator because it is fun and challenging.
This article is quite lengthy as it includes XML output and parsed data for easier understanding.
Initial assumptions
Today’s date is Sun Dec 17 10:07:09 CET 2017
.
The start date will be defined as 20171217T000000
and end date as 20171218T000000
.
Nextcloud DAV resource is available at <a href="https://cloud.example.org/remote.php/dav/" rel="nofollow">https://cloud.example.org/remote.php/dav/</a>
using username crono
and application password zabie
.
Install the required software
Install curl utility to request and download Nextcloud calendar events.
$ sudo apt-get install curl
Install xmlstarlet utility to parse downloaded XML documents.
$ sudo apt-get install xmlstarlet
Create an application password
Define a unique password for an application in the NextCloud server, so it could be revoked later. Do not use your password.
Command-line operations
Get a path for the user’s principal resource on the server.
$ curl --silent \ --request PROPFIND \ --header 'Content-Type: text/xml' \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:"> <d:prop> <d:current-user-principal /> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/</d:href> <d:propstat> <d:prop> <d:current-user-principal> <d:href>/remote.php/dav/principals/users/crono/</d:href> </d:current-user-principal> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request PROPFIND \ --header 'Content-Type: text/xml' \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:"> <d:prop> <d:current-user-principal /> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/d:current-user-principal/d:href' -n
/remote.php/dav/principals/users/crono/
Get a path that contains calendar collections owned by the user using the user’s principal resource address obtained in the previous step.
$ curl --silent \ --request PROPFIND \ --header 'Content-Type: text/xml' \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav"> <d:prop> <c:calendar-home-set /> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/principals/users/crono/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/principals/users/crono/</d:href> <d:propstat> <d:prop> <cal:calendar-home-set> <d:href>/remote.php/dav/calendars/crono/</d:href> </cal:calendar-home-set> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request PROPFIND \ --header 'Content-Type: text/xml' \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav"> <d:prop> <c:calendar-home-set /> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/principals/users/crono/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/cal:calendar-home-set/d:href' -n
/remote.php/dav/calendars/crono/
Get calendar paths for the given collection.
$ curl --silent \ --request PROPFIND \ --header 'Content-Type: text/xml' \ --header 'Depth: 1' \ --data '<d:propfind xmlns:d="DAV:"> <d:prop> <d:displayname/> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://o wncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/</d:href> <d:propstat> <d:prop> <d:displayname/> </d:prop> <d:status>HTTP/1.1 404 Not Found</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/personal/</d:href> <d:propstat> <d:prop> <d:displayname>Personal</d:displayname> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/debian/</d:href> <d:propstat> <d:prop> <d:displayname>Debian</d:displayname> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/work/</d:href> <d:propstat> <d:prop> <d:displayname>Work</d:displayname> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/projects/</d:href> <d:propstat> <d:prop> <d:displayname>Projects</d:displayname> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/inbox/</d:href> <d:propstat> <d:prop> <d:displayname/> </d:prop> <d:status>HTTP/1.1 404 Not Found</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/outbox/</d:href> <d:propstat> <d:prop> <d:displayname/> </d:prop> <d:status>HTTP/1.1 404 Not Found</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request PROPFIND \ --header 'Content-Type: text/xml' \ --header 'Depth: 1' \ --data '<d:propfind xmlns:d="DAV:"> <d:prop> <d:displayname/> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/ | \ xmlstarlet sel -t -m 'd:multistatus/d:response' -i "string-length(d:propstat/d:prop/d:displayname)" -i "d:propstat/d:status='HTTP/1.1 200 OK'" -v "d:href" -n
/remote.php/dav/calendars/crono/personal/ /remote.php/dav/calendars/crono/debian/ /remote.php/dav/calendars/crono/work/ /remote.php/dav/calendars/crono/projects/
Get a calendar name.
$ curl --silent \ --request PROPFIND \ --header "Content-Type: text/xml" \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:"> <d:prop> <d:displayname/> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org//remote.php/dav/calendars/crono/personal/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/personal/</d:href> <d:propstat> <d:prop> <d:displayname>Personal</d:displayname> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request PROPFIND \ --header "Content-Type: text/xml" \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:"> <d:prop> <d:displayname/> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org//remote.php/dav/calendars/crono/personal/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/d:displayname' -n
Personal
Get event types stored in this calendar e.g. VTODO
, VEVENT
.
$ curl --silent \ --request PROPFIND \ --header "Content-Type: text/xml" \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav"> <d:prop> <cal:supported-calendar-component-set/> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org//remote.php/dav/calendars/crono/projects/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/projects/</d:href> <d:propstat> <d:prop> <cal:supported-calendar-component-set> <cal:comp name="VEVENT"/> <cal:comp name="VTODO"/> </cal:supported-calendar-component-set> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request PROPFIND \ --header "Content-Type: text/xml" \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav"> <d:prop> <cal:supported-calendar-component-set/> </d:prop> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org//remote.php/dav/calendars/crono/projects/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/cal:supported-calendar-component-set/cal:comp/@name' -n
VEVENT VTODO
Get today’s events.
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="20171217T000000" end="20171218T000000"/> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/personal/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/personal/Nextcloud-KKZ132DLC63FFE1S4T9B.ics</d:href> <d:propstat> <d:prop> <d:getetag>"ba8c6d9009abb08fa4ea2be6cbe2ebe9"</d:getetag> <cal:calendar-data>BEGIN:VCALENDAR PRODID:-//Nextcloud calendar v1.5.7 VERSION:2.0 CALSCALE:GREGORIAN BEGIN:VEVENT CREATED:20171216T221307 DTSTAMP:20171216T221307 LAST-MODIFIED:20171217T012313 UID:JW3J5YXFDDADD3DUISWGNR SUMMARY:Configure VPN for Netflix CLASS:PUBLIC STATUS:CONFIRMED DTSTART;VALUE=DATE:20171217 DTEND;VALUE=DATE:20171218 END:VEVENT END:VCALENDAR</cal:calendar-data> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/personal/Nextcloud-SLK1IPCBJPSIANH6LFY3TQ.ics</d:href> <d:propstat> <d:prop> <d:getetag>"0921b6eb221dbd4eadc68dc22ebc78dd"</d:getetag> <cal:calendar-data>BEGIN:VCALENDAR PRODID:-//Nextcloud calendar v1.5.7 VERSION:2.0 CALSCALE:GREGORIAN BEGIN:VEVENT CREATED:20171215T235237 DTSTAMP:20171215T235237 LAST-MODIFIED:20171217T012316 UID:VSTUTPGUYRHMWP6HXLP3G SUMMARY:Renew car insurance CLASS:PUBLIC STATUS:CONFIRMED DTSTART;VALUE=DATE:20171217 DTEND;VALUE=DATE:20171218 END:VEVENT END:VCALENDAR</cal:calendar-data> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="20171217T000000" end="20171218T000000"/> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/personal/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/cal:calendar-data' -n
BEGIN:VCALENDAR PRODID:-//Nextcloud calendar v1.5.7 VERSION:2.0 CALSCALE:GREGORIAN BEGIN:VEVENT CREATED:20171216T221307 DTSTAMP:20171216T221307 LAST-MODIFIED:20171217T012313 UID:JW3J5YXFDDADD3DUISWGNR SUMMARY:Configure VPN for Netflix CLASS:PUBLIC STATUS:CONFIRMED DTSTART;VALUE=DATE:20171217 DTEND;VALUE=DATE:20171218 END:VEVENT END:VCALENDAR BEGIN:VCALENDAR PRODID:-//Nextcloud calendar v1.5.7 VERSION:2.0 CALSCALE:GREGORIAN BEGIN:VEVENT CREATED:20171215T235237 DTSTAMP:20171215T235237 LAST-MODIFIED:20171217T012316 UID:VSTUTPGUYRHMWP6HXLP3G SUMMARY:Renew car insurance CLASS:PUBLIC STATUS:CONFIRMED DTSTART;VALUE=DATE:20171217 DTEND;VALUE=DATE:20171218 END:VEVENT END:VCALENDAR
Get tasks to be done today.
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="DUE"> <c:time-range start="20171217T000000" end="20171218T000000"/> <c:is-defined/> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/projects/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/projects/Nextcloud-3kmehrxc5bmio2wj1g8geb.ics</d:href> <d:propstat> <d:prop> <d:getetag>"574bf3275954deb3912d3ee34cfcece5"</d:getetag> <cal:calendar-data>BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20171215T210907 DTSTAMP:20171217T012302 LAST-MODIFIED:20171217T012302 UID:0phsdngneftk SUMMARY:Create blog post about CalDAV PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 DUE:20171217T225000 CATEGORIES:Idea END:VTODO END:VCALENDAR</cal:calendar-data> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="DUE"> <c:time-range start="20171217T000000" end="20171218T000000"/> <c:is-defined/> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/projects/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/cal:calendar-data' -n
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20171215T210907 DTSTAMP:20171217T012302 LAST-MODIFIED:20171217T012302 UID:0phsdngneftk SUMMARY:Create blog post about CalDAV PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 DUE:20171217T225000 CATEGORIES:Idea END:VTODO END:VCALENDAR
Get overdue tasks.
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="DUE"> <c:time-range end="20171217T000000"/> <c:is-defined/> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/projects/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/projects/Nextcloud-dejyd26qk1vzx8lq938ct.ics</d:href> <d:propstat> <d:prop> <d:getetag>"c2d6081a16ce1982086c1073225e6595"</d:getetag> <cal:calendar-data>BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20171215T235541 DTSTAMP:20171216T224646 LAST-MODIFIED:20171216T224646 UID:t9xf9ou7dz SUMMARY:Inspect RFC4791 PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 DUE:20171215T000000 STATUS:NEEDS-ACTION CATEGORIES:Idea END:VTODO END:VCALENDAR</cal:calendar-data> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="DUE"> <c:time-range end="20171217T000000"/> <c:is-defined/> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/projects/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/cal:calendar-data' -n
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20171215T235541 DTSTAMP:20171216T224646 LAST-MODIFIED:20171216T224646 UID:t9xf9ou7dz SUMMARY:Inspect RFC4791 PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 DUE:20171215T000000 STATUS:NEEDS-ACTION CATEGORIES:Idea END:VTODO END:VCALENDAR
Get tasks that belong to the “Idea” category but do not contain the “RFC” string.
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="SUMMARY"> <c:text-match negate-condition="yes" collation="i;ascii-casemap">rfc</c:text-match> </c:prop-filter> <c:prop-filter name="CATEGORIES"> <c:text-match collation="i;ascii-casemap">idea</c:text-match> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/projects/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/projects/Nextcloud-3kmehrxc5bmio2wj1g8geb.ics</d:href> <d:propstat> <d:prop> <d:getetag>"574bf3275954deb3912d3ee34cfcece5"</d:getetag> <cal:calendar-data>BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20171215T210907 DTSTAMP:20171217T012302 LAST-MODIFIED:20171217T012302 UID:0phsdngneftk SUMMARY:Create blog post about CalDAV PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 DUE:20171217T225000 CATEGORIES:Idea END:VTODO END:VCALENDAR</cal:calendar-data> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="SUMMARY"> <c:text-match negate-condition="yes" collation="i;ascii-casemap">rfc</c:text-match> </c:prop-filter> <c:prop-filter name="CATEGORIES"> <c:text-match collation="i;ascii-casemap">idea</c:text-match> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/projects/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/cal:calendar-data' -n
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20171215T210907 DTSTAMP:20171217T012302 LAST-MODIFIED:20171217T012302 UID:0phsdngneftk SUMMARY:Create blog post about CalDAV PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 DUE:20171217T225000 CATEGORIES:Idea END:VTODO END:VCALENDAR
Get tasks without a defined due date.
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="DUE"> <c:is-not-defined/> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/debian/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/debian/Nextcloud-4xuiemhm07tko9lfqumdhq.ics</d:href> <d:propstat> <d:prop> <d:getetag>"150984578c2b889bacb96df2ba8fdb8c"</d:getetag> <cal:calendar-data>BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20170801T233039 DTSTAMP:20171216T215618 LAST-MODIFIED:20171216T215618 UID:8wddgk2ytvi SUMMARY:Install OpenVPN PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 END:VTODO END:VCALENDAR</cal:calendar-data> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/calendars/crono/debian/Nextcloud-uxeoyrtcfhoo5orjm6gefi.ics</d:href> <d:propstat> <d:prop> <d:getetag>"3ff5ad3d4a982916d8995a59d77dd594"</d:getetag> <cal:calendar-data>BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20170801T225943 DTSTAMP:20171216T215443 LAST-MODIFIED:20171216T215443 UID:ygs9uj2lh3n SUMMARY:Upgrade iptables firewall PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 END:VTODO END:VCALENDAR</cal:calendar-data> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>
$ curl --silent \ --request REPORT \ --header "Depth: 1" \ --header "Content-Type: text/xml" \ --data '<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="VTODO"> <c:prop-filter name="DUE"> <c:is-not-defined/> </c:prop-filter> <c:prop-filter name="COMPLETED"> <c:is-not-defined/> </c:prop-filter> </c:comp-filter> </c:comp-filter> </c:filter> </c:calendar-query>' \ --user crono:zabie \ https://cloud.example.org/remote.php/dav/calendars/crono/debian/ | \ xmlstarlet sel -t -v 'd:multistatus/d:response/d:propstat/d:prop/cal:calendar-data' -n
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20170801T233039 DTSTAMP:20171216T215618 LAST-MODIFIED:20171216T215618 UID:8wddgk2ytvi SUMMARY:Install OpenVPN PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 END:VTODO END:VCALENDAR BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Nextcloud Tasks v0.9.5 BEGIN:VTODO CREATED:20170801T225943 DTSTAMP:20171216T215443 LAST-MODIFIED:20171216T215443 UID:ygs9uj2lh3n SUMMARY:Upgrade iptables firewall PRIORITY:0 PERCENT-COMPLETE:0 X-OC-HIDESUBTASKS:0 END:VTODO END:VCALENDAR
Additional notes
You can return all property names and values on the calendar resource.
$ curl --silent \ --request PROPFIND \ --header "Content-Type: text/xml" \ --header 'Depth: 0' \ --data '<d:propfind xmlns:d="DAV:"> <d:allprop/> </d:propfind>' \ --user crono:zabie \ https://cloud.example.org//remote.php/dav/calendars/crono/personal/ | \ xmlstarlet format
<?xml version="1.0"?> <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <d:response> <d:href>/remote.php/dav/calendars/crono/personal/</d:href> <d:propstat> <d:prop> <d:resourcetype> <d:collection/> <cal:calendar/> </d:resourcetype> <cs:getctag>http://sabre.io/ns/sync/57</cs:getctag> <s:sync-token>57</s:sync-token> <cal:supported-calendar-component-set> <cal:comp name="VEVENT"/> <cal:comp name="VTODO"/> </cal:supported-calendar-component-set> <cal:schedule-calendar-transp> <cal:opaque/> </cal:schedule-calendar-transp> <oc:owner-principal>principals/users/crono</oc:owner-principal> <d:displayname>Personal</d:displayname> <x1:calendar-order xmlns:x1="http://apple.com/ns/ical/">0</x1:calendar-order> <x1:calendar-color xmlns:x1="http://apple.com/ns/ical/">#63DA38</x1:calendar-color> <x2:owner-displayname xmlns:x2="http://nextcloud.com/ns">crono</x2:owner-displayname> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> </d:multistatus>