tp-blather 0.8.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/.autotest +13 -0
- data/.gemtest +0 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +249 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE +22 -0
- data/README.md +413 -0
- data/Rakefile +20 -0
- data/TODO.md +2 -0
- data/blather.gemspec +51 -0
- data/examples/certs/README +20 -0
- data/examples/certs/ca-bundle.crt +3987 -0
- data/examples/echo.rb +19 -0
- data/examples/execute.rb +17 -0
- data/examples/ping_pong.rb +38 -0
- data/examples/print_hierarchy.rb +77 -0
- data/examples/rosterprint.rb +15 -0
- data/examples/stream_only.rb +28 -0
- data/examples/trusted_echo.rb +21 -0
- data/examples/xmpp4r/echo.rb +36 -0
- data/lib/blather.rb +112 -0
- data/lib/blather/cert_store.rb +53 -0
- data/lib/blather/client.rb +95 -0
- data/lib/blather/client/client.rb +345 -0
- data/lib/blather/client/dsl.rb +320 -0
- data/lib/blather/client/dsl/pubsub.rb +174 -0
- data/lib/blather/core_ext/eventmachine.rb +125 -0
- data/lib/blather/core_ext/ipaddr.rb +20 -0
- data/lib/blather/errors.rb +69 -0
- data/lib/blather/errors/sasl_error.rb +44 -0
- data/lib/blather/errors/stanza_error.rb +110 -0
- data/lib/blather/errors/stream_error.rb +84 -0
- data/lib/blather/file_transfer.rb +107 -0
- data/lib/blather/file_transfer/ibb.rb +68 -0
- data/lib/blather/file_transfer/s5b.rb +114 -0
- data/lib/blather/jid.rb +141 -0
- data/lib/blather/roster.rb +118 -0
- data/lib/blather/roster_item.rb +146 -0
- data/lib/blather/stanza.rb +167 -0
- data/lib/blather/stanza/disco.rb +32 -0
- data/lib/blather/stanza/disco/capabilities.rb +161 -0
- data/lib/blather/stanza/disco/disco_info.rb +205 -0
- data/lib/blather/stanza/disco/disco_items.rb +134 -0
- data/lib/blather/stanza/iq.rb +144 -0
- data/lib/blather/stanza/iq/command.rb +339 -0
- data/lib/blather/stanza/iq/ibb.rb +86 -0
- data/lib/blather/stanza/iq/ping.rb +50 -0
- data/lib/blather/stanza/iq/query.rb +53 -0
- data/lib/blather/stanza/iq/roster.rb +185 -0
- data/lib/blather/stanza/iq/s5b.rb +208 -0
- data/lib/blather/stanza/iq/si.rb +415 -0
- data/lib/blather/stanza/iq/vcard.rb +149 -0
- data/lib/blather/stanza/message.rb +428 -0
- data/lib/blather/stanza/message/muc_user.rb +119 -0
- data/lib/blather/stanza/muc/muc_user_base.rb +54 -0
- data/lib/blather/stanza/presence.rb +172 -0
- data/lib/blather/stanza/presence/c.rb +100 -0
- data/lib/blather/stanza/presence/muc.rb +35 -0
- data/lib/blather/stanza/presence/muc_user.rb +147 -0
- data/lib/blather/stanza/presence/status.rb +218 -0
- data/lib/blather/stanza/presence/subscription.rb +100 -0
- data/lib/blather/stanza/pubsub.rb +119 -0
- data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
- data/lib/blather/stanza/pubsub/create.rb +65 -0
- data/lib/blather/stanza/pubsub/errors.rb +18 -0
- data/lib/blather/stanza/pubsub/event.rb +139 -0
- data/lib/blather/stanza/pubsub/items.rb +103 -0
- data/lib/blather/stanza/pubsub/publish.rb +103 -0
- data/lib/blather/stanza/pubsub/retract.rb +92 -0
- data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
- data/lib/blather/stanza/pubsub/subscription.rb +135 -0
- data/lib/blather/stanza/pubsub/subscriptions.rb +83 -0
- data/lib/blather/stanza/pubsub/unsubscribe.rb +84 -0
- data/lib/blather/stanza/pubsub_owner.rb +51 -0
- data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
- data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
- data/lib/blather/stanza/x.rb +416 -0
- data/lib/blather/stream.rb +266 -0
- data/lib/blather/stream/client.rb +32 -0
- data/lib/blather/stream/component.rb +39 -0
- data/lib/blather/stream/features.rb +70 -0
- data/lib/blather/stream/features/register.rb +38 -0
- data/lib/blather/stream/features/resource.rb +63 -0
- data/lib/blather/stream/features/sasl.rb +190 -0
- data/lib/blather/stream/features/session.rb +45 -0
- data/lib/blather/stream/features/tls.rb +29 -0
- data/lib/blather/stream/parser.rb +102 -0
- data/lib/blather/version.rb +3 -0
- data/lib/blather/xmpp_node.rb +94 -0
- data/spec/blather/client/client_spec.rb +687 -0
- data/spec/blather/client/dsl/pubsub_spec.rb +492 -0
- data/spec/blather/client/dsl_spec.rb +266 -0
- data/spec/blather/errors/sasl_error_spec.rb +33 -0
- data/spec/blather/errors/stanza_error_spec.rb +129 -0
- data/spec/blather/errors/stream_error_spec.rb +108 -0
- data/spec/blather/errors_spec.rb +33 -0
- data/spec/blather/file_transfer_spec.rb +135 -0
- data/spec/blather/jid_spec.rb +87 -0
- data/spec/blather/roster_item_spec.rb +134 -0
- data/spec/blather/roster_spec.rb +107 -0
- data/spec/blather/stanza/discos/disco_info_spec.rb +247 -0
- data/spec/blather/stanza/discos/disco_items_spec.rb +154 -0
- data/spec/blather/stanza/iq/command_spec.rb +206 -0
- data/spec/blather/stanza/iq/ibb_spec.rb +124 -0
- data/spec/blather/stanza/iq/ping_spec.rb +45 -0
- data/spec/blather/stanza/iq/query_spec.rb +64 -0
- data/spec/blather/stanza/iq/roster_spec.rb +139 -0
- data/spec/blather/stanza/iq/s5b_spec.rb +57 -0
- data/spec/blather/stanza/iq/si_spec.rb +98 -0
- data/spec/blather/stanza/iq/vcard_spec.rb +93 -0
- data/spec/blather/stanza/iq_spec.rb +61 -0
- data/spec/blather/stanza/message/muc_user_spec.rb +152 -0
- data/spec/blather/stanza/message_spec.rb +282 -0
- data/spec/blather/stanza/presence/c_spec.rb +56 -0
- data/spec/blather/stanza/presence/muc_spec.rb +37 -0
- data/spec/blather/stanza/presence/muc_user_spec.rb +83 -0
- data/spec/blather/stanza/presence/status_spec.rb +144 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +102 -0
- data/spec/blather/stanza/presence_spec.rb +125 -0
- 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 +98 -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 +74 -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 +68 -0
- data/spec/blather/stanza/x_spec.rb +231 -0
- data/spec/blather/stanza_spec.rb +134 -0
- data/spec/blather/stream/client_spec.rb +1090 -0
- data/spec/blather/stream/component_spec.rb +108 -0
- data/spec/blather/stream/parser_spec.rb +152 -0
- data/spec/blather/stream/ssl_spec.rb +32 -0
- data/spec/blather/xmpp_node_spec.rb +47 -0
- data/spec/blather_spec.rb +34 -0
- data/spec/fixtures/pubsub.rb +311 -0
- data/spec/spec_helper.rb +17 -0
- data/yard/templates/default/class/html/handlers.erb +18 -0
- data/yard/templates/default/class/setup.rb +10 -0
- data/yard/templates/default/class/text/handlers.erb +1 -0
- metadata +459 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Blather
|
|
2
|
+
|
|
3
|
+
# Stream Errors
|
|
4
|
+
# [RFC3920 Section 9.3](http://xmpp.org/rfcs/rfc3920.html#streams-error-rules)
|
|
5
|
+
#
|
|
6
|
+
# @handler :stream_error
|
|
7
|
+
class StreamError < BlatherError
|
|
8
|
+
# @private
|
|
9
|
+
STREAM_ERR_NS = 'urn:ietf:params:xml:ns:xmpp-streams'
|
|
10
|
+
|
|
11
|
+
register :stream_error
|
|
12
|
+
|
|
13
|
+
attr_reader :text, :extras
|
|
14
|
+
|
|
15
|
+
# Factory method for instantiating the proper class for the error
|
|
16
|
+
#
|
|
17
|
+
# @param [Blather::XMPPNode] node the importable node
|
|
18
|
+
def self.import(node)
|
|
19
|
+
name = node.find_first('descendant::*[name()!="text"]', STREAM_ERR_NS).element_name
|
|
20
|
+
|
|
21
|
+
text = node.find_first 'descendant::*[name()="text"]', STREAM_ERR_NS
|
|
22
|
+
text = text.content if text
|
|
23
|
+
|
|
24
|
+
extras = node.find("descendant::*[namespace-uri()!='#{STREAM_ERR_NS}']").map { |n| n }
|
|
25
|
+
|
|
26
|
+
self.new name, text, extras
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Create a new Stream Error
|
|
30
|
+
# [RFC3920 Section 4.7.2](http://xmpp.org/rfcs/rfc3920.html#rfc.section.4.7.2)
|
|
31
|
+
#
|
|
32
|
+
# @param [String] name the error name
|
|
33
|
+
# @param [String, nil] text optional error text
|
|
34
|
+
# @param [Array<Blather::XMPPNode>] extras an array of extras to attach to the
|
|
35
|
+
# error
|
|
36
|
+
def initialize(name, text = nil, extras = [])
|
|
37
|
+
@name = name
|
|
38
|
+
@text = text
|
|
39
|
+
@extras = extras
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# The error name
|
|
43
|
+
#
|
|
44
|
+
# @return [Symbol]
|
|
45
|
+
def name
|
|
46
|
+
@name.gsub('-','_').to_sym
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Creates an XML node from the error
|
|
50
|
+
#
|
|
51
|
+
# @return [Blather::XMPPNode]
|
|
52
|
+
def to_node
|
|
53
|
+
node = XMPPNode.new('error')
|
|
54
|
+
node.namespace = {'stream' => Blather::Stream::STREAM_NS}
|
|
55
|
+
|
|
56
|
+
node << (err = XMPPNode.new(@name, node.document))
|
|
57
|
+
err.namespace = 'urn:ietf:params:xml:ns:xmpp-streams'
|
|
58
|
+
|
|
59
|
+
if self.text
|
|
60
|
+
node << (text = XMPPNode.new('text', node.document))
|
|
61
|
+
text.namespace = 'urn:ietf:params:xml:ns:xmpp-streams'
|
|
62
|
+
text.content = self.text
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
self.extras.each { |extra| node << extra.dup }
|
|
66
|
+
node
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Convert the object to a proper node then convert it to a string
|
|
70
|
+
#
|
|
71
|
+
# @return [String]
|
|
72
|
+
def to_xml
|
|
73
|
+
to_node.to_s
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @private
|
|
77
|
+
def inspect
|
|
78
|
+
"Stream Error (#{@name}): #{self.text}" + (self.extras.empty? ? '' : " [#{self.extras}]")
|
|
79
|
+
end
|
|
80
|
+
# @private
|
|
81
|
+
alias_method :to_s, :inspect
|
|
82
|
+
end # StreamError
|
|
83
|
+
|
|
84
|
+
end # Blather
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Blather
|
|
2
|
+
# File Transfer helper
|
|
3
|
+
# Takes care of accepting, declining and offering file transfers through the stream
|
|
4
|
+
class FileTransfer
|
|
5
|
+
|
|
6
|
+
# Set this to false if you don't want to use In-Band Bytestreams
|
|
7
|
+
attr_accessor :allow_ibb
|
|
8
|
+
|
|
9
|
+
# Set this to false if you don't want to use SOCKS5 Bytestreams
|
|
10
|
+
attr_accessor :allow_s5b
|
|
11
|
+
|
|
12
|
+
# Set this to true if you want SOCKS5 Bytestreams to attempt to use private network addresses
|
|
13
|
+
attr_accessor :allow_private_ips
|
|
14
|
+
|
|
15
|
+
# Create a new FileTransfer
|
|
16
|
+
#
|
|
17
|
+
# @param [Blather::Stream] stream the stream the file transfer should use
|
|
18
|
+
# @param [Blather::Stanza::Iq::Si] iq a si iq used to stream-initiation
|
|
19
|
+
def initialize(stream, iq = nil)
|
|
20
|
+
@stream = stream
|
|
21
|
+
@allow_s5b = true
|
|
22
|
+
@allow_ibb = true
|
|
23
|
+
|
|
24
|
+
@iq = iq
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Accept an incoming file-transfer
|
|
28
|
+
#
|
|
29
|
+
# @param [module] handler the handler for incoming data, see Blather::FileTransfer::SimpleFileReceiver for an example
|
|
30
|
+
# @param [Array] params the params to be passed into the handler
|
|
31
|
+
def accept(handler, *params)
|
|
32
|
+
answer = @iq.reply
|
|
33
|
+
|
|
34
|
+
answer.si.feature.x.type = :submit
|
|
35
|
+
|
|
36
|
+
supported_methods = @iq.si.feature.x.field("stream-method").options.map(&:value)
|
|
37
|
+
if supported_methods.include?(Stanza::Iq::S5b::NS_S5B) and @allow_s5b
|
|
38
|
+
answer.si.feature.x.fields = {:var => 'stream-method', :value => Stanza::Iq::S5b::NS_S5B}
|
|
39
|
+
|
|
40
|
+
@stream.register_handler :s5b_open, :from => @iq.from do |iq|
|
|
41
|
+
transfer = Blather::FileTransfer::S5b.new(@stream, iq)
|
|
42
|
+
transfer.allow_ibb_fallback = true if @allow_ibb
|
|
43
|
+
transfer.allow_private_ips = true if @allow_private_ips
|
|
44
|
+
transfer.accept(handler, *params)
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@stream.write answer
|
|
49
|
+
elsif supported_methods.include?(Stanza::Iq::Ibb::NS_IBB) and @allow_ibb
|
|
50
|
+
answer.si.feature.x.fields = {:var => 'stream-method', :value => Stanza::Iq::Ibb::NS_IBB}
|
|
51
|
+
|
|
52
|
+
@stream.register_handler :ibb_open, :from => @iq.from do |iq|
|
|
53
|
+
transfer = Blather::FileTransfer::Ibb.new(@stream, iq)
|
|
54
|
+
transfer.accept(handler, *params)
|
|
55
|
+
true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
@stream.write answer
|
|
59
|
+
else
|
|
60
|
+
reason = XMPPNode.new('no-valid-streams')
|
|
61
|
+
reason.namespace = Blather::Stanza::Iq::Si::NS_SI
|
|
62
|
+
|
|
63
|
+
@stream.write StanzaError.new(@iq, 'bad-request', 'cancel', nil, [reason]).to_node
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Decline an incoming file-transfer
|
|
68
|
+
def decline
|
|
69
|
+
answer = StanzaError.new(@iq, 'forbidden', 'cancel', 'Offer declined').to_node
|
|
70
|
+
|
|
71
|
+
@stream.write answer
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Offer a file to somebody, not implemented yet
|
|
75
|
+
def offer
|
|
76
|
+
# TODO: implement
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Simple handler for incoming file transfers
|
|
80
|
+
#
|
|
81
|
+
# You can define your own handler and pass it to the accept method.
|
|
82
|
+
module SimpleFileReceiver
|
|
83
|
+
def initialize(path, size)
|
|
84
|
+
@path = path
|
|
85
|
+
@size = size
|
|
86
|
+
@transferred = 0
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @private
|
|
90
|
+
def post_init
|
|
91
|
+
@file = File.open(@path, "w")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @private
|
|
95
|
+
def receive_data(data)
|
|
96
|
+
@transferred += data.size
|
|
97
|
+
@file.write data
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @private
|
|
101
|
+
def unbind
|
|
102
|
+
@file.close
|
|
103
|
+
File.delete(@path) unless @transferred == @size
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require "base64"
|
|
2
|
+
|
|
3
|
+
module Blather
|
|
4
|
+
class FileTransfer
|
|
5
|
+
# In-Band Bytestreams Transfer helper
|
|
6
|
+
# Takes care of accepting, declining and offering file transfers through the stream
|
|
7
|
+
class Ibb
|
|
8
|
+
def initialize(stream, iq)
|
|
9
|
+
@stream = stream
|
|
10
|
+
@iq = iq
|
|
11
|
+
@seq = 0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Accept an incoming file-transfer
|
|
15
|
+
#
|
|
16
|
+
# @param [module] handler the handler for incoming data, see Blather::FileTransfer::SimpleFileReceiver for an example
|
|
17
|
+
# @param [Array] params the params to be passed into the handler
|
|
18
|
+
def accept(handler, *params)
|
|
19
|
+
@io_read, @io_write = IO.pipe
|
|
20
|
+
EM::attach @io_read, handler, *params
|
|
21
|
+
|
|
22
|
+
@stream.register_handler :ibb_data, :from => @iq.from, :sid => @iq.sid do |iq|
|
|
23
|
+
if iq.data['seq'] == @seq.to_s
|
|
24
|
+
begin
|
|
25
|
+
@io_write << Base64.decode64(iq.data.content)
|
|
26
|
+
|
|
27
|
+
@stream.write iq.reply
|
|
28
|
+
|
|
29
|
+
@seq += 1
|
|
30
|
+
@seq = 0 if @seq > 65535
|
|
31
|
+
rescue Errno::EPIPE => e
|
|
32
|
+
@stream.write StanzaError.new(iq, 'not-acceptable', :cancel).to_node
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
@stream.write StanzaError.new(iq, 'unexpected-request', :wait).to_node
|
|
36
|
+
end
|
|
37
|
+
true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
@stream.register_handler :ibb_close, :from => @iq.from, :sid => @iq.sid do |iq|
|
|
41
|
+
@stream.write iq.reply
|
|
42
|
+
@stream.clear_handlers :ibb_data, :from => @iq.from, :sid => @iq.sid
|
|
43
|
+
@stream.clear_handlers :ibb_close, :from => @iq.from, :sid => @iq.sid
|
|
44
|
+
|
|
45
|
+
@io_write.close
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
@stream.clear_handlers :ibb_open, :from => @iq.from
|
|
50
|
+
@stream.clear_handlers :ibb_open, :from => @iq.from, :sid => @iq.sid
|
|
51
|
+
@stream.write @iq.reply
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Decline an incoming file-transfer
|
|
55
|
+
def decline
|
|
56
|
+
@stream.clear_handlers :ibb_open, :from => @iq.from
|
|
57
|
+
@stream.clear_handlers :ibb_data, :from => @iq.from, :sid => @iq.sid
|
|
58
|
+
@stream.clear_handlers :ibb_close, :from => @iq.from, :sid => @iq.sid
|
|
59
|
+
@stream.write StanzaError.new(@iq, 'not-acceptable', :cancel).to_node
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Offer a file to somebody, not implemented yet
|
|
63
|
+
def offer
|
|
64
|
+
# TODO: implement
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module Blather
|
|
2
|
+
class FileTransfer
|
|
3
|
+
# SOCKS5 Bytestreams Transfer helper
|
|
4
|
+
# Takes care of accepting, declining and offering file transfers through the stream
|
|
5
|
+
class S5b
|
|
6
|
+
|
|
7
|
+
# Set this to false if you don't want to fallback to In-Band Bytestreams
|
|
8
|
+
attr_accessor :allow_ibb_fallback
|
|
9
|
+
|
|
10
|
+
# Set this to true if the buddies of your bot will be in the same local network
|
|
11
|
+
#
|
|
12
|
+
# Usually IM clients advertise all network addresses which they can determine.
|
|
13
|
+
# Skipping the local ones can save time if your bot is not in the same local network as it's buddies
|
|
14
|
+
attr_accessor :allow_private_ips
|
|
15
|
+
|
|
16
|
+
def initialize(stream, iq)
|
|
17
|
+
@stream = stream
|
|
18
|
+
@iq = iq
|
|
19
|
+
@allow_ibb_fallback = true
|
|
20
|
+
@allow_private_ips = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Accept an incoming file-transfer
|
|
24
|
+
#
|
|
25
|
+
# @param [module] handler the handler for incoming data, see Blather::FileTransfer::SimpleFileReceiver for an example
|
|
26
|
+
# @param [Array] params the params to be passed into the handler
|
|
27
|
+
def accept(handler, *params)
|
|
28
|
+
@streamhosts = @iq.streamhosts
|
|
29
|
+
@streamhosts.delete_if {|s| begin IPAddr.new(s.host).private? rescue false end } unless @allow_private_ips
|
|
30
|
+
@socket_address = Digest::SHA1.hexdigest("#{@iq.sid}#{@iq.from}#{@iq.to}")
|
|
31
|
+
|
|
32
|
+
@handler = handler
|
|
33
|
+
@params = params
|
|
34
|
+
|
|
35
|
+
connect_next_streamhost
|
|
36
|
+
@stream.clear_handlers :s5b_open, :from => @iq.from
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Decline an incoming file-transfer
|
|
40
|
+
def decline
|
|
41
|
+
@stream.clear_handlers :s5b_open, :from => @iq.from
|
|
42
|
+
@stream.write StanzaError.new(@iq, 'not-acceptable', :auth).to_node
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Offer a file to somebody, not implemented yet
|
|
46
|
+
def offer
|
|
47
|
+
# TODO: implement
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def connect_next_streamhost
|
|
53
|
+
if streamhost = @streamhosts.shift
|
|
54
|
+
connect(streamhost)
|
|
55
|
+
else
|
|
56
|
+
if @allow_ibb_fallback
|
|
57
|
+
@stream.register_handler :ibb_open, :from => @iq.from, :sid => @iq.sid do |iq|
|
|
58
|
+
transfer = Blather::FileTransfer::Ibb.new(@stream, iq)
|
|
59
|
+
transfer.accept(@handler, *@params)
|
|
60
|
+
true
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@stream.write StanzaError.new(@iq, 'item-not-found', :cancel).to_node
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def connect(streamhost)
|
|
69
|
+
begin
|
|
70
|
+
socket = EM.connect streamhost.host, streamhost.port, SocketConnection, @socket_address, 0, @handler, *@params
|
|
71
|
+
|
|
72
|
+
socket.callback do
|
|
73
|
+
answer = @iq.reply
|
|
74
|
+
answer.streamhosts = nil
|
|
75
|
+
answer.streamhost_used = streamhost.jid
|
|
76
|
+
|
|
77
|
+
@stream.write answer
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
socket.errback do
|
|
81
|
+
connect_next_streamhost
|
|
82
|
+
end
|
|
83
|
+
rescue EventMachine::ConnectionError => e
|
|
84
|
+
connect_next_streamhost
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @private
|
|
89
|
+
class SocketConnection < EM::P::Socks5
|
|
90
|
+
include EM::Deferrable
|
|
91
|
+
|
|
92
|
+
def initialize(host, port, handler, *params)
|
|
93
|
+
super(host, port)
|
|
94
|
+
@@handler = handler
|
|
95
|
+
@params = params
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def post_init
|
|
99
|
+
self.succeed
|
|
100
|
+
|
|
101
|
+
class << self
|
|
102
|
+
include @@handler
|
|
103
|
+
end
|
|
104
|
+
send(:initialize, *@params)
|
|
105
|
+
post_init
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def unbind
|
|
109
|
+
self.fail if @socks_state != :connected
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
data/lib/blather/jid.rb
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
module Blather
|
|
2
|
+
|
|
3
|
+
# Jabber ID or JID
|
|
4
|
+
#
|
|
5
|
+
# See [RFC 3920 Section 3 - Addressing](http://xmpp.org/rfcs/rfc3920.html#addressing)
|
|
6
|
+
#
|
|
7
|
+
# An entity is anything that can be considered a network endpoint (i.e., an
|
|
8
|
+
# ID on the network) and that can communicate using XMPP. All such entities
|
|
9
|
+
# are uniquely addressable in a form that is consistent with RFC 2396 [URI].
|
|
10
|
+
# For historical reasons, the address of an XMPP entity is called a Jabber
|
|
11
|
+
# Identifier or JID. A valid JID contains a set of ordered elements formed
|
|
12
|
+
# of a domain identifier, node identifier, and resource identifier.
|
|
13
|
+
#
|
|
14
|
+
# The syntax for a JID is defined below using the Augmented Backus-Naur Form
|
|
15
|
+
# as defined in [ABNF]. (The IPv4address and IPv6address rules are defined
|
|
16
|
+
# in Appendix B of [IPv6]; the allowable character sequences that conform to
|
|
17
|
+
# the node rule are defined by the Nodeprep profile of [STRINGPREP] as
|
|
18
|
+
# documented in Appendix A of this memo; the allowable character sequences
|
|
19
|
+
# that conform to the resource rule are defined by the Resourceprep profile
|
|
20
|
+
# of [STRINGPREP] as documented in Appendix B of this memo; and the
|
|
21
|
+
# sub-domain rule makes reference to the concept of an internationalized
|
|
22
|
+
# domain label as described in [IDNA].)
|
|
23
|
+
#
|
|
24
|
+
# jid = [ node "@" ] domain [ "/" resource ]
|
|
25
|
+
# domain = fqdn / address-literal
|
|
26
|
+
# fqdn = (sub-domain 1*("." sub-domain))
|
|
27
|
+
# sub-domain = (internationalized domain label)
|
|
28
|
+
# address-literal = IPv4address / IPv6address
|
|
29
|
+
#
|
|
30
|
+
# All JIDs are based on the foregoing structure. The most common use of this
|
|
31
|
+
# structure is to identify an instant messaging user, the server to which
|
|
32
|
+
# the user connects, and the user's connected resource (e.g., a specific
|
|
33
|
+
# client) in the form of <user@host/resource>. However, node types other
|
|
34
|
+
# than clients are possible; for example, a specific chat room offered by a
|
|
35
|
+
# multi-user chat service could be addressed as <room@service> (where "room"
|
|
36
|
+
# is the name of the chat room and "service" is the hostname of the
|
|
37
|
+
# multi-user chat service) and a specific occupant of such a room could be
|
|
38
|
+
# addressed as <room@service/nick> (where "nick" is the occupant's room
|
|
39
|
+
# nickname). Many other JID types are possible (e.g., <domain/resource>
|
|
40
|
+
# could be a server-side script or service).
|
|
41
|
+
#
|
|
42
|
+
# Each allowable portion of a JID (node identifier, domain identifier, and
|
|
43
|
+
# resource identifier) MUST NOT be more than 1023 bytes in length, resulting
|
|
44
|
+
# in a maximum total size (including the '@' and '/' separators) of 3071
|
|
45
|
+
# bytes.
|
|
46
|
+
class JID
|
|
47
|
+
include Comparable
|
|
48
|
+
|
|
49
|
+
# Validating pattern for JID string
|
|
50
|
+
PATTERN = /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/.freeze
|
|
51
|
+
|
|
52
|
+
attr_reader :node,
|
|
53
|
+
:domain,
|
|
54
|
+
:resource
|
|
55
|
+
|
|
56
|
+
# @private
|
|
57
|
+
def self.new(node, domain = nil, resource = nil)
|
|
58
|
+
node.is_a?(JID) ? node : super
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Create a new JID object
|
|
62
|
+
#
|
|
63
|
+
# @overload initialize(jid)
|
|
64
|
+
# Passes the jid object right back out
|
|
65
|
+
# @param [Blather::JID] jid a jid object
|
|
66
|
+
# @overload initialize(jid)
|
|
67
|
+
# Creates a new JID parsed out of the provided jid
|
|
68
|
+
# @param [String] jid a jid in the standard format
|
|
69
|
+
# ("node@domain/resource")
|
|
70
|
+
# @overload initialize(node, domain = nil, resource = nil)
|
|
71
|
+
# Creates a new JID
|
|
72
|
+
# @param [String] node the node of the JID
|
|
73
|
+
# @param [String, nil] domian the domain of the JID
|
|
74
|
+
# @param [String, nil] resource the resource of the JID
|
|
75
|
+
# @raise [ArgumentError] if the parts of the JID are too large (1023 bytes)
|
|
76
|
+
# @return [Blather::JID] a new jid object
|
|
77
|
+
def initialize(node, domain = nil, resource = nil)
|
|
78
|
+
@resource = resource
|
|
79
|
+
@domain = domain
|
|
80
|
+
@node = node
|
|
81
|
+
|
|
82
|
+
if @domain.nil? && @resource.nil?
|
|
83
|
+
@node, @domain, @resource = @node.to_s.scan(PATTERN).first
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
raise ArgumentError, 'Node too long' if (@node || '').length > 1023
|
|
87
|
+
raise ArgumentError, 'Domain too long' if (@domain || '').length > 1023
|
|
88
|
+
raise ArgumentError, 'Resource too long' if (@resource || '').length > 1023
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Turn the JID into a string
|
|
92
|
+
#
|
|
93
|
+
# * ""
|
|
94
|
+
# * "domain"
|
|
95
|
+
# * "node@domain"
|
|
96
|
+
# * "domain/resource"
|
|
97
|
+
# * "node@domain/resource"
|
|
98
|
+
#
|
|
99
|
+
# @return [String] the JID as a string
|
|
100
|
+
def to_s
|
|
101
|
+
s = @domain
|
|
102
|
+
s = "#{@node}@#{s}" if @node
|
|
103
|
+
s = "#{s}/#{@resource}" if @resource
|
|
104
|
+
s
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Returns a new JID with resource removed.
|
|
108
|
+
#
|
|
109
|
+
# @return [Blather::JID] a new JID without a resource
|
|
110
|
+
def stripped
|
|
111
|
+
dup.strip!
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Removes the resource (sets it to nil)
|
|
115
|
+
#
|
|
116
|
+
# @return [Blather::JID] the JID without a resource
|
|
117
|
+
def strip!
|
|
118
|
+
@resource = nil
|
|
119
|
+
self
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Compare two JIDs, helpful for sorting etc.
|
|
123
|
+
#
|
|
124
|
+
# String representations are compared, see JID#to_s
|
|
125
|
+
#
|
|
126
|
+
# @param [#to_s] other a JID to comare against
|
|
127
|
+
# @return [Fixnum<-1, 0, 1>]
|
|
128
|
+
def <=>(other)
|
|
129
|
+
to_s.downcase <=> other.to_s.downcase
|
|
130
|
+
end
|
|
131
|
+
alias_method :eql?, :==
|
|
132
|
+
|
|
133
|
+
# Test if JID is stripped
|
|
134
|
+
#
|
|
135
|
+
# @return [true, false]
|
|
136
|
+
def stripped?
|
|
137
|
+
@resource.nil?
|
|
138
|
+
end
|
|
139
|
+
end # JID
|
|
140
|
+
|
|
141
|
+
end # Blather
|