xmpp4r 0.4 → 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 (68) hide show
  1. data/CHANGELOG +8 -0
  2. data/README.rdoc +4 -1
  3. data/Rakefile +10 -20
  4. data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +20 -1
  5. data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +7 -0
  6. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +7 -1
  7. data/lib/xmpp4r/callbacks.rb +9 -0
  8. data/lib/xmpp4r/caps/c.rb +14 -0
  9. data/lib/xmpp4r/caps/helper/helper.rb +1 -4
  10. data/lib/xmpp4r/client.rb +42 -15
  11. data/lib/xmpp4r/connection.rb +7 -3
  12. data/lib/xmpp4r/debuglog.rb +22 -1
  13. data/lib/xmpp4r/discovery.rb +1 -0
  14. data/lib/xmpp4r/discovery/helper/helper.rb +58 -0
  15. data/lib/xmpp4r/discovery/iq/discoinfo.rb +2 -2
  16. data/lib/xmpp4r/discovery/iq/discoitems.rb +2 -2
  17. data/lib/xmpp4r/errors.rb +5 -2
  18. data/lib/xmpp4r/httpbinding/client.rb +9 -19
  19. data/lib/xmpp4r/last.rb +2 -0
  20. data/lib/xmpp4r/last/helper/helper.rb +37 -0
  21. data/lib/xmpp4r/last/iq/last.rb +67 -0
  22. data/lib/xmpp4r/location.rb +2 -0
  23. data/lib/xmpp4r/location/helper/helper.rb +56 -0
  24. data/lib/xmpp4r/location/location.rb +179 -0
  25. data/lib/xmpp4r/message.rb +32 -0
  26. data/lib/xmpp4r/presence.rb +1 -1
  27. data/lib/xmpp4r/pubsub/children/configuration.rb +1 -1
  28. data/lib/xmpp4r/pubsub/children/items.rb +11 -2
  29. data/lib/xmpp4r/pubsub/children/publish.rb +14 -0
  30. data/lib/xmpp4r/pubsub/children/retract.rb +41 -0
  31. data/lib/xmpp4r/pubsub/helper/nodebrowser.rb +2 -3
  32. data/lib/xmpp4r/pubsub/helper/nodehelper.rb +4 -4
  33. data/lib/xmpp4r/pubsub/helper/oauth_service_helper.rb +90 -0
  34. data/lib/xmpp4r/pubsub/helper/servicehelper.rb +58 -19
  35. data/lib/xmpp4r/reliable.rb +168 -0
  36. data/lib/xmpp4r/rexmladdons.rb +6 -0
  37. data/lib/xmpp4r/roster/helper/roster.rb +5 -2
  38. data/lib/xmpp4r/sasl.rb +19 -8
  39. data/lib/xmpp4r/stream.rb +133 -31
  40. data/lib/xmpp4r/streamparser.rb +9 -1
  41. data/lib/xmpp4r/test/listener_mocker.rb +118 -0
  42. data/lib/xmpp4r/xmpp4r.rb +3 -1
  43. data/test/bytestreams/tc_ibb.rb +6 -4
  44. data/test/bytestreams/tc_socks5bytestreams.rb +3 -2
  45. data/test/caps/tc_helper.rb +4 -2
  46. data/test/dataforms/tc_data.rb +1 -1
  47. data/test/last/tc_helper.rb +75 -0
  48. data/test/lib/clienttester.rb +43 -14
  49. data/test/muc/tc_muc_mucclient.rb +6 -2
  50. data/test/pubsub/tc_helper.rb +131 -8
  51. data/test/pubsub/tc_nodeconfig.rb +7 -0
  52. data/test/reliable/tc_disconnect_cleanup.rb +334 -0
  53. data/test/reliable/tc_disconnect_exception.rb +37 -0
  54. data/test/reliable/tc_listener_mocked_test.rb +68 -0
  55. data/test/reliable/tc_reliable_connection.rb +31 -0
  56. data/test/roster/tc_helper.rb +21 -11
  57. data/test/rpc/tc_helper.rb +2 -2
  58. data/test/tc_callbacks.rb +3 -3
  59. data/test/tc_message.rb +15 -0
  60. data/test/tc_stream.rb +59 -121
  61. data/test/tc_streamError.rb +2 -4
  62. data/test/tc_streamparser.rb +26 -13
  63. data/test/ts_xmpp4r.rb +0 -9
  64. data/test/tune/tc_helper_recv.rb +0 -2
  65. data/test/vcard/tc_helper.rb +1 -1
  66. data/xmpp4r.gemspec +31 -84
  67. metadata +116 -167
  68. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb.orig +0 -62
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ XMPP4R 0.5 (15/06/2009)
2
+ =======================
3
+ * Many bugs fixed and tests cleanups (better Ruby 1.9 support, in
4
+ particular)
5
+ * Support for reliable connections (that auto-reconnect when being
6
+ disconnected, without losing messages)
7
+ * Better notification of server disconnects
8
+
1
9
  XMPP4R 0.4 (05/08/2008)
