simple_dav 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/simple_dav.rb +4 -359
- metadata +3 -3
data/lib/simple_dav.rb
CHANGED
@@ -10,362 +10,7 @@ require 'httpclient'
|
|
10
10
|
require 'nokogiri'
|
11
11
|
require 'logger'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
CLASS:PUBLIC
|
18
|
-
PROFILE:VCARD
|
19
|
-
END:VCARD
|
20
|
-
EOF
|
21
|
-
|
22
|
-
GROUPVCF = BASEVCF
|
23
|
-
|
24
|
-
class SimpleDav
|
25
|
-
attr_reader :headers, :uri, :client
|
26
|
-
|
27
|
-
# generate unique id to create resources
|
28
|
-
def gen_uid
|
29
|
-
"#{rand(100000)}-#{Time.now.to_i}-#{rand(100000)}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize(params = {})
|
33
|
-
begin
|
34
|
-
url = params[:ssl] ? "https://#{params[:server]}/" : "http://#{params[:server]}/"
|
35
|
-
url += case (@type = params[:type])
|
36
|
-
when "sogo" then "SOGo/dav/#{params[:user]}/"
|
37
|
-
else ""
|
38
|
-
end
|
39
|
-
@uri = URI.parse(url)
|
40
|
-
@uid = nil
|
41
|
-
@headers = {}
|
42
|
-
#open(uri) if uri
|
43
|
-
proxy = ENV['HTTP_PROXY'] || ENV['http_proxy'] || nil
|
44
|
-
@client = HTTPClient.new(proxy)
|
45
|
-
@client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE unless params[:verify]
|
46
|
-
if (@user = params[:user]) && params[:pass]
|
47
|
-
@client.set_basic_auth(@uri, @user, params[:pass])
|
48
|
-
end
|
49
|
-
rescue
|
50
|
-
raise RuntimeError.exception("Init Failed!! (#{$!.to_s})")
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
class AddressBook < SimpleDav
|
57
|
-
attr_reader :group
|
58
|
-
def initialize(params)
|
59
|
-
abu = "personal"
|
60
|
-
@vcard = nil
|
61
|
-
super(params)
|
62
|
-
@abu = @type == "sogo" ? "Contacts/#{abu}/" : "#{abu}"
|
63
|
-
@uri.path += @abu
|
64
|
-
@group = nil #store group uid
|
65
|
-
Card.adb = self
|
66
|
-
end
|
67
|
-
|
68
|
-
# select address book
|
69
|
-
def change_group(abu)
|
70
|
-
#todo select uid or nil if personnal
|
71
|
-
# old style folders
|
72
|
-
#@uri.path -= @abu
|
73
|
-
#@uri.path += (@abu = abu)
|
74
|
-
# new style v4 group
|
75
|
-
groups = Card.where({"X-ADDRESSBOOKSERVER-KIND" => "group", "f" => abu})
|
76
|
-
@group = groups && groups.first && groups.first.uid
|
77
|
-
end
|
78
|
-
|
79
|
-
# list available address books
|
80
|
-
#find all X-ADDRESSBOOKSERVER-KIND
|
81
|
-
def list
|
82
|
-
Card.where("X-ADDRESSBOOKSERVER-KIND" => "group")
|
83
|
-
end
|
84
|
-
|
85
|
-
# find addresse resource by uid
|
86
|
-
def self.find(uid)
|
87
|
-
Card.find(self, uid)
|
88
|
-
end
|
89
|
-
|
90
|
-
# create collection : not working actually
|
91
|
-
def create_folder(name, displayname = "", description = "")
|
92
|
-
query = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
|
93
|
-
xml.send('D:mkcol', 'xmlns:D' => "DAV:", 'xmlns:C' => "urn:ietf:params:xml:ns:carddav") do
|
94
|
-
xml.send('D:set') do
|
95
|
-
xml.send('D:prop')
|
96
|
-
xml.send('D:resourcetype') do
|
97
|
-
xml.send('D:collection')
|
98
|
-
xml.send('C:addressbook')
|
99
|
-
end
|
100
|
-
end
|
101
|
-
xml.send('D:displayname') do
|
102
|
-
xml << displayname
|
103
|
-
end
|
104
|
-
xml.send('C:addressbook-description', 'xml:lang' => "en") do
|
105
|
-
xml << description
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
headers = {
|
111
|
-
"content-Type" => "text/xml; charset=\"utf-8\"",
|
112
|
-
"Content-Length" => query.to_xml.to_s.size
|
113
|
-
}
|
114
|
-
|
115
|
-
res = @client.request('MKCOL', @uri, nil, query.to_xml.to_s, headers)
|
116
|
-
|
117
|
-
if res.status < 200 or res.status >= 300
|
118
|
-
raise "create failed: #{res.inspect}"
|
119
|
-
else
|
120
|
-
true
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# create address book group
|
125
|
-
def create(name, description = "")
|
126
|
-
uid = "#{gen_uid}"
|
127
|
-
|
128
|
-
@vcard = Card.new(GROUPVCF)
|
129
|
-
@vcard.add_attribute("X-ADDRESSBOOKSERVER-KIND", "group")
|
130
|
-
@vcard.add_attribute("rev", Time.now.utc.iso8601(2))
|
131
|
-
@vcard.add_attribute("uid", uid)
|
132
|
-
@vcard.add_attribute(:f, name)
|
133
|
-
@vcard.add_attribute(:fn, description)
|
134
|
-
|
135
|
-
headers = {
|
136
|
-
"If-None-Match" => "*",
|
137
|
-
"Content-Type" => "text/vcard",
|
138
|
-
"Content-Length" => @vcard.to_s.size
|
139
|
-
}
|
140
|
-
|
141
|
-
unc = @uri.clone
|
142
|
-
unc.path += "#{uid}.vcf"
|
143
|
-
res = @client.request('PUT', unc, nil, @vcard.to_s, headers)
|
144
|
-
|
145
|
-
if res.status < 200 or res.status >= 300
|
146
|
-
@uid = nil
|
147
|
-
raise "create failed: #{res.inspect}"
|
148
|
-
else
|
149
|
-
@uid = @group = uid
|
150
|
-
end
|
151
|
-
@vcard
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
# access to current vcard object
|
156
|
-
def vcard
|
157
|
-
@vcard
|
158
|
-
end
|
159
|
-
|
160
|
-
def debug_dev=(dev)
|
161
|
-
@client.debug_dev = dev
|
162
|
-
end
|
163
|
-
|
164
|
-
end
|
165
|
-
|
166
|
-
# attributes : n|email|title|nickname|tel|bday|fn|org|note|uid
|
167
|
-
# todo change for another vcard managment class
|
168
|
-
class Card
|
169
|
-
class << self; attr_accessor :adb end
|
170
|
-
@adb = nil
|
171
|
-
|
172
|
-
def initialize(text = BASEVCF)
|
173
|
-
@plain = text
|
174
|
-
return self
|
175
|
-
end
|
176
|
-
|
177
|
-
def self.find(uid)
|
178
|
-
where(:uid => uid)
|
179
|
-
end
|
180
|
-
|
181
|
-
# create address resource
|
182
|
-
def self.create(params)
|
183
|
-
@vcard = Card.new
|
184
|
-
params.each do |k,v|
|
185
|
-
@vcard.update_attribute(k,v)
|
186
|
-
end
|
187
|
-
|
188
|
-
headers = {
|
189
|
-
"If-None-Match" => "*",
|
190
|
-
"Content-Type" => "text/vcard",
|
191
|
-
"Content-Length" => @vcard.to_s.size
|
192
|
-
}
|
193
|
-
uid = "#{adb.gen_uid}.vcf"
|
194
|
-
|
195
|
-
@vcard.update_attribute(:uid, uid)
|
196
|
-
if adb && adb.group
|
197
|
-
@vcard.add_attribute("X-ADDRESSBOOKSERVER-MEMBER", "urn:uuid:#{adb.group}")
|
198
|
-
end
|
199
|
-
|
200
|
-
unc = adb.uri.clone
|
201
|
-
unc.path += uid
|
202
|
-
res = adb.client.request('PUT', unc, nil, @vcard.to_s, headers)
|
203
|
-
|
204
|
-
if res.status < 200 or res.status >= 300
|
205
|
-
@uid = nil
|
206
|
-
raise "create failed: #{res.inspect}"
|
207
|
-
else
|
208
|
-
@uid = uid
|
209
|
-
end
|
210
|
-
@vcard
|
211
|
-
end
|
212
|
-
|
213
|
-
def update(params)
|
214
|
-
params.each do |k,v|
|
215
|
-
update_attribute(k,v)
|
216
|
-
end
|
217
|
-
|
218
|
-
headers = {
|
219
|
-
"Content-Type" => "text/vcard",
|
220
|
-
"Content-Length" => @plain.size
|
221
|
-
}
|
222
|
-
uid = self.uid
|
223
|
-
|
224
|
-
unc = Card.adb.uri.clone
|
225
|
-
unc.path += uid
|
226
|
-
res = Card.adb.client.request('PUT', unc, nil, @plain, headers)
|
227
|
-
|
228
|
-
if res.status < 200 or res.status >= 300
|
229
|
-
@uid = nil
|
230
|
-
raise "create failed: #{res.inspect}"
|
231
|
-
else
|
232
|
-
@uid = uid
|
233
|
-
end
|
234
|
-
self
|
235
|
-
end
|
236
|
-
|
237
|
-
def delete
|
238
|
-
if @uid && Card.adb
|
239
|
-
|
240
|
-
headers = {
|
241
|
-
#"If-None-Match" => "*",
|
242
|
-
"Content-Type" => "text/xml; charset=\"utf-8\""
|
243
|
-
}
|
244
|
-
unc = adb.uri.clone
|
245
|
-
unc.path += @uid
|
246
|
-
res = adb.client.request('DELETE', unc, nil, nil, headers)
|
247
|
-
|
248
|
-
if res.status < 200 or res.status >= 300
|
249
|
-
@uid = nil
|
250
|
-
raise "delete failed: #{res.inspect}"
|
251
|
-
else
|
252
|
-
@uid = nil
|
253
|
-
true
|
254
|
-
end
|
255
|
-
else
|
256
|
-
raise "Failed : no connection or null id"
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def retreive
|
261
|
-
path = "#{self.uid}.vcf"
|
262
|
-
unc = adb.uri.clone
|
263
|
-
unc.path += path
|
264
|
-
res = adb.client.request('GET', unc)
|
265
|
-
|
266
|
-
if res.status < 200 or res.status >= 300
|
267
|
-
@uid = nil
|
268
|
-
raise "delete failed: #{res.inspect}"
|
269
|
-
else
|
270
|
-
puts res.body
|
271
|
-
@plain = res.body
|
272
|
-
@uid = uid
|
273
|
-
true
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
def update_attribute(a, v)
|
278
|
-
@plain.match(/^#{a.to_s.upcase}:(.+)$/) ? @plain.gsub!(/^#{a.to_s.upcase}:(.+)$/, "#{a.to_s.upcase}:#{v}") : add_attribute(a, v)
|
279
|
-
end
|
280
|
-
|
281
|
-
def add_attribute(a, v)
|
282
|
-
@plain["END:VCARD"] = "#{a.to_s.upcase}:#{v}\nEND:VCARD"
|
283
|
-
end
|
284
|
-
|
285
|
-
def method_missing(meth, *args, &block)
|
286
|
-
case meth.to_s
|
287
|
-
when /^((n|email|title|nickname|tel|bday|fn|org|note|uid|X-ADDRESSBOOKSERVER-KIND)=?)$/
|
288
|
-
run_on_field($1, *args, &block)
|
289
|
-
when /^find_by_(.+)$/
|
290
|
-
run_find_by_method($1, *args, &block)
|
291
|
-
else
|
292
|
-
super
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
def run_on_field(attrs, *args, &block)
|
297
|
-
field = attrs.upcase
|
298
|
-
field["EMAIL"] = "EMAIL;TYPE=work" if field.match("EMAIL")
|
299
|
-
|
300
|
-
if field =~ /=/
|
301
|
-
field = field[0..-2]
|
302
|
-
update_attribute(field, args)
|
303
|
-
else
|
304
|
-
if m = @plain.match(/#{field}:(.+)$/)
|
305
|
-
m[1]
|
306
|
-
else
|
307
|
-
nil
|
308
|
-
end
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
# find where RoR style
|
313
|
-
def self.where(conditions)
|
314
|
-
limit = 1
|
315
|
-
query = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
|
316
|
-
xml.send('B:addressbook-query', 'xmlns:B' => "urn:ietf:params:xml:ns:carddav") do
|
317
|
-
xml.send('A:prop', 'xmlns:A' => "DAV:",) do
|
318
|
-
xml.send('A:getetag')
|
319
|
-
xml.send('B:address-data')
|
320
|
-
|
321
|
-
end
|
322
|
-
#xml.send('C:filter', 'test' => "anyof") do
|
323
|
-
xml.send('B:filter', 'test' => 'anyof') do
|
324
|
-
conditions.each do |k,v|
|
325
|
-
xml.send('B:prop-filter', 'test' => 'allof','name' => k.to_s) do
|
326
|
-
#xml.send('C:text-match', 'collation' => "i;unicode-casemap", 'match-type' => "contains") do
|
327
|
-
xml.send('B:text-match', 'collation' => "i;unicode-casemap", 'match-type' => "contains") do
|
328
|
-
xml << v
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|
332
|
-
end
|
333
|
-
if limit
|
334
|
-
xml.send('C:limit') do
|
335
|
-
xml.send('C:nresults') do
|
336
|
-
xml << "#{limit}"
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
end
|
342
|
-
|
343
|
-
end
|
344
|
-
headers = {
|
345
|
-
"content-Type" => "text/xml; charset=\"utf-8\"",
|
346
|
-
"depth" => 1,
|
347
|
-
"Content-Length" => "#{query.to_xml.to_s.size}"
|
348
|
-
}
|
349
|
-
puts ">>>> #{adb.uri}\n"
|
350
|
-
content = adb.client.request('REPORT', adb.uri, nil, query.to_xml.to_s, headers)
|
351
|
-
puts "#{content.body}\n\n#{query.to_xml}\n\n"
|
352
|
-
xml = Nokogiri::XML(content.body)
|
353
|
-
vcards = []
|
354
|
-
xml.xpath('//C:address-data').each do |card|
|
355
|
-
vcards << Card.new(card.text)
|
356
|
-
end
|
357
|
-
return vcards
|
358
|
-
end
|
359
|
-
|
360
|
-
def run_find_by_method(attrs, *args, &block)
|
361
|
-
attrs = attrs.split('_and_')
|
362
|
-
attrs_with_args = [attrs, args].transpose
|
363
|
-
conditions = Hash[attrs_with_args]
|
364
|
-
where(conditions)
|
365
|
-
end
|
366
|
-
|
367
|
-
def to_s
|
368
|
-
@plain.to_s
|
369
|
-
end
|
370
|
-
|
371
|
-
end
|
13
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
14
|
+
require 'simple_dav/base'
|
15
|
+
require 'simple_dav/address_book'
|
16
|
+
require 'simple_dav/card'
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 5
|
9
|
+
version: 0.0.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Olivier DIRRENBERGER
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-10-
|
17
|
+
date: 2012-10-15 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|