vines 0.3.2 → 0.4.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/README +5 -9
- data/Rakefile +11 -9
- data/conf/config.rb +30 -4
- data/lib/vines/cluster/connection.rb +26 -0
- data/lib/vines/cluster/publisher.rb +55 -0
- data/lib/vines/cluster/pubsub.rb +92 -0
- data/lib/vines/cluster/sessions.rb +125 -0
- data/lib/vines/cluster/subscriber.rb +108 -0
- data/lib/vines/cluster.rb +246 -0
- data/lib/vines/command/init.rb +21 -24
- data/lib/vines/config/host.rb +48 -8
- data/lib/vines/config/port.rb +5 -0
- data/lib/vines/config/pubsub.rb +108 -0
- data/lib/vines/config.rb +74 -20
- data/lib/vines/jid.rb +14 -0
- data/lib/vines/router.rb +69 -55
- data/lib/vines/stanza/iq/disco_info.rb +22 -9
- data/lib/vines/stanza/iq/disco_items.rb +6 -3
- data/lib/vines/stanza/iq/ping.rb +1 -1
- data/lib/vines/stanza/iq/private_storage.rb +4 -8
- data/lib/vines/stanza/iq/roster.rb +6 -14
- data/lib/vines/stanza/iq/session.rb +2 -7
- data/lib/vines/stanza/iq/vcard.rb +4 -6
- data/lib/vines/stanza/iq/version.rb +1 -1
- data/lib/vines/stanza/iq.rb +8 -10
- data/lib/vines/stanza/presence/subscribe.rb +3 -11
- data/lib/vines/stanza/presence/subscribed.rb +16 -29
- data/lib/vines/stanza/presence/unsubscribe.rb +3 -15
- data/lib/vines/stanza/presence/unsubscribed.rb +3 -16
- data/lib/vines/stanza/presence.rb +30 -0
- data/lib/vines/stanza/pubsub/create.rb +39 -0
- data/lib/vines/stanza/pubsub/delete.rb +41 -0
- data/lib/vines/stanza/pubsub/publish.rb +66 -0
- data/lib/vines/stanza/pubsub/subscribe.rb +44 -0
- data/lib/vines/stanza/pubsub/unsubscribe.rb +30 -0
- data/lib/vines/stanza/pubsub.rb +22 -0
- data/lib/vines/stanza.rb +72 -22
- data/lib/vines/storage/couchdb.rb +46 -65
- data/lib/vines/storage/local.rb +20 -14
- data/lib/vines/storage/mongodb.rb +132 -0
- data/lib/vines/storage/null.rb +39 -0
- data/lib/vines/storage/redis.rb +61 -68
- data/lib/vines/storage/sql.rb +73 -69
- data/lib/vines/storage.rb +1 -1
- data/lib/vines/stream/client/bind.rb +2 -2
- data/lib/vines/stream/client/session.rb +71 -16
- data/lib/vines/stream/component/handshake.rb +1 -0
- data/lib/vines/stream/component/ready.rb +2 -2
- data/lib/vines/stream/http/session.rb +2 -0
- data/lib/vines/stream/http.rb +0 -6
- data/lib/vines/stream/server/final_restart.rb +1 -0
- data/lib/vines/stream/server/outbound/final_features.rb +1 -0
- data/lib/vines/stream/server/ready.rb +6 -2
- data/lib/vines/stream/server.rb +4 -3
- data/lib/vines/stream.rb +10 -6
- data/lib/vines/version.rb +1 -1
- data/lib/vines.rb +48 -22
- data/test/cluster/publisher_test.rb +45 -0
- data/test/cluster/sessions_test.rb +54 -0
- data/test/cluster/subscriber_test.rb +94 -0
- data/test/config/host_test.rb +100 -21
- data/test/config/pubsub_test.rb +181 -0
- data/test/config_test.rb +225 -43
- data/test/jid_test.rb +7 -0
- data/test/router_test.rb +181 -9
- data/test/stanza/iq/disco_info_test.rb +8 -6
- data/test/stanza/iq/disco_items_test.rb +3 -3
- data/test/stanza/iq/private_storage_test.rb +8 -19
- data/test/stanza/iq/roster_test.rb +1 -1
- data/test/stanza/iq/session_test.rb +3 -6
- data/test/stanza/iq/vcard_test.rb +6 -2
- data/test/stanza/iq/version_test.rb +3 -2
- data/test/stanza/iq_test.rb +5 -5
- data/test/stanza/message_test.rb +3 -2
- data/test/stanza/presence/probe_test.rb +2 -1
- data/test/stanza/pubsub/create_test.rb +138 -0
- data/test/stanza/pubsub/delete_test.rb +142 -0
- data/test/stanza/pubsub/publish_test.rb +373 -0
- data/test/stanza/pubsub/subscribe_test.rb +186 -0
- data/test/stanza/pubsub/unsubscribe_test.rb +179 -0
- data/test/stanza_test.rb +2 -1
- data/test/storage/local_test.rb +26 -25
- data/test/storage/mock_mongo.rb +40 -0
- data/test/storage/mock_redis.rb +98 -0
- data/test/storage/mongodb_test.rb +81 -0
- data/test/storage/null_test.rb +30 -0
- data/test/storage/redis_test.rb +3 -36
- data/test/stream/component/handshake_test.rb +4 -0
- data/test/stream/component/ready_test.rb +2 -1
- data/test/stream/server/ready_test.rb +7 -1
- data/web/404.html +5 -3
- data/web/chat/coffeescripts/chat.coffee +9 -5
- data/web/chat/javascripts/app.js +1 -1
- data/web/chat/javascripts/chat.js +14 -8
- data/web/chat/stylesheets/chat.css +4 -1
- data/web/lib/coffeescripts/button.coffee +9 -5
- data/web/lib/coffeescripts/filter.coffee +1 -1
- data/web/lib/coffeescripts/login.coffee +14 -1
- data/web/lib/coffeescripts/session.coffee +8 -11
- data/web/lib/images/dark-gray.png +0 -0
- data/web/lib/images/light-gray.png +0 -0
- data/web/lib/images/logo-large.png +0 -0
- data/web/lib/images/logo-small.png +0 -0
- data/web/lib/images/white.png +0 -0
- data/web/lib/javascripts/base.js +9 -8
- data/web/lib/javascripts/button.js +20 -12
- data/web/lib/javascripts/filter.js +1 -1
- data/web/lib/javascripts/icons.js +7 -1
- data/web/lib/javascripts/jquery.js +4 -4
- data/web/lib/javascripts/login.js +16 -2
- data/web/lib/javascripts/raphael.js +5 -7
- data/web/lib/javascripts/session.js +10 -14
- data/web/lib/stylesheets/base.css +7 -11
- data/web/lib/stylesheets/login.css +31 -27
- metadata +100 -34
data/lib/vines/config.rb
CHANGED
@@ -9,7 +9,7 @@ module Vines
|
|
9
9
|
class Config
|
10
10
|
LOG_LEVELS = %w[debug info warn error fatal].freeze
|
11
11
|
|
12
|
-
attr_reader :vhosts
|
12
|
+
attr_reader :router, :vhosts
|
13
13
|
|
14
14
|
@@instance = nil
|
15
15
|
def self.configure(&block)
|
@@ -21,7 +21,9 @@ module Vines
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def initialize(&block)
|
24
|
-
@vhosts, @ports = {}, {}
|
24
|
+
@vhosts, @ports, @cluster = {}, {}, nil
|
25
|
+
@null = Storage::Null.new
|
26
|
+
@router = Router.new(self)
|
25
27
|
instance_eval(&block)
|
26
28
|
raise "must define at least one virtual host" if @vhosts.empty?
|
27
29
|
end
|
@@ -31,7 +33,7 @@ module Vines
|
|
31
33
|
dupes = names.uniq.size != names.size || (@vhosts.keys & names).any?
|
32
34
|
raise "one host definition per domain allowed" if dupes
|
33
35
|
names.each do |name|
|
34
|
-
@vhosts[name] = Host.new(name, &block)
|
36
|
+
@vhosts[name] = Host.new(self, name, &block)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
@@ -45,6 +47,12 @@ module Vines
|
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
50
|
+
def cluster(&block)
|
51
|
+
return @cluster unless block
|
52
|
+
raise "one cluster definition allowed" if @cluster
|
53
|
+
@cluster = Cluster.new(self, &block)
|
54
|
+
end
|
55
|
+
|
48
56
|
def log(level)
|
49
57
|
const = Logger.const_get(level.to_s.upcase) rescue nil
|
50
58
|
unless LOG_LEVELS.include?(level.to_s) && const
|
@@ -59,10 +67,30 @@ module Vines
|
|
59
67
|
|
60
68
|
# Return true if the domain is virtual hosted by this server.
|
61
69
|
def vhost?(domain)
|
62
|
-
@vhosts.key?(domain)
|
70
|
+
@vhosts.key?(domain.to_s)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the storage system for the domain or a Storage::Null instance if
|
74
|
+
# the domain is not hosted at this server.
|
75
|
+
def storage(domain)
|
76
|
+
host = @vhosts[domain.to_s]
|
77
|
+
host ? host.storage : @null
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the PubSub system for the domain or nil if pubsub is not enabled
|
81
|
+
# for this domain.
|
82
|
+
def pubsub(domain)
|
83
|
+
host = @vhosts.values.find {|host| host.pubsub?(domain) }
|
84
|
+
host.pubsubs[domain.to_s] if host
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return true if the domain is a pubsub service hosted at a virtual host
|
88
|
+
# at this server.
|
89
|
+
def pubsub?(domain)
|
90
|
+
@vhosts.values.any? {|host| host.pubsub?(domain) }
|
63
91
|
end
|
64
92
|
|
65
|
-
# Return true if all
|
93
|
+
# Return true if all JIDs belong to components hosted by this server.
|
66
94
|
def component?(*jids)
|
67
95
|
!jids.flatten.index do |jid|
|
68
96
|
!component_password(JID.new(jid).domain)
|
@@ -75,7 +103,7 @@ module Vines
|
|
75
103
|
host.password(domain) if host
|
76
104
|
end
|
77
105
|
|
78
|
-
# Return true if all of the
|
106
|
+
# Return true if all of the JIDs are hosted by this server.
|
79
107
|
def local_jid?(*jids)
|
80
108
|
!jids.flatten.index do |jid|
|
81
109
|
!vhost?(JID.new(jid).domain)
|
@@ -84,13 +112,20 @@ module Vines
|
|
84
112
|
|
85
113
|
# Return true if private XML fragment storage is enabled for this domain.
|
86
114
|
def private_storage?(domain)
|
87
|
-
@vhosts[domain]
|
115
|
+
host = @vhosts[domain.to_s]
|
116
|
+
host.private_storage? if host
|
88
117
|
end
|
89
118
|
|
90
119
|
# Returns true if server-to-server connections are allowed with the
|
91
120
|
# given domain.
|
92
121
|
def s2s?(domain)
|
93
|
-
@ports[:server] && @ports[:server].hosts.include?(domain)
|
122
|
+
@ports[:server] && @ports[:server].hosts.include?(domain.to_s)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Return true if the server is a member of a cluster, serving the same
|
126
|
+
# domains from different machines.
|
127
|
+
def cluster?
|
128
|
+
!!@cluster
|
94
129
|
end
|
95
130
|
|
96
131
|
# Retrieve the Port subclass with this name:
|
@@ -99,16 +134,16 @@ module Vines
|
|
99
134
|
@ports[name] or raise ArgumentError.new("no port named #{name}")
|
100
135
|
end
|
101
136
|
|
102
|
-
# Return true if the two
|
137
|
+
# Return true if the two JIDs are allowed to send messages to each other.
|
103
138
|
# Both domains must have enabled cross_domain_messages in their config files.
|
104
139
|
def allowed?(to, from)
|
105
140
|
to, from = JID.new(to), JID.new(from)
|
106
141
|
return false if to.empty? || from.empty?
|
107
142
|
return true if to.domain == from.domain # same domain always allowed
|
108
143
|
return cross_domain?(to, from) if local_jid?(to, from) # both virtual hosted here
|
109
|
-
return
|
110
|
-
return
|
111
|
-
return
|
144
|
+
return check_subdomains(to, from) if subdomain?(to, from) # component/pubsub to component/pubsub
|
145
|
+
return check_subdomain(to, from) if subdomain?(to) # to component/pubsub
|
146
|
+
return check_subdomain(from, to) if subdomain?(from) # from component/pubsub
|
112
147
|
return cross_domain?(to) if local_jid?(to) # from is remote
|
113
148
|
return cross_domain?(from) if local_jid?(from) # to is remote
|
114
149
|
return false
|
@@ -116,25 +151,44 @@ module Vines
|
|
116
151
|
|
117
152
|
private
|
118
153
|
|
119
|
-
|
120
|
-
|
121
|
-
|
154
|
+
# Return true if all of the JIDs are some kind of subdomain resource hosted
|
155
|
+
# here (either a component or a pubsub domain).
|
156
|
+
def subdomain?(*jids)
|
157
|
+
!jids.flatten.index do |jid|
|
158
|
+
!component?(jid) && !pubsub?(jid)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Return true if the third-level subdomain JIDs (components and pubsubs)
|
163
|
+
# are allowed to communicate with each other. For example, a
|
164
|
+
# tea.wonderland.lit component should be allowed to send messages to
|
165
|
+
# pubsub.wonderland.lit because they share the second-level wonderland.lit
|
166
|
+
# domain.
|
167
|
+
def check_subdomains(to, from)
|
168
|
+
sub1, sub2 = strip_domain(to), strip_domain(from)
|
169
|
+
(sub1 == sub2) || cross_domain?(sub1, sub2)
|
122
170
|
end
|
123
171
|
|
124
|
-
|
125
|
-
|
172
|
+
# Return true if the third-level subdomain JID (component or pubsub) is
|
173
|
+
# allowed to communicate with the other JID. For example,
|
174
|
+
# pubsub.wonderland.lit should be allowed to send messages to
|
175
|
+
# alice@wonderland.lit because they share the second-level wonderland.lit
|
176
|
+
# domain.
|
177
|
+
def check_subdomain(subdomain, jid)
|
178
|
+
comp = strip_domain(subdomain)
|
126
179
|
return true if comp.domain == jid.domain
|
127
180
|
local_jid?(jid) ? cross_domain?(comp, jid) : cross_domain?(comp)
|
128
181
|
end
|
129
182
|
|
130
|
-
# Return the JID's domain with the first subdomain stripped off
|
131
|
-
# alice@tea.wonderland.lit
|
183
|
+
# Return the third-level JID's domain with the first subdomain stripped off
|
184
|
+
# to create a second-level domain. For example, alice@tea.wonderland.lit
|
185
|
+
# returns wonderland.lit.
|
132
186
|
def strip_domain(jid)
|
133
187
|
domain = jid.domain.split('.').drop(1).join('.')
|
134
188
|
JID.new(domain)
|
135
189
|
end
|
136
190
|
|
137
|
-
# Return true if all
|
191
|
+
# Return true if all JIDs are allowed to exchange cross domain messages.
|
138
192
|
def cross_domain?(*jids)
|
139
193
|
!jids.flatten.index do |jid|
|
140
194
|
!@vhosts[jid.domain].cross_domain_messages?
|
data/lib/vines/jid.rb
CHANGED
@@ -30,14 +30,28 @@ module Vines
|
|
30
30
|
validate
|
31
31
|
end
|
32
32
|
|
33
|
+
# Strip the resource part from this JID and return it as a new
|
34
|
+
# JID object. The new JID contains only the optional node part
|
35
|
+
# and the required domain part from the original. This JID remains
|
36
|
+
# unchanged.
|
33
37
|
def bare
|
34
38
|
JID.new(@node, @domain)
|
35
39
|
end
|
36
40
|
|
41
|
+
# Return true if this is a bare JID without a resource part.
|
37
42
|
def bare?
|
38
43
|
@resource.nil?
|
39
44
|
end
|
40
45
|
|
46
|
+
# Return true if this is a domain-only JID without a node or resource part.
|
47
|
+
def domain?
|
48
|
+
!empty? && to_s == @domain
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return true if this JID is equal to the empty string ''. That is, it's
|
52
|
+
# missing the node, domain, and resource parts that form a valid JID. It
|
53
|
+
# makes for easier error handling to be able to create JID objects from
|
54
|
+
# strings and then check if they're empty rather than nil.
|
41
55
|
def empty?
|
42
56
|
to_s == ''
|
43
57
|
end
|
data/lib/vines/router.rb
CHANGED
@@ -4,72 +4,74 @@ module Vines
|
|
4
4
|
# The router tracks all stream connections to the server for all clients,
|
5
5
|
# servers, and components. It sends stanzas to the correct stream based on
|
6
6
|
# the 'to' attribute. Router is a singleton, shared by all streams, that must
|
7
|
-
# be accessed with +
|
7
|
+
# be accessed with +Config#router+.
|
8
8
|
class Router
|
9
|
+
EMPTY = [].freeze
|
9
10
|
|
10
11
|
STREAM_TYPES = [:client, :server, :component].freeze
|
11
|
-
STREAM_TYPES.each do |name|
|
12
|
-
define_method "#{name}s" do
|
13
|
-
@streams[name]
|
14
|
-
end
|
15
|
-
end
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
def initialize
|
23
|
-
@config = nil
|
24
|
-
@streams = Hash.new {|h,k| h[k] = [] }
|
13
|
+
def initialize(config)
|
14
|
+
@config = config
|
15
|
+
@clients, @servers, @components = {}, [], []
|
25
16
|
@pending = Hash.new {|h,k| h[k] = [] }
|
26
17
|
end
|
27
18
|
|
28
|
-
# Returns streams for all connected resources for this JID. A
|
29
|
-
#
|
30
|
-
#
|
31
|
-
def connected_resources(jid, from)
|
19
|
+
# Returns streams for all connected resources for this JID. A resource is
|
20
|
+
# considered connected after it has completed authentication and resource
|
21
|
+
# binding.
|
22
|
+
def connected_resources(jid, from, proxies=true)
|
32
23
|
jid, from = JID.new(jid), JID.new(from)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
24
|
+
return [] unless @config.allowed?(jid, from)
|
25
|
+
|
26
|
+
local = @clients[jid.bare] || EMPTY
|
27
|
+
local = local.select {|stream| stream.user.jid == jid } unless jid.bare?
|
28
|
+
remote = proxies ? proxies(jid) : EMPTY
|
29
|
+
[local, remote].flatten
|
38
30
|
end
|
39
31
|
|
40
|
-
# Returns streams for all available resources for this JID. A
|
41
|
-
#
|
42
|
-
# This method accepts a single JID or a list of JIDs.
|
32
|
+
# Returns streams for all available resources for this JID. A resource is
|
33
|
+
# marked available after it sends initial presence.
|
43
34
|
def available_resources(*jids, from)
|
44
|
-
|
45
|
-
|
46
|
-
stream.available? && jids.include?(stream.user.jid.bare)
|
35
|
+
clients(jids, from) do |stream|
|
36
|
+
stream.available?
|
47
37
|
end
|
48
38
|
end
|
49
39
|
|
50
|
-
# Returns streams for all interested resources for this JID. A
|
51
|
-
#
|
52
|
-
# This method accepts a single JID or a list of JIDs.
|
40
|
+
# Returns streams for all interested resources for this JID. A resource is
|
41
|
+
# marked interested after it requests the roster.
|
53
42
|
def interested_resources(*jids, from)
|
54
|
-
|
55
|
-
|
56
|
-
stream.interested? && jids.include?(stream.user.jid.bare)
|
43
|
+
clients(jids, from) do |stream|
|
44
|
+
stream.interested?
|
57
45
|
end
|
58
46
|
end
|
59
47
|
|
60
48
|
# Add the connection to the routing table. The connection must return
|
61
49
|
# :client, :server, or :component from its +stream_type+ method so the
|
62
50
|
# router can properly route stanzas to the stream.
|
63
|
-
def <<(
|
64
|
-
|
65
|
-
|
66
|
-
|
51
|
+
def <<(stream)
|
52
|
+
case stream_type(stream)
|
53
|
+
when :client then
|
54
|
+
return unless stream.connected?
|
55
|
+
jid = stream.user.jid.bare
|
56
|
+
@clients[jid] ||= []
|
57
|
+
@clients[jid] << stream
|
58
|
+
when :server then @servers << stream
|
59
|
+
when :component then @components << stream
|
60
|
+
end
|
67
61
|
end
|
68
62
|
|
69
63
|
# Remove the connection from the routing table.
|
70
|
-
def delete(
|
71
|
-
|
72
|
-
|
64
|
+
def delete(stream)
|
65
|
+
case stream_type(stream)
|
66
|
+
when :client then
|
67
|
+
return unless stream.connected?
|
68
|
+
jid = stream.user.jid.bare
|
69
|
+
streams = @clients[jid] || []
|
70
|
+
streams.delete(stream)
|
71
|
+
@clients.delete(jid) if streams.empty?
|
72
|
+
when :server then @servers.delete(stream)
|
73
|
+
when :component then @components.delete(stream)
|
74
|
+
end
|
73
75
|
end
|
74
76
|
|
75
77
|
# Send the stanza to the appropriate remote server-to-server stream
|
@@ -96,7 +98,8 @@ module Vines
|
|
96
98
|
|
97
99
|
# Returns the total number of streams connected to the server.
|
98
100
|
def size
|
99
|
-
@
|
101
|
+
clients = @clients.values.inject(0) {|sum, arr| sum + arr.size }
|
102
|
+
clients + @servers.size + @components.size
|
100
103
|
end
|
101
104
|
|
102
105
|
private
|
@@ -124,16 +127,27 @@ module Vines
|
|
124
127
|
end
|
125
128
|
end
|
126
129
|
|
127
|
-
# Return the
|
128
|
-
#
|
130
|
+
# Return the client streams to which the from address is allowed to
|
131
|
+
# contact. Apply the filter block to each stream to narrow the results
|
132
|
+
# before returning the streams.
|
133
|
+
def clients(jids, from, &filter)
|
134
|
+
jids = filter_allowed(jids, from)
|
135
|
+
local = @clients.values_at(*jids).compact.flatten.select(&filter)
|
136
|
+
proxies = proxies(*jids).select(&filter)
|
137
|
+
[local, proxies].flatten
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return the bare JIDs from the list that are allowed to talk to
|
141
|
+
# the +from+ JID.
|
129
142
|
def filter_allowed(jids, from)
|
130
143
|
from = JID.new(from)
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
144
|
+
jids.flatten.map {|jid| JID.new(jid).bare }
|
145
|
+
.select {|jid| @config.allowed?(jid, from) }
|
146
|
+
end
|
147
|
+
|
148
|
+
def proxies(*jids)
|
149
|
+
return EMPTY unless @config.cluster?
|
150
|
+
@config.cluster.remote_sessions(*jids)
|
137
151
|
end
|
138
152
|
|
139
153
|
def connection_to(to, from)
|
@@ -141,17 +155,17 @@ module Vines
|
|
141
155
|
end
|
142
156
|
|
143
157
|
def component_stream(to)
|
144
|
-
components.
|
158
|
+
@components.select do |stream|
|
145
159
|
stream.ready? && stream.remote_domain == to.domain
|
146
|
-
end
|
160
|
+
end.sample
|
147
161
|
end
|
148
162
|
|
149
163
|
def server_stream(to, from)
|
150
|
-
servers.
|
164
|
+
@servers.select do |stream|
|
151
165
|
stream.ready? &&
|
152
166
|
stream.remote_domain == to.domain &&
|
153
167
|
stream.domain == from.domain
|
154
|
-
end
|
168
|
+
end.sample
|
155
169
|
end
|
156
170
|
|
157
171
|
def stream_type(connection)
|
@@ -9,23 +9,36 @@ module Vines
|
|
9
9
|
register "/iq[@id and @type='get']/ns:query", 'ns' => NS
|
10
10
|
|
11
11
|
def process
|
12
|
-
return if route_iq
|
12
|
+
return if route_iq || !allowed?
|
13
13
|
result = to_result.tap do |el|
|
14
14
|
el << el.document.create_element('query') do |query|
|
15
15
|
query.default_namespace = NS
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
if to_pubsub_domain?
|
17
|
+
identity(query, 'pubsub', 'service')
|
18
|
+
pubsub = [:pubsub_create, :pubsub_delete, :pubsub_instant, :pubsub_item_ids, :pubsub_publish, :pubsub_subscribe]
|
19
|
+
features(query, :disco_info, :ping, :pubsub, *pubsub)
|
20
|
+
else
|
21
|
+
identity(query, 'server', 'im')
|
22
|
+
features = [:disco_info, :disco_items, :ping, :vcard, :version]
|
23
|
+
features << :storage if stream.config.private_storage?(validate_to || stream.domain)
|
24
|
+
features(query, features)
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
27
28
|
stream.write(result)
|
28
29
|
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def identity(query, category, type)
|
34
|
+
query << query.document.create_element('identity', 'category' => category, 'type' => type)
|
35
|
+
end
|
36
|
+
|
37
|
+
def features(query, *features)
|
38
|
+
features.flatten.each do |feature|
|
39
|
+
query << query.document.create_element('feature', 'var' => NAMESPACES[feature])
|
40
|
+
end
|
41
|
+
end
|
29
42
|
end
|
30
43
|
end
|
31
44
|
end
|
@@ -9,12 +9,15 @@ module Vines
|
|
9
9
|
register "/iq[@id and @type='get']/ns:query", 'ns' => NS
|
10
10
|
|
11
11
|
def process
|
12
|
-
return if route_iq
|
12
|
+
return if route_iq || !allowed?
|
13
13
|
result = to_result.tap do |el|
|
14
14
|
el << el.document.create_element('query') do |query|
|
15
15
|
query.default_namespace = NS
|
16
|
-
|
17
|
-
|
16
|
+
unless to_pubsub_domain?
|
17
|
+
to = (validate_to || stream.domain).to_s
|
18
|
+
stream.config.vhosts[to].disco_items.each do |domain|
|
19
|
+
query << el.document.create_element('item', 'jid' => domain)
|
20
|
+
end
|
18
21
|
end
|
19
22
|
end
|
20
23
|
end
|
data/lib/vines/stanza/iq/ping.rb
CHANGED
@@ -44,14 +44,10 @@ module Vines
|
|
44
44
|
private
|
45
45
|
|
46
46
|
def to_result
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
'to' => stream.user.jid.to_s,
|
52
|
-
'type' => 'result')
|
53
|
-
yield node if block_given?
|
54
|
-
node
|
47
|
+
super.tap do |node|
|
48
|
+
node['from'] = stream.user.jid.to_s
|
49
|
+
yield node if block_given?
|
50
|
+
end
|
55
51
|
end
|
56
52
|
|
57
53
|
def validate_children_size
|
@@ -55,7 +55,7 @@ module Vines
|
|
55
55
|
|
56
56
|
contact = stream.user.contact(jid)
|
57
57
|
unless contact
|
58
|
-
contact = Contact.new(:
|
58
|
+
contact = Contact.new(jid: jid)
|
59
59
|
stream.user.roster << contact
|
60
60
|
end
|
61
61
|
contact.name = item['name']
|
@@ -89,9 +89,8 @@ module Vines
|
|
89
89
|
end
|
90
90
|
|
91
91
|
send_result_iq
|
92
|
-
push_roster_updates(stream.user.jid,
|
93
|
-
:
|
94
|
-
:subscription => 'remove'))
|
92
|
+
push_roster_updates(stream.user.jid,
|
93
|
+
Contact.new(jid: contact.jid, subscription: 'remove'))
|
95
94
|
|
96
95
|
if local_jid?(contact.jid)
|
97
96
|
send_unavailable(stream.user.jid, contact.jid) if contact.subscribed_from?
|
@@ -110,14 +109,7 @@ module Vines
|
|
110
109
|
presence = [%w[to unsubscribe], %w[from unsubscribed]].map do |meth, type|
|
111
110
|
presence(contact.jid, type) if contact.send("subscribed_#{meth}?")
|
112
111
|
end.compact
|
113
|
-
|
114
|
-
if local_jid?(contact.jid)
|
115
|
-
stream.interested_resources(contact.jid).each do |recipient|
|
116
|
-
presence.each {|el| recipient.write(el) }
|
117
|
-
end
|
118
|
-
else
|
119
|
-
presence.each {|el| router.route(el) }
|
120
|
-
end
|
112
|
+
broadcast_to_interested_resources(presence, contact.jid)
|
121
113
|
end
|
122
114
|
|
123
115
|
def presence(to, type)
|
@@ -138,8 +130,8 @@ module Vines
|
|
138
130
|
end
|
139
131
|
|
140
132
|
def send_result_iq
|
141
|
-
|
142
|
-
node
|
133
|
+
node = to_result
|
134
|
+
node.remove_attribute('from')
|
143
135
|
stream.write(node)
|
144
136
|
end
|
145
137
|
end
|
@@ -3,18 +3,13 @@
|
|
3
3
|
module Vines
|
4
4
|
class Stanza
|
5
5
|
class Iq
|
6
|
-
# Session support is deprecated, but Adium requires it so reply with an
|
6
|
+
# Session support is deprecated, but Adium requires it, so reply with an
|
7
7
|
# iq result stanza.
|
8
8
|
class Session < Iq
|
9
9
|
register "/iq[@id and @type='set']/ns:session", 'ns' => NAMESPACES[:session]
|
10
10
|
|
11
11
|
def process
|
12
|
-
|
13
|
-
result = doc.create_element('iq',
|
14
|
-
'from' => stream.domain,
|
15
|
-
'id' => self['id'],
|
16
|
-
'type' => 'result')
|
17
|
-
stream.write(result)
|
12
|
+
stream.write(to_result)
|
18
13
|
end
|
19
14
|
end
|
20
15
|
end
|
@@ -9,6 +9,7 @@ module Vines
|
|
9
9
|
register "/iq[@id and @type='get' or @type='set']/ns:vCard", 'ns' => NS
|
10
10
|
|
11
11
|
def process
|
12
|
+
return unless allowed?
|
12
13
|
if local?
|
13
14
|
get? ? vcard_query : vcard_update
|
14
15
|
else
|
@@ -22,7 +23,7 @@ module Vines
|
|
22
23
|
def vcard_query
|
23
24
|
to = validate_to
|
24
25
|
jid = to ? to.bare : stream.user.jid.bare
|
25
|
-
card = storage.find_vcard(jid)
|
26
|
+
card = storage(jid.domain).find_vcard(jid)
|
26
27
|
|
27
28
|
raise StanzaErrors::ItemNotFound.new(self, 'cancel') unless card
|
28
29
|
|
@@ -45,11 +46,8 @@ module Vines
|
|
45
46
|
|
46
47
|
storage.save_vcard(stream.user.jid, elements.first)
|
47
48
|
|
48
|
-
|
49
|
-
result
|
50
|
-
'id' => self['id'],
|
51
|
-
'to' => stream.user.jid.to_s,
|
52
|
-
'type' => 'result')
|
49
|
+
result = to_result
|
50
|
+
result.remove_attribute('from')
|
53
51
|
stream.write(result)
|
54
52
|
end
|
55
53
|
end
|
@@ -9,7 +9,7 @@ module Vines
|
|
9
9
|
register "/iq[@id and @type='get']/ns:query", 'ns' => NS
|
10
10
|
|
11
11
|
def process
|
12
|
-
return if route_iq
|
12
|
+
return if route_iq || to_pubsub_domain? || !allowed?
|
13
13
|
result = to_result.tap do |node|
|
14
14
|
node << node.document.create_element('query') do |query|
|
15
15
|
query.default_namespace = NS
|
data/lib/vines/stanza/iq.rb
CHANGED
@@ -24,25 +24,23 @@ module Vines
|
|
24
24
|
def to_result
|
25
25
|
doc = Document.new
|
26
26
|
doc.create_element('iq',
|
27
|
-
'from' => stream.domain,
|
27
|
+
'from' => validate_to || stream.domain,
|
28
28
|
'id' => self['id'],
|
29
|
-
'to' => stream.user.jid
|
29
|
+
'to' => stream.user.jid,
|
30
30
|
'type' => 'result')
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
+
# Return false if this IQ stanza is addressed to the server, or a pubsub
|
36
|
+
# service hosted here, and must be handled locally. Return true if the
|
37
|
+
# stanza must not be handled locally and has been routed to the appropriate
|
38
|
+
# component, s2s, or c2s stream.
|
35
39
|
def route_iq
|
36
40
|
to = validate_to
|
37
|
-
return false if to.nil? || to
|
41
|
+
return false if to.nil? || stream.config.vhost?(to) || to_pubsub_domain?
|
38
42
|
self['from'] = stream.user.jid.to_s
|
39
|
-
|
40
|
-
stream.available_resources(to).each do |recipient|
|
41
|
-
recipient.write(@node)
|
42
|
-
end
|
43
|
-
else
|
44
|
-
route
|
45
|
-
end
|
43
|
+
local? ? broadcast(stream.connected_resources(to)) : route
|
46
44
|
true
|
47
45
|
end
|
48
46
|
end
|