tp-blather 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/.autotest +13 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +8 -0
  6. data/CHANGELOG.md +249 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +5 -0
  9. data/LICENSE +22 -0
  10. data/README.md +413 -0
  11. data/Rakefile +20 -0
  12. data/TODO.md +2 -0
  13. data/blather.gemspec +51 -0
  14. data/examples/certs/README +20 -0
  15. data/examples/certs/ca-bundle.crt +3987 -0
  16. data/examples/echo.rb +19 -0
  17. data/examples/execute.rb +17 -0
  18. data/examples/ping_pong.rb +38 -0
  19. data/examples/print_hierarchy.rb +77 -0
  20. data/examples/rosterprint.rb +15 -0
  21. data/examples/stream_only.rb +28 -0
  22. data/examples/trusted_echo.rb +21 -0
  23. data/examples/xmpp4r/echo.rb +36 -0
  24. data/lib/blather.rb +112 -0
  25. data/lib/blather/cert_store.rb +53 -0
  26. data/lib/blather/client.rb +95 -0
  27. data/lib/blather/client/client.rb +345 -0
  28. data/lib/blather/client/dsl.rb +320 -0
  29. data/lib/blather/client/dsl/pubsub.rb +174 -0
  30. data/lib/blather/core_ext/eventmachine.rb +125 -0
  31. data/lib/blather/core_ext/ipaddr.rb +20 -0
  32. data/lib/blather/errors.rb +69 -0
  33. data/lib/blather/errors/sasl_error.rb +44 -0
  34. data/lib/blather/errors/stanza_error.rb +110 -0
  35. data/lib/blather/errors/stream_error.rb +84 -0
  36. data/lib/blather/file_transfer.rb +107 -0
  37. data/lib/blather/file_transfer/ibb.rb +68 -0
  38. data/lib/blather/file_transfer/s5b.rb +114 -0
  39. data/lib/blather/jid.rb +141 -0
  40. data/lib/blather/roster.rb +118 -0
  41. data/lib/blather/roster_item.rb +146 -0
  42. data/lib/blather/stanza.rb +167 -0
  43. data/lib/blather/stanza/disco.rb +32 -0
  44. data/lib/blather/stanza/disco/capabilities.rb +161 -0
  45. data/lib/blather/stanza/disco/disco_info.rb +205 -0
  46. data/lib/blather/stanza/disco/disco_items.rb +134 -0
  47. data/lib/blather/stanza/iq.rb +144 -0
  48. data/lib/blather/stanza/iq/command.rb +339 -0
  49. data/lib/blather/stanza/iq/ibb.rb +86 -0
  50. data/lib/blather/stanza/iq/ping.rb +50 -0
  51. data/lib/blather/stanza/iq/query.rb +53 -0
  52. data/lib/blather/stanza/iq/roster.rb +185 -0
  53. data/lib/blather/stanza/iq/s5b.rb +208 -0
  54. data/lib/blather/stanza/iq/si.rb +415 -0
  55. data/lib/blather/stanza/iq/vcard.rb +149 -0
  56. data/lib/blather/stanza/message.rb +428 -0
  57. data/lib/blather/stanza/message/muc_user.rb +119 -0
  58. data/lib/blather/stanza/muc/muc_user_base.rb +54 -0
  59. data/lib/blather/stanza/presence.rb +172 -0
  60. data/lib/blather/stanza/presence/c.rb +100 -0
  61. data/lib/blather/stanza/presence/muc.rb +35 -0
  62. data/lib/blather/stanza/presence/muc_user.rb +147 -0
  63. data/lib/blather/stanza/presence/status.rb +218 -0
  64. data/lib/blather/stanza/presence/subscription.rb +100 -0
  65. data/lib/blather/stanza/pubsub.rb +119 -0
  66. data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
  67. data/lib/blather/stanza/pubsub/create.rb +65 -0
  68. data/lib/blather/stanza/pubsub/errors.rb +18 -0
  69. data/lib/blather/stanza/pubsub/event.rb +139 -0
  70. data/lib/blather/stanza/pubsub/items.rb +103 -0
  71. data/lib/blather/stanza/pubsub/publish.rb +103 -0
  72. data/lib/blather/stanza/pubsub/retract.rb +92 -0
  73. data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
  74. data/lib/blather/stanza/pubsub/subscription.rb +135 -0
  75. data/lib/blather/stanza/pubsub/subscriptions.rb +83 -0
  76. data/lib/blather/stanza/pubsub/unsubscribe.rb +84 -0
  77. data/lib/blather/stanza/pubsub_owner.rb +51 -0
  78. data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
  79. data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
  80. data/lib/blather/stanza/x.rb +416 -0
  81. data/lib/blather/stream.rb +266 -0
  82. data/lib/blather/stream/client.rb +32 -0
  83. data/lib/blather/stream/component.rb +39 -0
  84. data/lib/blather/stream/features.rb +70 -0
  85. data/lib/blather/stream/features/register.rb +38 -0
  86. data/lib/blather/stream/features/resource.rb +63 -0
  87. data/lib/blather/stream/features/sasl.rb +190 -0
  88. data/lib/blather/stream/features/session.rb +45 -0
  89. data/lib/blather/stream/features/tls.rb +29 -0
  90. data/lib/blather/stream/parser.rb +102 -0
  91. data/lib/blather/version.rb +3 -0
  92. data/lib/blather/xmpp_node.rb +94 -0
  93. data/spec/blather/client/client_spec.rb +687 -0
  94. data/spec/blather/client/dsl/pubsub_spec.rb +492 -0
  95. data/spec/blather/client/dsl_spec.rb +266 -0
  96. data/spec/blather/errors/sasl_error_spec.rb +33 -0
  97. data/spec/blather/errors/stanza_error_spec.rb +129 -0
  98. data/spec/blather/errors/stream_error_spec.rb +108 -0
  99. data/spec/blather/errors_spec.rb +33 -0
  100. data/spec/blather/file_transfer_spec.rb +135 -0
  101. data/spec/blather/jid_spec.rb +87 -0
  102. data/spec/blather/roster_item_spec.rb +134 -0
  103. data/spec/blather/roster_spec.rb +107 -0
  104. data/spec/blather/stanza/discos/disco_info_spec.rb +247 -0
  105. data/spec/blather/stanza/discos/disco_items_spec.rb +154 -0
  106. data/spec/blather/stanza/iq/command_spec.rb +206 -0
  107. data/spec/blather/stanza/iq/ibb_spec.rb +124 -0
  108. data/spec/blather/stanza/iq/ping_spec.rb +45 -0
  109. data/spec/blather/stanza/iq/query_spec.rb +64 -0
  110. data/spec/blather/stanza/iq/roster_spec.rb +139 -0
  111. data/spec/blather/stanza/iq/s5b_spec.rb +57 -0
  112. data/spec/blather/stanza/iq/si_spec.rb +98 -0
  113. data/spec/blather/stanza/iq/vcard_spec.rb +93 -0
  114. data/spec/blather/stanza/iq_spec.rb +61 -0
  115. data/spec/blather/stanza/message/muc_user_spec.rb +152 -0
  116. data/spec/blather/stanza/message_spec.rb +282 -0
  117. data/spec/blather/stanza/presence/c_spec.rb +56 -0
  118. data/spec/blather/stanza/presence/muc_spec.rb +37 -0
  119. data/spec/blather/stanza/presence/muc_user_spec.rb +83 -0
  120. data/spec/blather/stanza/presence/status_spec.rb +144 -0
  121. data/spec/blather/stanza/presence/subscription_spec.rb +102 -0
  122. data/spec/blather/stanza/presence_spec.rb +125 -0
  123. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  124. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  125. data/spec/blather/stanza/pubsub/event_spec.rb +98 -0
  126. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  127. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  128. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  129. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  130. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  131. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  132. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +74 -0
  133. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  134. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  135. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  136. data/spec/blather/stanza/pubsub_spec.rb +68 -0
  137. data/spec/blather/stanza/x_spec.rb +231 -0
  138. data/spec/blather/stanza_spec.rb +134 -0
  139. data/spec/blather/stream/client_spec.rb +1090 -0
  140. data/spec/blather/stream/component_spec.rb +108 -0
  141. data/spec/blather/stream/parser_spec.rb +152 -0
  142. data/spec/blather/stream/ssl_spec.rb +32 -0
  143. data/spec/blather/xmpp_node_spec.rb +47 -0
  144. data/spec/blather_spec.rb +34 -0
  145. data/spec/fixtures/pubsub.rb +311 -0
  146. data/spec/spec_helper.rb +17 -0
  147. data/yard/templates/default/class/html/handlers.erb +18 -0
  148. data/yard/templates/default/class/setup.rb +10 -0
  149. data/yard/templates/default/class/text/handlers.erb +1 -0
  150. metadata +459 -0
