tp-blather 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- 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,174 @@
|
|
1
|
+
module Blather
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
# A helper class for providing a simplified PubSub interface to the
|
5
|
+
# DSL
|
6
|
+
class PubSub
|
7
|
+
attr_accessor :host
|
8
|
+
|
9
|
+
# Create a new pubsub DSL
|
10
|
+
#
|
11
|
+
# @param [Blather::Client] client the client who's connection will be used
|
12
|
+
# @param [#to_s] host the PubSub host
|
13
|
+
def initialize(client, host)
|
14
|
+
@client = client
|
15
|
+
@host = host
|
16
|
+
end
|
17
|
+
|
18
|
+
# Retrieve Affiliations
|
19
|
+
#
|
20
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
21
|
+
# @yield [Hash] affiliations See {Blather::Stanza::PubSub::Affiliations#list}
|
22
|
+
def affiliations(host = nil, &callback)
|
23
|
+
request Stanza::PubSub::Affiliations.new(:get, send_to(host)), :list, callback
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieve Subscriptions
|
27
|
+
#
|
28
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
29
|
+
# @yield [Hash] affiliations See {Blather::Stanza::PubSub::Subscriptions#list}
|
30
|
+
def subscriptions(host = nil, &callback)
|
31
|
+
request Stanza::PubSub::Subscriptions.new(:get, send_to(host)), :list, callback
|
32
|
+
end
|
33
|
+
|
34
|
+
# Discover Nodes
|
35
|
+
#
|
36
|
+
# @param [#to_s] path the node path
|
37
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
38
|
+
# @yield [Array<Blather::Stanza::DiscoItems::Item>] items
|
39
|
+
def nodes(path = nil, host = nil, &callback)
|
40
|
+
path ||= '/'
|
41
|
+
stanza = Stanza::DiscoItems.new(:get, path)
|
42
|
+
stanza.to = send_to(host)
|
43
|
+
request stanza, :items, callback
|
44
|
+
end
|
45
|
+
|
46
|
+
# Discover node information
|
47
|
+
#
|
48
|
+
# @param [#to_s] path the node path
|
49
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
50
|
+
# @yield [Blather::Stanza::DiscoInfo>] info
|
51
|
+
def node(path, host = nil, &callback)
|
52
|
+
stanza = Stanza::DiscoInfo.new(:get, path)
|
53
|
+
stanza.to = send_to(host)
|
54
|
+
request stanza, nil, callback
|
55
|
+
end
|
56
|
+
|
57
|
+
# Retrieve items for a node
|
58
|
+
#
|
59
|
+
# @param [#to_s] path the node path
|
60
|
+
# @param [Array<#to_s>] list a list of IDs to retrieve
|
61
|
+
# @param [Fixnum, #to_s] max the maximum number of items to return
|
62
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
63
|
+
# @yield [Array<Blather::Stanza::PubSub::PubSubItem>] items see {Blather::Stanza::PubSub::Items#items}
|
64
|
+
def items(path, list = [], max = nil, host = nil, &callback)
|
65
|
+
request(
|
66
|
+
Stanza::PubSub::Items.request(send_to(host), path, list, max),
|
67
|
+
:items,
|
68
|
+
callback
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Subscribe to a node
|
73
|
+
#
|
74
|
+
# @param [#to_s] node the node to subscribe to
|
75
|
+
# @param [Blather::JID, #to_s] jid is the jid that should be used.
|
76
|
+
# Defaults to the stripped current JID
|
77
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
78
|
+
# @yield [Blather::Stanza] stanza the reply stanza
|
79
|
+
def subscribe(node, jid = nil, host = nil)
|
80
|
+
jid ||= client.jid.stripped
|
81
|
+
stanza = Stanza::PubSub::Subscribe.new(:set, send_to(host), node, jid)
|
82
|
+
request(stanza) { |n| yield n if block_given? }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Unsubscribe from a node
|
86
|
+
#
|
87
|
+
# @param [#to_s] node the node to unsubscribe from
|
88
|
+
# @param [Blather::JID, #to_s] jid is the jid that should be used.
|
89
|
+
# Defaults to the stripped current JID
|
90
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
91
|
+
# @yield [Blather::Stanza] stanza the reply stanza
|
92
|
+
def unsubscribe(node, jid = nil, subid = nil, host = nil)
|
93
|
+
jid ||= client.jid.stripped
|
94
|
+
stanza = Stanza::PubSub::Unsubscribe.new(:set, send_to(host), node, jid, subid)
|
95
|
+
request(stanza) { |n| yield n if block_given? }
|
96
|
+
end
|
97
|
+
|
98
|
+
# Publish an item to a node
|
99
|
+
#
|
100
|
+
# @param [#to_s] node the node to publish to
|
101
|
+
# @param [#to_s] payload the payload to send see {Blather::Stanza::PubSub::Publish}
|
102
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
103
|
+
# @yield [Blather::Stanza] stanza the reply stanza
|
104
|
+
def publish(node, payload, host = nil)
|
105
|
+
stanza = Stanza::PubSub::Publish.new(send_to(host), node, :set, payload)
|
106
|
+
request(stanza) { |n| yield n if block_given? }
|
107
|
+
end
|
108
|
+
|
109
|
+
# Delete items from a node
|
110
|
+
#
|
111
|
+
# @param [#to_s] node the node to delete from
|
112
|
+
# @param [Array<#to_s>] ids a list of ids to delete
|
113
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
114
|
+
# @yield [Blather::Stanza] stanza the reply stanza
|
115
|
+
def retract(node, ids = [], host = nil)
|
116
|
+
stanza = Stanza::PubSub::Retract.new(send_to(host), node, :set, ids)
|
117
|
+
request(stanza) { |n| yield n if block_given? }
|
118
|
+
end
|
119
|
+
|
120
|
+
# Create a node
|
121
|
+
#
|
122
|
+
# @param [#to_s] node the node to create
|
123
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
124
|
+
# @param [optional, Blather::Stanza::X] configuration the additional configuration to be set to created node
|
125
|
+
# @yield [Blather::Stanza] stanza the reply stanza
|
126
|
+
def create(node, host = nil, configuration = nil)
|
127
|
+
stanza = Stanza::PubSub::Create.new(:set, send_to(host), node)
|
128
|
+
stanza.configure_node << configuration if configuration
|
129
|
+
request(stanza) { |n| yield n if block_given? }
|
130
|
+
end
|
131
|
+
|
132
|
+
# Purge all node items
|
133
|
+
#
|
134
|
+
# @param [#to_s] node the node to purge
|
135
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
136
|
+
# @yield [Blather::Stanza] stanza the reply stanza
|
137
|
+
def purge(node, host = nil)
|
138
|
+
stanza = Stanza::PubSubOwner::Purge.new(:set, send_to(host), node)
|
139
|
+
request(stanza) { |n| yield n if block_given? }
|
140
|
+
end
|
141
|
+
|
142
|
+
# Delete a node
|
143
|
+
#
|
144
|
+
# @param [#to_s] node the node to delete
|
145
|
+
# @param [#to_s] host the PubSub host (defaults to the initialized host)
|
146
|
+
# @yield [Blather::Stanza] stanza the reply stanza
|
147
|
+
def delete(node, host = nil)
|
148
|
+
stanza = Stanza::PubSubOwner::Delete.new(:set, send_to(host), node)
|
149
|
+
request(stanza) { |n| yield n if block_given? }
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
def request(node, method = nil, callback = nil, &block)
|
154
|
+
unless block_given?
|
155
|
+
block = lambda do |node|
|
156
|
+
callback.call(method ? node.__send__(method) : node)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
client.write_with_handler(node, &block)
|
161
|
+
end
|
162
|
+
|
163
|
+
def send_to(host = nil)
|
164
|
+
raise 'You must provide a host' unless (host ||= @host)
|
165
|
+
host
|
166
|
+
end
|
167
|
+
|
168
|
+
def client
|
169
|
+
@client
|
170
|
+
end
|
171
|
+
end # PubSub
|
172
|
+
|
173
|
+
end # DSL
|
174
|
+
end # Blather
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# @private
|
2
|
+
module EventMachine
|
3
|
+
# @private
|
4
|
+
module Protocols
|
5
|
+
# Basic SOCKS v5 client implementation
|
6
|
+
#
|
7
|
+
# Use as you would any regular connection:
|
8
|
+
#
|
9
|
+
# class MyConn < EM::P::Socks5
|
10
|
+
# def post_init
|
11
|
+
# send_data("sup")
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def receive_data(data)
|
15
|
+
# send_data("you said: #{data}")
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# EM.connect socks_host, socks_port, MyConn, host, port
|
20
|
+
#
|
21
|
+
# @private
|
22
|
+
class Socks5 < Connection
|
23
|
+
def initialize(host, port)
|
24
|
+
@host = host
|
25
|
+
@port = port
|
26
|
+
@socks_error_code = nil
|
27
|
+
@buffer = ''
|
28
|
+
@socks_state = :method_negotiation
|
29
|
+
@socks_methods = [0] # TODO: other authentication methods
|
30
|
+
setup_methods
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup_methods
|
34
|
+
class << self
|
35
|
+
def post_init; socks_post_init; end
|
36
|
+
def receive_data(*a); socks_receive_data(*a); end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def restore_methods
|
41
|
+
class << self
|
42
|
+
remove_method :post_init
|
43
|
+
remove_method :receive_data
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def socks_post_init
|
48
|
+
packet = [5, @socks_methods.size].pack('CC') + @socks_methods.pack('C*')
|
49
|
+
send_data(packet)
|
50
|
+
end
|
51
|
+
|
52
|
+
def socks_receive_data(data)
|
53
|
+
@buffer << data
|
54
|
+
|
55
|
+
if @socks_state == :method_negotiation
|
56
|
+
return if @buffer.size < 2
|
57
|
+
|
58
|
+
header_resp = @buffer.slice! 0, 2
|
59
|
+
_, method_code = header_resp.unpack("cc")
|
60
|
+
|
61
|
+
if @socks_methods.include?(method_code)
|
62
|
+
@socks_state = :connecting
|
63
|
+
packet = [5, 1, 0].pack("C*")
|
64
|
+
|
65
|
+
if @host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ # IPv4
|
66
|
+
packet << [1, $1.to_i, $2.to_i, $3.to_i, $4.to_i].pack("C*")
|
67
|
+
elsif @host.include?(":") # IPv6
|
68
|
+
l, r = if @host =~ /^(.*)::(.*)$/
|
69
|
+
[$1,$2].map {|i| i.split ":"}
|
70
|
+
else
|
71
|
+
[@host.split(":"),[]]
|
72
|
+
end
|
73
|
+
dec_groups = (l + Array.new(8-l.size-r.size, '0') + r).map {|i| i.hex}
|
74
|
+
packet << ([4] + dec_groups).pack("Cn8")
|
75
|
+
else # Domain
|
76
|
+
packet << [3, @host.length, @host].pack("CCA*")
|
77
|
+
end
|
78
|
+
packet << [@port].pack("n")
|
79
|
+
|
80
|
+
send_data packet
|
81
|
+
else
|
82
|
+
@socks_state = :invalid
|
83
|
+
@socks_error_code = method_code
|
84
|
+
close_connection
|
85
|
+
return
|
86
|
+
end
|
87
|
+
elsif @socks_state == :connecting
|
88
|
+
return if @buffer.size < 4
|
89
|
+
|
90
|
+
header_resp = @buffer.slice! 0, 4
|
91
|
+
_, response_code, _, address_type = header_resp.unpack("C*")
|
92
|
+
|
93
|
+
if response_code == 0
|
94
|
+
case address_type
|
95
|
+
when 1
|
96
|
+
@buffer.slice! 0, 4
|
97
|
+
when 3
|
98
|
+
len = @buffer.slice! 0, 1
|
99
|
+
@buffer.slice! 0, len.unpack("C").first
|
100
|
+
when 4
|
101
|
+
@buffer.slice! 0, 16
|
102
|
+
else
|
103
|
+
@socks_state = :invalid
|
104
|
+
@socks_error_code = address_type
|
105
|
+
close_connection
|
106
|
+
return
|
107
|
+
end
|
108
|
+
@buffer.slice! 0, 2
|
109
|
+
|
110
|
+
@socks_state = :connected
|
111
|
+
restore_methods
|
112
|
+
|
113
|
+
post_init
|
114
|
+
receive_data(@buffer) unless @buffer.empty?
|
115
|
+
else
|
116
|
+
@socks_state = :invalid
|
117
|
+
@socks_error_code = response_code
|
118
|
+
close_connection
|
119
|
+
return
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# @private
|
2
|
+
class IPAddr
|
3
|
+
PrivateRanges = [
|
4
|
+
IPAddr.new("10.0.0.0/8"),
|
5
|
+
IPAddr.new("172.16.0.0/12"),
|
6
|
+
IPAddr.new("192.168.0.0/16")
|
7
|
+
]
|
8
|
+
|
9
|
+
def private?
|
10
|
+
return false unless self.ipv4?
|
11
|
+
PrivateRanges.each do |ipr|
|
12
|
+
return true if ipr.include?(self)
|
13
|
+
end
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
|
17
|
+
def public?
|
18
|
+
!private?
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Blather
|
2
|
+
# Main error class
|
3
|
+
# This starts the error hierarchy
|
4
|
+
#
|
5
|
+
# @handler :error
|
6
|
+
class BlatherError < StandardError
|
7
|
+
class_attribute :handler_hierarchy
|
8
|
+
self.handler_hierarchy ||= []
|
9
|
+
|
10
|
+
# @private
|
11
|
+
@@handler_list = []
|
12
|
+
|
13
|
+
# Register the class's handler
|
14
|
+
#
|
15
|
+
# @param [Symbol] handler the handler name
|
16
|
+
def self.register(handler)
|
17
|
+
@@handler_list << handler
|
18
|
+
self.handler_hierarchy = [handler] + self.handler_hierarchy
|
19
|
+
end
|
20
|
+
|
21
|
+
# The list of registered handlers
|
22
|
+
#
|
23
|
+
# @return [Array<Symbol>] a list of currently registered handlers
|
24
|
+
def self.handler_list
|
25
|
+
@@handler_list
|
26
|
+
end
|
27
|
+
|
28
|
+
register :error
|
29
|
+
|
30
|
+
# @private
|
31
|
+
# HACK!! until I can refactor the entire Error object model
|
32
|
+
def id
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end # BlatherError
|
36
|
+
|
37
|
+
# Used in cases where a stanza only allows specific values for its attributes
|
38
|
+
# and an invalid value is attempted.
|
39
|
+
#
|
40
|
+
# @handler :argument_error
|
41
|
+
class ArgumentError < BlatherError
|
42
|
+
register :argument_error
|
43
|
+
end # ArgumentError
|
44
|
+
|
45
|
+
# The stream handler received a response it didn't know how to handle
|
46
|
+
#
|
47
|
+
# @handler :unknown_response_error
|
48
|
+
class UnknownResponse < BlatherError
|
49
|
+
register :unknown_response_error
|
50
|
+
attr_reader :node
|
51
|
+
|
52
|
+
def initialize(node)
|
53
|
+
@node = node
|
54
|
+
end
|
55
|
+
end # UnknownResponse
|
56
|
+
|
57
|
+
# Something bad happened while parsing the incoming stream
|
58
|
+
#
|
59
|
+
# @handler :parse_error
|
60
|
+
class ParseError < BlatherError
|
61
|
+
register :parse_error
|
62
|
+
attr_reader :message
|
63
|
+
|
64
|
+
def initialize(msg)
|
65
|
+
@message = msg.to_s
|
66
|
+
end
|
67
|
+
end # ParseError
|
68
|
+
|
69
|
+
end # Blather
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Blather
|
2
|
+
|
3
|
+
# General SASL Errors
|
4
|
+
# Check #name for the error name
|
5
|
+
#
|
6
|
+
# @handler :sasl_error
|
7
|
+
class SASLError < BlatherError
|
8
|
+
# @private
|
9
|
+
SASL_ERR_NS = 'urn:ietf:params:xml:ns:xmpp-sasl'
|
10
|
+
|
11
|
+
class_attribute :err_name
|
12
|
+
# @private
|
13
|
+
@@registrations = {}
|
14
|
+
|
15
|
+
register :sasl_error
|
16
|
+
|
17
|
+
# Import the stanza
|
18
|
+
#
|
19
|
+
# @param [Blather::XMPPNode] node the error node
|
20
|
+
# @return [Blather::SASLError]
|
21
|
+
def self.import(node)
|
22
|
+
self.new node
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create a new SASLError
|
26
|
+
#
|
27
|
+
# @param [Blather::XMPPNode] node the error node
|
28
|
+
def initialize(node)
|
29
|
+
super()
|
30
|
+
@node = node
|
31
|
+
end
|
32
|
+
|
33
|
+
# The actual error name
|
34
|
+
#
|
35
|
+
# @return [Symbol] a symbol representing the error name
|
36
|
+
def name
|
37
|
+
if @node
|
38
|
+
name = @node.find_first('ns:*', :ns => SASL_ERR_NS).element_name
|
39
|
+
name.gsub('-', '_').to_sym
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end # SASLError
|
43
|
+
|
44
|
+
end # Blather
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Blather
|
2
|
+
|
3
|
+
# Stanza errors
|
4
|
+
# RFC3920 Section 9.3 (http://xmpp.org/rfcs/rfc3920.html#stanzas-error)
|
5
|
+
#
|
6
|
+
# @handler :stanza_error
|
7
|
+
class StanzaError < BlatherError
|
8
|
+
# @private
|
9
|
+
STANZA_ERR_NS = 'urn:ietf:params:xml:ns:xmpp-stanzas'
|
10
|
+
# @private
|
11
|
+
VALID_TYPES = [:cancel, :continue, :modify, :auth, :wait].freeze
|
12
|
+
|
13
|
+
register :stanza_error
|
14
|
+
|
15
|
+
attr_reader :original, :name, :type, :text, :extras
|
16
|
+
|
17
|
+
# Factory method for instantiating the proper class for the error
|
18
|
+
#
|
19
|
+
# @param [Blather::XMPPNode] node the error node to import
|
20
|
+
# @return [Blather::StanzaError]
|
21
|
+
def self.import(node)
|
22
|
+
original = node.copy
|
23
|
+
original.remove_child 'error'
|
24
|
+
|
25
|
+
error_node = node.find_first '//*[local-name()="error"]'
|
26
|
+
|
27
|
+
name = error_node.find_first('child::*[name()!="text"]', STANZA_ERR_NS).element_name
|
28
|
+
type = error_node['type']
|
29
|
+
text = node.find_first 'descendant::*[name()="text"]', STANZA_ERR_NS
|
30
|
+
text = text.content if text
|
31
|
+
|
32
|
+
extras = error_node.find("descendant::*[name()!='text' and name()!='#{name}']").map { |n| n }
|
33
|
+
|
34
|
+
self.new original, name, type, text, extras
|
35
|
+
end
|
36
|
+
|
37
|
+
# Create a new StanzaError
|
38
|
+
#
|
39
|
+
# @param [Blather::XMPPNode] original the original stanza
|
40
|
+
# @param [String] name the error name
|
41
|
+
# @param [#to_s] type the error type as specified in
|
42
|
+
# [RFC3920](http://xmpp.org/rfcs/rfc3920.html#rfc.section.9.3.2)
|
43
|
+
# @param [String, nil] text additional text for the error
|
44
|
+
# @param [Array<Blather::XMPPNode>] extras an array of extra nodes to add
|
45
|
+
def initialize(original, name, type, text = nil, extras = [])
|
46
|
+
@original = original
|
47
|
+
@name = name
|
48
|
+
self.type = type
|
49
|
+
@text = text
|
50
|
+
@extras = extras
|
51
|
+
end
|
52
|
+
|
53
|
+
# Set the error type
|
54
|
+
#
|
55
|
+
# @param [#to_sym] type the new error type. Must be on of
|
56
|
+
# Blather::StanzaError::VALID_TYPES
|
57
|
+
# @see [RFC3920 Section 9.3.2](http://xmpp.org/rfcs/rfc3920.html#rfc.section.9.3.2)
|
58
|
+
def type=(type)
|
59
|
+
type = type.to_sym
|
60
|
+
if !VALID_TYPES.include?(type)
|
61
|
+
raise ArgumentError, "Invalid Type (#{type}), use: #{VALID_TYPES*' '}"
|
62
|
+
end
|
63
|
+
@type = type
|
64
|
+
end
|
65
|
+
|
66
|
+
# The error name
|
67
|
+
#
|
68
|
+
# @return [Symbol]
|
69
|
+
def name
|
70
|
+
@name.gsub('-','_').to_sym
|
71
|
+
end
|
72
|
+
|
73
|
+
# Creates an XML node from the error
|
74
|
+
#
|
75
|
+
# @return [Blather::XMPPNode]
|
76
|
+
def to_node
|
77
|
+
node = self.original.reply
|
78
|
+
node.type = 'error'
|
79
|
+
node << (error_node = XMPPNode.new('error'))
|
80
|
+
|
81
|
+
error_node << (err = XMPPNode.new(@name, error_node.document))
|
82
|
+
error_node['type'] = self.type
|
83
|
+
err.namespace = 'urn:ietf:params:xml:ns:xmpp-stanzas'
|
84
|
+
|
85
|
+
if self.text
|
86
|
+
error_node << (text = XMPPNode.new('text', error_node.document))
|
87
|
+
text.namespace = 'urn:ietf:params:xml:ns:xmpp-stanzas'
|
88
|
+
text.content = self.text
|
89
|
+
end
|
90
|
+
|
91
|
+
self.extras.each { |extra| error_node << extra.dup }
|
92
|
+
node
|
93
|
+
end
|
94
|
+
|
95
|
+
# Convert the object to a proper node then convert it to a string
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
def to_xml
|
99
|
+
to_node.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
# @private
|
103
|
+
def inspect
|
104
|
+
"Stanza Error (#{@name}): #{self.text} [#{self.extras}]"
|
105
|
+
end
|
106
|
+
# @private
|
107
|
+
alias_method :to_s, :inspect
|
108
|
+
end # StanzaError
|
109
|
+
|
110
|
+
end # Blather
|