vines 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/Rakefile +10 -10
- data/conf/certs/ca-bundle.crt +112 -378
- data/conf/config.rb +18 -9
- data/lib/vines.rb +8 -1
- data/lib/vines/command/cert.rb +2 -1
- data/lib/vines/command/init.rb +11 -0
- data/lib/vines/command/ldap.rb +6 -3
- data/lib/vines/command/schema.rb +1 -1
- data/lib/vines/config.rb +57 -146
- data/lib/vines/config/host.rb +85 -0
- data/lib/vines/config/port.rb +111 -0
- data/lib/vines/contact.rb +1 -1
- data/lib/vines/jid.rb +26 -4
- data/lib/vines/kit.rb +6 -0
- data/lib/vines/log.rb +24 -0
- data/lib/vines/router.rb +70 -38
- data/lib/vines/stanza.rb +45 -8
- data/lib/vines/stanza/iq.rb +3 -3
- data/lib/vines/stanza/iq/disco_info.rb +5 -1
- data/lib/vines/stanza/iq/disco_items.rb +3 -0
- data/lib/vines/stanza/iq/private_storage.rb +9 -5
- data/lib/vines/stanza/iq/roster.rb +11 -12
- data/lib/vines/stanza/iq/vcard.rb +4 -4
- data/lib/vines/stanza/iq/version.rb +25 -0
- data/lib/vines/stanza/message.rb +4 -5
- data/lib/vines/stanza/presence.rb +20 -18
- data/lib/vines/stanza/presence/probe.rb +3 -4
- data/lib/vines/stanza/presence/subscribe.rb +4 -3
- data/lib/vines/stanza/presence/subscribed.rb +6 -5
- data/lib/vines/stanza/presence/unsubscribe.rb +4 -4
- data/lib/vines/stanza/presence/unsubscribed.rb +4 -3
- data/lib/vines/storage/couchdb.rb +3 -3
- data/lib/vines/storage/ldap.rb +19 -8
- data/lib/vines/storage/local.rb +23 -12
- data/lib/vines/storage/redis.rb +3 -3
- data/lib/vines/storage/sql.rb +5 -5
- data/lib/vines/stream.rb +40 -6
- data/lib/vines/stream/client.rb +5 -6
- data/lib/vines/stream/client/auth.rb +3 -2
- data/lib/vines/stream/client/bind.rb +2 -2
- data/lib/vines/stream/client/bind_restart.rb +1 -2
- data/lib/vines/stream/client/ready.rb +2 -0
- data/lib/vines/stream/client/session.rb +13 -4
- data/lib/vines/stream/client/tls.rb +1 -0
- data/lib/vines/stream/component.rb +6 -5
- data/lib/vines/stream/component/ready.rb +5 -6
- data/lib/vines/stream/http.rb +10 -4
- data/lib/vines/stream/http/request.rb +23 -2
- data/lib/vines/stream/server.rb +13 -11
- data/lib/vines/stream/server/outbound/auth_result.rb +1 -0
- data/lib/vines/stream/server/outbound/tls_result.rb +1 -0
- data/lib/vines/stream/server/ready.rb +2 -2
- data/lib/vines/user.rb +2 -1
- data/lib/vines/version.rb +1 -1
- data/test/config/host_test.rb +292 -0
- data/test/config_test.rb +244 -103
- data/test/contact_test.rb +7 -1
- data/test/jid_test.rb +48 -0
- data/test/router_test.rb +16 -47
- data/test/stanza/iq/disco_info_test.rb +76 -0
- data/test/stanza/iq/disco_items_test.rb +47 -0
- data/test/stanza/iq/private_storage_test.rb +33 -10
- data/test/stanza/iq/roster_test.rb +15 -5
- data/test/stanza/iq/vcard_test.rb +8 -25
- data/test/stanza/iq/version_test.rb +62 -0
- data/test/stanza/iq_test.rb +13 -10
- data/test/stanza/message_test.rb +16 -24
- data/test/stanza/presence/probe_test.rb +52 -0
- data/test/stanza/presence/subscribe_test.rb +1 -5
- data/test/stanza_test.rb +77 -0
- data/test/stream/client/auth_test.rb +1 -0
- data/test/stream/client/ready_test.rb +2 -0
- data/test/stream/client/session_test.rb +7 -2
- data/test/stream/component/ready_test.rb +19 -36
- data/test/stream/http/request_test.rb +22 -2
- data/test/stream/server/ready_test.rb +14 -21
- data/web/404.html +9 -3
- data/web/chat/index.html +2 -2
- data/web/chat/javascripts/app.js +1 -1
- data/web/chat/stylesheets/chat.css +4 -9
- data/web/lib/coffeescripts/layout.coffee +2 -2
- data/web/{chat → lib}/coffeescripts/logout.coffee +0 -0
- data/web/lib/coffeescripts/notification.coffee +14 -0
- data/web/lib/coffeescripts/session.coffee +28 -24
- data/web/lib/coffeescripts/transfer.coffee +37 -34
- data/web/lib/javascripts/base.js +8 -8
- data/web/lib/javascripts/icons.js +3 -0
- data/web/lib/javascripts/jquery.js +4 -18
- data/web/lib/javascripts/layout.js +2 -2
- data/web/{chat → lib}/javascripts/logout.js +0 -0
- data/web/lib/javascripts/notification.js +26 -0
- data/web/lib/javascripts/session.js +20 -16
- data/web/lib/javascripts/transfer.js +45 -55
- data/web/lib/stylesheets/base.css +45 -9
- metadata +31 -15
@@ -23,7 +23,7 @@ module Vines
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def find_user(jid)
|
26
|
-
jid = JID.new(jid
|
26
|
+
jid = JID.new(jid).bare.to_s
|
27
27
|
if jid.empty? then yield; return end
|
28
28
|
get("user:#{jid}") do |doc|
|
29
29
|
user = if doc && doc['type'] == 'User'
|
@@ -61,7 +61,7 @@ module Vines
|
|
61
61
|
fiber :save_user
|
62
62
|
|
63
63
|
def find_vcard(jid)
|
64
|
-
jid = JID.new(jid
|
64
|
+
jid = JID.new(jid).bare.to_s
|
65
65
|
if jid.empty? then yield; return end
|
66
66
|
get("vcard:#{jid}") do |doc|
|
67
67
|
card = if doc && doc['type'] == 'Vcard'
|
@@ -85,7 +85,7 @@ module Vines
|
|
85
85
|
fiber :save_vcard
|
86
86
|
|
87
87
|
def find_fragment(jid, node)
|
88
|
-
jid = JID.new(jid
|
88
|
+
jid = JID.new(jid).bare.to_s
|
89
89
|
if jid.empty? then yield; return end
|
90
90
|
get(fragment_id(jid, node)) do |doc|
|
91
91
|
fragment = if doc && doc['type'] == 'Fragment'
|
data/lib/vines/storage/ldap.rb
CHANGED
@@ -9,8 +9,8 @@ module Vines
|
|
9
9
|
# information.
|
10
10
|
class Ldap
|
11
11
|
@@required = [:host, :port]
|
12
|
-
%w[tls dn password basedn object_class user_attr name_attr].each do |name|
|
13
|
-
@@required << name.to_sym
|
12
|
+
%w[tls dn password basedn object_class user_attr name_attr groupdn].each do |name|
|
13
|
+
@@required << name.to_sym unless name == 'groupdn'
|
14
14
|
define_method name do |*args|
|
15
15
|
@config[name.to_sym] = args.first
|
16
16
|
end
|
@@ -28,13 +28,10 @@ module Vines
|
|
28
28
|
def authenticate(username, password)
|
29
29
|
return if [username, password].any? {|arg| (arg || '').strip.empty? }
|
30
30
|
|
31
|
-
clas = Net::LDAP::Filter.eq('objectClass', @config[:object_class])
|
32
|
-
uid = Net::LDAP::Filter.eq(@config[:user_attr], username)
|
33
|
-
filter = clas & uid
|
34
|
-
attrs = [@config[:name_attr], 'mail']
|
35
|
-
|
36
31
|
ldap = connect(@config[:dn], @config[:password])
|
37
|
-
entries = ldap.search(
|
32
|
+
entries = ldap.search(
|
33
|
+
:attributes => [@config[:name_attr], 'mail'],
|
34
|
+
:filter => filter(username))
|
38
35
|
return unless entries && entries.size == 1
|
39
36
|
|
40
37
|
user = if connect(entries.first.dn, password).bind
|
@@ -44,6 +41,20 @@ module Vines
|
|
44
41
|
user
|
45
42
|
end
|
46
43
|
|
44
|
+
# Return an LDAP search filter for a user optionally belonging to the
|
45
|
+
# group defined by the groupdn config attribute.
|
46
|
+
def filter(username)
|
47
|
+
clas = Net::LDAP::Filter.eq('objectClass', @config[:object_class])
|
48
|
+
uid = Net::LDAP::Filter.eq(@config[:user_attr], username)
|
49
|
+
filter = clas & uid
|
50
|
+
if group = @config[:groupdn]
|
51
|
+
memberOf = Net::LDAP::Filter.eq('memberOf', group)
|
52
|
+
isMemberOf = Net::LDAP::Filter.eq('isMemberOf', group)
|
53
|
+
filter = filter & (memberOf | isMemberOf)
|
54
|
+
end
|
55
|
+
filter
|
56
|
+
end
|
57
|
+
|
47
58
|
private
|
48
59
|
|
49
60
|
def connect(dn, password)
|
data/lib/vines/storage/local.rb
CHANGED
@@ -20,8 +20,8 @@ module Vines
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def find_user(jid)
|
23
|
-
jid = JID.new(jid
|
24
|
-
file =
|
23
|
+
jid = JID.new(jid).bare.to_s
|
24
|
+
file = absolute_path("#{jid}.user") unless jid.empty?
|
25
25
|
record = YAML.load_file(file) rescue nil
|
26
26
|
return User.new(:jid => jid).tap do |user|
|
27
27
|
user.name, user.password = record.values_at('name', 'password')
|
@@ -41,44 +41,55 @@ module Vines
|
|
41
41
|
user.roster.each do |contact|
|
42
42
|
record['roster'][contact.jid.bare.to_s] = contact.to_h
|
43
43
|
end
|
44
|
-
|
45
|
-
File.open(file, 'w') do |f|
|
44
|
+
save("#{user.jid.bare.to_s}.user") do |f|
|
46
45
|
YAML.dump(record, f)
|
47
46
|
end
|
48
47
|
end
|
49
48
|
|
50
49
|
def find_vcard(jid)
|
51
|
-
jid = JID.new(jid
|
50
|
+
jid = JID.new(jid).bare.to_s
|
52
51
|
return if jid.empty?
|
53
|
-
file =
|
52
|
+
file = absolute_path("#{jid}.vcard")
|
54
53
|
Nokogiri::XML(File.read(file)).root rescue nil
|
55
54
|
end
|
56
55
|
|
57
56
|
def save_vcard(jid, card)
|
58
57
|
jid = JID.new(jid).bare.to_s
|
59
|
-
|
60
|
-
|
58
|
+
return if jid.empty?
|
59
|
+
save("#{jid}.vcard") do |f|
|
61
60
|
f.write(card.to_xml)
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
64
|
def find_fragment(jid, node)
|
66
|
-
jid = JID.new(jid
|
65
|
+
jid = JID.new(jid).bare.to_s
|
67
66
|
return if jid.empty?
|
68
|
-
file =
|
67
|
+
file = absolute_path(fragment_id(jid, node))
|
69
68
|
Nokogiri::XML(File.read(file)).root rescue nil
|
70
69
|
end
|
71
70
|
|
72
71
|
def save_fragment(jid, node)
|
73
72
|
jid = JID.new(jid).bare.to_s
|
74
|
-
|
75
|
-
|
73
|
+
return if jid.empty?
|
74
|
+
save(fragment_id(jid, node)) do |f|
|
76
75
|
f.write(node.to_xml)
|
77
76
|
end
|
78
77
|
end
|
79
78
|
|
80
79
|
private
|
81
80
|
|
81
|
+
def absolute_path(file)
|
82
|
+
File.expand_path(file, @dir).tap do |absolute|
|
83
|
+
raise 'path traversal' unless File.dirname(absolute) == @dir
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def save(file)
|
88
|
+
file = absolute_path(file)
|
89
|
+
File.open(file, 'w') {|f| yield f }
|
90
|
+
File.chmod(0600, file)
|
91
|
+
end
|
92
|
+
|
82
93
|
def fragment_id(jid, node)
|
83
94
|
id = Digest::SHA1.hexdigest("#{node.name}:#{node.namespace.href}")
|
84
95
|
"#{jid}-#{id}.fragment"
|
data/lib/vines/storage/redis.rb
CHANGED
@@ -22,7 +22,7 @@ module Vines
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def find_user(jid)
|
25
|
-
jid = JID.new(jid
|
25
|
+
jid = JID.new(jid).bare.to_s
|
26
26
|
if jid.empty? then yield; return end
|
27
27
|
find_roster(jid) do |contacts|
|
28
28
|
redis.get("user:#{jid}") do |response|
|
@@ -53,7 +53,7 @@ module Vines
|
|
53
53
|
fiber :save_user
|
54
54
|
|
55
55
|
def find_vcard(jid)
|
56
|
-
jid = JID.new(jid
|
56
|
+
jid = JID.new(jid).bare.to_s
|
57
57
|
if jid.empty? then yield; return end
|
58
58
|
redis.get("vcard:#{jid}") do |response|
|
59
59
|
card = if response
|
@@ -75,7 +75,7 @@ module Vines
|
|
75
75
|
fiber :save_vcard
|
76
76
|
|
77
77
|
def find_fragment(jid, node)
|
78
|
-
jid = JID.new(jid
|
78
|
+
jid = JID.new(jid).bare.to_s
|
79
79
|
if jid.empty? then yield; return end
|
80
80
|
redis.hget("fragments:#{jid}", fragment_id(node)) do |response|
|
81
81
|
fragment = if response
|
data/lib/vines/storage/sql.rb
CHANGED
@@ -40,7 +40,7 @@ module Vines
|
|
40
40
|
def find_user(jid)
|
41
41
|
ActiveRecord::Base.clear_reloadable_connections!
|
42
42
|
|
43
|
-
jid = JID.new(jid
|
43
|
+
jid = JID.new(jid).bare.to_s
|
44
44
|
return if jid.empty?
|
45
45
|
xuser = user_by_jid(jid)
|
46
46
|
return Vines::User.new(:jid => jid).tap do |user|
|
@@ -99,7 +99,7 @@ module Vines
|
|
99
99
|
def find_vcard(jid)
|
100
100
|
ActiveRecord::Base.clear_reloadable_connections!
|
101
101
|
|
102
|
-
jid = JID.new(jid
|
102
|
+
jid = JID.new(jid).bare.to_s
|
103
103
|
return if jid.empty?
|
104
104
|
if xuser = user_by_jid(jid)
|
105
105
|
Nokogiri::XML(xuser.vcard).root rescue nil
|
@@ -121,7 +121,7 @@ module Vines
|
|
121
121
|
def find_fragment(jid, node)
|
122
122
|
ActiveRecord::Base.clear_reloadable_connections!
|
123
123
|
|
124
|
-
jid = JID.new(jid
|
124
|
+
jid = JID.new(jid).bare.to_s
|
125
125
|
return if jid.empty?
|
126
126
|
if fragment = fragment_by_jid(jid, node)
|
127
127
|
Nokogiri::XML(fragment.xml).root rescue nil
|
@@ -151,7 +151,7 @@ module Vines
|
|
151
151
|
|
152
152
|
ActiveRecord::Schema.define do
|
153
153
|
create_table :users, :force => args[:force] do |t|
|
154
|
-
t.string :jid, :limit =>
|
154
|
+
t.string :jid, :limit => 2048, :null => false
|
155
155
|
t.string :name, :limit => 1000, :null => true
|
156
156
|
t.string :password, :limit => 1000, :null => true
|
157
157
|
t.text :vcard, :null => true
|
@@ -160,7 +160,7 @@ module Vines
|
|
160
160
|
|
161
161
|
create_table :contacts, :force => args[:force] do |t|
|
162
162
|
t.integer :user_id, :null => false
|
163
|
-
t.string :jid, :limit =>
|
163
|
+
t.string :jid, :limit => 2048, :null => false
|
164
164
|
t.string :name, :limit => 1000, :null => true
|
165
165
|
t.string :ask, :limit => 1000, :null => true
|
166
166
|
t.string :subscription, :limit => 1000, :null => false
|
data/lib/vines/stream.rb
CHANGED
@@ -10,26 +10,36 @@ module Vines
|
|
10
10
|
ERROR = 'error'.freeze
|
11
11
|
PAD = 20
|
12
12
|
|
13
|
-
attr_reader :domain
|
13
|
+
attr_reader :config, :domain
|
14
14
|
attr_accessor :user
|
15
15
|
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
end
|
19
|
+
|
16
20
|
def post_init
|
17
21
|
router << self
|
18
22
|
@remote_addr, @local_addr = addresses
|
19
23
|
@user, @closed, @stanza_size = nil, false, 0
|
20
24
|
@bucket = TokenBucket.new(100, 10)
|
21
25
|
@store = Store.new
|
22
|
-
|
23
26
|
@nodes = EM::Queue.new
|
24
27
|
process_node_queue
|
28
|
+
create_parser
|
29
|
+
log.info { "%s %21s -> %s" %
|
30
|
+
['Stream connected:'.ljust(PAD), @remote_addr, @local_addr] }
|
31
|
+
end
|
25
32
|
|
33
|
+
# Initialize a new XML parser for this connection. This is called when the
|
34
|
+
# stream is first connected as well as for stream restarts during
|
35
|
+
# negotiation. Subclasses can override this method to provide a different
|
36
|
+
# type of parser (e.g. HTTP).
|
37
|
+
def create_parser
|
26
38
|
@parser = Parser.new.tap do |p|
|
27
39
|
p.stream_open {|node| @nodes.push(node) }
|
28
40
|
p.stream_close { close_connection }
|
29
41
|
p.stanza {|node| @nodes.push(node) }
|
30
42
|
end
|
31
|
-
log.info { "%s %21s -> %s" %
|
32
|
-
['Stream connected:'.ljust(PAD), @remote_addr, @local_addr] }
|
33
43
|
end
|
34
44
|
|
35
45
|
def close_connection(after_writing=false)
|
@@ -48,21 +58,40 @@ module Vines
|
|
48
58
|
end
|
49
59
|
end
|
50
60
|
|
61
|
+
# Reset the connection's XML parser when a new <stream:stream> header
|
62
|
+
# is received.
|
63
|
+
def reset
|
64
|
+
create_parser
|
65
|
+
end
|
66
|
+
|
51
67
|
# Returns the storage system for the domain. If no domain is given,
|
52
68
|
# the stream's storage mechanism is returned.
|
53
69
|
def storage(domain=nil)
|
54
|
-
@config.vhosts[domain || self.domain]
|
70
|
+
host = @config.vhosts[domain || self.domain]
|
71
|
+
host.storage if host
|
55
72
|
end
|
56
73
|
|
57
74
|
# Reload the user's information into their active connections. Call this
|
58
75
|
# after storage.save_user() to sync the new user state with their other
|
59
76
|
# connections.
|
60
77
|
def update_user_streams(user)
|
61
|
-
|
78
|
+
connected_resources(user.jid.bare).each do |stream|
|
62
79
|
stream.user.update_from(user)
|
63
80
|
end
|
64
81
|
end
|
65
82
|
|
83
|
+
def connected_resources(jid)
|
84
|
+
router.connected_resources(jid, user.jid)
|
85
|
+
end
|
86
|
+
|
87
|
+
def available_resources(*jid)
|
88
|
+
router.available_resources(*jid, user.jid)
|
89
|
+
end
|
90
|
+
|
91
|
+
def interested_resources(*jid)
|
92
|
+
router.interested_resources(*jid, user.jid)
|
93
|
+
end
|
94
|
+
|
66
95
|
def ssl_verify_peer(pem)
|
67
96
|
# EM is supposed to close the connection when this returns false,
|
68
97
|
# but it only does that for inbound connections, not when we
|
@@ -206,5 +235,10 @@ module Vines
|
|
206
235
|
def tls_files
|
207
236
|
%w[crt key].map {|ext| File.join(VINES_ROOT, 'conf', 'certs', "#{domain}.#{ext}") }
|
208
237
|
end
|
238
|
+
|
239
|
+
def valid_address?(jid)
|
240
|
+
jid = JID.new(jid) rescue nil
|
241
|
+
jid && !jid.empty?
|
242
|
+
end
|
209
243
|
end
|
210
244
|
end
|
data/lib/vines/stream/client.rb
CHANGED
@@ -6,10 +6,8 @@ module Vines
|
|
6
6
|
# Implements the XMPP protocol for client-to-server (c2s) streams. This
|
7
7
|
# serves connected streams using the jabber:client namespace.
|
8
8
|
class Client < Stream
|
9
|
-
attr_reader :config
|
10
|
-
|
11
9
|
def initialize(config)
|
12
|
-
|
10
|
+
super
|
13
11
|
@session = Client::Session.new(self)
|
14
12
|
end
|
15
13
|
|
@@ -24,9 +22,9 @@ module Vines
|
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
27
|
-
%w[max_stanza_size max_resources_per_account
|
25
|
+
%w[max_stanza_size max_resources_per_account].each do |name|
|
28
26
|
define_method name do |*args|
|
29
|
-
|
27
|
+
config[:client].send(name, *args)
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
@@ -46,7 +44,8 @@ module Vines
|
|
46
44
|
@session.domain = to
|
47
45
|
send_stream_header(from)
|
48
46
|
raise StreamErrors::UnsupportedVersion unless node['version'] == '1.0'
|
49
|
-
raise StreamErrors::
|
47
|
+
raise StreamErrors::ImproperAddressing unless valid_address?(@session.domain)
|
48
|
+
raise StreamErrors::HostUnknown unless config.vhost?(@session.domain)
|
50
49
|
raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns'] == NAMESPACES[:client]
|
51
50
|
raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns:stream'] == NAMESPACES[:stream]
|
52
51
|
end
|
@@ -9,7 +9,7 @@ module Vines
|
|
9
9
|
SUCCESS = %Q{<success xmlns="#{NS}"/>}.freeze
|
10
10
|
MAX_AUTH_ATTEMPTS = 3
|
11
11
|
AUTH_MECHANISMS = {'PLAIN' => :plain_auth, 'EXTERNAL' => :external_auth}.freeze
|
12
|
-
|
12
|
+
|
13
13
|
def initialize(stream, success=BindRestart)
|
14
14
|
super
|
15
15
|
@attempts, @outstanding = 0, false
|
@@ -49,7 +49,7 @@ module Vines
|
|
49
49
|
|
50
50
|
# Authenticate c2s streams using a username and password. Call the
|
51
51
|
# authentication module in a separate thread to avoid blocking stanza
|
52
|
-
# processing for other users.
|
52
|
+
# processing for other users.
|
53
53
|
def plain_auth(stanza)
|
54
54
|
jid, node, password = Base64.decode64(stanza.text).split("\000")
|
55
55
|
jid = [node, stream.domain].join('@') if jid.nil? || jid.empty?
|
@@ -77,6 +77,7 @@ module Vines
|
|
77
77
|
|
78
78
|
def send_auth_success
|
79
79
|
stream.write(SUCCESS)
|
80
|
+
stream.reset
|
80
81
|
advance
|
81
82
|
end
|
82
83
|
|
@@ -51,12 +51,12 @@ module Vines
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def resource_limit_reached?
|
54
|
-
used = stream.
|
54
|
+
used = stream.connected_resources(stream.user.jid.bare).size
|
55
55
|
used >= stream.max_resources_per_account
|
56
56
|
end
|
57
57
|
|
58
58
|
def resource_used?(resource)
|
59
|
-
stream.
|
59
|
+
stream.available_resources(stream.user.jid).any? do |c|
|
60
60
|
c.user.jid.resource == resource
|
61
61
|
end
|
62
62
|
end
|
@@ -14,11 +14,10 @@ module Vines
|
|
14
14
|
doc = Document.new
|
15
15
|
features = doc.create_element('stream:features') do |el|
|
16
16
|
el << doc.create_element('bind', 'xmlns' => NAMESPACES[:bind])
|
17
|
-
el << doc.create_element('session', 'xmlns' => NAMESPACES[:session])
|
18
17
|
end
|
19
18
|
stream.write(features)
|
20
19
|
advance
|
21
|
-
end
|
20
|
+
end
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -15,6 +15,7 @@ module Vines
|
|
15
15
|
|
16
16
|
def initialize(stream)
|
17
17
|
@id = Kit.uuid
|
18
|
+
@config = stream.config
|
18
19
|
@state = Client::Start.new(stream)
|
19
20
|
@available = false
|
20
21
|
@domain = nil
|
@@ -91,14 +92,22 @@ module Vines
|
|
91
92
|
# has successfully subscribed.
|
92
93
|
def available_subscribed_to_resources
|
93
94
|
subscribed = @user.subscribed_to_contacts.map {|c| c.jid }
|
94
|
-
router.available_resources(subscribed)
|
95
|
+
router.available_resources(subscribed, @user.jid)
|
95
96
|
end
|
96
97
|
|
97
98
|
# Returns streams for available resources that are subscribed
|
98
99
|
# to this user's presence updates.
|
99
100
|
def available_subscribers
|
100
101
|
subscribed = @user.subscribed_from_contacts.map {|c| c.jid }
|
101
|
-
router.available_resources(subscribed)
|
102
|
+
router.available_resources(subscribed, @user.jid)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns contacts hosted at remote servers to which this user has
|
106
|
+
# successfully subscribed.
|
107
|
+
def remote_subscribed_to_contacts
|
108
|
+
@user.subscribed_to_contacts.reject do |c|
|
109
|
+
@config.local_jid?(c.jid)
|
110
|
+
end
|
102
111
|
end
|
103
112
|
|
104
113
|
# Returns contacts hosted at remote servers that are subscribed
|
@@ -106,7 +115,7 @@ module Vines
|
|
106
115
|
def remote_subscribers(to=nil)
|
107
116
|
jid = (to.nil? || to.empty?) ? nil : JID.new(to).bare
|
108
117
|
@user.subscribed_from_contacts.reject do |c|
|
109
|
-
|
118
|
+
@config.local_jid?(c.jid) || (jid && c.jid.bare != jid)
|
110
119
|
end
|
111
120
|
end
|
112
121
|
|
@@ -121,7 +130,7 @@ module Vines
|
|
121
130
|
'type' => 'unavailable')
|
122
131
|
|
123
132
|
broadcast(el, available_subscribers)
|
124
|
-
broadcast(el, router.available_resources(@user.jid))
|
133
|
+
broadcast(el, router.available_resources(@user.jid, @user.jid))
|
125
134
|
|
126
135
|
remote_subscribers.each do |contact|
|
127
136
|
node = el.clone
|