blather 0.4.16 → 0.5.0

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 (62) hide show
  1. data/.gemtest +0 -0
  2. data/CHANGELOG +12 -5
  3. data/README.md +1 -1
  4. data/Rakefile +1 -3
  5. data/blather.gemspec +11 -24
  6. data/examples/echo.rb +1 -0
  7. data/examples/execute.rb +1 -0
  8. data/examples/ping_pong.rb +1 -0
  9. data/examples/print_hierarchy.rb +1 -0
  10. data/examples/rosterprint.rb +1 -0
  11. data/examples/stream_only.rb +1 -0
  12. data/examples/xmpp4r/echo.rb +1 -0
  13. data/lib/blather.rb +5 -1
  14. data/lib/blather/client/client.rb +29 -154
  15. data/lib/blather/client/dsl.rb +9 -3
  16. data/lib/blather/client/dsl/pubsub.rb +2 -0
  17. data/lib/blather/core_ext/eventmachine.rb +4 -1
  18. data/lib/blather/core_ext/ipaddr.rb +2 -1
  19. data/lib/blather/core_ext/nokogiri.rb +3 -1
  20. data/lib/blather/errors/sasl_error.rb +1 -0
  21. data/lib/blather/errors/stanza_error.rb +3 -1
  22. data/lib/blather/errors/stream_error.rb +1 -0
  23. data/lib/blather/file_transfer.rb +4 -1
  24. data/lib/blather/file_transfer/s5b.rb +3 -4
  25. data/lib/blather/jid.rb +2 -0
  26. data/lib/blather/roster_item.rb +13 -3
  27. data/lib/blather/stanza.rb +11 -3
  28. data/lib/blather/stanza/disco/capabilities.rb +161 -0
  29. data/lib/blather/stanza/disco/disco_info.rb +3 -1
  30. data/lib/blather/stanza/disco/disco_items.rb +0 -1
  31. data/lib/blather/stanza/iq.rb +8 -2
  32. data/lib/blather/stanza/iq/command.rb +18 -3
  33. data/lib/blather/stanza/iq/ibb.rb +6 -3
  34. data/lib/blather/stanza/iq/s5b.rb +6 -3
  35. data/lib/blather/stanza/iq/si.rb +6 -1
  36. data/lib/blather/stanza/iq/vcard.rb +3 -1
  37. data/lib/blather/stanza/message.rb +5 -0
  38. data/lib/blather/stanza/presence.rb +1 -0
  39. data/lib/blather/stanza/presence/c.rb +1 -0
  40. data/lib/blather/stanza/presence/status.rb +1 -0
  41. data/lib/blather/stanza/pubsub/event.rb +2 -4
  42. data/lib/blather/stanza/pubsub/subscription.rb +1 -0
  43. data/lib/blather/stanza/x.rb +8 -0
  44. data/lib/blather/stream.rb +2 -0
  45. data/lib/blather/stream/client.rb +1 -0
  46. data/lib/blather/stream/component.rb +1 -0
  47. data/lib/blather/stream/features.rb +4 -3
  48. data/lib/blather/stream/features/resource.rb +4 -3
  49. data/lib/blather/stream/features/sasl.rb +9 -6
  50. data/lib/blather/stream/features/session.rb +5 -4
  51. data/lib/blather/stream/features/tls.rb +4 -3
  52. data/lib/blather/stream/parser.rb +4 -5
  53. data/lib/blather/version.rb +2 -1
  54. data/lib/blather/xmpp_node.rb +9 -0
  55. data/spec/blather/client/client_spec.rb +14 -1
  56. data/spec/blather/stanza/iq_spec.rb +16 -0
  57. data/spec/blather/stanza/presence_spec.rb +1 -1
  58. data/spec/blather/stanza_spec.rb +18 -0
  59. data/spec/blather/stream/client_spec.rb +2 -2
  60. metadata +52 -35
  61. data/lib/blather/core_ext/active_support.rb +0 -45
  62. data/lib/blather/core_ext/active_support/inheritable_attributes.rb +0 -117
data/.gemtest ADDED
File without changes
data/CHANGELOG CHANGED
@@ -1,9 +1,16 @@
1
+ v0.5.0
2
+ Feature(radsaq): Add a #connected? method on Blather::Client
3
+ Feature(benlangfeld)[API change]: Allow the removal of child nodes from an IQ reply
4
+ Bugfix(zlu): Use rubygems properly in examples
5
+ Bugfix(benlangfeld): Remove code borrowed from ActiveSupport and instead depend on it to avoid version conflicts
6
+ Documentation(sprsquish)
7
+
1
8
  v0.4.16
2
- Feature(benlangfeld): switch from jeweler to bundler
3
- Feature(benlangfeld): add cap support (XEP-0115)
4
- Bugfix(sprsquish): Better equality checking
5
- Bugfix(sprsquish): Fix #to_proc
6
- Bugfix(mironov): Skip private IPs by default
9
+ Feature(benlangfeld): switch from jeweler to bundler
10
+ Feature(benlangfeld): add cap support (XEP-0115)
11
+ Bugfix(sprsquish): Better equality checking
12
+ Bugfix(sprsquish): Fix #to_proc
13
+ Bugfix(mironov): Skip private IPs by default
7
14
 
8
15
  v0.4.15
9
16
  Feature(mironov): Implement XEP-0054: vcard-temp
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Blather
1
+ # Blather [ ![Build status](http://travis-ci.org/sprsquish/blather.png) ](http://travis-ci.org/sprsquish/blather)
2
2
 
3
3
  XMPP DSL (and more) for Ruby written on EventMachine and Nokogiri.
4
4
 
data/Rakefile CHANGED
@@ -23,10 +23,8 @@ require 'yard'
23
23
  YARD::Tags::Library.define_tag 'Blather handler', :handler, :with_name
24
24
  YARD::Templates::Engine.register_template_path 'yard/templates'
25
25
 
26
- YARD::Rake::YardocTask.new do |t|
26
+ YARD::Rake::YardocTask.new(:doc) do |t|
27
27
  t.options = ['--no-private', '-m', 'markdown', '-o', './doc/public/yard']
28
28
  end
29
29
 
30
- desc 'Generate documentation'
31
- task :doc => :yard
32
30
  task :default => :test
data/blather.gemspec CHANGED
@@ -21,29 +21,16 @@ Gem::Specification.new do |s|
21
21
  s.rdoc_options = %w{--charset=UTF-8}
22
22
  s.extra_rdoc_files = %w{LICENSE README.md}
23
23
 
24
- if s.respond_to? :specification_version then
25
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
- s.specification_version = 3
24
+ s.add_dependency("eventmachine", ["~> 0.12.6"])
25
+ s.add_dependency("nokogiri", [">= 1.4.0"])
26
+ s.add_dependency("minitest", [">= 1.7.1"])
27
+ s.add_dependency("activesupport", [">= 3.0.7"])
27
28
 
28
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
29
- s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.6"])
30
- s.add_runtime_dependency(%q<nokogiri>, ["~> 1.4.0"])
31
-
32
- s.add_development_dependency(%q<minitest>, ["~> 1.7.1"])
33
- s.add_development_dependency(%q<mocha>, ["~> 0.9.12"])
34
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
35
- s.add_development_dependency(%q<rcov>, ["~> 0.9.9"])
36
- s.add_development_dependency(%q<yard>, ["~> 0.6.1"])
37
- s.add_development_dependency(%q<bluecloth>, ["~> 2.1.0"])
38
- s.add_development_dependency(%q<rake>)
39
- else
40
- s.add_dependency(%q<eventmachine>, [">= 0.12.6"])
41
- s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
42
- s.add_dependency(%q<minitest>, [">= 1.7.1"])
43
- end
44
- else
45
- s.add_dependency(%q<eventmachine>, [">= 0.12.6"])
46
- s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
47
- s.add_dependency(%q<minitest>, [">= 1.7.1"])
48
- end
29
+ s.add_development_dependency("minitest", ["~> 1.7.1"])
30
+ s.add_development_dependency("mocha", ["~> 0.9.12"])
31
+ s.add_development_dependency("bundler", ["~> 1.0.0"])
32
+ s.add_development_dependency("rcov", ["~> 0.9.9"])
33
+ s.add_development_dependency("yard", ["~> 0.6.1"])
34
+ s.add_development_dependency("bluecloth", ["~> 2.1.0"])
35
+ s.add_development_dependency("rake")
49
36
  end
