rims 0.2.6 → 0.3.1
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/.gitignore +3 -0
- data/CHANGELOG.md +97 -0
- data/ChangeLog +49 -0
- data/Rakefile +8 -4
- data/lib/rims.rb +31 -29
- data/lib/rims/channel.rb +35 -10
- data/lib/rims/cmd.rb +109 -3
- data/lib/rims/error.rb +15 -0
- data/lib/rims/protocol.rb +28 -7
- data/lib/rims/protocol/decoder.rb +727 -457
- data/lib/rims/protocol/parser.rb +190 -82
- data/lib/rims/service.rb +172 -39
- data/lib/rims/test.rb +31 -20
- data/lib/rims/version.rb +1 -1
- data/load_test/Rakefile +3 -1
- data/rims.gemspec +14 -13
- data/test/cmd/test_command.rb +21 -1
- data/test/test_channel.rb +2 -1
- data/test/test_error.rb +33 -1
- data/test/test_lock.rb +4 -4
- data/test/test_passwd.rb +1 -1
- data/test/test_protocol_decoder.rb +555 -41
- data/test/test_protocol_fetch.rb +14 -10
- data/test/test_protocol_request.rb +305 -280
- data/test/test_protocol_search.rb +771 -893
- data/test/test_service.rb +165 -0
- metadata +22 -7
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
|
|
data/lib/rims/protocol.rb
CHANGED
@@ -4,6 +4,27 @@ module RIMS
|
|
4
4
|
class ProtocolError < Error
|
5
5
|
end
|
6
6
|
|
7
|
+
class ReadSizeError < ProtocolError
|
8
|
+
end
|
9
|
+
|
10
|
+
class LineTooLongError < ReadSizeError
|
11
|
+
end
|
12
|
+
|
13
|
+
class RecoverableReadSizeError < ReadSizeError
|
14
|
+
def initialize(message=nil, command_tag=nil, **kw_args)
|
15
|
+
super(message, **kw_args)
|
16
|
+
@command_tag = command_tag
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :command_tag
|
20
|
+
end
|
21
|
+
|
22
|
+
class LiteralSizeTooLargeError < RecoverableReadSizeError
|
23
|
+
end
|
24
|
+
|
25
|
+
class CommandSizeTooLargeError < RecoverableReadSizeError
|
26
|
+
end
|
27
|
+
|
7
28
|
class SyntaxError < ProtocolError
|
8
29
|
end
|
9
30
|
|
@@ -57,14 +78,14 @@ module RIMS
|
|
57
78
|
end
|
58
79
|
module_function :decode_base64
|
59
80
|
|
60
|
-
autoload :FetchBody,
|
61
|
-
autoload :RequestReader,
|
81
|
+
autoload :FetchBody, 'rims/protocol/parser'
|
82
|
+
autoload :RequestReader, 'rims/protocol/parser'
|
62
83
|
autoload :AuthenticationReader, 'rims/protocol/parser'
|
63
|
-
autoload :SearchParser,
|
64
|
-
autoload :FetchParser,
|
65
|
-
autoload :ConnectionLimits,
|
66
|
-
autoload :ConnectionTimer,
|
67
|
-
autoload :Decoder,
|
84
|
+
autoload :SearchParser, 'rims/protocol/parser'
|
85
|
+
autoload :FetchParser, 'rims/protocol/parser'
|
86
|
+
autoload :ConnectionLimits, 'rims/protocol/connection'
|
87
|
+
autoload :ConnectionTimer, 'rims/protocol/connection'
|
88
|
+
autoload :Decoder, 'rims/protocol/decoder'
|
68
89
|
|
69
90
|
def body(symbol: nil, option: nil, section: nil, section_list: nil, partial_origin: nil, partial_size: nil)
|
70
91
|
FetchBody.new(symbol, option, section, section_list, partial_origin, partial_size)
|
@@ -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,125 +22,174 @@ 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
|
-
|
26
|
-
|
27
|
-
last_line = nil
|
28
|
-
for data in res
|
40
|
+
output_write = lambda{|data|
|
41
|
+
begin
|
29
42
|
if (data == :flush) then
|
30
43
|
output.flush
|
31
44
|
else
|
32
45
|
logger.debug("response data: #{Protocol.io_data_log(data)}") if logger.debug?
|
33
46
|
output << data
|
34
|
-
last_line = data
|
35
47
|
end
|
48
|
+
rescue
|
49
|
+
logger.error('response write error.')
|
50
|
+
logging_error_chain($!, logger)
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
}
|
54
|
+
server_output_write = lambda{|res|
|
55
|
+
for data in res
|
56
|
+
output_write.call(data)
|
36
57
|
end
|
37
58
|
output.flush
|
38
59
|
|
39
|
-
|
60
|
+
nil
|
40
61
|
}
|
41
|
-
response_write =
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
62
|
+
response_write = lambda{|response|
|
63
|
+
output_write.call(response)
|
64
|
+
output.flush
|
65
|
+
logger.info("server response: #{response.strip}")
|
66
|
+
}
|
67
|
+
apply_imap_command = lambda{|name, *args, uid: false|
|
68
|
+
last_line = nil
|
69
|
+
if (uid) then
|
70
|
+
decoder.__send__(name, *args, uid: true) {|response|
|
71
|
+
output_write.call(response)
|
72
|
+
last_line = response if (response.is_a? String)
|
73
|
+
}
|
74
|
+
else
|
75
|
+
decoder.__send__(name, *args) {|response|
|
76
|
+
output_write.call(response)
|
77
|
+
last_line = response if (response.is_a? String)
|
78
|
+
}
|
49
79
|
end
|
80
|
+
output.flush
|
81
|
+
logger.info("server response: #{last_line.strip}") if last_line
|
50
82
|
}
|
51
83
|
|
52
|
-
|
84
|
+
apply_imap_command.call(:ok_greeting)
|
53
85
|
|
54
86
|
conn_timer = ConnectionTimer.new(limits, input.to_io)
|
55
|
-
request_reader =
|
87
|
+
request_reader = decoder.make_requrest_reader(input, output)
|
88
|
+
input_gets = request_reader.method(:gets)
|
56
89
|
|
57
|
-
|
58
|
-
conn_timer.
|
90
|
+
begin
|
91
|
+
until (conn_timer.command_wait_timeout?)
|
92
|
+
conn_timer.command_wait or break
|
59
93
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
logger.error(
|
94
|
+
begin
|
95
|
+
atom_list = request_reader.read_command
|
96
|
+
rescue LineTooLongError
|
97
|
+
raise
|
98
|
+
rescue LiteralSizeTooLargeError
|
99
|
+
logger.error('literal size too large error.')
|
100
|
+
logging_error_chain($!, logger)
|
101
|
+
response_write.call("#{request_reader.command_tag || '*'} BAD literal size too large\r\n")
|
102
|
+
next
|
103
|
+
rescue CommandSizeTooLargeError
|
104
|
+
logger.error('command size too large error.')
|
105
|
+
logging_error_chain($!, logger)
|
106
|
+
response_write.call("#{request_reader.command_tag || '*'} BAD command size too large\r\n")
|
107
|
+
next
|
108
|
+
rescue
|
109
|
+
logger.error('invalid client command.')
|
110
|
+
logging_error_chain($!, logger)
|
111
|
+
response_write.call("#{request_reader.command_tag || '*'} BAD client command syntax error\r\n")
|
112
|
+
next
|
66
113
|
end
|
67
|
-
response_write.call([ "* BAD client command syntax error\r\n" ])
|
68
|
-
next
|
69
|
-
end
|
70
114
|
|
71
|
-
|
115
|
+
break unless atom_list
|
72
116
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
log_opt_args = opt_args.dup
|
80
|
-
log_opt_args[-1] = '********'
|
81
|
-
when 'AUTHENTICATE'
|
82
|
-
if (opt_args[1]) then
|
117
|
+
tag, command, *opt_args = atom_list
|
118
|
+
normalized_command = imap_command_normalize(command)
|
119
|
+
logger.info("client command: #{tag} #{command}")
|
120
|
+
if (logger.debug?) then
|
121
|
+
case (normalized_command)
|
122
|
+
when 'LOGIN'
|
83
123
|
log_opt_args = opt_args.dup
|
84
|
-
log_opt_args[1] = '********'
|
124
|
+
log_opt_args[-1] = '********'
|
125
|
+
when 'AUTHENTICATE'
|
126
|
+
if (opt_args[1]) then
|
127
|
+
log_opt_args = opt_args.dup
|
128
|
+
log_opt_args[1] = '********'
|
129
|
+
else
|
130
|
+
log_opt_args = opt_args
|
131
|
+
end
|
85
132
|
else
|
86
133
|
log_opt_args = opt_args
|
87
134
|
end
|
88
|
-
|
89
|
-
log_opt_args = opt_args
|
135
|
+
logger.debug("client command parameter: #{log_opt_args.inspect}")
|
90
136
|
end
|
91
|
-
logger.debug("client command parameter: #{log_opt_args.inspect}")
|
92
|
-
end
|
93
137
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
138
|
+
begin
|
139
|
+
if (name = IMAP_CMDs[normalized_command]) then
|
140
|
+
case (name)
|
141
|
+
when :uid
|
142
|
+
unless (opt_args.empty?) then
|
143
|
+
uid_command, *uid_args = opt_args
|
144
|
+
logger.info("uid command: #{uid_command}")
|
145
|
+
logger.debug("uid parameter: #{uid_args}") if logger.debug?
|
146
|
+
if (uid_name = UID_CMDs[imap_command_normalize(uid_command)]) then
|
147
|
+
apply_imap_command.call(uid_name, tag, *uid_args, uid: true)
|
148
|
+
else
|
149
|
+
logger.error("unknown uid command: #{uid_command}")
|
150
|
+
response_write.call("#{tag} BAD unknown uid command\r\n")
|
151
|
+
end
|
104
152
|
else
|
105
|
-
logger.error(
|
106
|
-
response_write.call(
|
153
|
+
logger.error('empty uid parameter.')
|
154
|
+
response_write.call("#{tag} BAD empty uid parameter\r\n")
|
107
155
|
end
|
156
|
+
when :authenticate
|
157
|
+
apply_imap_command.call(:authenticate, tag, input_gets, server_output_write, *opt_args)
|
158
|
+
when :idle
|
159
|
+
apply_imap_command.call(:idle, tag, input_gets, server_output_write, conn_timer, *opt_args)
|
108
160
|
else
|
109
|
-
|
110
|
-
response_write.call([ "#{tag} BAD empty uid parameter\r\n" ])
|
161
|
+
apply_imap_command.call(name, tag, *opt_args)
|
111
162
|
end
|
112
|
-
when :authenticate
|
113
|
-
decoder.authenticate(tag, input_gets, output_write, *opt_args) {|res| response_write.call(res) }
|
114
|
-
when :idle
|
115
|
-
decoder.idle(tag, input_gets, output_write, conn_timer, *opt_args) {|res| response_write.call(res) }
|
116
163
|
else
|
117
|
-
|
164
|
+
logger.error("unknown command: #{command}")
|
165
|
+
response_write.call("#{tag} BAD unknown command\r\n")
|
118
166
|
end
|
119
|
-
|
120
|
-
|
121
|
-
|
167
|
+
rescue LineTooLongError
|
168
|
+
raise
|
169
|
+
rescue
|
170
|
+
logger.error('unexpected error.')
|
171
|
+
logging_error_chain($!, logger)
|
172
|
+
response_write.call("#{tag} BAD unexpected error\r\n")
|
122
173
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
logger.error(exception)
|
174
|
+
|
175
|
+
if (normalized_command == 'LOGOUT') then
|
176
|
+
break
|
127
177
|
end
|
128
|
-
response_write.call([ "#{tag} BAD unexpected error\r\n" ])
|
129
|
-
end
|
130
178
|
|
131
|
-
|
132
|
-
break
|
179
|
+
decoder = decoder.next_decoder
|
133
180
|
end
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
181
|
+
rescue LineTooLongError
|
182
|
+
logger.error('line too long error.')
|
183
|
+
logging_error_chain($!, logger)
|
184
|
+
response_write.call("* BAD line too long\r\n")
|
185
|
+
response_write.call("* BYE server autologout: connection terminated\r\n")
|
186
|
+
else
|
187
|
+
if (conn_timer.command_wait_timeout?) then
|
188
|
+
if (limits.command_wait_timeout_seconds > 0) then
|
189
|
+
response_write.call("* BYE server autologout: idle for too long\r\n")
|
190
|
+
else
|
191
|
+
response_write.call("* BYE server autologout: shutdown\r\n")
|
192
|
+
end
|
143
193
|
end
|
144
194
|
end
|
145
195
|
|
@@ -157,25 +207,10 @@ module RIMS
|
|
157
207
|
|
158
208
|
attr_reader :next_decoder
|
159
209
|
|
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
|
-
}
|
210
|
+
def logging_error_chain(error)
|
211
|
+
self.class.logging_error_chain(error, @logger)
|
177
212
|
end
|
178
|
-
private :
|
213
|
+
private :logging_error_chain
|
179
214
|
|
180
215
|
def guard_error(imap_command, tag, *args, **kw_args, &block)
|
181
216
|
begin
|
@@ -184,21 +219,21 @@ module RIMS
|
|
184
219
|
else
|
185
220
|
__send__(imap_command, tag, *args, **kw_args, &block)
|
186
221
|
end
|
222
|
+
rescue LineTooLongError
|
223
|
+
raise
|
187
224
|
rescue SyntaxError
|
188
225
|
@logger.error('client command syntax error.')
|
189
|
-
|
190
|
-
yield(
|
226
|
+
logging_error_chain($!)
|
227
|
+
yield("#{tag} BAD client command syntax error\r\n")
|
191
228
|
rescue ArgumentError
|
192
229
|
@logger.error('invalid command parameter.')
|
193
|
-
|
194
|
-
yield(
|
230
|
+
logging_error_chain($!)
|
231
|
+
yield("#{tag} BAD invalid command parameter\r\n")
|
195
232
|
rescue
|
196
233
|
raise if ($!.class.name =~ /AssertionFailedError/)
|
197
234
|
@logger.error('internal server error.')
|
198
|
-
|
199
|
-
|
200
|
-
end
|
201
|
-
yield([ "#{tag} BAD internal server error\r\n" ])
|
235
|
+
logging_error_chain($!)
|
236
|
+
yield("#{tag} BAD internal server error\r\n")
|
202
237
|
end
|
203
238
|
end
|
204
239
|
private :guard_error
|
@@ -256,8 +291,7 @@ module RIMS
|
|
256
291
|
end
|
257
292
|
private :imap_command
|
258
293
|
|
259
|
-
def make_engine_and_recovery_if_needed(drb_services, username,
|
260
|
-
logger: Logger.new(STDOUT))
|
294
|
+
def make_engine_and_recovery_if_needed(drb_services, username, logger: Logger.new(STDOUT))
|
261
295
|
unique_user_id = Authentication.unique_user_id(username)
|
262
296
|
logger.debug("unique user ID: #{username} -> #{unique_user_id}") if logger.debug?
|
263
297
|
|
@@ -265,7 +299,7 @@ module RIMS
|
|
265
299
|
engine = drb_services[:engine, unique_user_id]
|
266
300
|
|
267
301
|
begin
|
268
|
-
engine.recovery_if_needed(username) {|
|
302
|
+
engine.recovery_if_needed(username) {|response| yield(response) }
|
269
303
|
rescue
|
270
304
|
engine.destroy
|
271
305
|
raise
|
@@ -276,14 +310,13 @@ module RIMS
|
|
276
310
|
end
|
277
311
|
|
278
312
|
def make_logout_response(tag)
|
279
|
-
|
280
|
-
|
281
|
-
]
|
313
|
+
yield("* BYE server logout\r\n")
|
314
|
+
yield("#{tag} OK LOGOUT completed\r\n")
|
282
315
|
end
|
283
316
|
private :make_logout_response
|
284
317
|
|
285
318
|
def ok_greeting
|
286
|
-
yield(
|
319
|
+
yield("* OK RIMS v#{VERSION} IMAP4rev1 service ready.\r\n")
|
287
320
|
end
|
288
321
|
|
289
322
|
# common IMAP command
|
@@ -292,10 +325,8 @@ module RIMS
|
|
292
325
|
def capability(tag)
|
293
326
|
capability_list = %w[ IMAP4rev1 UIDPLUS IDLE ]
|
294
327
|
capability_list += @auth.capability.map{|auth_capability| "AUTH=#{auth_capability}" }
|
295
|
-
|
296
|
-
|
297
|
-
res << "#{tag} OK CAPABILITY completed\r\n"
|
298
|
-
yield(res)
|
328
|
+
yield("* CAPABILITY #{capability_list.join(' ')}\r\n")
|
329
|
+
yield("#{tag} OK CAPABILITY completed\r\n")
|
299
330
|
end
|
300
331
|
imap_command :capability
|
301
332
|
end
|
@@ -326,10 +357,24 @@ module RIMS
|
|
326
357
|
end
|
327
358
|
|
328
359
|
def initialize(drb_services, auth, logger,
|
329
|
-
mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user
|
360
|
+
mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user,
|
361
|
+
line_length_limit: Service::DEFAULT_CONFIG.protocol_line_length_limit,
|
362
|
+
literal_size_limit: Service::DEFAULT_CONFIG.protocol_literal_size_limit,
|
363
|
+
command_size_limit: Service::DEFAULT_CONFIG.protocol_command_size_limit)
|
330
364
|
super(auth, logger)
|
331
365
|
@drb_services = drb_services
|
332
366
|
@mail_delivery_user = mail_delivery_user
|
367
|
+
@line_length_limit = line_length_limit
|
368
|
+
@literal_size_limit = literal_size_limit
|
369
|
+
@command_size_limit = command_size_limit
|
370
|
+
@logger.debug("RIMS::Protocol::InitialDecoder#initialize at #{self}") if @logger.debug?
|
371
|
+
end
|
372
|
+
|
373
|
+
def make_requrest_reader(input, output)
|
374
|
+
RequestReader.new(input, output, @logger,
|
375
|
+
line_length_limit: @line_length_limit,
|
376
|
+
literal_size_limit: @literal_size_limit,
|
377
|
+
command_size_limit: @command_size_limit)
|
333
378
|
end
|
334
379
|
|
335
380
|
def auth?
|
@@ -341,22 +386,23 @@ module RIMS
|
|
341
386
|
end
|
342
387
|
|
343
388
|
def cleanup
|
389
|
+
@logger.debug("RIMS::Protocol::InitialDecoder#cleanup at #{self}") if @logger.debug?
|
344
390
|
nil
|
345
391
|
end
|
346
392
|
|
347
393
|
def make_not_authenticated_response(tag)
|
348
|
-
|
394
|
+
yield("#{tag} NO not authenticated\r\n")
|
349
395
|
end
|
350
396
|
private :make_not_authenticated_response
|
351
397
|
|
352
398
|
def noop(tag)
|
353
|
-
yield(
|
399
|
+
yield("#{tag} OK NOOP completed\r\n")
|
354
400
|
end
|
355
401
|
imap_command :noop
|
356
402
|
|
357
|
-
def logout(tag)
|
358
|
-
@next_decoder = LogoutDecoder.new(self)
|
359
|
-
|
403
|
+
def logout(tag, &block)
|
404
|
+
@next_decoder = LogoutDecoder.new(self, @logger)
|
405
|
+
make_logout_response(tag, &block)
|
360
406
|
end
|
361
407
|
imap_command :logout
|
362
408
|
|
@@ -366,7 +412,7 @@ module RIMS
|
|
366
412
|
@logger.info("mail delivery user: #{username}")
|
367
413
|
MailDeliveryDecoder.new(self, @drb_services, @auth, @logger)
|
368
414
|
else
|
369
|
-
engine = self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|
|
415
|
+
engine = self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|untagged_response| yield(untagged_response) }
|
370
416
|
UserMailboxDecoder.new(self, engine, @auth, @logger)
|
371
417
|
end
|
372
418
|
end
|
@@ -377,137 +423,137 @@ module RIMS
|
|
377
423
|
auth_reader = AuthenticationReader.new(@auth, client_response_input_gets, server_challenge_output_write, @logger)
|
378
424
|
if (username = auth_reader.authenticate_client(auth_type, inline_client_response_data_base64)) then
|
379
425
|
if (username != :*) then
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
426
|
+
@logger.info("authentication OK: #{username}")
|
427
|
+
@next_decoder = accept_authentication(username) {|untagged_response|
|
428
|
+
yield(untagged_response)
|
429
|
+
yield(:flush)
|
384
430
|
}
|
431
|
+
yield("#{tag} OK AUTHENTICATE #{auth_type} success\r\n")
|
385
432
|
else
|
386
433
|
@logger.info('bad authentication.')
|
387
|
-
yield(
|
434
|
+
yield("#{tag} BAD AUTHENTICATE failed\r\n")
|
388
435
|
end
|
389
436
|
else
|
390
|
-
yield(
|
437
|
+
yield("#{tag} NO authentication failed\r\n")
|
391
438
|
end
|
392
439
|
end
|
393
440
|
imap_command :authenticate
|
394
441
|
|
395
442
|
def login(tag, username, password)
|
396
443
|
if (@auth.authenticate_login(username, password)) then
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
444
|
+
@logger.info("login authentication OK: #{username}")
|
445
|
+
@next_decoder = accept_authentication(username) {|untagged_response|
|
446
|
+
yield(untagged_response)
|
447
|
+
yield(:flush)
|
401
448
|
}
|
449
|
+
yield("#{tag} OK LOGIN completed\r\n")
|
402
450
|
else
|
403
|
-
yield(
|
451
|
+
yield("#{tag} NO failed to login\r\n")
|
404
452
|
end
|
405
453
|
end
|
406
454
|
imap_command :login
|
407
455
|
|
408
|
-
def select(tag, mbox_name)
|
409
|
-
|
456
|
+
def select(tag, mbox_name, &block)
|
457
|
+
make_not_authenticated_response(tag, &block)
|
410
458
|
end
|
411
459
|
imap_command :select
|
412
460
|
|
413
|
-
def examine(tag, mbox_name)
|
414
|
-
|
461
|
+
def examine(tag, mbox_name, &block)
|
462
|
+
make_not_authenticated_response(tag, &block)
|
415
463
|
end
|
416
464
|
imap_command :examine
|
417
465
|
|
418
|
-
def create(tag, mbox_name)
|
419
|
-
|
466
|
+
def create(tag, mbox_name, &block)
|
467
|
+
make_not_authenticated_response(tag, &block)
|
420
468
|
end
|
421
469
|
imap_command :create
|
422
470
|
|
423
|
-
def delete(tag, mbox_name)
|
424
|
-
|
471
|
+
def delete(tag, mbox_name, &block)
|
472
|
+
make_not_authenticated_response(tag, &block)
|
425
473
|
end
|
426
474
|
imap_command :delete
|
427
475
|
|
428
|
-
def rename(tag, src_name, dst_name)
|
429
|
-
|
476
|
+
def rename(tag, src_name, dst_name, &block)
|
477
|
+
make_not_authenticated_response(tag, &block)
|
430
478
|
end
|
431
479
|
imap_command :rename
|
432
480
|
|
433
|
-
def subscribe(tag, mbox_name)
|
434
|
-
|
481
|
+
def subscribe(tag, mbox_name, &block)
|
482
|
+
make_not_authenticated_response(tag, &block)
|
435
483
|
end
|
436
484
|
imap_command :subscribe
|
437
485
|
|
438
|
-
def unsubscribe(tag, mbox_name)
|
439
|
-
|
486
|
+
def unsubscribe(tag, mbox_name, &block)
|
487
|
+
make_not_authenticated_response(tag, &block)
|
440
488
|
end
|
441
489
|
imap_command :unsubscribe
|
442
490
|
|
443
|
-
def list(tag, ref_name, mbox_name)
|
444
|
-
|
491
|
+
def list(tag, ref_name, mbox_name, &block)
|
492
|
+
make_not_authenticated_response(tag, &block)
|
445
493
|
end
|
446
494
|
imap_command :list
|
447
495
|
|
448
|
-
def lsub(tag, ref_name, mbox_name)
|
449
|
-
|
496
|
+
def lsub(tag, ref_name, mbox_name, &block)
|
497
|
+
make_not_authenticated_response(tag, &block)
|
450
498
|
end
|
451
499
|
imap_command :lsub
|
452
500
|
|
453
|
-
def status(tag, mbox_name, data_item_group)
|
454
|
-
|
501
|
+
def status(tag, mbox_name, data_item_group, &block)
|
502
|
+
make_not_authenticated_response(tag, &block)
|
455
503
|
end
|
456
504
|
imap_command :status
|
457
505
|
|
458
|
-
def append(tag, mbox_name, *opt_args, msg_text)
|
459
|
-
|
506
|
+
def append(tag, mbox_name, *opt_args, msg_text, &block)
|
507
|
+
make_not_authenticated_response(tag, &block)
|
460
508
|
end
|
461
509
|
imap_command :append
|
462
510
|
|
463
|
-
def check(tag)
|
464
|
-
|
511
|
+
def check(tag, &block)
|
512
|
+
make_not_authenticated_response(tag, &block)
|
465
513
|
end
|
466
514
|
imap_command :check
|
467
515
|
|
468
|
-
def close(tag)
|
469
|
-
|
516
|
+
def close(tag, &block)
|
517
|
+
make_not_authenticated_response(tag, &block)
|
470
518
|
end
|
471
519
|
imap_command :close
|
472
520
|
|
473
|
-
def expunge(tag)
|
474
|
-
|
521
|
+
def expunge(tag, &block)
|
522
|
+
make_not_authenticated_response(tag, &block)
|
475
523
|
end
|
476
524
|
imap_command :expunge
|
477
525
|
|
478
|
-
def search(tag, *cond_args, uid: false)
|
479
|
-
|
526
|
+
def search(tag, *cond_args, uid: false, &block)
|
527
|
+
make_not_authenticated_response(tag, &block)
|
480
528
|
end
|
481
529
|
imap_command :search
|
482
530
|
|
483
|
-
def fetch(tag, msg_set, data_item_group, uid: false)
|
484
|
-
|
531
|
+
def fetch(tag, msg_set, data_item_group, uid: false, &block)
|
532
|
+
make_not_authenticated_response(tag, &block)
|
485
533
|
end
|
486
534
|
imap_command :fetch
|
487
535
|
|
488
|
-
def store(tag, msg_set, data_item_name, data_item_value, uid: false)
|
489
|
-
|
536
|
+
def store(tag, msg_set, data_item_name, data_item_value, uid: false, &block)
|
537
|
+
make_not_authenticated_response(tag, &block)
|
490
538
|
end
|
491
539
|
imap_command :store
|
492
540
|
|
493
|
-
def copy(tag, msg_set, mbox_name, uid: false)
|
494
|
-
|
541
|
+
def copy(tag, msg_set, mbox_name, uid: false, &block)
|
542
|
+
make_not_authenticated_response(tag, &block)
|
495
543
|
end
|
496
544
|
imap_command :copy
|
497
545
|
|
498
|
-
def idle(tag, client_input_gets, server_output_write, connection_timer)
|
499
|
-
|
546
|
+
def idle(tag, client_input_gets, server_output_write, connection_timer, &block)
|
547
|
+
make_not_authenticated_response(tag, &block)
|
500
548
|
end
|
501
549
|
imap_command :idle
|
502
550
|
end
|
503
551
|
|
504
552
|
class LogoutDecoder < Decoder
|
505
|
-
def initialize(parent_decoder)
|
553
|
+
def initialize(parent_decoder, logger)
|
554
|
+
super(nil, logger)
|
506
555
|
@parent_decoder = parent_decoder
|
507
|
-
|
508
|
-
|
509
|
-
def next_decoder
|
510
|
-
self
|
556
|
+
@logger.debug("RIMS::Protocol::LogoutDecoder#initialize at #{self}") if @logger.debug?
|
511
557
|
end
|
512
558
|
|
513
559
|
def auth?
|
@@ -519,6 +565,7 @@ module RIMS
|
|
519
565
|
end
|
520
566
|
|
521
567
|
def cleanup
|
568
|
+
@logger.debug("RIMS::Protocol::LogoutDecoder#cleanup at #{self}") if @logger.debug?
|
522
569
|
unless (@parent_decoder.nil?) then
|
523
570
|
@parent_decoder.cleanup
|
524
571
|
@parent_decoder = nil
|
@@ -652,31 +699,81 @@ module RIMS
|
|
652
699
|
class AuthenticatedDecoder < Decoder
|
653
700
|
def authenticate(tag, client_response_input_gets, server_challenge_output_write,
|
654
701
|
auth_type, inline_client_response_data_base64=nil, &block)
|
655
|
-
yield(
|
702
|
+
yield("#{tag} NO duplicated authentication\r\n")
|
656
703
|
end
|
657
704
|
imap_command :authenticate
|
658
705
|
|
659
706
|
def login(tag, username, password, &block)
|
660
|
-
yield(
|
707
|
+
yield("#{tag} NO duplicated login\r\n")
|
661
708
|
end
|
662
709
|
imap_command :login
|
663
710
|
end
|
664
711
|
|
665
712
|
class UserMailboxDecoder < AuthenticatedDecoder
|
713
|
+
class BulkResponse
|
714
|
+
def initialize(limit_count, limit_size)
|
715
|
+
@limit_count = limit_count
|
716
|
+
@limit_size = limit_size
|
717
|
+
@responses = []
|
718
|
+
@size = 0
|
719
|
+
end
|
720
|
+
|
721
|
+
def count
|
722
|
+
@responses.length
|
723
|
+
end
|
724
|
+
|
725
|
+
attr_reader :size
|
726
|
+
|
727
|
+
def add(response)
|
728
|
+
@responses << response
|
729
|
+
@size += response.bytesize
|
730
|
+
self
|
731
|
+
end
|
732
|
+
|
733
|
+
alias << add
|
734
|
+
|
735
|
+
def empty?
|
736
|
+
@responses.empty?
|
737
|
+
end
|
738
|
+
|
739
|
+
def full?
|
740
|
+
count >= @limit_count || size >= @limit_size
|
741
|
+
end
|
742
|
+
|
743
|
+
def flush
|
744
|
+
res = @responses
|
745
|
+
if (count >= @limit_count) then
|
746
|
+
res = [ res.join('') ]
|
747
|
+
end
|
748
|
+
|
749
|
+
@responses = []
|
750
|
+
@size = 0
|
751
|
+
|
752
|
+
res
|
753
|
+
end
|
754
|
+
end
|
755
|
+
|
666
756
|
class Engine
|
667
757
|
def initialize(unique_user_id, mail_store, logger,
|
668
758
|
bulk_response_count: 100,
|
759
|
+
bulk_response_size: 1024**2 * 10,
|
669
760
|
read_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS,
|
670
761
|
write_lock_timeout_seconds: ReadWriteLock::DEFAULT_TIMEOUT_SECONDS,
|
671
|
-
cleanup_write_lock_timeout_seconds: 1
|
762
|
+
cleanup_write_lock_timeout_seconds: 1,
|
763
|
+
charset_aliases: RFC822::DEFAULT_CHARSET_ALIASES,
|
764
|
+
charset_convert_options: nil)
|
672
765
|
@unique_user_id = unique_user_id
|
673
766
|
@mail_store = mail_store
|
674
767
|
@logger = logger
|
675
768
|
@bulk_response_count = bulk_response_count
|
769
|
+
@bulk_response_size = bulk_response_size
|
676
770
|
@read_lock_timeout_seconds = read_lock_timeout_seconds
|
677
771
|
@write_lock_timeout_seconds = write_lock_timeout_seconds
|
678
772
|
@cleanup_write_lock_timeout_seconds = cleanup_write_lock_timeout_seconds
|
773
|
+
@charset_aliases = charset_aliases
|
774
|
+
@charset_convert_options = charset_convert_options
|
679
775
|
@folders = {}
|
776
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#initialize at #{self}") if @logger.debug?
|
680
777
|
end
|
681
778
|
|
682
779
|
attr_reader :unique_user_id
|
@@ -704,11 +801,13 @@ module RIMS
|
|
704
801
|
end
|
705
802
|
@folders[token] = folder
|
706
803
|
|
804
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#open_folder: #{token}") if @logger.debug?
|
707
805
|
token
|
708
806
|
end
|
709
807
|
private :open_folder
|
710
808
|
|
711
809
|
def close_folder(token)
|
810
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#close_folder: #{token}") if @logger.debug?
|
712
811
|
folder = @folders.delete(token) or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
713
812
|
folder.reload if folder.updated?
|
714
813
|
begin
|
@@ -752,9 +851,10 @@ module RIMS
|
|
752
851
|
end
|
753
852
|
|
754
853
|
def destroy
|
854
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder::Engine#destroy at #{self}") if @logger.debug?
|
755
855
|
tmp_mail_store = @mail_store
|
756
856
|
ReadWriteLock.write_lock_timeout_detach(@cleanup_write_lock_timeout_seconds, @write_lock_timeout_seconds, logger: @logger) {|timeout_seconds|
|
757
|
-
|
857
|
+
tmp_mail_store.write_synchronize(timeout_seconds) {
|
758
858
|
@logger.info("close mail store: #{@unique_user_id}")
|
759
859
|
tmp_mail_store.close
|
760
860
|
}
|
@@ -804,40 +904,66 @@ module RIMS
|
|
804
904
|
|
805
905
|
class << self
|
806
906
|
def imap_command_authenticated(name, **guard_optional)
|
907
|
+
name = name.to_sym
|
807
908
|
orig_name = "_#{name}".to_sym
|
808
909
|
alias_method orig_name, name
|
809
|
-
|
810
|
-
|
811
|
-
}
|
812
|
-
|
910
|
+
|
911
|
+
guard_options_name = "_#{name}_guard_options".to_sym
|
912
|
+
define_method guard_options_name, lambda{ guard_optional }
|
913
|
+
private guard_options_name
|
914
|
+
|
915
|
+
class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
916
|
+
def #{name}(token, tag, *args, **kw_args, &block)
|
917
|
+
guard_authenticated(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block)
|
918
|
+
end
|
919
|
+
EOF
|
920
|
+
|
921
|
+
name
|
813
922
|
end
|
814
923
|
private :imap_command_authenticated
|
815
924
|
|
816
925
|
def imap_command_selected(name, **guard_optional)
|
926
|
+
name = name.to_sym
|
817
927
|
orig_name = "_#{name}".to_sym
|
818
928
|
alias_method orig_name, name
|
819
|
-
|
820
|
-
|
821
|
-
}
|
822
|
-
|
929
|
+
|
930
|
+
guard_options_name = "_#{name}_guard_options".to_sym
|
931
|
+
define_method guard_options_name, lambda{ guard_optional }
|
932
|
+
private guard_options_name
|
933
|
+
|
934
|
+
class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
935
|
+
def #{name}(token, tag, *args, **kw_args, &block)
|
936
|
+
guard_selected(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block)
|
937
|
+
end
|
938
|
+
EOF
|
939
|
+
|
940
|
+
name
|
823
941
|
end
|
824
942
|
private :imap_command_selected
|
825
943
|
end
|
826
944
|
|
945
|
+
def new_bulk_response
|
946
|
+
BulkResponse.new(@bulk_response_count, @bulk_response_size)
|
947
|
+
end
|
948
|
+
private :new_bulk_response
|
949
|
+
|
827
950
|
def noop(token, tag)
|
828
|
-
res =
|
951
|
+
res = new_bulk_response
|
829
952
|
if (token) then
|
830
953
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
831
954
|
begin
|
832
955
|
@mail_store.read_synchronize(@read_lock_timeout_seconds) {
|
833
|
-
folder.server_response_fetch{|
|
956
|
+
folder.server_response_fetch{|untagged_response|
|
957
|
+
res << untagged_response
|
958
|
+
yield(res.flush) if res.full?
|
959
|
+
}
|
834
960
|
}
|
835
961
|
rescue ReadLockTimeoutError
|
836
962
|
@logger.warn("give up to get folder status because of read-lock timeout over #{@read_lock_timeout_seconds} seconds")
|
837
963
|
end
|
838
964
|
end
|
839
965
|
res << "#{tag} OK NOOP completed\r\n"
|
840
|
-
yield(res)
|
966
|
+
yield(res.flush)
|
841
967
|
end
|
842
968
|
|
843
969
|
def folder_open_msgs(token)
|
@@ -859,20 +985,21 @@ module RIMS
|
|
859
985
|
close_no_response(token)
|
860
986
|
end
|
861
987
|
|
862
|
-
res =
|
988
|
+
res = new_bulk_response
|
863
989
|
new_token = nil
|
864
990
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
865
991
|
|
866
992
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
867
993
|
new_token = open_folder(id)
|
868
|
-
folder_open_msgs(new_token)
|
869
|
-
res <<
|
870
|
-
|
994
|
+
folder_open_msgs(new_token) {|untagged_response|
|
995
|
+
res << untagged_response
|
996
|
+
yield(res.flush) if res.full?
|
997
|
+
}
|
871
998
|
res << "#{tag} OK [READ-WRITE] SELECT completed\r\n"
|
872
999
|
else
|
873
1000
|
res << "#{tag} NO not found a mailbox\r\n"
|
874
1001
|
end
|
875
|
-
yield(res)
|
1002
|
+
yield(res.flush)
|
876
1003
|
|
877
1004
|
new_token
|
878
1005
|
end
|
@@ -883,30 +1010,34 @@ module RIMS
|
|
883
1010
|
close_no_response(token)
|
884
1011
|
end
|
885
1012
|
|
886
|
-
res =
|
1013
|
+
res = new_bulk_response
|
887
1014
|
new_token = nil
|
888
1015
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
889
1016
|
|
890
1017
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
891
1018
|
new_token = open_folder(id, read_only: true)
|
892
|
-
folder_open_msgs(new_token)
|
893
|
-
res <<
|
894
|
-
|
1019
|
+
folder_open_msgs(new_token) {|untagged_response|
|
1020
|
+
res << untagged_response
|
1021
|
+
yield(res.flush) if res.full?
|
1022
|
+
}
|
895
1023
|
res << "#{tag} OK [READ-ONLY] EXAMINE completed\r\n"
|
896
1024
|
else
|
897
1025
|
res << "#{tag} NO not found a mailbox\r\n"
|
898
1026
|
end
|
899
|
-
yield(res)
|
1027
|
+
yield(res.flush)
|
900
1028
|
|
901
1029
|
new_token
|
902
1030
|
end
|
903
1031
|
imap_command_authenticated :examine
|
904
1032
|
|
905
1033
|
def create(token, tag, mbox_name)
|
906
|
-
res =
|
1034
|
+
res = new_bulk_response
|
907
1035
|
if (token) then
|
908
1036
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
909
|
-
folder.server_response_fetch{|
|
1037
|
+
folder.server_response_fetch{|untagged_response|
|
1038
|
+
res << untagged_response
|
1039
|
+
yield(res.flush) if res.full?
|
1040
|
+
}
|
910
1041
|
end
|
911
1042
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
912
1043
|
if (@mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -915,15 +1046,18 @@ module RIMS
|
|
915
1046
|
@mail_store.add_mbox(mbox_name_utf8)
|
916
1047
|
res << "#{tag} OK CREATE completed\r\n"
|
917
1048
|
end
|
918
|
-
yield(res)
|
1049
|
+
yield(res.flush)
|
919
1050
|
end
|
920
1051
|
imap_command_authenticated :create, exclusive: true
|
921
1052
|
|
922
1053
|
def delete(token, tag, mbox_name)
|
923
|
-
res =
|
1054
|
+
res = new_bulk_response
|
924
1055
|
if (token) then
|
925
1056
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
926
|
-
folder.server_response_fetch{|
|
1057
|
+
folder.server_response_fetch{|untagged_response|
|
1058
|
+
res << untagged_response
|
1059
|
+
yield(res.flush) if res.full?
|
1060
|
+
}
|
927
1061
|
end
|
928
1062
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
929
1063
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -936,38 +1070,47 @@ module RIMS
|
|
936
1070
|
else
|
937
1071
|
res << "#{tag} NO not found a mailbox\r\n"
|
938
1072
|
end
|
939
|
-
yield(res)
|
1073
|
+
yield(res.flush)
|
940
1074
|
end
|
941
1075
|
imap_command_authenticated :delete, exclusive: true
|
942
1076
|
|
943
1077
|
def rename(token, tag, src_name, dst_name)
|
944
|
-
res =
|
1078
|
+
res = new_bulk_response
|
945
1079
|
if (token) then
|
946
1080
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
947
|
-
folder.server_response_fetch{|
|
1081
|
+
folder.server_response_fetch{|untagged_response|
|
1082
|
+
res << untagged_response
|
1083
|
+
yield(res.flush) if res.full?
|
1084
|
+
}
|
948
1085
|
end
|
949
1086
|
src_name_utf8 = Net::IMAP.decode_utf7(src_name)
|
950
1087
|
dst_name_utf8 = Net::IMAP.decode_utf7(dst_name)
|
951
1088
|
unless (id = @mail_store.mbox_id(src_name_utf8)) then
|
952
|
-
|
1089
|
+
res << "#{tag} NO not found a mailbox\r\n"
|
1090
|
+
return yield(res.flush)
|
953
1091
|
end
|
954
1092
|
if (id == @mail_store.mbox_id('INBOX')) then
|
955
|
-
|
1093
|
+
res << "#{tag} NO not rename inbox\r\n"
|
1094
|
+
return yield(res.flush)
|
956
1095
|
end
|
957
1096
|
if (@mail_store.mbox_id(dst_name_utf8)) then
|
958
|
-
|
1097
|
+
res << "#{tag} NO duplicated mailbox\r\n"
|
1098
|
+
return yield(res.flush)
|
959
1099
|
end
|
960
1100
|
@mail_store.rename_mbox(id, dst_name_utf8)
|
961
1101
|
res << "#{tag} OK RENAME completed\r\n"
|
962
|
-
yield(res)
|
1102
|
+
yield(res.flush)
|
963
1103
|
end
|
964
1104
|
imap_command_authenticated :rename, exclusive: true
|
965
1105
|
|
966
1106
|
def subscribe(token, tag, mbox_name)
|
967
|
-
res =
|
1107
|
+
res = new_bulk_response
|
968
1108
|
if (token) then
|
969
1109
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
970
|
-
folder.server_response_fetch{|
|
1110
|
+
folder.server_response_fetch{|untagged_response|
|
1111
|
+
res << untagged_response
|
1112
|
+
yield(res.flush) if res.full?
|
1113
|
+
}
|
971
1114
|
end
|
972
1115
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
973
1116
|
if (@mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -975,15 +1118,18 @@ module RIMS
|
|
975
1118
|
else
|
976
1119
|
res << "#{tag} NO not found a mailbox\r\n"
|
977
1120
|
end
|
978
|
-
yield(res)
|
1121
|
+
yield(res.flush)
|
979
1122
|
end
|
980
1123
|
imap_command_authenticated :subscribe
|
981
1124
|
|
982
1125
|
def unsubscribe(token, tag, mbox_name)
|
983
|
-
res =
|
1126
|
+
res = new_bulk_response
|
984
1127
|
if (token) then
|
985
1128
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
986
|
-
folder.server_response_fetch{|
|
1129
|
+
folder.server_response_fetch{|untagged_response|
|
1130
|
+
res << untagged_response
|
1131
|
+
yield(res.flush) if res.full?
|
1132
|
+
}
|
987
1133
|
end
|
988
1134
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
989
1135
|
if (@mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -991,7 +1137,7 @@ module RIMS
|
|
991
1137
|
else
|
992
1138
|
res << "#{tag} NO not found a mailbox\r\n"
|
993
1139
|
end
|
994
|
-
yield(res)
|
1140
|
+
yield(res.flush)
|
995
1141
|
end
|
996
1142
|
imap_command_authenticated :unsubscribe
|
997
1143
|
|
@@ -1020,46 +1166,57 @@ module RIMS
|
|
1020
1166
|
private :list_mbox
|
1021
1167
|
|
1022
1168
|
def list(token, tag, ref_name, mbox_name)
|
1023
|
-
res =
|
1169
|
+
res = new_bulk_response
|
1024
1170
|
if (token) then
|
1025
1171
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1026
|
-
folder.server_response_fetch{|
|
1172
|
+
folder.server_response_fetch{|untagged_response|
|
1173
|
+
res << untagged_response
|
1174
|
+
yield(res.flush) if res.full?
|
1175
|
+
}
|
1027
1176
|
end
|
1028
1177
|
if (mbox_name.empty?) then
|
1029
1178
|
res << "* LIST (\\Noselect) NIL \"\"\r\n"
|
1030
1179
|
else
|
1031
|
-
list_mbox(ref_name, mbox_name)
|
1180
|
+
list_mbox(ref_name, mbox_name) {|mbox_entry|
|
1032
1181
|
res << "* LIST #{mbox_entry}\r\n"
|
1033
|
-
|
1182
|
+
yield(res.flush) if res.full?
|
1183
|
+
}
|
1034
1184
|
end
|
1035
1185
|
res << "#{tag} OK LIST completed\r\n"
|
1036
|
-
yield(res)
|
1186
|
+
yield(res.flush)
|
1037
1187
|
end
|
1038
1188
|
imap_command_authenticated :list
|
1039
1189
|
|
1040
1190
|
def lsub(token, tag, ref_name, mbox_name)
|
1041
|
-
res =
|
1191
|
+
res = new_bulk_response
|
1042
1192
|
if (token) then
|
1043
1193
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1044
|
-
folder.server_response_fetch{|
|
1194
|
+
folder.server_response_fetch{|untagged_response|
|
1195
|
+
res << untagged_response
|
1196
|
+
yield(res.flush) if res.full?
|
1197
|
+
}
|
1045
1198
|
end
|
1046
1199
|
if (mbox_name.empty?) then
|
1047
1200
|
res << "* LSUB (\\Noselect) NIL \"\"\r\n"
|
1048
1201
|
else
|
1049
|
-
list_mbox(ref_name, mbox_name)
|
1202
|
+
list_mbox(ref_name, mbox_name) {|mbox_entry|
|
1050
1203
|
res << "* LSUB #{mbox_entry}\r\n"
|
1051
|
-
|
1204
|
+
yield(res.flush) if res.full?
|
1205
|
+
}
|
1052
1206
|
end
|
1053
1207
|
res << "#{tag} OK LSUB completed\r\n"
|
1054
|
-
yield(res)
|
1208
|
+
yield(res.flush)
|
1055
1209
|
end
|
1056
1210
|
imap_command_authenticated :lsub
|
1057
1211
|
|
1058
1212
|
def status(token, tag, mbox_name, data_item_group)
|
1059
|
-
res =
|
1213
|
+
res = new_bulk_response
|
1060
1214
|
if (token) then
|
1061
1215
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1062
|
-
folder.server_response_fetch{|
|
1216
|
+
folder.server_response_fetch{|untagged_response|
|
1217
|
+
res << untagged_response
|
1218
|
+
yield(res.flush) if res.full?
|
1219
|
+
}
|
1063
1220
|
end
|
1064
1221
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
1065
1222
|
if (id = @mail_store.mbox_id(mbox_name_utf8)) then
|
@@ -1091,7 +1248,7 @@ module RIMS
|
|
1091
1248
|
else
|
1092
1249
|
res << "#{tag} NO not found a mailbox\r\n"
|
1093
1250
|
end
|
1094
|
-
yield(res)
|
1251
|
+
yield(res.flush)
|
1095
1252
|
end
|
1096
1253
|
imap_command_authenticated :status
|
1097
1254
|
|
@@ -1112,7 +1269,7 @@ module RIMS
|
|
1112
1269
|
private :mailbox_size_server_response_multicast_push
|
1113
1270
|
|
1114
1271
|
def append(token, tag, mbox_name, *opt_args, msg_text)
|
1115
|
-
res =
|
1272
|
+
res = new_bulk_response
|
1116
1273
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
1117
1274
|
if (mbox_id = @mail_store.mbox_id(mbox_name_utf8)) then
|
1118
1275
|
msg_flags = []
|
@@ -1161,30 +1318,39 @@ module RIMS
|
|
1161
1318
|
mailbox_size_server_response_multicast_push(mbox_id)
|
1162
1319
|
if (token) then
|
1163
1320
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1164
|
-
folder.server_response_fetch{|
|
1321
|
+
folder.server_response_fetch{|untagged_response|
|
1322
|
+
res << untagged_response
|
1323
|
+
yield(res.flush) if res.full?
|
1324
|
+
}
|
1165
1325
|
end
|
1166
1326
|
|
1167
1327
|
res << "#{tag} OK [APPENDUID #{mbox_id} #{uid}] APPEND completed\r\n"
|
1168
1328
|
else
|
1169
1329
|
if (token) then
|
1170
1330
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1171
|
-
folder.server_response_fetch{|
|
1331
|
+
folder.server_response_fetch{|untagged_response|
|
1332
|
+
res << untagged_response
|
1333
|
+
yield(res.flush) if res.full?
|
1334
|
+
}
|
1172
1335
|
end
|
1173
1336
|
res << "#{tag} NO [TRYCREATE] not found a mailbox\r\n"
|
1174
1337
|
end
|
1175
|
-
yield(res)
|
1338
|
+
yield(res.flush)
|
1176
1339
|
end
|
1177
1340
|
imap_command_authenticated :append, exclusive: true
|
1178
1341
|
|
1179
1342
|
def check(token, tag)
|
1180
|
-
res =
|
1343
|
+
res = new_bulk_response
|
1181
1344
|
if (token) then
|
1182
1345
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1183
|
-
folder.server_response_fetch{|
|
1346
|
+
folder.server_response_fetch{|untagged_response|
|
1347
|
+
res << untagged_response
|
1348
|
+
yield(res.flush) if res.full?
|
1349
|
+
}
|
1184
1350
|
end
|
1185
1351
|
@mail_store.sync
|
1186
1352
|
res << "#{tag} OK CHECK completed\r\n"
|
1187
|
-
yield(res)
|
1353
|
+
yield(res.flush)
|
1188
1354
|
end
|
1189
1355
|
imap_command_selected :check, exclusive: true
|
1190
1356
|
|
@@ -1212,27 +1378,21 @@ module RIMS
|
|
1212
1378
|
return yield([ "#{tag} NO cannot expunge in read-only mode\r\n" ]) if folder.read_only?
|
1213
1379
|
folder.reload if folder.updated?
|
1214
1380
|
|
1215
|
-
res =
|
1216
|
-
folder.server_response_fetch{|
|
1217
|
-
res <<
|
1218
|
-
|
1219
|
-
|
1220
|
-
res = []
|
1221
|
-
end
|
1222
|
-
}
|
1381
|
+
res = new_bulk_response
|
1382
|
+
folder.server_response_fetch{|untagged_response|
|
1383
|
+
res << untagged_response
|
1384
|
+
yield(res.flush) if res.full?
|
1385
|
+
}
|
1223
1386
|
|
1224
1387
|
folder.expunge_mbox do |msg_num|
|
1225
|
-
|
1226
|
-
res <<
|
1227
|
-
|
1228
|
-
|
1229
|
-
res = []
|
1230
|
-
end
|
1231
|
-
folder.server_response_multicast_push(r)
|
1388
|
+
untagged_response = "* #{msg_num} EXPUNGE\r\n"
|
1389
|
+
res << untagged_response
|
1390
|
+
yield(res.flush) if res.full?
|
1391
|
+
folder.server_response_multicast_push(untagged_response)
|
1232
1392
|
end
|
1233
1393
|
|
1234
1394
|
res << "#{tag} OK EXPUNGE completed\r\n"
|
1235
|
-
yield(res)
|
1395
|
+
yield(res.flush)
|
1236
1396
|
end
|
1237
1397
|
imap_command_selected :expunge, exclusive: true
|
1238
1398
|
|
@@ -1240,7 +1400,9 @@ module RIMS
|
|
1240
1400
|
folder = @folders[token] or raise KeyError.new("undefined folder token: #{token}", key: token, receiver: self)
|
1241
1401
|
folder.should_be_alive
|
1242
1402
|
folder.reload if folder.updated?
|
1243
|
-
parser = SearchParser.new(@mail_store, folder
|
1403
|
+
parser = SearchParser.new(@mail_store, folder,
|
1404
|
+
charset_aliases: @charset_aliases,
|
1405
|
+
charset_convert_options: @charset_convert_options)
|
1244
1406
|
|
1245
1407
|
if (! cond_args.empty? && cond_args[0].upcase == 'CHARSET') then
|
1246
1408
|
cond_args.shift
|
@@ -1250,7 +1412,7 @@ module RIMS
|
|
1250
1412
|
parser.charset = charset_string
|
1251
1413
|
rescue ArgumentError
|
1252
1414
|
@logger.warn("unknown charset: #{charset_string}")
|
1253
|
-
return yield([ "#{tag} NO [BADCHARSET (#{Encoding.list.map(&:to_s).join(' ')})] unknown charset\r\n" ])
|
1415
|
+
return yield([ "#{tag} NO [BADCHARSET (#{Encoding.list.reject(&:dummy?).map(&:to_s).join(' ')})] unknown charset\r\n" ])
|
1254
1416
|
end
|
1255
1417
|
end
|
1256
1418
|
|
@@ -1261,35 +1423,32 @@ module RIMS
|
|
1261
1423
|
if (cond_args[0].upcase == 'UID' && cond_args.length >= 2) then
|
1262
1424
|
begin
|
1263
1425
|
msg_set = folder.parse_msg_set(cond_args[1], uid: true)
|
1264
|
-
|
1426
|
+
msg_list = folder.msg_find_all(msg_set, uid: true)
|
1265
1427
|
cond_args.shift(2)
|
1266
1428
|
rescue MessageSetSyntaxError
|
1267
|
-
|
1429
|
+
msg_list = folder.each_msg
|
1268
1430
|
end
|
1269
1431
|
else
|
1270
1432
|
begin
|
1271
1433
|
msg_set = folder.parse_msg_set(cond_args[0], uid: false)
|
1272
|
-
|
1434
|
+
msg_list = folder.msg_find_all(msg_set, uid: false)
|
1273
1435
|
cond_args.shift
|
1274
1436
|
rescue MessageSetSyntaxError
|
1275
|
-
|
1437
|
+
msg_list = folder.each_msg
|
1276
1438
|
end
|
1277
1439
|
end
|
1278
1440
|
cond = parser.parse(cond_args)
|
1279
1441
|
|
1280
|
-
res =
|
1281
|
-
folder.server_response_fetch{|
|
1282
|
-
res <<
|
1283
|
-
|
1284
|
-
yield(res)
|
1285
|
-
res = []
|
1286
|
-
end
|
1442
|
+
res = new_bulk_response
|
1443
|
+
folder.server_response_fetch{|untagged_response|
|
1444
|
+
res << untagged_response
|
1445
|
+
yield(res.flush) if res.full?
|
1287
1446
|
}
|
1288
1447
|
|
1289
1448
|
res << '* SEARCH'
|
1290
1449
|
begin
|
1291
1450
|
begin
|
1292
|
-
for msg in
|
1451
|
+
for msg in msg_list
|
1293
1452
|
begin
|
1294
1453
|
if (cond.call(msg)) then
|
1295
1454
|
if (uid) then
|
@@ -1297,10 +1456,7 @@ module RIMS
|
|
1297
1456
|
else
|
1298
1457
|
res << " #{msg.num}"
|
1299
1458
|
end
|
1300
|
-
|
1301
|
-
yield(res)
|
1302
|
-
res = []
|
1303
|
-
end
|
1459
|
+
yield(res.flush) if res.full?
|
1304
1460
|
end
|
1305
1461
|
rescue EncodingError
|
1306
1462
|
@logger.warn("encoding error at the message: uidvalidity(#{folder.mbox_id}) uid(#{msg.uid})")
|
@@ -1311,14 +1467,12 @@ module RIMS
|
|
1311
1467
|
res << "\r\n"
|
1312
1468
|
end
|
1313
1469
|
rescue
|
1314
|
-
|
1315
|
-
yield(res)
|
1316
|
-
res = []
|
1470
|
+
yield(res.flush)
|
1317
1471
|
raise
|
1318
1472
|
end
|
1319
1473
|
|
1320
1474
|
res << "#{tag} OK SEARCH completed\r\n"
|
1321
|
-
yield(res)
|
1475
|
+
yield(res.flush)
|
1322
1476
|
end
|
1323
1477
|
imap_command_selected :search
|
1324
1478
|
|
@@ -1339,28 +1493,22 @@ module RIMS
|
|
1339
1493
|
end
|
1340
1494
|
end
|
1341
1495
|
|
1342
|
-
parser = FetchParser.new(@mail_store, folder)
|
1496
|
+
parser = FetchParser.new(@mail_store, folder, charset_aliases: @charset_aliases)
|
1343
1497
|
fetch = parser.parse(data_item_group)
|
1344
1498
|
|
1345
|
-
res =
|
1346
|
-
folder.server_response_fetch{|
|
1347
|
-
res <<
|
1348
|
-
|
1349
|
-
yield(res)
|
1350
|
-
res = []
|
1351
|
-
end
|
1499
|
+
res = new_bulk_response
|
1500
|
+
folder.server_response_fetch{|untagged_response|
|
1501
|
+
res << untagged_response
|
1502
|
+
yield(res.flush) if res.full?
|
1352
1503
|
}
|
1353
1504
|
|
1354
1505
|
for msg in msg_list
|
1355
1506
|
res << ('* '.b << msg.num.to_s.b << ' FETCH '.b << fetch.call(msg) << "\r\n".b)
|
1356
|
-
|
1357
|
-
yield(res)
|
1358
|
-
res = []
|
1359
|
-
end
|
1507
|
+
yield(res.flush) if res.full?
|
1360
1508
|
end
|
1361
1509
|
|
1362
1510
|
res << "#{tag} OK FETCH completed\r\n"
|
1363
|
-
yield(res)
|
1511
|
+
yield(res.flush)
|
1364
1512
|
end
|
1365
1513
|
imap_command_selected :fetch
|
1366
1514
|
|
@@ -1440,18 +1588,15 @@ module RIMS
|
|
1440
1588
|
end
|
1441
1589
|
end
|
1442
1590
|
|
1443
|
-
res =
|
1444
|
-
folder.server_response_fetch{|
|
1445
|
-
res <<
|
1446
|
-
|
1447
|
-
yield(res)
|
1448
|
-
res = []
|
1449
|
-
end
|
1591
|
+
res = new_bulk_response
|
1592
|
+
folder.server_response_fetch{|untagged_response|
|
1593
|
+
res << untagged_response
|
1594
|
+
yield(res.flush) if res.full?
|
1450
1595
|
}
|
1451
1596
|
|
1452
1597
|
if (is_silent) then
|
1453
1598
|
res << "#{tag} OK STORE completed\r\n"
|
1454
|
-
yield(res)
|
1599
|
+
yield(res.flush)
|
1455
1600
|
else
|
1456
1601
|
for msg in msg_list
|
1457
1602
|
flag_atom_list = nil
|
@@ -1471,17 +1616,14 @@ module RIMS
|
|
1471
1616
|
else
|
1472
1617
|
res << "* #{msg.num} FETCH (FLAGS (#{flag_atom_list.join(' ')}))\r\n"
|
1473
1618
|
end
|
1474
|
-
|
1475
|
-
yield(res)
|
1476
|
-
res = []
|
1477
|
-
end
|
1619
|
+
yield(res.flush) if res.full?
|
1478
1620
|
else
|
1479
1621
|
@logger.warn("not found a message and skipped: uidvalidity(#{folder.mbox_id}) uid(#{msg.uid})")
|
1480
1622
|
end
|
1481
1623
|
end
|
1482
1624
|
|
1483
1625
|
res << "#{tag} OK STORE completed\r\n"
|
1484
|
-
yield(res)
|
1626
|
+
yield(res.flush)
|
1485
1627
|
end
|
1486
1628
|
end
|
1487
1629
|
imap_command_selected :store, exclusive: true
|
@@ -1491,7 +1633,7 @@ module RIMS
|
|
1491
1633
|
folder.should_be_alive
|
1492
1634
|
folder.reload if folder.updated?
|
1493
1635
|
|
1494
|
-
res =
|
1636
|
+
res = new_bulk_response
|
1495
1637
|
mbox_name_utf8 = Net::IMAP.decode_utf7(mbox_name)
|
1496
1638
|
msg_set = folder.parse_msg_set(msg_set, uid: uid)
|
1497
1639
|
|
@@ -1507,17 +1649,26 @@ module RIMS
|
|
1507
1649
|
|
1508
1650
|
if (msg_list.size > 0) then
|
1509
1651
|
mailbox_size_server_response_multicast_push(mbox_id)
|
1510
|
-
folder.server_response_fetch{|
|
1652
|
+
folder.server_response_fetch{|untagged_response|
|
1653
|
+
res << untagged_response
|
1654
|
+
yield(res.flush) if res.full?
|
1655
|
+
}
|
1511
1656
|
res << "#{tag} OK [COPYUID #{mbox_id} #{src_uids.join(',')} #{dst_uids.join(',')}] COPY completed\r\n"
|
1512
1657
|
else
|
1513
|
-
folder.server_response_fetch{|
|
1658
|
+
folder.server_response_fetch{|untagged_response|
|
1659
|
+
res << untagged_response
|
1660
|
+
yield(res.flush) if res.full?
|
1661
|
+
}
|
1514
1662
|
res << "#{tag} OK COPY completed\r\n"
|
1515
1663
|
end
|
1516
1664
|
else
|
1517
|
-
folder.server_response_fetch{|
|
1665
|
+
folder.server_response_fetch{|untagged_response|
|
1666
|
+
res << untagged_response
|
1667
|
+
yield(res.flush) if res.full?
|
1668
|
+
}
|
1518
1669
|
res << "#{tag} NO [TRYCREATE] not found a mailbox\r\n"
|
1519
1670
|
end
|
1520
|
-
yield(res)
|
1671
|
+
yield(res.flush)
|
1521
1672
|
end
|
1522
1673
|
imap_command_selected :copy, exclusive: true
|
1523
1674
|
|
@@ -1529,12 +1680,15 @@ module RIMS
|
|
1529
1680
|
server_output_write.call([ "+ continue\r\n" ])
|
1530
1681
|
|
1531
1682
|
server_response_thread = Thread.new{
|
1532
|
-
|
1683
|
+
res = new_bulk_response
|
1684
|
+
@logger.info('idle server response thread start...')
|
1533
1685
|
folder.server_response_idle_wait{|server_response_list|
|
1534
|
-
for
|
1535
|
-
@logger.debug("idle server response: #{
|
1686
|
+
for untagged_response in server_response_list
|
1687
|
+
@logger.debug("idle server response: #{untagged_response}") if @logger.debug?
|
1688
|
+
res << untagged_response
|
1689
|
+
server_output_write.call(res.flush) if res.full?
|
1536
1690
|
end
|
1537
|
-
server_output_write.call(
|
1691
|
+
server_output_write.call(res.flush) unless res.empty?
|
1538
1692
|
}
|
1539
1693
|
@logger.info('idle server response thread terminated.')
|
1540
1694
|
}
|
@@ -1547,23 +1701,23 @@ module RIMS
|
|
1547
1701
|
server_response_thread.join
|
1548
1702
|
end
|
1549
1703
|
|
1550
|
-
|
1704
|
+
last_res = []
|
1551
1705
|
if (line) then
|
1552
1706
|
line.chomp!("\n")
|
1553
1707
|
line.chomp!("\r")
|
1554
1708
|
if (line.upcase == "DONE") then
|
1555
1709
|
@logger.info('idle terminated.')
|
1556
|
-
|
1710
|
+
last_res << "#{tag} OK IDLE terminated\r\n"
|
1557
1711
|
else
|
1558
1712
|
@logger.warn('unexpected client response and idle terminated.')
|
1559
1713
|
@logger.debug("unexpected client response data: #{line}") if @logger.debug?
|
1560
|
-
|
1714
|
+
last_res << "#{tag} BAD unexpected client response\r\n"
|
1561
1715
|
end
|
1562
1716
|
else
|
1563
1717
|
@logger.warn('unexpected client connection close and idle terminated.')
|
1564
|
-
|
1718
|
+
last_res << "#{tag} BAD unexpected client connection close\r\n"
|
1565
1719
|
end
|
1566
|
-
yield(
|
1720
|
+
yield(last_res)
|
1567
1721
|
end
|
1568
1722
|
imap_command_selected :idle, exclusive: nil
|
1569
1723
|
end
|
@@ -1573,6 +1727,7 @@ module RIMS
|
|
1573
1727
|
@parent_decoder = parent_decoder
|
1574
1728
|
@engine = engine
|
1575
1729
|
@token = nil
|
1730
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder#initialize at #{self}") if @logger.debug?
|
1576
1731
|
end
|
1577
1732
|
|
1578
1733
|
def auth?
|
@@ -1583,43 +1738,57 @@ module RIMS
|
|
1583
1738
|
! @token.nil?
|
1584
1739
|
end
|
1585
1740
|
|
1586
|
-
|
1741
|
+
# `not_cleanup_parent' keyword argument is defined for MailDeliveryDecoder
|
1742
|
+
def cleanup(not_cleanup_parent: false)
|
1743
|
+
@logger.debug("RIMS::Protocol::UserMailboxDecoder#cleanup at #{self}") if @logger.debug?
|
1744
|
+
|
1587
1745
|
unless (@engine.nil?) then
|
1588
1746
|
begin
|
1589
1747
|
@engine.cleanup(@token)
|
1590
1748
|
ensure
|
1591
1749
|
@token = nil
|
1592
1750
|
end
|
1751
|
+
end
|
1593
1752
|
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1753
|
+
unless (not_cleanup_parent) then
|
1754
|
+
unless (@engine.nil?) then
|
1755
|
+
begin
|
1756
|
+
@engine.destroy
|
1757
|
+
ensure
|
1758
|
+
@engine = nil
|
1759
|
+
end
|
1598
1760
|
end
|
1599
|
-
end
|
1600
1761
|
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1762
|
+
unless (@parent_decoder.nil?) then
|
1763
|
+
@parent_decoder.cleanup
|
1764
|
+
@parent_decoder = nil
|
1765
|
+
end
|
1604
1766
|
end
|
1605
1767
|
|
1606
1768
|
nil
|
1607
1769
|
end
|
1608
1770
|
|
1609
|
-
def noop(tag
|
1610
|
-
|
1771
|
+
def noop(tag)
|
1772
|
+
ret_val = nil
|
1773
|
+
@engine.noop(@token, tag) {|res|
|
1774
|
+
for response in res
|
1775
|
+
ret_val = yield(response)
|
1776
|
+
end
|
1777
|
+
}
|
1778
|
+
|
1779
|
+
ret_val
|
1611
1780
|
end
|
1612
1781
|
imap_command :noop
|
1613
1782
|
|
1614
|
-
def logout(tag)
|
1783
|
+
def logout(tag, &block)
|
1615
1784
|
if (@token) then
|
1616
1785
|
old_token = @token
|
1617
1786
|
@token = nil
|
1618
1787
|
@engine.cleanup(old_token)
|
1619
1788
|
end
|
1620
1789
|
|
1621
|
-
@next_decoder = LogoutDecoder.new(self)
|
1622
|
-
|
1790
|
+
@next_decoder = LogoutDecoder.new(self, @logger)
|
1791
|
+
make_logout_response(tag, &block)
|
1623
1792
|
end
|
1624
1793
|
imap_command :logout
|
1625
1794
|
|
@@ -1627,7 +1796,9 @@ module RIMS
|
|
1627
1796
|
ret_val = nil
|
1628
1797
|
old_token = @token
|
1629
1798
|
@token = @engine.select(old_token, tag, mbox_name) {|res|
|
1630
|
-
|
1799
|
+
for response in res
|
1800
|
+
ret_val = yield(response)
|
1801
|
+
end
|
1631
1802
|
}
|
1632
1803
|
|
1633
1804
|
ret_val
|
@@ -1638,134 +1809,225 @@ module RIMS
|
|
1638
1809
|
ret_val = nil
|
1639
1810
|
old_token = @token
|
1640
1811
|
@token = @engine.examine(old_token, tag, mbox_name) {|res|
|
1641
|
-
|
1812
|
+
for response in res
|
1813
|
+
ret_val = yield(response)
|
1814
|
+
end
|
1642
1815
|
}
|
1643
1816
|
|
1644
1817
|
ret_val
|
1645
1818
|
end
|
1646
1819
|
imap_command :examine
|
1647
1820
|
|
1648
|
-
def create(tag, mbox_name
|
1649
|
-
|
1821
|
+
def create(tag, mbox_name)
|
1822
|
+
ret_val = nil
|
1823
|
+
@engine.create(@token, tag, mbox_name) {|res|
|
1824
|
+
for response in res
|
1825
|
+
ret_val = yield(response)
|
1826
|
+
end
|
1827
|
+
}
|
1828
|
+
|
1829
|
+
ret_val
|
1650
1830
|
end
|
1651
1831
|
imap_command :create
|
1652
1832
|
|
1653
|
-
def delete(tag, mbox_name
|
1654
|
-
|
1833
|
+
def delete(tag, mbox_name)
|
1834
|
+
ret_val = nil
|
1835
|
+
@engine.delete(@token, tag, mbox_name) {|res|
|
1836
|
+
for response in res
|
1837
|
+
ret_val = yield(response)
|
1838
|
+
end
|
1839
|
+
}
|
1840
|
+
|
1841
|
+
ret_val
|
1655
1842
|
end
|
1656
1843
|
imap_command :delete
|
1657
1844
|
|
1658
|
-
def rename(tag, src_name, dst_name
|
1659
|
-
|
1845
|
+
def rename(tag, src_name, dst_name)
|
1846
|
+
ret_val = nil
|
1847
|
+
@engine.rename(@token, tag, src_name, dst_name) {|res|
|
1848
|
+
for response in res
|
1849
|
+
ret_val = yield(response)
|
1850
|
+
end
|
1851
|
+
}
|
1852
|
+
|
1853
|
+
ret_val
|
1660
1854
|
end
|
1661
1855
|
imap_command :rename
|
1662
1856
|
|
1663
|
-
def subscribe(tag, mbox_name
|
1664
|
-
|
1857
|
+
def subscribe(tag, mbox_name)
|
1858
|
+
ret_val = nil
|
1859
|
+
@engine.subscribe(@token, tag, mbox_name) {|res|
|
1860
|
+
for response in res
|
1861
|
+
ret_val = yield(response)
|
1862
|
+
end
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
ret_val
|
1665
1866
|
end
|
1666
1867
|
imap_command :subscribe
|
1667
1868
|
|
1668
|
-
def unsubscribe(tag, mbox_name
|
1669
|
-
|
1869
|
+
def unsubscribe(tag, mbox_name)
|
1870
|
+
ret_val = nil
|
1871
|
+
@engine.unsubscribe(@token, tag, mbox_name) {|res|
|
1872
|
+
for response in res
|
1873
|
+
ret_val = yield(response)
|
1874
|
+
end
|
1875
|
+
}
|
1876
|
+
|
1877
|
+
ret_val
|
1670
1878
|
end
|
1671
1879
|
imap_command :unsubscribe
|
1672
1880
|
|
1673
|
-
def list(tag, ref_name, mbox_name
|
1674
|
-
|
1881
|
+
def list(tag, ref_name, mbox_name)
|
1882
|
+
ret_val = nil
|
1883
|
+
@engine.list(@token, tag, ref_name, mbox_name) {|res|
|
1884
|
+
for response in res
|
1885
|
+
ret_val = yield(response)
|
1886
|
+
end
|
1887
|
+
}
|
1888
|
+
|
1889
|
+
ret_val
|
1675
1890
|
end
|
1676
1891
|
imap_command :list
|
1677
1892
|
|
1678
|
-
def lsub(tag, ref_name, mbox_name
|
1679
|
-
|
1893
|
+
def lsub(tag, ref_name, mbox_name)
|
1894
|
+
ret_val = nil
|
1895
|
+
@engine.lsub(@token, tag, ref_name, mbox_name) {|res|
|
1896
|
+
for response in res
|
1897
|
+
ret_val = yield(response)
|
1898
|
+
end
|
1899
|
+
}
|
1900
|
+
|
1901
|
+
ret_val
|
1680
1902
|
end
|
1681
1903
|
imap_command :lsub
|
1682
1904
|
|
1683
|
-
def status(tag, mbox_name, data_item_group
|
1684
|
-
|
1905
|
+
def status(tag, mbox_name, data_item_group)
|
1906
|
+
ret_val = nil
|
1907
|
+
@engine.status(@token, tag, mbox_name, data_item_group) {|res|
|
1908
|
+
for response in res
|
1909
|
+
ret_val = yield(response)
|
1910
|
+
end
|
1911
|
+
}
|
1912
|
+
|
1913
|
+
ret_val
|
1685
1914
|
end
|
1686
1915
|
imap_command :status
|
1687
1916
|
|
1688
|
-
def append(tag, mbox_name, *opt_args, msg_text
|
1689
|
-
|
1917
|
+
def append(tag, mbox_name, *opt_args, msg_text)
|
1918
|
+
ret_val = nil
|
1919
|
+
@engine.append(@token, tag, mbox_name, *opt_args, msg_text) {|res|
|
1920
|
+
for response in res
|
1921
|
+
ret_val = yield(response)
|
1922
|
+
end
|
1923
|
+
}
|
1924
|
+
|
1925
|
+
ret_val
|
1690
1926
|
end
|
1691
1927
|
imap_command :append
|
1692
1928
|
|
1693
|
-
def check(tag
|
1694
|
-
|
1929
|
+
def check(tag)
|
1930
|
+
ret_val = nil
|
1931
|
+
@engine.check(@token, tag) {|res|
|
1932
|
+
for response in res
|
1933
|
+
ret_val = yield(response)
|
1934
|
+
end
|
1935
|
+
}
|
1936
|
+
|
1937
|
+
ret_val
|
1695
1938
|
end
|
1696
1939
|
imap_command :check
|
1697
1940
|
|
1698
|
-
def close(tag
|
1941
|
+
def close(tag)
|
1942
|
+
ret_val = nil
|
1699
1943
|
old_token = @token
|
1700
1944
|
@token = nil
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
res << r
|
1706
|
-
end
|
1707
|
-
}
|
1945
|
+
@engine.close(old_token, tag) {|res|
|
1946
|
+
for response in res
|
1947
|
+
ret_val = yield(response)
|
1948
|
+
end
|
1708
1949
|
}
|
1950
|
+
|
1951
|
+
ret_val
|
1709
1952
|
end
|
1710
1953
|
imap_command :close
|
1711
1954
|
|
1712
1955
|
def expunge(tag)
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
}
|
1956
|
+
ret_val = nil
|
1957
|
+
@engine.expunge(@token, tag) {|res|
|
1958
|
+
for response in res
|
1959
|
+
ret_val = yield(response)
|
1960
|
+
end
|
1719
1961
|
}
|
1962
|
+
|
1963
|
+
ret_val
|
1720
1964
|
end
|
1721
1965
|
imap_command :expunge
|
1722
1966
|
|
1723
1967
|
def search(tag, *cond_args, uid: false)
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
}
|
1968
|
+
ret_val = nil
|
1969
|
+
@engine.search(@token, tag, *cond_args, uid: uid) {|res|
|
1970
|
+
for response in res
|
1971
|
+
ret_val = yield(response)
|
1972
|
+
end
|
1730
1973
|
}
|
1974
|
+
|
1975
|
+
ret_val
|
1731
1976
|
end
|
1732
1977
|
imap_command :search
|
1733
1978
|
|
1734
1979
|
def fetch(tag, msg_set, data_item_group, uid: false)
|
1735
|
-
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1740
|
-
}
|
1980
|
+
ret_val = nil
|
1981
|
+
@engine.fetch(@token, tag, msg_set, data_item_group, uid: uid) {|res|
|
1982
|
+
for response in res
|
1983
|
+
ret_val = yield(response)
|
1984
|
+
end
|
1741
1985
|
}
|
1986
|
+
|
1987
|
+
ret_val
|
1742
1988
|
end
|
1743
1989
|
imap_command :fetch
|
1744
1990
|
|
1745
1991
|
def store(tag, msg_set, data_item_name, data_item_value, uid: false)
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
}
|
1992
|
+
ret_val = nil
|
1993
|
+
@engine.store(@token, tag, msg_set, data_item_name, data_item_value, uid: uid) {|res|
|
1994
|
+
for response in res
|
1995
|
+
ret_val = yield(response)
|
1996
|
+
end
|
1752
1997
|
}
|
1998
|
+
|
1999
|
+
ret_val
|
1753
2000
|
end
|
1754
2001
|
imap_command :store
|
1755
2002
|
|
1756
|
-
def copy(tag, msg_set, mbox_name, uid: false
|
1757
|
-
|
2003
|
+
def copy(tag, msg_set, mbox_name, uid: false)
|
2004
|
+
ret_val = nil
|
2005
|
+
@engine.copy(@token, tag, msg_set, mbox_name, uid: uid) {|res|
|
2006
|
+
for response in res
|
2007
|
+
ret_val = yield(response)
|
2008
|
+
end
|
2009
|
+
}
|
2010
|
+
|
2011
|
+
ret_val
|
1758
2012
|
end
|
1759
2013
|
imap_command :copy
|
1760
2014
|
|
1761
|
-
def idle(tag, client_input_gets, server_output_write, connection_timer
|
1762
|
-
|
2015
|
+
def idle(tag, client_input_gets, server_output_write, connection_timer)
|
2016
|
+
ret_val = nil
|
2017
|
+
@engine.idle(@token, tag, client_input_gets, server_output_write, connection_timer) {|res|
|
2018
|
+
for response in res
|
2019
|
+
ret_val = yield(response)
|
2020
|
+
end
|
2021
|
+
}
|
2022
|
+
|
2023
|
+
ret_val
|
1763
2024
|
end
|
1764
2025
|
imap_command :idle
|
1765
2026
|
end
|
1766
2027
|
|
1767
2028
|
# alias
|
1768
|
-
Decoder::Engine
|
2029
|
+
Decoder::Engine = UserMailboxDecoder::Engine
|
2030
|
+
Decoder::BulkResponse = UserMailboxDecoder::BulkResponse
|
1769
2031
|
|
1770
2032
|
def Decoder.encode_delivery_target_mailbox(username, mbox_name)
|
1771
2033
|
"b64user-mbox #{Protocol.encode_base64(username)} #{mbox_name}"
|
@@ -1787,6 +2049,7 @@ module RIMS
|
|
1787
2049
|
@auth = auth
|
1788
2050
|
@last_user_cache_key_username = nil
|
1789
2051
|
@last_user_cache_value_engine = nil
|
2052
|
+
@logger.debug("RIMS::Protocol::MailDeliveryDecoder#initialize at #{self}") if @logger.debug?
|
1790
2053
|
end
|
1791
2054
|
|
1792
2055
|
def engine_cached?(username)
|
@@ -1834,6 +2097,8 @@ module RIMS
|
|
1834
2097
|
end
|
1835
2098
|
|
1836
2099
|
def cleanup
|
2100
|
+
@logger.debug("RIMS::Protocol::MailDeliveryDecoder#cleanup at #{self}") if @logger.debug?
|
2101
|
+
|
1837
2102
|
release_engine_cache
|
1838
2103
|
@drb_services = nil unless @drb_services.nil?
|
1839
2104
|
@auth = nil unless @auth.nil?
|
@@ -1846,9 +2111,9 @@ module RIMS
|
|
1846
2111
|
nil
|
1847
2112
|
end
|
1848
2113
|
|
1849
|
-
def logout(tag)
|
1850
|
-
@next_decoder = LogoutDecoder.new(self)
|
1851
|
-
|
2114
|
+
def logout(tag, &block)
|
2115
|
+
@next_decoder = LogoutDecoder.new(self, @logger)
|
2116
|
+
make_logout_response(tag, &block)
|
1852
2117
|
end
|
1853
2118
|
imap_command :logout
|
1854
2119
|
|
@@ -1856,85 +2121,87 @@ module RIMS
|
|
1856
2121
|
private :standard_capability
|
1857
2122
|
|
1858
2123
|
def capability(tag)
|
1859
|
-
standard_capability(tag) {|
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
end
|
1866
|
-
}
|
2124
|
+
standard_capability(tag) {|response|
|
2125
|
+
if (response.start_with? '* CAPABILITY ') then
|
2126
|
+
yield(response.strip + " X-RIMS-MAIL-DELIVERY-USER\r\n")
|
2127
|
+
else
|
2128
|
+
yield(response)
|
2129
|
+
end
|
1867
2130
|
}
|
1868
2131
|
end
|
1869
2132
|
imap_command :capability
|
1870
2133
|
|
1871
2134
|
def make_not_allowed_command_response(tag)
|
1872
|
-
|
2135
|
+
yield("#{tag} NO not allowed command on mail delivery user\r\n")
|
1873
2136
|
end
|
1874
2137
|
private :make_not_allowed_command_response
|
1875
2138
|
|
1876
|
-
def select(tag, mbox_name)
|
1877
|
-
|
2139
|
+
def select(tag, mbox_name, &block)
|
2140
|
+
make_not_allowed_command_response(tag, &block)
|
1878
2141
|
end
|
1879
2142
|
imap_command :select
|
1880
2143
|
|
1881
|
-
def examine(tag, mbox_name)
|
1882
|
-
|
2144
|
+
def examine(tag, mbox_name, &block)
|
2145
|
+
make_not_allowed_command_response(tag, &block)
|
1883
2146
|
end
|
1884
2147
|
imap_command :examine
|
1885
2148
|
|
1886
|
-
def create(tag, mbox_name)
|
1887
|
-
|
2149
|
+
def create(tag, mbox_name, &block)
|
2150
|
+
make_not_allowed_command_response(tag, &block)
|
1888
2151
|
end
|
1889
2152
|
imap_command :create
|
1890
2153
|
|
1891
|
-
def delete(tag, mbox_name)
|
1892
|
-
|
2154
|
+
def delete(tag, mbox_name, &block)
|
2155
|
+
make_not_allowed_command_response(tag, &block)
|
1893
2156
|
end
|
1894
2157
|
imap_command :delete
|
1895
2158
|
|
1896
|
-
def rename(tag, src_name, dst_name)
|
1897
|
-
|
2159
|
+
def rename(tag, src_name, dst_name, &block)
|
2160
|
+
make_not_allowed_command_response(tag, &block)
|
1898
2161
|
end
|
1899
2162
|
imap_command :rename
|
1900
2163
|
|
1901
|
-
def subscribe(tag, mbox_name)
|
1902
|
-
|
2164
|
+
def subscribe(tag, mbox_name, &block)
|
2165
|
+
make_not_allowed_command_response(tag, &block)
|
1903
2166
|
end
|
1904
2167
|
imap_command :subscribe
|
1905
2168
|
|
1906
|
-
def unsubscribe(tag, mbox_name)
|
1907
|
-
|
2169
|
+
def unsubscribe(tag, mbox_name, &block)
|
2170
|
+
make_not_allowed_command_response(tag, &block)
|
1908
2171
|
end
|
1909
2172
|
imap_command :unsubscribe
|
1910
2173
|
|
1911
|
-
def list(tag, ref_name, mbox_name)
|
1912
|
-
|
2174
|
+
def list(tag, ref_name, mbox_name, &block)
|
2175
|
+
make_not_allowed_command_response(tag, &block)
|
1913
2176
|
end
|
1914
2177
|
imap_command :list
|
1915
2178
|
|
1916
|
-
def lsub(tag, ref_name, mbox_name)
|
1917
|
-
|
2179
|
+
def lsub(tag, ref_name, mbox_name, &block)
|
2180
|
+
make_not_allowed_command_response(tag, &block)
|
1918
2181
|
end
|
1919
2182
|
imap_command :lsub
|
1920
2183
|
|
1921
|
-
def status(tag, mbox_name, data_item_group)
|
1922
|
-
|
2184
|
+
def status(tag, mbox_name, data_item_group, &block)
|
2185
|
+
make_not_allowed_command_response(tag, &block)
|
1923
2186
|
end
|
1924
2187
|
imap_command :status
|
1925
2188
|
|
1926
|
-
def deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine
|
2189
|
+
def deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine)
|
1927
2190
|
user_decoder = UserMailboxDecoder.new(self, engine, @auth, @logger)
|
1928
|
-
|
1929
|
-
|
2191
|
+
begin
|
2192
|
+
last_response = nil
|
2193
|
+
user_decoder.append(tag, mbox_name, *opt_args, msg_text) {|response|
|
2194
|
+
last_response = response
|
2195
|
+
yield(response)
|
2196
|
+
}
|
2197
|
+
if (last_response.split(' ', 3)[1] == 'OK') then
|
1930
2198
|
@logger.info("message delivery: successed to deliver #{msg_text.bytesize} octets message.")
|
1931
2199
|
else
|
1932
2200
|
@logger.info("message delivery: failed to deliver message.")
|
1933
2201
|
end
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1937
|
-
}
|
2202
|
+
ensure
|
2203
|
+
user_decoder.cleanup(not_cleanup_parent: true)
|
2204
|
+
end
|
1938
2205
|
end
|
1939
2206
|
private :deliver_to_user
|
1940
2207
|
|
@@ -1944,62 +2211,65 @@ module RIMS
|
|
1944
2211
|
|
1945
2212
|
if (@auth.user? username) then
|
1946
2213
|
if (engine_cached? username) then
|
1947
|
-
res = []
|
1948
2214
|
engine = engine_cache(username)
|
1949
|
-
deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine
|
2215
|
+
deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine) {|response|
|
2216
|
+
yield(response)
|
2217
|
+
}
|
1950
2218
|
else
|
1951
|
-
|
1952
|
-
|
1953
|
-
|
2219
|
+
engine = store_engine_cache(username) {
|
2220
|
+
self.class.make_engine_and_recovery_if_needed(@drb_services, username, logger: @logger) {|untagged_response|
|
2221
|
+
yield(untagged_response)
|
2222
|
+
yield(:flush)
|
1954
2223
|
}
|
1955
|
-
|
2224
|
+
}
|
2225
|
+
deliver_to_user(tag, username, mbox_name, opt_args, msg_text, engine) {|response|
|
2226
|
+
yield(response)
|
1956
2227
|
}
|
1957
2228
|
end
|
1958
|
-
yield(res)
|
1959
2229
|
else
|
1960
2230
|
@logger.info('message delivery: not found a user.')
|
1961
|
-
yield(
|
2231
|
+
yield("#{tag} NO not found a user and couldn't deliver a message to the user's mailbox\r\n")
|
1962
2232
|
end
|
1963
2233
|
end
|
1964
2234
|
imap_command :append
|
1965
2235
|
|
1966
|
-
def check(tag)
|
1967
|
-
|
2236
|
+
def check(tag, &block)
|
2237
|
+
make_not_allowed_command_response(tag, &block)
|
1968
2238
|
end
|
1969
2239
|
imap_command :check
|
1970
2240
|
|
1971
|
-
def close(tag)
|
1972
|
-
|
2241
|
+
def close(tag, &block)
|
2242
|
+
make_not_allowed_command_response(tag, &block)
|
1973
2243
|
end
|
1974
2244
|
imap_command :close
|
1975
2245
|
|
1976
|
-
def expunge(tag)
|
1977
|
-
|
2246
|
+
def expunge(tag, &block)
|
2247
|
+
make_not_allowed_command_response(tag, &block)
|
1978
2248
|
end
|
1979
2249
|
imap_command :expunge
|
1980
2250
|
|
1981
|
-
def search(tag, *cond_args, uid: false)
|
1982
|
-
|
2251
|
+
def search(tag, *cond_args, uid: false, &block)
|
2252
|
+
make_not_allowed_command_response(tag, &block)
|
1983
2253
|
end
|
1984
2254
|
imap_command :search
|
1985
2255
|
|
1986
|
-
def fetch(tag, msg_set, data_item_group, uid: false)
|
1987
|
-
|
2256
|
+
def fetch(tag, msg_set, data_item_group, uid: false, &block)
|
2257
|
+
make_not_allowed_command_response(tag, &block)
|
1988
2258
|
end
|
1989
2259
|
imap_command :fetch
|
1990
2260
|
|
1991
|
-
def store(tag, msg_set, data_item_name, data_item_value, uid: false)
|
1992
|
-
|
2261
|
+
def store(tag, msg_set, data_item_name, data_item_value, uid: false, &block)
|
2262
|
+
make_not_allowed_command_response(tag, &block)
|
1993
2263
|
end
|
1994
2264
|
imap_command :store
|
1995
2265
|
|
1996
|
-
def copy(tag, msg_set, mbox_name, uid: false)
|
1997
|
-
|
2266
|
+
def copy(tag, msg_set, mbox_name, uid: false, &block)
|
2267
|
+
make_not_allowed_command_response(tag, &block)
|
1998
2268
|
end
|
1999
2269
|
imap_command :copy
|
2000
2270
|
|
2001
|
-
def idle(tag, client_input_gets, server_output_write, connection_timer)
|
2002
|
-
|
2271
|
+
def idle(tag, client_input_gets, server_output_write, connection_timer, &block)
|
2272
|
+
make_not_allowed_command_response(tag, &block)
|
2003
2273
|
end
|
2004
2274
|
imap_command :idle
|
2005
2275
|
end
|