rims 0.2.5 → 0.2.6

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.
@@ -780,22 +780,22 @@ module RIMS
780
780
  end
781
781
  end
782
782
 
783
- services = Riser::DRbServices.new(drb_process_num)
784
- services.add_sticky_process_service(:engine,
785
- Riser::ResourceSet.build{|builder|
786
- builder.at_create{|unique_user_id|
787
- mail_store = MailStore.build(unique_user_id, kvs_meta_open, kvs_text_open)
788
- Protocol::Decoder::Engine.new(unique_user_id, mail_store, logger,
789
- bulk_response_count: @config.bulk_response_count,
790
- read_lock_timeout_seconds: @config.read_lock_timeout_seconds,
791
- write_lock_timeout_seconds: @config.write_lock_timeout_seconds,
792
- cleanup_write_lock_timeout_seconds: @config.cleanup_write_lock_timeout_seconds)
793
- }
794
- builder.at_destroy{|engine|
795
- engine.destroy
796
- }
797
- builder.alias_unref(:destroy)
798
- })
783
+ drb_services = Riser::DRbServices.new(drb_process_num)
784
+ drb_services.add_sticky_process_service(:engine,
785
+ Riser::ResourceSet.build{|builder|
786
+ builder.at_create{|unique_user_id|
787
+ mail_store = MailStore.build(unique_user_id, kvs_meta_open, kvs_text_open)
788
+ Protocol::Decoder::Engine.new(unique_user_id, mail_store, logger,
789
+ bulk_response_count: @config.bulk_response_count,
790
+ read_lock_timeout_seconds: @config.read_lock_timeout_seconds,
791
+ write_lock_timeout_seconds: @config.write_lock_timeout_seconds,
792
+ cleanup_write_lock_timeout_seconds: @config.cleanup_write_lock_timeout_seconds)
793
+ }
794
+ builder.at_destroy{|engine|
795
+ engine.destroy
796
+ }
797
+ builder.alias_unref(:destroy)
798
+ })
799
799
 
800
800
  server.before_start{|server_socket|
801
801
  logger.info('start server.')
@@ -906,11 +906,11 @@ module RIMS
906
906
  logger.info("authorization parameter: mail_delivery_user=#{@config.mail_delivery_user}")
907
907
 
908
908
  logger.info('dRuby services: start server.')
909
- services.start_server
909
+ drb_services.start_server
910
910
  }
911
911
  server.at_fork{
912
912
  logger.info('dRuby services: detach server.')
913
- services.detach_server
913
+ drb_services.detach_server
914
914
  }
915
915
  server.at_stop{|stop_state|
916
916
  case (stop_state)
@@ -926,7 +926,7 @@ module RIMS
926
926
  }
927
927
  server.preprocess{
928
928
  logger.info('dRuby services: start client.')
929
- services.start_client
929
+ drb_services.start_client
930
930
  auth.start_plug_in(logger)
931
931
  }
932
932
  server.dispatch{|socket|
@@ -947,7 +947,7 @@ module RIMS
947
947
  stream = Riser::WriteBufferStream.new(socket, @config.send_buffer_limit_size)
948
948
  end
949
949
  stream = Riser::LoggingStream.new(stream, protocol_logger)
950
- decoder = Protocol::Decoder.new_decoder(services, auth, logger, mail_delivery_user: @config.mail_delivery_user)
950
+ decoder = Protocol::Decoder.new_decoder(drb_services, auth, logger, mail_delivery_user: @config.mail_delivery_user)
951
951
  Protocol::Decoder.repl(decoder, conn_limits, stream, stream, logger)
952
952
  ensure
953
953
  if (stream) then
@@ -980,7 +980,7 @@ module RIMS
980
980
  }
981
981
  server.after_stop{
982
982
  logger.info('dRuby services: stop server.')
983
- services.stop_server
983
+ drb_services.stop_server
984
984
  logger.info('stop server.')
985
985
  }
986
986
 
@@ -1,5 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ require 'digest'
3
4
  require 'fileutils'
4
5
  require 'set'
5
6
 
@@ -68,16 +69,22 @@ module RIMS
68
69
 
69
70
  module ProtocolFetchMailSample
70
71
  def make_mail_simple
71
- @simple_mail = RIMS::RFC822::Message.new(<<-'EOF')
72
+ @simple_mail_body = <<-'EOF'
73
+ Hello world.
74
+ EOF
75
+
76
+ md5_digest = Digest::MD5.digest(@simple_mail_body)
77
+ @simple_mail = RIMS::RFC822::Message.new(<<-"EOF" + @simple_mail_body)
72
78
  To: foo@nonet.org
73
79
  From: bar@nonet.org
74
80
  Subject: test
75
81
  MIME-Version: 1.0
76
82
  Content-Type: text/plain; charset=us-ascii
77
83
  Content-Transfer-Encoding: 7bit
84
+ Content-MD5: #{[ md5_digest ].pack('m').strip}
85
+ Content-Language: en-US, en
78
86
  Date: Fri, 8 Nov 2013 06:47:50 +0900 (JST)
79
87
 
80
- Hello world.
81
88
  EOF
82
89
  end
83
90
  private :make_mail_simple
@@ -97,6 +104,9 @@ Content-Type: text/plain; charset=us-ascii
97
104
  Multipart test.
98
105
  --1383.905529.351297
99
106
  Content-Type: application/octet-stream
107
+ Content-Disposition: attachment
108
+ ; filename=test.dat
109
+ ; modification-date="Wed, 12 Feb 1997 16:29:51 -0500"
100
110
 
101
111
  0123456789
102
112
  --1383.905529.351297
@@ -108,6 +118,9 @@ Subject: inner multipart
108
118
  MIME-Version: 1.0
109
119
  Date: Fri, 8 Nov 2013 19:31:03 +0900
110
120
  Content-Type: multipart/mixed; boundary="1383.905529.351298"
121
+ Content-Disposition: attachment; filename=hello.txt
122
+ Content-Language: en
123
+ Content-Location: test
111
124
 
112
125
  --1383.905529.351298
113
126
  Content-Type: text/plain; charset=us-ascii
@@ -123,7 +136,9 @@ Content-Type: multipart/mixed; boundary="1383.905529.351299"
123
136
 
124
137
  --1383.905529.351299
125
138
  Content-Type: image/gif
139
+ Content-Disposition: inline
126
140
 
141
+ GIF image...
127
142
  --1383.905529.351299
128
143
  Content-Type: message/rfc822
129
144
 
@@ -136,6 +151,7 @@ Content-Type: multipart/mixed; boundary="1383.905529.351300"
136
151
 
137
152
  --1383.905529.351300
138
153
  Content-Type: text/plain; charset=us-ascii
154
+ Content-Location: foo
139
155
 
140
156
  HALO
141
157
  --1383.905529.351300
@@ -143,10 +159,12 @@ Content-Type: multipart/alternative; boundary="1383.905529.351301"
143
159
 
144
160
  --1383.905529.351301
145
161
  Content-Type: text/plain; charset=us-ascii
162
+ Content-Location: bar
146
163
 
147
164
  alternative message.
148
165
  --1383.905529.351301
149
166
  Content-Type: text/html; charset=us-ascii
167
+ Content-Location: baz
150
168
 
151
169
  <html>
152
170
  <body><p>HTML message</p></body>
@@ -186,7 +204,7 @@ Hello world.
186
204
  private :make_mail_empty
187
205
 
188
206
  def make_mail_no_body
189
- @no_body_mail = RIMS::RFC822::Message.new('foo')
207
+ @no_body_mail = RIMS::RFC822::Message.new("Subject: foo\r\n\r\n")
190
208
  end
191
209
  private :make_mail_no_body
192
210
 
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module RIMS
4
- VERSION = '0.2.5'
4
+ VERSION = '0.2.6'
5
5
  MAILBOX_DATA_STRUCTURE_VERSION = 'mailbox.2'
6
6
  end
7
7
 
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.required_ruby_version = '>= 2.0.0'
28
28
 
29
+ spec.add_runtime_dependency "rims-rfc822", '>= 0.2.0'
29
30
  spec.add_runtime_dependency "riser", '>= 0.1.8'
30
31
  spec.add_runtime_dependency "logger-joint"
31
32
  spec.add_development_dependency "bundler"
@@ -334,6 +334,35 @@ module RIMS::Test
334
334
  assert_equal(0, status.exitstatus)
335
335
  end
336
336
 
