blather 0.3.4 → 0.4.0
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 +1 -1
- data/README.rdoc +41 -12
- data/examples/echo.rb +1 -1
- data/examples/execute.rb +0 -5
- data/examples/pubsub/cli.rb +64 -0
- data/examples/pubsub/ping_pong.rb +18 -0
- data/examples/rosterprint.rb +14 -0
- data/examples/xmpp4r/echo.rb +35 -0
- data/lib/blather.rb +35 -12
- data/lib/blather/client.rb +1 -1
- data/lib/blather/client/client.rb +19 -13
- data/lib/blather/client/dsl.rb +16 -0
- data/lib/blather/client/dsl/pubsub.rb +133 -0
- data/lib/blather/core_ext/active_support.rb +1 -117
- data/lib/blather/core_ext/active_support/inheritable_attributes.rb +117 -0
- data/lib/blather/core_ext/nokogiri.rb +35 -0
- data/lib/blather/errors.rb +3 -20
- data/lib/blather/errors/sasl_error.rb +3 -1
- data/lib/blather/errors/stanza_error.rb +10 -17
- data/lib/blather/errors/stream_error.rb +11 -14
- data/lib/blather/jid.rb +1 -0
- data/lib/blather/roster.rb +9 -0
- data/lib/blather/roster_item.rb +6 -1
- data/lib/blather/stanza.rb +35 -18
- data/lib/blather/stanza/disco.rb +7 -1
- data/lib/blather/stanza/disco/disco_info.rb +45 -33
- data/lib/blather/stanza/disco/disco_items.rb +32 -21
- data/lib/blather/stanza/iq.rb +13 -8
- data/lib/blather/stanza/iq/query.rb +16 -8
- data/lib/blather/stanza/iq/roster.rb +33 -22
- data/lib/blather/stanza/message.rb +20 -31
- data/lib/blather/stanza/presence.rb +3 -5
- data/lib/blather/stanza/presence/status.rb +13 -21
- data/lib/blather/stanza/presence/subscription.rb +11 -16
- data/lib/blather/stanza/pubsub.rb +63 -0
- data/lib/blather/stanza/pubsub/affiliations.rb +50 -0
- data/lib/blather/stanza/pubsub/create.rb +43 -0
- data/lib/blather/stanza/pubsub/errors.rb +9 -0
- data/lib/blather/stanza/pubsub/event.rb +77 -0
- data/lib/blather/stanza/pubsub/items.rb +63 -0
- data/lib/blather/stanza/pubsub/publish.rb +58 -0
- data/lib/blather/stanza/pubsub/retract.rb +53 -0
- data/lib/blather/stanza/pubsub/subscribe.rb +42 -0
- data/lib/blather/stanza/pubsub/subscription.rb +66 -0
- data/lib/blather/stanza/pubsub/subscriptions.rb +55 -0
- data/lib/blather/stanza/pubsub/unsubscribe.rb +42 -0
- data/lib/blather/stanza/pubsub_owner.rb +41 -0
- data/lib/blather/stanza/pubsub_owner/delete.rb +34 -0
- data/lib/blather/stanza/pubsub_owner/purge.rb +34 -0
- data/lib/blather/stream.rb +76 -168
- data/lib/blather/stream/client.rb +1 -2
- data/lib/blather/stream/component.rb +9 -5
- data/lib/blather/stream/features.rb +53 -0
- data/lib/blather/stream/features/resource.rb +63 -0
- data/lib/blather/stream/{sasl.rb → features/sasl.rb} +53 -52
- data/lib/blather/stream/features/session.rb +44 -0
- data/lib/blather/stream/features/tls.rb +28 -0
- data/lib/blather/stream/parser.rb +70 -46
- data/lib/blather/xmpp_node.rb +113 -52
- data/spec/blather/client/client_spec.rb +44 -58
- data/spec/blather/client/dsl/pubsub_spec.rb +465 -0
- data/spec/blather/client/dsl_spec.rb +19 -6
- data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
- data/spec/blather/errors/sasl_error_spec.rb +8 -8
- data/spec/blather/errors/stanza_error_spec.rb +25 -33
- data/spec/blather/errors/stream_error_spec.rb +21 -16
- data/spec/blather/errors_spec.rb +4 -11
- data/spec/blather/jid_spec.rb +31 -30
- data/spec/blather/roster_item_spec.rb +34 -23
- data/spec/blather/roster_spec.rb +27 -12
- data/spec/blather/stanza/discos/disco_info_spec.rb +61 -42
- data/spec/blather/stanza/discos/disco_items_spec.rb +47 -35
- data/spec/blather/stanza/iq/query_spec.rb +34 -11
- data/spec/blather/stanza/iq/roster_spec.rb +47 -30
- data/spec/blather/stanza/iq_spec.rb +19 -14
- data/spec/blather/stanza/message_spec.rb +30 -17
- data/spec/blather/stanza/presence/status_spec.rb +43 -20
- data/spec/blather/stanza/presence/subscription_spec.rb +41 -21
- data/spec/blather/stanza/presence_spec.rb +34 -21
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
- data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
- data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
- data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
- data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
- data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
- data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
- data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
- data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
- data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
- data/spec/blather/stanza/pubsub_spec.rb +62 -0
- data/spec/blather/stanza_spec.rb +53 -38
- data/spec/blather/stream/client_spec.rb +231 -88
- data/spec/blather/stream/component_spec.rb +14 -5
- data/spec/blather/stream/parser_spec.rb +145 -0
- data/spec/blather/xmpp_node_spec.rb +192 -96
- data/spec/fixtures/pubsub.rb +311 -0
- data/spec/spec_helper.rb +5 -4
- metadata +54 -18
- data/Rakefile +0 -139
- data/ext/extconf.rb +0 -65
- data/ext/push_parser.c +0 -209
- data/lib/blather/core_ext/libxml.rb +0 -28
- data/lib/blather/stream/resource.rb +0 -48
- data/lib/blather/stream/session.rb +0 -36
- data/lib/blather/stream/stream_handler.rb +0 -39
- data/lib/blather/stream/tls.rb +0 -33
- data/spec/blather/core_ext/libxml_spec.rb +0 -58
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Blather
|
|
2
|
+
class Stanza
|
|
3
|
+
class PubSubOwner
|
|
4
|
+
|
|
5
|
+
class Purge < PubSubOwner
|
|
6
|
+
|
|
7
|
+
register :pubsub_purge, :purge, self.registered_ns
|
|
8
|
+
|
|
9
|
+
def self.new(type = :set, host = nil, node = nil)
|
|
10
|
+
new_node = super(type, host)
|
|
11
|
+
new_node.node = node
|
|
12
|
+
new_node
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def node
|
|
16
|
+
purge_node[:node]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def node=(node)
|
|
20
|
+
purge_node[:node] = node
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def purge_node
|
|
24
|
+
unless purge_node = pubsub.find_first('ns:purge', :ns => self.class.registered_ns)
|
|
25
|
+
self.pubsub << (purge_node = XMPPNode.new('purge', self.document))
|
|
26
|
+
purge_node.namespace = self.pubsub.namespace
|
|
27
|
+
end
|
|
28
|
+
purge_node
|
|
29
|
+
end
|
|
30
|
+
end #Retract
|
|
31
|
+
|
|
32
|
+
end #PubSub
|
|
33
|
+
end #Stanza
|
|
34
|
+
end #Blather
|
data/lib/blather/stream.rb
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
module Blather
|
|
2
2
|
|
|
3
3
|
class Stream < EventMachine::Connection
|
|
4
|
+
class NoConnection < RuntimeError; end
|
|
5
|
+
|
|
6
|
+
STREAM_NS = 'http://etherx.jabber.org/streams'
|
|
7
|
+
attr_accessor :jid, :password
|
|
8
|
+
|
|
4
9
|
##
|
|
5
10
|
# Start the stream between client and server
|
|
6
11
|
# [client] must be an object that will respond to #call and #jid=
|
|
@@ -10,9 +15,35 @@ module Blather
|
|
|
10
15
|
# [port] (optional) must be the port to connect to. defaults to 5222
|
|
11
16
|
def self.start(client, jid, pass, host = nil, port = 5222)
|
|
12
17
|
jid = JID.new jid
|
|
13
|
-
host
|
|
18
|
+
if host
|
|
19
|
+
connect host, port, self, client, jid, pass
|
|
20
|
+
else
|
|
21
|
+
require 'resolv'
|
|
22
|
+
srv = []
|
|
23
|
+
Resolv::DNS.open { |dns| srv = dns.getresources("_xmpp-client._tcp.#{jid.domain}", Resolv::DNS::Resource::IN::SRV) }
|
|
24
|
+
if srv.empty?
|
|
25
|
+
connect jid.domain, port, self, client, jid, pass
|
|
26
|
+
else
|
|
27
|
+
srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
|
|
28
|
+
conn = nil
|
|
29
|
+
srv.each { |r| break unless (conn = connect(r.target.to_s, r.port, self, client, jid, pass)) === false }
|
|
30
|
+
conn
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
14
34
|
|
|
15
|
-
|
|
35
|
+
##
|
|
36
|
+
# Attempt a connection
|
|
37
|
+
# Stream will raise +NoConnection+ if it receives #unbind before #post_init
|
|
38
|
+
# this catches that and returns false prompting for another attempt
|
|
39
|
+
def self.connect(host, port, conn, client, jid, pass)
|
|
40
|
+
EM.connect host, port, conn, client, jid, pass
|
|
41
|
+
rescue NoConnection
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
[:started, :stopped, :ready, :negotiating].each do |state|
|
|
46
|
+
define_method("#{state}?") { @state == state }
|
|
16
47
|
end
|
|
17
48
|
|
|
18
49
|
##
|
|
@@ -21,73 +52,53 @@ module Blather
|
|
|
21
52
|
# responds to #to_s
|
|
22
53
|
def send(stanza)
|
|
23
54
|
#TODO Queue if not ready
|
|
24
|
-
|
|
55
|
+
Blather.logger.debug "SENDING: (#{caller[1]}) #{stanza}"
|
|
25
56
|
send_data stanza.respond_to?(:to_xml) ? stanza.to_xml : stanza.to_s
|
|
26
57
|
end
|
|
27
58
|
|
|
28
|
-
##
|
|
29
|
-
# True if the stream is in the stopped state
|
|
30
|
-
def stopped?
|
|
31
|
-
@state == :stopped
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
##
|
|
35
|
-
# True when the stream is in the negotiation phase.
|
|
36
|
-
def negotiating?
|
|
37
|
-
![:stopped, :ready].include? @state
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
##
|
|
41
|
-
# True when the stream is ready
|
|
42
|
-
# The stream is ready immediately after receiving <stream:stream>
|
|
43
|
-
# and before any feature negotion. Once feature negoation starts
|
|
44
|
-
# the stream will not be ready until all negotations have completed
|
|
45
|
-
# successfully.
|
|
46
|
-
def ready?
|
|
47
|
-
@state == :ready
|
|
48
|
-
end
|
|
49
|
-
|
|
50
59
|
##
|
|
51
60
|
# Called by EM.connect to initialize stream variables
|
|
52
61
|
def initialize(client, jid, pass) # :nodoc:
|
|
53
62
|
super()
|
|
54
63
|
|
|
55
64
|
@error = nil
|
|
56
|
-
@client = client
|
|
65
|
+
@receiver = @client = client
|
|
57
66
|
|
|
58
67
|
self.jid = jid
|
|
59
|
-
@
|
|
60
|
-
|
|
61
|
-
@to = @jid.domain
|
|
68
|
+
@to = self.jid.domain
|
|
69
|
+
@password = pass
|
|
62
70
|
end
|
|
63
71
|
|
|
64
72
|
##
|
|
65
73
|
# Called when EM completes the connection to the server
|
|
66
74
|
# this kicks off the starttls/authorize/bind process
|
|
67
75
|
def connection_completed # :nodoc:
|
|
68
|
-
# @keepalive = EM::
|
|
69
|
-
|
|
70
|
-
dispatch
|
|
76
|
+
# @keepalive = EM::PeriodicTimer.new(60) { send_data ' ' }
|
|
77
|
+
start
|
|
71
78
|
end
|
|
72
79
|
|
|
73
80
|
##
|
|
74
81
|
# Called by EM with data from the wire
|
|
75
82
|
def receive_data(data) # :nodoc:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
@parser
|
|
83
|
+
Blather.logger.debug "\n#{'-'*30}\n"
|
|
84
|
+
Blather.logger.debug "<< #{data}"
|
|
85
|
+
@parser << data
|
|
79
86
|
|
|
80
|
-
rescue ParseWarning => e
|
|
81
|
-
@client.receive_data e
|
|
82
87
|
rescue ParseError => e
|
|
83
88
|
@error = e
|
|
84
|
-
send "<stream:error><xml-not-well-formed xmlns='
|
|
89
|
+
send "<stream:error><xml-not-well-formed xmlns='#{StreamError::STREAM_ERR_NS}'/></stream:error>"
|
|
85
90
|
stop
|
|
86
91
|
end
|
|
87
92
|
|
|
93
|
+
def post_init
|
|
94
|
+
@connected = true
|
|
95
|
+
end
|
|
96
|
+
|
|
88
97
|
##
|
|
89
98
|
# Called by EM when the connection is closed
|
|
90
99
|
def unbind # :nodoc:
|
|
100
|
+
raise NoConnection unless @connected
|
|
101
|
+
|
|
91
102
|
# @keepalive.cancel
|
|
92
103
|
@state = :stopped
|
|
93
104
|
@client.receive_data @error if @error
|
|
@@ -97,54 +108,41 @@ module Blather
|
|
|
97
108
|
##
|
|
98
109
|
# Called by the parser with parsed nodes
|
|
99
110
|
def receive(node) # :nodoc:
|
|
100
|
-
|
|
111
|
+
Blather.logger.debug "RECEIVING (#{node.element_name}) #{node}"
|
|
101
112
|
@node = node
|
|
102
113
|
|
|
103
|
-
if @node.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
114
|
+
if @node.namespace && @node.namespace.prefix == 'stream'
|
|
115
|
+
case @node.element_name
|
|
116
|
+
when 'stream'
|
|
117
|
+
@state = :ready if @state == :stopped
|
|
118
|
+
return
|
|
119
|
+
when 'error'
|
|
120
|
+
handle_stream_error
|
|
121
|
+
return
|
|
122
|
+
when 'end'
|
|
123
|
+
stop
|
|
124
|
+
return
|
|
125
|
+
when 'features'
|
|
126
|
+
@state = :negotiating
|
|
127
|
+
@receiver = Features.new(
|
|
128
|
+
self,
|
|
129
|
+
proc { ready! },
|
|
130
|
+
proc { |err| @error = err; stop }
|
|
131
|
+
)
|
|
132
|
+
end
|
|
123
133
|
end
|
|
134
|
+
@receiver.receive_data @node.to_stanza
|
|
124
135
|
end
|
|
125
136
|
|
|
126
137
|
##
|
|
127
138
|
# Ensure the JID gets attached to the client
|
|
128
139
|
def jid=(new_jid) # :nodoc:
|
|
129
|
-
|
|
140
|
+
Blather.logger.debug "NEW JID: #{new_jid}"
|
|
130
141
|
@jid = JID.new new_jid
|
|
131
142
|
@client.jid = @jid
|
|
132
143
|
end
|
|
133
144
|
|
|
134
145
|
protected
|
|
135
|
-
##
|
|
136
|
-
# Dispatch based on current state
|
|
137
|
-
def dispatch
|
|
138
|
-
__send__ @state
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
##
|
|
142
|
-
# Start the stream
|
|
143
|
-
# Each time the stream is started or re-started we need to kill off the old
|
|
144
|
-
# parser so as not to confuse it
|
|
145
|
-
def start
|
|
146
|
-
end
|
|
147
|
-
|
|
148
146
|
##
|
|
149
147
|
# Stop the stream
|
|
150
148
|
def stop
|
|
@@ -154,105 +152,15 @@ module Blather
|
|
|
154
152
|
end
|
|
155
153
|
end
|
|
156
154
|
|
|
157
|
-
##
|
|
158
|
-
# Called when @state == :stopped to start the stream
|
|
159
|
-
# Counter intuitive, I know
|
|
160
|
-
def stopped
|
|
161
|
-
start
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
##
|
|
165
|
-
# Called when @state == :ready
|
|
166
|
-
# Simply passes the stanza to the client
|
|
167
|
-
def ready
|
|
168
|
-
@client.receive_data @node.to_stanza
|
|
169
|
-
end
|
|
170
|
-
|
|
171
155
|
def handle_stream_error
|
|
172
|
-
@error = StreamError.import
|
|
156
|
+
@error = StreamError.import(@node)
|
|
173
157
|
stop
|
|
174
|
-
@state = :error
|
|
175
158
|
end
|
|
176
159
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
feature = @features.first
|
|
182
|
-
LOG.debug "FEATURE: #{feature}"
|
|
183
|
-
@state = case feature ? feature.namespaces.default.href : nil
|
|
184
|
-
when 'urn:ietf:params:xml:ns:xmpp-tls' then :establish_tls
|
|
185
|
-
when 'urn:ietf:params:xml:ns:xmpp-sasl' then :authenticate_sasl
|
|
186
|
-
when 'urn:ietf:params:xml:ns:xmpp-bind' then :bind_resource
|
|
187
|
-
when 'urn:ietf:params:xml:ns:xmpp-session' then :establish_session
|
|
188
|
-
else :ready
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# Dispatch to the individual feature methods unless
|
|
192
|
-
# feature negotiation is complete
|
|
193
|
-
dispatch unless ready?
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
##
|
|
197
|
-
# Start TLS
|
|
198
|
-
def establish_tls
|
|
199
|
-
unless @tls
|
|
200
|
-
@tls = TLS.new self
|
|
201
|
-
# on success destroy the TLS object and restart the stream
|
|
202
|
-
@tls.on_success { LOG.debug "TLS: SUCCESS"; @tls = nil; start }
|
|
203
|
-
# on failure stop the stream
|
|
204
|
-
@tls.on_failure { |err| LOG.debug "TLS: FAILURE"; @error = err; stop }
|
|
205
|
-
|
|
206
|
-
@node = @features.shift
|
|
207
|
-
end
|
|
208
|
-
@tls.handle @node
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
##
|
|
212
|
-
# Authenticate via SASL
|
|
213
|
-
def authenticate_sasl
|
|
214
|
-
unless @sasl
|
|
215
|
-
@sasl = SASL.new(self, @jid, @pass)
|
|
216
|
-
# on success destroy the SASL object and restart the stream
|
|
217
|
-
@sasl.on_success { LOG.debug "SASL SUCCESS"; @sasl = nil; start }
|
|
218
|
-
# on failure set the error and stop the stream
|
|
219
|
-
@sasl.on_failure { |err| LOG.debug "SASL FAIL"; @error = err; stop }
|
|
220
|
-
|
|
221
|
-
@node = @features.shift
|
|
222
|
-
end
|
|
223
|
-
@sasl.handle @node
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
##
|
|
227
|
-
# Bind to the resource provided by either the client or the server
|
|
228
|
-
def bind_resource
|
|
229
|
-
unless @resource
|
|
230
|
-
@resource = Resource.new self, @jid
|
|
231
|
-
# on success destroy the Resource object, set the jid, continue along the features dispatch process
|
|
232
|
-
@resource.on_success { |jid| LOG.debug "RESOURCE: SUCCESS"; @resource = nil; self.jid = jid; @state = :features; dispatch }
|
|
233
|
-
# on failure end the stream
|
|
234
|
-
@resource.on_failure { |err| LOG.debug "RESOURCE: FAILURE"; @error = err; stop }
|
|
235
|
-
|
|
236
|
-
@node = @features.shift
|
|
237
|
-
end
|
|
238
|
-
@resource.handle @node
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
##
|
|
242
|
-
# Establish the session between client and server
|
|
243
|
-
def establish_session
|
|
244
|
-
unless @session
|
|
245
|
-
@session = Session.new self, @to
|
|
246
|
-
# on success destroy the session object, let the client know the stream has been started
|
|
247
|
-
# then continue the features dispatch process
|
|
248
|
-
@session.on_success { LOG.debug "SESSION: SUCCESS"; @session = nil; @client.post_init; @state = :features; dispatch }
|
|
249
|
-
# on failure end the stream
|
|
250
|
-
@session.on_failure { |err| LOG.debug "SESSION: FAILURE"; @error = err; stop }
|
|
251
|
-
|
|
252
|
-
@node = @features.shift
|
|
253
|
-
end
|
|
254
|
-
@session.handle @node
|
|
160
|
+
def ready!
|
|
161
|
+
@state = :started
|
|
162
|
+
@receiver = @client
|
|
163
|
+
@client.post_init
|
|
255
164
|
end
|
|
256
165
|
end
|
|
257
|
-
|
|
258
166
|
end
|
|
@@ -6,14 +6,13 @@ class Stream
|
|
|
6
6
|
VERSION = '1.0'
|
|
7
7
|
NAMESPACE = 'jabber:client'
|
|
8
8
|
|
|
9
|
-
protected
|
|
10
9
|
def start
|
|
11
10
|
@parser = Parser.new self
|
|
12
11
|
start_stream = <<-STREAM
|
|
13
12
|
<stream:stream
|
|
14
13
|
to='#{@to}'
|
|
15
14
|
xmlns='#{NAMESPACE}'
|
|
16
|
-
xmlns:stream='
|
|
15
|
+
xmlns:stream='#{STREAM_NS}'
|
|
17
16
|
version='#{VERSION}'
|
|
18
17
|
xml:lang='#{LANG}'
|
|
19
18
|
>
|
|
@@ -6,24 +6,28 @@ class Stream
|
|
|
6
6
|
|
|
7
7
|
def receive(node) # :nodoc:
|
|
8
8
|
if node.element_name == 'handshake'
|
|
9
|
-
|
|
9
|
+
ready!
|
|
10
10
|
else
|
|
11
11
|
super
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
if node.
|
|
15
|
-
send("<handshake>#{Digest::SHA1.hexdigest(@node['id']+@
|
|
14
|
+
if node.document.find_first('/stream:stream[not(stream:error)]', :xmlns => NAMESPACE, :stream => STREAM_NS)
|
|
15
|
+
send("<handshake>#{Digest::SHA1.hexdigest(@node['id']+@password)}</handshake>")
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
def send(stanza)
|
|
20
|
+
stanza.from ||= self.jid if stanza.respond_to?(:from) && stanza.respond_to?(:from=)
|
|
21
|
+
super stanza
|
|
22
|
+
end
|
|
23
|
+
|
|
20
24
|
def start
|
|
21
25
|
@parser = Parser.new self
|
|
22
26
|
start_stream = <<-STREAM
|
|
23
27
|
<stream:stream
|
|
24
28
|
to='#{@jid}'
|
|
25
29
|
xmlns='#{NAMESPACE}'
|
|
26
|
-
xmlns:stream='
|
|
30
|
+
xmlns:stream='#{STREAM_NS}'
|
|
27
31
|
>
|
|
28
32
|
STREAM
|
|
29
33
|
send start_stream.gsub(/\s+/, ' ')
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Blather # :nodoc:
|
|
2
|
+
class Stream # :nodoc:
|
|
3
|
+
|
|
4
|
+
class Features
|
|
5
|
+
@@features = {}
|
|
6
|
+
def self.register(ns)
|
|
7
|
+
@@features[ns] = self
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.from_namespace(ns)
|
|
11
|
+
@@features[ns]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(stream, succeed, fail)
|
|
15
|
+
@stream = stream
|
|
16
|
+
@succeed = succeed
|
|
17
|
+
@fail = fail
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def receive_data(stanza)
|
|
21
|
+
if @feature
|
|
22
|
+
@feature.receive_data stanza
|
|
23
|
+
else
|
|
24
|
+
@features ||= stanza
|
|
25
|
+
next!
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def next!
|
|
30
|
+
@idx = @idx ? @idx+1 : 0
|
|
31
|
+
if stanza = @features.children[@idx]
|
|
32
|
+
if stanza.namespaces['xmlns'] && (klass = self.class.from_namespace(stanza.namespaces['xmlns']))
|
|
33
|
+
@feature = klass.new @stream, proc { next! }, @fail
|
|
34
|
+
@feature.receive_data stanza
|
|
35
|
+
else
|
|
36
|
+
next!
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
succeed!
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def succeed!
|
|
44
|
+
@succeed.call
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def fail!(msg)
|
|
48
|
+
@fail.call msg
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end #Stream
|
|
53
|
+
end #Blather
|