data/examples/echo.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rubygems'
3
4
  require 'blather/client'
4
5
 
5
6
  when_ready { puts "Connected ! send messages to #{jid.stripped}." }
data/examples/execute.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rubygems'
3
4
  require 'blather/client'
4
5
 
5
6
  message :chat?, :body => 'exit' do |m|
@@ -1,3 +1,4 @@
1
+ require 'rubygems'
1
2
  require 'blather/client/dsl'
2
3
  $stdout.sync = true
3
4
 
@@ -1,3 +1,4 @@
1
+ require 'rubygems'
1
2
  require 'blather'
2
3
 
3
4
  class Object
@@ -2,6 +2,7 @@
2
2
 
3
3
  # Prints out each roster entry
4
4
 
5
+ require 'rubygems'
5
6
  require 'blather/client'
6
7
 
7
8
  when_ready do
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rubygems'
3
4
  require 'blather'
4
5
 
5
6
  trap(:INT) { EM.stop }
@@ -2,6 +2,7 @@
2
2
 
3
3
  # This bot will reply to every message it receives. To end the game, send 'exit'
4
4
 
5
+ require 'rubygems'
5
6
  require 'xmpp4r/client'
6
7
  include Jabber
7
8
 
data/lib/blather.rb CHANGED
@@ -8,7 +8,9 @@
8
8
  digest/sha1
9
9
  logger
10
10
 
11
- blather/core_ext/active_support
11
+ active_support/core_ext/class/inheritable_attributes
12
+ active_support/core_ext/object/blank
13
+
12
14
  blather/core_ext/eventmachine
13
15
  blather/core_ext/ipaddr
14
16
  blather/core_ext/nokogiri
@@ -37,6 +39,7 @@
37
39
  blather/stanza/disco
38
40
  blather/stanza/disco/disco_info
39
41
  blather/stanza/disco/disco_items
42
+ blather/stanza/disco/capabilities
40
43
  blather/stanza/message
41
44
  blather/stanza/presence
42
45
  blather/stanza/presence/c
@@ -72,6 +75,7 @@
72
75
  blather/stream/features/tls
73
76
  ].each { |r| require r }
74
77
 
78
+ # The core Blather namespace
75
79
  module Blather
76
80
  # @private
77
81
  @@logger = nil
@@ -57,11 +57,16 @@ module Blather
57
57
  @tmp_handlers = {}
58
58
  @filters = {:before => [], :after => []}
59
59
  @roster = Roster.new self
60
- @caps = Caps.new
60
+ @caps = Stanza::Capabilities.new
61
61
 
62
62
  setup_initial_handlers
63
63
  end
64
64
 
65
+ # Check whether the client is currently connected.
66
+ def connected?
67
+ setup? && !@stream.stopped?
68
+ end
69
+
65
70
  # Get the current status. Taken from the `state` attribute of Status
66
71
  def status
67
72
  @status.state
@@ -162,17 +167,20 @@ module Blather
162
167
  self.stream.close_connection_after_writing
163
168
  end
164
169
 
165
- def post_init(stream, jid = nil) # @private
170
+ # @private
171
+ def post_init(stream, jid = nil)
166
172
  @stream = stream
167
173
  @jid = JID.new(jid) if jid
168
174
  self.jid.node ? client_post_init : ready!
169
175
  end
170
176
 
171
- def unbind # @private
177
+ # @private
178
+ def unbind
172
179
  call_handler_for(:disconnected, nil) || (EM.reactor_running? && EM.stop)
173
180
  end
174
181
 
175
- def receive_data(stanza) # @private
182
+ # @private
183
+ def receive_data(stanza)
176
184
  catch(:halt) do
177
185
  run_filters :before, stanza
178
186
  handle_stanza stanza
@@ -180,11 +188,13 @@ module Blather
180
188
  end
181
189
  end
182
190
 
183
- def setup? # @private
191
+ # @private
192
+ def setup?
184
193
  @setup.is_a? Array
185
194
  end
186
195
 
187
- def setup(jid, password, host = nil, port = nil) # @private
196
+ # @private
197
+ def setup(jid, password, host = nil, port = nil)
188
198
  @jid = JID.new(jid)
189
199
  @setup = [@jid, password]
190
200
  @setup << host if host
@@ -192,21 +202,22 @@ module Blather
192
202
  self
193
203
  end
194
204
 
195
- protected
196
- def stream # @private
205
+ protected
206
+
207
+ def stream
197
208
  @stream || raise('Stream not ready!')
198
209
  end
199
210
 
200
- def check_handler(type, guards) # @private
211
+ def check_handler(type, guards)
201
212
  Blather.logger.warn "Handler for type \"#{type}\" will never be called as it's not a registered type" unless current_handlers.include?(type)
202
213
  check_guards guards
203
214
  end
204
215
 
205
- def current_handlers # @private
216
+ def current_handlers
206
217
  [:ready, :disconnected] + Stanza.handler_list + BlatherError.handler_list
207
218
  end
208
219
 
209
- def setup_initial_handlers # @private
220
+ def setup_initial_handlers
210
221
  register_handler :error do |err|
211
222
  raise err
212
223
  end
@@ -225,12 +236,12 @@ module Blather
225
236
  end
226
237
  end
227
238
 
228
- def ready! # @private
239
+ def ready!
229
240
  @state = :ready
230
241
  call_handler_for :ready, nil
231
242
  end
232
243
 
233
- def client_post_init # @private
244
+ def client_post_init
234
245
  write_with_handler Stanza::Iq::Roster.new do |node|
235
246
  roster.process node
236
247
  write @status
@@ -238,14 +249,14 @@ module Blather
238
249
  end
239
250
  end
240
251
 
241
- def run_filters(type, stanza) # @private
252
+ def run_filters(type, stanza)
242
253
  @filters[type].each do |guards, handler, filter|
243
254
  next if handler && !stanza.handler_hierarchy.include?(handler)
244
255
  catch(:pass) { call_handler filter, guards, stanza }
245
256
  end
246
257
  end
247
258
 
248
- def handle_stanza(stanza) # @private
259
+ def handle_stanza(stanza)
249
260
  if handler = @tmp_handlers.delete(stanza.id)
250
261
  handler.call stanza
251
262
  else
@@ -255,14 +266,14 @@ module Blather
255
266
  end
256
267
  end
257
268
 
258
- def call_handler_for(type, stanza) # @private
269
+ def call_handler_for(type, stanza)
259
270
  return unless handler = @handlers[type]
260
271
  handler.find do |guards, handler|
261
272
  catch(:pass) { call_handler handler, guards, stanza }
262
273
  end
263
274
  end
264
275
 
265
- def call_handler(handler, guards, stanza) # @private
276
+ def call_handler(handler, guards, stanza)
266
277
  if guards.first.respond_to?(:to_str)
267
278
  result = stanza.find(*guards)
268
279
  handler.call(stanza, result) unless result.empty?
@@ -303,7 +314,7 @@ module Blather
303
314
  end
304
315
  end
305
316
 
306
- def check_guards(guards) # @private
317
+ def check_guards(guards)
307
318
  guards.each do |guard|
308
319
  case guard
309
320
  when Array
@@ -315,142 +326,6 @@ module Blather
315
326
  end
316
327
  end
317
328
  end
318
-
319
- class Caps < Blather::Stanza::DiscoInfo
320
- def self.new
321
- super :result
322
- end
323
-
324
- def ver
325
- generate_ver identities, features
326
- end
327
-
328
- def node=(node)
329
- @bare_node = node
330
- super "#{node}##{ver}"
331
- end
332
-
333
- def identities=(identities)
334
- super identities
335
- regenerate_full_node
336
- end
337
-
338
- def features=(features)
339
- super features
340
- regenerate_full_node
341
- end
342
-
343
- def c
344
- Blather::Stanza::Presence::C.new @bare_node, ver
345
- end
346
-
347
- private
348
-
349
- def regenerate_full_node
350
- self.node = @bare_node
351
- end
352
-
353
- def generate_ver_str(identities, features, forms = [])
354
- # 1. Initialize an empty string S.
355
- s = ''
356
-
357
- # 2. Sort the service discovery identities by category and
358
- # then by type (if it exists) and then by xml:lang (if it
359
- # exists), formatted as CATEGORY '/' [TYPE] '/' [LANG] '/'
360
- # [NAME]. Note that each slash is included even if the TYPE,
361
- # LANG, or NAME is not included.
362
- identities.sort! do |identity1, identity2|
363
- cmp_result = nil
364
- [:category, :type, :xml_lang, :name].each do |field|
365
- value1 = identity1.send(field)
366
- value2 = identity2.send(field)
367
-
368
- if value1 != value2
369
- cmp_result = value1 <=> value2
370
- break
371
- end
372
- end
373
- cmp_result
374
- end
375
-
376
- # 3. For each identity, append the 'category/type/lang/name' to
377
- # S, followed by the '<' character.
378
- s += identities.collect do |identity|
379
- [:category, :type, :xml_lang, :name].collect do |field|
380
- identity.send(field).to_s
381
- end.join('/') + '<'
382
- end.join
383
-
384
- # 4. Sort the supported service discovery features.
385
- features.sort! { |feature1, feature2| feature1.var <=> feature2.var }
386
-
387
- # 5. For each feature, append the feature to S, followed by the
388
- # '<' character.
389
- s += features.collect { |feature| feature.var.to_s + '<' }.join
390
-
391
- # 6. If the service discovery information response includes
392
- # XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e., by
393
- # the XML character data of the <value/> element).
394
- forms.sort! do |form1, form2|
395
- fform_type1 = form1.field 'FORM_TYPE'
396
- fform_type2 = form2.field 'FORM_TYPE'
397
- form_type1 = fform_type1 ? fform_type1.values.to_s : nil
398
- form_type2 = fform_type2 ? fform_type2.values.to_s : nil
399
- form_type1 <=> form_type2
400
- end
401
-
402
- # 7. For each extended service discovery information form:
403
- forms.each do |form|
404
- # 7.1. Append the XML character data of the FORM_TYPE field's
405
- # <value/> element, followed by the '<' character.
406
- fform_type = form.field 'FORM_TYPE'
407
- form_type = fform_type ? fform_type.values.to_s : nil
408
- s += "#{form_type}<"
409
-
410
- # 7.2. Sort the fields by the value of the "var" attribute
411
- fields = form.fields.sort { |field1, field2| field1.var <=> field2.var }
412
-
413
- # 7.3. For each field:
414
- fields.each do |field|
415
- # 7.3.1. Append the value of the "var" attribute, followed by
416
- # the '<' character.
417
- s += "#{field.var}<"
418
-
419
- # 7.3.2. Sort values by the XML character data of the <value/> element
420
- # values = field.values.sort { |value1, value2| value1 <=> value2 }
421
-
422
- # 7.3.3. For each <value/> element, append the XML character
423
- # data, followed by the '<' character.
424
- # s += values.collect { |value| "#{value}<" }.join
425
- s += "#{field.value}<"
426
- end
427
- end
428
- s
429
- end
430
-
431
- def generate_ver(identities, features, forms = [], hash = 'sha-1')
432
- s = generate_ver_str identities, features, forms
433
-
434
- # 9. Compute the verification string by hashing S using the
435
- # algorithm specified in the 'hash' attribute (e.g., SHA-1 as
436
- # defined in RFC 3174). The hashed data MUST be generated
437
- # with binary output and encoded using Base64 as specified in
438
- # Section 4 of RFC 4648 (note: the Base64 output MUST NOT
439
- # include whitespace and MUST set padding bits to zero).
440
-
441
- # See http://www.iana.org/assignments/hash-function-text-names
442
- hash_klass = case hash
443
- when 'md2' then nil
444
- when 'md5' then Digest::MD5
445
- when 'sha-1' then Digest::SHA1
446
- when 'sha-224' then nil
447
- when 'sha-256' then Digest::SHA256
448
- when 'sha-384' then Digest::SHA384
449
- when 'sha-512' then Digest::SHA512
450
- end
451
- hash_klass ? [hash_klass::digest(s)].pack('m').strip : nil
452
- end
453
- end # Caps
454
329
  end # Client
455
330
 
456
331
  end # Blather