caldav::CalDAV instproc PROPFIND (public)

 <instance of caldav::CalDAV[i]> 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 delete
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: