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.
Files changed (2) hide show
  1. data/lib/simple_dav.rb +4 -359
  2. 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
- BASEVCF = <<EOF
14
- BEGIN:VCARD
15
- PRODID:-//IDFuze//SimpleDav//EN
16
- VERSION:3.0
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
- - 4
9
- version: 0.0.4
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-05 00:00:00 +02:00
17
+ date: 2012-10-15 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency