blather 0.2.1 → 0.2.2
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.
- 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
|