vines 0.2.1 → 0.3.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 +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
|