Index: openacs-4/packages/oacs-dav/tcl/tDAV-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/oacs-dav/tcl/tDAV-procs.tcl,v diff -u -r1.16 -r1.17 --- openacs-4/packages/oacs-dav/tcl/tDAV-procs.tcl 25 Apr 2018 19:47:47 -0000 1.16 +++ openacs-4/packages/oacs-dav/tcl/tDAV-procs.tcl 30 Apr 2018 12:45:00 -0000 1.17 @@ -1,6 +1,6 @@ # # tDAV.tcl -# +# # Copyright 2003 Musea Technologies # # http://www.museatech.net @@ -11,11 +11,11 @@ # toddg@tdav.museatech.net # # Authors: Todd Gillespie -# Dave Bauer +# Dave Bauer # # Based upon sources from: # -# webdav.tcl +# webdav.tcl # # A WebDAV implementation for AOLserver 3.x. # @@ -65,7 +65,7 @@ # returns an HTTP response containing WebDAV options supported # # TODO Make this smart to return options based on URI -# We still need to pretend that the site root supports DAV +# We still need to pretend that the site root supports DAV # methods or some clients get confused. proc tdav::filter_webdav_options {args} { @@ -74,12 +74,12 @@ # The allowed webdav options for the share that the requested # URL belongs to. - + foreach {uri options} [nsv_array get tdav_options] { - if {[regexp $uri [ns_conn url]]} { - ns_set put [ns_conn outputheaders] Allow [join $options {, }] - break - } + if {[regexp $uri [ns_conn url]]} { + ns_set put [ns_conn outputheaders] Allow [join $options {, }] + break + } } # This tells MSFT products to skip looking for FrontPage extensions. @@ -96,9 +96,9 @@ # get body proc tdav::xml_valid_p {xml_doc} { - # TODO use tnc with tDOM to vaildate the xml request +# TODO use tnc with tDOM to vaildate the xml request return 1 - + } # tdav::read_xml @@ -115,11 +115,11 @@ proc tdav::read_xml {} { set fp "" while {$fp eq ""} { - set tmpfile [ad_tmpnam] - set fp [ns_openexcl $tmpfile] + set tmpfile [ad_tmpnam] + set fp [ns_openexcl $tmpfile] } #fconfigure $fp -translation binary -encoding binary -# fconfigure $fp -encoding utf-8 + # fconfigure $fp -encoding utf-8 ns_conncptofp $fp seek $fp 0 set xml [read $fp] @@ -137,18 +137,18 @@ # Arguments: # uri URI of the request being handled # list properties formatted in a Tcl list as -# propertyname value +# propertyname value # # Results: # file written including contents of list proc tdav::dbm_write_list {uri list} { set file [tdav::get_prop_file $uri] if {[catch {set f [open $file w]} err]} { - # probably no parent dir, create it: - file mkdir [file dirname $file] - # open again: - set f [open $file w] + # probably no parent dir, create it: + file mkdir [file dirname $file] + # open again: + set f [open $file w] } fconfigure $f -encoding utf-8 puts $f $list @@ -163,26 +163,26 @@ # uri URI to get properties filename for # # Results: -# Returns the filename containing user properties. +# Returns the filename containing user properties. proc tdav::get_prop_file {uri} { - # just in case. I hate that 'file join' fails on this - regsub {^/} $uri {} uri +# just in case. I hate that 'file join' fails on this +regsub {^/} $uri {} uri - # log this for failed config section +# log this for failed config section set name [ns_config "ns/server/[ns_info server]/tdav" propdir] if {$name eq ""} { - set name [file join $::acs::pageroot "../propdir/${uri}"] + set name [file join $::acs::pageroot "../propdir/${uri}"] } else { - set name [file join $name $uri] + set name [file join $name $uri] } # catch uncreated parent dirs here: if {![file exists [file dirname $name]]} { - # no parent dir, create it: - file mkdir [file dirname $name] - # safe for public consumption? + # no parent dir, create it: + file mkdir [file dirname $name] + # safe for public consumption? } return "${name}.prop" } @@ -198,21 +198,21 @@ # Returns the filename containing the lock information for URI proc tdav::get_lock_file {uri} { - # just in case. I hate that 'file join' fails on this - regsub {^/} $uri {} uri +# just in case. I hate that 'file join' fails on this +regsub {^/} $uri {} uri - # log this for failed config section +# log this for failed config section set name [ns_config "ns/server/[ns_info server]/tdav" lockdir] if {$name eq ""} { - set name [file join $::acs::pageroot "../lockdir/${uri}"] + set name [file join $::acs::pageroot "../lockdir/${uri}"] } else { - set name [file join $name $uri] + set name [file join $name $uri] } if {![file exists [file dirname $name]]} { - # no parent dir, create it: - file mkdir [file dirname $name] - # safe for public consumption? + # no parent dir, create it: + file mkdir [file dirname $name] + # safe for public consumption? } return "${name}.lock" @@ -327,7 +327,7 @@ # UNUSED proc tdav::dbm_write_array {uri arr} { - # extract list from array +# extract list from array tdav::dbm_write_list($uri,[array get arr]) # throw errors } @@ -346,7 +346,7 @@ set lockexpiretime [clock scan "$timeout seconds" -base $locktime] set timeout_left [expr {$lockexpiretime - [clock seconds]}] if {$timeout_left < 0} { - set timeout_left 0 + set timeout_left 0 } return $timeout_left } @@ -373,35 +373,35 @@ regsub {^/} $uri {} uri # if lock exists, work. if not, just return. if {[file exists [tdav::get_lock_file $uri]]} { - set lockinfo [tdav::read_lock $uri] + set lockinfo [tdav::read_lock $uri] - # check if lock is expired - if {[tdav::lock_timeout_left [lindex $lockinfo 4] [lindex $lockinfo 6]] == 0 } { - tdav::remove_lock $uri - return "unlocked" - } - set hdr [ns_set iget [ns_conn headers] If] - - # the If header exists, work, otherwise 423 - - if {[info exists hdr] && [string length $hdr]} { - set token "" - # add ? in the token re in case there is a conditional () - # in the header - regexp {(]+)>\s+)?\(<([^>]+)>\)} $hdr nil maybe hdr_uri token - - set ftk [lindex $lockinfo 3] - if {![info exists token] || $token ne $ftk } { + # check if lock is expired + if {[tdav::lock_timeout_left [lindex $lockinfo 4] [lindex $lockinfo 6]] == 0 } { + tdav::remove_lock $uri + return "unlocked" + } + set hdr [ns_set iget [ns_conn headers] If] + + # the If header exists, work, otherwise 423 + + if {[info exists hdr] && [string length $hdr]} { + set token "" + # add ? in the token re in case there is a conditional () + # in the header + regexp {(]+)>\s+)?\(<([^>]+)>\)} $hdr nil maybe hdr_uri token + + set ftk [lindex $lockinfo 3] + if {![info exists token] || $token ne $ftk } { ns_log Debug "tdav::check_lock: token mismatch $ftk expected hdr: $hdr token: $token" - ns_return 423 {text/plain} {} - return filter_return - } - } else { + ns_return 423 {text/plain} {} + return filter_return + } + } else { ns_log Debug "tdav::check_lock: no \"If\" header found for request of $uri" - ns_return 423 {text/plain} {} - return filter_return - } - # also check for uri == hdr_uri + ns_return 423 {text/plain} {} + return filter_return + } + # also check for uri == hdr_uri } return unlocked } @@ -422,20 +422,20 @@ regsub {^/} $uri {} uri # if lock exists, work. if not, just return. if {[file exists [tdav::get_lock_file $uri]]} { - set hdr [ns_set iget [ns_conn headers] {Lock-Token}] - # the If header exists, work, otherwise 423 - if {[info exists hdr] && [string length $hdr]} { - regexp {<([^>]+)>} $hdr nil token - set ftk [lindex [tdav::read_lock $uri] 3] - if {[info exists token] && $token eq $ftk} { - # it's good, the tokens match. carry on. - } else { - return filter_return - } - } else { - return filter_return - } - # also check for uri == hdr_uri + set hdr [ns_set iget [ns_conn headers] {Lock-Token}] + # the If header exists, work, otherwise 423 + if {[info exists hdr] && [string length $hdr]} { + regexp {<([^>]+)>} $hdr nil token + set ftk [lindex [tdav::read_lock $uri] 3] + if {[info exists token] && $token eq $ftk} { + # it's good, the tokens match. carry on. + } else { + return filter_return + } + } else { + return filter_return + } + # also check for uri == hdr_uri } return unlocked } @@ -458,17 +458,17 @@ proc tdav::get_fs_props {} { # global fs_props set fs_props {} - -# lappend fs_props [list ns0 supportlock] {subst {""}} + + # lappend fs_props [list ns0 supportlock] {subst {""}} lappend fs_props [list ns0 getcontenttype] {subst {[ns_guesstype $filename]}} lappend fs_props [list D getcontentlength] {subst {[file size $entry]}} lappend fs_props [list D creationdate] {subst {[clock format $file_stat(mtime) -format "%Y-%m-%dT%H:%M:%SZ" -gmt 1]}} lappend fs_props [list D getlastmodified] {subst {[clock format $file_stat(mtime) -format "%a, %d %b %Y %H:%M:%S %Z" -gmt 1]}} lappend fs_props [list D getetag] {subst {"1f9a-400-3948d0f5"}} lappend fs_props [list D resourcetype] {if {[file isdirectory $entry]} { - subst {D:collection} + subst {D:collection} } else { - subst {[ns_guesstype $filename]} + subst {[ns_guesstype $filename]} }} return $fs_props @@ -482,11 +482,11 @@ # ht # ACTION foreach c $proplist { - # extraneous, then name - set p [[$c childNodes] childNodes] - set name [$p nodeName] - # DATA: - set ht($name) [[$p childNodes] nodeValue] + # extraneous, then name + set p [[$c childNodes] childNodes] + set name [$p nodeName] + # DATA: + set ht($name) [[$p childNodes] nodeValue] } return $ht } @@ -499,11 +499,11 @@ # ht # ACTION foreach c $proplist { - # extraneous, then name - set p [[$c childNodes] childNodes] - set name [$p nodeName] - # DATA: - set ht($name) [[$p childNodes] nodeValue] + # extraneous, then name + set p [[$c childNodes] childNodes] + set name [$p nodeName] + # DATA: + set ht($name) [[$p childNodes] nodeValue] } return $ht } @@ -525,46 +525,46 @@ set depth [tdav::conn -set depth [ns_set iget [ns_conn headers] Depth]] set xml [tdav::read_xml] - + if {[catch {dom parse $xml} xd]} { - # xml body is not well formed - ns_returnbadrequest - return filter_return + # xml body is not well formed + ns_returnbadrequest + return filter_return } - + set setl [$xd getElementsByTagName "*set"] set rml [$xd getElementsByTagName "*remove"] set prop_req {} foreach node $rml { - set p [[$node childNodes] childNodes] - # we use localname because we always resolve the URI namespace - # for the tag name - set ns [$p namespaceURI] - if {$ns eq ""} { - set name [$p nodeName] - } else { - set name [$p localName] - } - if {[catch {set value [[$p childNodes] nodeValue]}]} { - set value "" - } - lappend prop_req remove [list [list $ns $name] $value] + set p [[$node childNodes] childNodes] + # we use localname because we always resolve the URI namespace + # for the tag name + set ns [$p namespaceURI] + if {$ns eq ""} { + set name [$p nodeName] + } else { + set name [$p localName] + } + if {[catch {set value [[$p childNodes] nodeValue]}]} { + set value "" + } + lappend prop_req remove [list [list $ns $name] $value] } foreach node $setl { - set p [[$node childNodes] childNodes] - # we use localname because we always resolve the URI namespace - # for the tag name - set ns [$p namespaceURI] - if {$ns eq ""} { - set name [$p nodeName] - } else { - set name [$p localName] - } - if {[catch {set value [[$p childNodes] nodeValue]}]} { - set value "" - } - lappend prop_req set [list [list $ns $name] $value] + set p [[$node childNodes] childNodes] + # we use localname because we always resolve the URI namespace + # for the tag name + set ns [$p namespaceURI] + if {$ns eq ""} { + set name [$p nodeName] + } else { + set name [$p localName] + } + if {[catch {set value [[$p childNodes] nodeValue]}]} { + set value "" + } + lappend prop_req set [list [list $ns $name] $value] } tdav::conn -set prop_req $prop_req @@ -590,21 +590,21 @@ proc tdav::webdav_proppatch {} { set uri [ns_conn url] - regsub {^/} $uri {} uri + regsub {^/} $uri {} uri set filename [file join $::acs::pageroot $uri] set body "" set ret_code 200 if {![file exists $filename]} { - set ret_code 404 + set ret_code 404 } else { - if {"unlocked" ne [tdav::check_lock $uri] } { - set ret_code 423 - set response "The resource is locked" - } else { - set prop_req [tdav::conn prop_req] - set response [tdav::update_user_props $uri $prop_req] - } - set ret_code 207 + if {"unlocked" ne [tdav::check_lock $uri] } { + set ret_code 423 + set response "The resource is locked" + } else { + set prop_req [tdav::conn prop_req] + set response [tdav::update_user_props $uri $prop_req] + } + set ret_code 207 } tdav::respond [list $ret_code $response] @@ -636,33 +636,33 @@ # decide on file or directory # why doesn't Tcl handle this? - # otoh, it lets us handle the notfound error here + # otoh, it lets us handle the notfound error here # wait, no, this is right as long as the DAV request is correct # so fuck it if {$depth > 0} { - set entries [glob -nocomplain [file join $::acs::pageroot $uri *]] + set entries [glob -nocomplain [file join $::acs::pageroot $uri *]] } else { - set entries [glob -nocomplain [file join $::acs::pageroot $uri]] + set entries [glob -nocomplain [file join $::acs::pageroot $uri]] } - + foreach entry $entries { - set entry_props [list] - set filename [lindex [file split $entry] end] - # Tcl befuddles me: - set href [string replace $entry 1 [string length $::acs::pageroot] ""] - file stat $entry file_stat - set collection_p [string equal "directory" $file_stat(type)] + set entry_props [list] + set filename [lindex [file split $entry] end] + # Tcl befuddles me: + set href [string replace $entry 1 [string length $::acs::pageroot] ""] + file stat $entry file_stat + set collection_p [string equal "directory" $file_stat(type)] - foreach {i j} [tdav::get_fs_props] { - lappend entry_props [list [lindex $i 0] [lindex $i 1]] [eval $j] - } - foreach {i j} [tdav::get_user_props $uri $depth $prop_req] { - lappend entry_props [list [lindex $i 0] [lindex $i 1]] $j - } - - lappend props [list $href $collection_p $entry_props] + foreach {i j} [tdav::get_fs_props] { + lappend entry_props [list [lindex $i 0] [lindex $i 1]] [eval $j] + } + foreach {i j} [tdav::get_user_props $uri $depth $prop_req] { + lappend entry_props [list [lindex $i 0] [lindex $i 1]] $j + } + + lappend props [list $href $collection_p $entry_props] } - + tdav::respond [list 207 $props] } @@ -682,45 +682,44 @@ # are always returned # # Results: -# returns a list of name/value pairs +# returns a list of name/value pairs proc tdav::get_user_props { uri depth prop_req } { regsub {^/} $uri {} luri - return [tdav::dbm_read_list $luri] + return [tdav::dbm_read_list $luri] } proc tdav::update_user_props {uri prop_req} { array set props [tdav::dbm_read_list $uri] set status {} foreach {action i} $prop_req { - set k [lindex $i 0] - set value [lindex $i 1] - switch -- $action { - set { - if {[catch {set props($k) $value} err]} { - lappend status [list "HTTP/1.1 409 Conflict" $k] - } else { - lappend status [list "HTTP/1.1 200 OK" $k] - } + lassign $i k value + switch -- $action { + set { + if {[catch {set props($k) $value} err]} { + lappend status [list "HTTP/1.1 409 Conflict" $k] + } else { + lappend status [list "HTTP/1.1 200 OK" $k] + } - } - remove { - #according to WebDAV spec removing a nonexistent - # property is not an error, if it's there - # remove it, otherwise, continue. - if {[info exists props($k)]} { - unset props($k) - } - lappend status [list "HTTP/1.1 200 OK" $k] - } - } + } + remove { + #according to WebDAV spec removing a nonexistent + # property is not an error, if it's there + # remove it, otherwise, continue. + if {[info exists props($k)]} { + unset props($k) + } + lappend status [list "HTTP/1.1 200 OK" $k] + } + } - #filter out filesystem sets - # DAVEB where is this filtering occurring? + #filter out filesystem sets + # DAVEB where is this filtering occurring? - #write the props back out to disc: - tdav::dbm_write_list $uri [array get props] - } + #write the props back out to disc: + tdav::dbm_write_list $uri [array get props] + } return $status } @@ -752,27 +751,27 @@ set entry [file join $::acs::pageroot $uri] # parse the xml body to check if its valid if {"" ne $xml && [catch {dom parse $xml} xd]} { - ns_return 400 text/plain "XML request not well-formed." - return filter_return + ns_return 400 text/plain "XML request not well-formed." + return filter_return } - + set xml_prop_list {} if {[info exists xd] && "" ne $xd } { - set prop [$xd getElementsByTagNameNS "DAV:" "prop"] - # if element doesn't exist we return all properties - if {$prop ne ""} { - set xml_prop_list [$prop childNodes] - } - foreach node $xml_prop_list { - set ns [$node namespaceURI] - if {$ns eq ""} { - set name [$node nodeName] - } else { - set name [$node localName] - } - lappend prop_req [list $ns $name] - } + set prop [$xd getElementsByTagNameNS "DAV:" "prop"] + # if element doesn't exist we return all properties + if {$prop ne ""} { + set xml_prop_list [$prop childNodes] + } + foreach node $xml_prop_list { + set ns [$node namespaceURI] + if {$ns eq ""} { + set name [$node nodeName] + } else { + set name [$node localName] + } + lappend prop_req [list $ns $name] + } } tdav::conn -set prop_req $prop_req # this should be the end of the filter. @@ -823,20 +822,20 @@ set ret_code 500 set body "" if {[file exists $entry]} { - if {"unlocked" ne [tdav::check_lock $uri] } { - set ret_code 423 - set body "Resource is locked." - } else { - file rename -force -- $tmpfile $entry - set ret_code 204 - } + if {"unlocked" ne [tdav::check_lock $uri] } { + set ret_code 423 + set body "Resource is locked." + } else { + file rename -force -- $tmpfile $entry + set ret_code 204 + } } else { file rename -- $tmpfile $entry - set ret_code 201 + set ret_code 201 } tdav::respond [list $ret_code ""] - + } # tdav::filter_webdav_delete @@ -851,7 +850,7 @@ # right now proc tdav::filter_webdav_delete {args} { - # not sure there is anything we need to set here +# not sure there is anything we need to set here return filter_ok } @@ -876,27 +875,27 @@ set ret_code 500 set body "" - + if {[file exists $entry]} { - # 423's and returns: - if {"unlocked" eq [tdav::check_lock $uri]} { - file delete -force -- $entry - tdav::delete_props $uri - tdav::remove_lock $uri - set ret_code 204 - } else { - set ret_code 423 - set body "Resource is locked." - } + # 423's and returns: + if {"unlocked" eq [tdav::check_lock $uri]} { + file delete -force -- $entry + tdav::delete_props $uri + tdav::remove_lock $uri + set ret_code 204 + } else { + set ret_code 423 + set body "Resource is locked." + } } else { - # file exists will fail on urls created by urlencode. do a decode here & test - # ? + # file exists will fail on urls created by urlencode. do a decode here & test + # ? - set ret_code 404 + set ret_code 404 } - + tdav::respond [list $ret_code $body] - + } # tdav::filter_webdav_mkcol @@ -913,10 +912,10 @@ proc tdav::filter_webdav_mkcol {args} { if {[ns_conn contentlength]} { - set ret_code 415 - set html_response "" - tdav::respond [list 415] - return filter_return + set ret_code 415 + set html_response "" + tdav::respond [list 415] + return filter_return } return filter_ok } @@ -936,19 +935,19 @@ proc tdav::webdav_mkcol {} { set uri [ns_conn url] regsub {^/} $uri {} uri - + set entry [file join $::acs::pageroot $uri] set filename [lindex [file split $entry] end] regsub {/[^/]*/*$} $entry {} parent_dir if {![file exists $parent_dir]} { - set ret_code 409 + set ret_code 409 } elseif {![file exists $entry]} { - file mkdir $entry - file mkdir [file join $::acs::pageroot "../props/" $uri] - set ret_code 201 + file mkdir $entry + file mkdir [file join $::acs::pageroot "../props/" $uri] + set ret_code 201 } else { - set ret_code 405 + set ret_code 405 } @@ -963,50 +962,50 @@ regsub {https?://[^/]+/} $destination {/} dest tdav::conn -set destination $dest return filter_ok - + } proc tdav::webdav_copy {} { set overwrite [tdav::conn overwrite] set dest [tdav::conn destination] - + set local_dest $::acs::pageroot append local_dest $dest set newuri [string replace $local_dest 1 [string length $::acs::pageroot] ""] regsub {^/} $newuri {} newuri set uri [ns_conn url] regsub {^/} $uri {} uri - + set entry [file join $::acs::pageroot $uri] set filename [lindex [file split $entry] end] regsub {^/} [ns_conn url] {} uri set entry [file join $::acs::pageroot $uri] - + if {![file exists $entry]} { - set ret_code 404 + set ret_code 404 } else { - if {[file exists $local_dest]} { - if {"unlocked" ne [tdav::check_lock $dest] } { - # ns_return 423 {text/plain} {Resource is locked.} - set ret_code 423 - set body "Resource is locked." - } else { - if {[string equal -nocase $overwrite "F"]} { - set ret_code 412 - } else { - set ret_code 204 - file copy -force -- $entry $local_dest - tdav::copy_props $uri $newuri - } - } - } else { - set ret_code 201 - file copy -- $entry $local_dest - tdav::copy_props $uri $newuri - } + if {[file exists $local_dest]} { + if {"unlocked" ne [tdav::check_lock $dest] } { + # ns_return 423 {text/plain} {Resource is locked.} + set ret_code 423 + set body "Resource is locked." + } else { + if {[string equal -nocase $overwrite "F"]} { + set ret_code 412 + } else { + set ret_code 204 + file copy -force -- $entry $local_dest + tdav::copy_props $uri $newuri + } + } + } else { + set ret_code 201 + file copy -- $entry $local_dest + tdav::copy_props $uri $newuri + } } ns_return $ret_code {text/html} {} tdav::respond [list $ret_code] @@ -1022,7 +1021,7 @@ tdav::conn -set destination $dest -return filter_ok + return filter_ok } proc tdav::webdav_move { args } { @@ -1036,38 +1035,38 @@ set uri [ns_conn url] regsub {^/} $uri {} uri - + set entry [file join $::acs::pageroot $uri] set filename [lindex [file split $entry] end] - + set ret_code 500 set body {} if {![file exists $entry]} { - set ret_code 404 + set ret_code 404 } else { - if {"unlocked" ne [tdav::check_lock $uri] } { -# ns_return 423 {text/plain} {Resource is locked.} - set ret_code 423 - set body "Resource is locked." - } elseif {[file exists $local_dest]} { - if {[string equal -nocase $overwrite "F"]} { - set ret_code 412 - } else { - set ret_code 204 - file delete -force -- $local_dest - file copy -force -- $entry $local_dest - file delete -force -- $entry - tdav::copy_props $uri $newuri - tdav::delete_props $uri - } - } else { - set ret_code 201 - file copy -- $entry $local_dest - tdav::copy_props $uri $newuri - file delete -force -- $entry - tdav::delete_props $uri - } + if {"unlocked" ne [tdav::check_lock $uri] } { + # ns_return 423 {text/plain} {Resource is locked.} + set ret_code 423 + set body "Resource is locked." + } elseif {[file exists $local_dest]} { + if {[string equal -nocase $overwrite "F"]} { + set ret_code 412 + } else { + set ret_code 204 + file delete -force -- $local_dest + file copy -force -- $entry $local_dest + file delete -force -- $entry + tdav::copy_props $uri $newuri + tdav::delete_props $uri + } + } else { + set ret_code 201 + file copy -- $entry $local_dest + tdav::copy_props $uri $newuri + file delete -force -- $entry + tdav::delete_props $uri + } } ns_return $ret_code {text/html} $body @@ -1084,14 +1083,14 @@ set scope [[[lindex $l 0] childNodes] nodeName] set type [[[lindex $l 1] childNodes] nodeName] if {[catch {set owner [[[lindex $l 2] childNodes] nodeValue]} err]} { - set owner "" + set owner "" } set depth [ns_set iget [ns_conn headers] Depth] set timeout [ns_set iget [ns_conn headers] Timeout] regsub {^Second-} $timeout {} timeout tdav::conn -set lock_timeout $timeout - if {$depth eq ""} { - set depth 0 + if {$depth eq ""} { + set depth 0 } tdav::conn -set depth $depth @@ -1105,10 +1104,10 @@ proc tdav::set_lock {uri depth type scope owner {timeout ""} {locktime ""} } { if {$timeout eq ""} { - set timeout [ns_config "ns/server/[ns_info server]/tdav" "defaultlocktimeout" "300"] + set timeout [ns_config "ns/server/[ns_info server]/tdav" "defaultlocktimeout" "300"] } if {$locktime eq ""} { - set locktime [clock format [clock seconds] -format "%T %D"] + set locktime [clock format [clock seconds] -format "%T %D"] } set token "opaquelocktoken:[ns_rand 2147483647]" set lock [list $type $scope $owner $token $timeout $depth $locktime] @@ -1126,30 +1125,30 @@ set entry [file join $::acs::pageroot $uri] set filename [lindex [file split $entry] end] set existing_lock_token [tdav::conn lock_token] -# if {![file exists $entry]} { -# set ret_code 404 -# } else + # if {![file exists $entry]} { + # set ret_code 404 + # } else if {"unlocked" ne [tdav::check_lock $uri] } { - set ret_code 423 - tdav::respond [list $ret_code] + set ret_code 423 + tdav::respond [list $ret_code] } else { - set depth [tdav::conn depth] - set timeout [tdav::conn lock_timeout] - if {$timeout eq ""} { - #probably make this a paramter? - set timeout 180 - } - if {"" ne $existing_lock_token && [file exists [tdav::get_lock_file $uri]} { - - set old_lock [tdav::read_lock $uri] - set new_lock [list [lindex $old_lock 0] [lindex $old_lock 1] [lindex $old_lock 2] [lindex $old_lock 3] $timeout [clock format [clock seconds]]] - tdav::write_lock $uri $new_lock - } else { - set token [tdav::set_lock $uri $depth $type $scope $owner $timeout [clock format [clock seconds]]] - } - set ret_code 200 + set depth [tdav::conn depth] + set timeout [tdav::conn lock_timeout] + if {$timeout eq ""} { + #probably make this a paramter? + set timeout 180 + } + if {"" ne $existing_lock_token && [file exists [tdav::get_lock_file $uri]} { - tdav::respond [list $ret_code [list depth $depth token $token timeout $timeout owner $owner scope $scope type $type]] + set old_lock [tdav::read_lock $uri] + set new_lock [list [lindex $old_lock 0] [lindex $old_lock 1] [lindex $old_lock 2] [lindex $old_lock 3] $timeout [clock format [clock seconds]]] + tdav::write_lock $uri $new_lock + } else { + set token [tdav::set_lock $uri $depth $type $scope $owner $timeout [clock format [clock seconds]]] + } + set ret_code 200 + + tdav::respond [list $ret_code [list depth $depth token $token timeout $timeout owner $owner scope $scope type $type]] } } @@ -1169,21 +1168,21 @@ set filename [lindex [file split $entry] end] if {![file exists $entry]} { - set ret_code 404 - set body {} + set ret_code 404 + set body {} } elseif {"unlocked" ne [tdav::check_lock_for_unlock $uri] } { - set ret_code 423 - set body "Resource is locked." + set ret_code 423 + set body "Resource is locked." } else { - tdav::remove_lock $uri - set ret_code 204 - set body "" + tdav::remove_lock $uri + set ret_code 204 + set body "" } tdav::respond [list $ret_code $body] } proc tdav::filter_stuff_nsperm {args} { - # should be something like "Basic 29234k3j49a" +# should be something like "Basic 29234k3j49a" set a [ns_set get [ns_conn headers] Authorization] # get the second bit, the base64 encoded bit set up [lindex [split $a " "] 1] @@ -1205,18 +1204,17 @@ proc tdav::respond { response } { set response_code [lindex $response 0] if {"423" eq $response_code} { - set response_body "The resource is locked" - set mime_type "text/plain" + set response_body "The resource is locked" + set mime_type "text/plain" } else { - set response_list [tdav::respond::[string tolower [ns_conn method]] $response] - set response_body [lindex $response_list 0] - set mime_type [lindex $response_list 1] - if {$mime_type eq ""} { - set mime_type "text/plain" - } - if {[string match "text/xml*" $mime_type]} { - set response_body [encoding convertto utf-8 $response_body] - } + set response_list [tdav::respond::[string tolower [ns_conn method]] $response] + lassign $response_list response_body mime_type + if {$mime_type eq ""} { + set mime_type "text/plain" + } + if {[string match "text/xml*" $mime_type]} { + set response_body [encoding convertto utf-8 $response_body] + } } ns_log debug "\n ----- tdav litmus headers ----- \n [ns_set iget [ns_conn headers] X-Litmus] \n -----\n" ns_log debug "\n ----- tdav::response response_body ----- \n $response_body \n ----- end ----- \n" @@ -1236,20 +1234,20 @@ array set lock [lindex $response 1] set body [subst { - - - - <${lock(type)}/> - <${lock(scope)}/> - ${lock(depth)} - ${lock(owner)}Second-${lock(timeout)} - - ${lock(token)} - - - - }] - + + + + <${lock(type)}/> + <${lock(scope)}/> + ${lock(depth)} + ${lock(owner)}Second-${lock(timeout)} + + ${lock(token)} + + + + }] + ns_set put [ns_conn outputheaders] "Lock-Token" "<${lock(token)}>" set ret_code 200 @@ -1259,7 +1257,7 @@ } proc tdav::respond::unlock { response } { - # probably should be doing something here +# probably should be doing something here set body "" @@ -1274,23 +1272,23 @@ set resp_code [lindex $response 0] set href "" set body [subst { - - - [ns_conn location]${href} + + + [ns_conn location]${href} }] foreach res [lindex $response 1] { - set status [lindex $res 0] - set ns [lindex $res 1 0] - set name [lindex $res 1 1] - append body [subst { - <$name xmlns='$ns'/> - $status - + set status [lindex $res 0] + set ns [lindex $res 1 0] + set name [lindex $res 1 1] + append body [subst { + <$name xmlns='$ns'/> + $status + }] } append body { - } + } return [list $body {text/xml charset="utf-8"}] } @@ -1305,173 +1303,171 @@ proc tdav::respond::mkcol { response } { set body "" switch -- [lindex $response 0] { - 415 { -# set body "" - } - 490 { -# set body "" - } - 201 { -# set body " -# -# 201 Created -# -#

Created

-#

Collection [ns_conn url] has been created.

-#
-#
-# " + 415 { + # set body "" + } + 490 { + # set body "" + } + 201 { + # set body " + # + # 201 Created + # + #

Created

+ #

Collection [ns_conn url] has been created.

+ #
+ #
+ # " - } - 405 { - set body " - -405 Method Not Allowed - -

Method not allowed

-" - } + } + 405 { + set body " + + 405 Method Not Allowed + +

Method not allowed

+ " + } } return [list $body text/html] } proc tdav::respond::propfind { response } { - # this proc requires that all properties to be returned are in the - # response lindex 1 - # we don't have to check the tdav fs props or lock properties - # they should already be there +# this proc requires that all properties to be returned are in the +# response lindex 1 +# we don't have to check the tdav fs props or lock properties +# they should already be there set d [dom createDocumentNS "DAV:" "D:multistatus"] set n [$d documentElement] $n setAttribute "xmlns:b" "urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" set mst_body "" foreach res [lindex $response 1] { - set href [lindex $res 0] - set props [lindex $res 2] - set r [$d createElementNS DAV: ns0:response] - $n appendChild $r - set h [$d createElement D:href] + lassign $res href . props + set r [$d createElementNS DAV: ns0:response] + $n appendChild $r + set h [$d createElement D:href] $h appendChild [$d createTextNode ${href}] - set propstat [$d createElement D:propstat] - set prop [$d createElement D:prop] - $r appendChild $h - $r appendChild $propstat + set propstat [$d createElement D:propstat] + set prop [$d createElement D:prop] + $r appendChild $h + $r appendChild $propstat - foreach {i j} $props { - # interestingly enough, adding the namespace here to the prop is fine - set name [lindex $i 1] - set ns [lindex $i 0] - if {"D" ne $ns && "ns0" ne $ns } { - # for user properties set the namespace explicitly in - # the tag - if {$ns ne ""} { - set pnode [$d createElementNS $ns $name] - } else { - set pnode [$d createElement $name] - } - } else { - set pnode [$d createElement ${ns}:${name}] - } + foreach {i j} $props { + # interestingly enough, adding the namespace here to the prop is fine + lassign $i ns name + if {"D" ne $ns && "ns0" ne $ns } { + # for user properties set the namespace explicitly in + # the tag + if {$ns ne ""} { + set pnode [$d createElementNS $ns $name] + } else { + set pnode [$d createElement $name] + } + } else { + set pnode [$d createElement ${ns}:${name}] + } - if {"creationdate" eq $name} { + if {"creationdate" eq $name} { - $pnode setAttribute "b:dt" "dateTime.tz" + $pnode setAttribute "b:dt" "dateTime.tz" } - if {"getlastmodified" eq $name} { + if {"getlastmodified" eq $name} { - $pnode setAttribute "b:dt" "dateTime.rfc1123" + $pnode setAttribute "b:dt" "dateTime.rfc1123" - } + } if {"D:collection" eq $j} { - - $pnode appendChild [$d createElement $j] - } else { - - $pnode appendChild [$d createTextNode $j] + $pnode appendChild [$d createElement $j] - } + } else { - $prop appendChild $pnode + $pnode appendChild [$d createTextNode $j] - } + } - set supportedlock [$d createElement D:supportedlock] - - set lockentry [$d createElement D:lockentry] - set lockscope [$d createElement D:lockscope] - set exclusive [$d createElement D:exclusive] - set locktype [$d createElement D:locktype] - set write_type [$d createElement D:write] - - $supportedlock appendChild $lockentry - + $prop appendChild $pnode + + } + + set supportedlock [$d createElement D:supportedlock] + + set lockentry [$d createElement D:lockentry] + set lockscope [$d createElement D:lockscope] + set exclusive [$d createElement D:exclusive] + set locktype [$d createElement D:locktype] + set write_type [$d createElement D:write] + + $supportedlock appendChild $lockentry + $locktype appendChild $write_type - $lockscope appendChild $exclusive + $lockscope appendChild $exclusive - $lockentry appendChild $lockscope - $lockentry appendChild $locktype + $lockentry appendChild $lockscope + $lockentry appendChild $locktype - $prop appendChild $supportedlock + $prop appendChild $supportedlock - set lockdiscovery [$d createElement D:lockdiscovery] - regsub {https?://[^/]+/} $href {/} local_uri - if {[file exists [tdav::get_lock_file $local_uri]]} { - # check for timeout - set lockinfo [tdav::read_lock $local_uri] - set lock_timeout_left [tdav::lock_timeout_left [lindex $lockinfo 4] [lindex $lockinfo 6]] - if {$lock_timeout_left > 0} { + set lockdiscovery [$d createElement D:lockdiscovery] + regsub {https?://[^/]+/} $href {/} local_uri + if {[file exists [tdav::get_lock_file $local_uri]]} { + # check for timeout + set lockinfo [tdav::read_lock $local_uri] + set lock_timeout_left [tdav::lock_timeout_left [lindex $lockinfo 4] [lindex $lockinfo 6]] + if {$lock_timeout_left > 0} { - set activelock [$d createElement D:activelock] - set locktype [$d createElement D:locktype] - set lockscope [$d createElement D:lockscope] - set depth [$d createElement D:depth] - set owner [$d createElement D:owner] - set timeout [$d createElement D:timeout] - set locktoken [$d createElement D:locktoken] - set locktokenhref [$d createElement D:href] - - $locktype appendChild [$d createElement D:[lindex $lockinfo 0]] - $lockscope appendChild [$d createElement D:[lindex $lockinfo 1]] - $depth appendChild [$d createTextNode [lindex $lockinfo 5]] + set activelock [$d createElement D:activelock] + set locktype [$d createElement D:locktype] + set lockscope [$d createElement D:lockscope] + set depth [$d createElement D:depth] + set owner [$d createElement D:owner] + set timeout [$d createElement D:timeout] + set locktoken [$d createElement D:locktoken] + set locktokenhref [$d createElement D:href] - $timeout appendChild [$d createTextNode Second-$lock_timeout_left] - $owner appendChild [$d createTextNode [lindex $lockinfo 2]] - $locktokenhref appendChild [$d createTextNode [lindex $lockinfo 3]] - $locktoken appendChild $locktokenhref + $locktype appendChild [$d createElement D:[lindex $lockinfo 0]] + $lockscope appendChild [$d createElement D:[lindex $lockinfo 1]] + $depth appendChild [$d createTextNode [lindex $lockinfo 5]] - $activelock appendChild $locktype - $activelock appendChild $lockscope - $activelock appendChild $depth - $activelock appendChild $timeout - $activelock appendChild $owner - $activelock appendChild $locktoken + $timeout appendChild [$d createTextNode Second-$lock_timeout_left] + $owner appendChild [$d createTextNode [lindex $lockinfo 2]] + $locktokenhref appendChild [$d createTextNode [lindex $lockinfo 3]] + $locktoken appendChild $locktokenhref - $lockdiscovery appendChild $activelock - } - } + $activelock appendChild $locktype + $activelock appendChild $lockscope + $activelock appendChild $depth + $activelock appendChild $timeout + $activelock appendChild $owner + $activelock appendChild $locktoken - $prop appendChild $lockdiscovery - $propstat appendChild $prop + $lockdiscovery appendChild $activelock + } + } - set status [$d createElement D:status] - set status_text [$d createTextNode "HTTP/1.1 200 OK"] + $prop appendChild $lockdiscovery + $propstat appendChild $prop - $status appendChild $status_text - $propstat appendChild $status + set status [$d createElement D:status] + set status_text [$d createTextNode "HTTP/1.1 200 OK"] + $status appendChild $status_text + $propstat appendChild $status - } - + } + + set body [$d asXML -escapeNonASCII] set body "\n${body}" set response [list $body {text/xml charset="utf-8"}] return $response - + } proc tdav::conn {args} { @@ -1484,44 +1480,44 @@ set var [lindex $args 1] } switch -- $flag { - -set { - set value [lindex $args 2] - set tdav_conn($var) $value - return $value - } + -set { + set value [lindex $args 2] + set tdav_conn($var) $value + return $value + } -get { if { [info exists tdav_conn($var)] } { return $tdav_conn($var) - } else { - return [ns_conn $var] - } - } + } else { + return [ns_conn $var] + } + } } } proc tdav::apply_filters {{uri "/*"} {options "OPTIONS GET HEAD POST DELETE TRACE PROPFIND PROPPATCH COPY MOVE MKCOL LOCK UNLOCK"} {enable_filesystem "f"}} { - # Verify that the options are valid options. Webdav requires - # support for a minimum set of options. And offers support for a - # limited set of options. (See RFC 2518) +# Verify that the options are valid options. Webdav requires +# support for a minimum set of options. And offers support for a +# limited set of options. (See RFC 2518) set required_options [list OPTIONS PROPFIND PROPPATCH MKCOL GET HEAD POST] foreach required_option $required_options { - if {$required_option ni [string toupper $options]} { - ns_log error "Required option $required_option missing from tDAV options for URI '$uri'. -Required web dav options are: '$required_options'." - return - } + if {$required_option ni [string toupper $options]} { + ns_log error "Required option $required_option missing from tDAV options for URI '$uri'. + Required web dav options are: '$required_options'." + return + } } set allowed_options [list OPTIONS COPY DELETE GET HEAD MKCOL MOVE LOCK POST PROPFIND PROPPATCH PUT TRACE UNLOCK] foreach option $options { - if {[lsearch -exact $allowed_options [string toupper $option]] < 0} { - ns_log error "Option $option is not an allowed tDAV option for URI '$uri'. -Allowed web dav options are: '$allowed_options'." - return - } - } + if {[lsearch -exact $allowed_options [string toupper $option]] < 0} { + ns_log error "Option $option is not an allowed tDAV option for URI '$uri'. + Allowed web dav options are: '$allowed_options'." + return + } + } # Register filters for selected tDAV options. Do not register a # filter for GET, POST or HEAD. @@ -1530,27 +1526,27 @@ # url matching for registered filters set filter_uri "[string trimright $uri /*]*" foreach option $options { - if {$option ni [list GET POST HEAD]} { - ns_log debug "tDAV registering filter for $filter_uri on $option" - ns_register_filter postauth [string toupper $option] "${filter_uri}" tdav::filter_webdav_[string tolower $option] + if {$option ni [list GET POST HEAD]} { + ns_log debug "tDAV registering filter for $filter_uri on $option" + ns_register_filter postauth [string toupper $option] "${filter_uri}" tdav::filter_webdav_[string tolower $option] } } ns_log notice "tDAV: Registered filters on $filter_uri" - + # Register procedures for selected tDAV options. Do not register a # proc for OPTIONS, GET, POST or HEAD. - if {"true" eq $enable_filesystem} { - - foreach option $options { - if {$option ni [list OPTIONS GET POST HEAD]} { - ns_log debug "tDAV registering proc for $uri on $option" - ns_register_proc [string toupper $option] "${uri}" tdav::webdav_[string tolower $option] - } - } - ns_log notice "tDAV: Registered procedures on $uri" + if {"true" eq $enable_filesystem} { + + foreach option $options { + if {$option ni [list OPTIONS GET POST HEAD]} { + ns_log debug "tDAV registering proc for $uri on $option" + ns_register_proc [string toupper $option] "${uri}" tdav::webdav_[string tolower $option] + } + } + ns_log notice "tDAV: Registered procedures on $uri" } else { - ns_log notice "tDAV: Filesystem access by WebDAV disabled" + ns_log notice "tDAV: Filesystem access by WebDAV disabled" } # Store the tDAV properties in an nsv set so that the registerd # filters and procedures don't have to read the config file @@ -1569,52 +1565,52 @@ proc tdav::remove_user {user} { # no corresponding ns_perm function. - # ns_perm setpass + # ns_perm setpass # ns_perm denyuser /* # might work } proc tdav::allow_user {uri user} { foreach {share_uri options} [nsv_array get tdav_options] { - if {[regexp $share_uri $uri]} { - foreach option $options { - ns_perm allowuser [string toupper $option] ${uri} $user - } - break - } + if {[regexp $share_uri $uri]} { + foreach option $options { + ns_perm allowuser [string toupper $option] ${uri} $user + } + break + } } } proc tdav::deny_user {uri user} { foreach {share_uri options} [nsv_array get tdav_options] { - if {[regexp $share_uri $uri]} { - foreach option $options { - ns_perm denyuser [string toupper $option] ${uri} $user - } - break - } + if {[regexp $share_uri $uri]} { + foreach option $options { + ns_perm denyuser [string toupper $option] ${uri} $user + } + break + } } } proc tdav::allow_group {uri group} { foreach {share_uri options} [nsv_array get tdav_options] { - if {[regexp $share_uri $uri]} { - foreach option $options { - ns_perm allowgroup [string toupper $option] ${uri} $group - } - break - } + if {[regexp $share_uri $uri]} { + foreach option $options { + ns_perm allowgroup [string toupper $option] ${uri} $group + } + break + } } } proc tdav::deny_group {uri group} { foreach {share_uri options} [nsv_array get tdav_options] { - if {[regexp $share_uri $uri]} { - foreach option $options { - ns_perm denygroup [string toupper $option] ${uri} $group - } - break - } + if {[regexp $share_uri $uri]} { + foreach option $options { + ns_perm denygroup [string toupper $option] ${uri} $group + } + break + } } } @@ -1633,15 +1629,15 @@ # The alternative is to define preauth filters on the WebDAV # methods and write your own code to handle authentication. This # is how the OpenACS implementation that uses tDAV works. - -# ns_perm adduser tdav [ns_crypt tdav salt] userfield -# ns_perm adduser tdav1 [ns_crypt tdav1 salt] userfield -# ns_perm addgroup tdav tdav tdav1 + # ns_perm adduser tdav [ns_crypt tdav salt] userfield + # ns_perm adduser tdav1 [ns_crypt tdav1 salt] userfield + # ns_perm addgroup tdav tdav tdav1 + set tdav_shares [ns_configsection "ns/server/[ns_info server]/tdav/shares"] if { "" ne $tdav_shares } { for {set i 0} {$i < [ns_set size $tdav_shares]} {incr i} { - set tdav_share [ns_configsection "ns/server/[ns_info server]/tdav/share/[ns_set key $tdav_shares $i]"] + set tdav_share [ns_configsection "ns/server/[ns_info server]/tdav/share/[ns_set key $tdav_shares $i]"] tdav::apply_filters [ns_set get $tdav_share uri] [ns_set get $tdav_share options] [ns_set get $tdav_share enablefilesystem] # uncomment the next line if you are using ns_perm authentication # tdav::allow_group [ns_set get $tdav_share uri] tdav