simple_dav 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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