rims 0.2.8 → 0.2.9
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.
- 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
|