em-xmpp 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,183 @@
1
+
2
+ require 'em-xmpp/namespaces'
3
+ require 'em-xmpp/entity'
4
+ require 'em-xmpp/handler'
5
+ require 'em-xmpp/xml_builder'
6
+ require 'em-xmpp/xml_parser'
7
+ require 'em-xmpp/cert_store'
8
+ require 'fiber'
9
+
10
+ module EM::Xmpp
11
+ module Evented
12
+ include Namespaces
13
+ include XmlBuilder
14
+ include XmlParser
15
+ def component?
16
+ @component
17
+ end
18
+
19
+ def jid_received(jid)
20
+ @jid = entity jid
21
+ end
22
+
23
+ def entity(jid)
24
+ Entity.new(self, jid)
25
+ end
26
+
27
+ def default_presence_params
28
+ {}
29
+ end
30
+
31
+ def default_message_params
32
+ {'to' => @jid.domain, 'id' => "em-xmpp.#{rand(65535)}"}
33
+ end
34
+
35
+ def default_iq_params
36
+ {'type' => 'get', 'id' => "em-xmpp.#{rand(65535)}"}
37
+ end
38
+
39
+ def presence_stanza(*args,&blk)
40
+ OutgoingStanza.new('presence', default_presence_params, *args,&blk)
41
+ end
42
+
43
+ def message_stanza(*args,&blk)
44
+ OutgoingStanza.new('message',default_message_params,*args,&blk)
45
+ end
46
+
47
+ def iq_stanza(*args,&blk)
48
+ OutgoingStanza.new('iq', default_iq_params, *args,&blk)
49
+ end
50
+
51
+ def send_stanza(stanza)
52
+ send_raw stanza.xml
53
+ if block_given?
54
+ upon(:anything) do |ctx|
55
+ if ctx.bit(:stanza).id == stanza.params['id']
56
+ yield ctx
57
+ ctx.delete_xpath_handler!
58
+ else
59
+ ctx
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ %w{upon on on_exception on_presence on_iq on_message on_decorator on_iq_decorator on_presence_decorator on_message_decorator}.each do |meth|
66
+ define_method(meth) do |*args,&blk|
67
+ @handler.send meth, *args, &blk
68
+ end
69
+ end
70
+
71
+
72
+ # XML (stanzas) stream
73
+
74
+ def ready
75
+ end
76
+
77
+ def stream_start(node)
78
+ end
79
+
80
+ def stanza_start(node)
81
+ end
82
+
83
+ def stanza_end(node)
84
+ Fiber.new { @handler.handle(node) }.resume
85
+ end
86
+
87
+ def unhandled_stanza(node)
88
+ raise RuntimeError, "did not handle node:\n#{node}"
89
+ end
90
+
91
+ def ssl_verify_peer(pem)
92
+ @certstore.trusted?(pem).tap do |trusted|
93
+ close_connection unless trusted
94
+ end
95
+ end
96
+
97
+ def receive_raw(dat)
98
+ @xml_parser << dat
99
+ end
100
+
101
+ def prepare_parser!
102
+ @xml_parser = ForwardingParser.new self
103
+ @stack = []
104
+ @stanza = nil
105
+ @streamdoc = nil
106
+
107
+ open_xml_stream
108
+ end
109
+
110
+ def restart_xml_stream
111
+ #make sure we stop receiving methods from the old parser
112
+ @xml_parser.document.recipient = nil
113
+ prepare_parser!
114
+ end
115
+
116
+ def send_xml(*args)
117
+ send_raw build_xml(*args)
118
+ end
119
+
120
+ def set_negotiation_handler!
121
+ @handler = StreamNegotiation.new self
122
+ end
123
+
124
+ def negotiation_finished
125
+ @pass = nil
126
+ @handler = Routine.new self
127
+ send_stanza presence_stanza() unless component?
128
+ framework_ready if respond_to? :framework_ready
129
+ ready
130
+ end
131
+
132
+ def negotiation_failed(node)
133
+ raise RuntimeError, "could not negotiate a stream:\n#{node}"
134
+ end
135
+
136
+ private
137
+
138
+ def open_xml_stream_tag
139
+ domain = @jid.domain
140
+ version = '1.0'
141
+ lang = 'en'
142
+ start_stream = <<-STREAM
143
+ <stream:stream
144
+ to='#{domain}'
145
+ version='#{version}'
146
+ xml:lang='#{lang}'
147
+ xmlns='#{Client}'
148
+ xmlns:stream='#{Stream}'
149
+ >
150
+ STREAM
151
+ end
152
+
153
+ def close_xml_stream_tag
154
+ '</stream:stream>'
155
+ end
156
+
157
+ def open_xml_stream
158
+ send_raw open_xml_stream_tag
159
+ end
160
+
161
+ def close_xml_stream
162
+ send_raw close_xml_stream_tag
163
+ end
164
+
165
+ public
166
+
167
+ ### TLS World
168
+
169
+ def ask_for_tls
170
+ send_xml('starttls', :xmlns => TLS)
171
+ end
172
+
173
+ def start_using_tls_and_reset_stream
174
+ initiate_tls
175
+ restart_xml_stream
176
+ end
177
+
178
+ def initiate_tls
179
+ raise NotImplementedError
180
+ end
181
+
182
+ end
183
+ end
@@ -3,6 +3,7 @@ require 'em-xmpp/namespaces'
3
3
  require 'em-xmpp/context'
4
4
  require 'em-xmpp/stanza_matcher'
5
5
  require 'em-xmpp/stanza_handler'
6
+ require 'em-xmpp/xml_builder'
6
7
  require 'base64'
7
8
  require 'sasl/base'
8
9
  require 'sasl'
@@ -10,14 +11,13 @@ require 'sasl'
10
11
  module EM::Xmpp
11
12
  class Handler
12
13
  include Namespaces
14
+ include XmlBuilder
13
15
 
14
16
  def initialize(conn)
15
17
  @connection = conn
16
18
  @handlers = []
17
19
  @decorator_handlers = []
18
20
  @exception_handlers = []
19
-
20
- stack_decorators
21
21
  end
22
22
 
23
23
  # wraps the stanza in a context and calls handle_context
@@ -25,82 +25,82 @@ module EM::Xmpp
25
25
  handle_context Context.new(@connection, stanza)
26
26
  end
27
27
 
28
- private
29
-
30
- def stack_decorators
28
+ def enable_default_stack_decorators!
31
29
  on_presence_decorator do |ctx|
32
- presence = ctx.bit!(:presence)
33
- ctx.bit!(:error) if presence.error?
30
+ presence = ctx.bit(:presence)
31
+ ctx.bit(:error) if presence.error?
34
32
  ctx
35
33
  end
36
34
  on_message_decorator do |ctx|
37
- msg = ctx.bit!(:message)
38
- ctx.bit!(:error) if msg.error?
35
+ msg = ctx.bit(:message)
36
+ ctx.bit(:error) if msg.error?
39
37
  ctx
40
38
  end
41
39
  on_iq_decorator do |ctx|
42
- iq = ctx.bit!(:iq)
43
- ctx.bit!(:error) if iq.error?
40
+ iq = ctx.bit(:iq)
41
+ ctx.bit(:error) if iq.error?
44
42
  ctx
45
43
  end
46
44
  on_decorator('//xmlns:pubsub', 'xmlns' => PubSub) do |ctx|
47
- ctx.bit!(:pubsub)
45
+ ctx.bit(:pubsub)
48
46
  ctx
49
47
  end
50
48
  on_decorator('//xmlns:event', 'xmlns' => PubSubEvent) do |ctx|
51
- ctx.bit!(:pubsubevent)
49
+ ctx.bit(:pubsubevent)
52
50
  ctx
53
51
  end
54
52
  on_decorator('//xmlns:delay', 'xmlns' => Delay) do |ctx|
55
- ctx.bit!(:delay)
53
+ ctx.bit(:delay)
56
54
  ctx
57
55
  end
58
56
  on_decorator('//xmlns:query', 'xmlns' => DiscoverInfos) do |ctx|
59
- ctx.bit!(:discoinfos)
57
+ ctx.bit(:discoinfos)
60
58
  ctx
61
59
  end
62
60
  on_decorator('//xmlns:query', 'xmlns' => DiscoverItems) do |ctx|
63
- ctx.bit!(:discoitems)
61
+ ctx.bit(:discoitems)
64
62
  ctx
65
63
  end
66
64
  on_decorator('//xmlns:query', 'xmlns' => Roster) do |ctx|
67
- ctx.bit!(:roster)
65
+ ctx.bit(:roster)
68
66
  ctx
69
67
  end
70
68
  on_decorator('//xmlns:command', 'xmlns' => Commands) do |ctx|
71
- ctx.bit!(:command)
69
+ ctx.bit(:command)
72
70
  ctx
73
71
  end
74
72
  on_decorator('//xmlns:data', 'xmlns' => BoB) do |ctx|
75
- ctx.bit!(:bob)
73
+ ctx.bit(:bob)
76
74
  ctx
77
75
  end
78
76
  on_decorator('//xmlns:x', 'xmlns' => DataForms) do |ctx|
79
- ctx.bit!(:dataforms)
77
+ ctx.bit(:dataforms)
80
78
  ctx
81
79
  end
82
80
  on_decorator('//xmlns:nick', 'xmlns' => Nick) do |ctx|
83
- ctx.bit!(:nickname)
81
+ ctx.bit(:nickname)
84
82
  ctx
85
83
  end
86
84
  on_decorator('//xmlns:x', 'xmlns' => MucUser) do |ctx|
87
- ctx.bit!(:mucuser)
85
+ ctx.bit(:mucuser)
88
86
  ctx
89
87
  end
90
88
  on_decorator('//xmlns:si', 'xmlns' => StreamInitiation) do |ctx|
91
- ctx.bit!(:streaminitiation)
89
+ ctx.bit(:streaminitiation)
92
90
  ctx
93
91
  end
94
92
  on_decorator('//xmlns:open | //xmlns:data | //xmlns:close', 'xmlns' => IBB) do |ctx|
95
- ctx.bit!(:ibb)
93
+ ctx.bit(:ibb)
96
94
  ctx
97
95
  end
98
96
  on_decorator('//xmlns:query', 'xmlns' => ByteStreams) do |ctx|
99
- ctx.bit!(:bytestreams)
97
+ ctx.bit(:bytestreams)
100
98
  ctx
101
99
  end
102
100
  end
103
101
 
102
+ private
103
+
104
104
  def add_decorator_handler(handler)
105
105
  @decorator_handlers << handler
106
106
  end
@@ -273,63 +273,73 @@ module EM::Xmpp
273
273
  on_exception(:anything) do |ctx|
274
274
  raise ctx['error']
275
275
  end
276
- on('//xmlns:starttls', {'xmlns' => TLS}) do |ctx|
277
- @connection.ask_for_tls
278
- ctx.delete_xpath_handler!.done!
279
- end
280
276
 
281
- on('//xmlns:proceed', {'xmlns' => TLS }) do |ctx|
282
- @connection.start_using_tls_and_reset_stream
283
- ctx.delete_xpath_handler!.done!
284
- end
277
+ if @connection.component?
278
+ on('//xmlns:handshake', {}) do |ctx|
279
+ @connection.negotiation_finished
280
+ ctx.delete_xpath_handler!.done!
281
+ end
285
282
 
286
- on('//xmlns:mechanisms', {'xmlns' => SASL}) do |ctx|
287
- search = ctx.xpath('//xmlns:mechanisms', {'xmlns' => SASL})
288
- if search.first
289
- mechanisms = search.first.children.map(&:content)
290
- start_sasl mechanisms
283
+ else
284
+ on('//xmlns:starttls', {'xmlns' => TLS}) do |ctx|
285
+ @connection.ask_for_tls
291
286
  ctx.delete_xpath_handler!.done!
292
- else
293
- raise RuntimeError, "how come there is no mechanism node?"
294
287
  end
295
- end
296
288
 
297
- on('//xmlns:challenge', {'xmlns' => SASL}) do |ctx|
298
- sasl_step ctx.stanza
299
- ctx.done!
300
- end
289
+ on('//xmlns:proceed', {'xmlns' => TLS }) do |ctx|
290
+ @connection.start_using_tls_and_reset_stream
291
+ ctx.delete_xpath_handler!.done!
292
+ end
301
293
 
302
- on('//xmlns:success', {'xmlns' => SASL}) do |ctx|
303
- @connection.restart_xml_stream
304
- ctx.delete_xpath_handler!.done!
305
- end
294
+ on('//xmlns:mechanisms', {'xmlns' => SASL}) do |ctx|
295
+ search = ctx.xpath('//xmlns:mechanisms', {'xmlns' => SASL})
296
+ if search.first
297
+ mechanisms = search.first.children.map(&:content)
298
+ start_sasl mechanisms
299
+ ctx.delete_xpath_handler!.done!
300
+ else
301
+ raise RuntimeError, "how come there is no mechanism node?"
302
+ end
303
+ end
306
304
 
