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.
@@ -38,8 +38,7 @@ module RIMS
38
38
  module_function :message_data_list
39
39
 
40
40
  def make_body(description)
41
- reader = RIMS::Protocol::RequestReader.new(StringIO.new('', 'r'), StringIO.new('', 'w'), Logger.new(STDOUT))
42
- reader.parse(reader.scan_line(description))[0]
41
+ RIMS::Protocol::RequestReader.parse(RIMS::Protocol::RequestReader.scan(description))[0]
43
42
  end
44
43
  private :make_body
45
44
 
@@ -68,29 +67,30 @@ module RIMS
68
67
  end
69
68
 
70
69
  module ProtocolFetchMailSample
71
- def make_mail_simple
72
- @simple_mail_body = <<-'EOF'
70
+ simple_mail_body = <<-'EOF'.freeze
73
71
  Hello world.
74
- EOF
72
+ EOF
75
73
 
76
- md5_digest = Digest::MD5.digest(@simple_mail_body)
77
- @simple_mail = RIMS::RFC822::Message.new(<<-"EOF" + @simple_mail_body)
74
+ MAIL_SIMPLE_TEXT = (<<-"EOF" + simple_mail_body).freeze
78
75
  To: foo@nonet.org
79
76
  From: bar@nonet.org
80
77
  Subject: test
81
78
  MIME-Version: 1.0
82
79
  Content-Type: text/plain; charset=us-ascii
83
80
  Content-Transfer-Encoding: 7bit
84
- Content-MD5: #{[ md5_digest ].pack('m').strip}
81
+ Content-MD5: #{[ Digest::MD5.digest(simple_mail_body) ].pack('m').strip}
85
82
  Content-Language: en-US, en
86
83
  Date: Fri, 8 Nov 2013 06:47:50 +0900 (JST)
87
84
 
88
- EOF
85
+ EOF
86
+
87
+ def make_mail_simple
88
+ @simple_mail = RIMS::RFC822::Message.new(MAIL_SIMPLE_TEXT)
89
+ @simple_mail_body = @simple_mail.body.raw_source
89
90
  end
90
91
  private :make_mail_simple
91
92
 
92
- def make_mail_multipart
93
- @mpart_mail = RIMS::RFC822::Message.new(<<-'EOF')
93
+ MPART_MAIL_TEXT = <<-'EOF'.freeze
94
94
  To: bar@nonet.com
95
95
  From: foo@nonet.com
96
96
  Subject: multipart test
@@ -173,12 +173,14 @@ Content-Location: baz
173
173
  --1383.905529.351300--
174
174
  --1383.905529.351299--
175
175
  --1383.905529.351297--
176
- EOF
176
+ EOF
177
+
178
+ def make_mail_multipart
179
+ @mpart_mail = RIMS::RFC822::Message.new(MPART_MAIL_TEXT)
177
180
  end
178
181
  private :make_mail_multipart
179
182
 
180
- def make_mail_mime_subject
181
- @mime_subject_mail = RIMS::RFC822::Message.new(<<-'EOF')
183
+ MAIL_MIME_SUBJECT_TEXT = <<-'EOF'.freeze
182
184
  Date: Fri, 8 Nov 2013 19:31:03 +0900
183
185
  Subject: =?ISO-2022-JP?B?GyRCJEYkOSRIGyhC?=
184
186
  From: foo@nonet.com, bar <bar@nonet.com>
@@ -194,22 +196,28 @@ In-Reply-To: <20131106081723.5KJU1774292@smtp.test.com>
194
196
  Message-Id: <20131107214750.445A1255B9F@smtp.nonet.com>
195
197
 
196
198
  Hello world.
197
- EOF
199
+ EOF
200
+
201
+ def make_mail_mime_subject
202
+ @mime_subject_mail = RIMS::RFC822::Message.new(MAIL_MIME_SUBJECT_TEXT)
198
203
  end
199
204
  private :make_mail_mime_subject
200
205
 
206
+ MAIL_EMPTY_TEXT = ''.freeze
207
+
201
208
  def make_mail_empty
202
- @empty_mail = RIMS::RFC822::Message.new('')
209
+ @empty_mail = RIMS::RFC822::Message.new(MAIL_EMPTY_TEXT)
203
210
  end
204
211
  private :make_mail_empty
205
212
 
213
+ MAIL_NO_BODY_TEXT = "Subject: foo\r\n\r\n".freeze
214
+
206
215
  def make_mail_no_body
207
- @no_body_mail = RIMS::RFC822::Message.new("Subject: foo\r\n\r\n")
216
+ @no_body_mail = RIMS::RFC822::Message.new(MAIL_NO_BODY_TEXT)
208
217
  end
209
218
  private :make_mail_no_body
210
219
 
211
- def make_mail_address_header_pattern
212
- @address_header_pattern_mail = RIMS::RFC822::Message.new(<<-'EOF')
220
+ MAIL_ADDRESS_HEADER_PATTERN_TEXT = <<-'EOF'.freeze
213
221
  To: "foo@nonet.org" <foo@nonet.org>
214
222
  From: bar@nonet.org
215
223
  Subject: test
@@ -219,7 +227,10 @@ Content-Transfer-Encoding: 7bit
219
227
  Date: Fri, 8 Nov 2013 06:47:50 +0900 (JST)
220
228
 
221
229
  Hello world.
222
- EOF
230
+ EOF
231
+
232
+ def make_mail_address_header_pattern
233
+ @address_header_pattern_mail = RIMS::RFC822::Message.new(MAIL_ADDRESS_HEADER_PATTERN_TEXT)
223
234
  end
224
235
  private :make_mail_address_header_pattern
225
236
  end
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module RIMS
4
- VERSION = '0.2.6'
4
+ VERSION = '0.3.1'
5
5
  MAILBOX_DATA_STRUCTURE_VERSION = 'mailbox.2'
6
6
  end
7
7
 
@@ -78,6 +78,8 @@ task :imap_append do
78
78
  end
79
79
  end
80
80
 
81
+ CLOBBER.include('imap_append')
82
+
81
83
  desc 'run server'
82
84
  task :run_server do
83
85
  run_server_conf('imap_server', USER_CONF, *%w[ -v debug -l debug --imap-host=localhost --imap-port=14300 ]) do
@@ -85,7 +87,7 @@ task :run_server do
85
87
  end
86
88
  end
87
89
 
88
- CLOBBER.include('imap_append')
90
+ CLOBBER.include('imap_server')
89
91
 
90
92
  # Local Variables:
91
93
  # mode: Ruby
@@ -5,10 +5,10 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'rims/version'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.name = "rims"
8
+ spec.name = 'rims'
9
9
  spec.version = RIMS::VERSION
10
- spec.authors = ["TOKI Yoshinori"]
11
- spec.email = ["toki@freedom.ne.jp"]
10
+ spec.authors = ['TOKI Yoshinori']
11
+ spec.email = ['toki@freedom.ne.jp']
12
12
  spec.summary = %q{RIMS is Ruby IMap Server}
13
13
  spec.description = <<-'EOF'
14
14
  RIMS is Ruby IMap Server.
@@ -16,23 +16,24 @@ Gem::Specification.new do |spec|
16
16
  server can run as a daemon, mailboxes are provided and messages
17
17
  can be delivered to them.
18
18
  EOF
19
- spec.homepage = "https://github.com/y10k/rims"
20
- spec.license = "MIT"
19
+ spec.homepage = 'https://github.com/y10k/rims'
20
+ spec.license = 'MIT'
21
21
 
22
22
  spec.files = `git ls-files`.split($/)
23
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
25
- spec.require_paths = ["lib"]
25
+ spec.require_paths = ['lib']
26
26
 
27
27
  spec.required_ruby_version = '>= 2.0.0'
28
28
 
29
- spec.add_runtime_dependency "rims-rfc822", '>= 0.2.0'
30
- spec.add_runtime_dependency "riser", '>= 0.1.8'
31
- spec.add_runtime_dependency "logger-joint"
32
- spec.add_development_dependency "bundler"
33
- spec.add_development_dependency "rake"
34
- spec.add_development_dependency "test-unit"
35
- spec.add_development_dependency "rdoc"
29
+ spec.add_runtime_dependency 'rims-rfc822', '>= 0.2.2'
30
+ spec.add_runtime_dependency 'riser', '>= 0.2.0'
31
+ spec.add_runtime_dependency 'logger-joint'
32
+ spec.add_development_dependency 'bundler'
33
+ spec.add_development_dependency 'rake'
34
+ spec.add_development_dependency 'test-unit'
35
+ spec.add_development_dependency 'rdoc'
36
+ spec.add_development_dependency 'irb'
36
37
  end
37
38
 
38
39
  # Local Variables:
@@ -119,6 +119,7 @@ module RIMS::Test
119
119
  '--no-daemonize' => [ %W[ -f #{BASE_DIR}/config.yml --no-daemonize ] ],
120
120
  '--daemon-debug' => [ %W[ -f #{BASE_DIR}/config.yml --daemon-debug ] ],
121
121
  '--no-daemon-debug' => [ %W[ -f #{BASE_DIR}/config.yml --no-daemon-debug ] ],
122
+ '--daemon-umask' => [ %W[ -f #{BASE_DIR}/config.yml --daemon-umask=0022 ] ],
122
123
  '--status-file' => [ %W[ -f #{BASE_DIR}/config.yml --status-file=status.yml ] ],
123
124
  '--privilege-user' => [ %W[ -f #{BASE_DIR}/config.yml --privilege-user=#{Process::UID.eid} ] ],
124
125
  '--privilege-group' => [ %W[ -f #{BASE_DIR}/config.yml --privilege-group=#{Process::GID.eid} ] ],
@@ -140,11 +141,30 @@ module RIMS::Test
140
141
  '--read-polling-interval' => [ %W[ -f #{BASE_DIR}/config.yml --read-polling-interval=5 ] ],
141
142
  '--command-wait-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --command-wait-timeout=3600 ] ],
142
143
 
144
+ # protocol:
145
+ '--line-length-limit' => [ %W[ -f #{BASE_DIR}/config.yml --line-length-limit=16384 ] ],
146
+ '--literal-size-limit' => [ %W[ -f #{BASE_DIR}/config.yml --literal-size-limit=16777216 ] ],
147
+ '--command-size-limit' => [ %W[ -f #{BASE_DIR}/config.yml --command-size-limit=16777216 ] ],
148
+
149
+ # charset aliases:
150
+ '--use-default-charset-aliases' => [ %W[ -f #{BASE_DIR}/config.yml --use-default-charset-aliases ] ],
151
+ '--no-use-default-charset-aliases' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-default-charset-aliases ] ],
152
+ '--add-charset-alias' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-default-charset-aliases --add-charset-alias=iso-2022-jp,CP50221 ] ],
153
+
154
+ # charset convert_options:
155
+ '--replace-charset-invalid' => [ %W[ -f #{BASE_DIR}/config.yml --replace-charset-invalid ] ],
156
+ '--no-replace-charset-invalid' => [ %W[ -f #{BASE_DIR}/config.yml --no-replace-charset-invalid ] ],
157
+ '--replace-charset-undef' => [ %W[ -f #{BASE_DIR}/config.yml --replace-charset-undef ] ],
158
+ '--no-replace-charset-undef' => [ %W[ -f #{BASE_DIR}/config.yml --no-replace-charset-undef ] ],
159
+ '--charset-replaced-mark' => [ %W[ -f #{BASE_DIR}/config.yml --charset-replaced-mark=? ] ],
160
+
143
161
  # drb_services:
144
162
  '--drb-process-num' => [ %W[ -f #{BASE_DIR}/config.yml --drb-process-num=4 ] ],
163
+ '--drb-load-limit' => [ %W[ -f #{BASE_DIR}/config.yml --drb-load-limit=134217728 ] ],
145
164
 
146
165
  # drb_services engine:
147
166
  '--bulk-response-count' => [ %W[ -f #{BASE_DIR}/config.yml --bulk-response-count=128 ] ],
167
+ '--bulk-response-size' => [ %W[ -f #{BASE_DIR}/config.yml --bulk-response-size=33554432 ] ],
148
168
  '--read-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --read-lock-timeout=10 ] ],
149
169
  '--write-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --write-lock-timeout=10 ] ],
150
170
  '--clenup-write-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --write-lock-timeout=5 ] ],
@@ -1232,7 +1252,7 @@ Hello world.
1232
1252
  assert_equal(seqno[1], imap_search.call([ 'ANSWERED' ])) # *a
1233
1253
  assert_equal(seqno[3], imap_search.call([ 'BCC', 'foo' ])) # *b
1234
1254
  assert_equal(seqno[1], imap_search.call([ 'BEFORE', @mpart_mail.date ]))
1235
- assert_equal(seqno[1, 3], imap_search.call([ 'BODY', 'Hello world.' ]))
1255
+ assert_equal(seqno[1, 2, 3], imap_search.call([ 'BODY', 'Hello world.' ]))
1236
1256
  assert_equal(seqno[3], imap_search.call([ 'CC', 'kate' ]))
1237
1257
  assert_equal(seqno[], imap_search.call([ 'DELETED' ]))
1238
1258
  assert_equal(seqno[2], imap_search.call([ 'DRAFT' ]))
@@ -55,7 +55,8 @@ module RIMS::Test
55
55
  pub1.publish('msg1')
56
56
  pub2.publish('msg2')
57
57
 
58
- error = assert_raise(RuntimeError) { pub3.publish('msg3') }
58
+ error = assert_raise(RIMS::ServerResponseChannelPublishError) { pub3.publish('msg3') }
59
+ pp error, error.optional_data if $DEBUG
59
60
  assert_match(/detached/, error.message)
60
61
 
61
62
  assert_equal(%w[ msg2 ], sub1.enum_for(:fetch).to_a)
@@ -4,7 +4,19 @@ require 'rims'
4
4
  require 'test/unit'
5
5
 
6
6
  module RIMS::Test
7
- class TestError < Test::Unit::TestCase
7
+ class ErrorTest < Test::Unit::TestCase
8
+ def test_optional_data
9
+ error = RIMS::Error.new('test', foo: 1, bar: '2')
10
+ assert_equal('test', error.message)
11
+ assert_equal({ foo: 1, bar: '2' }, error.optional_data)
12
+ end
13
+
14
+ def test_no_optional_data
15
+ error = RIMS::Error.new('test')
16
+ assert_equal('test', error.message)
17
+ assert_predicate(error.optional_data, :empty?)
18
+ end
19
+
8
20
  def test_trace_error_chain
9
21
  exception = assert_raise(RuntimeError) {
10
22
  begin
@@ -32,6 +44,26 @@ module RIMS::Test
32
44
  'error level 0'
33
45
  ], errors.map(&:message))
34
46
  end
47
+
48
+ def test_optional_data_block
49
+ count = 0
50
+ error = RIMS::Error.new('test', foo: 1, bar: '2')
51
+ RIMS::Error.optional_data(error) do |e, data|
52
+ count += 1
53
+ assert_equal(error, e)
54
+ assert_equal({ foo: 1, bar: '2' }, data)
55
+ end
56
+ assert_equal(1, count)
57
+ end
58
+
59
+ data('not a RIMS::Error' => StandardError.new('test'),
60
+ 'no optional data' => RIMS::Error.new('test'))
61
+ def test_no_optional_data_block(data)
62
+ error = data
63
+ RIMS::Error.optional_data(error) do |e, data|
64
+ flunk
65
+ end
66
+ end
35
67
  end
36
68
  end
37
69
 
@@ -51,7 +51,7 @@ module RIMS::Test
51
51
  assert_equal('write-lock wait timeout', error.message)
52
52
  end
53
53
 
54
- def calculate_threa_work_seconds
54
+ def calculate_thread_work_seconds
55
55
  t0 = Time.now
56
56
  1000.times{|i| i.succ }
57
57
  t1 = Time.now
@@ -60,10 +60,10 @@ module RIMS::Test
60
60
 
61
61
  wait_seconds
62
62
  end
63
- private :calculate_threa_work_seconds
63
+ private :calculate_thread_work_seconds
64
64
 
65
65
  def test_read_write_lock_multithread
66
- lock_wait_seconds = calculate_threa_work_seconds
66
+ lock_wait_seconds = calculate_thread_work_seconds
67
67
 
68
68
  count = 0
69
69
  read_thread_num = 10
@@ -116,7 +116,7 @@ module RIMS::Test
116
116
  def test_write_lock_timeout_detach
117
117
  logger = Logger.new(STDOUT)
118
118
  logger.level = ($DEBUG) ? Logger::DEBUG : Logger::FATAL
119
- wait_seconds = calculate_threa_work_seconds
119
+ wait_seconds = calculate_thread_work_seconds
120
120
 
121
121
  t_list = []
122
122
  assert_nil(RIMS::ReadWriteLock.write_lock_timeout_detach(wait_seconds, wait_seconds * 2, logger: logger ) {|timeout_seconds|
@@ -61,7 +61,7 @@ module RIMS::Test
61
61
  end
62
62
  end
63
63
 
64
- class PasswordHashSourceEntry < Test::Unit::TestCase
64
+ class PasswordHashSourceEntryTest < Test::Unit::TestCase
65
65
  def setup
66
66
  @digest_factory = Digest::SHA256
67
67
  @hash_type = 'SHA256'
@@ -127,6 +127,7 @@ module RIMS::Test
127
127
  cmd_name, cmd_args, cmd_client_output = parse_imap_command(tag, imap_command_message)
128
128
  normalized_cmd_name = RIMS::Protocol::Decoder.imap_command_normalize(cmd_name)
129
129
  cmd_id = RIMS::Protocol::Decoder::IMAP_CMDs[normalized_cmd_name] or flunk("not a imap command: #{cmd_name}")
130
+ cmd_kw_args = {}
130
131
 
131
132
  input = nil
132
133
  output = nil
@@ -146,32 +147,29 @@ module RIMS::Test
146
147
  cmd_args = inout_args + cmd_args
147
148
  end
148
149
  unless (uid.nil?) then
149
- cmd_args += [ { uid: uid } ]
150
+ cmd_kw_args[:uid] = uid
150
151
  end
151
152
 
152
153
  block_call = 0
153
154
  ret_val = nil
154
155
 
156
+ response_message = cmd_client_output.b
155
157
  pp [ :debug_imap_command, imap_command_message, cmd_id, cmd_args ] if $DEBUG
156
- @decoder.__send__(cmd_id, tag, *cmd_args) {|responses|
158
+ @decoder.__send__(cmd_id, tag, *cmd_args, **cmd_kw_args) {|response|
157
159
  block_call += 1
158
- response_message = cmd_client_output.b
159
- if (output) then
160
+ if (block_call == 1 && output) then
160
161
  response_message << output.string
161
162
  end
162
- for response in responses
163
- if (response != :flush) then
164
- response_message << response
165
- end
163
+ if (response != :flush) then
164
+ response_message << response
166
165
  end
167
- response_lines = StringIO.new(response_message, 'r').each_line
168
- ret_val = yield(response_lines)
169
- assert_raise(StopIteration) { response_lines.next }
170
166
  }
167
+ response_lines = StringIO.new(response_message, 'r').each_line
168
+ ret_val = yield(response_lines)
169
+ assert_raise(StopIteration) { response_lines.next }
171
170
  if (client_input_text) then
172
171
  pp input.string, output.string if $DEBUG
173
172
  end
174
- assert_equal(1, block_call, 'IMAP command block should be called only once.')
175
173
 
176
174
  @decoder = @decoder.next_decoder
177
175
 
@@ -259,8 +257,15 @@ module RIMS::Test
259
257
  end
260
258
  private :open_mail_store
261
259
 
260
+ LINE_LENGTH_LIMIT = 128
261
+ LITERAL_SIZE_LIMIT = 1024**2
262
+ COMMAND_SIZE_LIMIT = LITERAL_SIZE_LIMIT + LINE_LENGTH_LIMIT
263
+
262
264
  def make_decoder
263
- RIMS::Protocol::Decoder.new_decoder(@drb_services, @auth, @logger)
265
+ RIMS::Protocol::Decoder.new_decoder(@drb_services, @auth, @logger,
266
+ line_length_limit: LINE_LENGTH_LIMIT,
267
+ literal_size_limit: LITERAL_SIZE_LIMIT,
268
+ command_size_limit: COMMAND_SIZE_LIMIT)
264
269
  end
265
270
  private :make_decoder
266
271
 
@@ -293,13 +298,17 @@ module RIMS::Test
293
298
  @unique_user_id = RIMS::Authentication.unique_user_id('foo')
294
299
 
295
300
  @bulk_response_count = 10
301
+ @charset_aliases = RIMS::RFC822::CharsetAliases.new
302
+ @charset_convert_options = {}
296
303
  @drb_services = Riser::DRbServices.new(0)
297
304
  @drb_services.add_sticky_process_service(:engine,
298
305
  Riser::ResourceSet.build{|builder|
299
306
  builder.at_create{|unique_user_id|
300
307
  mail_store = RIMS::MailStore.build(unique_user_id, @kvs_open, @kvs_open)
301
308
  RIMS::Protocol::Decoder::Engine.new(unique_user_id, mail_store, @logger,
302
- bulk_response_count: @bulk_response_count)
309
+ bulk_response_count: @bulk_response_count,
310
+ charset_aliases: @charset_aliases,
311
+ charset_convert_options: @charset_convert_options)
303
312
  }
304
313
  builder.at_destroy{|engine|
305
314
  engine.destroy
@@ -378,6 +387,17 @@ module RIMS::Test
378
387
  end
379
388
  private :assert_imap_command
380
389
 
390
+ def assert_imap_closed
391
+ if (stream_test?) then
392
+ assert_raise(Errno::EPIPE, StopIteration) {
393
+ assert_imap_command('NOOP') {|assert|
394
+ assert.equal("#{tag} OK NOOP completed")
395
+ }
396
+ }
397
+ end
398
+ end
399
+ private :assert_imap_closed
400
+
381
401
  def client_plain_response_base64(authentication_id, plain_password)
382
402
  response_txt = [ authentication_id, authentication_id, plain_password ].join("\0")
383
403
  RIMS::Protocol.encode_base64(response_txt)
@@ -560,6 +580,8 @@ module RIMS::Test
560
580
  assert.match(/^\* BYE /)
561
581
  assert.equal("#{tag} OK LOGOUT completed")
562
582
  }
583
+
584
+ assert_imap_closed
563
585
  }
564
586
  end
565
587
 
@@ -605,6 +627,8 @@ module RIMS::Test
605
627
  }
606
628
 
607
629
  assert_equal(false, @decoder.auth?) if command_test?
630
+
631
+ assert_imap_closed
608
632
  }
609
633
  end
610
634
 
@@ -656,6 +680,8 @@ module RIMS::Test
656
680
  }
657
681
 
658
682
  assert_equal(false, @decoder.auth?) if command_test?
683
+
684
+ assert_imap_closed
659
685
  }
660
686
  end
661
687
 
@@ -711,6 +737,8 @@ module RIMS::Test
711
737
  }
712
738
 
713
739
  assert_equal(false, @decoder.auth?) if command_test?
740
+
741
+ assert_imap_closed
714
742
  }
715
743
  end
716
744
 
@@ -753,6 +781,8 @@ module RIMS::Test
753
781
  }
754
782
 
755
783
  assert_equal(false, @decoder.auth?) if command_test?
784
+
785
+ assert_imap_closed
756
786
  }
757
787
  end
758
788
 
@@ -834,6 +864,8 @@ module RIMS::Test
834
864
  assert_equal(false, @decoder.selected?)
835
865
  end
836
866
 
867
+ assert_imap_closed
868
+
837
869
  open_mail_store{
838
870
  assert_msg_uid( 2, 3)
839
871
  assert_flag_enabled_msgs('answered', )
@@ -884,6 +916,8 @@ module RIMS::Test
884
916
  assert.match(/^\* BYE /)
885
917
  assert.equal("#{tag} OK LOGOUT completed")
886
918
  }
919
+
920
+ assert_imap_closed
887
921
  }
888
922
  end
889
923
 
@@ -965,6 +999,8 @@ module RIMS::Test
965
999
  assert_equal(false, @decoder.selected?)
966
1000
  end
967
1001
 
1002
+ assert_imap_closed
1003
+
968
1004
  open_mail_store{
969
1005
  assert_msg_uid( 1, 2, 3)
970
1006
  assert_flag_enabled_msgs('answered', )
@@ -1015,6 +1051,8 @@ module RIMS::Test
1015
1051
  assert.match(/^\* BYE /)
1016
1052
  assert.equal("#{tag} OK LOGOUT completed")
1017
1053
  }
1054
+
1055
+ assert_imap_closed
1018
1056
  }
1019
1057
  end
1020
1058
 
@@ -1064,6 +1102,8 @@ module RIMS::Test
1064
1102
  assert.match(/^\* BYE /)
1065
1103
  assert.equal("#{tag} OK LOGOUT completed")
1066
1104
  }
1105
+
1106
+ assert_imap_closed
1067
1107
  }
1068
1108
  end
1069
1109
 
@@ -1100,6 +1140,8 @@ module RIMS::Test
1100
1140
  assert.match(/^\* BYE /)
1101
1141
  assert.equal("#{tag} OK LOGOUT completed")
1102
1142
  }
1143
+
1144
+ assert_imap_closed
1103
1145
  }
1104
1146
  end
1105
1147
 
@@ -1172,6 +1214,8 @@ module RIMS::Test
1172
1214
  assert.match(/^\* BYE /)
1173
1215
  assert.equal("#{tag} OK LOGOUT completed")
1174
1216
  }
1217
+
1218
+ assert_imap_closed
1175
1219
  }
1176
1220
  end
1177
1221
 
@@ -1212,6 +1256,8 @@ module RIMS::Test
1212
1256
  assert.match(/^\* BYE /)
1213
1257
  assert.equal("#{tag} OK LOGOUT completed")
1214
1258
  }
1259
+
1260
+ assert_imap_closed
1215
1261
  }
1216
1262
  end
1217
1263
 
@@ -1291,6 +1337,8 @@ module RIMS::Test
1291
1337
  assert.match(/^\* BYE /)
1292
1338
  assert.equal("#{tag} OK LOGOUT completed")
1293
1339
  }
1340
+
1341
+ assert_imap_closed
1294
1342
  }
1295
1343
  end
1296
1344
 
@@ -1338,6 +1386,8 @@ module RIMS::Test
1338
1386
  assert.match(/^\* BYE /)
1339
1387
  assert.equal("#{tag} OK LOGOUT completed")
1340
1388
  }
1389
+
1390
+ assert_imap_closed
1341
1391
  }
1342
1392
  end
1343
1393
 
@@ -1407,6 +1457,8 @@ module RIMS::Test
1407
1457
  assert.match(/^\* BYE /)
1408
1458
  assert.equal("#{tag} OK LOGOUT completed")
1409
1459
  }
1460
+
1461
+ assert_imap_closed
1410
1462
  }
1411
1463
  end
1412
1464
 
@@ -1517,6 +1569,8 @@ module RIMS::Test
1517
1569
  assert.match(/^\* BYE /)
1518
1570
  assert.equal("#{tag} OK LOGOUT completed")
1519
1571
  }
1572
+
1573
+ assert_imap_closed
1520
1574
  }
1521
1575
  end
1522
1576
 
@@ -1555,6 +1609,8 @@ module RIMS::Test
1555
1609
  assert.match(/^\* BYE /)
1556
1610
  assert.equal("#{tag} OK LOGOUT completed")
1557
1611
  }
1612
+
1613
+ assert_imap_closed
1558
1614
  }
1559
1615
  end
1560
1616
 
@@ -1661,6 +1717,8 @@ module RIMS::Test
1661
1717
  assert.match(/^\* BYE /)
1662
1718
  assert.equal("#{tag} OK LOGOUT completed")
1663
1719
  }
1720
+
1721
+ assert_imap_closed
1664
1722
  }
1665
1723
  end
1666
1724
 
@@ -1692,6 +1750,8 @@ module RIMS::Test
1692
1750
  assert.match(/^\* BYE /)
1693
1751
  assert.equal("#{tag} OK LOGOUT completed")
1694
1752
  }
1753
+
1754
+ assert_imap_closed
1695
1755
  }
1696
1756
  end
1697
1757
 
@@ -1759,6 +1819,8 @@ module RIMS::Test
1759
1819
  assert.match(/^\* BYE /)
1760
1820
  assert.equal("#{tag} OK LOGOUT completed")
1761
1821
  }
1822
+
1823
+ assert_imap_closed
1762
1824
  }
1763
1825
  end
1764
1826
 
@@ -1879,6 +1941,8 @@ module RIMS::Test
1879
1941
  assert.match(/^\* BYE /)
1880
1942
  assert.equal("#{tag} OK LOGOUT completed")
1881
1943
  }
1944
+
1945
+ assert_imap_closed
1882
1946
  }
1883
1947
  end
1884
1948
 
@@ -1918,6 +1982,8 @@ module RIMS::Test
1918
1982
  assert.match(/^\* BYE /)
1919
1983
  assert.equal("#{tag} OK LOGOUT completed")
1920
1984
  }
1985
+
1986
+ assert_imap_closed
1921
1987
  }
1922
1988
  end
1923
1989
 
@@ -1926,6 +1992,69 @@ module RIMS::Test
1926
1992
  test_append_utf7_mbox_name
1927
1993
  end
1928
1994
 
1995
+ def test_append_literal_stream
1996
+ make_mail_simple
1997
+ make_mail_multipart
1998
+ make_mail_mime_subject
1999
+
2000
+ use_imap_stream_decode_engine # always run in stream
2001
+ imap_decode_engine_evaluate{
2002
+ if (stream_test?) then
2003
+ assert_untagged_response{|assert|
2004
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
2005
+ }
2006
+ end
2007
+
2008
+ assert_imap_command('LOGIN foo open_sesame') {|assert|
2009
+ assert.equal("#{tag} OK LOGIN completed")
2010
+ }
2011
+
2012
+ open_mail_store{
2013
+ assert_msg_uid()
2014
+ }
2015
+
2016
+ assert_imap_command("APPEND INBOX #{literal(@simple_mail.raw_source)}") {|assert|
2017
+ assert.match(/^\+ /)
2018
+ assert.match(/^#{tag} OK \[APPENDUID \d+ \d+\] APPEND completed/)
2019
+ }
2020
+
2021
+ open_mail_store{
2022
+ assert_msg_uid(1)
2023
+ assert_equal(@simple_mail.raw_source, get_msg_text(1))
2024
+ assert_msg_flags(1, recent: true)
2025
+ }
2026
+
2027
+ assert_imap_command("APPEND INBOX #{literal(@mpart_mail.raw_source)}") {|assert|
2028
+ assert.match(/^\+ /)
2029
+ assert.match(/^#{tag} OK \[APPENDUID \d+ \d+\] APPEND completed/)
2030
+ }
2031
+
2032
+ open_mail_store{
2033
+ assert_msg_uid(1, 2)
2034
+ assert_equal(@mpart_mail.raw_source, get_msg_text(2))
2035
+ assert_msg_flags(2, recent: true)
2036
+ }
2037
+
2038
+ assert_imap_command("APPEND INBOX #{literal(@mime_subject_mail.raw_source)}") {|assert|
2039
+ assert.match(/^\+ /)
2040
+ assert.match(/^#{tag} OK \[APPENDUID \d+ \d+\] APPEND completed/)
2041
+ }
2042
+
2043
+ open_mail_store{
2044
+ assert_msg_uid(1, 2, 3)
2045
+ assert_equal(@mime_subject_mail.raw_source, get_msg_text(3))
2046
+ assert_msg_flags(3, recent: true)
2047
+ }
2048
+
2049
+ assert_imap_command('LOGOUT') {|assert|
2050
+ assert.match(/^\* BYE /)
2051
+ assert.equal("#{tag} OK LOGOUT completed")
2052
+ }
2053
+
2054
+ assert_imap_closed
2055
+ }
2056
+ end
2057
+
1929
2058
  def test_check
1930
2059
  imap_decode_engine_evaluate{
1931
2060
  if (stream_test?) then
@@ -1962,7 +2091,7 @@ module RIMS::Test
1962
2091
  }
1963
2092
 
1964
2093
  assert_imap_command('SELECT INBOX') {|assert|
1965
- assert.skip_while{|line| line =~ /^\* /}
2094
+ assert.skip_while{|line| line =~ /^\* / }
1966
2095
  assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
1967
2096
  }
1968
2097
 
@@ -1979,6 +2108,8 @@ module RIMS::Test
1979
2108
  assert.match(/^\* BYE /)
1980
2109
  assert.equal("#{tag} OK LOGOUT completed")
1981
2110
  }
2111
+
2112
+ assert_imap_closed
1982
2113
  }
1983
2114
  end
1984
2115
 
@@ -2090,6 +2221,8 @@ module RIMS::Test
2090
2221
  assert_equal(false, @decoder.auth?)
2091
2222
  assert_equal(false, @decoder.selected?)
2092
2223
  end
2224
+
2225
+ assert_imap_closed
2093
2226
  }
2094
2227
  end
2095
2228
 
@@ -2194,6 +2327,8 @@ module RIMS::Test
2194
2327
  assert_equal(false, @decoder.auth?)
2195
2328
  assert_equal(false, @decoder.selected?)
2196
2329
  end
2330
+
2331
+ assert_imap_closed
2197
2332
  }
2198
2333
  end
2199
2334
 
@@ -2344,6 +2479,8 @@ module RIMS::Test
2344
2479
  assert.match(/^\* BYE /)
2345
2480
  assert.equal("#{tag} OK LOGOUT completed")
2346
2481
  }
