Index: openacs-4/packages/xotcl-core/tcl/dav-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-core/tcl/Attic/dav-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xotcl-core/tcl/dav-procs.tcl 20 Jul 2018 15:07:43 -0000 1.1 @@ -0,0 +1,392 @@ +::xo::library doc { + XoWiki - dav procs. Simple WebDAV implementation to access files in the wiki via the + WebDAV protocol. + + @creation-date 2010-04-10 + @author Gustaf Neumann + @cvs-id $Id: dav-procs.tcl,v 1.1 2018/07/20 15:07:43 antoniop Exp $ +} +package require XOTcl 2 + +namespace eval ::xo { + + # + # Subclass ::xo::ProtocolHander for dav (as used by ical) + # + Class create ::xo::dav -superclass ProtocolHandler -parameter { + {url /webdav} + } + + set davStmlog 1 + set davLog 1 + + # + # Simple WebDAV interface implementation to access files via the + # WebDAV protocol. No actual StoreManager is defined here. One can + # be found in the xowiki package. Additional ones must be + # implemented based on some OpenACS file API (e.g. the file-storage) + # + # Architecturally, this WebDAV implementation could be used for + # multiple Storage managers (stm). + # Still to do: + # + # a) In this version, the storage manager supports only a limited + # set of operations on folder. + # + # Features: + # - supports wiki files and folders based on formpages, + # - drag file from other filessystems into toplevel or subfolder, + # - move files between folders/subfolders, + # - delete files in folders/subfolders + # - rename files in foldersfiles (according to WebDAV + # standards a copy and delete) + # - macOS Finder operations: Duplicate, Copy work (folders/subfolders) + # + # Limitations: + # - macOS Finder operation "compress" does not work + # (complains about volume full) + # + # b) locking is not implemented, just a few minimal functions are + # included + # + # Limitations: some level of functionality could be provided only on + # selected clients due to differences in webDAV standard + # implementation. This list is currently hardcoded in the code + # below, but should be put in a parameter in the future. + # + # Gustaf Neumann (April 2010) + # + Class create WebDAV -superclass ::xo::dav -parameter { + {stm} + {url /xodav/} + {package_id} + {user_id} + {package ::xo::Package} + } + + WebDAV instproc handle_request {} { + set user_agent [string tolower [ns_set get [ns_conn headers] User-Agent]] + # TODO: parameter + # set allowed_ua_patterns [::parameter::get_from_package_key \ + # -package_key xotcl-core \ + # -parameter SupportedWebDAVClients \ + # -default {Cyberduck WinSCP davfs2 neon gvfs}] + set allowed_ua_patterns "Cyberduck WinSCP davfs2 neon gvfs" + if {![regexp -nocase [join $allowed_ua_patterns |] $user_agent]} { + ns_return 404 text/plain "not supported" + } else { + next + } + } + + WebDAV instproc log {msg} {if {$::xo::davLog} {ns_log notice "dav: $msg"}} + + # The following block can provide pseudo URLs as mount points, using + # "!" as substitution character. + # + # WebDAV instproc get_package_id {} { + # set uri ${:uri} + # set top [lindex ${:urlv} 1] + # if {[string match *!* $top]} { + # regsub -all ! $top / top + # set uri /$top/[join [lrange ${:urlv} 2 end] /] + # [:package] initialize -url $uri + # #$package_id set package_url ${:uri} + # :log "--[:package] initialize -url $uri (was ${:uri} urlv ${:urlv})" + # return $package_id + # } else { + # next + # } + # } + + WebDAV instproc not_for_us {} { + # TODO unwire allowed packages + return [expr {![info exists :package_id] || + [${:package_id} package_key] ni {xowiki xowf file-storage}}] + } + # + # DAV Methods + # + + WebDAV instproc OPTIONS {} { + if {[:not_for_us]} {return [next] } + ns_set put [ns_conn outputheaders] DAV 1,2 + ns_set put [ns_conn outputheaders] DAV + # possible methods: OPTIONS,GET,HEAD,DELETE,TRACE,PROPFIND,PROPPATCH,COPY,MOVE,LOCK,UNLOCK + ns_set put [ns_conn outputheaders] Allow OPTIONS,GET,DELETE,PROPFIND,PROPPATCH,COPY,MOVE + ns_set put [ns_conn outputheaders] MS-Author-Via DAV + ns_return 200 text/plain {} + } + + WebDAV instproc GET {} { + set r [${:stm} deliver_file -path ${:uri}] + :log "### GET returned $r" + switch [dict get $r success] { + 1 { ; } + 0 { ns_return 404 text/plain [dict get $r msg] } + -1 { ns_return 403 text/plain "forbidden: [dict get $r msg]" } + } + } + + WebDAV instproc HEAD {} { + set r [${:stm} file_properties -path ${:uri}] + :log "### HEAD returned $r" + switch [dict get $r success] { + 1 { + set hdrs [ns_conn outputheaders] + + set p [lindex [dict get $r props] 0] + ns_set put $hdrs "Last-Modified" [:tcl_time_to_http_date [dict get $p last_modified]] + ns_set put $hdrs "Content-Length" [dict get $p content_length] + ns_return 200 text/plain "" + } + 0 {ns_return 404 text/plain "File ${:uri} not found"} + -1 { ns_return 403 text/plain "forbidden: [dict get $r msg]" } + } + } + + WebDAV instproc MKCOL {} { + :log "### MKCOL ${:uri}" + set r [${:stm} create_folder -path ${:uri}] + # :log "MKCOL returned $r" + switch [dict get $r success] { + 1 { ns_return 201 text/plain "created: [dict get $r msg]" } + 2 { ns_return 204 text/plain [dict get $r msg] } + 0 { ns_return 409 text/plain "no such parent: [dict get $r msg]" } + -1 { ns_return 403 text/plain "forbidden: [dict get $r msg]" } + } + } + + WebDAV instproc PUT {} { + set contentfile [::xo::get_raw_request_body -as_file] + # Optionally we would be able to disable creation of some OS specific files + # set fn [lindex [split [string trimright ${:uri} /] /] end] + # if {$fn in {".DS_Store" "._.DS_Store"}} { + # set r [dict create success 1 msg "MacOS-specific '$fn' file ignored"] + # } else { + :log "### PUT ${:uri} content length [file size $contentfile] file $contentfile" + set r [${:stm} create_file -path ${:uri} -contentfile $contentfile] + # } + :log "### PUT returned $r" + switch [dict get $r success] { + 1 { ns_return 201 text/plain "created: [dict get $r msg]" } + 2 { ns_return 204 text/plain [dict get $r msg] } + 0 { ns_return 409 text/plain "no such parent: [dict get $r msg]" } + -1 { ns_return 403 text/plain "forbidden: [dict get $r msg]" } + } + } + + WebDAV instproc PROPPATCH {} { + set content [::xo::get_raw_request_body -as_string] + :log "### PROPPATCH ${:uri} $content" + # + # win7 wants to set the creation and modification times + # + # + # + # + # Sat, 29 Jun 2013 19:36:18 GMT + # Sat, 29 Jun 2013 19:36:18 GMT + # Sat, 29 Jun 2013 19:36:18 GMT + # 00000020 + # + # + # + # + # For the time being, we ignore this attempts + # + set props "" + dom parse $content doc1 + $doc1 documentElement root1 + foreach n [$root1 selectNodes //D:prop/*] { + #ns_log notice "FOUND [$n asHTML]" + lappend props [$n nodeName] "HTTP/1.1 200 OK" + } + # :log "### PROPPATCH props $props" + set response [:multiStatus \ + [:multiStatusResonse -href ${:uri} -propstats $props]] + set r {success 1} + switch [dict get $r success] { + 1 { ns_return 207 text/xml $response } + } + } + + WebDAV instproc DELETE {} { + set r [${:stm} delete_file -path ${:uri}] + :log "### DELETE returned $r" + switch [dict get $r success] { + 1 { ns_return 204 text/plain "" } + 0 { ns_return 404 text/plain [dict get $r msg] } + -1 { ns_return 403 text/plain "forbidden: [dict get $r msg]" } + } + } + + WebDAV instproc COPY {} { + set r [${:stm} copy_file -path ${:uri} -destination ${:destination}] + :log "### COPY returned $r" + switch [dict get $r success] { + 1 { ns_return 201 text/plain "created: [dict get $r msg]" } + 2 { ns_return 204 text/plain "" } + 0 { ns_return 403 text/plain [dict get $r msg] } + -1 { ns_return 403 text/plain "forbidden: [dict get $r msg]" } + } + } + + WebDAV instproc MOVE {} { + set r [${:stm} move_file -path ${:uri} -destination ${:destination}] + :log "### MOVE returned $r" + switch [dict get $r success] { + 1 { ns_return 201 text/plain "created: [dict get $r msg]" } + 2 { ns_return 204 text/plain "" } + 0 { ns_return 403 text/plain "forbidden [dict get $r msg]" } + } + } + + WebDAV instproc PROPFIND {} { + if {[:not_for_us]} { return [next] } + + # uri contains the path without the dav prefix (e.g. /xowiki/), + :log "### PROPFIND uri <${:uri}> [ns_set array [ns_conn headers]]" + # :log [ns_conn content] + + set depth [ns_set iget [ns_conn headers] Depth] + if {$depth ne ""} {set depth [list -depth $depth]} + set r [${:stm} file_properties -path ${:uri} -prefix "" {*}$depth] + + :log "### PROPFIND returned $r" + switch [dict get $r success] { + 1 { + set body "" + foreach p [dict get $r props] {append body [:multiStatusProps -props $p]} + set result [:multiStatus $body] + :log "### PROPFIND returns $result" + ns_return 207 text/xml $result + } + 0 { ns_return 404 text/xml "Not found"} + -1 { :multiStatusError "HTTP/1.1 403 Forbidden" } + } + } + + WebDAV instproc LOCK {} { + :log "--LOCK ${:uri}";#"\n[ns_conn content]\n[ns_set array [ns_conn headers]]\n" + set text [subst { + + + + + +0 + +http://www.apple.com/webdav_fs/ +Second-600 +opaquelocktoken:[:lockToken] + + + + }] + ns_return 200 text/xml $text + } + + WebDAV instproc UNLOCK {} { + :log "--UNLOCK ${:uri}";#"\n[ns_conn content] \n[ns_set array [ns_conn headers]]\n" + ns_return 204 text/plain "" + } + + + # + # some helper methods + # + + WebDAV instproc init {} { + # tell storage manager about corresponding dav object + ${:stm} configure -dav [self] + next + } + + WebDAV instproc lockToken {} { + # + # generate a token with the same properties as oacs-dav + # + set tokenList [list] + set peer [split [ns_conn peeraddr] .] + foreach v [list [clock clicks -milliseconds] \ + [ns_rand 2147483647] \ + [lindex $peer 0][lindex $peer 1] [lindex $peer 2][lindex $peer 3]] { + lappend tokenList [format %x $v] + } + return [join $tokenList -] + } + + WebDAV instproc encode {string} { + set user_agent [string tolower [ns_set get [ns_conn headers] User-Agent]] + if {[string first "microsoft data access internet publishing" $user_agent] != -1} { + set string [string map {" " "{{blank}}"} $string] + set string [ns_urlencode $string] + set string [string map {"%7b%7bblank%7d%7d" " "} $string] + } else { + set string [string map {"&" "&"} $string] + } + return $string + } + + WebDAV instproc multiStatusProps {-props:required} { + #:log "multiStatusProps $props" + # we require the fields href, collection, last_modified, content_type + set r [dict create content_length "" status "HTTP/1.1 200 OK" creationdate ""] + set r [dict replace $r {*}$props] + + lappend davprops \ + lp1:resourcetype [expr {[dict get $r collection] ? "" : ""}] \ + lp1:creationdate [:tcl_time_to_iso8601 [dict get $r creationdate]] \ + lp1:getlastmodified [:tcl_time_to_http_date [dict get $r last_modified]] \ + g0:getcontentlength [dict get $r content_length] \ + D:supportedlock {} \ + D:lockdiscovery {} \ + D:getcontenttype [dict get $r content_type] + + return [:multiStatusResonse \ + -href [dict get $r href] \ + -propstats [list $davprops [dict get $r status]]] + } + + # + # define abstact storage manager + # + + nx::Class create StorageManager -superclass nx::Class { + :property dav + + :public method deliver_file {-path:required} { + # abstract method to send a file to the user + } + :public method create_file {-path:required -content:required} { + # abstract method to create a new file + } + :public method create_folder {-path:required} { + # abstract method to create a new folder + } + :public method delete_file {-path:required} { + # abstract method to delete a file + } + :public method copy_file {-path:required -destination:required} { + # abstract method to copy a file + } + :public method move_file {-path:required -destination:required} { + # abstract method to move a file + } + :public method file_properties {-path:required -prefix {-depth 0}} { + # abstract method to return properties of a file + } + + :method log {msg} {if {$::xowiki::davStmlog} {ns_log notice "dav::stm: $msg"}} + } + +} +::xo::library source_dependent + +# +# Local variables: +# mode: tcl +# tcl-indent-level: 2 +# indent-tabs-mode: nil +# End: Index: openacs-4/packages/xotcl-core/tcl/ical-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-core/tcl/ical-procs.tcl,v diff -u -r1.18 -r1.19 --- openacs-4/packages/xotcl-core/tcl/ical-procs.tcl 18 Apr 2018 22:25:03 -0000 1.18 +++ openacs-4/packages/xotcl-core/tcl/ical-procs.tcl 20 Jul 2018 15:07:43 -0000 1.19 @@ -286,13 +286,6 @@ return $t } - # - # Subclass ::xo::ProtocolHandler for dav (as used by ical) - # - Class create ::xo::dav -superclass ProtocolHandler -parameter { - {url /webdav} - } - } ::xo::library source_dependent Index: openacs-4/packages/xowiki/tcl/xowiki-dav-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/Attic/xowiki-dav-init.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xowiki/tcl/xowiki-dav-init.tcl 20 Jul 2018 15:07:43 -0000 1.1 @@ -0,0 +1 @@ +::xowiki::dav register Index: openacs-4/packages/xowiki/tcl/xowiki-dav-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/Attic/xowiki-dav-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xowiki/tcl/xowiki-dav-procs.tcl 20 Jul 2018 15:07:43 -0000 1.1 @@ -0,0 +1,355 @@ +::xo::library doc { + XoWiki - dav procs. Simple WebDAV implementation to access files in the wiki via the + WebDAV protocol. + + @creation-date 2010-04-10 + @author Gustaf Neumann + @cvs-id $Id: xowiki-dav-procs.tcl,v 1.1 2018/07/20 15:07:43 antoniop Exp $ +} +package require XOTcl 2 + +namespace eval ::xowiki { + + # + # Concrete storage manager + # + nx::Class create StorageManager=xowiki -superclass ::xo::StorageManager { + :property {folder_form_name en:folder.form} + } + + StorageManager=xowiki method get_folder_form {-package_id:required} { + # + # Get the xowiki form that represents the folder template + # + + return [::xowiki::Weblog instantiate_forms -forms ${:folder_form_name} \ + -package_id $package_id] + } + + StorageManager=xowiki method file_path_ref {-path:required} { + set package_id [${:dav} package_id] + set parent_id [$package_id folder_id] + set package_url [$package_id package_url] + set dav_prefix [string trimright [${:dav} url] /]$package_url + set rel_path [string range $path [string length $package_url] end] + #:log "##### rel_path '$rel_path' package_url '$package_url'" + # provide default values for item props + set r [dict create package_id $package_id parent_id $parent_id \ + collection 0 item_id 0 href $dav_prefix$rel_path fname "" \ + last_modified "" content_type "" content_length ""] + + set rpath [string trim $rel_path /] + if {$rpath eq ""} { + # the root folder of the package + set folder_object [$package_id require_folder_object] + return [dict replace $r item_id $parent_id href $dav_prefix$rpath \ + creationdate [$folder_object set creation_date] \ + last_modified [$folder_object last_modified] \ + content_type "httpd/unix-directory" collection 1] + } + + set elements [split $rpath /] + # :log "##### elements: $elements" + foreach elem $elements { + set file_object [$package_id get_page_from_name -name file:$elem -parent_id $parent_id] + #:log "##### lookup of file:$elem $parent_id => $file_object" + if {$file_object ne ""} { + #:log FO=[$file_object serialize] + # The file_object does not contain a content_length. we could obtain it from the + # path, but the SQL query is more generic as it can deal with other types as well. + set content_length [xo::dc get_value get_content_length \ + "select content_length from cr_revisions where revision_id = [$file_object revision_id]" \ + 0] + :log cl=$content_length-[$file_object full_file_name]-->[file size [$file_object full_file_name]] + return [dict replace $r \ + item_id [$file_object item_id] \ + parent_id $parent_id \ + fname file:$elem \ + last_modified [$file_object last_modified] \ + creationdate [$file_object set creation_date] \ + content_type [$file_object mime_type] \ + content_length $content_length] + } + + set folder_page_object [$package_id get_page_from_name \ + -assume_folder true -name $elem -parent_id $parent_id] + :log "##### lookup of $elem $parent_id => $folder_page_object" + if {$folder_page_object ne ""} { + if {[$folder_page_object info class] ne "::xowiki::FormPage"} { + return [dict replace $r fname $elem parent_id $parent_id] + } + set item_id [$folder_page_object item_id] + set prev_parent_id $parent_id + set parent_id [$folder_page_object item_id] + set last_elem $elem + } else { + return [dict replace $r fname $elem parent_id $parent_id] + } + } + + return [dict replace $r \ + item_id $item_id parent_id $prev_parent_id fname $last_elem \ + collection 1 content_type "httpd/unix-directory"] + } + + StorageManager=xowiki public method deliver_file {-path:required} { + set r [:file_path_ref -path $path] + if {[dict get $r item_id]} { + set file_object [::xo::db::CrClass get_instance_from_db -item_id [dict get $r item_id]] + if {![::[dict get $r package_id] check_permissions [dict get $r item_id] view]} { + return [dict create success -1 msg "permission denied"] + } + # Calling download on a file or link should work this way. + # Maybe we can extend this to photo.form instance or similar as well. + $file_object set package_id [dict get $r package_id] + [dict get $r package_id] reply_to_user [$file_object www-download] + return [dict create success 1 msg "file $path scheduled for delivery"] + } + return [dict create success 0 msg "file $path not found"] + } + + StorageManager=xowiki public method create_folder {-path:required} { + set r [:file_path_ref -path $path] + set package_id [dict get $r package_id] + + set folder_form_id [:get_folder_form -package_id $package_id] + if {![::$package_id check_permissions $package_id edit-new]} { + return [dict create success -1 msg "folder create $path: permission denied"] + } + ::$package_id get_lang_and_name -name [dict get $r fname] lang strippedname + + set folder [$folder_form_id create_form_page_instance \ + -name $strippedname \ + -package_id $package_id \ + -parent_id [dict get $r parent_id] \ + -publish_status "ready"] + $folder set title $strippedname + $folder set creation_user [${:dav} user_id] + $folder set creator [person::name -person_id [${:dav} user_id]] + $folder save_new + return [dict create success 1 msg "folder created $path"] + } + + StorageManager=xowiki public method create_file {-path:required -contentfile:required} { + set r [:file_path_ref -path $path] + set item_id [dict get $r item_id] + set package_id [dict get $r package_id] + + if {$item_id} { + if {![::$package_id check_permissions $item_id edit]} { + return [dict create success -1 msg "update $path: permission denied"] + } + # the file exists already, we add a new revision + set file_object [::xo::db::CrClass get_instance_from_db -item_id $item_id] + set save_method save + set operation updated + set success 2 + } else { + if {![::$package_id check_permissions $package_id edit-new]} { + return [dict create success -1 msg "create $path: permission denied"] + } + # create a fresh file + set file_object [::xowiki::File new -destroy_on_cleanup \ + -title [file tail $path] \ + -name file:[dict get $r fname] \ + -parent_id [dict get $r parent_id] \ + -mime_type [::xowiki::guesstype [dict get $r fname]] \ + -package_id $package_id \ + -creation_user [${:dav} user_id]] + set save_method save_new + set operation created + set success 1 + } + + $file_object set import_file $contentfile + $file_object $save_method + + ::xo::xotcl_object_cache flush [$file_object set item_id] + ::xo::xotcl_object_cache flush [$file_object set revision_id] + + return [dict create success $success msg "file $operation $path via $save_method"] + } + + StorageManager=xowiki public method delete_file {-path:required} { + set r [:file_path_ref -path $path] + set item_id [dict get $r item_id] + if {$item_id} { + # We could check for deletion, but mac-os x likes to create tmp + # files, where the create right has to be the same as the delete + # right, otherwise operations are pending + set package_id [dict get $r package_id] + if {[::$package_id check_permissions $item_id write]} { + $package_id www-delete -item_id $item_id \ + -name [dict get $r fname] -parent_id [dict get $r parent_id] + return [dict create success 1 msg "file [dict get $r fname] deleted"] + } else { + return [dict create success -1 msg "insufficient permissions to delete file $path"] + } + } + return [dict create success 0 msg "file not found"] + } + + StorageManager=xowiki public method copy_file {-path:required -destination:required} { + set r [:file_path_ref -path $path] + set item_id [dict get $r item_id] + if {$item_id} { + # maybe add "copy" permission + if {[::[dict get $r package_id] check_permissions $item_id read]} { + set dest [:file_path_ref -path $destination] + :log "#### dest '$destination' => $dest" + #if {![::[dict get $dest package_id] check_permissions [dict get $dest item_id]]} { + #} + } else { + return [dict create success -3 msg "file copy: [dict get $r msg]"] + } + # Currently we have no cross package copy support. Maybe not needed. + set file_object [::xo::db::CrClass get_instance_from_db -item_id $item_id] + set r [:create_file -path $destination \ + -contentfile [$file_object full_file_name]] + return [dict create success [dict get $r success] msg "file copy: [dict get $r msg]"] + } else { + return [dict create success 0 msg "File $path not found"] + } + } + + StorageManager=xowiki public method move_file {-path:required -destination:required} { + set r [:file_path_ref -path $path] + set item_id [dict get $r item_id] + if {$item_id} { + set file_object [::xo::db::CrClass get_instance_from_db -item_id $item_id] + if {![$file_object istype ::xowiki::File]} { + # this must be a folder + set package_id [dict get $r package_id] + if {![::$package_id check_permissions $package_id edit-new]} { + return [dict create success -1 msg "folder create $path: permission denied"] + } + set dest [split [string trimright $destination "/"] /] + set name [lindex $dest end] + set target [join [lrange $dest 0 end-1] /] + #set b [:file_path_ref -path $target] + #$file_object reparent -target_item_id [dict get $b item_id] + $file_object rename -old_name [$file_object name] -new_name $name + $file_object set title $name + $file_object save + ::xo::clusterwide ns_cache flush xotcl_object_cache $file_object + return [dict create success 1 msg "folder moved"] + } + } + # The RFC says that we have to create a new file and delete the + # old one. + set r [:copy_file -path $path -destination $destination] + if {[dict get $r success] > 0} { + :delete_file -path $path + } + return [dict create success [dict get $r success] msg "file rename: [dict get $r msg]"] + } + + StorageManager=xowiki public method file_properties { + -path:required + {-prefix ""} + {-depth 0} + } { + :log "##### file_properties path=$path prefix=$prefix depth=$depth" + set item_props [:file_path_ref -path $path] + set item_id [dict get $item_props item_id] + #:log "##### item_props $item_props" + + if {!$item_id} { + return [dict create success 0 msg "File $path not found" props ""] + } + + set props [list] + if {![dict get $item_props collection]} { + # + # Properties of a single file + # + return [dict create success 1 msg "Properties of $path" props [list $item_props]] + + } else { + # + # Properties of a container + # -depth is ignored for now + # + # first, include the folder entry .... + lappend props $item_props + # ... and then the entries of the folder + # + if {$depth != 0} { + # + # Get the file entries + # + set package_id [dict get $item_props package_id] + if {[string range $path end end] ne "/"} {append path /} + set sql [::xowiki::File instance_select_query \ + -folder_id $item_id \ + -from_clause ", xowiki_page p" \ + -where_clause "p.page_id = bt.revision_id" \ + -select_attributes {content_length mime_type last_modified} \ + -orderby ci.name] + + foreach entry [db_list_of_lists dbqd..instance_select $sql] { + lassign $entry \ + file_item_id name publish_status object_type file_package_id \ + content_length mime_type last_modified + if {![regexp {^file:(.*)$} $name _ fname]} continue + + set href [dict get $item_props href]$fname + # set href [ad_urlencode_path $href] + :log "..... FILE $href content_length $content_length" + lappend props [dict create collection 0 \ + href $href \ + last_modified $last_modified \ + content_type $mime_type \ + content_length $content_length] + } + + # + # Get the folder form entries + # + set folder_form_id [:get_folder_form -package_id $package_id] + set folder_pages [::xowiki::FormPage get_form_entries \ + -parent_id $item_id \ + -base_item_ids $folder_form_id -form_fields "" \ + -publish_status ready -package_id $package_id] + #:log props=$props + foreach folder [$folder_pages children] { + set href [$package_id pretty_link \ + -path_encode false \ + -parent_id [$folder parent_id] \ + [$folder name]] + set href [string trimright [${:dav} url] /]$href + #set href [ad_urlencode_path $href] + :log "..... FOLDER [dict get $item_props href] " + lappend props [dict create collection 1 \ + href $href \ + last_modified [$folder last_modified] \ + content_type "httpd/unix-directory" \ + content_length ""] + :log after-lappend-props=$props + } + } + + return [dict create success 1 msg "Properties of $path" props $props] + } + } + +} + +# +# finally create handler objects +# +namespace eval ::xowiki { + # create an instance of the xowiki storage manager + StorageManager=xowiki create WebDav-stm-xowiki + + # create an instance of the the webdav handler for xowiki + ::xo::WebDAV create ::xowiki::dav -stm ::xowiki::WebDav-stm-xowiki +} +::xo::library source_dependent + +# +# Local variables: +# mode: tcl +# tcl-indent-level: 2 +# indent-tabs-mode: nil +# End: