vines 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -2
- data/Rakefile +63 -8
- data/bin/vines +0 -1
- data/conf/config.rb +16 -7
- data/lib/vines.rb +21 -16
- data/lib/vines/command/init.rb +5 -3
- data/lib/vines/config.rb +34 -0
- data/lib/vines/contact.rb +14 -0
- data/lib/vines/stanza.rb +26 -0
- data/lib/vines/stanza/iq.rb +1 -1
- data/lib/vines/stanza/iq/disco_info.rb +3 -0
- data/lib/vines/stanza/iq/private_storage.rb +83 -0
- data/lib/vines/stanza/iq/roster.rb +26 -30
- data/lib/vines/stanza/presence.rb +0 -12
- data/lib/vines/stanza/presence/subscribe.rb +3 -20
- data/lib/vines/stanza/presence/subscribed.rb +9 -10
- data/lib/vines/stanza/presence/unsubscribe.rb +8 -15
- data/lib/vines/stanza/presence/unsubscribed.rb +8 -8
- data/lib/vines/storage.rb +28 -0
- data/lib/vines/storage/couchdb.rb +29 -0
- data/lib/vines/storage/local.rb +22 -0
- data/lib/vines/storage/redis.rb +26 -0
- data/lib/vines/storage/sql.rb +48 -5
- data/lib/vines/stream/client.rb +6 -8
- data/lib/vines/stream/http.rb +23 -21
- data/lib/vines/stream/http/auth.rb +1 -1
- data/lib/vines/stream/http/bind.rb +1 -1
- data/lib/vines/stream/http/bind_restart.rb +4 -3
- data/lib/vines/stream/http/ready.rb +1 -1
- data/lib/vines/stream/http/request.rb +94 -5
- data/lib/vines/stream/http/session.rb +8 -6
- data/lib/vines/version.rb +1 -1
- data/test/config_test.rb +12 -0
- data/test/contact_test.rb +40 -0
- data/test/rake_test_loader.rb +11 -3
- data/test/stanza/iq/private_storage_test.rb +177 -0
- data/test/stanza/iq/roster_test.rb +1 -1
- data/test/stanza/iq_test.rb +63 -0
- data/test/storage/couchdb_test.rb +7 -1
- data/test/storage/local_test.rb +8 -2
- data/test/storage/redis_test.rb +16 -7
- data/test/storage/sql_test.rb +8 -1
- data/test/storage/storage_tests.rb +50 -0
- data/test/stream/http/auth_test.rb +3 -0
- data/test/stream/http/ready_test.rb +3 -0
- data/test/stream/http/request_test.rb +86 -0
- data/test/stream/parser_test.rb +2 -0
- data/web/404.html +43 -0
- data/web/apple-touch-icon.png +0 -0
- data/web/chat/coffeescripts/chat.coffee +385 -0
- data/web/chat/coffeescripts/init.coffee +15 -0
- data/web/chat/coffeescripts/logout.coffee +5 -0
- data/web/chat/index.html +17 -0
- data/web/chat/javascripts/app.js +1 -0
- data/web/chat/javascripts/chat.js +436 -0
- data/web/chat/javascripts/init.js +21 -0
- data/web/chat/javascripts/logout.js +11 -0
- data/web/chat/stylesheets/chat.css +290 -0
- data/web/favicon.png +0 -0
- data/web/lib/coffeescripts/contact.coffee +32 -0
- data/web/lib/coffeescripts/layout.coffee +30 -0
- data/web/lib/coffeescripts/login.coffee +52 -0
- data/web/lib/coffeescripts/navbar.coffee +84 -0
- data/web/lib/coffeescripts/router.coffee +40 -0
- data/web/lib/coffeescripts/session.coffee +211 -0
- data/web/lib/images/default-user.png +0 -0
- data/web/lib/images/logo-large.png +0 -0
- data/web/lib/images/logo-small.png +0 -0
- data/web/lib/javascripts/base.js +9 -0
- data/web/lib/javascripts/contact.js +94 -0
- data/web/lib/javascripts/icons.js +101 -0
- data/web/lib/javascripts/jquery.cookie.js +91 -0
- data/web/lib/javascripts/jquery.js +18 -0
- data/web/lib/javascripts/layout.js +48 -0
- data/web/lib/javascripts/login.js +61 -0
- data/web/lib/javascripts/navbar.js +69 -0
- data/web/lib/javascripts/raphael.js +8 -0
- data/web/lib/javascripts/router.js +105 -0
- data/web/lib/javascripts/session.js +322 -0
- data/web/lib/javascripts/strophe.js +1 -0
- data/web/lib/stylesheets/base.css +223 -0
- data/web/lib/stylesheets/login.css +63 -0
- metadata +51 -9
data/README
CHANGED
@@ -17,8 +17,8 @@ database. SSL encryption is mandatory on all client and server connections.
|
|
17
17
|
== Dependencies
|
18
18
|
|
19
19
|
* bcrypt-ruby >= 2.1.4
|
20
|
-
* eventmachine >=
|
21
|
-
* nokogiri >= 1.
|
20
|
+
* eventmachine >= 0.12.10
|
21
|
+
* nokogiri >= 1.5.0
|
22
22
|
* ruby >= 1.9.2
|
23
23
|
|
24
24
|
== Ubuntu setup
|
data/Rakefile
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/clean'
|
3
|
-
require 'rake/gempackagetask'
|
4
3
|
require 'rake/testtask'
|
4
|
+
require 'rubygems/package_task'
|
5
|
+
require 'nokogiri'
|
5
6
|
require_relative 'lib/vines/version'
|
6
7
|
|
7
8
|
spec = Gem::Specification.new do |s|
|
@@ -21,28 +22,28 @@ all client and server connections."
|
|
21
22
|
s.email = %w[david@negativecode.com chris@negativecode.com]
|
22
23
|
s.homepage = "http://www.getvines.com"
|
23
24
|
|
24
|
-
s.files = FileList['[A-Z]*', '{bin,lib,conf}/**/*']
|
25
|
+
s.files = FileList['[A-Z]*', '{bin,lib,conf,web}/**/*']
|
25
26
|
s.test_files = FileList["test/**/*"]
|
26
27
|
s.executables = %w[vines]
|
27
28
|
s.require_path = "lib"
|
28
29
|
|
29
30
|
s.add_dependency "activerecord", "~> 3.0"
|
30
31
|
s.add_dependency "bcrypt-ruby", "~> 2.1"
|
31
|
-
s.add_dependency
|
32
|
+
s.add_dependency "em-http-request", "~> 0.3"
|
32
33
|
s.add_dependency "em-redis", "~> 0.3"
|
33
|
-
s.add_dependency "eventmachine", "
|
34
|
+
s.add_dependency "eventmachine", "~> 0.12"
|
34
35
|
s.add_dependency "http_parser.rb", "~> 0.5"
|
35
36
|
s.add_dependency "net-ldap", "~> 0.2"
|
36
|
-
s.add_dependency "nokogiri", "~> 1.
|
37
|
+
s.add_dependency "nokogiri", "~> 1.5"
|
37
38
|
|
38
|
-
s.add_development_dependency "minitest"
|
39
|
+
s.add_development_dependency "minitest", "= 2.2.2"
|
39
40
|
s.add_development_dependency "rake"
|
40
41
|
s.add_development_dependency "sqlite3"
|
41
42
|
|
42
43
|
s.required_ruby_version = '>= 1.9.2'
|
43
44
|
end
|
44
45
|
|
45
|
-
|
46
|
+
Gem::PackageTask.new(spec) do |pkg|
|
46
47
|
pkg.need_tar = true
|
47
48
|
end
|
48
49
|
|
@@ -62,4 +63,58 @@ Rake::TestTask.new(:test) do |test|
|
|
62
63
|
test.warning = false
|
63
64
|
end
|
64
65
|
|
65
|
-
|
66
|
+
# Find lib and chat js includes and return them as two arrays.
|
67
|
+
def scripts(doc)
|
68
|
+
lib, chat = [], []
|
69
|
+
doc.css('script').each do |node|
|
70
|
+
file = node['src'].split('/').last()
|
71
|
+
if node['src'].start_with?('/lib')
|
72
|
+
lib << file
|
73
|
+
elsif node['src'].start_with?('/chat')
|
74
|
+
chat << file
|
75
|
+
end
|
76
|
+
end
|
77
|
+
[lib, chat]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Replace script tags with combined and minimized files.
|
81
|
+
def rewrite_js(doc)
|
82
|
+
doc.css('script').each {|node| node.remove }
|
83
|
+
doc.css('head').each do |node|
|
84
|
+
%w[/lib/javascripts/base.js /chat/javascripts/app.js].each do |src|
|
85
|
+
script = doc.create_element('script',
|
86
|
+
'type' => 'text/javascript',
|
87
|
+
'src' => src)
|
88
|
+
node.add_child(script)
|
89
|
+
node.add_child(doc.create_text_node("\n"))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
task :compile do
|
95
|
+
index = 'web/chat/index.html'
|
96
|
+
doc = Nokogiri::HTML(File.read(index))
|
97
|
+
lib, chat = scripts(doc)
|
98
|
+
|
99
|
+
rewrite_js(doc)
|
100
|
+
# save index.html before rewriting
|
101
|
+
FileUtils.cp(index, '/tmp/index.html')
|
102
|
+
File.open(index, 'w') {|f| f.write(doc.to_xml(:indent => 2)) }
|
103
|
+
|
104
|
+
lib = lib.map {|f| "web/lib/javascripts/#{f}"}.join(' ')
|
105
|
+
chat = chat.map {|f| "web/chat/javascripts/#{f}"}.join(' ')
|
106
|
+
|
107
|
+
sh %{coffee -c -b -o web/chat/javascripts web/chat/coffeescripts/*.coffee}
|
108
|
+
sh %{cat #{chat} | uglifyjs -nc > web/chat/javascripts/app.js}
|
109
|
+
|
110
|
+
sh %{coffee -c -b -o web/lib/javascripts web/lib/coffeescripts/*.coffee}
|
111
|
+
sh %{cat #{lib} | uglifyjs -nc > web/lib/javascripts/base.js}
|
112
|
+
end
|
113
|
+
|
114
|
+
task :cleanup do
|
115
|
+
# move index.html back into place after gem packaging
|
116
|
+
FileUtils.cp('/tmp/index.html', 'web/chat/index.html')
|
117
|
+
File.delete('/tmp/index.html')
|
118
|
+
end
|
119
|
+
|
120
|
+
task :default => [:clobber, :test, :compile, :gem, :cleanup]
|
data/bin/vines
CHANGED
data/conf/config.rb
CHANGED
@@ -19,13 +19,13 @@ Vines::Config.configure do
|
|
19
19
|
# Shared storage example:
|
20
20
|
# host 'verona.lit', 'wonderland.lit' do
|
21
21
|
# storage 'fs' do
|
22
|
-
# dir '
|
22
|
+
# dir 'data/users'
|
23
23
|
# end
|
24
24
|
# end
|
25
25
|
|
26
26
|
host 'wonderland.lit' do
|
27
27
|
storage 'fs' do
|
28
|
-
dir '
|
28
|
+
dir 'data/users'
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -36,7 +36,7 @@ Vines::Config.configure do
|
|
36
36
|
#
|
37
37
|
# host 'wonderland.lit' do
|
38
38
|
# storage 'fs' do
|
39
|
-
# dir '
|
39
|
+
# dir 'data/users'
|
40
40
|
# end
|
41
41
|
# ldap 'ldap.wonderland.lit', 636 do
|
42
42
|
# dn 'cn=Directory Manager'
|
@@ -51,7 +51,10 @@ Vines::Config.configure do
|
|
51
51
|
|
52
52
|
# Configure the client-to-server port. The max_resources_per_account attribute
|
53
53
|
# limits how many concurrent connections one user can have to the server.
|
54
|
+
# The private_storage attribute allows clients to store XML fragments
|
55
|
+
# on the server, using the XEP-0049 Private XML Storage feature.
|
54
56
|
client '0.0.0.0', 5222 do
|
57
|
+
private_storage true
|
55
58
|
max_stanza_size 65536
|
56
59
|
max_resources_per_account 5
|
57
60
|
end
|
@@ -65,11 +68,17 @@ Vines::Config.configure do
|
|
65
68
|
hosts []
|
66
69
|
end
|
67
70
|
|
68
|
-
# Configure the
|
69
|
-
#
|
71
|
+
# Configure the built-in HTTP server that serves static files and responds to
|
72
|
+
# XEP-0124 BOSH requests. This allows HTTP clients to connect to
|
73
|
+
# the XMPP server. The root attribute defines the web server's document root.
|
74
|
+
# It will only serve files out of this directory. The bind attribute defines
|
75
|
+
# the URL to which BOSH clients must POST their XMPP stanza requests.
|
70
76
|
http '0.0.0.0', 5280 do
|
71
|
-
|
77
|
+
bind '/xmpp'
|
78
|
+
private_storage true
|
79
|
+
max_stanza_size 65536
|
72
80
|
max_resources_per_account 5
|
81
|
+
root 'web'
|
73
82
|
end
|
74
83
|
|
75
84
|
# Configure the XEP-0114 external component port. Add entries for each
|
@@ -85,7 +94,7 @@ end
|
|
85
94
|
# Available storage implementations:
|
86
95
|
|
87
96
|
#storage 'fs' do
|
88
|
-
# dir '
|
97
|
+
# dir 'data/users'
|
89
98
|
#end
|
90
99
|
|
91
100
|
#storage 'couchdb' do
|
data/lib/vines.rb
CHANGED
@@ -2,22 +2,25 @@
|
|
2
2
|
|
3
3
|
module Vines
|
4
4
|
NAMESPACES = {
|
5
|
-
:stream
|
6
|
-
:client
|
7
|
-
:server
|
8
|
-
:component
|
9
|
-
:roster
|
10
|
-
:non_sasl
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
5
|
+
:stream => 'http://etherx.jabber.org/streams'.freeze,
|
6
|
+
:client => 'jabber:client'.freeze,
|
7
|
+
:server => 'jabber:server'.freeze,
|
8
|
+
:component => 'jabber:component:accept'.freeze,
|
9
|
+
:roster => 'jabber:iq:roster'.freeze,
|
10
|
+
:non_sasl => 'jabber:iq:auth'.freeze,
|
11
|
+
:storage => 'jabber:iq:private'.freeze,
|
12
|
+
:sasl => 'urn:ietf:params:xml:ns:xmpp-sasl'.freeze,
|
13
|
+
:tls => 'urn:ietf:params:xml:ns:xmpp-tls'.freeze,
|
14
|
+
:bind => 'urn:ietf:params:xml:ns:xmpp-bind'.freeze,
|
15
|
+
:session => 'urn:ietf:params:xml:ns:xmpp-session'.freeze,
|
16
|
+
:ping => 'urn:xmpp:ping'.freeze,
|
17
|
+
:disco_items => 'http://jabber.org/protocol/disco#items'.freeze,
|
18
|
+
:disco_info => 'http://jabber.org/protocol/disco#info'.freeze,
|
19
|
+
:http_bind => 'http://jabber.org/protocol/httpbind'.freeze,
|
20
|
+
:bosh => 'urn:xmpp:xbosh'.freeze,
|
21
|
+
:vcard => 'vcard-temp'.freeze,
|
22
|
+
:si => 'http://jabber.org/protocol/si'.freeze,
|
23
|
+
:byte_streams => 'http://jabber.org/protocol/bytestreams'.freeze
|
21
24
|
}.freeze
|
22
25
|
|
23
26
|
module Log
|
@@ -52,6 +55,7 @@ end
|
|
52
55
|
em-redis
|
53
56
|
eventmachine
|
54
57
|
fiber
|
58
|
+
fileutils
|
55
59
|
http/parser
|
56
60
|
logger
|
57
61
|
net/ldap
|
@@ -70,6 +74,7 @@ end
|
|
70
74
|
vines/stanza/iq/disco_items
|
71
75
|
vines/stanza/iq/error
|
72
76
|
vines/stanza/iq/ping
|
77
|
+
vines/stanza/iq/private_storage
|
73
78
|
vines/stanza/iq/result
|
74
79
|
vines/stanza/iq/roster
|
75
80
|
vines/stanza/iq/session
|
data/lib/vines/command/init.rb
CHANGED
@@ -10,9 +10,11 @@ module Vines
|
|
10
10
|
raise "Directory already initialized: #{domain}" if File.exists?(dir)
|
11
11
|
Dir.mkdir(dir)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
%w[conf web].each do |sub|
|
14
|
+
FileUtils.cp_r(File.expand_path("../../../../#{sub}", __FILE__), dir)
|
15
|
+
end
|
16
|
+
users, log, pid = %w[data/users log pid].map do |sub|
|
17
|
+
File.join(dir, sub).tap {|subdir| FileUtils.makedirs(subdir) }
|
16
18
|
end
|
17
19
|
|
18
20
|
create_users(domain, users)
|
data/lib/vines/config.rb
CHANGED
@@ -144,6 +144,14 @@ module Vines
|
|
144
144
|
@settings[:max_resources_per_account]
|
145
145
|
end
|
146
146
|
end
|
147
|
+
|
148
|
+
def private_storage(enabled)
|
149
|
+
@settings[:private_storage] = !!enabled
|
150
|
+
end
|
151
|
+
|
152
|
+
def private_storage?
|
153
|
+
@settings[:private_storage]
|
154
|
+
end
|
147
155
|
end
|
148
156
|
|
149
157
|
class ServerPort < Port
|
@@ -166,6 +174,8 @@ module Vines
|
|
166
174
|
def initialize(config, host='0.0.0.0', port=5280, &block)
|
167
175
|
@stream = Vines::Stream::Http
|
168
176
|
super(config, host, port, &block)
|
177
|
+
defaults = {:root => File.expand_path('web'), :bind => '/xmpp'}
|
178
|
+
@settings = defaults.merge(@settings)
|
169
179
|
end
|
170
180
|
|
171
181
|
def max_resources_per_account(max=nil)
|
@@ -175,6 +185,30 @@ module Vines
|
|
175
185
|
@settings[:max_resources_per_account]
|
176
186
|
end
|
177
187
|
end
|
188
|
+
|
189
|
+
def private_storage(enabled)
|
190
|
+
@settings[:private_storage] = !!enabled
|
191
|
+
end
|
192
|
+
|
193
|
+
def private_storage?
|
194
|
+
@settings[:private_storage]
|
195
|
+
end
|
196
|
+
|
197
|
+
def root(dir=nil)
|
198
|
+
if dir
|
199
|
+
@settings[:root] = File.expand_path(dir)
|
200
|
+
else
|
201
|
+
@settings[:root]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def bind(url=nil)
|
206
|
+
if url
|
207
|
+
@settings[:bind] = url
|
208
|
+
else
|
209
|
+
@settings[:bind]
|
210
|
+
end
|
211
|
+
end
|
178
212
|
end
|
179
213
|
|
180
214
|
class ComponentPort < Port
|
data/lib/vines/contact.rb
CHANGED
@@ -80,6 +80,20 @@ module Vines
|
|
80
80
|
}
|
81
81
|
end
|
82
82
|
|
83
|
+
# Write an iq stanza to the recipient stream representing this contact's
|
84
|
+
# current roster item state.
|
85
|
+
def send_roster_push(recipient)
|
86
|
+
doc = Nokogiri::XML::Document.new
|
87
|
+
node = doc.create_element('iq',
|
88
|
+
'id' => Kit.uuid,
|
89
|
+
'to' => recipient.user.jid.to_s,
|
90
|
+
'type' => 'set')
|
91
|
+
node << doc.create_element('query', 'xmlns' => NAMESPACES[:roster]) do |query|
|
92
|
+
query << to_roster_xml
|
93
|
+
end
|
94
|
+
recipient.write(node)
|
95
|
+
end
|
96
|
+
|
83
97
|
# Returns this contact as an xmpp <item> element.
|
84
98
|
def to_roster_xml
|
85
99
|
doc = Nokogiri::XML::Document.new
|
data/lib/vines/stanza.rb
CHANGED
@@ -55,6 +55,32 @@ module Vines
|
|
55
55
|
raise 'subclass must implement'
|
56
56
|
end
|
57
57
|
|
58
|
+
# Broadcast unavailable presence from the user's available resources to the
|
59
|
+
# recipient's available resources. Route the stanza to a remote server if
|
60
|
+
# the recipient isn't hosted locally.
|
61
|
+
def send_unavailable(from, to)
|
62
|
+
router.available_resources(from).each do |stream|
|
63
|
+
el = unavailable(stream.user.jid, to)
|
64
|
+
if router.local_jid?(to)
|
65
|
+
router.available_resources(to).each do |recipient|
|
66
|
+
recipient.write(el)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
router.route(el)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return an unavailable presence stanza addressed to the given JID.
|
75
|
+
def unavailable(from, to)
|
76
|
+
doc = Document.new
|
77
|
+
doc.create_element('presence',
|
78
|
+
'from' => from.to_s,
|
79
|
+
'id' => Kit.uuid,
|
80
|
+
'to' => to.to_s,
|
81
|
+
'type' => 'unavailable')
|
82
|
+
end
|
83
|
+
|
58
84
|
def method_missing(method, *args, &block)
|
59
85
|
@node.send(method, *args, &block)
|
60
86
|
end
|
data/lib/vines/stanza/iq.rb
CHANGED
@@ -15,7 +15,7 @@ module Vines
|
|
15
15
|
|
16
16
|
def process
|
17
17
|
if self['id'] && VALID_TYPES.include?(self['type'])
|
18
|
-
raise StanzaErrors::FeatureNotImplemented.new(@node, 'cancel')
|
18
|
+
route_iq or raise StanzaErrors::FeatureNotImplemented.new(@node, 'cancel')
|
19
19
|
else
|
20
20
|
raise StanzaErrors::BadRequest.new(@node, 'modify')
|
21
21
|
end
|
@@ -15,6 +15,9 @@ module Vines
|
|
15
15
|
query.default_namespace = NS
|
16
16
|
query << el.document.create_element('feature', 'var' => NAMESPACES[:ping])
|
17
17
|
query << el.document.create_element('feature', 'var' => NAMESPACES[:vcard])
|
18
|
+
if stream.private_storage?
|
19
|
+
query << el.document.create_element('feature', 'var' => NAMESPACES[:storage])
|
20
|
+
end
|
18
21
|
end
|
19
22
|
end
|
20
23
|
stream.write(result)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Vines
|
4
|
+
class Stanza
|
5
|
+
class Iq
|
6
|
+
# Implements the Private Storage feature defined in XEP-0049. Clients are
|
7
|
+
# allowed to save arbitrary XML documents on the server, identified by
|
8
|
+
# element name and namespace.
|
9
|
+
class PrivateStorage < Query
|
10
|
+
NS = NAMESPACES[:storage]
|
11
|
+
|
12
|
+
register "/iq[@id and (@type='get' or @type='set')]/ns:query", 'ns' => NS
|
13
|
+
|
14
|
+
def process
|
15
|
+
unless stream.private_storage?
|
16
|
+
raise StanzaErrors::ServiceUnavailable.new(self, 'cancel')
|
17
|
+
end
|
18
|
+
validate_to_address
|
19
|
+
validate_children_size
|
20
|
+
validate_namespaces
|
21
|
+
get? ? retrieve_fragment : update_fragment
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def retrieve_fragment
|
27
|
+
found = storage.find_fragment(stream.user.jid, elements.first.elements.first)
|
28
|
+
raise StanzaErrors::ItemNotFound.new(self, 'cancel') unless found
|
29
|
+
|
30
|
+
result = to_result do |node|
|
31
|
+
node << node.document.create_element('query') do |query|
|
32
|
+
query.default_namespace = NS
|
33
|
+
query << found
|
34
|
+
end
|
35
|
+
end
|
36
|
+
stream.write(result)
|
37
|
+
end
|
38
|
+
|
39
|
+
def update_fragment
|
40
|
+
elements.first.elements.each do |node|
|
41
|
+
storage.save_fragment(stream.user.jid, node)
|
42
|
+
end
|
43
|
+
stream.write(to_result)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def to_result
|
49
|
+
doc = Document.new
|
50
|
+
node = doc.create_element('iq',
|
51
|
+
'from' => stream.user.jid.to_s,
|
52
|
+
'id' => self['id'],
|
53
|
+
'to' => stream.user.jid.to_s,
|
54
|
+
'type' => 'result')
|
55
|
+
yield node if block_given?
|
56
|
+
node
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_children_size
|
60
|
+
size = elements.first.elements.size
|
61
|
+
if (get? && size != 1) || (set? && size == 0)
|
62
|
+
raise StanzaErrors::NotAcceptable.new(self, 'modify')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_to_address
|
67
|
+
to = (self['to'] || '').strip
|
68
|
+
unless to.empty? || to == stream.user.jid.bare.to_s
|
69
|
+
raise StanzaErrors::Forbidden.new(self, 'cancel')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_namespaces
|
74
|
+
elements.first.elements.each do |node|
|
75
|
+
if node.namespace.nil? || NAMESPACES.values.include?(node.namespace.href)
|
76
|
+
raise StanzaErrors::NotAcceptable.new(self, 'modify')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|