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
@@ -4,4 +4,5 @@
4
4
 
5
5
  require 'xmpp4r/discovery/iq/discoinfo'
6
6
  require 'xmpp4r/discovery/iq/discoitems'
7
+ require 'xmpp4r/discovery/helper/helper'
7
8
  require 'xmpp4r/discovery/helper/responder'
@@ -0,0 +1,58 @@
1
+ # =XMPP4R - XMPP Library for Ruby
2
+ # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
+ # Website::http://home.gna.org/xmpp4r/
4
+
5
+ require 'xmpp4r'
6
+ require 'xmpp4r/discovery'
7
+
8
+ module Jabber
9
+ module Discovery
10
+ ##
11
+ # A Helper to manage service and item discovery.
12
+ class Helper
13
+ def initialize(client)
14
+ @stream = client
15
+ end
16
+
17
+ ##
18
+ # Service discovery on a JID.
19
+ # jid:: [JID]
20
+ # return:: [Jabber::Discovery::IqQueryDiscoInfo]
21
+ def get_info_for(jid, node = nil)
22
+ iq = Jabber::Iq.new(:get, jid)
23
+ iq.from = @stream.jid
24
+ disco = Jabber::Discovery::IqQueryDiscoInfo.new
25
+ disco.node = node
26
+ iq.add(disco)
27
+
28
+ res = nil
29
+
30
+ @stream.send_with_id(iq) { |reply|
31
+ res = reply.query
32
+ }
33
+
34
+ res
35
+ end
36
+
37
+ ##
38
+ # Item discovery on a JID.
39
+ # jid:: [JID]
40
+ # return:: [Jabber::Discovery::IqQueryDiscoItems]
41
+ def get_items_for(jid, node = nil)
42
+ iq = Jabber::Iq.new(:get, jid)
43
+ iq.from = @stream.jid
44
+ disco = Jabber::Discovery::IqQueryDiscoItems.new
45
+ disco.node = node
46
+ iq.add(disco)
47
+
48
+ res = nil
49
+
50
+ @stream.send_with_id(iq) { |reply|
51
+ res = reply.query
52
+ }
53
+
54
+ res
55
+ end
56
+ end
57
+ end
58
+ end
@@ -29,14 +29,14 @@ module Jabber
29
29
  end
30
30
 
31
31
  ##
32
- # Get the queried Service Discovery node or nil
32
+ # Set the queried Service Discovery node or nil
33
33
  # val:: [String]
34
34
  def node=(val)
35
35
  attributes['node'] = val
36
36
  end
37
37
 
38
38
  ##
39
- # Get the queried Service Discovery node or nil
39
+ # Set the queried Service Discovery node or nil
40
40
  # (chaining-friendly)
41
41
  # val:: [String]
42
42
  def set_node(val)
@@ -32,13 +32,13 @@ module Jabber
32
32
  end
33
33
 
34
34
  ##
35
- # Get the queried Service Discovery node or nil
35
+ # Set the queried Service Discovery node or nil
36
36
  def node=(val)
37
37
  attributes['node'] = val
38
38
  end
39
39
 
40
40
  ##
41
- # Get the queried Service Discovery node or nil
41
+ # Set the queried Service Discovery node or nil
42
42
  # (chaining-friendly)
43
43
  def set_node(val)
44
44
  self.node = val
@@ -12,6 +12,9 @@ module Jabber
12
12
  # A client-side only argument error
13
13
  class ArgumentError < JabberError; end
14
14
 
15
+ # Server disconnected us
16
+ class ServerDisconnected < JabberError; end
17
+
15
18
  ##
16
19
  # An error returned from the server
17
20
  #
@@ -45,16 +48,16 @@ module Jabber
45
48
 
46
49
  class ComponentAuthenticationFailure < JabberError; end
47
50
 
48
- # TODO : Give this a better name
49
51
  class NoNameXmlnsRegistered < JabberError
50
52
  def initialize(klass)
51
53
  super "Class #{klass} has not set name and xmlns"
52
54
  end
53
55
  end
54
56
 
55
- # TODO : Give this a better name
56
57
  class SOCKS5Error < JabberError; end
57
58
 
59
+ class InvalidChatState < JabberError; end
60
+
58
61
  ##
59
62
  # A class used to build/parse <error/> elements.
60
63
  # Look at XEP-0086 for explanation:
@@ -2,8 +2,10 @@
2
2
  # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
3
  # Website::http://home.gna.org/xmpp4r/
4
4
 
5
+ # TODO: eval <body type='terminate' condition=
5
6
 
6
7
  require 'xmpp4r/client'
8
+ require 'xmpp4r/semaphore'
7
9
  require 'net/http'
8
10
 
9
11
  module Jabber
@@ -50,6 +52,7 @@ module Jabber
50
52
  @last_send = Time.at(0)
51
53
  @send_buffer = ''
52
54
 
55
+ @http_requests = 1
53
56
  @http_wait = 20
54
57
  @http_hold = 1
55
58
  @http_content_type = 'text/xml; charset=utf-8'
@@ -73,7 +76,7 @@ module Jabber
73
76
  @stream_features = {}
74
77
  @http_rid = IdGenerator.generate_id.to_i
75
78
  @pending_rid = @http_rid
76
- @pending_rid_lock = Mutex.new
79
+ @pending_rid_lock = Semaphore.new
77
80
 
78
81
  req_body = REXML::Element.new('body')
79
82
  req_body.attributes['rid'] = @http_rid
@@ -82,7 +85,7 @@ module Jabber
82
85
  req_body.attributes['wait'] = @http_wait.to_s
83
86
  req_body.attributes['to'] = @jid.domain
84
87
  if host
85
- req_body.attributes['route'] = 'xmpp:#{host}:#{port}'
88
+ req_body.attributes['route'] = "xmpp:#{host}:#{port}"
86
89
  end
87
90
  req_body.attributes['secure'] = 'true'
88
91
  req_body.attributes['xmlns'] = 'http://jabber.org/protocol/httpbind'
@@ -107,19 +110,6 @@ module Jabber
107
110
  @features_sem.run
108
111
  end
109
112
 
110
- ##
111
- # Send a stanza, additionally with block
112
- #
113
- # This method ensures a 'jabber:client' namespace for
114
- # the stanza
115
- def send(xml, &block)
116
- if xml.kind_of? REXML::Element
117
- xml.add_namespace('jabber:client')
118
- end
119
-
120
- super
121
- end
122
-
123
113
  ##
124
114
  # Ensure that there is one pending request
125
115
  #
@@ -148,7 +138,7 @@ module Jabber
148
138
  # result:: [REXML::Element]
149
139
  def receive_elements_with_rid(rid, elements)
150
140
  while rid > @pending_rid
151
- @pending_rid_lock.lock
141
+ @pending_rid_lock.wait
152
142
  end
153
143
  @pending_rid = rid + 1
154
144
 
@@ -156,7 +146,7 @@ module Jabber
156
146
  receive(e)
157
147
  }
158
148
 
159
- @pending_rid_lock.unlock
149
+ @pending_rid_lock.run
160
150
  end
161
151
 
162
152
  ##
@@ -167,12 +157,12 @@ module Jabber
167
157
  request.content_length = body.size
168
158
  request.body = body
169
159
  request['Content-Type'] = @http_content_type
170
- Jabber::debuglog("HTTP REQUEST (#{@pending_requests}/#{@http_requests}):\n#{request.body}")
160
+ Jabber::debuglog("HTTP REQUEST (#{@pending_requests + 1}/#{@http_requests}):\n#{request.body}")
171
161
  response = Net::HTTP.start(@uri.host, @uri.port) { |http|
172
162
  http.use_ssl = true if @uri.kind_of? URI::HTTPS
173
163
  http.request(request)
174
164
  }
175
- Jabber::debuglog("HTTP RESPONSE (#{@pending_requests}/#{@http_requests}):\n#{response.body}")
165
+ Jabber::debuglog("HTTP RESPONSE (#{@pending_requests + 1}/#{@http_requests}): #{response.class}\n#{response.body}")
176
166
 
177
167
  unless response.kind_of? Net::HTTPSuccess
178
168
  # Unfortunately, HTTPResponses aren't exceptions