2482
+
2483
+ assert_imap_closed
2347
2484
  }
2348
2485
  end
2349
2486
 
@@ -2420,6 +2557,8 @@ module RIMS::Test
2420
2557
  assert.match(/^\* BYE /)
2421
2558
  assert.equal("#{tag} OK LOGOUT completed")
2422
2559
  }
2560
+
2561
+ assert_imap_closed
2423
2562
  }
2424
2563
  end
2425
2564
 
@@ -2549,6 +2688,8 @@ module RIMS::Test
2549
2688
  assert.match(/^\* BYE /)
2550
2689
  assert.equal("#{tag} OK LOGOUT completed")
2551
2690
  }
2691
+
2692
+ assert_imap_closed
2552
2693
  }
2553
2694
  end
2554
2695
 
@@ -2635,13 +2776,13 @@ module RIMS::Test
2635
2776
  }
2636
2777
 
2637
2778
  utf8_msg = "\u306F\u306B\u307B"
2638
- assert_imap_command("SEARCH CHARSET utf-8 BODY {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2779
+ assert_imap_command("SEARCH CHARSET utf-8 BODY #{literal(utf8_msg)}".b) {|assert|
2639
2780
  assert.match(/^\+ /)
2640
2781
  assert.equal("* SEARCH 4 5\r\n")
2641
2782
  assert.equal("#{tag} OK SEARCH completed\r\n")
2642
2783
  }
2643
2784
 
2644
- assert_imap_command("SEARCH CHARSET euc-jp BODY {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2785
+ assert_imap_command("SEARCH CHARSET euc-jp BODY #{literal(utf8_msg)}".b) {|assert|
2645
2786
  assert.match(/^\+ /)
2646
2787
  assert.match(/^#{tag} BAD /, peek_next_line: true).match(/syntax error/)
2647
2788
  }
@@ -2666,6 +2807,8 @@ module RIMS::Test
2666
2807
  assert.match(/^\* BYE /)
2667
2808
  assert.equal("#{tag} OK LOGOUT completed")
2668
2809
  }
2810
+
2811
+ assert_imap_closed
2669
2812
  }
2670
2813
  end
2671
2814
 
@@ -2759,13 +2902,13 @@ module RIMS::Test
2759
2902
  }
2760
2903
 
2761
2904
  utf8_msg = "\u306F\u306B\u307B"
2762
- assert_imap_command("SEARCH CHARSET utf-8 TEXT {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2905
+ assert_imap_command("SEARCH CHARSET utf-8 TEXT #{literal(utf8_msg)}".b) {|assert|
2763
2906
  assert.match(/^\+ /)
2764
2907
  assert.equal("* SEARCH 4 5\r\n")
2765
2908
  assert.equal("#{tag} OK SEARCH completed\r\n")
2766
2909
  }
2767
2910
 
2768
- assert_imap_command("SEARCH CHARSET euc-jp TEXT {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2911
+ assert_imap_command("SEARCH CHARSET euc-jp TEXT #{literal(utf8_msg)}".b) {|assert|
2769
2912
  assert.match(/^\+ /)
2770
2913
  assert.match(/^#{tag} BAD /, peek_next_line: true).match(/syntax error/)
2771
2914
  }
@@ -2790,6 +2933,8 @@ module RIMS::Test
2790
2933
  assert.match(/^\* BYE /)
2791
2934
  assert.equal("#{tag} OK LOGOUT completed")
2792
2935
  }
2936
+
2937
+ assert_imap_closed
2793
2938
  }
2794
2939
  end
2795
2940
 
@@ -2851,7 +2996,7 @@ module RIMS::Test
2851
2996
  }
2852
2997
 
2853
2998
  utf8_msg = "\u306F\u306B\u307B"
2854
- assert_imap_command("SEARCH CHARSET utf-8 TEXT {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2999
+ assert_imap_command("SEARCH CHARSET utf-8 TEXT #{literal(utf8_msg)}".b) {|assert|
2855
3000
  assert.match(/^\+ /)
2856
3001
  assert.equal("* SEARCH\r\n")
2857
3002
  assert.equal("#{tag} OK SEARCH completed\r\n")
@@ -2861,6 +3006,8 @@ module RIMS::Test
2861
3006
  assert.match(/^\* BYE /)
2862
3007
  assert.equal("#{tag} OK LOGOUT completed")
2863
3008
  }
3009
+
3010
+ assert_imap_closed
2864
3011
  }
2865
3012
  end
2866
3013
 
@@ -2869,7 +3016,8 @@ module RIMS::Test
2869
3016
  test_search_charset_skip_encoding_error
2870
3017
  end
2871
3018
 
2872
- def test_search_interrupt_by_bad_response
3019
+ # skip this test because `EncodingError' is ignored.
3020
+ def _test_search_interrupt_by_bad_response
2873
3021
  imap_decode_engine_evaluate{
2874
3022
  if (stream_test?) then
2875
3023
  assert_untagged_response{|assert|
@@ -2915,7 +3063,7 @@ module RIMS::Test
2915
3063
  assert_equal(true, @decoder.selected?)
2916
3064
  end
2917
3065
 
2918
- assert_imap_command('SEARCH TEXT foo') {|assert|
3066
+ assert_imap_command('SEARCH CHARSET utf-8 TEXT foo') {|assert|
2919
3067
  assert.match(/\A\* SEARCH( \d+)+\r\n\z/, peek_next_line: true).no_match(/ #{@bulk_response_count.succ}/)
2920
3068
  assert.equal("#{tag} BAD internal server error\r\n")
2921
3069
  }
@@ -2924,10 +3072,13 @@ module RIMS::Test
2924
3072
  assert.match(/^\* BYE /)
2925
3073
  assert.equal("#{tag} OK LOGOUT completed")
2926
3074
  }
3075
+
3076
+ assert_imap_closed
2927
3077
  }
2928
3078
  end
2929
3079
 
2930
- def test_search_interrupt_by_bad_response_stream
3080
+ # skip this test because `EncodingError' is ignored.
3081
+ def _test_search_interrupt_by_bad_response_stream
2931
3082
  use_imap_stream_decode_engine
2932
3083
  test_search_interrupt_by_bad_response
2933
3084
  end
@@ -3076,6 +3227,8 @@ module RIMS::Test
3076
3227
  assert.match(/^\* BYE /)
3077
3228
  assert.equal("#{tag} OK LOGOUT completed")
3078
3229
  }
3230
+
3231
+ assert_imap_closed
3079
3232
  }
3080
3233
  end
3081
3234
 
@@ -3228,6 +3381,8 @@ module RIMS::Test
3228
3381
  assert.match(/^\* BYE /)
3229
3382
  assert.equal("#{tag} OK LOGOUT completed")
3230
3383
  }
3384
+
3385
+ assert_imap_closed
3231
3386
  }
3232
3387
  end
3233
3388
 
@@ -3580,6 +3735,8 @@ module RIMS::Test
3580
3735
  assert.match(/^\* BYE /)
3581
3736
  assert.equal("#{tag} OK LOGOUT completed")
3582
3737
  }
3738
+
3739
+ assert_imap_closed
3583
3740
  }
3584
3741
  end
3585
3742
 
@@ -3882,6 +4039,8 @@ module RIMS::Test
3882
4039
  assert.match(/^\* BYE /)
3883
4040
  assert.equal("#{tag} OK LOGOUT completed")
3884
4041
  }
4042
+
4043
+ assert_imap_closed
3885
4044
  }
3886
4045
  end
3887
4046
 
@@ -4234,6 +4393,8 @@ module RIMS::Test
4234
4393
  assert.match(/^\* BYE /)
4235
4394
  assert.equal("#{tag} OK LOGOUT completed")
4236
4395
  }
4396
+
4397
+ assert_imap_closed
4237
4398
  }
4238
4399
  end
4239
4400
 
@@ -4536,6 +4697,8 @@ module RIMS::Test
4536
4697
  assert.match(/^\* BYE /)
4537
4698
  assert.equal("#{tag} OK LOGOUT completed")
4538
4699
  }
4700
+
4701
+ assert_imap_closed
4539
4702
  }
4540
4703
  end
4541
4704
 
@@ -4705,6 +4868,8 @@ module RIMS::Test
4705
4868
  assert.match(/^\* BYE /)
4706
4869
  assert.equal("#{tag} OK LOGOUT completed")
4707
4870
  }
4871
+
4872
+ assert_imap_closed
4708
4873
  }
4709
4874
  end
4710
4875
 
@@ -4909,6 +5074,8 @@ module RIMS::Test
4909
5074
  assert.match(/^\* BYE /)
4910
5075
  assert.equal("#{tag} OK LOGOUT completed")
4911
5076
  }
5077
+
5078
+ assert_imap_closed
4912
5079
  }
4913
5080
  end
4914
5081
 
@@ -5113,6 +5280,8 @@ module RIMS::Test
5113
5280
  assert.match(/^\* BYE /)
5114
5281
  assert.equal("#{tag} OK LOGOUT completed")
5115
5282
  }
5283
+
5284
+ assert_imap_closed
5116
5285
  }
5117
5286
  end
5118
5287
 
@@ -5166,6 +5335,8 @@ module RIMS::Test
5166
5335
  assert.match(/^\* BYE /)
5167
5336
  assert.equal("#{tag} OK LOGOUT completed")
5168
5337
  }
5338
+
5339
+ assert_imap_closed
5169
5340
  }
5170
5341
  end
5171
5342
 
@@ -5209,7 +5380,7 @@ module RIMS::Test
5209
5380
  }
5210
5381
 
5211
5382
  assert_imap_command('SELECT INBOX') {|assert|
5212
- assert.skip_while{|line| line =~ /^\* /}
5383
+ assert.skip_while{|line| line =~ /^\* / }
5213
5384
  assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
5214
5385
  }
5215
5386
 
@@ -5236,7 +5407,7 @@ module RIMS::Test
5236
5407
  }
5237
5408
 
5238
5409
  assert_imap_command('EXAMINE INBOX') {|assert|
5239
- assert.skip_while{|line| line =~ /^\* /}
5410
+ assert.skip_while{|line| line =~ /^\* / }
5240
5411
  assert.equal("#{tag} OK [READ-ONLY] EXAMINE completed")
5241
5412
  }
5242
5413
 
@@ -5258,6 +5429,8 @@ module RIMS::Test
5258
5429
  assert_equal(false, @decoder.auth?)
5259
5430
  assert_equal(false, @decoder.selected?)
5260
5431
  end
5432
+
5433
+ assert_imap_closed
5261
5434
  }
5262
5435
  end
5263
5436
 
@@ -5297,7 +5470,7 @@ module RIMS::Test
5297
5470
  }
5298
5471
 
5299
5472
  assert_imap_command('SELECT INBOX') {|assert|
5300
- assert.skip_while{|line| line =~ /^\* /}
5473
+ assert.skip_while{|line| line =~ /^\* / }
5301
5474
  assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
5302
5475
  }
5303
5476
 
@@ -5343,7 +5516,7 @@ module RIMS::Test
5343
5516
  }
5344
5517
 
5345
5518
  assert_imap_command('EXAMINE INBOX') {|assert|
5346
- assert.skip_while{|line| line =~ /^\* /}
5519
+ assert.skip_while{|line| line =~ /^\* / }
5347
5520
  assert.equal("#{tag} OK [READ-ONLY] EXAMINE completed")
5348
5521
  }
5349
5522
 
@@ -5366,6 +5539,8 @@ module RIMS::Test
5366
5539
  assert_equal(false, @decoder.auth?)
5367
5540
  assert_equal(false, @decoder.selected?)
5368
5541
  end
5542
+
5543
+ assert_imap_closed
5369
5544
  }
5370
5545
  end
5371
5546
 
@@ -5375,11 +5550,11 @@ module RIMS::Test
5375
5550
  end
5376
5551
 
5377
5552
  def test_error_handling_stream
5378
- use_imap_stream_decode_engine
5553
+ use_imap_stream_decode_engine # always run in stream
5379
5554
  imap_decode_engine_evaluate{
5380
5555
  assert_imap_command('') {|assert|
5381
5556
  assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
5382
- assert.equal('* BAD client command syntax error')
5557
+ assert.equal("#{tag} BAD client command syntax error")
5383
5558
  }
5384
5559
 
5385
5560
  assert_imap_command('no_command') {|assert|
@@ -5397,6 +5572,30 @@ module RIMS::Test
5397
5572
  assert_imap_command('noop detarame') {|assert|
5398
5573
  assert.equal("#{tag} BAD invalid command parameter")
5399
5574
  }
5575
+
5576
+ assert_imap_command("APPEND INBOX {#{LITERAL_SIZE_LIMIT + 1}}") {|assert|
5577
+ assert.equal("#{tag} BAD literal size too large")
5578
+ }
5579
+
5580
+ assert_imap_command("APPEND #{literal('x' * LITERAL_SIZE_LIMIT)} #{'y' * (LINE_LENGTH_LIMIT - 3)}") {|assert|
5581
+ assert.match(/^\+ /)
5582
+ assert.equal("#{tag} BAD command size too large") # by last line
5583
+ }
5584
+
5585
+ assert_imap_command("APPEND #{literal('x' * LITERAL_SIZE_LIMIT)} {#{LITERAL_SIZE_LIMIT}}") {|assert|
5586
+ assert.match(/^\+ /)
5587
+ assert.equal("#{tag} BAD command size too large") # by last literal
5588
+ }
5589
+
5590
+ @tag = '*T000'
5591
+ assert_imap_command('noop') {|assert|
5592
+ assert.equal('* BAD client command syntax error')
5593
+ }
5594
+
5595
+ @tag = '+T000'
5596
+ assert_imap_command('noop') {|assert|
5597
+ assert.equal('* BAD client command syntax error')
5598
+ }
5400
5599
  }
5401
5600
  end
5402
5601
 
@@ -5428,6 +5627,8 @@ module RIMS::Test
5428
5627
  }
5429
5628
 
5430
5629
  assert_equal(false, @decoder.auth?) if command_test?
5630
+
5631
+ assert_imap_closed
5431
5632
  }
5432
5633
  end
5433
5634
 
@@ -5584,6 +5785,8 @@ module RIMS::Test
5584
5785
  }
5585
5786
 
5586
5787
  assert_equal(false, @decoder.auth?) if command_test?
5788
+
5789
+ assert_imap_closed
5587
5790
  }
5588
5791
  end
5589
5792
 
@@ -5642,6 +5845,8 @@ module RIMS::Test
5642
5845
  }
5643
5846
 
5644
5847
  assert_equal(false, @decoder.auth?) if command_test?
5848
+
5849
+ assert_imap_closed
5645
5850
  }
5646
5851
  end
5647
5852
 
@@ -5724,7 +5929,7 @@ module RIMS::Test
5724
5929
  }
5725
5930
 
5726
5931
  assert_imap_command('SELECT INBOX') {|assert|
5727
- assert.skip_while{|line| line =~ /^\* /}
5932
+ assert.skip_while{|line| line =~ /^\* / }
5728
5933
  assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
5729
5934
  }
5730
5935
 
@@ -5748,7 +5953,7 @@ module RIMS::Test
5748
5953
  }
5749
5954
 
5750
5955
  assert_imap_command('SELECT INBOX') {|assert|
5751
- assert.skip_while{|line| line =~ /^\* /}
5956
+ assert.skip_while{|line| line =~ /^\* / }
5752
5957
  assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
5753
5958
  }
5754
5959
 
@@ -5772,7 +5977,7 @@ module RIMS::Test
5772
5977
  }
5773
5978
 
5774
5979
  assert_imap_command('SELECT INBOX') {|assert|
5775
- assert.skip_while{|line| line =~ /^\* /}
5980
+ assert.skip_while{|line| line =~ /^\* / }
5776
5981
  assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
5777
5982
  }
5778
5983
 
@@ -5800,7 +6005,7 @@ module RIMS::Test
5800
6005
  }
5801
6006
 
5802
6007
  assert_imap_command('SELECT INBOX') {|assert|
5803
- assert.skip_while{|line| line =~ /^\* /}
6008
+ assert.skip_while{|line| line =~ /^\* / }
5804
6009
  assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
5805
6010
  }
5806
6011
 
@@ -5833,10 +6038,8 @@ module RIMS::Test
5833
6038
  }
5834
6039
 
5835
6040
  another_decoder = make_decoder
5836
- another_writer = proc{|res|
5837
- for line in res
5838
- p line if $DEBUG
5839
- end
6041
+ another_writer = proc{|response|
6042
+ p response if $DEBUG
5840
6043
  }
5841
6044
 
5842
6045
  another_decoder.login('tag', 'foo', 'open_sesame', &another_writer)
@@ -6111,10 +6314,8 @@ module RIMS::Test
6111
6314
  }
6112
6315
 
6113
6316
  another_decoder = make_decoder
6114
- another_writer = proc{|res|
6115
- for line in res
6116
- p line if $DEBUG
6117
- end
6317
+ another_writer = proc{|response|
6318
+ p response if $DEBUG
6118
6319
  }
6119
6320
 
6120
6321
  another_decoder.login('tag', 'foo', 'open_sesame', &another_writer)
@@ -6175,6 +6376,232 @@ module RIMS::Test
6175
6376
  use_imap_stream_decode_engine
6176
6377
  test_idle_untagged_server_response
6177
6378
  end
6379
+
6380
+ def test_charset_aliases
6381
+ imap_decode_engine_evaluate{
6382
+ if (stream_test?) then
6383
+ assert_untagged_response{|assert|
6384
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
6385
+ }
6386
+ end
6387
+
6388
+ platform_dependent_character = "\u2460"
6389
+ open_mail_store{
6390
+ add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
6391
+ "\r\n" +
6392
+ "#{platform_dependent_character.encode(Encoding::CP50221).b}")
6393
+ }
6394
+
6395
+ if (command_test?) then
6396
+ assert_equal(false, @decoder.auth?)
6397
+ assert_equal(false, @decoder.selected?)
6398
+ end
6399
+
6400
+ assert_imap_command('LOGIN foo open_sesame') {|assert|
6401
+ assert.equal("#{tag} OK LOGIN completed")
6402
+ }
6403
+
6404
+ if (command_test?) then
6405
+ assert_equal(true, @decoder.auth?)
6406
+ assert_equal(false, @decoder.selected?)
6407
+ end
6408
+
6409
+ assert_imap_command('SELECT INBOX') {|assert|
6410
+ assert.skip_while{|line| line =~ /^\* / }
6411
+ assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
6412
+ }
6413
+
6414
+ if (command_test?) then
6415
+ assert_equal(true, @decoder.auth?)
6416
+ assert_equal(true, @decoder.selected?)
6417
+ end
6418
+
6419
+ assert_imap_command("SEARCH CHARSET utf-8 TEXT #{literal(platform_dependent_character)}") {|assert|
6420
+ assert.match(/^\+ /)
6421
+ assert.equal("* SEARCH\r\n") # skip by `EncodingError'
6422
+ assert.equal("#{tag} OK SEARCH completed\r\n")
6423
+ }
6424
+
6425
+ # not recommend changing charset aliases after passing them to the decoder.
6426
+ # here, the charset aliases are reluctantly changed for testing.
6427
+ @charset_aliases.add_alias('iso-2022-jp', Encoding::CP50221)
6428
+
6429
+ assert_imap_command("SEARCH CHARSET utf-8 TEXT #{literal(platform_dependent_character)}") {|assert|
6430
+ assert.match(/^\+ /)
6431
+ assert.equal("* SEARCH 1\r\n") # matched!
6432
+ assert.equal("#{tag} OK SEARCH completed\r\n")
6433
+ }
6434
+
6435
+ assert_imap_command('CLOSE') {|assert|
6436
+ assert.equal("#{tag} OK CLOSE completed")
6437
+ }
6438
+
6439
+ if (command_test?) then
6440
+ assert_equal(true, @decoder.auth?)
6441
+ assert_equal(false, @decoder.selected?)
6442
+ end
6443
+
6444
+ assert_imap_command('LOGOUT') {|assert|
6445
+ assert.match(/^\* BYE /)
6446
+ assert.equal("#{tag} OK LOGOUT completed")
6447
+ }
6448
+
6449
+ if (command_test?) then
6450
+ assert_equal(false, @decoder.auth?)
6451
+ assert_equal(false, @decoder.selected?)
6452
+ end
6453
+
6454
+ assert_imap_closed
6455
+ }
6456
+ end
6457
+
6458
+ def test_charset_aliases_stream
6459
+ use_imap_stream_decode_engine
6460
+ test_charset_aliases
6461
+ end
6462
+
6463
+ def test_charset_convert_options
6464
+ imap_decode_engine_evaluate{
6465
+ if (stream_test?) then
6466
+ assert_untagged_response{|assert|
6467
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
6468
+ }
6469
+ end
6470
+
6471
+ platform_dependent_character = "\u2460"
6472
+ open_mail_store{
6473
+ add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
6474
+ "\r\n" +
6475
+ "#{platform_dependent_character.encode(Encoding::CP50221).b}")
6476
+ }
6477
+
6478
+ if (command_test?) then
6479
+ assert_equal(false, @decoder.auth?)
6480
+ assert_equal(false, @decoder.selected?)
6481
+ end
6482
+
6483
+ assert_imap_command('LOGIN foo open_sesame') {|assert|
6484
+ assert.equal("#{tag} OK LOGIN completed")
6485
+ }
6486
+
6487
+ if (command_test?) then
6488
+ assert_equal(true, @decoder.auth?)
6489
+ assert_equal(false, @decoder.selected?)
6490
+ end
6491
+
6492
+ assert_imap_command('SELECT INBOX') {|assert|
6493
+ assert.skip_while{|line| line =~ /^\* / }
6494
+ assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
6495
+ }
6496
+
6497
+ if (command_test?) then
6498
+ assert_equal(true, @decoder.auth?)
6499
+ assert_equal(true, @decoder.selected?)
6500
+ end
6501
+
6502
+ assert_imap_command(%Q'SEARCH CHARSET utf-8 TEXT #{literal("\uFFFD")}') {|assert|
6503
+ assert.match(/^\+ /)
6504
+ assert.equal("* SEARCH\r\n") # skip by `EncodingError'
6505
+ assert.equal("#{tag} OK SEARCH completed\r\n")
6506
+ }
6507
+
6508
+ # not recommend changing charset convert options after passing them to the decoder.
6509
+ # here, the options are reluctantly changed for testing.
6510
+ @charset_convert_options[:undef] = :replace
6511
+
6512
+ assert_imap_command("SEARCH CHARSET utf-8 TEXT #{literal("\uFFFD")}") {|assert|
6513
+ assert.match(/^\+ /)
6514
+ assert.equal("* SEARCH 1\r\n") # matched!
6515
+ assert.equal("#{tag} OK SEARCH completed\r\n")
6516
+ }
6517
+
6518
+ assert_imap_command('CLOSE') {|assert|
6519
+ assert.equal("#{tag} OK CLOSE completed")
6520
+ }
6521
+
6522
+ if (command_test?) then
6523
+ assert_equal(true, @decoder.auth?)
6524
+ assert_equal(false, @decoder.selected?)
6525
+ end
6526
+
6527
+ assert_imap_command('LOGOUT') {|assert|
6528
+ assert.match(/^\* BYE /)
6529
+ assert.equal("#{tag} OK LOGOUT completed")
6530
+ }
6531
+
6532
+ if (command_test?) then
6533
+ assert_equal(false, @decoder.auth?)
6534
+ assert_equal(false, @decoder.selected?)
6535
+ end
6536
+
6537
+ assert_imap_closed
6538
+ }
6539
+ end
6540
+
6541
+ def test_charset_convert_options_stream
6542
+ use_imap_stream_decode_engine
6543
+ test_charset_convert_options
6544
+ end
6545
+
6546
+ def test_command_line_too_long_error_stream
6547
+ use_imap_stream_decode_engine # always run in stream
6548
+ imap_decode_engine_evaluate{
6549
+ assert_untagged_response{|assert|
6550
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
6551
+ }
6552
+
6553
+ assert_imap_command('APPEND INBOX ' + 'x' * LINE_LENGTH_LIMIT) {|assert|
6554
+ assert.equal('* BAD line too long')
6555
+ assert.equal('* BYE server autologout: connection terminated')
6556
+ }
6557
+
6558
+ assert_imap_closed
6559
+ }
6560
+ end
6561
+
6562
+ def test_authenticate_line_too_long_error_stream
6563
+ use_imap_stream_decode_engine # always run in stream
6564
+ imap_decode_engine_evaluate{
6565
+ assert_untagged_response{|assert|
6566
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
6567
+ }
6568
+
6569
+ assert_imap_command('AUTHENTICATE plain',
6570
+ client_input_text: 'x' * LINE_LENGTH_LIMIT + "\r\n") {|assert|
6571
+ assert.equal('+ ')
6572
+ assert.equal('* BAD line too long')
6573
+ assert.equal('* BYE server autologout: connection terminated')
6574
+ }
6575
+
6576
+ assert_imap_closed
6577
+ }
6578
+ end
6579
+
6580
+ def test_idle_line_too_long_error_stream
6581
+ use_imap_stream_decode_engine # always run in stream
6582
+ imap_decode_engine_evaluate{
6583
+ assert_untagged_response{|assert|
6584
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
6585
+ }
6586
+
6587
+ assert_imap_command('LOGIN foo open_sesame') {|assert|
6588
+ assert.equal("#{tag} OK LOGIN completed")
6589
+ }
6590
+
6591
+ assert_imap_command('SELECT INBOX') {|assert|
6592
+ assert.skip_while{|line| line =~ /^\* / }
6593
+ assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
6594
+ }
6595
+
6596
+ assert_imap_command('IDLE', client_input_text: 'DONE' + ' ' * LINE_LENGTH_LIMIT + "\r\n") {|assert|
6597
+ assert.match(/^\+ /)
6598
+ assert.equal('* BAD line too long')
6599
+ assert.equal('* BYE server autologout: connection terminated')
6600
+ }
6601
+
6602
+ assert_imap_closed
6603
+ }
6604
+ end
6178
6605
  end
