vines 0.1.0
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/LICENSE +19 -0
- data/README +34 -0
- data/Rakefile +55 -0
- data/bin/vines +95 -0
- data/conf/certs/README +32 -0
- data/conf/certs/ca-bundle.crt +3987 -0
- data/conf/config.rb +114 -0
- data/lib/vines.rb +155 -0
- data/lib/vines/command/bcrypt.rb +12 -0
- data/lib/vines/command/cert.rb +49 -0
- data/lib/vines/command/init.rb +58 -0
- data/lib/vines/command/ldap.rb +35 -0
- data/lib/vines/command/restart.rb +12 -0
- data/lib/vines/command/schema.rb +24 -0
- data/lib/vines/command/start.rb +28 -0
- data/lib/vines/command/stop.rb +18 -0
- data/lib/vines/config.rb +191 -0
- data/lib/vines/contact.rb +99 -0
- data/lib/vines/daemon.rb +78 -0
- data/lib/vines/error.rb +150 -0
- data/lib/vines/jid.rb +56 -0
- data/lib/vines/kit.rb +23 -0
- data/lib/vines/router.rb +125 -0
- data/lib/vines/stanza.rb +55 -0
- data/lib/vines/stanza/iq.rb +50 -0
- data/lib/vines/stanza/iq/auth.rb +18 -0
- data/lib/vines/stanza/iq/disco_info.rb +25 -0
- data/lib/vines/stanza/iq/disco_items.rb +23 -0
- data/lib/vines/stanza/iq/error.rb +16 -0
- data/lib/vines/stanza/iq/ping.rb +16 -0
- data/lib/vines/stanza/iq/query.rb +10 -0
- data/lib/vines/stanza/iq/result.rb +16 -0
- data/lib/vines/stanza/iq/roster.rb +153 -0
- data/lib/vines/stanza/iq/session.rb +22 -0
- data/lib/vines/stanza/iq/vcard.rb +58 -0
- data/lib/vines/stanza/message.rb +41 -0
- data/lib/vines/stanza/presence.rb +119 -0
- data/lib/vines/stanza/presence/error.rb +23 -0
- data/lib/vines/stanza/presence/probe.rb +38 -0
- data/lib/vines/stanza/presence/subscribe.rb +66 -0
- data/lib/vines/stanza/presence/subscribed.rb +64 -0
- data/lib/vines/stanza/presence/unavailable.rb +15 -0
- data/lib/vines/stanza/presence/unsubscribe.rb +57 -0
- data/lib/vines/stanza/presence/unsubscribed.rb +50 -0
- data/lib/vines/storage.rb +216 -0
- data/lib/vines/storage/couchdb.rb +119 -0
- data/lib/vines/storage/ldap.rb +59 -0
- data/lib/vines/storage/local.rb +66 -0
- data/lib/vines/storage/redis.rb +108 -0
- data/lib/vines/storage/sql.rb +174 -0
- data/lib/vines/store.rb +51 -0
- data/lib/vines/stream.rb +198 -0
- data/lib/vines/stream/client.rb +131 -0
- data/lib/vines/stream/client/auth.rb +94 -0
- data/lib/vines/stream/client/auth_restart.rb +33 -0
- data/lib/vines/stream/client/bind.rb +58 -0
- data/lib/vines/stream/client/bind_restart.rb +25 -0
- data/lib/vines/stream/client/closed.rb +13 -0
- data/lib/vines/stream/client/ready.rb +15 -0
- data/lib/vines/stream/client/start.rb +27 -0
- data/lib/vines/stream/client/tls.rb +37 -0
- data/lib/vines/stream/component.rb +53 -0
- data/lib/vines/stream/component/handshake.rb +25 -0
- data/lib/vines/stream/component/ready.rb +24 -0
- data/lib/vines/stream/component/start.rb +19 -0
- data/lib/vines/stream/http.rb +111 -0
- data/lib/vines/stream/http/http_request.rb +22 -0
- data/lib/vines/stream/http/http_state.rb +139 -0
- data/lib/vines/stream/http/http_states.rb +53 -0
- data/lib/vines/stream/parser.rb +78 -0
- data/lib/vines/stream/server.rb +126 -0
- data/lib/vines/stream/server/auth.rb +13 -0
- data/lib/vines/stream/server/auth_restart.rb +19 -0
- data/lib/vines/stream/server/final_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/auth.rb +31 -0
- data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/auth_result.rb +28 -0
- data/lib/vines/stream/server/outbound/final_features.rb +27 -0
- data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/start.rb +20 -0
- data/lib/vines/stream/server/outbound/tls.rb +30 -0
- data/lib/vines/stream/server/outbound/tls_result.rb +31 -0
- data/lib/vines/stream/server/ready.rb +20 -0
- data/lib/vines/stream/server/start.rb +13 -0
- data/lib/vines/stream/server/tls.rb +13 -0
- data/lib/vines/stream/state.rb +55 -0
- data/lib/vines/token_bucket.rb +46 -0
- data/lib/vines/user.rb +124 -0
- data/lib/vines/version.rb +5 -0
- data/lib/vines/xmpp_server.rb +25 -0
- data/test/config_test.rb +396 -0
- data/test/error_test.rb +59 -0
- data/test/ext/nokogiri.rb +14 -0
- data/test/jid_test.rb +71 -0
- data/test/kit_test.rb +21 -0
- data/test/router_test.rb +60 -0
- data/test/stanza/iq/roster_test.rb +198 -0
- data/test/stanza/iq/session_test.rb +30 -0
- data/test/stanza/iq/vcard_test.rb +159 -0
- data/test/stanza/message_test.rb +124 -0
- data/test/stanza/presence/subscribe_test.rb +75 -0
- data/test/storage/couchdb_test.rb +102 -0
- data/test/storage/ldap_test.rb +207 -0
- data/test/storage/local_test.rb +54 -0
- data/test/storage/redis_test.rb +75 -0
- data/test/storage/sql_test.rb +55 -0
- data/test/storage/storage_tests.rb +134 -0
- data/test/storage_test.rb +90 -0
- data/test/stream/client/auth_test.rb +127 -0
- data/test/stream/client/ready_test.rb +47 -0
- data/test/stream/component/handshake_test.rb +46 -0
- data/test/stream/component/ready_test.rb +105 -0
- data/test/stream/component/start_test.rb +41 -0
- data/test/stream/parser_test.rb +121 -0
- data/test/stream/server/outbound/auth_test.rb +77 -0
- data/test/stream/server/ready_test.rb +100 -0
- data/test/token_bucket_test.rb +24 -0
- data/test/user_test.rb +64 -0
- metadata +318 -0
data/lib/vines/jid.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class JID
|
|
5
|
+
include Comparable
|
|
6
|
+
|
|
7
|
+
PATTERN = /^(?:([^@]*)@)??([^@\/]*)(?:\/(.*?))?$/.freeze
|
|
8
|
+
|
|
9
|
+
attr_reader :node, :domain, :resource
|
|
10
|
+
attr_writer :resource
|
|
11
|
+
|
|
12
|
+
def self.new(node, domain=nil, resource=nil)
|
|
13
|
+
node.is_a?(JID) ? node : super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(node, domain=nil, resource=nil)
|
|
17
|
+
@node, @domain, @resource = node, domain, resource
|
|
18
|
+
|
|
19
|
+
if @domain.nil? && @resource.nil?
|
|
20
|
+
@node, @domain, @resource = @node.to_s.scan(PATTERN).first
|
|
21
|
+
end
|
|
22
|
+
[@node, @domain].each {|piece| piece.downcase! if piece }
|
|
23
|
+
|
|
24
|
+
[@node, @domain, @resource].each do |piece|
|
|
25
|
+
raise ArgumentError, 'jid too long' if (piece || '').size > 1023
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def bare
|
|
30
|
+
JID.new(@node, @domain)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def bare?
|
|
34
|
+
@resource.nil?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def <=>(jid)
|
|
38
|
+
self.to_s <=> jid.to_s
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def eql?(jid)
|
|
42
|
+
jid.is_a?(JID) && self == jid
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def hash
|
|
46
|
+
self.to_s.hash
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_s
|
|
50
|
+
s = @domain
|
|
51
|
+
s = "#{@node}@#{s}" if @node
|
|
52
|
+
s = "#{s}/#{@resource}" if @resource
|
|
53
|
+
s
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/vines/kit.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
|
|
5
|
+
# A module for utility methods with no better home.
|
|
6
|
+
module Kit
|
|
7
|
+
|
|
8
|
+
# Create a hex-encoded, SHA-512 HMAC of the data, using the secret key.
|
|
9
|
+
def self.hmac(key, data)
|
|
10
|
+
digest = OpenSSL::Digest::Digest.new("sha512")
|
|
11
|
+
OpenSSL::HMAC.hexdigest(digest, key, data)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Generates a random uuid per rfc 4122 that's useful for including in
|
|
15
|
+
# stream, iq, and other xmpp stanzas.
|
|
16
|
+
def self.uuid
|
|
17
|
+
hex = (0...16).map { "%02x" % rand(256) }.join
|
|
18
|
+
hex[12] = '4'
|
|
19
|
+
hex[16] = %w[8 9 a b][rand(4)]
|
|
20
|
+
hex.scan(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/).first.join('-')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/vines/router.rb
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
# The router tracks all stream connections to the server for all clients,
|
|
5
|
+
# servers, and components. It sends stanzas to the correct stream based on
|
|
6
|
+
# the 'to' attribute. Router is a singleton, shared by all streams, that must
|
|
7
|
+
# be accessed with +Router.instance+, not +Router.new+.
|
|
8
|
+
class Router
|
|
9
|
+
ROUTABLE_STANZAS = %w[message iq presence].freeze
|
|
10
|
+
|
|
11
|
+
@@instance = nil
|
|
12
|
+
def self.instance
|
|
13
|
+
@@instance ||= Router.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
@config = nil
|
|
18
|
+
@streams = Hash.new {|h,k| h[k] = [] }
|
|
19
|
+
@pending = Hash.new {|h,k| h[k] = [] }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
%w[Client Server Component].each do |klass|
|
|
23
|
+
name = klass.split(/(?=[A-Z])/).join('_').downcase
|
|
24
|
+
define_method(name + 's') do
|
|
25
|
+
@streams["Vines::Stream::#{klass}"]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def http_states
|
|
30
|
+
@streams["Vines::Stream::Http::HttpState"]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns streams for all connected resources for this JID. A
|
|
34
|
+
# resource is considered connected after it has completed authentication
|
|
35
|
+
# and resource binding.
|
|
36
|
+
def connected_resources(jid)
|
|
37
|
+
jid = JID.new(jid)
|
|
38
|
+
(clients + http_states).select do |stream|
|
|
39
|
+
stream.connected? && jid == (jid.bare? ? stream.user.jid.bare : stream.user.jid)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns streams for all available resources for this JID. A
|
|
44
|
+
# resource is marked available after it sends initial presence.
|
|
45
|
+
# This method accepts a single JID or a list of JIDs.
|
|
46
|
+
def available_resources(*jid)
|
|
47
|
+
ids = jid.flatten.map {|jid| JID.new(jid).bare }
|
|
48
|
+
(clients + http_states).select do |stream|
|
|
49
|
+
stream.available? && ids.include?(stream.user.jid.bare)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns streams for all interested resources for this JID. A
|
|
54
|
+
# resource is marked interested after it requests the roster.
|
|
55
|
+
# This method accepts a single JID or a list of JIDs.
|
|
56
|
+
def interested_resources(*jid)
|
|
57
|
+
ids = jid.flatten.map {|jid| JID.new(jid).bare }
|
|
58
|
+
(clients + http_states).select do |stream|
|
|
59
|
+
stream.interested? && ids.include?(stream.user.jid.bare)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Add the connection to the routing table.
|
|
64
|
+
def <<(connection)
|
|
65
|
+
@config ||= connection.config
|
|
66
|
+
@streams[connection.class.to_s] << connection
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Remove the connection from the routing table.
|
|
70
|
+
def delete(connection)
|
|
71
|
+
@streams[connection.class.to_s].delete(connection)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Send the stanza to the appropriate remote server-to-server stream
|
|
75
|
+
# or an external component stream.
|
|
76
|
+
def route(stanza)
|
|
77
|
+
to, from = %w[to from].map {|attr| JID.new(stanza[attr]) }
|
|
78
|
+
if stream = connection_to(to.domain)
|
|
79
|
+
stream.write(stanza)
|
|
80
|
+
elsif @pending.key?(to.domain)
|
|
81
|
+
@pending[to.domain] << stanza
|
|
82
|
+
elsif @config.s2s?(to.domain)
|
|
83
|
+
@pending[to.domain] << stanza
|
|
84
|
+
Vines::Stream::Server.start(@config, to.domain, from.domain) do |stream|
|
|
85
|
+
if stream
|
|
86
|
+
@pending[to.domain].each {|s| stream.write(s) }
|
|
87
|
+
else
|
|
88
|
+
@pending[to.domain].each do |s|
|
|
89
|
+
xml = StanzaErrors::RemoteServerNotFound.new(s, 'cancel').to_xml
|
|
90
|
+
connected_resources(s['from']).each {|c| c.write(xml) }
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
@pending.delete(to.domain)
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
raise StanzaErrors::RemoteServerNotFound.new(stanza, 'cancel')
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Returns true if this stanza should be processed locally. Returns false
|
|
101
|
+
# if it's destined for a remote domain or external component.
|
|
102
|
+
def local?(stanza)
|
|
103
|
+
return true unless ROUTABLE_STANZAS.include?(stanza.name)
|
|
104
|
+
to = (stanza['to'] || '').strip
|
|
105
|
+
to.empty? || local_jid?(to)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def local_jid?(jid)
|
|
109
|
+
@config.vhost?(JID.new(jid).domain)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Returns the total number of streams connected to the server.
|
|
113
|
+
def size
|
|
114
|
+
@streams.values.inject(0) {|sum, arr| sum + arr.size }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
def connection_to(domain)
|
|
120
|
+
(components + servers).find do |stream|
|
|
121
|
+
stream.ready? && stream.remote_domain == domain
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
data/lib/vines/stanza.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stanza
|
|
5
|
+
include Nokogiri::XML
|
|
6
|
+
|
|
7
|
+
attr_reader :stream
|
|
8
|
+
MESSAGE = 'message'.freeze
|
|
9
|
+
@@types = {}
|
|
10
|
+
|
|
11
|
+
def self.register(xpath, ns={})
|
|
12
|
+
@@types[[xpath, ns]] = self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.from_node(node, stream)
|
|
16
|
+
# optimize common case
|
|
17
|
+
return Message.new(node, stream) if node.name == MESSAGE
|
|
18
|
+
found = @@types.select {|pair, v| node.xpath(*pair).any? }
|
|
19
|
+
.sort {|a, b| b[0][0].length - a[0][0].length }.first
|
|
20
|
+
found ? found[1].new(node, stream) : nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def initialize(node, stream)
|
|
24
|
+
@node, @stream = node, stream
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def broadcast(recipients)
|
|
28
|
+
stream.broadcast(@node, recipients)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def local?
|
|
32
|
+
stream.router.local?(@node)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def route
|
|
36
|
+
stream.router.route(@node)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def router
|
|
40
|
+
stream.router
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def storage(domain=stream.domain)
|
|
44
|
+
stream.storage(domain)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def process
|
|
48
|
+
raise 'subclass must implement'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def method_missing(method, *args, &block)
|
|
52
|
+
@node.send(method, *args, &block)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stanza
|
|
5
|
+
class Iq < Stanza
|
|
6
|
+
register "/iq"
|
|
7
|
+
|
|
8
|
+
VALID_TYPES = %w[get set result error].freeze
|
|
9
|
+
|
|
10
|
+
VALID_TYPES.each do |type|
|
|
11
|
+
define_method "#{type}?" do
|
|
12
|
+
self['type'] == type
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def process
|
|
17
|
+
if self['id'] && VALID_TYPES.include?(self['type'])
|
|
18
|
+
raise StanzaErrors::FeatureNotImplemented.new(@node, 'cancel')
|
|
19
|
+
else
|
|
20
|
+
raise StanzaErrors::BadRequest.new(@node, 'modify')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_result
|
|
25
|
+
doc = Document.new
|
|
26
|
+
doc.create_element('iq',
|
|
27
|
+
'from' => stream.domain,
|
|
28
|
+
'id' => self['id'],
|
|
29
|
+
'to' => stream.user.jid.to_s,
|
|
30
|
+
'type' => 'result')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def route_iq
|
|
36
|
+
to = (self['to'] || '').strip
|
|
37
|
+
return false if to.empty? || to == stream.domain
|
|
38
|
+
self['from'] = stream.user.jid.to_s
|
|
39
|
+
if local?
|
|
40
|
+
router.available_resources(to).each do |recipient|
|
|
41
|
+
recipient.write(@node)
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
route
|
|
45
|
+
end
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stanza
|
|
5
|
+
class Iq
|
|
6
|
+
class Auth < Query
|
|
7
|
+
register "/iq[@id and @type='get']/ns:query", 'ns' => NAMESPACES[:non_sasl]
|
|
8
|
+
|
|
9
|
+
def process
|
|
10
|
+
# XEP-0078 says we MUST send a service-unavailable error
|
|
11
|
+
# here, but Adium 1.4.1 won't login if we do that, so just
|
|
12
|
+
# swallow this stanza.
|
|
13
|
+
# raise StanzaErrors::ServiceUnavailable.new(@node, 'cancel')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stanza
|
|
5
|
+
class Iq
|
|
6
|
+
class DiscoInfo < Query
|
|
7
|
+
NS = NAMESPACES[:disco_info]
|
|
8
|
+
|
|
9
|
+
register "/iq[@id and @type='get']/ns:query", 'ns' => NS
|
|
10
|
+
|
|
11
|
+
def process
|
|
12
|
+
return if route_iq
|
|
13
|
+
result = to_result.tap do |el|
|
|
14
|
+
el << el.document.create_element('query') do |query|
|
|
15
|
+
query.default_namespace = NS
|
|
16
|
+
query << el.document.create_element('feature', 'var' => NAMESPACES[:ping])
|
|
17
|
+
query << el.document.create_element('feature', 'var' => NAMESPACES[:vcard])
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
stream.write(result)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stanza
|
|
5
|
+
class Iq
|
|
6
|
+
class DiscoItems < Query
|
|
7
|
+
NS = NAMESPACES[:disco_items]
|
|
8
|
+
|
|
9
|
+
register "/iq[@id and @type='get']/ns:query", 'ns' => NS
|
|
10
|
+
|
|
11
|
+
def process
|
|
12
|
+
return if route_iq
|
|
13
|
+
result = to_result.tap do |el|
|
|
14
|
+
el << el.document.create_element('query') do |query|
|
|
15
|
+
query.default_namespace = NS
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
stream.write(result)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stanza
|
|
5
|
+
class Iq
|
|
6
|
+
class Ping < Iq
|
|
7
|
+
register "/iq[@id and @type='get']/ns:ping", 'ns' => NAMESPACES[:ping]
|
|
8
|
+
|
|
9
|
+
def process
|
|
10
|
+
return if route_iq
|
|
11
|
+
stream.write(to_result)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|