@@ -0,0 +1,415 @@
1
+ require 'time' # For Time#xmlschema
2
+
3
+ module Blather
4
+ class Stanza
5
+ class Iq
6
+
7
+ # # Si Stanza
8
+ #
9
+ # [XEP-0096: SI File Transfer](http://xmpp.org/extensions/xep-0096.html)
10
+ #
11
+ # This is a base class for any si based Iq stanzas. It provides a base set
12
+ # of methods for working with si stanzas
13
+ #
14
+ # @example Basic file transfer acceptance
15
+ # client.register_handler :file_transfer do |iq|
16
+ # transfer = Blather::FileTransfer.new(client, iq)
17
+ # transfer.accept(Blather::FileTransfer::SimpleFileReceiver, "/path/to/#{iq.si.file["name"]}", iq.si.file["size"].to_i)
18
+ # end
19
+ #
20
+ # @example Basic file transfer refusal
21
+ # client.register_handler :file_transfer do |iq|
22
+ # transfer = Blather::FileTransfer.new(client, iq)
23
+ # transfer.decline
24
+ # end
25
+ #
26
+ # @example File transfer acceptance by in-band bytestreams with custom handler
27
+ # client.register_handler :file_transfer do |iq|
28
+ # transfer = Blather::FileTransfer.new(client, iq)
29
+ # transfer.allow_ibb = true
30
+ # transfer.allow_s5b = false
31
+ # transfer.accept(MyFileReceiver, iq)
32
+ # end
33
+ #
34
+ # @handler :file_transfer
35
+ class Si < Iq
36
+ # @private
37
+ NS_SI = 'http://jabber.org/protocol/si'
38
+ register :file_transfer, :si, NS_SI
39
+
40
+ # Overrides the parent method to ensure a si node is created
41
+ #
42
+ # @see Blather::Stanza::Iq.new
43
+ def self.new(type = :set)
44
+ node = super
45
+ node.si
46
+ node
47
+ end
48
+
49
+ # Overrides the parent method to ensure the current si node is destroyed
50
+ #
51
+ # @see Blather::Stanza::Iq#inherit
52
+ def inherit(node)
53
+ si.remove
54
+ super
55
+ end
56
+
57
+ # Find or create si node
58
+ #
59
+ # @return [Si::Si]
60
+ def si
61
+ Si.find_or_create self
62
+ end
63
+
64
+ # Replaces si node
65
+ #
66
+ # @param [Si::Si, XML::Node] node the stanza's new si node
67
+ #
68
+ # @return [Si::Si]
69
+ def si=(node)
70
+ si.remove
71
+ self << node
72
+ Si.find_or_create self
73
+ end
74
+
75
+ # Overrides the parent method to ensure the current si node is destroyed
76
+ #
77
+ # @see Blather::Stanza#reply
78
+ def reply
79
+ reply = Stanza::Iq::Si.import super
80
+ reply.si.remove
81
+ reply
82
+ end
83
+
84
+ # Si stanza fragment
85
+ class Si < XMPPNode
86
+ # Create a new Si::Si object
87
+ #
88
+ # @param [XML::Node, nil] node a node to inherit from
89
+ #
90
+ # @return [Si::Si]
91
+ def self.new(node = nil)
92
+ new_node = super :si
93
+ new_node.namespace = NS_SI
94
+ new_node.inherit node if node
95
+ new_node
96
+ end
97
+
98
+ # Find or create si node in Si Iq and converts it to Si::Si
99
+ #
100
+ # @param [Si] parent a Si Iq where to find or create si
101
+ #
102
+ # @return [Si::Si]
103
+ def self.find_or_create(parent)
104
+ if found_si = parent.find_first('//ns:si', :ns => NS_SI)
105
+ si = self.new found_si
106
+ found_si.remove
107
+ else
108
+ si = self.new
109
+ end
110
+ parent << si
111
+
112
+ si
113
+ end
114
+
115
+ # Get the id of the stream
116
+ #
117
+ # @return [String, nil]
118
+ def id
119
+ read_attr :id
120
+ end
121
+
122
+ # Set the id
123
+ #
124
+ # @param [String, nil] id the id of the stream
125
+ def id=(id)
126
+ write_attr :id, id
127
+ end
128
+
129
+ # Get the MIME type of the stream
130
+ #
131
+ # @return [String, nil]
132
+ def mime_type
133
+ read_attr 'mime-type'
134
+ end
135
+
136
+ # Set the MIME type
137
+ #
138
+ # @param [String, nil] type the MIME type of the stream
139
+ def mime_type=(type)
140
+ write_attr 'mime-type', type
141
+ end
142
+
143
+ # Get the profile of the stream
144
+ #
145
+ # @return [String, nil]
146
+ def profile
147
+ read_attr :profile
148
+ end
149
+
150
+ # Set the profile
151
+ #
152
+ # @param [String, nil] profile the profile of the stream
153
+ def profile=(profile)
154
+ write_attr :profile, profile
155
+ end
156
+
157
+ # Find or create file node
158
+ #
159
+ # @return [Si::Si::File]
160
+ def file
161
+ File.find_or_create self
162
+ end
163
+
164
+ # Find or create feature node
165
+ #
166
+ # @return [Si::Si::Feature]
167
+ def feature
168
+ Feature.find_or_create self
169
+ end
170
+
171
+ # Feature stanza fragment
172
+ class Feature < XMPPNode
173
+ register :feature, 'http://jabber.org/protocol/feature-neg'
174
+
175
+ # Create a new Si::Si::Feature object
176
+ #
177
+ # @param [XML::Node, nil] node a node to inherit from
178
+ #
179
+ # @return [Si::Si::Feature]
180
+ def self.new(node = nil)
181
+ new_node = super :feature
182
+ new_node.namespace = self.registered_ns
183
+ new_node.inherit node if node
184
+ new_node
185
+ end
186
+
187
+ # Find or create feature node in si node and converts it to Si::Si::Feature
188
+ #
189
+ # @param [Si::Si] parent a si node where to find or create feature
190
+ #
191
+ # @return [Si::Si::Feature]
192
+ def self.find_or_create(parent)
193
+ if found_feature = parent.find_first('//ns:feature', :ns => self.registered_ns)
194
+ feature = self.new found_feature
195
+ found_feature.remove
196
+ else
197
+ feature = self.new
198
+ end
199
+ parent << feature
200
+
201
+ feature
202
+ end
203
+
204
+ # Find or create x node
205
+ #
206
+ # @return [Stanza::X]
207
+ def x
208
+ Stanza::X.find_or_create self
209
+ end
210
+ end
211
+
212
+ # File stanza fragment
213
+ class File < XMPPNode
214
+ register :file, 'http://jabber.org/protocol/si/profile/file-transfer'
215
+
216
+ # Create a new Si::Si::File object
217
+ #
218
+ # @param [XML::Node, nil] node a node to inherit from
219
+ #
220
+ # @return [Si::Si::File]
221
+ def self.new(name = nil, size = nil)
222
+ new_node = super :file
223
+
224
+ case name
225
+ when Nokogiri::XML::Node
226
+ new_node.inherit name
227
+ else
228
+ new_node.name = name
229
+ new_node.size = size
230
+ end
231
+ new_node
232
+ end
233
+
234
+ # Find or create file node in si node and converts it to Si::Si::File
235
+ #
236
+ # @param [Si::Si] parent a si node where to find or create file
237
+ #
238
+ # @return [Si::Si::File]
239
+ def self.find_or_create(parent)
240
+ if found_file = parent.find_first('//ns:file', :ns => self.registered_ns)
241
+ file = self.new found_file
242
+ found_file.remove
243
+ else
244
+ file = self.new
245
+ end
246
+ parent << file
247
+
248
+ file
249
+ end
250
+
251
+ # Get the filename
252
+ #
253
+ # @return [String, nil]
254
+ def name
255
+ read_attr :name
256
+ end
257
+
258
+ # Set the filename
259
+ #
260
+ # @param [String, nil] name the name of the file
261
+ def name=(name)
262
+ write_attr :name, name
263
+ end
264
+
265
+ # Get the hash
266
+ #
267
+ # @return [String, nil]
268
+ def hash
269
+ read_attr :hash
270
+ end
271
+
272
+ # Set the hash
273
+ #
274
+ # @param [String, nil] hash the MD5 hash of the file
275
+ def hash=(hash)
276
+ write_attr :hash, hash
277
+ end
278
+
279
+ # Get the date
280
+ #
281
+ # @return [Time, nil]
282
+ def date
283
+ begin
284
+ Time.xmlschema(read_attr(:date))
285
+ rescue ArgumentError
286
+ nil
287
+ end
288
+ end
289
+
290
+ # Set the date
291
+ #
292
+ # @param [Time, nil] date the last modification time of the file
293
+ def date=(date)
294
+ write_attr :date, (date ? date.xmlschema : nil)
295
+ end
296
+
297
+ # Get the size
298
+ #
299
+ # @return [Fixnum, nil]
300
+ def size
301
+ if (s = read_attr(:size)) && (s =~ /^\d+$/)
302
+ s.to_i
303
+ else
304
+ nil
305
+ end
306
+ end
307
+
308
+ # Set the size
309
+ #
310
+ # @param [Fixnum, nil] size the size, in bytes, of the file
311
+ def size=(size)
312
+ write_attr :size, size
313
+ end
314
+
315
+ # Get the desc
316
+ #
317
+ # @return [String, nil]
318
+ def desc
319
+ content_from 'ns:desc', :ns => self.class.registered_ns
320
+ end
321
+
322
+ # Set the desc
323
+ #
324
+ # @param [String, nil] desc the description of the file
325
+ def desc=(desc)
326
+ set_content_for :desc, desc
327
+ end
328
+
329
+ # Find or create range node
330
+ #
331
+ # @return [Si::Si::File::Range]
332
+ def range
333
+ Range.find_or_create self
334
+ end
335
+ end
336
+
337
+ # Range stanza fragment
338
+ class Range < XMPPNode
339
+ register :range, 'http://jabber.org/protocol/si/profile/file-transfer'
340
+
341
+ # Create a new Si::Si::File::Range object
342
+ #
343
+ # @param [XML::Node, nil] node a node to inherit from
344
+ #
345
+ # @return [Si::Si::File::Range]
346
+ def self.new(offset = nil, length = nil)
347
+ new_node = super :range
348
+
349
+ case offset
350
+ when Nokogiri::XML::Node
351
+ new_node.inherit offset
352
+ else
353
+ new_node.offset = offset
354
+ new_node.length = length
355
+ end
356
+ new_node
357
+ end
358
+ # Find or create range node in file node and converts it to Si::Si::File::Range
359
+ #
360
+ # @param [Si::Si::File] parent a file node where to find or create range
361
+ #
362
+ # @return [Si::Si::File::Range]
363
+ def self.find_or_create(parent)
364
+ if found_range = parent.find_first('//ns:range', :ns => self.registered_ns)
365
+ range = self.new found_range
366
+ found_range.remove
367
+ else
368
+ range = self.new
369
+ end
370
+ parent << range
371
+
372
+ range
373
+ end
374
+
375
+ # Get the offset
376
+ #
377
+ # @return [Fixnum, nil]
378
+ def offset
379
+ if (o = read_attr(:offset)) && (o =~ /^\d+$/)
380
+ o.to_i
381
+ else
382
+ nil
383
+ end
384
+ end
385
+
386
+ # Set the offset
387
+ #
388
+ # @param [Fixnum, nil] offset the position, in bytes, to start transferring the file data from
389
+ def offset=(offset)
390
+ write_attr :offset, offset
391
+ end
392
+
393
+ # Get the length
394
+ #
395
+ # @return [Fixnum, nil]
396
+ def length
397
+ if (l = read_attr(:length)) && (l =~ /^\d+$/)
398
+ l.to_i
399
+ else
400
+ nil
401
+ end
402
+ end
403
+
404
+ # Set the length
405
+ #
406
+ # @param [Fixnum, nil] length the number of bytes to retrieve starting at offset
407
+ def length=(length)
408
+ write_attr :length, length
409
+ end
410
+ end
411
+ end
412
+ end
413
+ end
414
+ end
415
+ end
@@ -0,0 +1,149 @@
1
+ module Blather
2
+ class Stanza
3
+ class Iq
4
+
5
+ # # Vcard Stanza
6
+ #
7
+ # [XEP-0054 vcard-temp](http://xmpp.org/extensions/xep-0054.html)
8
+ #
9
+ # This is a base class for any vcard based Iq stanzas. It provides a base set
10
+ # of methods for working with vcard stanzas
11
+ #
12
+ # @example Retrieving One's vCard
13
+ # iq = Blather::Stanza::Iq::Vcard.new :get
14
+ # client.write_with_handler iq do |response|
15
+ # puts response.vcard
16
+ # end
17
+ #
18
+ # @example Updating One's vCard
19
+ # iq = Blather::Stanza::Iq::Vcard.new :set
20
+ # iq.vcard['NICKNAME'] = 'Romeo'
21
+ # client.write_with_handler iq do |response|
22
+ # puts response
23
+ # end
24
+ #
25
+ # @example Viewing Another User's vCard
26
+ # iq = Blather::Stanza::Iq::Vcard.new :get, 'mercutio@example.org'
27
+ # client.write_with_handler iq do |response|
28
+ # puts response.vcard
29
+ # end
30
+ #
31
+ # @handler :vcard
32
+ class Vcard < Iq
33
+
34
+ register :vcard, :vCard, 'vcard-temp'
35
+
36
+ # Overrides the parent method to ensure a vcard node is created
37
+ #
38
+ # @see Blather::Stanza::Iq.new
39
+ def self.new(type = nil, to = nil, id = nil)
40
+ node = super
41
+ node.vcard
42
+ node
43
+ end
44
+
45
+ # Overrides the parent method to ensure the current vcard node is destroyed
46
+ #
47
+ # @see Blather::Stanza::Iq#inherit
48
+ def inherit(node)
49
+ vcard.remove
50
+ super
51
+ self
52
+ end
53
+
54
+ # Find or create vcard node
55
+ #
56
+ # @return [Vcard::Vcard]
57
+ def vcard
58
+ Vcard.find_or_create self
59
+ end
60
+
61
+ # Replaces vcard node
62
+ #
63
+ # @param [Vcard::Vcard, XML::Node] info the stanza's new vcard node
64
+ #
65
+ # @return [Vcard::Vcard]
66
+ def vcard=(info)
67
+ vcard.remove
68
+ self << info
69
+ Vcard.find_or_create self
70
+ end
71
+
72
+ # Vcard stanza fragment
73
+ class Vcard < XMPPNode
74
+
75
+ # @private
76
+ VCARD_NS = 'vcard-temp'
77
+
78
+ # Create a new Vcard::Vcard object
79
+ #
80
+ # @param [XML::Node, nil] node a node to inherit from
81
+ #
82
+ # @return [Vcard::Vcard]
83
+ def self.new(node = nil)
84
+ new_node = super :vCard
85
+ new_node.namespace = VCARD_NS
86
+ new_node.inherit node if node
87
+ new_node
88
+ end
89
+
90
+ # Find or create vCard node in Vcard Iq and converts it to Vcard::Vcard
91
+ #
92
+ # @param [Vcard] parent a Vcard Iq where to find or create vCard
93
+ #
94
+ # @return [Vcard::Vcard]
95
+ def self.find_or_create(parent)
96
+ if found_vcard = parent.find_first('//ns:vCard', :ns => VCARD_NS)
97
+ vcard = self.new found_vcard
98
+ found_vcard.remove
99
+ else
100
+ vcard = self.new
101
+ end
102
+ parent << vcard
103
+
104
+ vcard
105
+ end
106
+
107
+ # Find the element's value by name
108
+ #
109
+ # @param [String] name the name of the element
110
+ #
111
+ # @return [String, nil]
112
+ def [](name)
113
+ name = name.split("/").map{|child| "ns:#{child}"}.join("/")
114
+
115
+ if elem = find_first(name, :ns => VCARD_NS)
116
+ elem.content
117
+ else
118
+ nil
119
+ end
120
+ end
121
+
122
+ # Set the element's value
123
+ #
124
+ # @param [String] name the name of the element
125
+ # @param [String, nil] value the new value of element
126
+ #
127
+ # @return [String, nil]
128
+ def []=(name, value)
129
+ elem = nil
130
+ parent = self
131
+
132
+ name.split("/").each do |child|
133
+ elem = parent.find_first("ns:#{child}", :ns => VCARD_NS)
134
+ unless elem
135
+ elem = XMPPNode.new(child, parent.document)
136
+ parent << elem
137
+ parent = elem
138
+ else
139
+ parent = elem
140
+ end
141
+ end
142
+
143
+ elem.content = value
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end