davclient 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,76 @@
1
+ = DavClient
2
+
3
+ * http://davclient.rubyforge.org
4
+ * http://rubyforge.org/mailman/listinfo/davclient-general
5
+
6
+ == DESCRIPTION:
7
+
8
+ WebDAV command line client written in Ruby for managing content on
9
+ webservers that support the WebDAV extensions.
10
+
11
+ == Requirements
12
+
13
+ The command line utility curl installed and available in your unix path.
14
+
15
+ == LIRBRARY SYNOPSIS:
16
+
17
+ require 'rubygems'
18
+ require 'davclient'
19
+
20
+ # Print url of all files in webdav folder recursively
21
+ # with basic tree walking
22
+
23
+ url = 'http://test.webdav.org/dav/'
24
+ WebDAV.find(url, :recursive => true) do |item|
25
+ puts item.href
26
+ end
27
+
28
+ == COMMAND LINE UTILITIES:
29
+
30
+ DavClient includes the command line utility 'dav'. It is inspired by git and should be familiar to unix users.
31
+ The command 'dav cd url' sets current working url, 'dav ls' list files and 'dav pwd'
32
+ prints current working url. , users can access files, folders and their properties on webdav servers.
33
+
34
+ The only authentication method supported at the moment, is by reading usernames and passwords from
35
+ a file named ~/.netrc. If username is missing, the 'dav' command will print out detailed instructions
36
+ on how to add username etc. to the '~/.netrc' file.
37
+
38
+ == COMMAND LINE SYNOPSIS:
39
+
40
+ >dav cd http://test.webdav.org/dav/
41
+ http://test.webdav.org/dav/
42
+ >dav ls
43
+ images/
44
+ index.html
45
+ >dav pwd
46
+ http://test.webdav.org/dav/
47
+
48
+ == INSTALL:
49
+
50
+ [sudo] gem install davclient
51
+
52
+ or
53
+
54
+ git clone git://github.com/thomasfl/davclient.git
55
+ cd davclient
56
+ gem build Rakefile
57
+ sudo gem install davclient-x.x.x.gem
58
+
59
+ Curl comes preinstalled on Mac OS X. It can be downloaded from
60
+ http://curl.haxx.se/ . If you are using debian or ubuntu, it
61
+ can be installed by:
62
+
63
+ sudo apt-get install curl
64
+
65
+ == Background:
66
+
67
+ There has been posted a few examples on the web of how to make a WebDAV client.
68
+ The problem is that they all seem to support only one type of username and password
69
+ authentication. DavClient instead uses the command line tool 'curl' to do all the
70
+ authentication and networking. To avoid handling authentication all togheter, curl
71
+ are told to look up all usernames and passwords are in a file named ~/.netrc.
72
+
73
+ The command 'dav' is non-interactive and inspired by git, making it suitable for
74
+ use in scripts. If you can script in Ruby, the examples folder includes sample
75
+ scripts using the davclient Ruby library.
76
+
data/bin/dav ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'davclient'
4
+ require 'davclient/davcli'
5
+
6
+ DavCLI.dav(ARGV)
@@ -0,0 +1,73 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ def remove_newlines(string)
4
+ string.gsub("\n","").gsub(/ +/," ") + " "
5
+ end
6
+
7
+ # Templates for curl commands:
8
+ curl_propfind_cmd = <<EOF
9
+ #{$curl}
10
+ --request PROPFIND
11
+ --header 'Content-Type: text/xml; charset="utf-8"'
12
+ --header "Depth: 1"
13
+ --data-ascii '<?xml version="1.0" encoding="utf-8"?>
14
+ <DAV:propfind xmlns:DAV="DAV:"><DAV:allprop/></DAV:propfind>'
15
+ --netrc
16
+ EOF
17
+ CURL_PROPFIND = remove_newlines(curl_propfind_cmd)
18
+
19
+ curl_proppatch_cmd = <<EOF
20
+ #{$curl}
21
+ --request PROPPATCH
22
+ --header 'Content-Type: text/xml; charset="utf-8"'
23
+ --header "Depth: 1"
24
+ --data-ascii '<?xml version="1.0"?>
25
+ <d:propertyupdate xmlns:d="DAV:" xmlns:v="vrtx">
26
+ <d:set>
27
+ <d:prop>
28
+ <!--property-and-value-->
29
+ </d:prop>
30
+ </d:set>
31
+ </d:propertyupdate>'
32
+ --netrc
33
+ EOF
34
+ CURL_PROPPATCH = remove_newlines(curl_proppatch_cmd)
35
+
36
+ curl_delete_cmd = <<EOF
37
+ #{$curl}
38
+ --request DELETE
39
+ --header 'Content-Type: text/xml; charset="utf-8"'
40
+ --netrc
41
+ EOF
42
+ CURL_DELETE = remove_newlines(curl_delete_cmd)
43
+
44
+ curl_mkcol_cmd = <<EOF
45
+ #{$curl}
46
+ --request MKCOL
47
+ --header 'Content-Type: text/xml; charset="utf-8"'
48
+ --netrc
49
+ EOF
50
+ CURL_MKCOL = remove_newlines(curl_mkcol_cmd)
51
+
52
+ CURL_OPTIONS = "#{$curl} -i -X OPTIONS --netrc "
53
+
54
+ curl_copy = <<EOF
55
+ #{$curl}
56
+ --request COPY
57
+ --header 'Content-Type: text/xml; charset="utf-8"'
58
+ --header 'Destination: <!--destination-->'
59
+ --netrc
60
+ EOF
61
+
62
+ CURL_COPY = remove_newlines(curl_copy)
63
+
64
+
65
+ curl_move = <<EOF
66
+ #{$curl}
67
+ --request MOVE
68
+ --header 'Content-Type: text/xml; charset="utf-8"'
69
+ --header 'Destination: <!--destination-->'
70
+ --netrc
71
+ EOF
72
+
73
+ CURL_MOVE = remove_newlines(curl_move)
@@ -0,0 +1,88 @@
1
+ # WebDav ls command line utility
2
+ # Synopsis:
3
+ # dav ls [options][url]
4
+ #
5
+ # or standalone:
6
+ #
7
+ # ruby dav-ls [options][url]
8
+
9
+ require 'rubygems'
10
+ require 'davclient'
11
+ require 'optparse'
12
+
13
+ class LsCLI
14
+
15
+ def self.ls(args)
16
+ options = read_options(args)
17
+ url = args[0]
18
+ tmp_cwurl = WebDAV.CWURL
19
+ if(not url)then
20
+ url = WebDAV.CWURL
21
+ if(not url)then
22
+ puts "#{$0} ls: no current working url"
23
+ puts "Usage: Use '#{$0} cd [url|dir] to set current working url"
24
+ exit
25
+ end
26
+ else
27
+ WebDAV.cd(url)
28
+ end
29
+
30
+ url = WebDAV.CWURL
31
+ WebDAV.find(url, :recursive => false ) do |item|
32
+ if(options[:showUrl])then
33
+ puts item.href
34
+ elsif(options[:longFormat])
35
+
36
+ else
37
+ print item.basename
38
+ print "/" if item.isCollection?
39
+ puts
40
+ end
41
+ end
42
+
43
+ # Restore CWURL
44
+ WebDAV.cd(tmp_cwurl)
45
+ end
46
+
47
+ private
48
+
49
+ def self.read_options(args)
50
+ options = {}
51
+
52
+ optparse = OptionParser.new do|opts|
53
+ opts.banner = "Usage: #{$0} ls [options] url"
54
+
55
+ opts.on( '-h', '--help', 'Display this screen' ) do
56
+ puts opts
57
+ exit
58
+ end
59
+
60
+ options[:longFormat] = false
61
+ opts.on( '-l', "List in long format" ) do
62
+ options[:longFormat] = true
63
+ end
64
+
65
+ options[:showUrl] = false
66
+ opts.on('-a', "Include full url in names.") do
67
+ options[:showUrl] = true
68
+ end
69
+
70
+ end
71
+
72
+ begin
73
+ optparse.parse! args
74
+ rescue
75
+ puts "Error: " + $!
76
+ puts optparse
77
+ exit
78
+ end
79
+
80
+ return options
81
+ end
82
+
83
+ end
84
+
85
+ # Make this file an executable script
86
+ if $0 == __FILE__
87
+ LsCLI.ls(ARGV)
88
+ end
@@ -0,0 +1,92 @@
1
+ # Handle 'dav propfind [URL]' command
2
+ require 'rubygems'
3
+ require 'davclient'
4
+ require 'optparse'
5
+
6
+ class PropfindCLI
7
+
8
+ def self.propfind(args)
9
+ options = read_options(args)
10
+
11
+ url = args[0]
12
+ if(not(url)) then
13
+ url = WebDAV.CWURL
14
+ end
15
+
16
+ if(not(url)) then
17
+ puts "Error: Missing mandatory url"
18
+ puts optparse
19
+ exit
20
+ end
21
+
22
+ if(options[:xml])then
23
+ puts WebDAV.propfind(url, :xml => true)
24
+ else
25
+
26
+ # TODO This is experimental code in desperat need
27
+ # of love and attention
28
+ item = WebDAV.propfind(url)
29
+ puts item.collection
30
+
31
+ prev_url = nil
32
+ WebDAV.find(url, :children => options[:children]) do | url, item |
33
+ if(prev_url != url) then
34
+ puts
35
+ puts "url = " + url.to_s
36
+ prev_url = url
37
+ end
38
+
39
+ name = item.prefix
40
+ if(item.namespace)then
41
+ name = name + "(" + item.namespace + ")"
42
+ end
43
+ name = name + item.name
44
+ puts name.ljust(40) + " = '" + item.text.to_s + "'"
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ private
52
+
53
+ def self.read_options(args)
54
+ options = {}
55
+
56
+ title = nil
57
+ optparse = OptionParser.new do|opts|
58
+ opts.banner = "Usage: #{$0} propfind [options] url"
59
+
60
+ opts.on( '-h', '--help', 'Display this screen' ) do
61
+ puts opts
62
+ exit
63
+ end
64
+
65
+ options[:xml] = true
66
+ opts.on( '-p', '--pretty', "Pretty print output instead of returning xml" ) do
67
+ options[:xml] = false
68
+ end
69
+
70
+ options[:children] = false
71
+ opts.on('-c', '--children', "Show children if viewing collection (folder)") do
72
+ options[:children] = true
73
+ end
74
+
75
+ end
76
+
77
+ begin
78
+ optparse.parse!
79
+ rescue
80
+ puts "Error: " + $!
81
+ puts optparse
82
+ exit
83
+ end
84
+
85
+ return options
86
+ end
87
+
88
+ end
89
+
90
+ if $0 == __FILE__
91
+ PropfindCLI.propfind(ARGV)
92
+ end
@@ -0,0 +1,71 @@
1
+ # WebDav put command line utility
2
+ # Synopsis:
3
+ # dav put [options][url]
4
+ #
5
+ # or standalone:
6
+ #
7
+ # ruby dav-ls [options][url]
8
+
9
+ require 'rubygems'
10
+ require 'davclient'
11
+ require 'optparse'
12
+
13
+ class PutCLI
14
+
15
+ def self.put(args)
16
+ options = read_options(args)
17
+ url = args[0]
18
+ if(options[:string])then
19
+ begin
20
+ WebDAV.put_string(url,options[:string])
21
+ rescue
22
+ puts $0 + ": " + $!
23
+ end
24
+ puts "Published content to " + url
25
+ else
26
+ puts "PUT file not implemented"
27
+ end
28
+
29
+ end
30
+
31
+ private
32
+
33
+ def self.usage()
34
+ puts "Usage: #{$0} put --string \"<html>..</html>\" url"
35
+ end
36
+
37
+ def self.read_options(args)
38
+ options = {}
39
+
40
+ optparse = OptionParser.new do|opts|
41
+ opts.banner = "Usage: #{$0} put [options] url"
42
+
43
+ opts.on( '-h', '--help', 'Display this screen' ) do
44
+ puts opts
45
+ exit
46
+ end
47
+
48
+ options[:string] = false
49
+ opts.on( '-s', '--string', "Put contents of string" ) do |str |
50
+ options[:string] = str
51
+ end
52
+
53
+ end
54
+
55
+ begin
56
+ optparse.parse! args
57
+ rescue
58
+ puts "Error: " + $!
59
+ puts optparse
60
+ exit
61
+ end
62
+
63
+ return options
64
+ end
65
+
66
+ end
67
+
68
+ # Make this file an executable script
69
+ if $0 == __FILE__
70
+ PutCLI.put(ARGV)
71
+ end
@@ -0,0 +1,166 @@
1
+ require 'davclient/dav-ls'
2
+ require 'davclient/dav-put'
3
+ require 'davclient/dav-propfind'
4
+
5
+ # Handle the 'dav' command line commands
6
+
7
+ class DavCLI
8
+
9
+ def self.cat(args)
10
+ if(args.size == 1)
11
+ url = args[0]
12
+ puts WebDAV.get(url)
13
+ else
14
+ puts "Illegal arguments: " + args[1..100].join(" ")
15
+ puts "#{$0}: usage '#{$0} cat [url|filename]"
16
+ end
17
+ end
18
+
19
+ def self.pwd(args)
20
+ cwurl = WebDAV.CWURL
21
+ if(cwurl)
22
+ puts cwurl
23
+ else
24
+ puts "#{$0}: No working url set. Use 'dav cd url' to set url"
25
+ end
26
+
27
+ end
28
+
29
+ def self.cd(args)
30
+ url = args[0]
31
+ if(url == nil)then
32
+ puts "#{$0} cd: Missing mandatory url."
33
+ exit
34
+ end
35
+ begin
36
+ WebDAV.cd(url)
37
+ puts "Changing WebDAV URL to: " + WebDAV.CWURL
38
+ rescue Exception => exception
39
+ puts exception
40
+ end
41
+ end
42
+
43
+ def self.mkcol(args)
44
+ if(args.size == 1 )
45
+ WebDAV.mkcol(args[0])
46
+ else
47
+ puts "#{$0}: usage '#{$0} mkcol url|path"
48
+ end
49
+ end
50
+
51
+ def self.delete(args)
52
+ if(args.size == 1)
53
+ url = WebDAV.delete(args[0])
54
+ puts "#{$0} delete: Deleted '#{url}'"
55
+ else
56
+ puts "#{$0}: usage '#{$0} delete url|path"
57
+ end
58
+ end
59
+
60
+ def self.options(args)
61
+ if(args.size == 0 or args.size == 1)
62
+ puts WebDAV.options(args[0])
63
+ else
64
+ puts "#{$0}: usage '#{$0} options [url]"
65
+ end
66
+ end
67
+
68
+ def self.propfind(args)
69
+ PropfindCLI.propfind(args)
70
+ end
71
+
72
+ def self.ls(args)
73
+ LsCLI.ls(args)
74
+ end
75
+
76
+ def self.cp(args)
77
+ if(args.size == 2 )
78
+ WebDAV.cp(args[0], args[1])
79
+ else
80
+ puts "#{$0}: usage '#{$0} cp src dest"
81
+ end
82
+ end
83
+
84
+
85
+ def self.mv(args)
86
+ if(args.size == 2 )
87
+ WebDAV.mv(args[0], args[1])
88
+ else
89
+ puts "#{$0}: usage '#{$0} copy mv dest"
90
+ end
91
+ end
92
+
93
+ def self.print_dav_usage
94
+ puts "usage: #{$0} COMMAND [ARGS]"
95
+ puts ""
96
+ puts "Available #{$0} commands:"
97
+ puts " ls List files on webdav server"
98
+ puts " pwd Print current working url"
99
+ puts " cd Change current working url"
100
+ puts " cp Copy resource"
101
+ puts " mv Move resource"
102
+ puts " rm Remove resource"
103
+ puts " cat Print content of resource"
104
+ puts " propfind Print webdav properties for url"
105
+ puts " mkcol Make collection"
106
+ puts " options Display webservers WebDAV options"
107
+ puts ""
108
+ puts "See '#{$0} COMMAND -h' for more information on a specific command."
109
+ exit
110
+ end
111
+
112
+ def self.dav(args)
113
+ command = args[0]
114
+
115
+ if(command == "-h" or command =~ /help/ or command =~ /\?/) then
116
+ print_dav_usage
117
+ end
118
+
119
+ if(command == "-v" or command =~ /version/ ) then
120
+ puts "#{$0} version " + WebDAV.version
121
+ exit
122
+ end
123
+
124
+ args = args[1..100]
125
+ case command
126
+ when "cat" then
127
+ cat(args)
128
+ when "ls" then
129
+ LsCLI.ls(args)
130
+ when "pwd"
131
+ pwd(args)
132
+ when "cd"
133
+ cd(args)
134
+ when "cp"
135
+ cp(args)
136
+ when "copy"
137
+ cp(args)
138
+ when "mv"
139
+ mv(args)
140
+ when "move"
141
+ mv(args)
142
+ when "mkcol"
143
+ mkcol(args)
144
+ when "mkdir"
145
+ mkcol(args)
146
+ when "put"
147
+ PutCLI.put(args)
148
+ when "delete"
149
+ delete(args)
150
+ when "del"
151
+ delete(args)
152
+ when "rm"
153
+ delete(args)
154
+ when "propfind"
155
+ propfind(args)
156
+ when "props"
157
+ propfind(args)
158
+ when "options"
159
+ options(args)
160
+ else
161
+ puts "Unknown command :'" + command + "'"
162
+ print_dav_usage
163
+ end
164
+ end
165
+
166
+ end
@@ -0,0 +1,118 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'hpricot'
5
+
6
+ # Extensions to the Hpricot XML parser.
7
+ module Hpricot
8
+
9
+
10
+
11
+ class Elem
12
+
13
+ # Makes properties available as simple method calls.
14
+ #
15
+ # Example:
16
+ # print item.creationdate()
17
+ def method_missing(method_name, *args)
18
+ if(args.size == 0) then
19
+ return property(method_name.to_s)
20
+ end
21
+ raise "Method missing"
22
+ end
23
+
24
+ # Resource url
25
+ def href()
26
+ self.at("d:href").innerText
27
+ end
28
+
29
+ # Returns true of resource is a collection, i.e. a folder and not a file.
30
+ def isCollection?()
31
+ self.at("d:collection") != nil
32
+ end
33
+
34
+ end
35
+
36
+ # TODO Not used. Delete???
37
+ def type_convert_value(value)
38
+ if(returnValue == "true")then
39
+ return true
40
+ end
41
+ if(returnValue == "false")then
42
+ return false
43
+ end
44
+ # Number format???
45
+ ## Dato format
46
+ return returnValue
47
+ end
48
+
49
+ # TODO: Make list of recognized namespace prefixes configurable
50
+ # Get property.
51
+ # Example:
52
+ # page = WebDAV.find(url)
53
+ # print page.property("published-date")
54
+ def property(name)
55
+
56
+ property = property = self.at(name)
57
+ if(property)then
58
+ returnValue = property.innerText
59
+ return returnValue
60
+ end
61
+
62
+ property = property = self.at(name.downcase)
63
+ if(property)then
64
+ return property.innerText
65
+ end
66
+
67
+ vrtx_property = self.at("v:" + name)
68
+ if(vrtx_property)then
69
+ return vrtx_property.innerText
70
+ end
71
+
72
+ vrtx_property = self.at("v:" + name.downcase)
73
+ if(vrtx_property)then
74
+ return vrtx_property.innerText
75
+ end
76
+
77
+ dav_property = self.at("d:" +name)
78
+ if( dav_property)then
79
+ return dav_property.innerText
80
+ end
81
+
82
+ dav_property = self.at("d:" +name.downcase)
83
+ if( dav_property)then
84
+ return dav_property.innerText
85
+ end
86
+
87
+ return nil
88
+ end
89
+
90
+ def basename
91
+ File.basename(self.at("d:href").innerText)
92
+ end
93
+
94
+ # TODO: Move to vortex_lib.rb
95
+ def dateProperty(name)
96
+ date = self.property(name)
97
+ if(date =~ /\dZ$/)then
98
+ # Fix for bug in vortex:
99
+ #
100
+ # Some date properties are in xmlshcema datetime format, but
101
+ # all tough the time seems to be localtime the timezone is
102
+ # specified as Z not CEST. Fix is to set timezone and add
103
+ # 2 hours.
104
+ date = date.gsub(/\dZ$/," CEST")
105
+ time = Time.parse(date)
106
+ time = time + (60 * 60 * 2)
107
+ return time
108
+ end
109
+ time = Time.parse(date)
110
+ return time
111
+ end
112
+
113
+ # Set the items WebDAV properties. Properties must be a string with XML.
114
+ def proppatch(properties)
115
+ WebDAV.proppatch(href, properties)
116
+ end
117
+
118
+ end
data/lib/davclient.rb ADDED
@@ -0,0 +1,451 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'hpricot'
4
+ require 'tempfile'
5
+ require 'open3'
6
+ require 'pathname'
7
+ require 'davclient/hpricot_extensions'
8
+
9
+ # :stopdoc:
10
+
11
+ # Path to curl executable:
12
+ $curl = "curl"
13
+
14
+ require 'davclient/curl_commands'
15
+
16
+ # :startdoc:
17
+
18
+ # WebDAV client
19
+ module WebDAV
20
+
21
+ # :stopdoc:
22
+ VERSION = '0.0.5'
23
+ # :startdoc:
24
+
25
+ # Returns the version string for the library.
26
+ #
27
+ def self.version
28
+ VERSION
29
+ end
30
+
31
+ # Returns current working url. Used by command line utilites
32
+ def self.CWURL
33
+ return $CWURL if($CWURL) # Used by tests
34
+ cwurl = nil
35
+ filename = cwurl_filename
36
+ if(File.exists?(filename))
37
+ File.open(filename, 'r') {|f| cwurl = f.read() }
38
+ end
39
+ return cwurl
40
+ end
41
+
42
+ # Make relative url absolute. Returns error if no current working
43
+ # url has been set.
44
+ #
45
+ # Example:
46
+ #
47
+ # WebDAV.cd("https://example.org/subfolder")
48
+ # print WebDAV.absoluteUrl("..") => "https://example.org/"
49
+ def self.absoluteUrl(url)
50
+ if(not(url =~ /^http.?:\/\//))then
51
+ cwurl = Pathname.new(self.CWURL)
52
+ cwurl = cwurl + url
53
+ url = cwurl.to_s
54
+ # url = url + "/" if(not(url =~ /\/$/))
55
+
56
+ if(not(url =~ /^http.?:\/\//))then
57
+ warn "#{$0}: Error: illegal url: " + url
58
+ exit
59
+ end
60
+ end
61
+ return url
62
+ end
63
+
64
+ # Change current working url. Takes relative pathnames.
65
+ #
66
+ # Examples:
67
+ #
68
+ # WebDAV.cd("http://www.example.org")
69
+ #
70
+ # WebDAV.cd("../folder")
71
+ def self.cd(url)
72
+ url = absoluteUrl(url)
73
+ url = url + "/" if(not(url =~ /\/$/))
74
+
75
+ resource = WebDAV.propfind(url)
76
+ if(resource and resource.isCollection?)then
77
+ WebDAV.CWURL = url
78
+ else
79
+ # TODO Make proper exception
80
+ raise Exception, "cd: URL '#{cwurl} is not a WebDAV collection."
81
+ end
82
+ end
83
+
84
+ # Sets current working url by storing url in a tempfile with parent process pid
85
+ # as part of the filename.
86
+ def self.CWURL=(url)
87
+ $CWURL = url # Used by tests
88
+ File.open(cwurl_filename, 'w') {|f| f.write(url) }
89
+ end
90
+
91
+ # Get content of resource as string
92
+ #
93
+ # Example:
94
+ #
95
+ # html = WebDAV.get(url)
96
+ #
97
+ # html = WebDAV.get("file_in_current_working_folder.html")
98
+ def self.get(url)
99
+ url = absoluteUrl(url)
100
+
101
+ curl_command = "#{$curl} --netrc " + url
102
+ return exec_curl(curl_command)
103
+ end
104
+
105
+ # Set WebDAV properties for url as xml.
106
+ #
107
+ # Example:
108
+ #
109
+ # WebDAV.proppatch("https://dav.webdav.org/folder","<contentLastModified>2007-12-12 12:00:00 GMT</contentLastModified>
110
+ def self.proppatch(href, property)
111
+ curl_command = CURL_PROPPATCH + " \""+href+"\""
112
+ curl_command = curl_command.gsub("<!--property-and-value-->",property)
113
+ response = exec_curl(curl_command)
114
+ if(not(response =~ /200 OK/)) then
115
+ puts "Error:\nRequest:\n" + curl_command + "\n\nResponse: " + response
116
+ exit(0)
117
+ end
118
+ end
119
+
120
+ # Get WebDAV properties
121
+ #
122
+ # Examples:
123
+ # item = propfind(url) - Returns a Hpricot::Elem object
124
+ #
125
+ # xml = propfind(url, :xml => true) - Returns xml for debugging.
126
+ def self.propfind(*args)
127
+ url = args[0]
128
+ url = absoluteUrl(url)
129
+ options = args[1]
130
+
131
+ curl_command = CURL_PROPFIND + " \"" + url + "\""
132
+ response = exec_curl(curl_command)
133
+
134
+ if(response == "")then
135
+ return nil
136
+ end
137
+
138
+ if(not(response =~ /200 OK/)) then
139
+ puts "Error:\nRequest:\n" + curl_command + "\n\nResponse: " + response
140
+ exit(0)
141
+ end
142
+
143
+ if(options and options[:xml])then
144
+ return response
145
+ end
146
+ doc = Hpricot( response )
147
+ items_filtered = Array.new()
148
+ items = doc.search("//d:response").reverse
149
+ items.each do |item|
150
+
151
+ # Only return root item if folder
152
+ if(item.href == url or item.href == url + "/" ) then
153
+ return item
154
+ end
155
+ end
156
+ return nil
157
+ end
158
+
159
+ # Find files and folders.
160
+ #
161
+ # Examples:
162
+ #
163
+ # result = find( url )
164
+ #
165
+ # result = find( url, :type => "collection" ,:recursive => true)
166
+ #
167
+ # You can also pass a block of code:
168
+ #
169
+ # find( url, :type => "collection" ,:recursive => true) do |folder|
170
+ # puts folder.href
171
+ # end
172
+ #
173
+ def self.find(*args, &block)
174
+ href = args[0]
175
+ options = args[1]
176
+ type = nil
177
+ recursive = false
178
+ if(options)then
179
+
180
+ if(options[:type])then
181
+ type = options[:type]
182
+ end
183
+ if(options[:recursive])then
184
+ recursive = options[:recursive]
185
+ end
186
+ end
187
+ dav_xml_output = propfind(href, :xml => true)
188
+ if(not(dav_xml_output))then
189
+ return nil
190
+ end
191
+
192
+ doc = Hpricot( dav_xml_output )
193
+ items_filtered = Array.new()
194
+ items = doc.search("//d:response").reverse
195
+
196
+ # filter items
197
+ items.each do |item|
198
+
199
+ # Ignore info about root item (file or folder)
200
+ if(item.href != href) then
201
+
202
+ if(type == nil)then
203
+ # No filters
204
+ items_filtered.push(item)
205
+ if(block) then
206
+ yield item
207
+ end
208
+
209
+ else
210
+ # Filter result set
211
+ if((type == "collection" or type == "folder") and item.collection )then
212
+ items_filtered.push(item)
213
+ if(block) then
214
+ yield item
215
+ end
216
+ end
217
+ if(type == "file" and item.collection == false )then
218
+ items_filtered.push(item)
219
+ if(block) then
220
+ yield item
221
+ end
222
+ end
223
+ end
224
+
225
+ end
226
+ end
227
+
228
+ if(recursive)then
229
+ items_filtered.each do |item|
230
+ if(item.collection && item.href != args[0])then
231
+ result = find(item.href, args[1], &block)
232
+ if(result != nil)
233
+ items_filtered.concat( result)
234
+ end
235
+ end
236
+ end
237
+ end
238
+
239
+ return items_filtered
240
+ end
241
+
242
+ # Make collection
243
+ # Accepts relative url's
244
+ def self.mkcol(*args) # url, props)
245
+ url = args[0]
246
+ props = args[3]
247
+ url = absoluteUrl(url)
248
+ curl_command = CURL_MKCOL + " " + url
249
+ response = exec_curl(curl_command)
250
+
251
+ if(props)then
252
+ proppatch(url,props)
253
+ end
254
+ if(response =~ />Created</)then
255
+ return true
256
+ end
257
+ return response
258
+ end
259
+
260
+ # Returns true if resource exists
261
+ def self.exists?(url)
262
+ url = absoluteUrl(url)
263
+ props = WebDAV.propfind(url)
264
+ if(props.to_s.size == 0)then
265
+ return false
266
+ else
267
+ return true
268
+ end
269
+ end
270
+
271
+ # Copy resources
272
+ #
273
+ # Examples:
274
+ #
275
+ # WebDAV.cp("src.html","https://example.org/destination/destination.html"
276
+ def self.cp(src,dest)
277
+ srcUrl = absoluteUrl(src)
278
+ destUrl = absoluteUrl(dest)
279
+
280
+ # puts "DEBUG: " + srcUrl + " => " + destUrl
281
+ curl_command = CURL_COPY.sub("<!--destination-->", destUrl) + " " + srcUrl
282
+ response = exec_curl(curl_command)
283
+
284
+ if(response == "")then
285
+ return destUrl
286
+ end
287
+ return false
288
+ end
289
+
290
+
291
+ # Move resources
292
+ #
293
+ # Examples:
294
+ #
295
+ # WebDAV.mv("src.html","https://example.org/destination/destination.html"
296
+ def self.mv(src,dest)
297
+ srcUrl = absoluteUrl(src)
298
+ destUrl = absoluteUrl(dest)
299
+
300
+ # puts "DEBUG: " + srcUrl + " => " + destUrl
301
+ curl_command = CURL_MOVE.sub("<!--destination-->", destUrl) + " " + srcUrl
302
+ response = exec_curl(curl_command)
303
+
304
+ if(response == "")then
305
+ return destUrl
306
+ end
307
+ return false
308
+ end
309
+
310
+
311
+ # Delete resource
312
+ #
313
+ # Examples:
314
+ #
315
+ # WebDAV.cd("https://example.org/folder")
316
+ # WebDAV.mkcol("subfolder")
317
+ # WebDAV.delete("subfolder")
318
+ def self.delete(url)
319
+
320
+ url = absoluteUrl(url)
321
+
322
+ curl_command = CURL_DELETE + url
323
+ response = exec_curl(curl_command)
324
+
325
+ if(response == "")then
326
+ return url
327
+ end
328
+ if(not(response =~ /200 OK/)) then
329
+ puts "Error:\nRequest:\n" + curl_command + "\n\nResponse: " + response
330
+ return false
331
+ end
332
+ return url
333
+ end
334
+
335
+
336
+ # Low level WebDAV publish
337
+ #
338
+ # Example:
339
+ #
340
+ # WebDAV.publish("https://dav.example.org/index.html","<h1>Hello</h1>",nil)
341
+ def self.publish(url, string, props)
342
+ self.put_string(url, string)
343
+ if(props)then
344
+ self.proppatch(url,props)
345
+ end
346
+ end
347
+
348
+
349
+ # Puts content of string to file on server with url
350
+ #
351
+ # Example:
352
+ #
353
+ # WebDAV.put("https://dav.webdav.org/file.html", "<html><h1>Test</h1></html>"
354
+ def self.put_string(url, html)
355
+ url = absoluteUrl(url)
356
+
357
+ if(url =~ /\/$/)then
358
+ raise "Error: WebDAV.put_html: url can not be a collection (folder)."
359
+ end
360
+
361
+ tmp_dir = "/tmp/" + rand.to_s[2..10] + "/"
362
+ FileUtils.mkdir_p tmp_dir
363
+ tmp_file = tmp_dir + "webdav.tmp"
364
+ File.open(tmp_file, 'w') {|f| f.write(html) }
365
+
366
+ curl_command = "#{$curl} --netrc --silent --upload-file #{tmp_file} #{url}"
367
+ response = exec_curl(curl_command)
368
+ if(response != "" and not(response =~ /200 OK/)) then
369
+ raise "Error:\n WebDAV.put: WebDAV Request:\n" + curl_command + "\n\nResponse: " + response
370
+ end
371
+ end
372
+
373
+ # Returns a string with the webservers WebDAV options (PUT, PROPFIND, etc.)
374
+ def self.options(url)
375
+ if(not(url))
376
+ url = self.CWURL
377
+ end
378
+ return self.exec_curl(CURL_OPTIONS + url )
379
+ end
380
+
381
+ # :stopdoc:
382
+
383
+ # TODO put file utility
384
+ # TESTME
385
+ def put_file(filename, href)
386
+ # TODO Detect if href is a collection or not??
387
+ curl_command = "#{$curl} --netrc --request PUT #{filename} #{href}"
388
+ return exec_curl(curl_command)
389
+ # return execute_curl_cmd(curl_put_cmd)
390
+ end
391
+ # :startdoc:
392
+
393
+ private
394
+
395
+ # Returns filename /tmp/cwurl.#pid that holds the current working directory
396
+ # for the shell's pid
397
+ def self.cwurl_filename
398
+ tmp_file = Tempfile.new("dummy").path
399
+ basename = File.basename(tmp_file)
400
+ tmp_folder = tmp_file.gsub(basename, "")
401
+ return tmp_folder + "cwurl." + Process.ppid.to_s
402
+ end
403
+
404
+ # Display instructions for adding credentials to .netrc file
405
+ def self.display_unauthorized_message(href)
406
+ puts "Error: 401 Unauthorized: " + href
407
+ href.match(/^http.*\/\/([^\/]*)/)
408
+ puts "\nTry adding the following to your ~/.netrc file:"
409
+ puts ""
410
+ puts "machine #{$1}"
411
+ puts " login " + ENV['USER']
412
+ puts " password ********"
413
+ puts ""
414
+ end
415
+
416
+
417
+ # Run 'curl' as a subprocess
418
+ def self.exec_curl(curl_command)
419
+ response = ""
420
+
421
+ puts curl_command if($DEBUG)
422
+
423
+ Open3.popen3(curl_command) do |stdin, stdout, stderr|
424
+
425
+ response = stdout.readlines.join("")
426
+
427
+ if(response == "")
428
+ stderr = stderr.readlines.join("").sub(/^\W/,"")
429
+ if(stderr =~ /command/)
430
+ puts "Error: " + stderr
431
+ exit
432
+ end
433
+ if(stderr =~ /^curl:/)
434
+ puts "Error: " + stderr
435
+ puts
436
+ puts curl_command
437
+ puts
438
+ exit
439
+ end
440
+ end
441
+ end
442
+ if(response =~ /401 Unauthorized/)then
443
+ href = curl_command.match( /"(http[^\"]*)"$/ )[0].gsub(/"/,"")
444
+ self.display_unauthorized_message(href)
445
+ exit
446
+ end
447
+ return response
448
+ end
449
+
450
+
451
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: davclient
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Flemming
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-10 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0.6"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: zentest
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "3.5"
34
+ version:
35
+ description: WebDAV command line client written in Ruby for managing content on webservers that support the WebDAV extensions.
36
+ email: thomasfl@usit.uio.no
37
+ executables:
38
+ - dav
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.rdoc
43
+ files:
44
+ - lib/davclient.rb
45
+ - lib/davclient/hpricot_extensions.rb
46
+ - lib/davclient/curl_commands.rb
47
+ - bin/dav
48
+ - lib/davclient/davcli.rb
49
+ - lib/davclient/dav-put.rb
50
+ - lib/davclient/dav-ls.rb
51
+ - lib/davclient/dav-propfind.rb
52
+ - README.rdoc
53
+ has_rdoc: true
54
+ homepage: http://folk.uio.no/thomasfl
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements:
75
+ - cURL command line tool available from http://curl.haxx.se/
76
+ - Servername, username and password must be supplied in ~/.netrc file.
77
+ rubyforge_project: davclient
78
+ rubygems_version: 1.3.5
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Command line WebDAV client and Ruby library.
82
+ test_files: []
83
+