337
+ data('default' => [ false, %w[] ],
338
+ '-r' => [ false, %w[ -r prime ] ],
339
+ '--required-feature' => [ false, %w[ --required-feature=prime ] ],
340
+ '--format=yaml' => [ false, %w[ --format=yaml ] ],
341
+ '--format=json' => [ false, %w[ --format=json ] ],
342
+
343
+ # deplicated options
344
+ 'deplicated:--load-library' => [ true, %w[ --load-library=prime ] ])
345
+ def test_environment(data)
346
+ deplicated, options = data
347
+
348
+ stdout, stderr, status = Open3.capture3('rims', 'environment', *options)
349
+ pp [ stdout, stderr, status ] if $DEBUG
350
+
351
+ assert_equal(0, status.exitstatus)
352
+ if (deplicated) then
353
+ assert_match(/^warning:/, stderr)
354
+ else
355
+ assert_equal('', stderr)
356
+ end
357
+
358
+ assert_match(/RIMS Environment/, stdout)
359
+ assert_match(/RUBY VERSION.*#{Regexp.quote(RUBY_DESCRIPTION)}/, stdout)
360
+ assert_match(/RIMS VERSION.*#{Regexp.quote(RIMS::VERSION)}/, stdout)
361
+ assert_match(/AUTHENTICATION PLUG-IN.*plain/m, stdout)
362
+ assert_match(/AUTHENTICATION PLUG-IN.*hash/m, stdout)
363
+ assert_match(/KEY-VALUE STORE PLUG-IN.*gdbm/m, stdout)
364
+ end
365
+
337
366
  tls_dir = Pathname(__FILE__).parent.parent / "tls"
338
367
  TLS_CA_CERT = tls_dir / 'ca.cert'
339
368
  TLS_SERVER_CERT = tls_dir / 'server_localhost.cert'
@@ -1277,49 +1306,112 @@ Hello world.
1277
1306
  envelope = lambda{|mail|
1278
1307
  Net::IMAP::Envelope.new(mail.header['Date'],
1279
1308
  mail.header['Subject'],
1280
- mail.from ? mail.from.map{|addr| Net::IMAP::Address.new(*addr) } : nil,
1281
- mail.reply_to ? mail.reply_to.map{|addr| Net::IMAP::Address.new(*addr) } : nil,
1282
- mail.sender ? mail.sender.map{|addr| Net::IMAP::Address.new(*addr) } : nil,
1283
- mail.to ? mail.to.map{|addr| Net::IMAP::Address.new(*addr) } : nil,
1284
- mail.cc ? mail.cc.map{|addr| Net::IMAP::Address.new(*addr) } : nil,
1285
- mail.bcc ? mail.bcc.map{|addr| Net::IMAP::Address.new(*addr) } : nil,
1309
+ mail.from ? mail.from.map{|addr| Net::IMAP::Address.new(*addr.to_a) } : nil,
1310
+ mail.reply_to ? mail.reply_to.map{|addr| Net::IMAP::Address.new(*addr.to_a) } : nil,
1311
+ mail.sender ? mail.sender.map{|addr| Net::IMAP::Address.new(*addr.to_a) } : nil,
1312
+ mail.to ? mail.to.map{|addr| Net::IMAP::Address.new(*addr.to_a) } : nil,
1313
+ mail.cc ? mail.cc.map{|addr| Net::IMAP::Address.new(*addr.to_a) } : nil,
1314
+ mail.bcc ? mail.bcc.map{|addr| Net::IMAP::Address.new(*addr.to_a) } : nil,
1286
1315
  mail.header['In-Reply-To'],
1287
1316
  mail.header['Message-Id'])
1288
1317
  }
1289
- body_type = lambda{|mail|
1290
- case (mail.media_main_type_upcase)
1291
- when 'TEXT'
1318
+ body_type = lambda{|mail, extension=false|
1319
+ body_params = lambda{|params|
1320
+ if (params && ! params.empty?) then
1321
+ Hash[params.map{|n, v| [ n.upcase, v ] }]
1322
+ end
1323
+ }
1324
+ body_disposition = lambda{|mail|
1325
+ if (mail.content_disposition) then
1326
+ Net::IMAP::ContentDisposition.new(mail.content_disposition_upcase,
1327
+ body_params[mail.content_disposition_parameter_list])
1328
+ end
1329
+ }
1330
+ body_language = lambda{|mail|
1331
+ if (mail.content_language) then
1332
+ if (mail.content_language.length > 1) then
1333
+ mail.content_language_upcase
1334
+ else
1335
+ mail.content_language_upcase[0]
1336
+ end
1337
+ end
1338
+ }
1339
+ if (mail.text?) then
1292
1340
  Net::IMAP::BodyTypeText.new(mail.media_main_type_upcase,
1293
1341
  mail.media_sub_type_upcase,
1294
- Hash[mail.content_type_parameters.map{|n, v| [ n.upcase, v ] }],
1342
+ body_params[mail.content_type_parameter_list],
1295
1343
  mail.header['Content-Id'],
1296
1344
  mail.header['Content-Description'],
1297
1345
  mail.header.fetch_upcase('Content-Transfer-Encoding'),
1298
1346
  mail.raw_source.bytesize,
1299
- mail.raw_source.each_line.count)
1300
- when 'MESSAGE'
1347
+ mail.raw_source.each_line.count,
1348
+ *(
1349
+ if (extension) then
1350
+ [ mail.header['Content-MD5'],
1351
+ body_disposition[mail],
1352
+ body_language[mail],
1353
+ [ mail.header['Content-Location'] ]
1354
+ ]
1355
+ else
1356
+ []
1357
+ end
1358
+ ))
1359
+ elsif (mail.message?) then
1301
1360
  Net::IMAP::BodyTypeMessage.new(mail.media_main_type_upcase,
1302
1361
  mail.media_sub_type_upcase,
1303
- Hash[mail.content_type_parameters.map{|n, v| [ n.upcase, v ] }],
1362
+ body_params[mail.content_type_parameter_list],
1304
1363
  mail.header['Content-Id'],
1305
1364
  mail.header['Content-Description'],
1306
1365
  mail.header.fetch_upcase('Content-Transfer-Encoding'),
1307
1366
  mail.raw_source.bytesize,
1308
1367
  envelope[mail.message],
1309
- body_type[mail.message],
1310
- mail.raw_source.each_line.count)
1311
- when 'MULTIPART'
1368
+ body_type[mail.message, extension],
1369
+ mail.raw_source.each_line.count,
1370
+ *(
1371
+ if (extension) then
1372
+ [ mail.header['Content-MD5'],
1373
+ body_disposition[mail],
1374
+ body_language[mail],
1375
+ [ mail.header['Content-Location'] ]
1376
+ ]
1377
+ else
1378
+ []
1379
+ end
1380
+ ))
1381
+ elsif (mail.multipart?) then
1312
1382
  Net::IMAP::BodyTypeMultipart.new(mail.media_main_type_upcase,
1313
1383
  mail.media_sub_type_upcase,
1314
- mail.parts.map{|m| body_type[m] })
1384
+ mail.parts.map{|m| body_type[m, extension] },
1385
+ *(
1386
+ if (extension) then
1387
+ [ body_params[mail.content_type_parameter_list],
1388
+ body_disposition[mail],
1389
+ body_language[mail],
1390
+ [ mail.header['Content-Location'] ]
1391
+ ]
1392
+ else
1393
+ []
1394
+ end
1395
+ ))
1315
1396
  else
1316
1397
  Net::IMAP::BodyTypeBasic.new(mail.media_main_type_upcase,
1317
1398
  mail.media_sub_type_upcase,
1318
- Hash[mail.content_type_parameters.map{|n, v| [ n.upcase, v ] }],
1399
+ body_params[mail.content_type_parameter_list],
1319
1400
  mail.header['Content-Id'],
1320
1401
  mail.header['Content-Description'],
1321
1402
  mail.header.fetch_upcase('Content-Transfer-Encoding'),
1322
- mail.raw_source.bytesize)
1403
+ mail.raw_source.bytesize,
1404
+ *(
1405
+ if (extension) then
1406
+ [ mail.header['Content-MD5'],
1407
+ body_disposition[mail],
1408
+ body_language[mail],
1409
+ [ mail.header['Content-Location'] ]
1410
+ ]
1411
+ else
1412
+ []
1413
+ end
1414
+ ))
1323
1415
  end