2
10
  =======================
3
11
  * Initial support for Ruby 1.9 (see README_ruby19.txt)
@@ -25,6 +25,8 @@ which can be enabled in your code with:
25
25
  Lucas Nussbaum <lucas@lucas-nussbaum.net>
26
26
  Stephan Maka <stephan@spaceboyz.net>
27
27
  Kirill A. Shutemov <k.shutemov@gmail.com>
28
+ Glenn Rempe <glenn@rempe.us>
29
+ Jacob Burkhart <jacob@brontes3d.com>
28
30
  Yuki Mitsui
29
31
  Peter Schrammel
30
32
  Olli
@@ -33,10 +35,11 @@ which can be enabled in your code with:
33
35
  Chris Zelenak
34
36
  Matthew Wood
35
37
  Sam Ruby
36
- Glenn Rempe <glenn@rempe.us>
37
38
  Tim Carey-Smith
38
39
  Scott Lillibridge
39
40
  Joshua Sierles
41
+ Ripta Pasay <github@r8y.org>
42
+ Seth Fitzsimmons
40
43
 
41
44
 
42
45
  == Source Code
data/Rakefile CHANGED
@@ -32,10 +32,10 @@ RDOC_OPTIONS = [
32
32
  ]
33
33
 
34
34
  # Extra files outside of the lib dir that should be included with the rdocs.
35
- RDOC_FILES = %w( README.rdoc README_ruby19.txt CHANGELOG LICENSE COPYING )
35
+ RDOC_FILES = (%w( README.rdoc README_ruby19.txt CHANGELOG LICENSE COPYING )).sort
36
36
 
37
37
  # The full file list used for rdocs, tarballs, gems, and for generating the xmpp4r.gemspec.
38
- PKG_FILES = %w( Rakefile setup.rb xmpp4r.gemspec ) + RDOC_FILES + Dir["{lib,test,data,tools}/**/*"]
38
+ PKG_FILES = (%w( Rakefile setup.rb xmpp4r.gemspec ) + RDOC_FILES + Dir["{lib,test,data,tools}/**/*"]).sort
39
39
 
40
40
  ##############################################################################
41
41
  # DEFAULT TASK
@@ -98,7 +98,7 @@ begin
98
98
  t.test_files = ['test/ts_xmpp4r.rb']
99
99
  t.output_dir = "coverage"
100
100
  end
101
- rescue Object
101
+ rescue LoadError
102
102
  end
103
103
 
104
104
  # DOT GRAPH
@@ -133,16 +133,9 @@ end
133
133
  # What files/dirs should 'rake clean' remove?
134
134
  CLEAN.include ["*.gem", "pkg", "rdoc", "coverage", "tools/*.png"]
135
135
 
136
- # Flag for RubyGems installation used to add rake package tasks conditionally.
137
- # Full gem + tarball on systems with RubyGems. More limited on systems without.
138
- @rubygems = nil
139
-
140
136
  begin
141
137
  require 'rake/gempackagetask'
142
138
 
143
- # RubyGems is installed, known since require 'rake/gempackagetask' succeeded.
144
- @rubygems = true
145
-
146
139
  spec = Gem::Specification.new do |s|
147
140
  s.name = PKG_NAME
148
141
  s.version = PKG_VERSION
@@ -166,6 +159,7 @@ begin
166
159
  Rake::GemPackageTask.new(spec) do |pkg|
167
160
  pkg.gem_spec = spec
168
161
  pkg.need_tar = true
162
+ pkg.need_zip = true
169
163
  end
170
164
 
171
165
  namespace :gem do
@@ -189,12 +183,11 @@ begin
189
183
  desc "Update Github Gemspec"
190
184
  task :update_gemspec do
191
185
  skip_fields = %w(new_platform original_platform date)
192
- integer_fields = %w(specification_version)
193
186
 
194
187
  result = "# WARNING : RAKE AUTO-GENERATED FILE. DO NOT MANUALLY EDIT!\n"
