em-xmpp 0.0.11 → 0.0.12

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.
@@ -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