blather 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +2 -0
- data/README.rdoc +54 -29
- data/Rakefile +94 -13
- data/VERSION.yml +4 -0
- data/examples/drb_client.rb +2 -4
- data/examples/echo.rb +13 -8
- data/examples/pubsub/cli.rb +64 -0
- data/examples/pubsub/ping_pong.rb +18 -0
- data/examples/pubsub/pubsub_dsl.rb +52 -0
- data/examples/pubsub_client.rb +39 -0
- data/examples/rosterprint.rb +14 -0
- data/examples/xmpp4r/echo.rb +35 -0
- data/ext/extconf.rb +65 -0
- data/lib/blather.rb +18 -121
- data/lib/blather/client.rb +13 -0
- data/lib/blather/client/client.rb +165 -0
- data/lib/blather/client/dsl.rb +99 -0
- data/lib/blather/client/pubsub.rb +53 -0
- data/lib/blather/client/pubsub/node.rb +27 -0
- data/lib/blather/core_ext/active_support.rb +1 -0
- data/lib/blather/core_ext/libxml.rb +7 -1
- data/lib/blather/errors.rb +39 -18
- data/lib/blather/errors/sasl_error.rb +87 -0
- data/lib/blather/errors/stanza_error.rb +262 -0
- data/lib/blather/errors/stream_error.rb +253 -0
- data/lib/blather/jid.rb +9 -16
- data/lib/blather/roster.rb +9 -0
- data/lib/blather/roster_item.rb +7 -4
- data/lib/blather/stanza.rb +19 -25
- data/lib/blather/stanza/disco.rb +9 -0
- data/lib/blather/stanza/disco/disco_info.rb +84 -0
- data/lib/blather/stanza/disco/disco_items.rb +59 -0
- data/lib/blather/stanza/iq.rb +16 -4
- data/lib/blather/stanza/iq/query.rb +6 -4
- data/lib/blather/stanza/iq/roster.rb +38 -38
- data/lib/blather/stanza/pubsub.rb +33 -0
- data/lib/blather/stanza/pubsub/affiliations.rb +52 -0
- data/lib/blather/stanza/pubsub/errors.rb +9 -0
- data/lib/blather/stanza/pubsub/event.rb +21 -0
- data/lib/blather/stanza/pubsub/items.rb +59 -0
- data/lib/blather/stanza/pubsub/owner.rb +9 -0
- data/lib/blather/stanza/pubsub/subscriptions.rb +57 -0
- data/lib/blather/stream.rb +125 -57
- data/lib/blather/stream/client.rb +26 -0
- data/lib/blather/stream/component.rb +34 -0
- data/lib/blather/stream/parser.rb +17 -27
- data/lib/blather/stream/resource.rb +21 -24
- data/lib/blather/stream/sasl.rb +60 -37
- data/lib/blather/stream/session.rb +12 -19
- data/lib/blather/stream/stream_handler.rb +39 -0
- data/lib/blather/stream/tls.rb +22 -18
- data/lib/blather/xmpp_node.rb +91 -17
- data/spec/blather/core_ext/libxml_spec.rb +58 -0
- data/spec/blather/errors/sasl_error_spec.rb +56 -0
- data/spec/blather/errors/stanza_error_spec.rb +148 -0
- data/spec/blather/errors/stream_error_spec.rb +114 -0
- data/spec/blather/errors_spec.rb +40 -0
- data/spec/blather/jid_spec.rb +0 -7
- data/spec/blather/roster_item_spec.rb +5 -0
- data/spec/blather/roster_spec.rb +6 -6
- data/spec/blather/stanza/discos/disco_info_spec.rb +207 -0
- data/spec/blather/stanza/discos/disco_items_spec.rb +136 -0
- data/spec/blather/stanza/iq/query_spec.rb +9 -2
- data/spec/blather/stanza/iq/roster_spec.rb +117 -1
- data/spec/blather/stanza/iq_spec.rb +29 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +12 -1
- data/spec/blather/stanza/presence_spec.rb +29 -0
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +46 -0
- data/spec/blather/stanza/pubsub/items_spec.rb +59 -0
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +63 -0
- data/spec/blather/stanza/pubsub_spec.rb +26 -0
- data/spec/blather/stanza_spec.rb +13 -1
- data/spec/blather/stream/client_spec.rb +787 -0
- data/spec/blather/stream/component_spec.rb +86 -0
- data/spec/blather/xmpp_node_spec.rb +75 -22
- data/spec/fixtures/pubsub.rb +157 -0
- data/spec/spec_helper.rb +6 -14
- metadata +86 -74
- data/CHANGELOG +0 -5
- data/Manifest +0 -47
- data/blather.gemspec +0 -41
- data/lib/blather/stanza/error.rb +0 -31
- data/spec/blather/stream_spec.rb +0 -462
- data/spec/build_safe.rb +0 -20
@@ -0,0 +1,253 @@
|
|
1
|
+
module Blather
|
2
|
+
|
3
|
+
##
|
4
|
+
# Stream Errors
|
5
|
+
# RFC3920 Section 9.3 (http://xmpp.org/rfcs/rfc3920.html#streams-error-rules)
|
6
|
+
class StreamError < BlatherError
|
7
|
+
class_inheritable_accessor :err_name
|
8
|
+
@@registrations = {}
|
9
|
+
|
10
|
+
register :stream_error
|
11
|
+
|
12
|
+
attr_reader :text, :extras
|
13
|
+
|
14
|
+
##
|
15
|
+
# Register the handler and type to simplify importing
|
16
|
+
def self.register(handler, err_name)
|
17
|
+
super handler
|
18
|
+
self.err_name = err_name
|
19
|
+
@@registrations[err_name] = self
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Retreive an error class from a given name
|
24
|
+
def self.class_from_registration(err_name)
|
25
|
+
@@registrations[err_name.to_s] || self
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Factory method for instantiating the proper class
|
30
|
+
# for the error
|
31
|
+
def self.import(node)
|
32
|
+
name = node.find_first('descendant::*[name()!="text"]', 'urn:ietf:params:xml:ns:xmpp-streams').element_name
|
33
|
+
text = node.find_first 'descendant::text', 'urn:ietf:params:xml:ns:xmpp-streams'
|
34
|
+
text = text.content if text
|
35
|
+
|
36
|
+
extras = node.find("descendant::*[name()!='text' and name()!='#{name}']").map { |n| n }
|
37
|
+
|
38
|
+
class_from_registration(name).new text, extras
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# <tt>text</tt> is the (optional) error message.
|
43
|
+
# <tt>extras</tt> should be an array of nodes to attach to the error
|
44
|
+
# each extra should be in an application specific namespace
|
45
|
+
# see RFC3920 Section 4.7.2 (http://xmpp.org/rfcs/rfc3920.html#rfc.section.4.7.2)
|
46
|
+
def initialize(text = nil, extras = [])
|
47
|
+
@text = text
|
48
|
+
@extras = extras
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# XMPP defined error name
|
53
|
+
def err_name
|
54
|
+
self.class.err_name
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Creates an XML node from the error
|
59
|
+
def to_node
|
60
|
+
node = XMPPNode.new('stream:error')
|
61
|
+
|
62
|
+
err = XMPPNode.new(self.err_name)
|
63
|
+
err.namespace = 'urn:ietf:params:xml:ns:xmpp-streams'
|
64
|
+
node << err
|
65
|
+
|
66
|
+
if self.text
|
67
|
+
text = XMPPNode.new('text')
|
68
|
+
text.namespace = 'urn:ietf:params:xml:ns:xmpp-streams'
|
69
|
+
text << self.text
|
70
|
+
node << text
|
71
|
+
end
|
72
|
+
|
73
|
+
self.extras.each do |extra|
|
74
|
+
extra_copy = extra.copy
|
75
|
+
extra_copy.namespace = extra.namespace
|
76
|
+
node << extra_copy
|
77
|
+
end
|
78
|
+
node
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Turns the object into XML fit to be sent over the stream
|
83
|
+
def to_xml
|
84
|
+
to_node.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
def inspect # :nodoc:
|
88
|
+
"Stream Error (#{self.err_name}): #{self.text}"
|
89
|
+
end
|
90
|
+
alias_method :to_s, :inspect # :nodoc:
|
91
|
+
|
92
|
+
##
|
93
|
+
# The entity has sent XML that cannot be processed; this error MAY be used instead of the more specific XML-related errors,
|
94
|
+
# such as <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, and <xml-not-well-formed/>,
|
95
|
+
# although the more specific errors are preferred.
|
96
|
+
class BadFormat < StreamError
|
97
|
+
register :stream_bad_format_error, 'bad-format'
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# The entity has sent a namespace prefix that is unsupported, or has sent no namespace prefix on an element that requires
|
102
|
+
# such a prefix (see XML Namespace Names and Prefixes).
|
103
|
+
class BadNamespacePrefix < StreamError
|
104
|
+
register :stream_bad_namespace_prefix_error, 'bad-namespace-prefix'
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# The server is closing the active stream for this entity because a new stream has been initiated that conflicts with the
|
109
|
+
# existing stream.
|
110
|
+
class Conflict < StreamError
|
111
|
+
register :stream_conflict_error, 'conflict'
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# The entity has not generated any traffic over the stream for some period of time (configurable according to a local service policy).
|
116
|
+
class ConnectionTimeout < StreamError
|
117
|
+
register :stream_connection_timeout_error, 'connection-timeout'
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# The value of the 'to' attribute provided by the initiating entity in the stream header corresponds to a hostname that is no
|
122
|
+
# longer hosted by the server.
|
123
|
+
class HostGone < StreamError
|
124
|
+
register :stream_host_gone_error, 'host-gone'
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# The value of the 'to' attribute provided by the initiating entity in the stream header does not correspond to a hostname that
|
129
|
+
# is hosted by the server.
|
130
|
+
class HostUnknown < StreamError
|
131
|
+
register :stream_host_unknown_error, 'host-unknown'
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# a stanza sent between two servers lacks a 'to' or 'from' attribute (or the attribute has no value).
|
136
|
+
class ImproperAddressing < StreamError
|
137
|
+
register :stream_improper_addressing_error, 'improper-addressing'
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# The server has experienced a misconfiguration or an otherwise-undefined internal error that prevents it from servicing the stream.
|
142
|
+
class InternalServerError < StreamError
|
143
|
+
register :stream_internal_server_error, 'internal-server-error'
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# The JID or hostname provided in a 'from' address does not match an authorized JID or validated domain negotiated between
|
148
|
+
# servers via SASL or dialback, or between a client and a server via authentication and resource binding.
|
149
|
+
class InvalidFrom < StreamError
|
150
|
+
register :stream_invalid_from_error, 'invalid-from'
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# The stream ID or dialback ID is invalid or does not match an ID previously provided.
|
155
|
+
class InvalidId < StreamError
|
156
|
+
register :stream_invalid_id_error, 'invalid-id'
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# The streams namespace name is something other than "http://etherx.jabber.org/streams" or the dialback namespace name is something
|
161
|
+
# other than "jabber:server:dialback" (see XML Namespace Names and Prefixes).
|
162
|
+
class InvalidNamespace < StreamError
|
163
|
+
register :stream_invalid_namespace_error, 'invalid-namespace'
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# The entity has sent invalid XML over the stream to a server that performs validation (see Validation).
|
168
|
+
class InvalidXml < StreamError
|
169
|
+
register :stream_invalid_xml_error, 'invalid-xml'
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# The entity has attempted to send data before the stream has been authenticated, or otherwise is not authorized to perform an action
|
174
|
+
# related to stream negotiation; the receiving entity MUST NOT process the offending stanza before sending the stream error.
|
175
|
+
class NotAuthorized < StreamError
|
176
|
+
register :stream_not_authorized_error, 'not-authorized'
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# The entity has violated some local service policy; the server MAY choose to specify the policy in the <text/> element or an
|
181
|
+
# application-specific condition element.
|
182
|
+
class PolicyViolation < StreamError
|
183
|
+
register :stream_policy_violation_error, 'policy-violation'
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# The server is unable to properly connect to a remote entity that is required for authentication or authorization.
|
188
|
+
class RemoteConnectionFailed < StreamError
|
189
|
+
register :stream_remote_connection_failed_error, 'remote-connection-failed'
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# The server lacks the system resources necessary to service the stream.
|
194
|
+
class ResourceConstraint < StreamError
|
195
|
+
register :stream_resource_constraint_error, 'resource-constraint'
|
196
|
+
end
|
197
|
+
|
198
|
+
##
|
199
|
+
# The entity has attempted to send restricted XML features such as a comment, processing instruction, DTD, entity reference,
|
200
|
+
# or unescaped character (see Restrictions).
|
201
|
+
class RestrictedXml < StreamError
|
202
|
+
register :stream_restricted_xml_error, 'restricted-xml'
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# The server will not provide service to the initiating entity but is redirecting traffic to another host; the server SHOULD
|
207
|
+
# specify the alternate hostname or IP address (which MUST be a valid domain identifier) as the XML character data of the
|
208
|
+
# <see-other-host/> element.
|
209
|
+
class SeeOtherHost < StreamError
|
210
|
+
register :stream_see_other_host_error, 'see-other-host'
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# The server is being shut down and all active streams are being closed.
|
215
|
+
class SystemShutdown < StreamError
|
216
|
+
register :stream_system_shutdown_error, 'system-shutdown'
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# The error condition is not one of those defined by the other conditions in this list; this error condition SHOULD be used
|
221
|
+
# only in conjunction with an application-specific condition.
|
222
|
+
class UndefinedCondition < StreamError
|
223
|
+
register :stream_undefined_condition_error, 'undefined-condition'
|
224
|
+
end
|
225
|
+
|
226
|
+
##
|
227
|
+
# The initiating entity has encoded the stream in an encoding that is not supported by the server (see Character Encoding).
|
228
|
+
class UnsupportedEncoding < StreamError
|
229
|
+
register :stream_unsupported_encoding_error, 'unsupported-encoding'
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# The initiating entity has sent a first-level child of the stream that is not supported by the server.
|
234
|
+
class UnsupportedStanzaType < StreamError
|
235
|
+
register :stream_unsupported_stanza_type_error, 'unsupported-stanza-type'
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# The value of the 'version' attribute provided by the initiating entity in the stream header specifies a version of XMPP
|
240
|
+
# That is not supported by the server; the server MAY specify the version(s) it supports in the <text/> element.
|
241
|
+
class UnsupportedVersion < StreamError
|
242
|
+
register :stream_unsupported_version_error, 'unsupported-version'
|
243
|
+
end
|
244
|
+
|
245
|
+
##
|
246
|
+
# The initiating entity has sent XML that is not well-formed as defined by [XML].
|
247
|
+
class XmlNotWellFormed < StreamError
|
248
|
+
register :stream_xml_not_well_formed_error, 'xml-not-well-formed'
|
249
|
+
end
|
250
|
+
|
251
|
+
end #StreamError
|
252
|
+
|
253
|
+
end #Blather
|
data/lib/blather/jid.rb
CHANGED
@@ -5,24 +5,23 @@ module Blather
|
|
5
5
|
class JID
|
6
6
|
include Comparable
|
7
7
|
|
8
|
-
PATTERN = /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))
|
9
|
-
|
10
|
-
begin
|
11
|
-
require 'idn'
|
12
|
-
USE_STRINGPREP = true
|
13
|
-
rescue LoadError
|
14
|
-
USE_STRINGPREP = false
|
15
|
-
end
|
8
|
+
PATTERN = /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/.freeze
|
16
9
|
|
10
|
+
##
|
17
11
|
# Get the JID's node
|
18
12
|
attr_reader :node
|
19
13
|
|
14
|
+
##
|
20
15
|
# Get the JID's domain
|
21
16
|
attr_reader :domain
|
22
17
|
|
18
|
+
##
|
23
19
|
# Get the JID's resource
|
24
20
|
attr_reader :resource
|
25
21
|
|
22
|
+
##
|
23
|
+
# If a JID is passed in just return it.
|
24
|
+
# No need to copy out all the values
|
26
25
|
def self.new(node, domain = nil, resource = nil)
|
27
26
|
node.is_a?(JID) ? node : super
|
28
27
|
end
|
@@ -39,14 +38,8 @@ module Blather
|
|
39
38
|
@node, @domain, @resource = @node.to_s.scan(PATTERN).first
|
40
39
|
end
|
41
40
|
|
42
|
-
if
|
43
|
-
|
44
|
-
@domain = IDN::Stringprep.nameprep(@domain) if @domain
|
45
|
-
@resource = IDN::Stringprep.resourceprep(@resource) if @resource
|
46
|
-
else
|
47
|
-
@node.downcase! if @node
|
48
|
-
@domain.downcase! if @domain
|
49
|
-
end
|
41
|
+
@node.downcase! if @node
|
42
|
+
@domain.downcase! if @domain
|
50
43
|
|
51
44
|
raise ArgumentError, 'Node too long' if (@node || '').length > 1023
|
52
45
|
raise ArgumentError, 'Domain too long' if (@domain || '').length > 1023
|
data/lib/blather/roster.rb
CHANGED
@@ -71,6 +71,15 @@ module Blather
|
|
71
71
|
@items.dup
|
72
72
|
end
|
73
73
|
|
74
|
+
##
|
75
|
+
# A hash of items keyed by group
|
76
|
+
def grouped
|
77
|
+
self.inject(Hash.new{|h,k|h[k]=[]}) do |hash, item|
|
78
|
+
item[1].groups.each { |group| hash[group] << item[1] }
|
79
|
+
hash
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
74
83
|
private
|
75
84
|
def self.key(jid)
|
76
85
|
JID.new(jid).stripped.to_s
|
data/lib/blather/roster_item.rb
CHANGED
@@ -17,6 +17,7 @@ module Blather
|
|
17
17
|
# item:: can be a JID, String (a@b) or a Stanza
|
18
18
|
def initialize(item)
|
19
19
|
@statuses = []
|
20
|
+
@groups = []
|
20
21
|
|
21
22
|
case item
|
22
23
|
when JID
|
@@ -24,12 +25,14 @@ module Blather
|
|
24
25
|
when String
|
25
26
|
self.jid = JID.new(item).stripped
|
26
27
|
when XMPPNode
|
27
|
-
self.jid = JID.new(item[
|
28
|
-
self.name = item[
|
29
|
-
self.subscription = item[
|
30
|
-
self.ask = item[
|
28
|
+
self.jid = JID.new(item[:jid]).stripped
|
29
|
+
self.name = item[:name]
|
30
|
+
self.subscription = item[:subscription]
|
31
|
+
self.ask = item[:ask]
|
31
32
|
item.groups.each { |g| self.groups << g }
|
32
33
|
end
|
34
|
+
|
35
|
+
@groups = [nil] if @groups.empty?
|
33
36
|
end
|
34
37
|
|
35
38
|
##
|
data/lib/blather/stanza.rb
CHANGED
@@ -3,6 +3,7 @@ module Blather
|
|
3
3
|
# Base XMPP Stanza
|
4
4
|
class Stanza < XMPPNode
|
5
5
|
@@last_id = 0
|
6
|
+
@@handler_list = []
|
6
7
|
|
7
8
|
class_inheritable_array :handler_heirarchy
|
8
9
|
|
@@ -13,12 +14,17 @@ module Blather
|
|
13
14
|
# that inherits Stanza can register a callback for itself
|
14
15
|
# which is added to a list and iterated over when looking for
|
15
16
|
# a callback to use
|
16
|
-
def self.register(type, name = nil,
|
17
|
+
def self.register(type, name = nil, ns = nil)
|
18
|
+
@@handler_list << type
|
17
19
|
self.handler_heirarchy ||= []
|
18
20
|
self.handler_heirarchy.unshift type
|
19
21
|
|
20
22
|
name = name || self.name || type
|
21
|
-
super name,
|
23
|
+
super name, ns
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.handler_list
|
27
|
+
@@handler_list
|
22
28
|
end
|
23
29
|
|
24
30
|
##
|
@@ -65,43 +71,31 @@ module Blather
|
|
65
71
|
self
|
66
72
|
end
|
67
73
|
|
68
|
-
|
69
|
-
attributes['id'] = id
|
70
|
-
end
|
71
|
-
|
72
|
-
def id
|
73
|
-
attributes['id']
|
74
|
-
end
|
74
|
+
attribute_accessor :id, :to_sym => false
|
75
75
|
|
76
|
-
|
77
|
-
attributes['to'] = to
|
78
|
-
end
|
76
|
+
attribute_writer :to, :from
|
79
77
|
|
80
78
|
##
|
81
79
|
# returns:: JID created from the "to" value of the stanza
|
82
80
|
def to
|
83
|
-
JID.new(attributes[
|
84
|
-
end
|
85
|
-
|
86
|
-
def from=(from)
|
87
|
-
attributes['from'] = from
|
81
|
+
JID.new(attributes[:to]) if attributes[:to]
|
88
82
|
end
|
89
83
|
|
90
84
|
##
|
91
85
|
# returns:: JID created from the "from" value of the stanza
|
92
86
|
def from
|
93
|
-
JID.new(attributes[
|
87
|
+
JID.new(attributes[:from]) if attributes[:from]
|
94
88
|
end
|
95
89
|
|
96
|
-
|
97
|
-
attributes['type'] = type
|
98
|
-
end
|
90
|
+
attribute_accessor :type
|
99
91
|
|
100
92
|
##
|
101
|
-
#
|
102
|
-
|
103
|
-
|
93
|
+
# Transform the stanza into a stanza error
|
94
|
+
# <tt>err_name_or_class</tt> can be the name of the error or the error class to use
|
95
|
+
# <tt>type</tt>, <tt>text</tt>, <tt>extras</tt> are the same as for StanzaError#new
|
96
|
+
def as_error(err_name_or_class, type, text = nil, extras = [])
|
97
|
+
klass = (err_name_or_class.is_a?(Class) ? err_name_or_class : StanzaError.class_from_registration(err_name_or_class))
|
98
|
+
klass.new self, type, text, extras
|
104
99
|
end
|
105
|
-
|
106
100
|
end
|
107
101
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Blather
|
2
|
+
class Stanza
|
3
|
+
|
4
|
+
##
|
5
|
+
# DiscoInfo object ()
|
6
|
+
#
|
7
|
+
class DiscoInfo < Disco
|
8
|
+
register :disco_info, nil, 'http://jabber.org/protocol/disco#info'
|
9
|
+
|
10
|
+
def initialize(type = nil, node = nil, identities = [], features = [])
|
11
|
+
super type
|
12
|
+
|
13
|
+
self.node = node
|
14
|
+
|
15
|
+
[identities].flatten.each do |id|
|
16
|
+
query << (id.is_a?(Identity) ? id : Identity.new(id[:name], id[:type], id[:category]))
|
17
|
+
end
|
18
|
+
|
19
|
+
[features].flatten.each do |feature|
|
20
|
+
query << (feature.is_a?(Feature) ? feature : Feature.new(feature))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# List of identity objects
|
26
|
+
def identities
|
27
|
+
identities = query.find('identity')
|
28
|
+
identities = query.find('query_ns:identity', :query_ns => self.class.ns) if identities.empty?
|
29
|
+
identities.map { |i| Identity.new i }
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# List of feature objects
|
34
|
+
def features
|
35
|
+
features = query.find('feature')
|
36
|
+
features = query.find('query_ns:feature', :query_ns => self.class.ns) if features.empty?
|
37
|
+
features.map { |i| Feature.new i }
|
38
|
+
end
|
39
|
+
|
40
|
+
class Identity < XMPPNode
|
41
|
+
attribute_accessor :category, :type
|
42
|
+
attribute_accessor :name, :to_sym => false
|
43
|
+
|
44
|
+
def initialize(name, type = nil, category = nil)
|
45
|
+
super :identity
|
46
|
+
|
47
|
+
if name.is_a?(XML::Node)
|
48
|
+
self.inherit name
|
49
|
+
else
|
50
|
+
self.name = name
|
51
|
+
self.type = type
|
52
|
+
self.category = category
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def eql?(other)
|
57
|
+
other.kind_of?(self.class) &&
|
58
|
+
other.name == self.name &&
|
59
|
+
other.type == self.type &&
|
60
|
+
other.category == self.category
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Feature < XMPPNode
|
65
|
+
attribute_accessor :var, :to_sym => false
|
66
|
+
|
67
|
+
def initialize(var)
|
68
|
+
super :feature
|
69
|
+
if var.is_a?(XML::Node)
|
70
|
+
self.inherit var
|
71
|
+
else
|
72
|
+
self.var = var
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def eql?(other)
|
77
|
+
other.kind_of?(self.class) &&
|
78
|
+
other.var == self.var
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end #Stanza
|
84
|
+
end #Blather
|