195
188
  result << "# RUN : 'rake gem:update_gemspec'\n\n"
196
189
  result << "Gem::Specification.new do |s|\n"
197
- spec.instance_variables.each do |ivar|
190
+ spec.instance_variables.sort.each do |ivar|
198
191
  value = spec.instance_variable_get(ivar)
199
192
  name = ivar.split("@").last
200
193
  next if skip_fields.include?(name) || value.nil? || value == "" || (value.respond_to?(:empty?) && value.empty?)
@@ -207,8 +200,7 @@ begin
207
200
  case value
208
201
  when Array
209
202
  value = name != "files" ? value.inspect : value.sort.uniq.inspect.split(",").join(",\n")
210
- when String
211
- value = value.to_i if integer_fields.include?(name)
203
+ when String, Fixnum, true, false
212
204
  value = value.inspect
213
205
  else
214
206
  value = value.to_s.inspect
@@ -227,8 +219,7 @@ begin
227
219
  task :gem => ['gem:update_gemspec']
228
220
 
229
221
  rescue LoadError
230
- @rubygems = false
231
- warning = <<EOF
222
+ puts <<EOF
232
223
  ###
233
224
  Packaging Warning : RubyGems is apparently not installed on this
234
225
  system and any file add/remove/rename will not
@@ -239,24 +230,23 @@ rescue LoadError
239
230
  gemspec will also stay in sync for others.
240
231
  ###
241
232
  EOF
242
- puts warning
243
233
  end
244
234
 
245
235
  # we are apparently on a system that does not have RubyGems installed.
246
236
  # Lets try to provide only the basic tarball package tasks as a fallback.
247
- if @rubygems == false
237
+ unless defined? Gem
248
238
  begin
249
239
  require 'rake/packagetask'
250
240
  Rake::PackageTask.new(PKG_NAME, PKG_VERSION) do |p|
251
241
  p.package_files = PKG_FILES
252
242
  p.need_tar = true
243
+ p.need_zip = true
253
244
  end
254
245
  rescue LoadError
255
- warning = <<EOF
246
+ puts <<EOF
256
247
  ###
257
248
  Warning : Unable to require the 'rake/packagetask'. Is Rake installed?
258
249
  ###
259
250
  EOF
260
- puts warning
261
251
  end
262
252
  end
@@ -7,7 +7,8 @@ $:.unshift '../../../../../lib'
7
7
 
8
8
  require 'optparse'
9
9
  require 'xmpp4r/client'
10
- require 'xmpp4r/version/iq/version'
10
+ require 'xmpp4r/version'
11
+ require 'xmpp4r/discovery'
11
12
  include Jabber
12
13
  #Jabber::debug = true
13
14
 
@@ -15,6 +16,7 @@ include Jabber
15
16
  jid = JID.new('bot@localhost/Bot')
16
17
  password = 'bot'
17
18
  domains = []
19
+ domains_ejabberd = []
18
20
  OptionParser.new do |opts|
19
21
  opts.banner = 'Usage: versionpoll.rb -j jid -p password -d DOMAINS'
20
22
  opts.separator ''
@@ -48,6 +50,18 @@ cl.add_iq_callback do |i|
48
50
  cl.send(Iq.new_browseget.set_to(j))
49
51
  end
50
52
  end
53
+ elsif i.type == :result and i.query.kind_of? Discovery::IqQueryDiscoItems
54
+ i.query.items.each do |e|
55
+ j = e.jid
56
+ if not queried.include?(j)
57
+ activity = true
58
+ queried << j
59
+ iq = Iq.new(:get)
60
+ iq.query = Version::IqQueryVersion.new
61
+ iq.set_to(j)
62
+ cl.send(iq)
63
+ end
64
+ end
51
65
  end
52
66
  end
53
67
 
@@ -80,6 +94,11 @@ cl.send(Presence.new)
80
94
  for d in domains do
81
95
  cl.send(Iq.new_browseget.set_to("#{d}/admin"))
82
96
  end
97
+ for d in domains_ejabberd do
98
+ iq = Iq.new(:get, d)
99
+ iq.add(Discovery::IqQueryDiscoItems.new).node = 'online users'
100
+ cl.send(iq)
101
+ end
83
102
 
84
103
  activity = true
85
104
  while activity
@@ -13,6 +13,11 @@ module Jabber
13
13
  def initialize(stream, session_id, initiator_jid, target_jid)
14
14
  # Target and Initiator are swapped here, because we're the target
15
15
  super(stream, session_id, target_jid, initiator_jid)