@@ -0,0 +1,2 @@
1
+ require 'xmpp4r/last/iq/last'
2
+ require 'xmpp4r/last/helper/helper'
@@ -0,0 +1,37 @@
1
+ # =XMPP4R - XMPP Library for Ruby
2
+ # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
+ # Website::http://home.gna.org/xmpp4r/
4
+
5
+ require 'xmpp4r'
6
+ require 'xmpp4r/last'
7
+
8
+ module Jabber
9
+ module LastActivity
10
+ ##
11
+ # A Helper to manage discovery of Last Activity.
12
+ class Helper
13
+ def initialize(client)
14
+ @stream = client
15
+ end
16
+
17
+ ##
18
+ # Gets the last activity from a JID.
19
+ # jid:: [JID]
20
+ # return:: [Jabber::LastActivity::IqQueryLastActivity]
21
+ def get_last_activity_from(jid)
22
+ iq = Jabber::Iq.new(:get, jid)
23
+ iq.from = @stream.jid
24
+ iq.add(Jabber::LastActivity::IqQueryLastActivity.new)
25
+
26
+ reply = @stream.send_with_id(iq)
27
+
28
+ if reply.query && reply.query.kind_of?(IqQueryLastActivity)
29
+ reply.query
30
+ else
31
+ nil
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,67 @@
1
+ # =XMPP4R - XMPP Library for Ruby
2
+ # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
+ # Website::http://home.gna.org/xmpp4r/
4
+
5
+ require 'xmpp4r/query'
6
+
7
+ module Jabber
8
+ module LastActivity
9
+ NS_LAST_ACTIVITY = 'jabber:iq:last'
10
+
11
+ ##
12
+ # Class for handling Last Activity queries
13
+ # (XEP-0012)
14
+ class IqQueryLastActivity < IqQuery
15
+ name_xmlns 'query', NS_LAST_ACTIVITY
16
+
17
+ ##
18
+ # Get the number of seconds since last activity.
19
+ #
20
+ # With a bare jid, this will return the number of seconds since the
21
+ # client was last seen (offline user query).
22
+ #
23
+ # With a full jid, this will return the number of seconds that the
24
+ # client has been idle (online user query).
25
+ #
26
+ # With a server, this will return the server or component's uptime in
27
+ # seconds (server / component query).
28
+ def seconds
29
+ attributes['seconds'] ? attributes['seconds'].to_i : nil
30
+ end
31
+
32
+ ##
33
+ # Set the number of seconds since last activity
34
+ def seconds=(val)
35
+ attributes['seconds'] = val.to_s
36
+ end
37
+
38
+ ##
39
+ # Set the number of seconds since last activity
40
+ # (chaining-friendly)
41
+ def set_second(val)
42
+ self.seconds = val
43
+ self
44
+ end
45
+
46
+ ##
47
+ # For an offline user query, get the last status.
48
+ def status
49
+ self.text
50
+ end
51
+
52
+ ##
53
+ # For an offline user query, set the last status.
54
+ def status=(val)
55
+ self.text = val
56
+ end
57
+
58
+ ##
59
+ # For an offline user query, set the last status.
60
+ # (chaining-friendly)
61
+ def set_status(val)
62
+ self.status = val
63
+ self
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,2 @@
1
+ require 'xmpp4r/location/location'
2
+ require 'xmpp4r/location/helper/helper'
@@ -0,0 +1,56 @@
1
+ # =XMPP4R - XMPP Library for Ruby
2
+ # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
+ # Website::http://home.gna.org/xmpp4r/
4
+
5
+ require 'xmpp4r'
6
+ require 'xmpp4r/pubsub'
7
+ require 'xmpp4r/location/location'
8
+
9
+ module Jabber
10
+ module UserLocation
11
+ ##
12
+ # A Helper for XEP-0080 User Location
13
+ #
14
+ # Use this helper to send a user's location, or receive them from a
15
+ # specified jid. Described at http://www.xmpp.org/extensions/xep-0080.html
16
+ #
17
+ # For example:
18
+ # <pre>
19
+ # h = UserLocation::Helper( @client, 'radio1@hug.hellomatty.com' )
20
+ # h.add_userlocation_callback do |location|
21
+ # puts "Now in: #{location.locality}"
22
+ # end
23
+ # </pre>
24
+ class Helper < PubSub::ServiceHelper
25
+ ##
26
+ # Send out the current location.
27
+ #
28
+ # location:: [Jabber::UserLocation::Location] current_location
29
+ def current_location(location)
30
+ item = Jabber::PubSub::Item.new()
31
+ item.add(location)
32
+
33
+ publish_item_to(NS_USERLOCATION, item)
34
+ end
35
+
36
+ ##
37
+ # Use this method to indicate that you wish to stop publishing
38
+ # a location.
39
+ def stop_publishing
40
+ current_location(Jabber::UserLocation::Location.new())
41
+ end
42
+
43
+ ##
44
+ # Add a callback that will be invoked when a location is received
45
+ # from the jid specified when you constructed the Helper.
46
+ def add_userlocation_callback(prio = 200, ref = nil, &block)
47
+ add_event_callback(prio, ref) do |event|
48
+ location = event.first_element('items/item/location')
49
+ if location
50
+ block.call(location)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,179 @@
1
+ # =XMPP4R - XMPP Library for Ruby
2
+ # License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
3
+ # Website::http://home.gna.org/xmpp4r/
4
+
5
+ require 'time'
6
+ require 'xmpp4r/xmppelement'
7
+ require 'rexml/element'
8
+
9
+ module Jabber
10
+ module UserLocation
11
+ NS_USERLOCATION = 'http://jabber.org/protocol/geoloc'
12
+ ALLOWABLE_ATTRIBUTES = %w(accuracy alt area bearing building country
13
+ datum description floor lat locality lon postalcode region room
14
+ speed street text timestamp uri)
15
+
16
+ ##
17
+ # The <geoloc> XMPP element, as defined in XEP-0080 User Location
18
+ #
19
+ # See http://xmpp.org/extensions/xep-0080.html - this element
20
+ # encapsulates data about a user's current location. These are
21
+ # expressed as child elements such as <locality>, <lat>, etc.
22
+ # which are also managed by this class.
23
+ #
24
+ # If the element has no children then it indicates that the user
25
+ # has stopped publishing their location.
26
+ class Location < XMPPElement
27
+ name_xmlns 'geoloc', NS_USERLOCATION
28
+ force_xmlns true
29
+
30
+ ##
31
+ # Construct a new <location> element.
32
+ #
33
+ # Supply no arguments to make an empty element to indicate that
34
+ # location is no longer being published.
35
+ #
36
+ # attributes:: [Hash] location attributes
37
+ def initialize(attributes = {})
38
+ super()
39
+
40
+ # validate attributes
41
+ attributes = attributes.select do |k,v|
42
+ ALLOWABLE_ATTRIBUTES.include?(k) && !v.nil?
43
+ end
44
+
45
+ attributes.each do |k,v|
46
+ v = x.xmlschema if v.is_a?(Time)
47
+ add_element(REXML::Element.new(k)).text = v.to_s
48
+ end
49
+ end
50
+
51
+
52
+ ##
53
+ # Returns true if a location is currently being published, otherwise false.
54
+ def published?
55
+ (elements.size > 0)
56
+ end
57
+
58
+ ##
59
+ # Get the accuracy attribute of this location.
60
+ def accuracy
61
+ first_element('accuracy').text if first_element('accuracy')
62
+ end
63
+
64
+ ##
65
+ # Get the alt attribute of this location.
66
+ def alt
67
+ first_element('alt').text if first_element('alt')
68
+ end
69
+
70
+ ##
71
+ # Get the area attribute of this location.
72
+ def area
73
+ first_element('area').text if first_element('area')
74
+ end
75
+
76
+ ##
77
+ # Get the bearing attribute of this location.
78
+ def bearing
79
+ first_element('bearing').text if first_element('bearing')
80
+ end
81
+
82
+ ##
83
+ # Get the building attribute of this location.
84
+ def building
85
+ first_element('building').text if first_element('building')
86
+ end
87
+
88
+ ##
89
+ # Get the country attribute of this location.
90
+ def country
91
+ first_element('country').text if first_element('country')
92
+ end
93
+
94
+ ##
95
+ # Get the datum attribute of this location.
96
+ def datum
97
+ first_element('datum').text if first_element('datum')
98
+ end
99
+
100
+ ##
101
+ # Get the description attribute of this location.
102
+ def description
103
+ first_element('description').text if first_element('description')
104
+ end
105
+
106
+ ##
107
+ # Get the floor attribute of this location.
108
+ def floor
109
+ first_element('floor').text if first_element('floor')
110
+ end
111
+
112
+ ##
113
+ # Get the lat attribute of this location.
114
+ def lat
115
+ first_element('lat').text if first_element('lat')
116
+ end
117
+
118
+ ##
119
+ # Get the locality attribute of this location.
120
+ def locality
121
+ first_element('locality').text if first_element('locality')
122
+ end
123
+
124
+ ##
125
+ # Get the lon attribute of this location.
126
+ def lon
127
+ first_element('lon').text if first_element('lon')
128
+ end
129
+
130
+ ##
131
+ # Get the postalcode attribute of this location.
132
+ def postalcode
133
+ first_element('postalcode').text if first_element('postalcode')
134
+ end
135
+
136
+ ##
137
+ # Get the region attribute of this location.
138
+ def region
139
+ first_element('region').text if first_element('region')
140
+ end
141
+
142
+ ##
143
+ # Get the room attribute of this location.
144
+ def room
145
+ first_element('room').text if first_element('room')
146
+ end
147
+
148
+ ##
149
+ # Get the speed attribute of this location.
150
+ def speed
151
+ first_element('speed').text if first_element('speed')
152
+ end
153
+
154
+ ##
155
+ # Get the street attribute of this location.
156
+ def street
157
+ first_element('street').text if first_element('street')
158
+ end
159
+
160
+ ##
161
+ # Get the text attribute of this location.
162
+ def text
163
+ first_element('text').text if first_element('text')
164
+ end
165
+
166
+ ##
167
+ # Get the timestamp attribute of this location.
168
+ def timestamp
169
+ first_element('timestamp').text if first_element('timestamp')
170
+ end
171
+
172
+ ##
173
+ # Get the uri attribute of this location.
174
+ def uri
175
+ first_element('uri').text if first_element('uri')
176
+ end
177
+ end
178
+ end
179
+ end