1324
1416
  }
1325
1417
 
@@ -1406,9 +1498,9 @@ Hello world.
1406
1498
  imap_fetch.call(msg_set[1..-1], 'BODY'))
1407
1499
 
1408
1500
  assert_equal(fetch_data[
1409
- [ 1, { 'BODYSTRUCTURE' => body_type[@simple_mail] } ],
1410
- [ 2, { 'BODYSTRUCTURE' => body_type[@mpart_mail] } ],
1411
- [ 3, { 'BODYSTRUCTURE' => body_type[@mime_subject_mail] } ]
1501
+ [ 1, { 'BODYSTRUCTURE' => body_type[@simple_mail, true] } ],
1502
+ [ 2, { 'BODYSTRUCTURE' => body_type[@mpart_mail, true] } ],
1503
+ [ 3, { 'BODYSTRUCTURE' => body_type[@mime_subject_mail, true] } ]
1412
1504
  ],
1413
1505
  imap_fetch.call(msg_set[1..-1], 'BODYSTRUCTURE'))
1414
1506
 
@@ -135,8 +135,10 @@ module RIMS::Test
135
135
  output = StringIO.new('', 'w')
136
136
  input_gets = input.method(:gets)
137
137
  output_write = lambda{|res|
138
- for line in res
139
- output << line
138
+ for data in res
139
+ if (data != :flush) then
140
+ output << data
141
+ end
140
142
  end
141
143
  }