16
+ @accept_ready = Semaphore::new
17
+ end
18
+
19
+ def accept_wait
20
+ @accept_ready.wait
16
21
  end
17
22
 
18
23
  ##
@@ -39,6 +44,8 @@ module Jabber
39
44
  end
40
45
  }
41
46
 
47
+ @accept_ready.run
48
+
42
49
  connect_sem.wait
43
50
  true
44
51
  end
@@ -11,8 +11,14 @@ module Jabber
11
11
  # See SOCKS5Bytestreams#initialize
12
12
  def initialize(stream, session_id, initiator_jid, target_jid)
13
13
  @connect_timeout = 60
14
+ @accept_ready = Semaphore::new
14
15
  super
15
16
  end
17
+
18
+ def accept_wait
19
+ @accept_ready.wait
20
+ end
21
+
16
22
  ##
17
23
  # Wait until the stream has been established
18
24
  #
@@ -58,7 +64,7 @@ module Jabber
58
64
  false
59
65
  end
60
66
  }
61
-
67
+ @accept_ready.run
62
68
  begin
63
69
  Timeout::timeout(@connect_timeout) { connect_sem.wait }
64
70
  rescue Timeout::Error
@@ -39,6 +39,7 @@ module Jabber
39
39
  # < 100:: all those numbers are normally available for your application.
40
40
  # That's enough, don't you think ?
41
41
  class CallbackList
42
+ include Enumerable
42
43
 
43
44
  # Create a new list of callbacks
44
45
  def initialize
@@ -70,6 +71,10 @@ module Jabber
70
71
  self
71
72
  end
72
73
 
74
+ def each(&block)
75
+ @list.each(&block)
76
+ end
77
+
73
78
  ##
74
79
  # Number of elements in the list
75
80
  # return:: [Integer] The number of elements
@@ -120,5 +125,9 @@ module Jabber
120
125
  @ref = ref
121
126
  @block = block
122
127
  end
128
+
129
+ def to_s
130
+ "#<#{[self.class, priority, ref].compact * " "}>"
131
+ end
123
132
  end
124
133
  end
@@ -48,6 +48,20 @@ module Jabber
48
48
  def hash
49
49
  attributes['hash']
50
50
  end
51
+
52
+ ##
53
+ # Get the value of this element's 'ext' attribute,
54
+ # the list of extensions for legacy clients.
55
+ def ext
56
+ attributes['ext']
57
+ end
58
+
59
+ ##
60
+ # Is this a legacy caps response, as defined by version 1.3 of
61
+ # the XEP-0115 specification?
62
+ def legacy?
63
+ hash.nil? || hash.empty?
64
+ end
51
65
  end
52
66
  end
53
67
  end
@@ -40,10 +40,7 @@ module Jabber
40
40
 
41
41
  @stream.add_iq_callback(250) do |iq|
42
42
  if iq.type == :get and iq.query.kind_of? Jabber::Discovery::IqQueryDiscoInfo
43
- Thread.new do
44
- Thread.abort_on_exception = true
45
- handle_discoinfo_query(iq)
46
- end
43
+ handle_discoinfo_query(iq)
47
44
  true
48
45
  else
49
46
  false
@@ -75,7 +75,9 @@ module Jabber
75
75
  # Close the connection,
76
76
  # sends <tt></stream:stream></tt> tag first
77
77
  def close
78
- send("</stream:stream>")
78
+ if @status == CONNECTED
79
+ send("</stream:stream>")
80
+ end
79
81
  super
80
82
  end
81
83
 
@@ -117,6 +119,44 @@ module Jabber
117
119
  end
118
120
  end
119
121
 
122
+ ##
123
+ # Resource binding (RFC3920bis-06 - section 8.)
124
+ #
125
+ # XMPP allows to bind to multiple resources
126
+ def bind(desired_resource=nil)
127
+ iq = Iq.new(:set)
128
+ bind = iq.add REXML::Element.new('bind')
129
+ bind.add_namespace @stream_features['bind']
130
+ if desired_resource
131
+ resource = bind.add REXML::Element.new('resource')
132
+ resource.text = desired_resource
133
+ end
134
+
135
+ jid = nil
136
+ send_with_id(iq) do |reply|
137
+ reply_bind = reply.first_element('bind')
138
+ if reply_bind
139
+ reported_jid = reply_bind.first_element('jid')
140
+ if reported_jid and reported_jid.text
141
+ jid = JID.new(reported_jid.text)
142
+ end
143
+ end
144
+ end
145
+ jid
146
+ end
147
+
148
+ ##
149
+ # Resource unbinding (RFC3920bis-06 - section 8.6.3.)
150
+ def unbind(desired_resource)
151
+ iq = Iq.new(:set)
152
+ unbind = iq.add REXML::Element.new('unbind')
153
+ unbind.add_namespace @stream_features['unbind']
154
+ resource = unbind.add REXML::Element.new('resource')
155
+ resource.text = desired_resource
156
+
157
+ send_with_id(iq)
158
+ end
159
+
120
160
  ##
