rims 0.2.8 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -0
- data/ChangeLog +5 -0
- data/Rakefile +8 -4
- data/lib/rims/channel.rb +35 -10
- data/lib/rims/cmd.rb +11 -0
- data/lib/rims/error.rb +15 -0
- data/lib/rims/protocol/decoder.rb +595 -385
- data/lib/rims/protocol/parser.rb +2 -2
- data/lib/rims/service.rb +14 -9
- data/lib/rims/version.rb +1 -1
- data/load_test/Rakefile +3 -1
- data/rims.gemspec +1 -1
- data/test/cmd/test_command.rb +1 -0
- data/test/test_channel.rb +2 -1
- data/test/test_error.rb +32 -0
- data/test/test_lock.rb +4 -4
- data/test/test_protocol_decoder.rb +113 -32
- data/test/test_service.rb +8 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d256a00569dbf130c60b1ce0a2e81eaaaee80c8f05bd539951044050d8730ed8
|
4
|
+
data.tar.gz: dadb9184722598429f498a3c024bb911717f2cacd28e8b2b72073704401c6af1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d630fcd4aea66809516f8878d5b0f9511331c3afaf1fc71a6f0ac08f5a4329345868f5a5cf2665e54a9985dd7939c7b478da2c8f7cfe1a686603f621519cef75
|
7
|
+
data.tar.gz: 6a34c95ce5f6a6012da5e790326e2e991ecccc0cb186ac53fd8c6b2b1f829df0b41c8087fa567970dbf912295901ed4e4a83865117e1c564df90da43b7874807
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
Change Log
|
2
|
+
==========
|
3
|
+
|
4
|
+
0.2.9
|
5
|
+
-----
|
6
|
+
Released on 2019-12-12.
|
7
|
+
|
8
|
+
### Added
|
9
|
+
- Add `umask(2)` configuration parameter. [#29](https://github.com/y10k/rims/issues/29)
|
10
|
+
- Add debug logging for conflicted subscriber error. This problem is
|
11
|
+
not solved because it does not reappear. [#28](https://github.com/y10k/rims/issues/28)
|
12
|
+
|
13
|
+
### Changed
|
14
|
+
- Ready to Ruby 2.7. [#35](https://github.com/y10k/rims/issues/35)
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
- Fix a bug of detached thread finishing a protocol decoder engine.
|
18
|
+
- Make bulk message size of inter-process communication not exceeding `DRb`'s `load_limit`.
|
19
|
+
[#30](https://github.com/y10k/rims/issues/30)
|
20
|
+
[#33](https://github.com/y10k/rims/issues/33)
|
21
|
+
|
22
|
+
0.2.8
|
23
|
+
-----
|
24
|
+
Released on 2019-10-10.
|
25
|
+
|
26
|
+
0.2.7
|
27
|
+
-----
|
28
|
+
Released on 2019-07-27.
|
29
|
+
|
30
|
+
0.2.6
|
31
|
+
-----
|
32
|
+
Released on 2019-07-09.
|
33
|
+
|
34
|
+
0.2.5
|
35
|
+
-----
|
36
|
+
Released on 2019-06-10.
|
37
|
+
|
38
|
+
0.2.4
|
39
|
+
-----
|
40
|
+
Released on 2019-04-25.
|
41
|
+
|
42
|
+
0.2.3
|
43
|
+
-----
|
44
|
+
Released on 2019-04-10.
|
45
|
+
|
46
|
+
0.2.2
|
47
|
+
-----
|
48
|
+
Released on 2019-03-06.
|
49
|
+
|
50
|
+
0.2.1
|
51
|
+
-----
|
52
|
+
Released on 2019-02-18.
|
53
|
+
|
54
|
+
0.1.0
|
55
|
+
-----
|
56
|
+
Released on 2015-02-22.
|
57
|
+
|
58
|
+
0.0.4
|
59
|
+
-----
|
60
|
+
Released on 2014-06-08.
|
61
|
+
|
62
|
+
0.0.3
|
63
|
+
-----
|
64
|
+
Released on 2014-04-15.
|
65
|
+
|
66
|
+
0.0.2
|
67
|
+
-----
|
68
|
+
Released on 2014-03-05.
|
69
|
+
|
70
|
+
0.0.1
|
71
|
+
-----
|
72
|
+
Released on 2014-02-24.
|
73
|
+
|
data/ChangeLog
CHANGED
data/Rakefile
CHANGED
@@ -28,14 +28,18 @@ Rake::RDocTask.new do |rd|
|
|
28
28
|
rd.rdoc_files.include('lib/**/*.rb')
|
29
29
|
end
|
30
30
|
|
31
|
+
rule '.html' => '.md' do |t|
|
32
|
+
sh "pandoc --from=markdown --to=html5 --standalone --self-contained --css=$HOME/.pandoc/github.css --output=#{t.name} #{t.source}"
|
33
|
+
end
|
34
|
+
|
31
35
|
desc 'Build README.html from markdown source'
|
32
36
|
task :readme => %w[ README.html ]
|
33
|
-
|
34
|
-
file 'README.html' => [ 'README.md' ] do
|
35
|
-
sh "pandoc --from=markdown --to=html5 --standalone --self-contained --css=$HOME/.pandoc/github.css --output=README.html README.md"
|
36
|
-
end
|
37
37
|
CLOBBER.include 'README.html'
|
38
38
|
|
39
|
+
desc 'Build CHANGELOG.html from markdown source'
|
40
|
+
task :changelog => %w[ CHANGELOG.html ]
|
41
|
+
CLOBBER.include 'CHANGELOG.html'
|
42
|
+
|
39
43
|
namespace :test_cert do
|
40
44
|
tls_dir = Pathname('test/tls')
|
41
45
|
|
data/lib/rims/channel.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
+
require 'forwardable'
|
4
|
+
|
3
5
|
module RIMS
|
6
|
+
class ServerResponseChannelError < Error
|
7
|
+
end
|
8
|
+
|
9
|
+
class ServerResponseChannelAttachError < ServerResponseChannelError
|
10
|
+
end
|
11
|
+
|
12
|
+
class ServerResponseChannelDetachError < ServerResponseChannelError
|
13
|
+
end
|
14
|
+
|
15
|
+
class ServerResponseChannelPublishError < ServerResponseChannelError
|
16
|
+
end
|
17
|
+
|
4
18
|
class ServerResponseChannel
|
5
19
|
def initialize
|
6
20
|
@mutex = Thread::Mutex.new
|
@@ -9,14 +23,16 @@ module RIMS
|
|
9
23
|
|
10
24
|
def make_pub_sub_pair(mbox_id)
|
11
25
|
pub = ServerResponsePublisher.new(self, mbox_id)
|
12
|
-
sub = ServerResponseSubscriber.new(self,
|
26
|
+
sub = ServerResponseSubscriber.new(self, pub)
|
13
27
|
return pub, attach(sub)
|
14
28
|
end
|
15
29
|
|
16
30
|
def attach(sub)
|
17
31
|
@mutex.synchronize{
|
18
32
|
@channel[sub.mbox_id] ||= {}
|
19
|
-
(@channel[sub.mbox_id].key? sub.pub_sub_pair_key)
|
33
|
+
if (@channel[sub.mbox_id].key? sub.pub_sub_pair_key) then
|
34
|
+
raise ServerResponseChannelAttachError.new('conflicted subscriber.', channel: self, subscriber: sub)
|
35
|
+
end
|
20
36
|
@channel[sub.mbox_id][sub.pub_sub_pair_key] = sub
|
21
37
|
}
|
22
38
|
|
@@ -30,8 +46,13 @@ module RIMS
|
|
30
46
|
# - ServerResponseSubscriber#detach
|
31
47
|
def detach(sub)
|
32
48
|
@mutex.synchronize{
|
33
|
-
((@channel.key? sub.mbox_id) && (@channel[sub.mbox_id].key? sub.pub_sub_pair_key))
|
34
|
-
|
49
|
+
unless ((@channel.key? sub.mbox_id) && (@channel[sub.mbox_id].key? sub.pub_sub_pair_key)) then
|
50
|
+
raise ServerResponseChannelDetachError.new('unregistered pub-sub pair.', channel: self, subscriber: sub)
|
51
|
+
end
|
52
|
+
|
53
|
+
unless (@channel[sub.mbox_id][sub.pub_sub_pair_key] == sub) then
|
54
|
+
raise ServerResponseChannelDetachError.new('internal error: mismatched subscriber.', channel: self, subscribe: sub)
|
55
|
+
end
|
35
56
|
|
36
57
|
@channel[sub.mbox_id].delete(sub.pub_sub_pair_key)
|
37
58
|
if (@channel[sub.mbox_id].empty?) then
|
@@ -74,7 +95,12 @@ module RIMS
|
|
74
95
|
end
|
75
96
|
|
76
97
|
def publish(response_message)
|
77
|
-
@channel
|
98
|
+
unless (@channel) then
|
99
|
+
raise ServerResponseChannelPublishError.new('detached publisher.',
|
100
|
+
publisher: self,
|
101
|
+
pub_sub_pair_key: pub_sub_pair_key,
|
102
|
+
message: response_message)
|
103
|
+
end
|
78
104
|
@channel.publish(@mbox_id, pub_sub_pair_key, response_message)
|
79
105
|
nil
|
80
106
|
end
|
@@ -89,15 +115,14 @@ module RIMS
|
|
89
115
|
# do not call this method directly, call the following method
|
90
116
|
# instead.
|
91
117
|
# - ServerResponseChannel#make_pub_sub_pair
|
92
|
-
def initialize(channel,
|
118
|
+
def initialize(channel, pub)
|
93
119
|
@channel = channel
|
94
|
-
@
|
95
|
-
@pub_sub_pair_key = pub_sub_pair_key
|
120
|
+
@pub = pub
|
96
121
|
@queue = Thread::Queue.new
|
97
122
|
end
|
98
123
|
|
99
|
-
|
100
|
-
|
124
|
+
extend Forwardable
|
125
|
+
def_delegators :@pub, :mbox_id, :pub_sub_pair_key
|
101
126
|
|
102
127
|
# do not call this method directly, call the following method
|
103
128
|
# instead.
|
data/lib/rims/cmd.rb
CHANGED
@@ -325,6 +325,16 @@ module RIMS
|
|
325
325
|
})
|
326
326
|
}
|
327
327
|
end
|
328
|
+
options.on('--daemon-umask=UMASK',
|
329
|
+
Integer,
|
330
|
+
"Umask(2). effective only with daemon command. default is `#{'%04o' % Service::DEFAULT_CONFIG.daemon_umask}'."
|
331
|
+
) do |umask|
|
332
|
+
build.chain{|c|
|
333
|
+
c.load(daemon: {
|
334
|
+
umask: umask
|
335
|
+
})
|
336
|
+
}
|
337
|
+
end
|
328
338
|
options.on('--status-file=FILE',
|
329
339
|
String,
|
330
340
|
"Name of status file. effective only with daemon command. default is `#{Service::DEFAULT_CONFIG.status_file}'."
|
@@ -1132,6 +1142,7 @@ module RIMS
|
|
1132
1142
|
Riser::Daemon.start_daemon(daemonize: svc_conf.daemonize?,
|
1133
1143
|
daemon_name: svc_conf.daemon_name,
|
1134
1144
|
daemon_debug: svc_conf.daemon_debug?,
|
1145
|
+
daemon_umask: svc_conf.daemon_umask,
|
1135
1146
|
status_file: svc_conf.status_file,
|
1136
1147
|
listen_address: proc{
|
1137
1148
|
# to reload on server restart
|
data/lib/rims/error.rb
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
module RIMS
|
4
4
|
class Error < StandardError
|
5
|
+
def initialize(*args, **kw_args)
|
6
|
+
super(*args)
|
7
|
+
@optional_data = kw_args.dup.freeze
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :optional_data
|
11
|
+
|
5
12
|
def self.trace_error_chain(exception)
|
6
13
|
return enum_for(:trace_error_chain, exception) unless block_given?
|
7
14
|
|
@@ -12,6 +19,14 @@ module RIMS
|
|
12
19
|
|
13
20
|
nil
|
14
21
|
end
|
22
|
+
|
23
|
+
def self.optional_data(error) # :yields: error, data
|
24
|
+
if (error.is_a? Error) then
|
25
|
+
unless (error.optional_data.empty?) then
|
26
|
+
yield(error, error.optional_data)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
15
30
|
end
|
16
31
|
end
|
17
32
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'logger'
|
4
4
|
require 'net/imap'
|
5
|
+
require 'pp'
|
5
6
|
require 'time'
|
6
7
|
|
7
8
|
module RIMS
|
@@ -21,35 +22,67 @@ module RIMS
|
|
21
22
|
name.upcase
|
22
23
|
end
|
23
24
|
|
25
|
+
def self.logging_error_chain(error, logger)
|
26
|
+
Error.trace_error_chain(error) do |exception|
|
27
|
+
if (logger.debug?) then
|
28
|
+
Error.optional_data(exception) do |error, data|
|
29
|
+
logger.debug("error message: #{error.message} (#{error.class})")
|
30
|
+
for name, value in data
|
31
|
+
logger.debug("error data [#{name}]: #{value.pretty_inspect}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
logger.error(exception)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
24
39
|
def self.repl(decoder, limits, input, output, logger)
|
25
40
|
input_gets = input.method(:gets)
|
26
|
-
output_write = lambda{|
|
27
|
-
|
28
|
-
for data in res
|
41
|
+
output_write = lambda{|data|
|
42
|
+
begin
|
29
43
|
if (data == :flush) then
|
30
44
|
output.flush
|
31
45
|
else
|
32
46
|
logger.debug("response data: #{Protocol.io_data_log(data)}") if logger.debug?
|
33
47
|
output << data
|
34
|
-
last_line = data
|
35
48
|
end
|
49
|
+
rescue
|
50
|
+
logger.error('response write error.')
|
51
|
+
logging_error_chain($!, logger)
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
}
|
55
|
+
server_output_write = lambda{|res|
|
56
|
+
for data in res
|
57
|
+
output_write.call(data)
|
36
58
|
end
|
37
59
|
output.flush
|
38
60
|
|
39
|
-
|
61
|
+
nil
|
40
62
|
}
|
41
|
-
response_write =
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
63
|
+
response_write = lambda{|response|
|
64
|
+
output_write.call(response)
|
65
|
+
output.flush
|
66
|
+
logger.info("server response: #{response.strip}")
|
67
|
+
}
|
68
|
+
apply_imap_command = lambda{|name, *args, uid: false|
|
69
|
+
last_line = nil
|
70
|
+
if (uid) then
|
71
|
+
decoder.__send__(name, *args, uid: true) {|response|
|
72
|
+
output_write.call(response)
|
73
|
+
last_line = response if (response.is_a? String)
|
74
|
+
}
|
75
|
+
else
|
76
|
+
decoder.__send__(name, *args) {|response|
|
77
|
+
output_write.call(response)
|
78
|
+
last_line = response if (response.is_a? String)
|
79
|
+
}
|
49
80
|
end
|
81
|
+
output.flush
|
82
|
+
logger.info("server response: #{last_line.strip}") if last_line
|
50
83
|
}
|
51
84
|
|
52
|
-
|
85
|
+
apply_imap_command.call(:ok_greeting)
|
53
86
|
|
54
87
|
conn_timer = ConnectionTimer.new(limits, input.to_io)
|
55
88
|
request_reader = RequestReader.new(input, output, logger)
|
@@ -61,10 +94,8 @@ module RIMS
|
|
61
94
|
atom_list = request_reader.read_command
|
62
95
|
rescue
|
63
96
|
logger.error('invalid client command.')
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
response_write.call([ "* BAD client command syntax error\r\n" ])
|
97
|
+
logging_error_chain($!, logger)
|
98
|
+
response_write.call("* BAD client command syntax error\r\n")
|
68
99
|
next
|
69
100
|
end
|
70
101
|
|
@@ -100,32 +131,30 @@ module RIMS
|
|
100
131
|
logger.info("uid command: #{uid_command}")
|
101
132
|
logger.debug("uid parameter: #{uid_args}") if logger.debug?
|
102
133
|
if (uid_name = UID_CMDs[imap_command_normalize(uid_command)]) then
|
103
|
-
|
134
|
+
apply_imap_command.call(uid_name, tag, *uid_args, uid: true)
|
104
135
|
else
|
105
136
|
logger.error("unknown uid command: #{uid_command}")
|
106
|
-
response_write.call(
|
137
|
+
response_write.call("#{tag} BAD unknown uid command\r\n")
|
107
138
|
end
|
108
139
|
else
|
109
140
|
logger.error('empty uid parameter.')
|
110
|
-
response_write.call(
|
141
|
+
response_write.call("#{tag} BAD empty uid parameter\r\n")
|
111
142
|
end
|
112
143
|
when :authenticate
|
113
|
-
|
144
|
+
apply_imap_command.call(:authenticate, tag, input_gets, server_output_write, *opt_args)
|
114
145
|
when :idle
|
115
|
-
|
146
|
+
apply_imap_command.call(:idle, tag, input_gets, server_output_write, conn_timer, *opt_args)
|
116
147
|
else
|
117
|
-
|
148
|
+
apply_imap_command.call(name, tag, *opt_args)
|
118
149
|
end
|
119
150
|
else
|
120
151
|
logger.error("unknown command: #{command}")
|
121
|
-
response_write.call(
|
152
|
+
response_write.call("#{tag} BAD unknown command\r\n")
|
122
153
|
end
|
123
154
|
rescue
|
124
155
|
logger.error('unexpected error.')
|
125
|
-
|
126
|
-
|
127
|
-
end
|
128
|
-
response_write.call([ "#{tag} BAD unexpected error\r\n" ])
|
156
|
+
logging_error_chain($!, logger)
|
157
|
+
response_write.call("#{tag} BAD unexpected error\r\n")
|
129
158
|
end
|
130
159
|
|
131
160
|
if (normalized_command == 'LOGOUT') then
|
@@ -137,9 +166,9 @@ module RIMS
|
|
137
166
|
|
138
167
|
if (conn_timer.command_wait_timeout?) then
|
139
168
|
if (limits.command_wait_timeout_seconds > 0) then
|
140
|
-
response_write.call(
|
169
|
+
response_write.call("* BYE server autologout: idle for too long\r\n")
|
141
170
|
else
|
142
|
-
response_write.call(
|
171
|
+
response_write.call("* BYE server autologout: shutdown\r\n")
|
143
172
|
end
|
144
173
|
end
|
145
174
|
|
@@ -157,25 +186,10 @@ module RIMS
|
|
157
186
|
|
158
187
|
attr_reader :next_decoder
|
159
188
|
|
160
|
-
def
|
161
|
-
|
162
|
-
begin
|
163
|
-
yield(res)
|
164
|
-
rescue SyntaxError
|
165
|
-
@logger.error('client command syntax error.')
|
166
|
-
@logger.error($!)
|
167
|
-
res << "#{tag} BAD client command syntax error\r\n"
|
168
|
-
rescue
|
169
|
-
raise if ($!.class.name =~ /AssertionFailedError/)
|
170
|
-
@logger.error('internal server error.')
|
171
|
-
Error.trace_error_chain($!) do |exception|
|
172
|
-
@logger.error(exception)
|
173
|
-
end
|
174
|
-
res << "#{tag} BAD internal server error\r\n"
|
175
|
-
end
|
176
|
-
}
|
189
|
+
def logging_error_chain(error)
|
190
|
+
self.class.logging_error_chain(error, @logger)
|
177
191
|
end
|
178
|
-
private :
|
192
|
+
private :logging_error_chain
|
179
193
|
|
180
194
|
def guard_error(imap_command, tag, *args, **kw_args, &block)
|
181
195
|
begin
|
@@ -186,19 +200,17 @@ module RIMS
|
|
186
200
|
end
|
187
201
|
rescue SyntaxError
|
188
202
|
@logger.error('client command syntax error.')
|
189
|
-
|
190
|
-
yield(
|
203
|
+
logging_error_chain($!)
|
204
|
+
yield("#{tag} BAD client command syntax error\r\n")
|
191
205
|
rescue ArgumentError
|
192
206
|
@logger.error('invalid command parameter.')
|
193
|
-
|
194
|
-
yield(
|
207
|
+
logging_error_chain($!)
|
208
|
+
yield("#{tag} BAD invalid command parameter\r\n")
|
195
209
|
rescue
|
196
210
|
raise if ($!.class.name =~ /AssertionFailedError/)
|
197
211
|
@logger.error('internal server error.')
|
198
|
-
|
199
|
-
|
200
|
-
end
|
201
|
-
yield([ "#{tag} BAD internal server error\r\n" ])
|
212
|
+
logging_error_chain($!)
|
213
|
+
yield("#{tag} BAD internal server error\r\n")
|
202
214
|
end
|
203
215
|
end
|
204
216
|
private :guard_error
|
@@ -256,8 +268,7 @@ module RIMS
|
|
256
268
|
end
|
257
269
|
private :imap_command
|
258
270
|
|
259
|
-
def make_engine_and_recovery_if_needed(drb_services, username,
|
260
|
-
logger: Logger.new(STDOUT))
|
271
|
+
def make_engine_and_recovery_if_needed(drb_services, username, logger: Logger.new(STDOUT))
|
261
272
|
unique_user_id = Authentication.unique_user_id(username)
|
262
273
|
logger.debug("unique user ID: #{username} -> #{unique_user_id}") if logger.debug?
|
263
274
|
|
@@ -265,7 +276,7 @@ module RIMS
|
|
265
276
|
engine = drb_services[:engine, unique_user_id]
|
266
277
|
|
267
278
|
begin
|
268
|
-
engine.recovery_if_needed(username) {|
|
279
|
+
engine.recovery_if_needed(username) {|response| yield(response) }
|
269
280
|
rescue
|
270
281
|
engine.destroy
|
271
282
|
raise
|
@@ -276,14 +287,13 @@ module RIMS
|
|
276
287
|
end
|
277
288
|
|
278
289
|
def make_logout_response(tag)
|
279
|
-
|
280
|
-
|
281
|
-
]
|
290
|
+
yield("* BYE server logout\r\n")
|
291
|
+
yield("#{tag} OK LOGOUT completed\r\n")
|
282
292
|
end
|
283
293
|
private :make_logout_response
|
284
294
|
|
285
295
|
def ok_greeting
|
286
|
-
yield(
|
296
|
+
yield("* OK RIMS v#{VERSION} IMAP4rev1 service ready.\r\n")
|
287
297
|
end
|
288
298
|
|
289
299
|
# common IMAP command
|
@@ -292,10 +302,8 @@ module RIMS
|
|
292
302
|
def capability(tag)
|
293
303
|
capability_list = %w[ IMAP4rev1 UIDPLUS IDLE ]
|
294
304
|
capability_list += @auth.capability.map{|auth_capability| "AUTH=#{auth_capability}" }
|
295
|
-
|
296
|
-
|
297
|
-
res << "#{tag} OK CAPABILITY completed\r\n"
|
298
|
-
yield(res)
|
305
|
+
yield("* CAPABILITY #{capability_list.join(' ')}\r\n")
|
306
|
+
yield("#{tag} OK CAPABILITY completed\r\n")
|
299
307
|
end
|
300
308
|
imap_command :capability
|
301
309
|
end
|
@@ -330,6 +338,7 @@ module RIMS
|
|
330
338
|
super(auth, logger)
|
331
339
|
@drb_services = drb_services
|
332
340
|
@mail_delivery_user = mail_delivery_user
|
341
|
+
@logger.debug("RIMS::Protocol::InitialDecoder#initialize at #{self}") if @logger.debug?
|
333
342
|
end
|
334
343
|
|
335
344
|
def auth?
|
@@ -341,22 +350,23 @@ module RIMS
|
|
341
350
|
end
|
342
351
|
|
343
352
|
def cleanup
|
353
|
+
@logger.debug("RIMS::Protocol::InitialDecoder#cleanup at #{self}") if @logger.debug?
|
344
354
|
nil
|
345
355
|
end
|
346
356
|
|
347
357
|
def make_not_authenticated_response(tag)
|
348
|
-
|
358
|
+
yield("#{tag} NO not authenticated\r\n")
|
349
359
|
end
|
350
360
|
private :make_not_authenticated_response
|
351
361
|
|
352
362
|
def noop(tag)
|
353
|
-
yield(
|
363
|
+
yield("#{tag} OK NOOP completed\r\n")
|
354
364
|
end
|
355
365
|
imap_command :noop
|
356
366
|
|
357
|
-
def logout(tag)
|
358
|
-
@next_decoder = LogoutDecoder.new(self)
|
359
|
-
|
367
|
+
def logout(tag, &block)
|
368
|
+
@next_decoder = LogoutDecoder.new(self, @logger)
|
369
|
+
make_logout_response(tag, &block)
|
360
370
|
end
|
361
371
|
imap_command :logout
|
362
372
|
|
@@ -366,7 +376,7 @@ module RIMS
|
|
366
376
|
@logger.info("mail delivery user: #{username}")
|
367
377
|
MailDeliveryDecoder.new(self, @drb_services, @auth, @logger)
|
368
378
|
else
|
369
|
-
engine = self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|
|
379
|
+
engine = self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|untagged_response| yield(untagged_response) }
|
370
380
|
UserMailboxDecoder.new(self, engine, @auth, @logger)
|
371
381
|
end
|
372
382
|
end
|
@@ -377,137 +387,137 @@ module RIMS
|
|
377
387
|
auth_reader = AuthenticationReader.new(@auth, client_response_input_gets, server_challenge_output_write, @logger)
|
378
388
|
if (username = auth_reader.authenticate_client(auth_type, inline_client_response_data_base64)) then
|
379
389
|
if (username != :*) then
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
390
|
+
@logger.info("authentication OK: #{username}")
|
391
|
+
@next_decoder = accept_authentication(username) {|untagged_response|
|
392
|
+
yield(untagged_response)
|
393
|
+
yield(:flush)
|
384
394
|
}
|
395
|
+
yield("#{tag} OK AUTHENTICATE #{auth_type} success\r\n")
|
385
396
|
else
|
386
397
|
@logger.info('bad authentication.')
|
387
|
-
yield(
|
398
|
+
yield("#{tag} BAD AUTHENTICATE failed\r\n")
|
388
399
|
end
|
389
400
|
else
|
390
|
-
yield(
|
401
|
+
yield("#{tag} NO authentication failed\r\n")
|
391
402
|
end
|
392
403
|
end
|
393
404
|
imap_command :authenticate
|
394
405
|
|
395
406
|
def login(tag, username, password)
|
396
407
|
if (@auth.authenticate_login(username, password)) then
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
408
|
+
@logger.info("login authentication OK: #{username}")
|
409
|
+
@next_decoder = accept_authentication(username) {|untagged_response|
|
410
|
+
yield(untagged_response)
|
411
|
+
yield(:flush)
|
401
412
|
}
|
413
|
+
yield("#{tag} OK LOGIN completed\r\n")
|
402
414
|
else
|
403
|
-
yield(
|
415
|
+
yield("#{tag} NO failed to login\r\n")
|
404
416
|
end
|
405
417
|
end
|
406
418
|
imap_command :login
|
407
419
|
|
408
|
-
def select(tag, mbox_name)
|
409
|
-
|
420
|
+
def select(tag, mbox_name, &block)
|
421
|
+
make_not_authenticated_response(tag, &block)
|
410
422
|
end
|
411
423
|
imap_command :select
|
412
424
|
|
413
|
-
def examine(tag, mbox_name)
|
414
|
-
|
425
|
+
def examine(tag, mbox_name, &block)
|
426
|
+
make_not_authenticated_response(tag, &block)
|
415
427
|
end
|
416
428
|
imap_command :examine
|
417
429
|
|
418
|
-
def create(tag, mbox_name)
|
419
|
-
|
430
|
+
def create(tag, mbox_name, &block)
|
431
|
+
make_not_authenticated_response(tag, &block)
|
420
432
|
end
|
421
433
|
imap_command :create
|
422
434
|
|
423
|
-
def delete(tag, mbox_name)
|
424
|
-
|
435
|
+
def delete(tag, mbox_name, &block)
|
436
|
+
make_not_authenticated_response(tag, &block)
|
425
437
|
end
|
426
438
|
imap_command :delete
|
427
439
|
|
428
|
-
def rename(tag, src_name, dst_name)
|
429
|
-
|
440
|
+
def rename(tag, src_name, dst_name, &block)
|
441
|
+
make_not_authenticated_response(tag, &block)
|
430
442
|
end
|
431
443
|
imap_command :rename
|
432
444
|
|
433
|
-
def subscribe(tag, mbox_name)
|
434
|
-
|
445
|
+
def subscribe(tag, mbox_name, &block)
|
446
|
+
make_not_authenticated_response(tag, &block)
|
435
447
|
end
|
436
448
|
imap_command :subscribe
|
437
449
|
|
438
|
-
def unsubscribe(tag, mbox_name)
|
439
|
-
|
450
|
+
def unsubscribe(tag, mbox_name, &block)
|
451
|
+
make_not_authenticated_response(tag, &block)
|
440
452
|
end
|
441
453
|
imap_command :unsubscribe
|
442
454
|
|
443
|
-
def list(tag, ref_name, mbox_name)
|
444
|
-
|
455
|
+
def list(tag, ref_name, mbox_name, &block)
|
456
|
+
make_not_authenticated_response(tag, &block)
|
445
457
|
end
|
446
458
|
imap_command :list
|
447
459
|
|
448
|
-
def lsub(tag, ref_name, mbox_name)
|
449
|
-
|
460
|
+
def lsub(tag, ref_name, mbox_name, &block)
|
461
|
+
make_not_authenticated_response(tag, &block)
|
450
462
|
end
|
451
463
|
imap_command :lsub
|
452
464
|
|
453
|
-
def status(tag, mbox_name, data_item_group)
|
454
|
-
|
465
|
+
def status(tag, mbox_name, data_item_group, &block)
|
466
|
+
make_not_authenticated_response(tag, &block)
|
455
467
|
end
|
456
468
|
imap_command :status
|
457
469
|
|
458
|
-
def append(tag, mbox_name, *opt_args, msg_text)
|
459
|
-
|
470
|
+
def append(tag, mbox_name, *opt_args, msg_text, &block)
|
471
|
+
make_not_authenticated_response(tag, &block)
|
460
472
|
end
|
461
473
|
imap_command :append
|
462
474
|
|
463
|
-
def check(tag)
|
464
|
-
|
475
|
+
def check(tag, &block)
|
476
|
+
make_not_authenticated_response(tag, &block)
|
465
477
|
end
|
466
478
|
imap_command :check
|
467
479
|
|
468
|
-
def close(tag)
|
469
|
-
|
480
|
+
def close(tag, &block)
|
481
|
+
make_not_authenticated_response(tag, &block)
|
470
482
|
end
|
471
483
|
imap_command :close
|
472
484
|
|
473
|
-
def expunge(tag)
|
474
|
-
|
485
|
+
def expunge(tag, &block)
|
486
|
+
make_not_authenticated_response(tag, &block)
|
475
487
|
end
|
476
488
|
imap_command :expunge
|
477
489
|
|
478
|
-
def search(tag, *cond_args, uid: false)
|
479
|
-
|
490
|
+
def search(tag, *cond_args, uid: false, &block)
|
491
|
+
make_not_authenticated_response(tag, &block)
|
480
492
|
end
|
481
493
|
imap_command :search
|
482
494
|
|
483
|
-
def fetch(tag, msg_set, data_item_group, uid: false)
|
484
|
-
|
495
|
+
def fetch(tag, msg_set, data_item_group, uid: false, &block)
|
496
|
+
make_not_authenticated_response(tag, &block)
|
485
497
|
end
|
486
498
|
imap_command :fetch
|
487
499
|
|
488
|
-
def store(tag, msg_set, data_item_name, data_item_value, uid: false)
|
489
|
-
|
500
|
+
def store(tag, msg_set, data_item_name, data_item_value, uid: false, &block)
|
501
|
+
make_not_authenticated_response(tag, &block)
|
490
502
|
end
|
491
503
|
imap_command :store
|
492
504
|
|
493
|
-
def copy(tag, msg_set, mbox_name, uid: false)
|
494
|
-
|
505
|
+
def copy(tag, msg_set, mbox_name, uid: false, &block)
|
506
|
+
make_not_authenticated_response(tag, &block)
|
495
507
|
end
|
496
508
|
imap_command :copy
|
497
509
|
|
498
|
-
def idle(tag, client_input_gets, server_output_write, connection_timer)
|
499
|
-
|
510
|
+
def idle(tag, client_input_gets, server_output_write, connection_timer, &block)
|
511
|
+
make_not_authenticated_response(tag, &block)
|
500
512
|
end
|
501
513
|
imap_command :idle
|
502
514
|
end
|
503
515
|
|
504
516
|
class LogoutDecoder < Decoder
|
505
|
-
def initialize(parent_decoder)
|
517
|
+
def initialize(parent_decoder, logger)
|
518
|
+
super(nil, logger)
|
506
519
|
@parent_decoder = parent_decoder
|
507
|
-
|
508
|
-
|
509
|
-
def next_decoder
|
510
|
-
self
|
520
|
+
@logger.debug("RIMS::Protocol::LogoutDecoder#initialize at #{self}") if @logger.debug?
|
511
521
|
end
|
512
522
|
|
513
523
|
def auth?
|
@@ -519,6 +529,7 @@ module RIMS
|
|
519
529
|
end
|
520
530
|
|
521
531
|
def cleanup
|
532
|
+
@logger.debug("RIMS::Protocol::LogoutDecoder#cleanup at #{self}") if @logger.debug?
|
522
533
|
unless (@parent_decoder.nil?) then
|
523
534
|
@parent_decoder.cleanup
|
524
535
|
@parent_decoder = nil
|
@@ -652,20 +663,64 @@ module RIMS
|
|
652
663
|
class AuthenticatedDecoder < Decoder
|
653
664
|
def authenticate(tag, client_response_input_gets, server_challenge_output_write,
|
654
665
|
auth_type, inline_client_response_data_base64=nil, &block)
|
655
|
-
yield(
|
666
|
+
yield("#{tag} NO duplicated authentication\r\n")
|
656
667
|
end
|
657
668
|
imap_command :authenticate
|
658
669
|
|
659
670
|
def login(tag, username, password, &block)
|
660
|
-
yield(
|
671
|
+
yield("#{tag} NO duplicated login\r\n")
|
661
672
|
end
|
662
673
|
imap_command :login
|
663
674
|
end
|
664
675
|
|
665
676
|
class UserMailboxDecoder < AuthenticatedDecoder
|
677
|
+
class BulkResponse
|
678
|
+
def initialize(limit_count, limit_size)
|
679
|
+
@limit_count = limit_count
|
680
|
+
@limit_size = limit_size
|
681
|
+
@responses = []
|
682
|
+
@size = 0
|
683
|
+
end
|
684
|
+
|
685
|
+
def count
|
686
|
+
@responses.length
|
687
|
+
end
|
688
|
+
|
689
|
+
attr_reader :size
|
690
|
+
|
691
|
+
def add(response)
|
692
|
+
@responses << response
|
693
|
+
@size += response.bytesize
|
694
|
+
self
|
695
|
+
end
|
696
|
+
|
697
|
+
alias << add
|
698
|
+
|
699
|
+
def empty?
|
700
|
+
@responses.empty?
|
701
|
+
end
|
702
|
+
|
703
|
+
def full?
|
704
|
+
count >= @limit_count || size >= @limit_size
|
705
|
+
end
|
706
|
+
|
707
|
+
def flush
|
708
|
+
res = @responses
|
709
|
+
if (count >= @limit_count) then
|
710
|
+
res = [ res.join('') ]
|
711
|
+
end
|
712
|
+
|
713
|
+
@responses = []
|
714
|
+
@size = 0
|
715
|
+
|
716
|
+
res
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
666
720
|
class Engine
|
667
721
|
def initialize(unique_user_id, mail_store, logger,
|
668
722
|
bulk_response_count: 100,
|
723
|
+
bulk_response_size: 1024**2 * 10,
|
669
724
|
read_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS,
|
670
725
|
write_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS,
|
671
726
|
cleanup_write_lock_timeout_seconds: 1,
|
@@ -675,12 +730,14 @@ module RIMS
|
|
675
730
|
@mail_store = mail_store
|
676
731
|
@logger = logger
|
677
732
|
@bulk_response_count = bulk_response_count
|
733
|
+
@bulk_response_size = bulk_response_size
|
678
734
|
@read_lock_timeout_seconds = read_lock_timeout_seconds
|
679
735
|
@write_lock_timeout_seconds = write_lock_timeout_seconds
|
680
736
|
@cleanup_write_lock_timeout_seconds = cleanup_write_lock_timeout_seconds
|
681
737
|
@charset_aliases = charset_aliases
|
682
738
|
@charset_convert_options = charset_convert_options
|
683
739
|
@folders = {}
|
740
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#initialize at #{self}") if @logger.debug?
|
684
741
|
end
|
685
742
|
|
686
743
|
attr_reader :unique_user_id
|
@@ -708,11 +765,13 @@ module RIMS
|
|
708
765
|
end
|
709
766
|
@folders[token] = folder
|
710
767
|
|
768
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#open_folder: #{token}") if @logger.debug?
|
711
769
|
token
|
712
770
|
end
|
713
771
|
private :open_folder
|
714
772
|
|
715
773
|
def close_folder(token)
|
774
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#close_folder: #{token}") if @logger.debug?
|
716
775
|
folder = @folders.delete(token) or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
717
776
|
folder.reload if folder.updated?
|
718
777
|
begin
|
@@ -756,9 +815,10 @@ module RIMS
|
|
756
815
|
end
|
757
816
|
|
758
817
|
def destroy
|
818
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#destroy at #{self}") if @logger.debug?
|
759
819
|
tmp_mail_store = @mail_store
|
760
820
|
ReadWriteLock.write_lock_timeout_detach(@cleanup_write_lock_timeout_seconds, @write_lock_timeout_seconds, logger: @logger) {|timeout_seconds|
|
761
|
-
|
821
|
+
tmp_mail_store.write_synchronize(timeout_seconds) {
|
762
822
|
@logger.info("close mail store: #{@unique_user_id}")
|
763
823
|
tmp_mail_store.close
|
764
824
|
}
|
@@ -828,20 +888,28 @@ module RIMS
|
|
828
888
|
private :imap_command_selected
|
829
889
|
end
|
830
890
|
|
891
|
+
def new_bulk_response
|
892
|
+
BulkResponse.new(@bulk_response_count, @bulk_response_size)
|
893
|
+
end
|
894
|
+
private :new_bulk_response
|
895
|
+
|
831
896
|
def noop(token, tag)
|
832
|
-
res =
|
897
|
+
res = new_bulk_response
|
833
898
|
if (token) then
|
834
899
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
835
900
|
begin
|
836
901
|
@mail_store.read_synchronize(@read_lock_timeout_seconds) {
|
837
|
-
folder.server_response_fetch{|
|
902
|
+
folder.server_response_fetch{|untagged_response|
|
903
|
+
res << untagged_response
|
904
|
+
yield(res.flush) if res.full?
|
905
|
+
}
|
838
906
|
}
|
839
907
|
rescue ReadLockTimeoutError
|
840
908
|
@logger.warn("give up to get folder status because of read-lock timeout over #{@read_lock_timeout_seconds} seconds")
|
841
909
|
end
|
842
910
|
end
|
843
911
|
res << "#{tag} OK NOOP completed\r\n"
|
844
|
-
yield(res)
|
912
|
+
yield(res.flush)
|
845
913
|
end
|
846
914
|
|
847
915
|
def folder_open_msgs(token)
|
@@ -863,20 +931,21 @@ module RIMS
|
|
863
931
|
close_no_response(token)
|
864
932
|
end
|
865
933
|
|
866
|
-
res =
|
934
|
+
res = new_bulk_response
|
867
935
|
new_token = nil
|
868
936
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
869
937
|
|
870
938
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
871
939
|
new_token = open_folder(id)
|
872
|
-
folder_open_msgs(new_token)
|
873
|
-
res <<
|
874
|
-
|
940
|
+
folder_open_msgs(new_token) {|untagged_response|
|
941
|
+
res << untagged_response
|
942
|
+
yield(res.flush) if res.full?
|
943
|
+
}
|
875
944
|
res << "#{tag} OK [READ-WRITE] SELECT completed\r\n"
|
876
945
|
else
|
877
946
|
res << "#{tag} NO not found a mailbox\r\n"
|
878
947
|
end
|
879
|
-
yield(res)
|
948
|
+
yield(res.flush)
|
880
949
|
|
881
950
|
new_token
|
882
951
|
end
|
@@ -887,30 +956,34 @@ module RIMS
|
|
887
956
|
close_no_response(token)
|
888
957
|
end
|
889
958
|
|
890
|
-
res =
|
959
|
+
res = new_bulk_response
|
891
960
|
new_token = nil
|
892
961
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
893
962
|
|
894
963
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
895
964
|
new_token = open_folder(id, read_only: true)
|
896
|
-
folder_open_msgs(new_token)
|
897
|
-
res <<
|
898
|
-
|
965
|
+
folder_open_msgs(new_token) {|untagged_response|
|
966
|
+
res << untagged_response
|
967
|
+
yield(res.flush) if res.full?
|
968
|
+
}
|
899
969
|
res << "#{tag} OK [READ-ONLY] EXAMINE completed\r\n"
|
900
970
|
else
|
901
971
|
res << "#{tag} NO not found a mailbox\r\n"
|
902
972
|
end
|
903
|
-
yield(res)
|
973
|
+
yield(res.flush)
|
904
974
|
|
905
975
|
new_token
|
906
976
|
end
|
907
977
|
imap_command_authenticated :examine
|
908
978
|
|
909
979
|
def create(token, tag, mbox_name)
|
910
|
-
res =
|
980
|
+
res = new_bulk_response
|
911
981
|
if (token) then
|
912
982
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
913
|
-
folder.server_response_fetch{|
|
983
|
+
folder.server_response_fetch{|untagged_response|
|
984
|
+
res << untagged_response
|
985
|
+
yield(res.flush) if res.full?
|
986
|
+
}
|
914
987
|
end
|
915
988
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
916
989
|
if (@mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -919,15 +992,18 @@ module RIMS
|
|
919
992
|
@mail_store.add_mbox(mbox_name_utf8)
|
920
993
|
res << "#{tag} OK CREATE completed\r\n"
|
921
994
|
end
|
922
|
-
yield(res)
|
995
|
+
yield(res.flush)
|
923
996
|
end
|
924
997
|
imap_command_authenticated :create, exclusive: true
|
925
998
|
|
926
999
|
def delete(token, tag, mbox_name)
|
927
|
-
res =
|
1000
|
+
res = new_bulk_response
|
928
1001
|
if (token) then
|
929
1002
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
930
|
-
folder.server_response_fetch{|
|
1003
|
+
folder.server_response_fetch{|untagged_response|
|
1004
|
+
res << untagged_response
|
1005
|
+
yield(res.flush) if res.full?
|
1006
|
+
}
|
931
1007
|
end
|
932
1008
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
933
1009
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -940,38 +1016,47 @@ module RIMS
|
|
940
1016
|
else
|
941
1017
|
res << "#{tag} NO not found a mailbox\r\n"
|
942
1018
|
end
|
943
|
-
yield(res)
|
1019
|
+
yield(res.flush)
|
944
1020
|
end
|
945
1021
|
imap_command_authenticated :delete, exclusive: true
|
946
1022
|
|
947
1023
|
def rename(token, tag, src_name, dst_name)
|
948
|
-
res =
|
1024
|
+
res = new_bulk_response
|
949
1025
|
if (token) then
|
950
1026
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
951
|
-
folder.server_response_fetch{|
|
1027
|
+
folder.server_response_fetch{|untagged_response|
|
1028
|
+
res << untagged_response
|
1029
|
+
yield(res.flush) if res.full?
|
1030
|
+
}
|
952
1031
|
end
|
953
1032
|
src_name_utf8 = Net::IMAP.decode_utf7(src_name)
|
954
1033
|
dst_name_utf8 = Net::IMAP.decode_utf7(dst_name)
|
955
1034
|
unless (id = @mail_store.mbox_id(src_name_utf8)) then
|
956
|
-
|
1035
|
+
res << "#{tag} NO not found a mailbox\r\n"
|
1036
|
+
return yield(res.flush)
|
957
1037
|
end
|
958
1038
|
if (id == @mail_store.mbox_id('INBOX')) then
|
959
|
-
|
1039
|
+
res << "#{tag} NO not rename inbox\r\n"
|
1040
|
+
return yield(res.flush)
|
960
1041
|
end
|
961
1042
|
if (@mail_store.mbox_id(dst_name_utf8)) then
|
962
|
-
|
1043
|
+
res << "#{tag} NO duplicated mailbox\r\n"
|
1044
|
+
return yield(res.flush)
|
963
1045
|
end
|
964
1046
|
@mail_store.rename_mbox(id, dst_name_utf8)
|
965
1047
|
res << "#{tag} OK RENAME completed\r\n"
|
966
|
-
yield(res)
|
1048
|
+
yield(res.flush)
|
967
1049
|
end
|
968
1050
|
imap_command_authenticated :rename, exclusive: true
|
969
1051
|
|
970
1052
|
def subscribe(token, tag, mbox_name)
|
971
|
-
res =
|
1053
|
+
res = new_bulk_response
|
972
1054
|
if (token) then
|
973
1055
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
974
|
-
folder.server_response_fetch{|
|
1056
|
+
folder.server_response_fetch{|untagged_response|
|
1057
|
+
res << untagged_response
|
1058
|
+
yield(res.flush) if res.full?
|
1059
|
+
}
|
975
1060
|
end
|
976
1061
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
977
1062
|
if (@mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -979,15 +1064,18 @@ module RIMS
|
|
979
1064
|
else
|
980
1065
|
res << "#{tag} NO not found a mailbox\r\n"
|
981
1066
|
end
|
982
|
-
yield(res)
|
1067
|
+
yield(res.flush)
|
983
1068
|
end
|
984
1069
|
imap_command_authenticated :subscribe
|
985
1070
|
|
986
1071
|
def unsubscribe(token, tag, mbox_name)
|
987
|
-
res =
|
1072
|
+
res = new_bulk_response
|
988
1073
|
if (token) then
|
989
1074
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
990
|
-
folder.server_response_fetch{|
|
1075
|
+
folder.server_response_fetch{|untagged_response|
|
1076
|
+
res << untagged_response
|
1077
|
+
yield(res.flush) if res.full?
|
1078
|
+
}
|
991
1079
|
end
|
992
1080
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
993
1081
|
if (@mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -995,7 +1083,7 @@ module RIMS
|
|
995
1083
|
else
|
996
1084
|
res << "#{tag} NO not found a mailbox\r\n"
|
997
1085
|
end
|
998
|
-
yield(res)
|
1086
|
+
yield(res.flush)
|
999
1087
|
end
|
1000
1088
|
imap_command_authenticated :unsubscribe
|
1001
1089
|
|
@@ -1024,46 +1112,57 @@ module RIMS
|
|
1024
1112
|
private :list_mbox
|
1025
1113
|
|
1026
1114
|
def list(token, tag, ref_name, mbox_name)
|
1027
|
-
res =
|
1115
|
+
res = new_bulk_response
|
1028
1116
|
if (token) then
|
1029
1117
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1030
|
-
folder.server_response_fetch{|
|
1118
|
+
folder.server_response_fetch{|untagged_response|
|
1119
|
+
res << untagged_response
|
1120
|
+
yield(res.flush) if res.full?
|
1121
|
+
}
|
1031
1122
|
end
|
1032
1123
|
if (mbox_name.empty?) then
|
1033
1124
|
res << "* LIST (\\Noselect) NIL \"\"\r\n"
|
1034
1125
|
else
|
1035
|
-
list_mbox(ref_name, mbox_name)
|
1126
|
+
list_mbox(ref_name, mbox_name) {|mbox_entry|
|
1036
1127
|
res << "* LIST #{mbox_entry}\r\n"
|
1037
|
-
|
1128
|
+
yield(res.flush) if res.full?
|
1129
|
+
}
|
1038
1130
|
end
|
1039
1131
|
res << "#{tag} OK LIST completed\r\n"
|
1040
|
-
yield(res)
|
1132
|
+
yield(res.flush)
|
1041
1133
|
end
|
1042
1134
|
imap_command_authenticated :list
|
1043
1135
|
|
1044
1136
|
def lsub(token, tag, ref_name, mbox_name)
|
1045
|
-
res =
|
1137
|
+
res = new_bulk_response
|
1046
1138
|
if (token) then
|
1047
1139
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1048
|
-
folder.server_response_fetch{|
|
1140
|
+
folder.server_response_fetch{|untagged_response|
|
1141
|
+
res << untagged_response
|
1142
|
+
yield(res.flush) if res.full?
|
1143
|
+
}
|
1049
1144
|
end
|
1050
1145
|
if (mbox_name.empty?) then
|
1051
1146
|
res << "* LSUB (\\Noselect) NIL \"\"\r\n"
|
1052
1147
|
else
|
1053
|
-
list_mbox(ref_name, mbox_name)
|
1148
|
+
list_mbox(ref_name, mbox_name) {|mbox_entry|
|
1054
1149
|
res << "* LSUB #{mbox_entry}\r\n"
|
1055
|
-
|
1150
|
+
yield(res.flush) if res.full?
|
1151
|
+
}
|
1056
1152
|
end
|
1057
1153
|
res << "#{tag} OK LSUB completed\r\n"
|
1058
|
-
yield(res)
|
1154
|
+
yield(res.flush)
|
1059
1155
|
end
|
1060
1156
|
imap_command_authenticated :lsub
|
1061
1157
|
|
1062
1158
|
def status(token, tag, mbox_name, data_item_group)
|
1063
|
-
res =
|
1159
|
+
res = new_bulk_response
|
1064
1160
|
if (token) then
|
1065
1161
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1066
|
-
folder.server_response_fetch{|
|
1162
|
+
folder.server_response_fetch{|untagged_response|
|
1163
|
+
res << untagged_response
|
1164
|
+
yield(res.flush) if res.full?
|
1165
|
+
}
|
1067
1166
|
end
|
1068
1167
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
1069
1168
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -1095,7 +1194,7 @@ module RIMS
|
|
1095
1194
|
else
|
1096
1195
|
res << "#{tag} NO not found a mailbox\r\n"
|
1097
1196
|
end
|
1098
|
-
yield(res)
|
1197
|
+
yield(res.flush)
|
1099
1198
|
end
|
1100
1199
|
imap_command_authenticated :status
|
1101
1200
|
|
@@ -1116,7 +1215,7 @@ module RIMS
|
|
1116
1215
|
private :mailbox_size_server_response_multicast_push
|
1117
1216
|
|
1118
1217
|
def append(token, tag, mbox_name, *opt_args, msg_text)
|
1119
|
-
res =
|
1218
|
+
res = new_bulk_response
|
1120
1219
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
1121
1220
|
if (mbox_id = @mail_store.mbox_id(mbox_name_utf8)) then
|
1122
1221
|
msg_flags = []
|
@@ -1165,30 +1264,39 @@ module RIMS
|
|
1165
1264
|
mailbox_size_server_response_multicast_push(mbox_id)
|
1166
1265
|
if (token) then
|
1167
1266
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1168
|
-
folder.server_response_fetch{|
|
1267
|
+
folder.server_response_fetch{|untagged_response|
|
1268
|
+
res << untagged_response
|
1269
|
+
yield(res.flush) if res.full?
|
1270
|
+
}
|
1169
1271
|
end
|
1170
1272
|
|
1171
1273
|
res << "#{tag} OK [APPENDUID #{mbox_id} #{uid}] APPEND completed\r\n"
|
1172
1274
|
else
|
1173
1275
|
if (token) then
|
1174
1276
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1175
|
-
folder.server_response_fetch{|
|
1277
|
+
folder.server_response_fetch{|untagged_response|
|
1278
|
+
res << untagged_response
|
1279
|
+
yield(res.flush) if res.full?
|
1280
|
+
}
|
1176
1281
|
end
|
1177
1282
|
res << "#{tag} NO [TRYCREATE] not found a mailbox\r\n"
|
1178
1283
|
end
|
1179
|
-
yield(res)
|
1284
|
+
yield(res.flush)
|
1180
1285
|
end
|
1181
1286
|
imap_command_authenticated :append, exclusive: true
|
1182
1287
|
|
1183
1288
|
def check(token, tag)
|
1184
|
-
res =
|
1289
|
+
res = new_bulk_response
|
1185
1290
|
if (token) then
|
1186
1291
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1187
|
-
folder.server_response_fetch{|
|
1292
|
+
folder.server_response_fetch{|untagged_response|
|
1293
|
+
res << untagged_response
|
1294
|
+
yield(res.flush) if res.full?
|
1295
|
+
}
|
1188
1296
|
end
|
1189
1297
|
@mail_store.sync
|
1190
1298
|
res << "#{tag} OK CHECK completed\r\n"
|
1191
|
-
yield(res)
|
1299
|
+
yield(res.flush)
|
1192
1300
|
end
|
1193
1301
|
imap_command_selected :check, exclusive: true
|
1194
1302
|
|
@@ -1216,27 +1324,21 @@ module RIMS
|
|
1216
1324
|
return yield([ "#{tag} NO cannot expunge in read-only mode\r\n" ]) if folder.read_only?
|
1217
1325
|
folder.reload if folder.updated?
|
1218
1326
|
|
1219
|
-
res =
|
1220
|
-
folder.server_response_fetch{|
|
1221
|
-
res <<
|
1222
|
-
|
1223
|
-
|
1224
|
-
res = []
|
1225
|
-
end
|
1226
|
-
}
|
1327
|
+
res = new_bulk_response
|
1328
|
+
folder.server_response_fetch{|untagged_response|
|
1329
|
+
res << untagged_response
|
1330
|
+
yield(res.flush) if res.full?
|
1331
|
+
}
|
1227
1332
|
|
1228
1333
|
folder.expunge_mbox do |msg_num|
|
1229
|
-
|
1230
|
-
res <<
|
1231
|
-
|
1232
|
-
|
1233
|
-
res = []
|
1234
|
-
end
|
1235
|
-
folder.server_response_multicast_push(r)
|
1334
|
+
untagged_response = "* #{msg_num} EXPUNGE\r\n"
|
1335
|
+
res << untagged_response
|
1336
|
+
yield(res.flush) if res.full?
|
1337
|
+
folder.server_response_multicast_push(untagged_response)
|
1236
1338
|
end
|
1237
1339
|
|
1238
1340
|
res << "#{tag} OK EXPUNGE completed\r\n"
|
1239
|
-
yield(res)
|
1341
|
+
yield(res.flush)
|
1240
1342
|
end
|
1241
1343
|
imap_command_selected :expunge, exclusive: true
|
1242
1344
|
|
@@ -1283,13 +1385,10 @@ module RIMS
|
|
1283
1385
|
end
|
1284
1386
|
cond = parser.parse(cond_args)
|
1285
1387
|
|
1286
|
-
res =
|
1287
|
-
folder.server_response_fetch{|
|
1288
|
-
res <<
|
1289
|
-
|
1290
|
-
yield(res)
|
1291
|
-
res = []
|
1292
|
-
end
|
1388
|
+
res = new_bulk_response
|
1389
|
+
folder.server_response_fetch{|untagged_response|
|
1390
|
+
res << untagged_response
|
1391
|
+
yield(res.flush) if res.full?
|
1293
1392
|
}
|
1294
1393
|
|
1295
1394
|
res << '* SEARCH'
|
@@ -1303,10 +1402,7 @@ module RIMS
|
|
1303
1402
|
else
|
1304
1403
|
res << " #{msg.num}"
|
1305
1404
|
end
|
1306
|
-
|
1307
|
-
yield(res)
|
1308
|
-
res = []
|
1309
|
-
end
|
1405
|
+
yield(res.flush) if res.full?
|
1310
1406
|
end
|
1311
1407
|
rescue EncodingError
|
1312
1408
|
@logger.warn("encoding error at the message: uidvalidity(#{folder.mbox_id}) uid(#{msg.uid})")
|
@@ -1317,14 +1413,12 @@ module RIMS
|
|
1317
1413
|
res << "\r\n"
|
1318
1414
|
end
|
1319
1415
|
rescue
|
1320
|
-
|
1321
|
-
yield(res)
|
1322
|
-
res = []
|
1416
|
+
yield(res.flush)
|
1323
1417
|
raise
|
1324
1418
|
end
|
1325
1419
|
|
1326
1420
|
res << "#{tag} OK SEARCH completed\r\n"
|
1327
|
-
yield(res)
|
1421
|
+
yield(res.flush)
|
1328
1422
|
end
|
1329
1423
|
imap_command_selected :search
|
1330
1424
|
|
@@ -1348,25 +1442,19 @@ module RIMS
|
|
1348
1442
|
parser = FetchParser.new(@mail_store, folder, charset_aliases: @charset_aliases)
|
1349
1443
|
fetch = parser.parse(data_item_group)
|
1350
1444
|
|
1351
|
-
res =
|
1352
|
-
folder.server_response_fetch{|
|
1353
|
-
res <<
|
1354
|
-
|
1355
|
-
yield(res)
|
1356
|
-
res = []
|
1357
|
-
end
|
1445
|
+
res = new_bulk_response
|
1446
|
+
folder.server_response_fetch{|untagged_response|
|
1447
|
+
res << untagged_response
|
1448
|
+
yield(res.flush) if res.full?
|
1358
1449
|
}
|
1359
1450
|
|
1360
1451
|
for msg in msg_list
|
1361
1452
|
res << ('* '.b << msg.num.to_s.b << ' FETCH '.b << fetch.call(msg) << "\r\n".b)
|
1362
|
-
|
1363
|
-
yield(res)
|
1364
|
-
res = []
|
1365
|
-
end
|
1453
|
+
yield(res.flush) if res.full?
|
1366
1454
|
end
|
1367
1455
|
|
1368
1456
|
res << "#{tag} OK FETCH completed\r\n"
|
1369
|
-
yield(res)
|
1457
|
+
yield(res.flush)
|
1370
1458
|
end
|
1371
1459
|
imap_command_selected :fetch
|
1372
1460
|
|
@@ -1446,18 +1534,15 @@ module RIMS
|
|
1446
1534
|
end
|
1447
1535
|
end
|
1448
1536
|
|
1449
|
-
res =
|
1450
|
-
folder.server_response_fetch{|
|
1451
|
-
res <<
|
1452
|
-
|
1453
|
-
yield(res)
|
1454
|
-
res = []
|
1455
|
-
end
|
1537
|
+
res = new_bulk_response
|
1538
|
+
folder.server_response_fetch{|untagged_response|
|
1539
|
+
res << untagged_response
|
1540
|
+
yield(res.flush) if res.full?
|
1456
1541
|
}
|
1457
1542
|
|
1458
1543
|
if (is_silent) then
|
1459
1544
|
res << "#{tag} OK STORE completed\r\n"
|
1460
|
-
yield(res)
|
1545
|
+
yield(res.flush)
|
1461
1546
|
else
|
1462
1547
|
for msg in msg_list
|
1463
1548
|
flag_atom_list = nil
|
@@ -1477,17 +1562,14 @@ module RIMS
|
|
1477
1562
|
else
|
1478
1563
|
res << "* #{msg.num} FETCH (FLAGS (#{flag_atom_list.join(' ')}))\r\n"
|
1479
1564
|
end
|
1480
|
-
|
1481
|
-
yield(res)
|
1482
|
-
res = []
|
1483
|
-
end
|
1565
|
+
yield(res.flush) if res.full?
|
1484
1566
|
else
|
1485
1567
|
@logger.warn("not found a message and skipped: uidvalidity(#{folder.mbox_id}) uid(#{msg.uid})")
|
1486
1568
|
end
|
1487
1569
|
end
|
1488
1570
|
|
1489
1571
|
res << "#{tag} OK STORE completed\r\n"
|
1490
|
-
yield(res)
|
1572
|
+
yield(res.flush)
|
1491
1573
|
end
|
1492
1574
|
end
|
1493
1575
|
imap_command_selected :store, exclusive: true
|
@@ -1497,7 +1579,7 @@ module RIMS
|
|
1497
1579
|
folder.should_be_alive
|
1498
1580
|
folder.reload if folder.updated?
|
1499
1581
|
|
1500
|
-
res =
|
1582
|
+
res = new_bulk_response
|
1501
1583
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
1502
1584
|
msg_set = folder.parse_msg_set(msg_set, uid: uid)
|
1503
1585
|
|
@@ -1513,17 +1595,26 @@ module RIMS
|
|
1513
1595
|
|
1514
1596
|
if (msg_list.size > 0) then
|
1515
1597
|
mailbox_size_server_response_multicast_push(mbox_id)
|
1516
|
-
folder.server_response_fetch{|
|
1598
|
+
folder.server_response_fetch{|untagged_response|
|
1599
|
+
res << untagged_response
|
1600
|
+
yield(res.flush) if res.full?
|
1601
|
+
}
|
1517
1602
|
res << "#{tag} OK [COPYUID #{mbox_id} #{src_uids.join(',')} #{dst_uids.join(',')}] COPY completed\r\n"
|
1518
1603
|
else
|
1519
|
-
folder.server_response_fetch{|
|
1604
|
+
folder.server_response_fetch{|untagged_response|
|
1605
|
+
res << untagged_response
|
1606
|
+
yield(res.flush) if res.full?
|
1607
|
+
}
|
1520
1608
|
res << "#{tag} OK COPY completed\r\n"
|
1521
1609
|
end
|
1522
1610
|
else
|
1523
|
-
folder.server_response_fetch{|
|
1611
|
+
folder.server_response_fetch{|untagged_response|
|
1612
|
+
res << untagged_response
|
1613
|
+
yield(res.flush) if res.full?
|
1614
|
+
}
|
1524
1615
|
res << "#{tag} NO [TRYCREATE] not found a mailbox\r\n"
|
1525
1616
|
end
|
1526
|
-
yield(res)
|
1617
|
+
yield(res.flush)
|
1527
1618
|
end
|
1528
1619
|
imap_command_selected :copy, exclusive: true
|
1529
1620
|
|
@@ -1535,12 +1626,15 @@ module RIMS
|
|
1535
1626
|
server_output_write.call([ "+ continue\r\n" ])
|
1536
1627
|
|
1537
1628
|
server_response_thread = Thread.new{
|
1538
|
-
|
1629
|
+
res = new_bulk_response
|
1630
|
+
@logger.info('idle server response thread start...')
|
1539
1631
|
folder.server_response_idle_wait{|server_response_list|
|
1540
|
-
for
|
1541
|
-
@logger.debug("idle server response: #{
|
1632
|
+
for untagged_response in server_response_list
|
1633
|
+
@logger.debug("idle server response: #{untagged_response}") if @logger.debug?
|
1634
|
+
res << untagged_response
|
1635
|
+
server_output_write.call(res.flush) if res.full?
|
1542
1636
|
end
|
1543
|
-
server_output_write.call(
|
1637
|
+
server_output_write.call(res.flush) unless res.empty?
|
1544
1638
|
}
|
1545
1639
|
@logger.info('idle server response thread terminated.')
|
1546
1640
|
}
|
@@ -1553,23 +1647,23 @@ module RIMS
|
|
1553
1647
|
server_response_thread.join
|
1554
1648
|
end
|
1555
1649
|
|
1556
|
-
|
1650
|
+
last_res = []
|
1557
1651
|
if (line) then
|
1558
1652
|
line.chomp!("\n")
|
1559
1653
|
line.chomp!("\r")
|
1560
1654
|
if (line.upcase == "DONE") then
|
1561
1655
|
@logger.info('idle terminated.')
|
1562
|
-
|
1656
|
+
last_res << "#{tag} OK IDLE terminated\r\n"
|
1563
1657
|
else
|
1564
1658
|
@logger.warn('unexpected client response and idle terminated.')
|
1565
1659
|
@logger.debug("unexpected client response data: #{line}") if @logger.debug?
|
1566
|
-
|
1660
|
+
last_res << "#{tag} BAD unexpected client response\r\n"
|
1567
1661
|
end
|
1568
1662
|
else
|
1569
1663
|
@logger.warn('unexpected client connection close and idle terminated.')
|
1570
|
-
|
1664
|
+
last_res << "#{tag} BAD unexpected client connection close\r\n"
|
1571
1665
|
end
|
1572
|
-
yield(
|
1666
|
+
yield(last_res)
|
1573
1667
|
end
|
1574
1668
|
imap_command_selected :idle, exclusive: nil
|
1575
1669
|
end
|
@@ -1579,6 +1673,7 @@ module RIMS
|
|
1579
1673
|
@parent_decoder = parent_decoder
|
1580
1674
|
@engine = engine
|
1581
1675
|
@token = nil
|
1676
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder#initialize at #{self}") if @logger.debug?
|
1582
1677
|
end
|
1583
1678
|
|
1584
1679
|
def auth?
|
@@ -1589,43 +1684,57 @@ module RIMS
|
|
1589
1684
|
! @token.nil?
|
1590
1685
|
end
|
1591
1686
|
|
1592
|
-
|
1687
|
+
# `not_cleanup_parent' keyword argument is defined for MailDeliveryDecoder
|
1688
|
+
def cleanup(not_cleanup_parent: false)
|
1689
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder#cleanup at #{self}") if @logger.debug?
|
1690
|
+
|
1593
1691
|
unless (@engine.nil?) then
|
1594
1692
|
begin
|
1595
1693
|
@engine.cleanup(@token)
|
1596
1694
|
ensure
|
1597
1695
|
@token = nil
|
1598
1696
|
end
|
1697
|
+
end
|
1599
1698
|
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1699
|
+
unless (not_cleanup_parent) then
|
1700
|
+
unless (@engine.nil?) then
|
1701
|
+
begin
|
1702
|
+
@engine.destroy
|
1703
|
+
ensure
|
1704
|
+
@engine = nil
|
1705
|
+
end
|
1604
1706
|
end
|
1605
|
-
end
|
1606
1707
|
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1708
|
+
unless (@parent_decoder.nil?) then
|
1709
|
+
@parent_decoder.cleanup
|
1710
|
+
@parent_decoder = nil
|
1711
|
+
end
|
1610
1712
|
end
|
1611
1713
|
|
1612
1714
|
nil
|
1613
1715
|
end
|
1614
1716
|
|
1615
|
-
def noop(tag
|
1616
|
-
|
1717
|
+
def noop(tag)
|
1718
|
+
ret_val = nil
|
1719
|
+
@engine.noop(@token, tag) {|res|
|
1720
|
+
for response in res
|
1721
|
+
ret_val = yield(response)
|
1722
|
+
end
|
1723
|
+
}
|
1724
|
+
|
1725
|
+
ret_val
|
1617
1726
|
end
|
1618
1727
|
imap_command :noop
|
1619
1728
|
|
1620
|
-
def logout(tag)
|
1729
|
+
def logout(tag, &block)
|
1621
1730
|
if (@token) then
|
1622
1731
|
old_token = @token
|
1623
1732
|
@token = nil
|
1624
1733
|
@engine.cleanup(old_token)
|
1625
1734
|
end
|
1626
1735
|
|
1627
|
-
@next_decoder = LogoutDecoder.new(self)
|
1628
|
-
|
1736
|
+
@next_decoder = LogoutDecoder.new(self, @logger)
|
1737
|
+
make_logout_response(tag, &block)
|
1629
1738
|
end
|
1630
1739
|
imap_command :logout
|
1631
1740
|
|
@@ -1633,7 +1742,9 @@ module RIMS
|
|
1633
1742
|
ret_val = nil
|
1634
1743
|
old_token = @token
|
1635
1744
|
@token = @engine.select(old_token, tag, mbox_name) {|res|
|
1636
|
-
|
1745
|
+
for response in res
|
1746
|
+
ret_val = yield(response)
|
1747
|
+
end
|
1637
1748
|
}
|
1638
1749
|
|
1639
1750
|
ret_val
|
@@ -1644,134 +1755,225 @@ module RIMS
|
|
1644
1755
|
ret_val = nil
|
1645
1756
|
old_token = @token
|
1646
1757
|
@token = @engine.examine(old_token, tag, mbox_name) {|res|
|
1647
|
-
|
1758
|
+
for response in res
|
1759
|
+
ret_val = yield(response)
|
1760
|
+
end
|
1648
1761
|
}
|
1649
1762
|
|
1650
1763
|
ret_val
|
1651
1764
|
end
|
1652
1765
|
imap_command :examine
|
1653
1766
|
|
1654
|
-
def create(tag, mbox_name
|
1655
|
-
|
1767
|
+
def create(tag, mbox_name)
|
1768
|
+
ret_val = nil
|
1769
|
+
@engine.create(@token, tag, mbox_name) {|res|
|
1770
|
+
for response in res
|
1771
|
+
ret_val = yield(response)
|
1772
|
+
end
|
1773
|
+
}
|
1774
|
+
|
1775
|
+
ret_val
|
1656
1776
|
end
|
1657
1777
|
imap_command :create
|
1658
1778
|
|
1659
|
-
def delete(tag, mbox_name
|
1660
|
-
|
1779
|
+
def delete(tag, mbox_name)
|
1780
|
+
ret_val = nil
|
1781
|
+
@engine.delete(@token, tag, mbox_name) {|res|
|
1782
|
+
for response in res
|
1783
|
+
ret_val = yield(response)
|
1784
|
+
end
|
1785
|
+
}
|
1786
|
+
|
1787
|
+
ret_val
|
1661
1788
|
end
|
1662
1789
|
imap_command :delete
|
1663
1790
|
|
1664
|
-
def rename(tag, src_name, dst_name
|
1665
|
-
|
1791
|
+
def rename(tag, src_name, dst_name)
|
1792
|
+
ret_val = nil
|
1793
|
+
@engine.rename(@token, tag, src_name, dst_name) {|res|
|
1794
|
+
for response in res
|
1795
|
+
ret_val = yield(response)
|
1796
|
+
end
|
1797
|
+
}
|
1798
|
+
|
1799
|
+
ret_val
|
1666
1800
|
end
|
1667
1801
|
imap_command :rename
|
1668
1802
|
|
1669
|
-
def subscribe(tag, mbox_name
|
1670
|
-
|
1803
|
+
def subscribe(tag, mbox_name)
|
1804
|
+
ret_val = nil
|
1805
|
+
@engine.subscribe(@token, tag, mbox_name) {|res|
|
1806
|
+
for response in res
|
1807
|
+
ret_val = yield(response)
|
1808
|
+
end
|
1809
|
+
}
|
1810
|
+
|
1811
|
+
ret_val
|
1671
1812
|
end
|
1672
1813
|
imap_command :subscribe
|
1673
1814
|
|
1674
|
-
def unsubscribe(tag, mbox_name
|
1675
|
-
|
1815
|
+
def unsubscribe(tag, mbox_name)
|
1816
|
+
ret_val = nil
|
1817
|
+
@engine.unsubscribe(@token, tag, mbox_name) {|res|
|
1818
|
+
for response in res
|
1819
|
+
ret_val = yield(response)
|
1820
|
+
end
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
ret_val
|
1676
1824
|
end
|
1677
1825
|
imap_command :unsubscribe
|
1678
1826
|
|
1679
|
-
def list(tag, ref_name, mbox_name
|
1680
|
-
|
1827
|
+
def list(tag, ref_name, mbox_name)
|
1828
|
+
ret_val = nil
|
1829
|
+
@engine.list(@token, tag, ref_name, mbox_name) {|res|
|
1830
|
+
for response in res
|
1831
|
+
ret_val = yield(response)
|
1832
|
+
end
|
1833
|
+
}
|
1834
|
+
|
1835
|
+
ret_val
|
1681
1836
|
end
|
1682
1837
|
imap_command :list
|
1683
1838
|
|
1684
|
-
def lsub(tag, ref_name, mbox_name
|
1685
|
-
|
1839
|
+
def lsub(tag, ref_name, mbox_name)
|
1840
|
+
ret_val = nil
|
1841
|
+
@engine.lsub(@token, tag, ref_name, mbox_name) {|res|
|
1842
|
+
for response in res
|
1843
|
+
ret_val = yield(response)
|
1844
|
+
end
|
1845
|
+
}
|
1846
|
+
|
1847
|
+
ret_val
|
1686
1848
|
end
|
1687
1849
|
imap_command :lsub
|
1688
1850
|
|
1689
|
-
def status(tag, mbox_name, data_item_group
|
1690
|
-
|
1851
|
+
def status(tag, mbox_name, data_item_group)
|
1852
|
+
ret_val = nil
|
1853
|
+
@engine.status(@token, tag, mbox_name, data_item_group) {|res|
|
1854
|
+
for response in res
|
1855
|
+
ret_val = yield(response)
|
1856
|
+
end
|
1857
|
+
}
|
1858
|
+
|
1859
|
+
ret_val
|
1691
1860
|
end
|
1692
1861
|
imap_command :status
|
1693
1862
|
|
1694
|
-
def append(tag, mbox_name, *opt_args, msg_text
|
1695
|
-
|
1863
|
+
def append(tag, mbox_name, *opt_args, msg_text)
|
1864
|
+
ret_val = nil
|
1865
|
+
@engine.append(@token, tag, mbox_name, *opt_args, msg_text) {|res|
|
1866
|
+
for response in res
|
1867
|
+
ret_val = yield(response)
|
1868
|
+
end
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
ret_val
|
1696
1872
|
end
|
1697
1873
|
imap_command :append
|
1698
1874
|
|
1699
|
-
def check(tag
|
1700
|
-
|
1875
|
+
def check(tag)
|
1876
|
+
ret_val = nil
|
1877
|
+
@engine.check(@token, tag) {|res|
|
1878
|
+
for response in res
|
1879
|
+
ret_val = yield(response)
|
1880
|
+
end
|
1881
|
+
}
|
1882
|
+
|
1883
|
+
ret_val
|
1701
1884
|
end
|
1702
1885
|
imap_command :check
|
1703
1886
|
|
1704
1887
|
def close(tag, &block)
|
1888
|
+
ret_val = nil
|
1705
1889
|
old_token = @token
|
1706
1890
|
@token = nil
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
res << r
|
1712
|
-
end
|
1713
|
-
}
|
1891
|
+
@engine.close(old_token, tag) {|res|
|
1892
|
+
for response in res
|
1893
|
+
ret_val = yield(response)
|
1894
|
+
end
|
1714
1895
|
}
|
1896
|
+
|
1897
|
+
ret_val
|
1715
1898
|
end
|
1716
1899
|
imap_command :close
|
1717
1900
|
|
1718
1901
|
def expunge(tag)
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
}
|
1902
|
+
ret_val = nil
|
1903
|
+
@engine.expunge(@token, tag) {|res|
|
1904
|
+
for response in res
|
1905
|
+
ret_val = yield(response)
|
1906
|
+
end
|
1725
1907
|
}
|
1908
|
+
|
1909
|
+
ret_val
|
1726
1910
|
end
|
1727
1911
|
imap_command :expunge
|
1728
1912
|
|
1729
1913
|
def search(tag, *cond_args, uid: false)
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1735
|
-
}
|
1914
|
+
ret_val = nil
|
1915
|
+
@engine.search(@token, tag, *cond_args, uid: uid) {|res|
|
1916
|
+
for response in res
|
1917
|
+
ret_val = yield(response)
|
1918
|
+
end
|
1736
1919
|
}
|
1920
|
+
|
1921
|
+
ret_val
|
1737
1922
|
end
|
1738
1923
|
imap_command :search
|
1739
1924
|
|
1740
1925
|
def fetch(tag, msg_set, data_item_group, uid: false)
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
}
|
1926
|
+
ret_val = nil
|
1927
|
+
@engine.fetch(@token, tag, msg_set, data_item_group, uid: uid) {|res|
|
1928
|
+
for response in res
|
1929
|
+
ret_val = yield(response)
|
1930
|
+
end
|
1747
1931
|
}
|
1932
|
+
|
1933
|
+
ret_val
|
1748
1934
|
end
|
1749
1935
|
imap_command :fetch
|
1750
1936
|
|
1751
1937
|
def store(tag, msg_set, data_item_name, data_item_value, uid: false)
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
}
|
1938
|
+
ret_val = nil
|
1939
|
+
@engine.store(@token, tag, msg_set, data_item_name, data_item_value, uid: uid) {|res|
|
1940
|
+
for response in res
|
1941
|
+
ret_val = yield(response)
|
1942
|
+
end
|
1758
1943
|
}
|
1944
|
+
|
1945
|
+
ret_val
|
1759
1946
|
end
|
1760
1947
|
imap_command :store
|
1761
1948
|
|
1762
1949
|
def copy(tag, msg_set, mbox_name, uid: false, &block)
|
1763
|
-
|
1950
|
+
ret_val = nil
|
1951
|
+
@engine.copy(@token, tag, msg_set, mbox_name, uid: uid) {|res|
|
1952
|
+
for response in res
|
1953
|
+
ret_val = yield(response)
|
1954
|
+
end
|
1955
|
+
}
|
1956
|
+
|
1957
|
+
ret_val
|
1764
1958
|
end
|
1765
1959
|
imap_command :copy
|
1766
1960
|
|
1767
1961
|
def idle(tag, client_input_gets, server_output_write, connection_timer, &block)
|
1768
|
-
|
1962
|
+
ret_val = nil
|
1963
|
+
@engine.idle(@token, tag, client_input_gets, server_output_write, connection_timer) {|res|
|
1964
|
+
for response in res
|
1965
|
+
ret_val = yield(response)
|
1966
|
+
end
|
1967
|
+
}
|
1968
|
+
|
1969
|
+
ret_val
|
1769
1970
|
end
|
1770
1971
|
imap_command :idle
|
1771
1972
|
end
|
1772
1973
|
|
1773
1974
|
# alias
|
1774
|
-
Decoder::Engine
|
1975
|
+
Decoder::Engine = UserMailboxDecoder::Engine
|
1976
|
+
Decoder::BulkResponse = UserMailboxDecoder::BulkResponse
|
1775
1977
|
|
1776
1978
|
def Decoder.encode_delivery_target_mailbox(username, mbox_name)
|
1777
1979
|
"b64user-mbox #{Protocol.encode_base64(username)} #{mbox_name}"
|
@@ -1793,6 +1995,7 @@ module RIMS
|
|
1793
1995
|
@auth = auth
|
1794
1996
|
@last_user_cache_key_username = nil
|
1795
1997
|
@last_user_cache_value_engine = nil
|
1998
|
+
@logger.debug("RIMS::Protocol::MailDeliveryDecoder#initialize at #{self}") if @logger.debug?
|
1796
1999
|
end
|
1797
2000
|
|
1798
2001
|
def engine_cached?(username)
|
@@ -1840,6 +2043,8 @@ module RIMS
|
|
1840
2043
|
end
|
1841
2044
|
|
1842
2045
|
def cleanup
|
2046
|
+
@logger.debug("RIMS::Protocol::MailDeliveryDecoder#cleanup at #{self}") if @logger.debug?
|
2047
|
+
|
1843
2048
|
release_engine_cache
|
1844
2049
|
@drb_services = nil unless @drb_services.nil?
|
1845
2050
|
@auth = nil unless @auth.nil?
|
@@ -1852,9 +2057,9 @@ module RIMS
|
|
1852
2057
|
nil
|
1853
2058
|
end
|
1854
2059
|
|
1855
|
-
def logout(tag)
|
1856
|
-
@next_decoder = LogoutDecoder.new(self)
|
1857
|
-
|
2060
|
+
def logout(tag, &block)
|
2061
|
+
@next_decoder = LogoutDecoder.new(self, @logger)
|
2062
|
+
make_logout_response(tag, &block)
|
1858
2063
|
end
|
1859
2064
|
imap_command :logout
|
1860
2065
|
|
@@ -1862,85 +2067,87 @@ module RIMS
|
|
1862
2067
|
private :standard_capability
|
1863
2068
|
|
1864
2069
|
def capability(tag)
|
1865
|
-
standard_capability(tag) {|
|
1866
|
-
|
1867
|
-
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
end
|
1872
|
-
}
|
2070
|
+
standard_capability(tag) {|response|
|
2071
|
+
if (response.start_with? '* CAPABILITY ') then
|
2072
|
+
yield(response.strip + " X-RIMS-MAIL-DELIVERY-USER\r\n")
|
2073
|
+
else
|
2074
|
+
yield(response)
|
2075
|
+
end
|
1873
2076
|
}
|
1874
2077
|
end
|
1875
2078
|
imap_command :capability
|
1876
2079
|
|
1877
2080
|
def make_not_allowed_command_response(tag)
|
1878
|
-
|
2081
|
+
yield("#{tag} NO not allowed command on mail delivery user\r\n")
|
1879
2082
|
end
|
1880
2083
|
private :make_not_allowed_command_response
|
1881
2084
|
|
1882
|
-
def select(tag, mbox_name)
|
1883
|
-
|
2085
|
+
def select(tag, mbox_name, &block)
|
2086
|
+
make_not_allowed_command_response(tag, &block)
|
1884
2087
|
end
|
1885
2088
|
imap_command :select
|
1886
2089
|
|
1887
|
-
def examine(tag, mbox_name)
|
1888
|
-
|
2090
|
+
def examine(tag, mbox_name, &block)
|
2091
|
+
make_not_allowed_command_response(tag, &block)
|
1889
2092
|
end
|
1890
2093
|
imap_command :examine
|
1891
2094
|
|
1892
|
-
def create(tag, mbox_name)
|
1893
|
-
|
2095
|
+
def create(tag, mbox_name, &block)
|
2096
|
+
make_not_allowed_command_response(tag, &block)
|
1894
2097
|
end
|
1895
2098
|
imap_command :create
|
1896
2099
|
|
1897
|
-
def delete(tag, mbox_name)
|
1898
|
-
|
2100
|
+
def delete(tag, mbox_name, &block)
|
2101
|
+
make_not_allowed_command_response(tag, &block)
|
1899
2102
|
end
|
1900
2103
|
imap_command :delete
|
1901
2104
|
|
1902
|
-
def rename(tag, src_name, dst_name)
|
1903
|
-
|
2105
|
+
def rename(tag, src_name, dst_name, &block)
|
2106
|
+
make_not_allowed_command_response(tag, &block)
|
1904
2107
|
end
|
1905
2108
|
imap_command :rename
|
1906
2109
|
|
1907
|
-
def subscribe(tag, mbox_name)
|
1908
|
-
|
2110
|
+
def subscribe(tag, mbox_name, &block)
|
2111
|
+
make_not_allowed_command_response(tag, &block)
|
1909
2112
|
end
|
1910
2113
|
imap_command :subscribe
|
1911
2114
|
|
1912
|
-
def unsubscribe(tag, mbox_name)
|
1913
|
-
|
2115
|
+
def unsubscribe(tag, mbox_name, &block)
|
2116
|
+
make_not_allowed_command_response(tag, &block)
|
1914
2117
|
end
|
1915
2118
|
imap_command :unsubscribe
|
1916
2119
|
|
1917
|
-
def list(tag, ref_name, mbox_name)
|
1918
|
-
|
2120
|
+
def list(tag, ref_name, mbox_name, &block)
|
2121
|
+
make_not_allowed_command_response(tag, &block)
|
1919
2122
|
end
|
1920
2123
|
imap_command :list
|
1921
2124
|
|
1922
|
-
def lsub(tag, ref_name, mbox_name)
|
1923
|
-
|
2125
|
+
def lsub(tag, ref_name, mbox_name, &block)
|
2126
|
+
make_not_allowed_command_response(tag, &block)
|
1924
2127
|
end
|
1925
2128
|
imap_command :lsub
|
1926
2129
|
|
1927
|
-
def status(tag, mbox_name, data_item_group)
|
1928
|
-
|
2130
|
+
def status(tag, mbox_name, data_item_group, &block)
|
2131
|
+
make_not_allowed_command_response(tag, &block)
|
1929
2132
|
end
|
1930
2133
|
imap_command :status
|
1931
2134
|
|
1932
|
-
def deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine
|
2135
|
+
def deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine)
|
1933
2136
|
user_decoder = UserMailboxDecoder.new(self, engine, @auth, @logger)
|
1934
|
-
|
1935
|
-
|
2137
|
+
begin
|
2138
|
+
last_response = nil
|
2139
|
+
user_decoder.append(tag, mbox_name, *opt_args, msg_text) {|response|
|
2140
|
+
last_response = response
|
2141
|
+
yield(response)
|
2142
|
+
}
|
2143
|
+
if (last_response.split(' ', 3)[1] == 'OK') then
|
1936
2144
|
@logger.info("message delivery: successed to deliver #{msg_text.bytesize} octets message.")
|
1937
2145
|
else
|
1938
2146
|
@logger.info("message delivery: failed to deliver message.")
|
1939
2147
|
end
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
}
|
2148
|
+
ensure
|
2149
|
+
user_decoder.cleanup(not_cleanup_parent: true)
|
2150
|
+
end
|
1944
2151
|
end
|
1945
2152
|
private :deliver_to_user
|
1946
2153
|
|
@@ -1950,62 +2157,65 @@ module RIMS
|
|
1950
2157
|
|
1951
2158
|
if (@auth.user? username) then
|
1952
2159
|
if (engine_cached? username) then
|
1953
|
-
res = []
|
1954
2160
|
engine = engine_cache(username)
|
1955
|
-
deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine
|
2161
|
+
deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine) {|response|
|
2162
|
+
yield(response)
|
2163
|
+
}
|
1956
2164
|
else
|
1957
|
-
|
1958
|
-
|
1959
|
-
|
2165
|
+
engine = store_engine_cache(username) {
|
2166
|
+
self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|untagged_response|
|
2167
|
+
yield(untagged_response)
|
2168
|
+
yield(:flush)
|
1960
2169
|
}
|
1961
|
-
|
2170
|
+
}
|
2171
|
+
deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine) {|response|
|
2172
|
+
yield(response)
|
1962
2173
|
}
|
1963
2174
|
end
|
1964
|
-
yield(res)
|
1965
2175
|
else
|
1966
2176
|
@logger.info('message delivery: not found a user.')
|
1967
|
-
yield(
|
2177
|
+
yield("#{tag} NO not found a user and couldn't deliver a message to the user's mailbox\r\n")
|
1968
2178
|
end
|
1969
2179
|
end
|
1970
2180
|
imap_command :append
|
1971
2181
|
|
1972
|
-
def check(tag)
|
1973
|
-
|
2182
|
+
def check(tag, &block)
|
2183
|
+
make_not_allowed_command_response(tag, &block)
|
1974
2184
|
end
|
1975
2185
|
imap_command :check
|
1976
2186
|
|
1977
|
-
def close(tag)
|
1978
|
-
|
2187
|
+
def close(tag, &block)
|
2188
|
+
make_not_allowed_command_response(tag, &block)
|
1979
2189
|
end
|
1980
2190
|
imap_command :close
|
1981
2191
|
|
1982
|
-
def expunge(tag)
|
1983
|
-
|
2192
|
+
def expunge(tag, &block)
|
2193
|
+
make_not_allowed_command_response(tag, &block)
|
1984
2194
|
end
|
1985
2195
|
imap_command :expunge
|
1986
2196
|
|
1987
|
-
def search(tag, *cond_args, uid: false)
|
1988
|
-
|
2197
|
+
def search(tag, *cond_args, uid: false, &block)
|
2198
|
+
make_not_allowed_command_response(tag, &block)
|
1989
2199
|
end
|
1990
2200
|
imap_command :search
|
1991
2201
|
|
1992
|
-
def fetch(tag, msg_set, data_item_group, uid: false)
|
1993
|
-
|
2202
|
+
def fetch(tag, msg_set, data_item_group, uid: false, &block)
|
2203
|
+
make_not_allowed_command_response(tag, &block)
|
1994
2204
|
end
|
1995
2205
|
imap_command :fetch
|
1996
2206
|
|
1997
|
-
def store(tag, msg_set, data_item_name, data_item_value, uid: false)
|
1998
|
-
|
2207
|
+
def store(tag, msg_set, data_item_name, data_item_value, uid: false, &block)
|
2208
|
+
make_not_allowed_command_response(tag, &block)
|
1999
2209
|
end
|
2000
2210
|
imap_command :store
|
2001
2211
|
|
2002
|
-
def copy(tag, msg_set, mbox_name, uid: false)
|
2003
|
-
|
2212
|
+
def copy(tag, msg_set, mbox_name, uid: false, &block)
|
2213
|
+
make_not_allowed_command_response(tag, &block)
|
2004
2214
|
end
|
2005
2215
|
imap_command :copy
|
2006
2216
|
|
2007
|
-
def idle(tag, client_input_gets, server_output_write, connection_timer)
|
2008
|
-
|
2217
|
+
def idle(tag, client_input_gets, server_output_write, connection_timer, &block)
|
2218
|
+
make_not_allowed_command_response(tag, &block)
|
2009
2219
|
end
|
2010
2220
|
imap_command :idle
|
2011
2221
|
end
|