I'm trying to get a list of calendars owned by the current user from a CalDAV server.
I was able to obtain this information using our initial test account with the following request:
PROPFIND /calendars/users/test/
<propfind xmlns='DAV:'>
<allprop/>
</propfind>
The result is a <multistatus>
element with several <response>
elements. If I extract the elements where resourcetype
is calendar, I get my list of calendars.
However, when we added additional users, this produces a "Not Found" error, so I instead used a "principal-match" request to obtain the current user's "calendar-home-set" path.
That path looks like /d817aaec-7d24-5b38-bc2f-6369da72cdd9/. So I tried the above request with this path. Now the result is a <multistatus>
element with only a single <response>
element. It does not contain any calendars. The first response is exactly like the first response from in my original request.
I can't for the life of me figure out the magic sauce that would allow me to get the users list of calendars in all cases.
EDIT:
Here's some of my code. The "/calendars/users/test/" URL I tried initially is returned from GetRequestAddress()
. My second case where I used principal-match
to get the calendar path used CalendarHomeSet
(both shown below).
Headers["Depth"] = "1";
//XElement xmlResult = UploadXml(GetRequestAddress(), // Alternatively, CalendarHomeSet
method: CalDavMethod.PropertyFind,
xml: XDocument.Parse("<propfind xmlns='DAV:'>" +
"<allprop/>" +
"</propfind>").Root);
private string GetRequestAddress(string calendarHRef = null, string resource = null)
{
string path = calendarHRef;
if (String.IsNullOrWhiteSpace(path))
path = String.Format("/calendars/users/{0}/", UserName);
if (!String.IsNullOrWhiteSpace(resource))
path = Path.Combine(path, resource);
return path;
}
/// <summary>
/// Gets/sets the path to the parent folder of any calendar subfolders
/// owned by the current user.
/// </summary>
public string CalendarHomeSet
{
get
{
if (calendarHomeSet == null)
{
Headers["Depth"] = "0";
XElement xmlResult = UploadXml(String.Format("/principals/users/{0}/", UserName),
method: "REPORT",
xml: XDocument.Parse(XmlHeader +
"<D:principal-match xmlns:D=\"DAV:\">" +
"<D:self/>" +
"<D:prop>" +
"<C:calendar-home-set xmlns:C=\"urn:ietf:params:xml:ns:caldav\"/>" +
"</D:prop>" +
"</D:principal-match>").Root);
//
XElement el = xmlResult.Descendants(CalDavXmlns + "calendar-home-set").FirstOrDefault();
if (el != null)
{
calendarHomeSet = (string)el;
if (!calendarHomeSet.EndsWith("/"))
calendarHomeSet += '/';
}
}
return calendarHomeSet;
}
set
{
calendarHomeSet = value;
}
}
private string calendarHomeSet = null;
SECOND EDIT:
Here are some more details about the exact contents of my requests and responses. In the first one, notice that the results include a collection followed by two calendar collections.
PROPFIND /calendars/users/test/
<propfind xmlns="DAV:">
<allprop />
</propfind>
Response:
<multistatus xmlns="DAV:">
<response>
<href>/calendars/users/test/</href>
<propstat>
<prop>
<getetag>"4293-1000-4FFC9A16"</getetag>
<current-user-principal>
<href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
</current-user-principal>
<displayname>Test User</displayname>
<getcontenttype>httpd/unix-directory</getcontenttype>
<supportedlock>
<lockentry>
<lockscope>
<exclusive />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
<lockentry>
<lockscope>
<shared />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
</supportedlock>
<resourcetype>
<collection />
</resourcetype>
<getcontentlength />
<getlastmodified>Tue, 10 Jul 2012 21:09:42 GMT</getlastmodified>
<creationdate>2012-07-10T21:09:42Z</creationdate>
<resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalendarHomeFile</resource-class>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>/calendars/users/test/calendar/</href>
<propstat>
<prop>
<getetag>"42DB-1000-50108ABC"</getetag>
<current-user-principal>
<href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
</current-user-principal>
<calendar-order xmlns="http://apple.com/ns/ical/">1</calendar-order>
<displayname>calendar</displayname>
<calendar-color xmlns="http://apple.com/ns/ical/">#F64F00FF</calendar-color>
<getctag xmlns="http://calendarserver.org/ns/">2012-07-26 00:09:32.361284</getctag>
<getcontenttype>httpd/unix-directory</getcontenttype>
<supportedlock>
<lockentry>
<lockscope>
<exclusive />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
<lockentry>
<lockscope>
<shared />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
</supportedlock>
<resourcetype>
<collection />
<calendar xmlns="urn:ietf:params:xml:ns:caldav" />
</resourcetype>
<getcontentlength />
<schedule-calendar-transp xmlns="urn:ietf:params:xml:ns:caldav">
<opaque />
</schedule-calendar-transp>
<getlastmodified>Thu, 26 Jul 2012 00:09:32 GMT</getlastmodified>
<creationdate>2012-07-26T00:09:32Z</creationdate>
<resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalDAVFile</resource-class>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>/calendars/users/test/8C1F393E-04E8-428A-819A-933C3A9338AD/</href>
<propstat>
<prop>
<getetag>"43AA-1000-50079D1C"</getetag>
<current-user-principal>
<href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
</current-user-principal>
<calendar-order xmlns="http://apple.com/ns/ical/">0</calendar-order>
<displayname>Jon Wood Calendar</displayname>
<calendar-color xmlns="http://apple.com/ns/ical/">#711a76</calendar-color>
<getctag xmlns="http://calendarserver.org/ns/">2012-07-19 05:37:32.673835</getctag>
<getcontenttype>httpd/unix-directory</getcontenttype>
<supportedlock>
<lockentry>
<lockscope>
<exclusive />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
<lockentry>
<lockscope>
<shared />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
</supportedlock>
<resourcetype>
<collection />
<calendar xmlns="urn:ietf:params:xml:ns:caldav" />
</resourcetype>
<getcontentlength />
<schedule-calendar-transp xmlns="urn:ietf:params:xml:ns:caldav">
<transparent />
</schedule-calendar-transp>
<getlastmodified>Thu, 19 Jul 2012 05:37:32 GMT</getlastmodified>
<creationdate>2012-07-19T05:37:32Z</creationdate>
<resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalDAVFile</resource-class>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>/calendars/users/test/outbox/</href>
<propstat>
<prop>
<getetag>"D4E-1000-4FFB15AF"</getetag>
<current-user-principal>
<href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
</current-user-principal>
<displayname>outbox</displayname>
<getctag xmlns="http://calendarserver.org/ns/">2012-07-09 17:32:31.950308</getctag>
<getcontenttype>httpd/unix-directory</getcontenttype>
<supportedlock>
<lockentry>
<lockscope>
<exclusive />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
<lockentry>
<lockscope>
<shared />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
</supportedlock>
<resourcetype>
<collection />
<schedule-outbox xmlns="urn:ietf:params:xml:ns:caldav" />
</resourcetype>
<getcontentlength />
<getlastmodified>Mon, 09 Jul 2012 17:32:31 GMT</getlastmodified>
<creationdate>2012-07-09T17:32:31Z</creationdate>
<resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">ScheduleOutboxFile</resource-class>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>/calendars/users/test/freebusy</href>
<propstat>
<prop>
<getetag>"D7D-0-4FFC3F7C"</getetag>
<current-user-principal>
<href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
</current-user-principal>
<displayname>freebusy</displayname>
<getcontenttype>text/plain</getcontenttype>
<supportedlock>
<lockentry>
<lockscope>
<exclusive />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
<lockentry>
<lockscope>
<shared />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
</supportedlock>
<resourcetype>
<free-busy-url xmlns="http://calendarserver.org/ns/" />
</resourcetype>
<getcontentlength>0</getcontentlength>
<getlastmodified>Tue, 10 Jul 2012 14:43:08 GMT</getlastmodified>
<creationdate>2012-07-10T14:43:08Z</creationdate>
<resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">FreeBusyURLFile</resource-class>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>/calendars/users/test/inbox/</href>
<propstat>
<prop>
<getetag>"42FB-1000-4FF21C60"</getetag>
<current-user-principal>
<href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
</current-user-principal>
<displayname>inbox</displayname>
<getctag xmlns="http://calendarserver.org/ns/">2012-07-02 22:10:40.527683</getctag>
<getcontenttype>httpd/unix-directory</getcontenttype>
<supportedlock>
<lockentry>
<lockscope>
<exclusive />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
<lockentry>
<lockscope>
<shared />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
</supportedlock>
<resourcetype>
<collection />
<schedule-inbox xmlns="urn:ietf:params:xml:ns:caldav" />
</resourcetype>
<getcontentlength />
<schedule-default-calendar-URL xmlns="urn:ietf:params:xml:ns:caldav">
<href xmlns="DAV:">/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/calendar</href>
</schedule-default-calendar-URL>
<getlastmodified>Mon, 02 Jul 2012 22:10:40 GMT</getlastmodified>
<creationdate>2012-07-02T22:10:40Z</creationdate>
<resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">ScheduleInboxFile</resource-class>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
Next, I tried the same request except against a different URL. This time, I used a URL I obtained by querying the principal. Now the results still contain that initial collection, but they don't contain the calendars.
PROPFIND /calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/ (CalendarHomeSet)
<propfind xmlns="DAV:">
<allprop />
</propfind>
Response:
<multistatus xmlns="DAV:">
<response>
<href>/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
<propstat>
<prop>
<getetag>"4293-1000-4FFC9A16"</getetag>
<current-user-principal>
<href>/principals/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9/</href>
</current-user-principal>
<displayname>Test User</displayname>
<getcontenttype>httpd/unix-directory</getcontenttype>
<supportedlock>
<lockentry>
<lockscope>
<exclusive />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
<lockentry>
<lockscope>
<shared />
</lockscope>
<locktype>
<write />
</locktype>
</lockentry>
</supportedlock>
<resourcetype>
<collection />
</resourcetype>
<getcontentlength />
<getlastmodified>Tue, 10 Jul 2012 21:09:42 GMT</getlastmodified>
<creationdate>2012-07-10T21:09:42Z</creationdate>
<resource-class xmlns="http://twistedmatrix.com/xml_namespace/dav/">CalendarHomeFile</resource-class>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
THIRD EDIT:
And here's the request and response I used to get the calendar home set:
REPORT /principals/users/test/
<D:principal-match xmlns:D="DAV:">
<D:self />
<D:prop>
<C:calendar-home-set xmlns:C="urn:ietf:params:xml:ns:caldav" />
</D:prop>
</D:principal-match>
Response:
<multistatus xmlns="DAV:">
<response>
<href>/principals/users/test/</href>
<propstat>
<prop>
<calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
<href xmlns="DAV:">/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9</href>
</calendar-home-set>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
Two things I can think of right now:
If those pointers don't help, you should show the full requests and responses.
EDIT
This is how you should typically do discovery in CalDAV.
I have a feeling that because you do a principal-match, and don't use current-user-principal; this is going a bit wrong. But I'm not fully sure. My hunch is simply that your detected calendar-home-set is wrong.