121
161
  # Use a SASL authentication mechanism and bind to a resource
122
162
  #
@@ -138,20 +178,7 @@ module Jabber
138
178
 
139
179
  # Resource binding (RFC3920 - 7)
140
180
  if @stream_features.has_key? 'bind'
141
- iq = Iq.new(:set)
142
- bind = iq.add REXML::Element.new('bind')
143
- bind.add_namespace @stream_features['bind']
144
- if jid.resource
145
- resource = bind.add REXML::Element.new('resource')
146
- resource.text = jid.resource
147
- end
148
-
149
- send_with_id(iq) do |reply|
150
- reported_jid = reply.first_element('jid')
151
- if reported_jid and reported_jid.text
152
- @jid = JID.new(reported_jid.text)
153
- end
154
- end
181
+ @jid = bind(@jid.resource)
155
182
  end
156
183
 
157
184
  # Session starting
@@ -86,10 +86,11 @@ module Jabber
86
86
 
87
87
  ##
88
88
  # Closing connection:
89
- # first kill keepaliveThread, then call Stream#close!
89
+ # first kill keepaliveThread (but only if it's not me), then call Stream#close!
90
90
  def close!
91
- @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive?
91
+ @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive? and @keepaliveThread != Thread.current
92
92
  super
93
+ @keepaliveThread.kill if @keepaliveThread and @keepaliveThread.alive?
93
94
  end
94
95
 
95
96
  def accept_features
@@ -131,7 +132,7 @@ module Jabber
131
132
  true
132
133
  }
133
134
  if reply.name != 'proceed'
134
- raise ServerError(reply.first_element('error'))
135
+ raise ServerError.new(reply.first_element('error'))
135
136
  end
136
137
  # Don't be interrupted
137
138
  stop
@@ -204,6 +205,9 @@ module Jabber
204
205
  # seconds.
205
206
  def keepalive_loop
206
207
  loop do
208
+ unless is_connected?
209
+ Thread.current.kill
210
+ end
207
211
  difference = @last_send + @keepalive_interval - Time.now
208
212
  if difference <= 0
209
213
  send(' ')
@@ -8,7 +8,8 @@ module Jabber
8
8
  def Jabber::logger
9
9
  @@logger ||= Logger.new($stderr)
10
10
  end
11
-
11
+
12
+ # Set the logger to use for debug and warn (if enabled)
12
13
  def Jabber::logger=(logger)
13
14
  @@logger = logger
14
15
  end
@@ -16,6 +17,9 @@ module Jabber
16
17
  # Is debugging mode enabled ?
17
18
  @@debug = false
18
19
 
20
+ # Is warnings mode enabled ?
21
+ @@warnings = false
22
+
19
23
  # Enable/disable debugging mode. When debug mode is enabled, information
20
24
  # can be logged using Jabber::debuglog. When debug mode is disabled, calls
21
25
  # to Jabber::debuglog are just ignored.
@@ -23,6 +27,16 @@ module Jabber
23
27
  @@debug = debug
24
28
  if @@debug
25
29
  debuglog('Debugging mode enabled.')
30
+ #if debug is enabled, we should automatically enable warnings too
31
+ Jabber::warnings = true
32
+ end
33
+ end
34
+
35
+ # Enable/disable warnings mode.
36
+ def Jabber::warnings=(warnings)
37
+ @@warnings = warnings
38
+ if @@warnings
39
+ warnlog('Warnings mode enabled.')
26
40
  end
27
41
  end
28
42
 
@@ -39,4 +53,11 @@ module Jabber
39
53
  return if not @@debug
40
54
  logger.debug string.chomp.gsub("\n", "\n ")
41
55
  end
56
+
57
+ # Outputs a string only if warnings mode is enabled.
58
+ def Jabber::warnlog(string)
59
+ return if not @@warnings
60
+ logger.warn string.chomp.gsub("\n", "\n ")
61
+ end
62
+
42
63
  end