307
- on('//xmlns:bind', {'xmlns' => Bind}) do |ctx|
308
- bind_to_resource
309
- ctx.delete_xpath_handler!.done!
310
- end
305
+ on('//xmlns:challenge', {'xmlns' => SASL}) do |ctx|
306
+ sasl_step ctx.stanza
307
+ ctx.done!
308
+ end
311
309
 
312
- on('//xmlns:bind', {'xmlns' => Bind}) do |ctx|
313
- jid = extract_jid ctx.stanza
310
+ on('//xmlns:success', {'xmlns' => SASL}) do |ctx|
311
+ @connection.restart_xml_stream
312
+ ctx.delete_xpath_handler!.done!
313
+ end
314
314
 
315
- if jid
316
- @connection.jid_received jid
317
- start_session
318
- else
319
- raise RuntimeError, "no jid despite binding"
315
+ on('//xmlns:bind', {'xmlns' => Bind}) do |ctx|
316
+ bind_to_resource
317
+ ctx.delete_xpath_handler!.done!
320
318
  end
321
319
 
322
- ctx.delete_xpath_handler!.done!
323
- end
320
+ on('//xmlns:bind', {'xmlns' => Bind}) do |ctx|
321
+ jid = extract_jid ctx.stanza
324
322
 
325
- on('//xmlns:session', {'xmlns' => Session}) do |ctx|
326
- @connection.negotiation_finished
327
- ctx.delete_xpath_handler!.done!
328
- end
323
+ if jid
324
+ @connection.jid_received jid
325
+ start_session
326
+ else
327
+ raise RuntimeError, "no jid despite binding"
328
+ end
329
+
330
+ ctx.delete_xpath_handler!.done!
331
+ end
332
+
333
+ on('//xmlns:session', {'xmlns' => Session}) do |ctx|
334
+ @connection.negotiation_finished
335
+ ctx.delete_xpath_handler!.done!
336
+ end
337
+
338
+ on('//xmlns:failure', {'xmlns' => SASL}) do |ctx|
339
+ @connection.negotiation_failed(ctx.stanza)
340
+ ctx.done!
341
+ end
329
342
 
330
- on('//xmlns:failure', {'xmlns' => SASL}) do |ctx|
331
- @connection.negotiation_failed(ctx.stanza)
332
- ctx.done!
333
343
  end
334
344
 
335
345
  on(:anything) do |ctx|
@@ -341,24 +351,23 @@ module EM::Xmpp
341
351
 
342
352
  def extract_jid(stanza)
343
353
  jid = stanza.xpath('//bind:jid', {'bind' => Bind})
344
- jid.text if jid.any?
354
+ jid.first.text if jid.any?
345
355
  end
346
356
 
347
357
  def bind_to_resource(wanted_res=nil)
348
- c.send_stanza(c.iq_stanza('type' => 'set') do |x|
349
- x.bind('xmlns' => Bind) do |y|
350
- y.resource(wanted_res) if wanted_res
351
- end
352
- end)
358
+ c.send_stanza(c.iq_stanza({'type' => 'set'},
359
+ x('bind',{'xmlns' => Bind},
360
+ x_if(wanted_res,'resource',wanted_res)
361
+ )
362
+ )
363
+ )
353
364
  end
354
365
 
355
366
  def start_session
356
- session_request = c.iq_stanza('type' => 'set', 'to' => jid.domain) do |x|
357
- x.session('xmlns' => Session)
358
- end
367
+ session_request = c.iq_stanza({'type' => 'set', 'to' => jid.domain}, x('session','xmlns' => Session))
359
368
 
360
369
  c.send_stanza(session_request) do |ctx|
361
- if ctx.bit!(:stanza).type == 'result'
370
+ if ctx.bit(:stanza).type == 'result'
362
371
  @connection.negotiation_finished
363
372
  ctx.delete_xpath_handler!.done!
364
373
  else
@@ -385,13 +394,7 @@ module EM::Xmpp
385
394
  end
386
395
 
387
396
  def reply_sasl(msg, val=nil, mech=nil)
388
- c.send_xml do |x|
389
- if val
390
- x.send(msg, val, {'xmlns' => SASL, 'mechanism' => mech})
391
- else
392
- x.send(msg, {'xmlns' => SASL, 'mechanism' => mech})
393
- end
394
- end
397
+ c.send_xml(msg, val, 'xmlns' => SASL, 'mechanism' => mech)
395
398
  end
396
399
 
397
400
  end