6179
6606
 
6180
6607
  class ProtocolMailDeliveryDecoderTest < Test::Unit::TestCase
@@ -6197,6 +6624,93 @@ module RIMS::Test
6197
6624
  assert_equal(%w[ foo INBOX ], RIMS::Protocol::Decoder.decode_delivery_target_mailbox(encoded_mbox_name))
6198
6625
  end
6199
6626
  end
6627
+
6628
+ class ProtocolDecoderBulkResponseTest < Test::Unit::TestCase
6629
+ def setup
6630
+ limit_count = 10
6631
+ limit_size = 100
6632
+ @res = RIMS::Protocol::Decoder::BulkResponse.new(limit_count, limit_size)
6633
+ end
6634
+
6635
+ data('empty' => [ 0, 0, [] ],
6636
+ '1' => [ 1, 3, %w[ foo ] ],
6637
+ '2' => [ 2, 6, %w[ foo bar ] ],
6638
+ '3' => [ 3, 11, %w[ foo bar baaaz ] ])
6639
+ def test_add(data)
6640
+ expected_count, expected_size, response_list = data
6641
+
6642
+ assert_equal(0, @res.count)
6643
+ assert_equal(0, @res.size)
6644
+
6645
+ for response in response_list
6646
+ @res << response
6647
+ end
6648
+
6649
+ assert_equal(expected_count, @res.count)
6650
+ assert_equal(expected_size, @res.size)
6651
+ end
6652
+
6653
+ def test_emtpy?
6654
+ assert_true(@res.empty?)
6655
+ end
6656
+
6657
+ def test_not_empty?
6658
+ @res << 'foo'
6659
+ assert_false(@res.empty?)
6660
+ end
6661
+
6662
+ data('count: boundary' => %w[ 1 2 3 4 5 6 7 8 9 0 ],
6663
+ 'count: over' => %w[ 1 2 3 4 5 6 7 8 9 0 a ],
6664
+ 'size: boundary' => [ 'x' * 50, 'y' * 50 ],
6665
+ 'size: over' => [ 'x' * 50, 'y' * 50, 'z' ],
6666
+ 'count,size: boundary' => %w[ 1 2 3 4 5 6 7 8 9 0 ].map{|s| s * 10 },
6667
+ 'count,size: over' => %w[ 1 2 3 4 5 6 7 8 9 0 ].map{|s| s * 10 } + %w[ a ])
6668
+ def test_full?(data)
6669
+ response_list = data
6670
+ for response in response_list
6671
+ @res << response
6672
+ end
6673
+ assert_true(@res.full?)
6674
+ end
6675
+
6676
+ data('empty' => [],
6677
+ 'under' => %w[ foo bar baz ],
6678
+ 'count: boundary' => %w[ 1 2 3 4 5 6 7 8 9 ],
6679
+ 'size: boundary' => [ 'x' * 50, 'y' * 49 ])
6680
+ def test_not_full?(data)
6681
+ response_list = data
6682
+ for response in response_list
6683
+ @res << response
6684
+ end
6685
+ assert_false(@res.full?)
6686
+ end
6687
+
6688
+ def test_flush
6689
+ @res << 'foo'
6690
+ @res << 'bar'
6691
+ r1 = @res.flush
6692
+ assert_equal('foo' + 'bar', r1.join(''), 'responses may be joined.')
6693
+ assert_true(@res.empty?)
6694
+ assert_false(@res.full?)
6695
+
6696
+ @res << 'baz'
6697
+ r2 = @res.flush
6698
+ assert_equal('baz', r2.join(''), 'responses may be joined.')
6699
+ assert_true(@res.empty?)
6700
+ assert_false(@res.full?)
6701
+
6702
+ assert_not_equal(r1, r2)
6703
+ end
6704
+
6705
+ def test_flush_joined
6706
+ for c in ('a'..).first(10)
6707
+ @res << c
6708
+ end
6709
+ assert_equal([ ('a'..).first(10).join('') ], @res.flush)
6710
+ assert_true(@res.empty?)
6711
+ assert_false(@res.full?)
6712
+ end
6713
+ end
6200
6714
  end
6201
6715
 
6202
6716
  # Local Variables: