caldav::CalDAV instproc PROPFIND (public)
<instance of caldav::CalDAV> PROPFIND
Defined in /var/www/openacs.org/packages/caldav/tcl/caldav-procs.tcl
read and answer PROPFIND requests RFC 2518, section 8.1 https://tools.ietf.org/html/rfc4918#page-35
- Testcases:
- PROPFIND_ios, PROPFIND_android, PROPFIND_thunderbird, Thunderbird_subscribe, macOS_subscribe
Source code: #https://github.com/seiyanuta/busybook/blob/master/Documentation/caldav-request-examples.md # Do a PROPFIND on the url the user supplied, requesting {DAV:}current-user-principal. # Using this url, you do a PROPFIND to find out more information about the user. # Here, you should typically request for the calendar-home-set property in the caldav namespace. # Then, using the calendar-home-set, do a PROPFIND (depth: 1) to find the calendars. # A client MUST submit a Depth header with a value of "0", "1", # or "infinity" with a PROPFIND request. Servers MUST support # "0" and "1" depth requests on WebDAV-compliant resources and # SHOULD support "infinity" requests. Servers SHOULD treat a # request without a Depth header as if a "Depth: infinity" # header was included. # set depth [ns_set iget [ns_conn headers] Depth "infinity"] #ns_log notice "caldav: depth = $depth" set content [:getcontent {Depth "infinity"}] set doc [:parseRequest $content] ns_log notice "after parseRequest <$content>" if {$doc eq ""} { return [:request_error "could not parse request. Probably invalid XML"] } set root [$doc documentElement] # # Element name of root node must be "propfind" # if {[$root localName] ne "propfind"} { $doc delete return [:request_error "invalid request, no <propfind> element"] } set prop [$root firstChild] # # child of root must be prop or allprop # set elementName [$prop localName] if {$elementName ni {prop allprop}} { $doc delete return [:request_error "invalid request, no <prop> or <allprop> element, but '$elementName' provided"] } # # Special case allprop: return all properties # if {$elementName eq "allprop"} { dom parse -- { <A:prop xmlns:A="DAV:"> <A:getcontenttype/> <A:getetag/> <A:sync-token/> <A:supported-report-set/> <c:getctag xmlns:c="http://calendarserver.org/ns/"/> <A:resourcetype/> <B:supported-calendar-component-set xmlns:B="urn:ietf:params:xml:ns:caldav"/> <B:calendar-home-set xmlns:B="urn:ietf:params:xml:ns:caldav"/> <A:displayname/> <A:current-user-principal/> </A:prop> } propTree set prop [$propTree firstChild] } set response "" # The incoming request URI should fall into the following categories # # - TOPLEVEL: /caldav # - PRINCIPAL: /caldav/principal # - FULL CALENDAR: /caldav/calendar # # GN TODO: remove the following test when we are sure it is ok. #ns_log notice "PROPFIND <${:uri}>, tail <[file tail ${:uri}]> urlv: <${:urlv}>" if {[file tail ${:uri}] ne [lindex ${:urlv} end]} { ns_log notice "========================== <[file tail ${:uri}]> ne <[lindex ${:urlv} end]>" error } switch [lindex ${:urlv} end] { "" { ns_log notice "=== CalDAV /caldav/ depth $depth" append response [:generateResponse -queryType top -user_id ${:user_id} $prop] if {$depth ne "0"} { # # Not sure, what should be sent in such cases. we # could send "principal" or "calendar" replies. ns_log notice "CalDAV /caldav/ query <${:uri}> with depth $depth" #append response [:generateResponse -queryType principal $prop] } } "principal" { # A principal is a network resource that represents a distinct human or # computational actor that initiates access to network resources. # https://tools.ietf.org/html/rfc3744 append response [:generateResponse -queryType principal $prop] # # here we ignore depth for the time being # } "calendar" { # TODO: we assume, we are working on the aggregated calendar :calendar_ids "" #set calendar_id [::caldav::get_sync_calendar -user_id ${:user_id}] #append response [:generateResponse -queryType calendar -calendar_id $calendar_id $prop] append response [:generateResponse -queryType calendar -calendar_id "" $prop] #ns_log notice "=== CALENDAR depth $depth FIND getetag=[$prop selectNodes -namespaces {d DAV:} //d:getetag] PROP [$prop asXML] " if {$depth ne "0"} { # # Search in depth 1 to deeper. Since all our # calendar data is at depth 1, there is no need to # differentiate. # # GN TODO: In general, PROPFIND on calendars is # needed also without etags, not sure, where the # restriction concerning "etag"comes from. # if {[$prop selectNodes -namespaces {d DAV:} //d:getetag] ne ""} { # # Query attributes containing also etags for # this users' resources # foreach item [calendars get_calitems -user_id ${:user_id}] { append response [:generateResponse -queryType resource -cal_item $item $prop] } } else { ns_log notice "CalDAV: ===== calendar query on components with depth $depth on [$prop asXML]" } } } default { $doc delete ad_log warning "caldav: PROFIND called for unknown resource: '${:uri}'" :response 404 text/plain "no such resource: '${:uri}'" return #return [:request_error "invalid URI '${:uri}'"] } } # create response append resp {<?xml version="1.0" encoding="utf-8" ?>} \n {<d:multistatus } {xmlns:d="DAV:" } {xmlns:cs="http://calendarserver.org/ns/" } {xmlns:c="urn:ietf:params:xml:ns:caldav" } {xmlns:ical="http://apple.com/ns/ical/">} $response </d:multistatus> :response 207 text/xml $resp $doc deleteXQL Not present: Generic, PostgreSQL, Oracle