xmpp4r 0.4 → 0.5

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