142
144
  inout_args = [ input_gets, output_write ]
@@ -158,7 +160,9 @@ module RIMS::Test
158
160
  response_message << output.string
159
161
  end
160
162
  for response in responses
161
- response_message << response
163
+ if (response != :flush) then
164
+ response_message << response
165
+ end
162
166
  end
163
167
  response_lines = StringIO.new(response_message, 'r').each_line
164
168
  ret_val = yield(response_lines)
@@ -242,7 +246,7 @@ module RIMS::Test
242
246
  extend Forwardable
243
247
 
244
248
  def open_mail_store
245
- @services.call_service(:engine, @unique_user_id) {|engine|
249
+ @drb_services.call_service(:engine, @unique_user_id) {|engine|
246
250
  begin
247
251
  @mail_store = engine.mail_store
248
252
  @mail_store.write_synchronize{
@@ -256,7 +260,7 @@ module RIMS::Test
256
260
  private :open_mail_store
257
261
 
258
262
  def make_decoder
259
- RIMS::Protocol::Decoder.new_decoder(@services, @auth, @logger)
263
+ RIMS::Protocol::Decoder.new_decoder(@drb_services, @auth, @logger)
260
264
  end
261
265
  private :make_decoder
262
266
 
@@ -288,20 +292,22 @@ module RIMS::Test
288
292
  }
289
293
  @unique_user_id = RIMS::Authentication.unique_user_id('foo')
290
294
 
291
- @services = Riser::DRbServices.new(0)
292
- @services.add_sticky_process_service(:engine,
293
- Riser::ResourceSet.build{|builder|
294
- builder.at_create{|unique_user_id|
295
- mail_store = RIMS::MailStore.build(unique_user_id, @kvs_open, @kvs_open)
296
- RIMS::Protocol::Decoder::Engine.new(unique_user_id, mail_store, @logger)
297
- }
298
- builder.at_destroy{|engine|
299
- engine.destroy
300
- }
301
- builder.alias_unref(:destroy)
302
- })
303
- @services.start_server
304
- @services.start_client
295
+ @bulk_response_count = 10
296
+ @drb_services = Riser::DRbServices.new(0)
297
+ @drb_services.add_sticky_process_service(:engine,
298
+ Riser::ResourceSet.build{|builder|
299
+ builder.at_create{|unique_user_id|
300
+ mail_store = RIMS::MailStore.build(unique_user_id, @kvs_open, @kvs_open)
301
+ RIMS::Protocol::Decoder::Engine.new(unique_user_id, mail_store, @logger,
302
+ bulk_response_count: @bulk_response_count)
303
+ }
304
+ builder.at_destroy{|engine|
305
+ engine.destroy
306
+ }
307
+ builder.alias_unref(:destroy)
308
+ })
309
+ @drb_services.start_server
310
+ @drb_services.start_client
305
311
 
306
312
  open_mail_store{
307
313
  @inbox_id = @mail_store.mbox_id('INBOX')
@@ -328,8 +334,8 @@ module RIMS::Test
328
334
  end
329
335
 
330
336
  def teardown
331
- assert_equal(0, @services.get_service(:engine, @unique_user_id).proxy_count)
332
- @services.stop_server
337
+ assert_equal(0, @drb_services.get_service(:engine, @unique_user_id).proxy_count)
338
+ @drb_services.stop_server
333
339
  pp @kvs if $DEBUG
334
340
  end
335
341
 
@@ -2439,11 +2445,6 @@ module RIMS::Test
2439
2445
  assert.match(/^#{tag} NO /, peek_next_line: true).match(/not auth/)
2440
2446
  }
2441
2447
 
2442
- if (command_test?) then
2443
- assert_equal(false, @decoder.auth?)
2444
- assert_equal(false, @decoder.selected?)
2445
- end
2446
-
2447
2448
  assert_imap_command('LOGIN foo open_sesame') {|assert|
2448
2449
  assert.equal("#{tag} OK LOGIN completed")
2449
2450
  }
@@ -2591,15 +2592,10 @@ module RIMS::Test
2591
2592
  assert_equal(false, @decoder.selected?)
2592
2593
  end
2593
2594
 
2594
- assert_imap_command('SEARCH CHARSET utf-8 ALL') {|assert|
2595
+ assert_imap_command('SEARCH CHARSET us-ascii ALL') {|assert|
2595
2596
  assert.match(/^#{tag} NO /, peek_next_line: true).match(/not auth/)
2596
2597
  }
2597
2598
 
2598
- if (command_test?) then
2599
- assert_equal(false, @decoder.auth?)
2600
- assert_equal(false, @decoder.selected?)
2601
- end
2602
-
2603
2599
  assert_imap_command('LOGIN foo open_sesame') {|assert|
2604
2600
  assert.equal("#{tag} OK LOGIN completed")
2605
2601
  }
@@ -2609,7 +2605,7 @@ module RIMS::Test
2609
2605
  assert_equal(false, @decoder.selected?)
2610
2606
  end
2611
2607
 
2612
- assert_imap_command('SEARCH CHARSET utf-8 ALL') {|assert|
2608
+ assert_imap_command('SEARCH CHARSET us-ascii ALL') {|assert|
2613
2609
  assert.match(/^#{tag} NO /, peek_next_line: true).match(/not selected/)
2614
2610
  }
2615
2611
 
@@ -2623,17 +2619,17 @@ module RIMS::Test
2623
2619
  assert_equal(true, @decoder.selected?)
2624
2620
  end
2625
2621
 
2626
- assert_imap_command('SEARCH CHARSET utf-8 ALL') {|assert|
2622
+ assert_imap_command('SEARCH CHARSET us-ascii ALL') {|assert|
2627
2623
  assert.equal("* SEARCH 1 2 3 4 5\r\n")
2628
2624
  assert.equal("#{tag} OK SEARCH completed\r\n")
2629
2625
  }
2630
2626
 
2631
- assert_imap_command('SEARCH CHARSET utf-8 BODY foo') {|assert|
2627
+ assert_imap_command('SEARCH CHARSET us-ascii BODY foo') {|assert|
2632
2628
  assert.equal("* SEARCH 1 2 3\r\n")
2633
2629
  assert.equal("#{tag} OK SEARCH completed\r\n")
2634
2630
  }
2635
2631
 
2636
- assert_imap_command('SEARCH CHARSET utf-8 BODY bar') {|assert|
2632
+ assert_imap_command('SEARCH CHARSET us-ascii BODY bar') {|assert|
2637
2633
  assert.equal("* SEARCH\r\n")
2638
2634
  assert.equal("#{tag} OK SEARCH completed\r\n")
2639
2635
  }
@@ -2645,6 +2641,15 @@ module RIMS::Test
2645
2641
  assert.equal("#{tag} OK SEARCH completed\r\n")
2646
2642
  }
2647
2643
 
2644
+ assert_imap_command("SEARCH CHARSET euc-jp BODY {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2645
+ assert.match(/^\+ /)
2646
+ assert.match(/^#{tag} BAD /, peek_next_line: true).match(/syntax error/)
2647
+ }
2648
+
2649
+ assert_imap_command('SEARCH CHARSET x-nothing BODY foo') {|assert|
2650
+ assert.match(/^#{tag} NO \[BADCHARSET \(\S+( \S+)*\)\] unknown charset/)
2651
+ }
2652
+
2648
2653
  assert_imap_command('SEARCH CHARSET') {|assert|
2649
2654
  assert.match(/^#{tag} BAD /, peek_next_line: true).match(/syntax error/)
2650
2655
  }
@@ -2679,6 +2684,7 @@ module RIMS::Test
2679
2684
 
2680
2685
  open_mail_store{
2681
2686
  add_msg("Content-Type: text/plain\r\n" +
2687
+ "\r\n" +
2682
2688
  "foo")
2683
2689
  add_msg("Content-Type: text/plain; charset=utf-8\r\n" +
2684
2690
  "X-foo: dummy\r\n" +
@@ -2705,15 +2711,10 @@ module RIMS::Test
2705
2711
  assert_equal(false, @decoder.selected?)
2706
2712
  end
2707
2713
 
2708
- assert_imap_command('SEARCH CHARSET utf-8 ALL') {|assert|
2714
+ assert_imap_command('SEARCH CHARSET us-ascii ALL') {|assert|
2709
2715
  assert.match(/^#{tag} NO /, peek_next_line: true).match(/not auth/)
2710
2716
  }
2711
2717
 
2712
- if (command_test?) then
2713
- assert_equal(false, @decoder.auth?)
2714
- assert_equal(false, @decoder.selected?)
2715
- end
2716
-
2717
2718
  assert_imap_command('LOGIN foo open_sesame') {|assert|
2718
2719
  assert.equal("#{tag} OK LOGIN completed")
2719
2720
  }
@@ -2723,7 +2724,7 @@ module RIMS::Test
2723
2724
  assert_equal(false, @decoder.selected?)
2724
2725
  end
2725
2726
 
2726
- assert_imap_command('SEARCH CHARSET utf-8 ALL') {|assert|
2727
+ assert_imap_command('SEARCH CHARSET us-ascii ALL') {|assert|
2727
2728
  assert.match(/^#{tag} NO /, peek_next_line: true).match(/not selected/)
2728
2729
  }
2729
2730
 
@@ -2737,12 +2738,12 @@ module RIMS::Test
2737
2738
  assert_equal(true, @decoder.selected?)
2738
2739
  end
2739
2740
 
2740
- assert_imap_command('SEARCH CHARSET utf-8 ALL') {|assert|
2741
+ assert_imap_command('SEARCH CHARSET us-ascii ALL') {|assert|
2741
2742
  assert.equal("* SEARCH 1 2 3 4 5\r\n")
2742
2743
  assert.equal("#{tag} OK SEARCH completed\r\n")
2743
2744
  }
2744
2745
 
2745
- assert_imap_command('SEARCH CHARSET utf-8 TEXT foo') {|assert|
2746
+ assert_imap_command('SEARCH CHARSET us-ascii TEXT foo') {|assert|
2746
2747
  assert.equal("* SEARCH 1 2 3\r\n")
2747
2748
  assert.equal("#{tag} OK SEARCH completed\r\n")
2748
2749
  }
@@ -2752,7 +2753,7 @@ module RIMS::Test
2752
2753
  assert.equal("#{tag} OK SEARCH completed\r\n")
2753
2754
  }
2754
2755
 
2755
- assert_imap_command('SEARCH CHARSET utf-8 TEXT baz') {|assert|
2756
+ assert_imap_command('SEARCH CHARSET us-ascii TEXT baz') {|assert|
2756
2757
  assert.equal("* SEARCH\r\n")
2757
2758
  assert.equal("#{tag} OK SEARCH completed\r\n")
2758
2759
  }
@@ -2764,6 +2765,15 @@ module RIMS::Test
2764
2765
  assert.equal("#{tag} OK SEARCH completed\r\n")
2765
2766
  }
2766
2767
 
2768
+ assert_imap_command("SEARCH CHARSET euc-jp TEXT {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2769
+ assert.match(/^\+ /)
2770
+ assert.match(/^#{tag} BAD /, peek_next_line: true).match(/syntax error/)
2771
+ }
2772
+
2773
+ assert_imap_command('SEARCH CHARSET x-nothing TEXT foo') {|assert|
2774
+ assert.match(/^#{tag} NO \[BADCHARSET \(\S+( \S+)*\)\] unknown charset/)
2775
+ }
2776
+
2767
2777
  assert_imap_command('SEARCH CHARSET') {|assert|
2768
2778
  assert.match(/^#{tag} BAD /, peek_next_line: true).match(/syntax error/)
2769
2779
  }
@@ -2788,6 +2798,140 @@ module RIMS::Test
2788
2798
  test_search_charset_text
2789
2799
  end
2790
2800
 
2801
+ def test_search_charset_skip_encoding_error
2802
+ imap_decode_engine_evaluate{
2803
+ if (stream_test?) then
2804
+ assert_untagged_response{|assert|
2805
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
2806
+ }
2807
+ end
2808
+
2809
+ open_mail_store{
2810
+ add_msg("Content-Type: text/plain\r\n" +
2811
+ "\r\n" +
2812
+ "foo")
2813
+ add_msg("Content-Type: text/plain; charset=iso-2022-jp\r\n" +
2814
+ "\r\n" +
2815
+ # utf-8
2816
+ "\u3053\u3093\u306B\u3061\u306F\r\n" +
2817
+ "\u3044\u308D\u306F\u306B\u307B\u3078\u3068\r\n" +
2818
+ "\u3042\u3044\u3046\u3048\u304A\r\n" +
2819
+ "foo\r\n")
2820
+
2821
+ assert_msg_uid(1, 2)
2822
+ }
2823
+
2824
+ if (command_test?) then
2825
+ assert_equal(false, @decoder.auth?)
2826
+ assert_equal(false, @decoder.selected?)
2827
+ end
2828
+
2829
+ assert_imap_command('LOGIN foo open_sesame') {|assert|
2830
+ assert.equal("#{tag} OK LOGIN completed")
2831
+ }
2832
+
2833
+ if (command_test?) then
2834
+ assert_equal(true, @decoder.auth?)
2835
+ assert_equal(false, @decoder.selected?)
2836
+ end
2837
+
2838
+ assert_imap_command('SELECT INBOX') {|assert|
2839
+ assert.skip_while{|line| line =~ /^\* / }
2840
+ assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
2841
+ }
2842
+
2843
+ if (command_test?) then
2844
+ assert_equal(true, @decoder.auth?)
2845
+ assert_equal(true, @decoder.selected?)
2846
+ end
2847
+
2848
+ assert_imap_command('SEARCH CHARSET us-ascii BODY foo') {|assert|
2849
+ assert.equal("* SEARCH 1\r\n")
2850
+ assert.equal("#{tag} OK SEARCH completed\r\n")
2851
+ }
2852
+
2853
+ utf8_msg = "\u306F\u306B\u307B"
2854
+ assert_imap_command("SEARCH CHARSET utf-8 TEXT {#{utf8_msg.bytesize}}\r\n#{utf8_msg}".b) {|assert|
2855
+ assert.match(/^\+ /)
2856
+ assert.equal("* SEARCH\r\n")
2857
+ assert.equal("#{tag} OK SEARCH completed\r\n")
2858
+ }
2859
+
2860
+ assert_imap_command('LOGOUT') {|assert|
2861
+ assert.match(/^\* BYE /)
2862
+ assert.equal("#{tag} OK LOGOUT completed")
2863
+ }
2864
+ }
2865
+ end
2866
+
2867
+ def test_search_charset_skip_encoding_error_stream
2868
+ use_imap_stream_decode_engine
2869
+ test_search_charset_skip_encoding_error
2870
+ end
2871
+
2872
+ def test_search_interrupt_by_bad_response
2873
+ imap_decode_engine_evaluate{
2874
+ if (stream_test?) then
2875
+ assert_untagged_response{|assert|
2876
+ assert.equal("* OK RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.")
2877
+ }
2878
+ end
2879
+
2880
+ open_mail_store{
2881
+ @bulk_response_count.times do
2882
+ add_msg("Content-Type: text/plain\r\n" +
2883
+ "\r\n" +
2884
+ "foo")
2885
+ end
2886
+
2887
+ add_msg("Content-Type: text/plain; charset=x-nothing\r\n" +
2888
+ "\r\n" +
2889
+ "foo")
2890
+
2891
+ assert_msg_uid(*(1..(@bulk_response_count.succ)).to_a)
2892
+ }
2893
+
2894
+ if (command_test?) then
2895
+ assert_equal(false, @decoder.auth?)
2896
+ assert_equal(false, @decoder.selected?)
2897
+ end
2898
+
2899
+ assert_imap_command('LOGIN foo open_sesame') {|assert|
2900
+ assert.equal("#{tag} OK LOGIN completed")
2901
+ }
2902
+
2903
+ if (command_test?) then
2904
+ assert_equal(true, @decoder.auth?)
2905
+ assert_equal(false, @decoder.selected?)
2906
+ end
2907
+
2908
+ assert_imap_command('SELECT INBOX') {|assert|
2909
+ assert.skip_while{|line| line =~ /^\* / }
2910
+ assert.equal("#{tag} OK [READ-WRITE] SELECT completed")
2911
+ }
2912
+
2913
+ if (command_test?) then
2914
+ assert_equal(true, @decoder.auth?)
2915
+ assert_equal(true, @decoder.selected?)
2916
+ end
2917
+
2918
+ assert_imap_command('SEARCH TEXT foo') {|assert|
2919
+ assert.match(/\A\* SEARCH( \d+)+\r\n\z/, peek_next_line: true).no_match(/ #{@bulk_response_count.succ}/)
2920
+ assert.equal("#{tag} BAD internal server error\r\n")
2921
+ }
2922
+
2923
+ assert_imap_command('LOGOUT') {|assert|
2924
+ assert.match(/^\* BYE /)
2925
+ assert.equal("#{tag} OK LOGOUT completed")
2926
+ }
2927
+ }
2928
+ end
2929
+
2930
+ def test_search_interrupt_by_bad_response_stream
2931
+ use_imap_stream_decode_engine
2932
+ test_search_interrupt_by_bad_response
2933
+ end
2934
+
2791
2935
  def test_fetch
2792
2936
  imap_decode_engine_evaluate{
2793
2937
  if (stream_test?) then