xmpp4r 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +12 -0
- data/Rakefile +2 -4
- data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +6 -6
- data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +3 -3
- data/data/doc/xmpp4r/examples/advanced/minimuc.rb +5 -5
- data/data/doc/xmpp4r/examples/advanced/xmpping.rb +17 -4
- data/data/doc/xmpp4r/examples/advanced/xmppingrc.sample +5 -0
- data/data/doc/xmpp4r/examples/basic/echo_threaded.rb +6 -2
- data/data/doc/xmpp4r/examples/basic/muc_owner_config.rb +13 -0
- data/lib/xmpp4r.rb +0 -6
- data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +6 -7
- data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +5 -6
- data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +3 -5
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +1 -1
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +10 -8
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +3 -5
- data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +11 -17
- data/lib/xmpp4r/bytestreams/iq/si.rb +13 -32
- data/lib/xmpp4r/callbacks.rb +124 -0
- data/lib/xmpp4r/client.rb +2 -5
- data/lib/xmpp4r/command/helper/responder.rb +53 -0
- data/lib/xmpp4r/command/iq/command.rb +154 -0
- data/lib/xmpp4r/connection.rb +49 -12
- data/lib/xmpp4r/dataforms/x/data.rb +66 -29
- data/lib/xmpp4r/delay/x/delay.rb +2 -3
- data/lib/xmpp4r/discovery/iq/discoinfo.rb +20 -33
- data/lib/xmpp4r/discovery/iq/discoitems.rb +5 -28
- data/lib/xmpp4r/error.rb +5 -10
- data/lib/xmpp4r/feature_negotiation/iq/feature.rb +2 -20
- data/lib/xmpp4r/httpbinding.rb +5 -0
- data/lib/xmpp4r/httpbinding/client.rb +285 -0
- data/lib/xmpp4r/iq.rb +22 -41
- data/lib/xmpp4r/message.rb +8 -38
- data/lib/xmpp4r/muc.rb +2 -0
- data/lib/xmpp4r/muc/helper/mucclient.rb +50 -1
- data/lib/xmpp4r/muc/helper/simplemucclient.rb +2 -2
- data/lib/xmpp4r/muc/iq/mucowner.rb +11 -0
- data/lib/xmpp4r/muc/x/muc.rb +2 -30
- data/lib/xmpp4r/muc/x/mucuserinvite.rb +4 -2
- data/lib/xmpp4r/muc/x/mucuseritem.rb +4 -2
- data/lib/xmpp4r/presence.rb +7 -35
- data/lib/xmpp4r/pubsub.rb +1 -0
- data/lib/xmpp4r/pubsub/helper/nodebrowser.rb +174 -0
- data/lib/xmpp4r/pubsub/helper/nodehelper.rb +153 -0
- data/lib/xmpp4r/pubsub/helper/servicehelper.rb +326 -0
- data/lib/xmpp4r/pubsub/iq/pubsub.rb +19 -0
- data/lib/xmpp4r/pubsub/stanzas/event.rb +49 -0
- data/lib/xmpp4r/pubsub/stanzas/item.rb +27 -0
- data/lib/xmpp4r/pubsub/stanzas/items.rb +35 -0
- data/lib/xmpp4r/pubsub/stanzas/subscription.rb +58 -0
- data/lib/xmpp4r/query.rb +4 -32
- data/lib/xmpp4r/rexmladdons.rb +7 -772
- data/lib/xmpp4r/roster/helper/roster.rb +29 -50
- data/lib/xmpp4r/roster/iq/roster.rb +6 -35
- data/lib/xmpp4r/roster/x/roster.rb +13 -30
- data/lib/xmpp4r/rpc.rb +2 -0
- data/lib/xmpp4r/rpc/helper/client.rb +114 -0
- data/lib/xmpp4r/rpc/helper/server.rb +75 -0
- data/lib/xmpp4r/rpc/helper/xmlrpcaddons.rb +57 -0
- data/lib/xmpp4r/rpc/iq/rpc.rb +24 -0
- data/lib/xmpp4r/sasl.rb +1 -1
- data/lib/xmpp4r/semaphore.rb +38 -0
- data/lib/xmpp4r/stream.rb +104 -165
- data/lib/xmpp4r/streamparser.rb +2 -2
- data/lib/xmpp4r/vcard/iq/vcard.rb +5 -12
- data/lib/xmpp4r/version/helper/responder.rb +2 -1
- data/lib/xmpp4r/version/iq/version.rb +6 -18
- data/lib/xmpp4r/x.rb +20 -26
- data/lib/xmpp4r/xmpp4r.rb +1 -1
- data/lib/xmpp4r/xmppelement.rb +152 -0
- data/lib/xmpp4r/{xmlstanza.rb → xmppstanza.rb} +17 -29
- data/setup.rb +1 -0
- data/test/bytestreams/tc_ibb.rb +8 -8
- data/test/dataforms/tc_data.rb +81 -0
- data/test/lib/clienttester.rb +20 -17
- data/test/muc/tc_muc_mucclient.rb +48 -23
- data/test/muc/tc_muc_simplemucclient.rb +7 -4
- data/test/muc/tc_mucowner.rb +50 -0
- data/test/pubsub/tc_helper.rb +227 -0
- data/test/roster/tc_helper.rb +181 -55
- data/test/roster/tc_iqqueryroster.rb +33 -0
- data/test/roster/tc_xroster.rb +6 -3
- data/test/rpc/tc_helper.rb +84 -0
- data/test/tc_callbacks.rb +2 -1
- data/test/tc_class_names.rb +9 -1
- data/test/tc_error.rb +1 -0
- data/test/tc_iq.rb +13 -12
- data/test/tc_message.rb +1 -0
- data/test/tc_presence.rb +1 -0
- data/test/tc_rexml.rb +1 -1
- data/test/tc_stream.rb +147 -102
- data/test/tc_streamComponent.rb +94 -0
- data/test/tc_streamError.rb +67 -29
- data/test/tc_streamSend.rb +1 -1
- data/test/tc_xmppstanza.rb +125 -0
- data/test/ts_xmpp4r.rb +37 -28
- data/test/version/tc_helper.rb +14 -0
- data/test/version/tc_iqqueryversion.rb +4 -3
- metadata +163 -123
- data/data/doc/xmpp4r/examples/basic/echo_nonthreaded.rb +0 -32
- data/lib/callbacks.rb +0 -122
- data/test/tc_streamThreaded.rb +0 -168
- data/test/tc_xmlstanza.rb +0 -76
@@ -0,0 +1,57 @@
|
|
1
|
+
require "xmlrpc/parser"
|
2
|
+
require "xmlrpc/create"
|
3
|
+
require "xmlrpc/config"
|
4
|
+
require "xmlrpc/utils" # ParserWriterChooseMixin
|
5
|
+
|
6
|
+
|
7
|
+
module XMLRPC
|
8
|
+
class Create
|
9
|
+
##
|
10
|
+
# create a Method Call
|
11
|
+
# name:: [String] name of the method
|
12
|
+
# params:: [Array] params of the method as a array
|
13
|
+
def methodCall(name, *params)
|
14
|
+
name = name.to_s
|
15
|
+
|
16
|
+
if name !~ /[a-zA-Z0-9_.:\/]+/
|
17
|
+
raise ArgumentError, "Wrong XML-RPC method-name"
|
18
|
+
end
|
19
|
+
|
20
|
+
parameter = params.collect { |param|
|
21
|
+
@writer.ele("param", conv2value(param))
|
22
|
+
}
|
23
|
+
|
24
|
+
tree = @writer.document(
|
25
|
+
@writer.ele("methodCall",
|
26
|
+
@writer.tag("methodName", name),
|
27
|
+
@writer.ele("params", *parameter)
|
28
|
+
)
|
29
|
+
)
|
30
|
+
|
31
|
+
@writer.document_to_str(tree) + "\n"
|
32
|
+
end
|
33
|
+
##
|
34
|
+
# create a response to a method call
|
35
|
+
# is_ret:: [TrueClass] is this a return (true) or a error (false)
|
36
|
+
# params:: [Array] a array of params
|
37
|
+
|
38
|
+
def methodResponse(is_ret, *params)
|
39
|
+
|
40
|
+
if is_ret
|
41
|
+
resp = params.collect do |param|
|
42
|
+
@writer.ele("param", conv2value(param))
|
43
|
+
end
|
44
|
+
|
45
|
+
resp = [@writer.ele("params", *resp)]
|
46
|
+
else
|
47
|
+
if params.size != 1 or params[0] === XMLRPC::FaultException
|
48
|
+
raise ArgumentError, "no valid fault-structure given"
|
49
|
+
end
|
50
|
+
resp = @writer.ele("fault", conv2value(params[0].to_h))
|
51
|
+
end
|
52
|
+
|
53
|
+
tree = @writer.document(@writer.ele("methodResponse", resp))
|
54
|
+
@writer.document_to_str(tree) + "\n"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
4
|
+
|
5
|
+
require 'xmpp4r/query'
|
6
|
+
|
7
|
+
module Jabber
|
8
|
+
module RPC
|
9
|
+
class IqQueryRPC < IqQuery
|
10
|
+
NS_RPC = 'jabber:iq:rpc'
|
11
|
+
name_xmlns 'query', NS_RPC
|
12
|
+
|
13
|
+
# TODO: Is typed_add with a String right here?
|
14
|
+
def typed_add(e)
|
15
|
+
if e.kind_of? String
|
16
|
+
typed_add(REXML::Document.new(e).root)
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
data/lib/xmpp4r/sasl.rb
CHANGED
@@ -57,7 +57,7 @@ module Jabber
|
|
57
57
|
def auth(password)
|
58
58
|
auth_text = "#{@stream.jid.strip}\x00#{@stream.jid.node}\x00#{password}"
|
59
59
|
error = nil
|
60
|
-
@stream.send(generate_auth('PLAIN', Base64::encode64(auth_text).
|
60
|
+
@stream.send(generate_auth('PLAIN', Base64::encode64(auth_text).gsub(/\s/, ''))) { |reply|
|
61
61
|
if reply.name != 'success'
|
62
62
|
error = reply.first_element(nil).name
|
63
63
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# =XMPP4R - XMPP Library for Ruby
|
2
|
+
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
3
|
+
# Website::http://home.gna.org/xmpp4r/
|
4
|
+
|
5
|
+
module Jabber
|
6
|
+
##
|
7
|
+
# This class implements semaphore for threads synchronization.
|
8
|
+
class Semaphore
|
9
|
+
|
10
|
+
##
|
11
|
+
# Initialize new semaphore
|
12
|
+
#
|
13
|
+
# val:: [Integer] number of threads, that can enter to section
|
14
|
+
def initialize(val=0)
|
15
|
+
@tickets = val
|
16
|
+
@lock = Mutex.new
|
17
|
+
@cond = ConditionVariable.new
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Waits until are available some free tickets
|
22
|
+
def wait
|
23
|
+
@lock.synchronize {
|
24
|
+
@cond.wait(@lock) while !(@tickets > 0)
|
25
|
+
@tickets -= 1
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Unlocks guarded section, increments number of free tickets
|
31
|
+
def run
|
32
|
+
@lock.synchronize {
|
33
|
+
@tickets += 1
|
34
|
+
@cond.signal
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/xmpp4r/stream.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
|
3
3
|
# Website::http://home.gna.org/xmpp4r/
|
4
4
|
|
5
|
-
require 'callbacks'
|
5
|
+
require 'xmpp4r/callbacks'
|
6
6
|
require 'socket'
|
7
7
|
require 'thread'
|
8
|
-
|
8
|
+
require 'xmpp4r/semaphore'
|
9
9
|
require 'xmpp4r/streamparser'
|
10
10
|
require 'xmpp4r/presence'
|
11
11
|
require 'xmpp4r/message'
|
@@ -40,6 +40,9 @@ module Jabber
|
|
40
40
|
# Create a new stream
|
41
41
|
# (just initializes)
|
42
42
|
def initialize(threaded = true)
|
43
|
+
unless threaded
|
44
|
+
raise "Non-threaded mode was removed from XMPP4R."
|
45
|
+
end
|
43
46
|
@fd = nil
|
44
47
|
@status = DISCONNECTED
|
45
48
|
@xmlcbs = CallbackList::new
|
@@ -47,20 +50,15 @@ module Jabber
|
|
47
50
|
@messagecbs = CallbackList::new
|
48
51
|
@iqcbs = CallbackList::new
|
49
52
|
@presencecbs = CallbackList::new
|
50
|
-
|
51
|
-
|
52
|
-
threaded = true
|
53
|
-
end
|
54
|
-
@threaded = threaded
|
55
|
-
@stanzaqueue = []
|
56
|
-
@stanzaqueue_lock = Mutex::new
|
53
|
+
@send_lock = Mutex.new
|
54
|
+
@last_send = Time.now
|
57
55
|
@exception_block = nil
|
58
56
|
@threadblocks = []
|
59
|
-
# @pollCounter = 10
|
60
|
-
@waiting_thread = nil
|
61
57
|
@wakeup_thread = nil
|
62
58
|
@streamid = nil
|
63
|
-
@
|
59
|
+
@streamns = 'jabber:client'
|
60
|
+
@features_sem = Semaphore.new
|
61
|
+
@parser_thread = nil
|
64
62
|
end
|
65
63
|
|
66
64
|
##
|
@@ -71,36 +69,42 @@ module Jabber
|
|
71
69
|
|
72
70
|
@fd = fd
|
73
71
|
@parser = StreamParser.new(@fd, self)
|
74
|
-
@
|
72
|
+
@parser_thread = Thread.new do
|
73
|
+
Thread.current.abort_on_exception = true
|
75
74
|
begin
|
76
75
|
@parser.parse
|
76
|
+
Jabber::debuglog("DISCONNECTED\n")
|
77
|
+
|
78
|
+
if @exception_block
|
79
|
+
Thread.new { close!; @exception_block.call(nil, self, :disconnected) }
|
80
|
+
else
|
81
|
+
close!
|
82
|
+
end
|
77
83
|
rescue Exception => e
|
78
84
|
Jabber::debuglog("EXCEPTION:\n#{e.class}\n#{e.message}\n#{e.backtrace.join("\n")}")
|
79
85
|
|
80
86
|
if @exception_block
|
81
|
-
Thread.new
|
87
|
+
Thread.new do
|
88
|
+
Thread.current.abort_on_exception = true
|
89
|
+
close
|
90
|
+
@exception_block.call(e, self, :start)
|
91
|
+
end
|
82
92
|
else
|
83
|
-
|
84
|
-
|
93
|
+
if Jabber::debug
|
94
|
+
puts "Exception caught in Parser thread! (#{e.class})"
|
95
|
+
puts e.backtrace
|
96
|
+
end
|
97
|
+
close!
|
85
98
|
raise
|
86
99
|
end
|
87
100
|
end
|
88
101
|
end
|
89
|
-
|
90
|
-
# begin
|
91
|
-
# poll
|
92
|
-
# rescue
|
93
|
-
# puts "Exception caught in Poll thread, dumping backtrace and" +
|
94
|
-
# " exiting...\n" + $!.exception + "\n"
|
95
|
-
# puts $!.backtrace
|
96
|
-
# exit
|
97
|
-
# end
|
98
|
-
# end
|
102
|
+
|
99
103
|
@status = CONNECTED
|
100
104
|
end
|
101
105
|
|
102
106
|
def stop
|
103
|
-
@
|
107
|
+
@parser_thread.kill
|
104
108
|
@parser = nil
|
105
109
|
end
|
106
110
|
|
@@ -126,10 +130,11 @@ module Jabber
|
|
126
130
|
# to commit suicide(???)
|
127
131
|
if @exception_block
|
128
132
|
# New thread, because close will kill the current thread
|
129
|
-
Thread.new
|
133
|
+
Thread.new do
|
134
|
+
Thread.current.abort_on_exception = true
|
130
135
|
close
|
131
136
|
@exception_block.call(e, self, :parser)
|
132
|
-
|
137
|
+
end
|
133
138
|
else
|
134
139
|
puts "Stream#parse_failure was called by XML parser. Dumping " +
|
135
140
|
"backtrace...\n" + e.exception + "\n"
|
@@ -143,10 +148,11 @@ module Jabber
|
|
143
148
|
# This method is called by the parser upon receiving <tt></stream:stream></tt>
|
144
149
|
def parser_end
|
145
150
|
if @exception_block
|
146
|
-
Thread.new
|
151
|
+
Thread.new do
|
152
|
+
Thread.current.abort_on_exception = true
|
147
153
|
close
|
148
154
|
@exception_block.call(nil, self, :close)
|
149
|
-
|
155
|
+
end
|
150
156
|
else
|
151
157
|
close
|
152
158
|
end
|
@@ -171,30 +177,31 @@ module Jabber
|
|
171
177
|
# Processes a received REXML::Element and executes
|
172
178
|
# registered thread blocks and filters against it.
|
173
179
|
#
|
174
|
-
# If in threaded mode, a new thread will be spawned
|
175
|
-
# for the call to receive_nonthreaded.
|
176
180
|
# element:: [REXML::Element] The received element
|
177
181
|
def receive(element)
|
178
|
-
if @threaded
|
179
|
-
# Don't spawn a new thread here. An implicit feature
|
180
|
-
# of XMPP is constant order of stanzas.
|
181
|
-
receive_nonthreaded(element)
|
182
|
-
else
|
183
|
-
receive_nonthreaded(element)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def receive_nonthreaded(element)
|
188
182
|
Jabber::debuglog("RECEIVED:\n#{element.to_s}")
|
183
|
+
|
184
|
+
if element.namespace('').to_s == '' # REXML namespaces are always strings
|
185
|
+
element.add_namespace(@streamns)
|
186
|
+
end
|
187
|
+
|
189
188
|
case element.prefix
|
190
189
|
when 'stream'
|
191
190
|
case element.name
|
192
191
|
when 'stream'
|
193
192
|
stanza = element
|
194
193
|
@streamid = element.attributes['id']
|
194
|
+
@streamns = element.namespace('') if element.namespace('')
|
195
|
+
|
196
|
+
# Hack: component streams are basically client streams.
|
197
|
+
# Someday we may want to create special stanza classes
|
198
|
+
# for components/s2s deriving from normal stanzas but
|
199
|
+
# posessing these namespaces
|
200
|
+
@streamns = 'jabber:client' if @streamns == 'jabber:component:accept'
|
201
|
+
|
195
202
|
unless element.attributes['version'] # isn't XMPP compliant, so
|
196
203
|
Jabber::debuglog("FEATURES: server not XMPP compliant, will not wait for features")
|
197
|
-
@
|
204
|
+
@features_sem.run # don't wait for <stream:features/>
|
198
205
|
end
|
199
206
|
when 'features'
|
200
207
|
stanza = element
|
@@ -208,20 +215,16 @@ module Jabber
|
|
208
215
|
end
|
209
216
|
}
|
210
217
|
Jabber::debuglog("FEATURES: received")
|
211
|
-
@
|
218
|
+
@features_sem.run
|
212
219
|
else
|
213
220
|
stanza = element
|
214
221
|
end
|
215
222
|
else
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
when 'presence'
|
222
|
-
stanza = Presence::import(element)
|
223
|
-
else
|
224
|
-
stanza = element
|
223
|
+
# Any stanza, classes are registered by XMPPElement::name_xmlns
|
224
|
+
begin
|
225
|
+
stanza = XMPPStanza::import(element)
|
226
|
+
rescue NoNameXmlnsRegistered
|
227
|
+
stanza = element
|
225
228
|
end
|
226
229
|
end
|
227
230
|
|
@@ -251,23 +254,7 @@ module Jabber
|
|
251
254
|
end
|
252
255
|
}
|
253
256
|
|
254
|
-
|
255
|
-
process_one(stanza)
|
256
|
-
else
|
257
|
-
# stanzaqueue will be read when the user call process
|
258
|
-
@stanzaqueue_lock.lock
|
259
|
-
@stanzaqueue.push(stanza)
|
260
|
-
@stanzaqueue_lock.unlock
|
261
|
-
@waiting_thread.wakeup if @waiting_thread
|
262
|
-
end
|
263
|
-
end
|
264
|
-
private :receive_nonthreaded
|
265
|
-
|
266
|
-
##
|
267
|
-
# Process |element| until it is consumed. Returns element.consumed?
|
268
|
-
# element The element to process
|
269
|
-
def process_one(stanza)
|
270
|
-
Jabber::debuglog("PROCESSING:\n#{stanza.to_s}")
|
257
|
+
Jabber::debuglog("PROCESSING:\n#{stanza.to_s} (#{stanza.class})")
|
271
258
|
return true if @xmlcbs.process(stanza)
|
272
259
|
return true if @stanzacbs.process(stanza)
|
273
260
|
case stanza
|
@@ -279,61 +266,6 @@ module Jabber
|
|
279
266
|
return true if @presencecbs.process(stanza)
|
280
267
|
end
|
281
268
|
end
|
282
|
-
private :process_one
|
283
|
-
|
284
|
-
##
|
285
|
-
# Process |max| XML stanzas and call listeners for all of them.
|
286
|
-
#
|
287
|
-
# max:: [Integer] the number of stanzas to process (nil means process
|
288
|
-
# all available)
|
289
|
-
def process(max = nil)
|
290
|
-
n = 0
|
291
|
-
@stanzaqueue_lock.lock
|
292
|
-
while @stanzaqueue.size > 0 and (max == nil or n < max)
|
293
|
-
e = @stanzaqueue.shift
|
294
|
-
@stanzaqueue_lock.unlock
|
295
|
-
process_one(e)
|
296
|
-
n += 1
|
297
|
-
@stanzaqueue_lock.lock
|
298
|
-
end
|
299
|
-
@stanzaqueue_lock.unlock
|
300
|
-
n
|
301
|
-
end
|
302
|
-
|
303
|
-
##
|
304
|
-
# Process an XML stanza and call the listeners for it. If no stanza is
|
305
|
-
# currently available, wait for max |time| seconds before returning.
|
306
|
-
#
|
307
|
-
# time:: [Integer] time to wait in seconds. If nil, wait infinitely.
|
308
|
-
# all available)
|
309
|
-
def wait_and_process(time = nil)
|
310
|
-
if time == 0
|
311
|
-
return process(1)
|
312
|
-
end
|
313
|
-
@stanzaqueue_lock.lock
|
314
|
-
if @stanzaqueue.size > 0
|
315
|
-
e = @stanzaqueue.shift
|
316
|
-
@stanzaqueue_lock.unlock
|
317
|
-
process_one(e)
|
318
|
-
return 1
|
319
|
-
end
|
320
|
-
|
321
|
-
@waiting_thread = Thread.current
|
322
|
-
@wakeup_thread = Thread.new { sleep time ; @waiting_thread.wakeup if @waiting_thread }
|
323
|
-
@waiting_thread.stop
|
324
|
-
@wakeup_thread.kill if @wakeup_thread
|
325
|
-
@wakeup_thread = nil
|
326
|
-
@waiting_thread = nil
|
327
|
-
|
328
|
-
@stanzaqueue_lock.lock
|
329
|
-
if @stanzaqueue.size > 0
|
330
|
-
e = @stanzaqueue.shift
|
331
|
-
@stanzaqueue_lock.unlock
|
332
|
-
process_one(e)
|
333
|
-
return 1
|
334
|
-
end
|
335
|
-
return 0
|
336
|
-
end
|
337
269
|
|
338
270
|
##
|
339
271
|
# This is used by Jabber::Stream internally to
|
@@ -341,18 +273,32 @@ module Jabber
|
|
341
273
|
# Stream#send.
|
342
274
|
class ThreadBlock
|
343
275
|
def initialize(block)
|
344
|
-
@thread = Thread.current
|
345
276
|
@block = block
|
277
|
+
@waiter = Semaphore.new
|
278
|
+
@exception = nil
|
346
279
|
end
|
347
280
|
def call(*args)
|
348
281
|
@block.call(*args)
|
349
282
|
end
|
283
|
+
def wait
|
284
|
+
@waiter.wait
|
285
|
+
raise @exception if @exception
|
286
|
+
end
|
350
287
|
def wakeup
|
351
288
|
# TODO: Handle threadblock removal if !alive?
|
352
|
-
@
|
289
|
+
@waiter.run
|
353
290
|
end
|
354
291
|
def raise(exception)
|
355
|
-
@
|
292
|
+
@exception = exception
|
293
|
+
@waiter.run
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def send_data(data)
|
298
|
+
@send_lock.synchronize do
|
299
|
+
@last_send = Time.now
|
300
|
+
@fd << data
|
301
|
+
@fd.flush
|
356
302
|
end
|
357
303
|
end
|
358
304
|
|
@@ -368,31 +314,46 @@ module Jabber
|
|
368
314
|
# &block:: [Block] The optional block
|
369
315
|
def send(xml, &block)
|
370
316
|
Jabber::debuglog("SENDING:\n#{xml}")
|
371
|
-
@threadblocks.unshift(ThreadBlock.new(block)) if block
|
372
|
-
Thread.critical = true # we don't want to be interupted before we stop!
|
317
|
+
@threadblocks.unshift(threadblock = ThreadBlock.new(block)) if block
|
373
318
|
begin
|
374
|
-
|
375
|
-
|
319
|
+
# Temporarily remove stanza's namespace to
|
320
|
+
# reduce bandwidth consumption
|
321
|
+
if xml.kind_of? XMPPStanza and xml.namespace == 'jabber:client'
|
322
|
+
xml.delete_namespace
|
323
|
+
send_data(xml.to_s)
|
324
|
+
xml.add_namespace(@streamns)
|
325
|
+
else
|
326
|
+
send_data(xml.to_s)
|
327
|
+
end
|
376
328
|
rescue Exception => e
|
377
329
|
Jabber::debuglog("EXCEPTION:\n#{e.class}\n#{e.message}\n#{e.backtrace.join("\n")}")
|
378
330
|
|
379
|
-
if @exception_block
|
380
|
-
Thread.new
|
331
|
+
if @exception_block
|
332
|
+
Thread.new do
|
333
|
+
Thread.current.abort_on_exception = true
|
334
|
+
close!
|
335
|
+
@exception_block.call(e, self, :sending)
|
336
|
+
end
|
381
337
|
else
|
382
|
-
|
338
|
+
if Jabber::debug
|
339
|
+
puts "Exception caught while sending! (#{e.class})"
|
340
|
+
puts e.backtrace
|
341
|
+
end
|
383
342
|
close!
|
384
343
|
raise
|
385
344
|
end
|
386
345
|
end
|
387
|
-
Thread.critical = false
|
388
346
|
# The parser thread might be running this (think of a callback running send())
|
389
347
|
# If this is the case, we mustn't stop (or we would cause a deadlock)
|
390
|
-
|
391
|
-
|
348
|
+
if block and Thread.current != @parser_thread
|
349
|
+
threadblock.wait
|
350
|
+
elsif block
|
351
|
+
Jabber::debuglog("WARNING:\nCannot stop current thread in Jabber::Stream#send because it is the parser thread!")
|
352
|
+
end
|
392
353
|
end
|
393
354
|
|
394
355
|
##
|
395
|
-
# Send an XMMP stanza with an Jabber::
|
356
|
+
# Send an XMMP stanza with an Jabber::XMPPStanza#id. The id will be
|
396
357
|
# generated by Jabber::IdGenerator if not already set.
|
397
358
|
#
|
398
359
|
# The block will be called once: when receiving a stanza with the
|
@@ -407,7 +368,7 @@ module Jabber
|
|
407
368
|
# Please see Stream#send for some implementational details.
|
408
369
|
#
|
409
370
|
# Please read the note about nesting at Stream#send
|
410
|
-
# xml:: [
|
371
|
+
# xml:: [XMPPStanza]
|
411
372
|
def send_with_id(xml, &block)
|
412
373
|
if xml.id.nil?
|
413
374
|
xml.id = Jabber::IdGenerator.instance.generate_id
|
@@ -416,7 +377,7 @@ module Jabber
|
|
416
377
|
res = nil
|
417
378
|
error = nil
|
418
379
|
send(xml) do |received|
|
419
|
-
if received.kind_of?
|
380
|
+
if received.kind_of? XMPPStanza and received.id == xml.id
|
420
381
|
if received.type == :error
|
421
382
|
error = (received.error ? received.error : Error.new)
|
422
383
|
true
|
@@ -436,27 +397,6 @@ module Jabber
|
|
436
397
|
res
|
437
398
|
end
|
438
399
|
|
439
|
-
##
|
440
|
-
# Starts a polling thread to send "keep alive" data to prevent
|
441
|
-
# the Jabber connection from closing for inactivity.
|
442
|
-
#
|
443
|
-
# Currently not working!
|
444
|
-
def poll
|
445
|
-
sleep 10
|
446
|
-
while true
|
447
|
-
sleep 2
|
448
|
-
# @pollCounter = @pollCounter - 1
|
449
|
-
# if @pollCounter < 0
|
450
|
-
# begin
|
451
|
-
# send(" \t ")
|
452
|
-
# rescue
|
453
|
-
# Thread.new {@exception_block.call if @exception_block}
|
454
|
-
# break
|
455
|
-
# end
|
456
|
-
# end
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
400
|
##
|
461
401
|
# Adds a callback block to process received XML messages
|
462
402
|
#
|
@@ -554,8 +494,7 @@ module Jabber
|
|
554
494
|
end
|
555
495
|
|
556
496
|
def close!
|
557
|
-
@
|
558
|
-
# @pollThread.kill
|
497
|
+
@parser_thread.kill if @parser_thread
|
559
498
|
@fd.close if @fd and !@fd.closed?
|
560
499
|
@status = DISCONNECTED
|
561
500
|
end
|