rims 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -169,7 +169,10 @@ Reply-To: foo@nonet.com
169
169
  To: alice@test.com, bob <bob@test.com>
170
170
  Cc: Kate <kate@test.com>
171
171
  Bcc: foo@nonet.com
172
- In-Reply-To: <20131106081723.5KJU1774292@smtp.testt.com>
172
+ MIME-Version: 1.0
173
+ Content-Type: text/plain; charset=us-ascii
174
+ Content-Transfer-Encoding: 7bit
175
+ In-Reply-To: <20131106081723.5KJU1774292@smtp.test.com>
173
176
  Message-Id: <20131107214750.445A1255B9F@smtp.nonet.com>
174
177
 
175
178
  Hello world.
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module RIMS
4
- VERSION = '0.2.4'
4
+ VERSION = '0.2.5'
5
5
  MAILBOX_DATA_STRUCTURE_VERSION = 'mailbox.2'
6
6
  end
7
7
 
@@ -28,6 +28,23 @@ module RIMS::Test
28
28
  @base_dir.rmtree
29
29
  end
30
30
 
31
+ def imap_connect(use_ssl=false)
32
+ imap = timeout(10) {
33
+ begin
34
+ Net::IMAP.new('localhost', 1430, use_ssl, TLS_CA_CERT.to_s)
35
+ rescue SystemCallError
36
+ sleep(0.1)
37
+ retry
38
+ end
39
+ }
40
+ begin
41
+ yield(imap)
42
+ ensure
43
+ imap.disconnect
44
+ end
45
+ end
46
+ private :imap_connect
47
+
31
48
  def test_rims_no_args
32
49
  stdout, stderr, status = Open3.capture3('rims')
33
50
  pp [ stdout, stderr, status ] if $DEBUG
@@ -64,71 +81,102 @@ module RIMS::Test
64
81
  assert_equal('', stderr)
65
82
  end
66
83
 
67
- data('-f' => [ %W[ -f #{BASE_DIR}/config.yml ] ],
68
- '--config-yaml' => [ %W[ --config-yaml #{BASE_DIR}/config.yml ] ],
69
- '-r' => [ %W[ -f #{BASE_DIR}/config.yml -r prime ] ],
70
- '--required-feature' => [ %W[ -f #{BASE_DIR}/config.yml --required-feature=prime ] ],
71
- '-d,--passwd-file' => [ %W[ -d #{BASE_DIR} --passwd-file=plain:passwd.yml ] ],
72
- '--base-dir,--passwd-file' => [ %W[ --base-dir=#{BASE_DIR} --passwd-file=plain:passwd.yml ] ],
73
- '--log-file' => [ %W[ -f #{BASE_DIR}/config.yml --log-file=server.log ] ],
74
- '-l' => [ %W[ -f #{BASE_DIR}/config.yml -l debug ] ],
75
- '--log-level' => [ %W[ -f #{BASE_DIR}/config.yml --log-level=debug ] ],
76
- '--log-shift-age' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age=10 ] ],
77
- '--log-shift-daily' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age-daily ] ],
78
- '--log-shift-weekly' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age-weekly ] ],
79
- '--log-shift-monthly' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age-monthly ] ],
80
- '--log-shift-size' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-size=1048576 ] ],
81
- '-v' => [ %W[ -f #{BASE_DIR}/config.yml -v debug ] ],
82
- '--log-stdout' => [ %W[ -f #{BASE_DIR}/config.yml --log-stdout=debug ] ],
83
- '--protocol-log-file' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-file=imap.log ] ],
84
- '-p' => [ %W[ -f #{BASE_DIR}/config.yml -p info ] ],
85
- '--protocol-log-level' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-level=info ] ],
86
- '--protocol-log-shift-age' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age=10 ] ],
87
- '--protocol-log-shift-age-daily' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age-daily ] ],
88
- '--protocol-log-shift-age-weekly' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age-weekly ] ],
89
- '--protocol-log-shift-age-monthly' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age-monthly ] ],
90
- '--protocol-log-shift-size' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-size=1048576 ] ],
91
- '--daemonize' => [ %W[ -f #{BASE_DIR}/config.yml --daemonize ] ],
92
- '--no-daemonize' => [ %W[ -f #{BASE_DIR}/config.yml --no-daemonize ] ],
93
- '--daemon-debug' => [ %W[ -f #{BASE_DIR}/config.yml --daemon-debug ] ],
94
- '--no-daemon-debug' => [ %W[ -f #{BASE_DIR}/config.yml --no-daemon-debug ] ],
95
- '--status-file' => [ %W[ -f #{BASE_DIR}/config.yml --status-file=status.yml ] ],
96
- '--privilege-user' => [ %W[ -f #{BASE_DIR}/config.yml --privilege-user=#{Process::UID.eid} ] ],
97
- '--privilege-group' => [ %W[ -f #{BASE_DIR}/config.yml --privilege-group=#{Process::GID.eid} ] ],
98
- '-s' => [ %W[ -f #{BASE_DIR}/config.yml -s localhost:1430 ] ],
99
- '--listen' => [ %W[ -f #{BASE_DIR}/config.yml --listen=localhost:1430 ] ],
100
- '--accept-polling-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --accept-polling-timeout=0.1 ] ],
101
- '--thread-num' => [ %W[ -f #{BASE_DIR}/config.yml --thread-num=4 ] ],
102
- '--thread-queue-size' => [ %W[ -f #{BASE_DIR}/config.yml --thread-queue-size=128 ] ],
103
- '--thread-queue-polling-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --thread-queue-polling-timeout=0.1 ] ],
104
- '--send-buffer-limit' => [ %W[ -f #{BASE_DIR}/config.yml --send-buffer-limit=131072 ] ],
105
- '--read-polling-interval' => [ %W[ -f #{BASE_DIR}/config.yml --read-polling-interval=5 ] ],
106
- '--command-wait-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --command-wait-timeout=3600 ] ],
107
- '--read-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --read-lock-timeout=10 ] ],
108
- '--write-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --write-lock-timeout=10 ] ],
109
- '--clenup-write-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --write-lock-timeout=5 ] ],
110
- '--meta-kvs-type' => [ %W[ -f #{BASE_DIR}/config.yml --meta-kvs-type=gdbm ] ],
111
- '--meta-kvs-config' => [ %W[ -f #{BASE_DIR}/config.yml --meta-kvs-config={} ] ],
112
- '--use-meta-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --use-meta-kvs-checksum ] ],
113
- '--no-use-meta-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-meta-kvs-checksum ] ],
114
- '--text-kvs-type' => [ %W[ -f #{BASE_DIR}/config.yml --text-kvs-type=gdbm ] ],
115
- '--text-kvs-config' => [ %W[ -f #{BASE_DIR}/config.yml --text-kvs-config={} ] ],
116
- '--use-text-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --use-text-kvs-checksum ] ],
117
- '--no-use-text-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-text-kvs-checksum ] ],
118
- '--auth-hostname' => [ %W[ -f #{BASE_DIR}/config.yml --auth-hostname=imap.example.com ] ],
119
- '--passwd-config' => [ %W[ -d #{BASE_DIR} --passwd-config=plain:[{"user":"foo","pass":"foo"}] ] ],
120
- '--mail-delivery-user' => [ %W[ -f #{BASE_DIR}/config.yml --mail-delivery-user=postman ] ],
121
-
122
- # deplicated options
123
- 'deplicated:--imap-host' => [ %W[ -f #{BASE_DIR}/config.yml --imap-host=localhost ], true ],
124
- 'deplicated:--imap-port' => [ %W[ -f #{BASE_DIR}/config.yml --imap-port=1430 ], true ],
125
- 'deplicated:--ip-addr' => [ %W[ -f #{BASE_DIR}/config.yml --ip-addr=0.0.0.0 ], true ],
126
- 'deplicated:--ip-port' => [ %W[ -f #{BASE_DIR}/config.yml --ip-port=1430 ], true ],
127
- 'deplicated:--kvs-type' => [ %W[ -f #{BASE_DIR}/config.yml --kvs-type=gdbm ], true ],
128
- 'deplicated:--use-kvs-cksum' => [ %W[ -f #{BASE_DIR}/config.yml --use-kvs-cksum ], true ],
129
- 'deplicated:--no-use-kvs-cksum' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-kvs-cksum ], true ],
130
- 'deplicated:-u,-w' => [ %W[ -d #{BASE_DIR} -u foo -w foo ], true ],
131
- 'deplicated:--username,--password' => [ %W[ -d #{BASE_DIR} --username=foo --password=foo ], true ])
84
+ data(
85
+ # base:
86
+ '-f' => [ %W[ -f #{BASE_DIR}/config.yml ] ],
87
+ '--config-yaml' => [ %W[ --config-yaml #{BASE_DIR}/config.yml ] ],
88
+ '-r' => [ %W[ -f #{BASE_DIR}/config.yml -r prime ] ],
89
+ '--required-feature' => [ %W[ -f #{BASE_DIR}/config.yml --required-feature=prime ] ],
90
+ '-d,--passwd-file' => [ %W[ -d #{BASE_DIR} --passwd-file=plain:passwd.yml ] ],
91
+ '--base-dir,--passwd-file' => [ %W[ --base-dir=#{BASE_DIR} --passwd-file=plain:passwd.yml ] ],
92
+
93
+ # logging file:
94
+ '--log-file' => [ %W[ -f #{BASE_DIR}/config.yml --log-file=server.log ] ],
95
+ '-l' => [ %W[ -f #{BASE_DIR}/config.yml -l debug ] ],
96
+ '--log-level' => [ %W[ -f #{BASE_DIR}/config.yml --log-level=debug ] ],
97
+ '--log-shift-age' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age=10 ] ],
98
+ '--log-shift-daily' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age-daily ] ],
99
+ '--log-shift-weekly' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age-weekly ] ],
100
+ '--log-shift-monthly' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-age-monthly ] ],
101
+ '--log-shift-size' => [ %W[ -f #{BASE_DIR}/config.yml --log-shift-size=1048576 ] ],
102
+
103
+ # logging stdout:
104
+ '-v' => [ %W[ -f #{BASE_DIR}/config.yml -v debug ] ],
105
+ '--log-stdout' => [ %W[ -f #{BASE_DIR}/config.yml --log-stdout=debug ] ],
106
+
107
+ # logging protocol:
108
+ '--protocol-log-file' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-file=imap.log ] ],
109
+ '-p' => [ %W[ -f #{BASE_DIR}/config.yml -p info ] ],
110
+ '--protocol-log-level' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-level=info ] ],
111
+ '--protocol-log-shift-age' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age=10 ] ],
112
+ '--protocol-log-shift-age-daily' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age-daily ] ],
113
+ '--protocol-log-shift-age-weekly' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age-weekly ] ],
114
+ '--protocol-log-shift-age-monthly' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-age-monthly ] ],
115
+ '--protocol-log-shift-size' => [ %W[ -f #{BASE_DIR}/config.yml --protocol-log-shift-size=1048576 ] ],
116
+
117
+ # daemon:
118
+ '--daemonize' => [ %W[ -f #{BASE_DIR}/config.yml --daemonize ] ],
119
+ '--no-daemonize' => [ %W[ -f #{BASE_DIR}/config.yml --no-daemonize ] ],
120
+ '--daemon-debug' => [ %W[ -f #{BASE_DIR}/config.yml --daemon-debug ] ],
121
+ '--no-daemon-debug' => [ %W[ -f #{BASE_DIR}/config.yml --no-daemon-debug ] ],
122
+ '--status-file' => [ %W[ -f #{BASE_DIR}/config.yml --status-file=status.yml ] ],
123
+ '--privilege-user' => [ %W[ -f #{BASE_DIR}/config.yml --privilege-user=#{Process::UID.eid} ] ],
124
+ '--privilege-group' => [ %W[ -f #{BASE_DIR}/config.yml --privilege-group=#{Process::GID.eid} ] ],
125
+
126
+ # server:
127
+ '-s' => [ %W[ -f #{BASE_DIR}/config.yml -s localhost:1430 ] ],
128
+ '--listen' => [ %W[ -f #{BASE_DIR}/config.yml --listen=localhost:1430 ] ],
129
+ '--accept-polling-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --accept-polling-timeout=0.1 ] ],
130
+ '--process-num' => [ %W[ -f #{BASE_DIR}/config.yml --process-num=4 ] ],
131
+ '--process-num,--process-queue-size' => [ %W[ -f #{BASE_DIR}/config.yml --process-num=4 --process-queue-size=64 ] ],
132
+ '--process-num,--process-queue-polling-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --process-num=4 --process-queue-polling-timeout=0.1 ] ],
133
+ '--process-num,--process-send-io-polling-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --process-num=4 --process-send-io-polling-timeout=0.1 ] ],
134
+ '--thread-num' => [ %W[ -f #{BASE_DIR}/config.yml --thread-num=4 ] ],
135
+ '--thread-queue-size' => [ %W[ -f #{BASE_DIR}/config.yml --thread-queue-size=128 ] ],
136
+ '--thread-queue-polling-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --thread-queue-polling-timeout=0.1 ] ],
137
+
138
+ # connection:
139
+ '--send-buffer-limit' => [ %W[ -f #{BASE_DIR}/config.yml --send-buffer-limit=131072 ] ],
140
+ '--read-polling-interval' => [ %W[ -f #{BASE_DIR}/config.yml --read-polling-interval=5 ] ],
141
+ '--command-wait-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --command-wait-timeout=3600 ] ],
142
+
143
+ # drb_services:
144
+ '--drb-process-num' => [ %W[ -f #{BASE_DIR}/config.yml --drb-process-num=4 ] ],
145
+
146
+ # drb_services engine:
147
+ '--bulk-response-count' => [ %W[ -f #{BASE_DIR}/config.yml --bulk-response-count=128 ] ],
148
+ '--read-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --read-lock-timeout=10 ] ],
149
+ '--write-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --write-lock-timeout=10 ] ],
150
+ '--clenup-write-lock-timeout' => [ %W[ -f #{BASE_DIR}/config.yml --write-lock-timeout=5 ] ],
151
+
152
+ # storage meta_key_value_store:
153
+ '--meta-kvs-type' => [ %W[ -f #{BASE_DIR}/config.yml --meta-kvs-type=gdbm ] ],
154
+ '--meta-kvs-config' => [ %W[ -f #{BASE_DIR}/config.yml --meta-kvs-config={} ] ],
155
+ '--use-meta-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --use-meta-kvs-checksum ] ],
156
+ '--no-use-meta-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-meta-kvs-checksum ] ],
157
+
158
+ # storage text_key_value_store:
159
+ '--text-kvs-type' => [ %W[ -f #{BASE_DIR}/config.yml --text-kvs-type=gdbm ] ],
160
+ '--text-kvs-config' => [ %W[ -f #{BASE_DIR}/config.yml --text-kvs-config={} ] ],
161
+ '--use-text-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --use-text-kvs-checksum ] ],
162
+ '--no-use-text-kvs-checksum' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-text-kvs-checksum ] ],
163
+
164
+ # authentication:
165
+ '--auth-hostname' => [ %W[ -f #{BASE_DIR}/config.yml --auth-hostname=imap.example.com ] ],
166
+ '--passwd-config' => [ %W[ -d #{BASE_DIR} --passwd-config=plain:[{"user":"foo","pass":"foo"}] ] ],
167
+ '--mail-delivery-user' => [ %W[ -f #{BASE_DIR}/config.yml --mail-delivery-user=postman ] ],
168
+
169
+ # deplicated options
170
+ 'deplicated:--imap-host' => [ %W[ -f #{BASE_DIR}/config.yml --imap-host=localhost ], true ],
171
+ 'deplicated:--imap-port' => [ %W[ -f #{BASE_DIR}/config.yml --imap-port=1430 ], true ],
172
+ 'deplicated:--ip-addr' => [ %W[ -f #{BASE_DIR}/config.yml --ip-addr=0.0.0.0 ], true ],
173
+ 'deplicated:--ip-port' => [ %W[ -f #{BASE_DIR}/config.yml --ip-port=1430 ], true ],
174
+ 'deplicated:--kvs-type' => [ %W[ -f #{BASE_DIR}/config.yml --kvs-type=gdbm ], true ],
175
+ 'deplicated:--use-kvs-cksum' => [ %W[ -f #{BASE_DIR}/config.yml --use-kvs-cksum ], true ],
176
+ 'deplicated:--no-use-kvs-cksum' => [ %W[ -f #{BASE_DIR}/config.yml --no-use-kvs-cksum ], true ],
177
+ 'deplicated:-u,-w' => [ %W[ -d #{BASE_DIR} -u foo -w foo ], true ],
178
+ 'deplicated:--username,--password' => [ %W[ -d #{BASE_DIR} --username=foo --password=foo ], true ]
179
+ )
132
180
  def test_server(data)
133
181
  options, deplicated = data
134
182
 
@@ -155,15 +203,7 @@ module RIMS::Test
155
203
  result
156
204
  }
157
205
 
158
- imap = timeout(10) {
159
- begin
160
- Net::IMAP.new('localhost', 1430)
161
- rescue SystemCallError
162
- sleep(0.1)
163
- retry
164
- end
165
- }
166
- begin
206
+ imap_connect{|imap|
167
207
  imap.noop
168
208
  imap.login('foo', 'foo')
169
209
  imap.noop
@@ -174,9 +214,7 @@ module RIMS::Test
174
214
  fetch_list = imap.fetch(1, %w[ RFC822 ])
175
215
  assert_equal([ 'HALO' ], fetch_list.map{|f| f.attr['RFC822'] })
176
216
  imap.logout
177
- ensure
178
- imap.disconnect
179
- end
217
+ }
180
218
  ensure
181
219
  Process.kill(:TERM, wait_thread.pid)
182
220
  stdout_result = stdout_thread.value if stdout_thread
@@ -241,15 +279,7 @@ module RIMS::Test
241
279
  assert_equal('', stderr)
242
280
  assert_equal(0, status.exitstatus)
243
281
 
244
- imap = timeout(10) {
245
- begin
246
- Net::IMAP.new('localhost', 1430)
247
- rescue SystemCallError
248
- sleep(0.1)
249
- retry
250
- end
251
- }
252
- begin
282
+ imap_connect{|imap|
253
283
  imap.noop
254
284
  imap.login('foo', 'foo')
255
285
  imap.noop
@@ -260,9 +290,7 @@ module RIMS::Test
260
290
  fetch_list = imap.fetch(1, %w[ RFC822 ])
261
291
  assert_equal([ 'HALO' ], fetch_list.map{|f| f.attr['RFC822'] })
262
292
  imap.logout
263
- ensure
264
- imap.disconnect
265
- end
293
+ }
266
294
 
267
295
  stdout, stderr, status = Open3.capture3('rims', 'daemon', 'status', '-d', @base_dir.to_s)
268
296
  pp [ stdout, stderr, status ] if $DEBUG
@@ -360,35 +388,32 @@ module RIMS::Test
360
388
  Open3.popen3('rims', 'server', '-f', config_path.to_s) {|stdin, stdout, stderr, wait_thread|
361
389
  begin
362
390
  stdout_thread = Thread.new{
363
- result = stdout.read
364
- puts [ :stdout, result ].pretty_inspect if $DEBUG
365
- result
391
+ for line in stdout
392
+ puts "stdout: #{line}" if $DEBUG
393
+ end
366
394
  }
367
395
  stderr_thread = Thread.new{
368
- result = stderr.read
369
- puts [ :stderr, result ].pretty_inspect if $DEBUG
370
- result
371
- }
372
-
373
- imap = timeout(10) {
374
- begin
375
- Net::IMAP.new('localhost', 1430, use_ssl, TLS_CA_CERT.to_s)
376
- rescue SystemCallError
377
- sleep(0.1)
378
- retry
396
+ for line in stderr
397
+ puts "stderr: #{line}" if $DEBUG
379
398
  end
380
399
  }
381
- begin
400
+
401
+ ret_val = nil
402
+ imap_connect(use_ssl) {|imap|
382
403
  imap.noop
383
404
  ret_val = yield(imap)
384
- imap.logout
385
- ensure
386
- imap.disconnect
387
- end
405
+ imap.logout unless imap.disconnected?
406
+ }
388
407
  ensure
389
408
  Process.kill(:TERM, wait_thread.pid)
390
409
  stdout_thread.join if stdout_thread
391
410
  stderr_thread.join if stderr_thread
411
+ if ($DEBUG) then
412
+ p :rims_log
413
+ puts((@base_dir + 'rims.log').read)
414
+ p :protocol_log
415
+ puts((@base_dir + 'protocol.log').read)
416
+ end
392
417
  end
393
418
 
394
419
  server_status = wait_thread.value
@@ -992,6 +1017,976 @@ Hello world.
992
1017
  end
993
1018
  assert_equal(0, status.exitstatus)
994
1019
  end
1020
+
1021
+ include ProtocolFetchMailSample
1022
+
1023
+ data('default' => {},
1024
+ 'use_ssl' => { use_ssl: true },
1025
+ 'multi-process' => { process_num: 4 },
1026
+ 'use_ssl,multi-process' => {
1027
+ use_ssl: true,
1028
+ process_num: 4
1029
+ })
1030
+ def test_system(data)
1031
+ use_ssl = (data.key? :use_ssl) ? data[:use_ssl] : false
1032
+ process_num = data[:process_num] || 0
1033
+
1034
+ config = {
1035
+ server: {
1036
+ process_num: process_num
1037
+ },
1038
+ drb_services: {
1039
+ process_num: process_num
1040
+ }
1041
+ }
1042
+
1043
+ run_server(use_ssl: use_ssl, optional: config) {|imap|
1044
+ assert_imap_no_response = lambda{|error_message_pattern, &block|
1045
+ error_response = assert_raise(Net::IMAP::NoResponseError) { block.call }
1046
+ assert_match(error_message_pattern, error_response.message)
1047
+ }
1048
+
1049
+ assert_no_response_authenticated_state_imap_commands = lambda{|error_message_pattern|
1050
+ assert_imap_no_response[error_message_pattern] { imap.subscribe('INBOX') }
1051
+ assert_imap_no_response[error_message_pattern] { imap.unsubscribe('INBOX') }
1052
+ assert_imap_no_response[error_message_pattern] { imap.list('', '*') }
1053
+ assert_imap_no_response[error_message_pattern] { imap.lsub('', '*') }
1054
+ assert_imap_no_response[error_message_pattern] { imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]) }
1055
+ assert_imap_no_response[error_message_pattern] { imap.create('foo') }
1056
+ assert_imap_no_response[error_message_pattern] { imap.rename('foo', 'bar') }
1057
+ assert_imap_no_response[error_message_pattern] { imap.delete('bar') }
1058
+ assert_imap_no_response[error_message_pattern] { imap.append('INBOX', 'a') }
1059
+ assert_imap_no_response[error_message_pattern] { imap.select('INBOX') }
1060
+ assert_imap_no_response[error_message_pattern] { imap.examine('INBOX') }
1061
+ }
1062
+
1063
+ assert_no_response_selected_state_imap_commands = lambda{|error_message_pattern|
1064
+ assert_imap_no_response[error_message_pattern] { imap.check }
1065
+ assert_imap_no_response[error_message_pattern] { imap.search(%w[ * ]) }
1066
+ assert_imap_no_response[error_message_pattern] { imap.uid_search(%w[ * ]) }
1067
+ assert_imap_no_response[error_message_pattern] { imap.fetch(1..-1, 'RFC822') }
1068
+ assert_imap_no_response[error_message_pattern] { imap.uid_fetch(1..-1, 'RFC822') }
1069
+ assert_imap_no_response[error_message_pattern] { imap.store(1..-1, '+FLAGS', [ :Deleted ]) }
1070
+ assert_imap_no_response[error_message_pattern] { imap.uid_store(1..-1, '+FLAGS', [ :Deleted ]) }
1071
+ assert_imap_no_response[error_message_pattern] { imap.copy(1..-1, 'foo') }
1072
+ assert_imap_no_response[error_message_pattern] { imap.uid_copy(1..-1, 'foo') }
1073
+ assert_imap_no_response[error_message_pattern] { imap.expunge }
1074
+ assert_imap_no_response[error_message_pattern] { imap.idle(0.1) { flunk } } # error log is a Net::IMAP bug to ignore Command Continuation Request
1075
+ assert_imap_no_response[error_message_pattern] { imap.close }
1076
+ }
1077
+
1078
+ # State: Not Authenticated
1079
+ assert_equal('OK', imap.greeting.name)
1080
+ assert_equal("RIMS v#{RIMS::VERSION} IMAP4rev1 service ready.", imap.greeting.data.text)
1081
+
1082
+ # IMAP commands for Any State
1083
+ assert_equal(%w[ IMAP4REV1 UIDPLUS IDLE AUTH=PLAIN AUTH=CRAM-MD5 ], imap.capability)
1084
+ imap.noop
1085
+
1086
+ # IMAP commands for Authenticated State
1087
+ assert_no_response_authenticated_state_imap_commands.call(/not authenticated/)
1088
+
1089
+ # IMAP commands for Selected State
1090
+ assert_no_response_selected_state_imap_commands.call(/not authenticated/)
1091
+
1092
+ imap_connect(use_ssl) {|imap_auth_plain|
1093
+ imap_auth_plain.authenticate('PLAIN', 'foo', 'foo')
1094
+ imap_auth_plain.logout
1095
+ }
1096
+
1097
+ imap_connect(use_ssl) {|imap_auth_cram_md5|
1098
+ imap_auth_cram_md5.authenticate('CRAM-MD5', 'foo', 'foo')
1099
+ imap_auth_cram_md5.logout
1100
+ }
1101
+
1102
+ # State: Not Authenticated -> Authenticated
1103
+ imap.login('foo', 'foo')
1104
+
1105
+ # IMAP commands for Any State
1106
+ assert_equal(%w[ IMAP4REV1 UIDPLUS IDLE AUTH=PLAIN AUTH=CRAM-MD5 ], imap.capability)
1107
+ imap.noop
1108
+
1109
+ # IMAP commands for Authenticated State
1110
+ imap.subscribe('INBOX')
1111
+ assert_imap_no_response[/not implemented/] { imap.unsubscribe('INBOX') }
1112
+
1113
+ assert_equal([ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'INBOX' } ],
1114
+ imap.list('', '*').map(&:to_h))
1115
+ assert_equal([ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'INBOX' } ],
1116
+ imap.lsub('', '*').map(&:to_h))
1117
+
1118
+ status = {
1119
+ 'MESSAGES' => 0,
1120
+ 'RECENT' => 0,
1121
+ 'UNSEEN' => 0,
1122
+ 'UIDNEXT' => 1,
1123
+ 'UIDVALIDITY' => 1
1124
+ }
1125
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1126
+
1127
+ # INBOX will not be changed.
1128
+ assert_imap_no_response[/duplicated mailbox/] { imap.create('INBOX') }
1129
+ assert_imap_no_response[/not rename inbox/] { imap.rename('INBOX', 'foo') }
1130
+ assert_imap_no_response[/not delete inbox/] { imap.delete('INBOX') }
1131
+ assert_equal([ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'INBOX' } ], imap.list('', '*').map(&:to_h))
1132
+
1133
+ imap.create('foo')
1134
+ assert_equal([ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'INBOX' },
1135
+ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'foo' }
1136
+ ],
1137
+ imap.list('', '*').map(&:to_h))
1138
+ imap.rename('foo', 'bar')
1139
+ assert_equal([ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'INBOX' },
1140
+ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'bar' }
1141
+ ],
1142
+ imap.list('', '*').map(&:to_h))
1143
+ imap.delete('bar')
1144
+ assert_equal([ { attr: [:Noinferiors, :Unmarked], delim: nil, name: 'INBOX' } ],
1145
+ imap.list('', '*').map(&:to_h))
1146
+
1147
+ # IMAP commands for Selected State
1148
+ assert_no_response_selected_state_imap_commands.call(/not selected/)
1149
+
1150
+ append_inbox = lambda{|message, *optional|
1151
+ imap.append('INBOX', message, *optional)
1152
+ if (optional[0] && (optional[0].is_a? Array)) then
1153
+ flags = optional[0]
1154
+ else
1155
+ flags = []
1156
+ end
1157
+ status['MESSAGES'] += 1
1158
+ status['RECENT'] += 1
1159
+ status['UNSEEN'] += 1 unless (flags.include? :Seen)
1160
+ status['UIDNEXT'] += 1
1161
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1162
+ }
1163
+
1164
+ # message UID offset
1165
+ uid_offset = 6
1166
+ uid_offset.times do
1167
+ append_inbox.call('', [ :Deleted ])
1168
+ end
1169
+ imap.select('INBOX')
1170
+ assert_equal((1..uid_offset).to_a.reverse, imap.expunge)
1171
+ imap.close
1172
+ status['MESSAGES'] -= uid_offset
1173
+ status['RECENT'] = 0
1174
+ status['UNSEEN'] -= uid_offset
1175
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1176
+
1177
+ make_mail_simple
1178
+ append_inbox.call(@simple_mail.raw_source, [ :Answered, :Flagged ], @simple_mail.date)
1179
+
1180
+ # reset recent flag
1181
+ imap.select('INBOX')
1182
+ imap.close
1183
+ status['RECENT'] = 0
1184
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1185
+
1186
+ make_mail_multipart
1187
+ append_inbox.call(@mpart_mail.raw_source, [ :Draft, :Seen ], @mpart_mail.date)
1188
+
1189
+ make_mail_mime_subject
1190
+ append_inbox.call(@mime_subject_mail.raw_source, @mime_subject_mail.date)
1191
+
1192
+ assert_imap_search = lambda{|uid|
1193
+ if (uid) then
1194
+ imap_search = imap.method(:uid_search)
1195
+ seqno = lambda{|*args| args.map{|i| uid_offset + i } }
1196
+ else
1197
+ imap_search = imap.method(:search)
1198
+ seqno = lambda{|*args| args }
1199
+ end
1200
+
1201
+ assert_equal(seqno[2], imap_search.call([ 2 ]))
1202
+ assert_equal(seqno[1, 2, 3], imap_search.call(%w[ ALL ]))
1203
+ assert_equal(seqno[1], imap_search.call([ 'ANSWERED' ])) # *a
1204
+ assert_equal(seqno[3], imap_search.call([ 'BCC', 'foo' ])) # *b
1205
+ assert_equal(seqno[1], imap_search.call([ 'BEFORE', @mpart_mail.date ]))
1206
+ assert_equal(seqno[1, 3], imap_search.call([ 'BODY', 'Hello world.' ]))
1207
+ assert_equal(seqno[3], imap_search.call([ 'CC', 'kate' ]))
1208
+ assert_equal(seqno[], imap_search.call([ 'DELETED' ]))
1209
+ assert_equal(seqno[2], imap_search.call([ 'DRAFT' ]))
1210
+ assert_equal(seqno[1], imap_search.call([ 'FLAGGED' ]))
1211
+ assert_equal(seqno[2, 3], imap_search.call([ 'FROM', 'foo' ]))
1212
+ assert_equal(seqno[3], imap_search.call([ 'HEADER', 'Message-Id', '20131107214750.445A1255B9F' ]))
1213
+ assert_equal(seqno[], imap_search.call([ 'KEYWORD', 'unsupported' ]))
1214
+ assert_equal(seqno[2], imap_search.call([ 'LARGER', @mime_subject_mail.raw_source.bytesize ])) # *c
1215
+ assert_equal(seqno[3], imap_search.call([ 'NEW' ]))
1216
+ assert_equal(seqno[1], imap_search.call([ 'OLD' ]))
1217
+ assert_equal(seqno[1], imap_search.call([ 'ON', @simple_mail.date ]))
1218
+ assert_equal(seqno[2, 3], imap_search.call([ 'RECENT' ]))
1219
+ assert_equal(seqno[2], imap_search.call([ 'SEEN' ]))
1220
+ assert_equal(seqno[1], imap_search.call([ 'SENTBEFORE', @mpart_mail.date ]))
1221
+ assert_equal(seqno[1], imap_search.call([ 'SENTON', @simple_mail.date ]))
1222
+ assert_equal(seqno[2, 3], imap_search.call([ 'SENTSINCE', @simple_mail.date ]))
1223
+ assert_equal(seqno[1], imap_search.call([ 'SMALLER', @mime_subject_mail.raw_source.bytesize ]))
1224
+ assert_equal(seqno[2], imap_search.call([ 'SUBJECT', 'multipart' ]))
1225
+ assert_equal(seqno[1], imap_search.call([ 'TEXT', 'Subject: test' ]))
1226
+ assert_equal(seqno[1, 2, 3], imap_search.call([ 'TEXT', 'Hello world.' ]))
1227
+ assert_equal(seqno[1], imap_search.call([ 'TO', 'foo' ]))
1228
+ assert_equal(seqno[1], imap_search.call([ 'UID', uid_offset + 1 ]))
1229
+ assert_equal(seqno[2, 3], imap_search.call([ 'UNANSWERED' ]))
1230
+ assert_equal(seqno[1, 2, 3], imap_search.call([ 'UNDELETED' ]))
1231
+ assert_equal(seqno[1, 3], imap_search.call([ 'UNDRAFT' ]))
1232
+ assert_equal(seqno[2, 3], imap_search.call([ 'UNFLAGGED' ]))
1233
+ assert_equal(seqno[1, 2, 3], imap_search.call([ 'UNKEYWORD', 'unsupported' ]))
1234
+ assert_equal(seqno[1, 3], imap_search.call([ 'UNSEEN' ]))
1235
+ assert_equal(seqno[1, 3], imap_search.call([ 'NOT', 'LARGER', @mime_subject_mail.raw_source.bytesize ])) # not *c
1236
+ assert_equal(seqno[1, 3], imap_search.call([ 'OR', 'ANSWERED', 'BCC', 'foo' ])) # or *a *b
1237
+ }
1238
+ assert_imap_search_seqno = lambda{ assert_imap_search.call(false) }
1239
+ assert_imap_search_uid = lambda{ assert_imap_search.call(true) }
1240
+
1241
+ imap_date_fmt = '%d-%b-%Y %H:%M:%S %z'
1242
+ assert_imap_fetch_read_only = lambda{|uid|
1243
+ if (uid) then
1244
+ imap_fetch = imap.method(:uid_fetch)
1245
+ msg_set = lambda{|seqno_set|
1246
+ case (seqno_set)
1247
+ when Array
1248
+ seqno_set.map{|i| uid_offset + i }
1249
+ when Range
1250
+ first = uid_offset + seqno_set.first
1251
+ if (seqno_set.last >= 0) then
1252
+ last = uid_offset + seqno_set.last
1253
+ else
1254
+ last = seqno_set.last
1255
+ end
1256
+ first..last
1257
+ when Integer
1258
+ uid_offset + seqno_set
1259
+ else
1260
+ raise TypeError, "unknown message set type: #{seqno_set}"
1261
+ end
1262
+ }
1263
+ fetch_data = lambda{|*data_list|
1264
+ data_list.map{|seqno, attr|
1265
+ unless (attr.key? 'UID') then
1266
+ attr = attr.merge({ 'UID' => uid_offset + seqno })
1267
+ end
1268
+ Net::IMAP::FetchData.new(seqno, attr)
1269
+ }
1270
+ }
1271
+ else
1272
+ imap_fetch = imap.method(:fetch)
1273
+ msg_set = lambda{|seqno_set| seqno_set }
1274
+ fetch_data = lambda{|*data_list| data_list.map{|i| Net::IMAP::FetchData.new(*i) } }
1275
+ end
1276
+
1277
+ envelope = lambda{|mail|
1278
+ Net::IMAP::Envelope.new(mail.header['Date'],
1279
+ 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,
1286
+ mail.header['In-Reply-To'],
1287
+ mail.header['Message-Id'])
1288
+ }
1289
+ body_type = lambda{|mail|
1290
+ case (mail.media_main_type_upcase)
1291
+ when 'TEXT'
1292
+ Net::IMAP::BodyTypeText.new(mail.media_main_type_upcase,
1293
+ mail.media_sub_type_upcase,
1294
+ Hash[mail.content_type_parameters.map{|n, v| [ n.upcase, v ] }],
1295
+ mail.header['Content-Id'],
1296
+ mail.header['Content-Description'],
1297
+ mail.header.fetch_upcase('Content-Transfer-Encoding'),
1298
+ mail.raw_source.bytesize,
1299
+ mail.raw_source.each_line.count)
1300
+ when 'MESSAGE'
1301
+ Net::IMAP::BodyTypeMessage.new(mail.media_main_type_upcase,
1302
+ mail.media_sub_type_upcase,
1303
+ Hash[mail.content_type_parameters.map{|n, v| [ n.upcase, v ] }],
1304
+ mail.header['Content-Id'],
1305
+ mail.header['Content-Description'],
1306
+ mail.header.fetch_upcase('Content-Transfer-Encoding'),
1307
+ mail.raw_source.bytesize,
1308
+ envelope[mail.message],
1309
+ body_type[mail.message],
1310
+ mail.raw_source.each_line.count)
1311
+ when 'MULTIPART'
1312
+ Net::IMAP::BodyTypeMultipart.new(mail.media_main_type_upcase,
1313
+ mail.media_sub_type_upcase,
1314
+ mail.parts.map{|m| body_type[m] })
1315
+ else
1316
+ Net::IMAP::BodyTypeBasic.new(mail.media_main_type_upcase,
1317
+ mail.media_sub_type_upcase,
1318
+ Hash[mail.content_type_parameters.map{|n, v| [ n.upcase, v ] }],
1319
+ mail.header['Content-Id'],
1320
+ mail.header['Content-Description'],
1321
+ mail.header.fetch_upcase('Content-Transfer-Encoding'),
1322
+ mail.raw_source.bytesize)
1323
+ end
1324
+ }
1325
+
1326
+ assert_equal(fetch_data[
1327
+ [ 1,
1328
+ { 'FLAGS' => [ :Answered, :Flagged ],
1329
+ 'INTERNALDATE' => @simple_mail.date.getutc.strftime(imap_date_fmt),
1330
+ 'RFC822.SIZE' => @simple_mail.raw_source.bytesize,
1331
+ 'ENVELOPE' => envelope[@simple_mail]
1332
+ }
1333
+ ],
1334
+ [ 2,
1335
+ { 'FLAGS' => [ :Seen, :Draft, :Recent ],
1336
+ 'INTERNALDATE' => @mpart_mail.date.getutc.strftime(imap_date_fmt),
1337
+ 'RFC822.SIZE' => @mpart_mail.raw_source.bytesize,
1338
+ 'ENVELOPE' => envelope[@mpart_mail]
1339
+ }
1340
+ ],
1341
+ [ 3,
1342
+ { 'FLAGS' => [ :Recent ],
1343
+ 'INTERNALDATE' => @mime_subject_mail.date.getutc.strftime(imap_date_fmt),
1344
+ 'RFC822.SIZE' => @mime_subject_mail.raw_source.bytesize,
1345
+ 'ENVELOPE' => envelope[@mime_subject_mail]
1346
+ }
1347
+ ]
1348
+ ],
1349
+ imap_fetch.call(msg_set[1..-1], 'ALL'))
1350
+
1351
+ assert_equal(fetch_data[
1352
+ [ 1,
1353
+ { 'FLAGS' => [ :Answered, :Flagged ],
1354
+ 'INTERNALDATE' => @simple_mail.date.getutc.strftime(imap_date_fmt),
1355
+ 'RFC822.SIZE' => @simple_mail.raw_source.bytesize
1356
+ }
1357
+ ],
1358
+ [ 2,
1359
+ { 'FLAGS' => [ :Seen, :Draft, :Recent ],
1360
+ 'INTERNALDATE' => @mpart_mail.date.getutc.strftime(imap_date_fmt),
1361
+ 'RFC822.SIZE' => @mpart_mail.raw_source.bytesize
1362
+ }
1363
+ ],
1364
+ [ 3,
1365
+ { 'FLAGS' => [ :Recent ],
1366
+ 'INTERNALDATE' => @mime_subject_mail.date.getutc.strftime(imap_date_fmt),
1367
+ 'RFC822.SIZE' => @mime_subject_mail.raw_source.bytesize
1368
+ }
1369
+ ]
1370
+ ],
1371
+ imap_fetch.call(msg_set[1..-1], 'FAST'))
1372
+
1373
+ assert_equal(fetch_data[
1374
+ [ 1,
1375
+ { 'FLAGS' => [ :Answered, :Flagged ],
1376
+ 'INTERNALDATE' => @simple_mail.date.getutc.strftime(imap_date_fmt),
1377
+ 'RFC822.SIZE' => @simple_mail.raw_source.bytesize,
1378
+ 'ENVELOPE' => envelope[@simple_mail],
1379
+ 'BODY' => body_type[@simple_mail]
1380
+ }
1381
+ ],
1382
+ [ 2,
1383
+ { 'FLAGS' => [ :Seen, :Draft, :Recent ],
1384
+ 'INTERNALDATE' => @mpart_mail.date.getutc.strftime(imap_date_fmt),
1385
+ 'RFC822.SIZE' => @mpart_mail.raw_source.bytesize,
1386
+ 'ENVELOPE' => envelope[@mpart_mail],
1387
+ 'BODY' => body_type[@mpart_mail]
1388
+ }
1389
+ ],
1390
+ [ 3,
1391
+ { 'FLAGS' => [ :Recent ],
1392
+ 'INTERNALDATE' => @mime_subject_mail.date.getutc.strftime(imap_date_fmt),
1393
+ 'RFC822.SIZE' => @mime_subject_mail.raw_source.bytesize,
1394
+ 'ENVELOPE' => envelope[@mime_subject_mail],
1395
+ 'BODY' => body_type[@mime_subject_mail]
1396
+ }
1397
+ ]
1398
+ ],
1399
+ imap_fetch.call(msg_set[1..-1], 'FULL'))
1400
+
1401
+ assert_equal(fetch_data[
1402
+ [ 1, { 'BODY' => body_type[@simple_mail] } ],
1403
+ [ 2, { 'BODY' => body_type[@mpart_mail] } ],
1404
+ [ 3, { 'BODY' => body_type[@mime_subject_mail] } ]
1405
+ ],
1406
+ imap_fetch.call(msg_set[1..-1], 'BODY'))
1407
+
1408
+ 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] } ]
1412
+ ],
1413
+ imap_fetch.call(msg_set[1..-1], 'BODYSTRUCTURE'))
1414
+
1415
+ assert_equal(fetch_data[
1416
+ [ 1, { 'ENVELOPE' => envelope[@simple_mail] } ],
1417
+ [ 2, { 'ENVELOPE' => envelope[@mpart_mail] } ],
1418
+ [ 3, { 'ENVELOPE' => envelope[@mime_subject_mail] } ]
1419
+ ],
1420
+ imap_fetch.call(msg_set[1..-1], 'ENVELOPE'))
1421
+
1422
+ assert_equal(fetch_data[
1423
+ [ 1, { 'FLAGS' => [ :Answered, :Flagged ] } ],
1424
+ [ 2, { 'FLAGS' => [ :Seen, :Draft, :Recent ] } ],
1425
+ [ 3, { 'FLAGS' => [ :Recent ] } ]
1426
+ ],
1427
+ imap_fetch.call(msg_set[1..-1], 'FLAGS'))
1428
+
1429
+ assert_equal(fetch_data[
1430
+ [ 1, { 'INTERNALDATE' => @simple_mail.date.getutc.strftime(imap_date_fmt) } ],
1431
+ [ 2, { 'INTERNALDATE' => @mpart_mail.date.getutc.strftime(imap_date_fmt) } ],
1432
+ [ 3, { 'INTERNALDATE' => @mime_subject_mail.date.getutc.strftime(imap_date_fmt) } ]
1433
+ ],
1434
+ imap_fetch.call(msg_set[1..-1], 'INTERNALDATE'))
1435
+
1436
+ assert_equal(fetch_data[
1437
+ [ 1, { 'RFC822.HEADER' => @simple_mail.header.raw_source } ],
1438
+ [ 2, { 'RFC822.HEADER' => @mpart_mail.header.raw_source } ],
1439
+ [ 3, { 'RFC822.HEADER' => @mime_subject_mail.header.raw_source } ]
1440
+ ],
1441
+ imap_fetch.call(msg_set[1..-1], 'RFC822.HEADER'))
1442
+
1443
+ assert_equal(fetch_data[
1444
+ [ 1, { 'RFC822.SIZE' => @simple_mail.raw_source.bytesize } ],
1445
+ [ 2, { 'RFC822.SIZE' => @mpart_mail.raw_source.bytesize } ],
1446
+ [ 3, { 'RFC822.SIZE' => @mime_subject_mail.raw_source.bytesize } ]
1447
+ ],
1448
+ imap_fetch.call(msg_set[1..-1], 'RFC822.SIZE'))
1449
+
1450
+ assert_equal(fetch_data[
1451
+ [ 1, { 'UID' => uid_offset + 1 } ],
1452
+ [ 2, { 'UID' => uid_offset + 2 } ],
1453
+ [ 3, { 'UID' => uid_offset + 3 } ]
1454
+ ],
1455
+ imap_fetch.call(msg_set[1..-1], 'UID'))
1456
+
1457
+ assert_equal(fetch_data[
1458
+ [ 1, { 'BODY[]' => @simple_mail.raw_source } ],
1459
+ [ 2, { 'BODY[]' => @mpart_mail.raw_source } ],
1460
+ [ 3, { 'BODY[]' => @mime_subject_mail.raw_source } ]
1461
+ ],
1462
+ imap_fetch.call(msg_set[1..-1], 'BODY.PEEK[]'))
1463
+
1464
+ assert_equal(fetch_data[
1465
+ [ 1, { 'BODY[HEADER]' => @simple_mail.header.raw_source } ],
1466
+ [ 2, { 'BODY[HEADER]' => @mpart_mail.header.raw_source } ],
1467
+ [ 3, { 'BODY[HEADER]' => @mime_subject_mail.header.raw_source } ]
1468
+ ],
1469
+ imap_fetch.call(msg_set[1..-1], 'BODY.PEEK[HEADER]'))
1470
+
1471
+ assert_equal(fetch_data[
1472
+ [ 1,
1473
+ { 'BODY[HEADER.FIELDS (DATE SUBJECT)]' =>
1474
+ @simple_mail.header.find_all{|n, v|
1475
+ %w(DATE SUBJECT).include? n.upcase
1476
+ }.map{|n, v| "#{n}: #{v}\r\n" }.join('') + "\r\n"
1477
+ }
1478
+ ],
1479
+ [ 2,
1480
+ { 'BODY[HEADER.FIELDS (DATE SUBJECT)]' =>
1481
+ @mpart_mail.header.find_all{|n, v|
1482
+ %w(DATE SUBJECT).include? n.upcase
1483
+ }.map{|n, v| "#{n}: #{v}\r\n" }.join('') + "\r\n"
1484
+ }
1485
+ ],
1486
+ [ 3,
1487
+ { 'BODY[HEADER.FIELDS (DATE SUBJECT)]' =>
1488
+ @mime_subject_mail.header.find_all{|n, v|
1489
+ %w(DATE SUBJECT).include? n.upcase
1490
+ }.map{|n, v| "#{n}: #{v}\r\n" }.join('') + "\r\n"
1491
+ }
1492
+ ]
1493
+ ],
1494
+ imap_fetch.call(msg_set[1..-1], 'BODY.PEEK[HEADER.FIELDS (DATE SUBJECT)]'))
1495
+
1496
+ assert_equal(fetch_data[
1497
+ [ 1,
1498
+ { 'BODY[HEADER.FIELDS.NOT (TO FROM)]' =>
1499
+ @simple_mail.header.find_all{|n, v|
1500
+ ! (%w(TO FROM).include? n.upcase)
1501
+ }.map{|n, v| "#{n}: #{v}\r\n" }.join('') + "\r\n"
1502
+ }
1503
+ ],
1504
+ [ 2,
1505
+ { 'BODY[HEADER.FIELDS.NOT (TO FROM)]' =>
1506
+ @mpart_mail.header.find_all{|n, v|
1507
+ ! (%w(TO FROM).include? n.upcase)
1508
+ }.map{|n, v| "#{n}: #{v}\r\n" }.join('') + "\r\n"
1509
+ }
1510
+ ],
1511
+ [ 3,
1512
+ { 'BODY[HEADER.FIELDS.NOT (TO FROM)]' =>
1513
+ @mime_subject_mail.header.find_all{|n, v|
1514
+ ! (%w(TO FROM).include? n.upcase)
1515
+ }.map{|n, v| "#{n}: #{v}\r\n" }.join('') + "\r\n"
1516
+ }
1517
+ ]
1518
+ ],
1519
+ imap_fetch.call(msg_set[1..-1], 'BODY.PEEK[HEADER.FIELDS.NOT (TO FROM)]'))
1520
+
1521
+ assert_equal(fetch_data[
1522
+ [ 1, { 'BODY[TEXT]' => @simple_mail.body.raw_source } ],
1523
+ [ 2, { 'BODY[TEXT]' => @mpart_mail.body.raw_source } ],
1524
+ [ 3, { 'BODY[TEXT]' => @mime_subject_mail.body.raw_source } ]
1525
+ ],
1526
+ imap_fetch.call(msg_set[1..-1], 'BODY.PEEK[TEXT]'))
1527
+
1528
+ assert_equal(fetch_data[
1529
+ [ 1, { 'BODY[1.MIME]' => @simple_mail.header.raw_source } ],
1530
+ [ 2, { 'BODY[1.MIME]' => @mpart_mail.parts[0].header.raw_source } ],
1531
+ [ 3, { 'BODY[1.MIME]' => @mime_subject_mail.header.raw_source } ]
1532
+ ],
1533
+ imap_fetch.call(msg_set[1..-1], 'BODY.PEEK[1.MIME]'))
1534
+
1535
+ assert_fetch_body_sections = lambda{|body_section_table|
1536
+ res = imap_fetch.call(msg_set[2], body_section_table.keys)
1537
+ assert_equal(1, res.length)
1538
+ assert_equal(2, res[0].seqno)
1539
+ if (uid) then
1540
+ assert_equal(body_section_table.size + 1, res[0].attr.size)
1541
+ assert_equal(uid_offset + 2, res[0].attr['UID'])
1542
+ else
1543
+ assert_equal(body_section_table.size, res[0].attr.size)
1544
+ end
1545
+ for body_section, expected_fetch_data in body_section_table
1546
+ body_section = body_section.dup
1547
+ body_section.upcase!
1548
+ body_section.sub!(/\.PEEK/, '')
1549
+ assert_equal(expected_fetch_data, res[0].attr[body_section], body_section)
1550
+ end
1551
+ }
1552
+
1553
+ assert_fetch_body_sections.call({ 'BODY.PEEK[1]' => @mpart_mail.parts[0].body.raw_source,
1554
+ 'BODY.PEEK[2]' => @mpart_mail.parts[1].body.raw_source,
1555
+ 'BODY.PEEK[3]' => @mpart_mail.parts[2].body.raw_source,
1556
+ 'BODY.PEEK[3.1]' => @mpart_mail.parts[2].message.parts[0].body.raw_source,
1557
+ 'BODY.PEEK[3.2]' => @mpart_mail.parts[2].message.parts[1].body.raw_source,
1558
+ 'BODY.PEEK[4]' => @mpart_mail.parts[3].body.raw_source,
1559
+ 'BODY.PEEK[4.1]' => @mpart_mail.parts[3].parts[0].body.raw_source,
1560
+ 'BODY.PEEK[4.2]' => @mpart_mail.parts[3].parts[1].body.raw_source,
1561
+ 'BODY.PEEK[4.2.1]' => @mpart_mail.parts[3].parts[1].message.parts[0].body.raw_source,
1562
+ 'BODY.PEEK[4.2.2]' => @mpart_mail.parts[3].parts[1].message.parts[1].body.raw_source,
1563
+ 'BODY.PEEK[4.2.2.1]' => @mpart_mail.parts[3].parts[1].message.parts[1].parts[0].body.raw_source,
1564
+ 'BODY.PEEK[4.2.2.2]' => @mpart_mail.parts[3].parts[1].message.parts[1].parts[1].body.raw_source
1565
+ })
1566
+
1567
+ assert_fetch_body_sections.call({ 'BODY.PEEK[1.MIME]' => @mpart_mail.parts[0].header.raw_source,
1568
+ 'BODY.PEEK[2.MIME]' => @mpart_mail.parts[1].header.raw_source,
1569
+ 'BODY.PEEK[3.MIME]' => @mpart_mail.parts[2].header.raw_source,
1570
+ 'BODY.PEEK[3.1.MIME]' => @mpart_mail.parts[2].message.parts[0].header.raw_source,
1571
+ 'BODY.PEEK[3.2.MIME]' => @mpart_mail.parts[2].message.parts[1].header.raw_source,
1572
+ 'BODY.PEEK[4.MIME]' => @mpart_mail.parts[3].header.raw_source,
1573
+ 'BODY.PEEK[4.1.MIME]' => @mpart_mail.parts[3].parts[0].header.raw_source,
1574
+ 'BODY.PEEK[4.2.MIME]' => @mpart_mail.parts[3].parts[1].header.raw_source,
1575
+ 'BODY.PEEK[4.2.1.MIME]' => @mpart_mail.parts[3].parts[1].message.parts[0].header.raw_source,
1576
+ 'BODY.PEEK[4.2.2.MIME]' => @mpart_mail.parts[3].parts[1].message.parts[1].header.raw_source,
1577
+ 'BODY.PEEK[4.2.2.1.MIME]' => @mpart_mail.parts[3].parts[1].message.parts[1].parts[0].header.raw_source,
1578
+ 'BODY.PEEK[4.2.2.2.MIME]' => @mpart_mail.parts[3].parts[1].message.parts[1].parts[1].header.raw_source
1579
+ })
1580
+
1581
+ assert_fetch_body_sections.call({ 'BODY.PEEK[3.HEADER]' => @mpart_mail.parts[2].message.header.raw_source,
1582
+ 'BODY.PEEK[4.2.HEADER]' => @mpart_mail.parts[3].parts[1].message.header.raw_source
1583
+ })
1584
+
1585
+ assert_fetch_body_sections.call({ 'BODY.PEEK[3.TEXT]' => @mpart_mail.parts[2].message.body.raw_source,
1586
+ 'BODY.PEEK[4.2.TEXT]' => @mpart_mail.parts[3].parts[1].message.body.raw_source
1587
+ })
1588
+ }
1589
+ assert_imap_fetch_read_only_seqno = lambda{ assert_imap_fetch_read_only.call(false) }
1590
+ assert_imap_fetch_read_only_uid = lambda{ assert_imap_fetch_read_only.call(true) }
1591
+
1592
+ assert_imap_store = lambda{|uid|
1593
+ if (uid) then
1594
+ imap_store = imap.method(:uid_store)
1595
+ imap_fetch = imap.method(:uid_fetch)
1596
+ seqno = uid_offset + 3
1597
+ else
1598
+ imap_store = imap.method(:store)
1599
+ imap_fetch = imap.method(:fetch)
1600
+ seqno = 3
1601
+ end
1602
+
1603
+ assert_equal([ :Answered, :Flagged, :Deleted, :Seen, :Draft, :Recent ],
1604
+ imap_store.call(seqno, 'FLAGS', [ :Answered, :Flagged, :Deleted, :Seen, :Draft ])[0].attr['FLAGS'])
1605
+ assert_equal([ :Answered, :Flagged, :Deleted, :Seen, :Draft, :Recent ],
1606
+ imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'])
1607
+
1608
+ assert_nil(imap_store.call(seqno, 'FLAGS.SILENT', []))
1609
+ assert_equal([ :Recent ],
1610
+ imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'])
1611
+
1612
+ assert_equal([ :Answered, :Deleted, :Draft, :Recent ],
1613
+ imap_store.call(seqno, '+FLAGS', [ :Answered, :Deleted, :Draft ])[0].attr['FLAGS'])
1614
+ assert_equal([ :Answered, :Deleted, :Draft, :Recent ],
1615
+ imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'])
1616
+
1617
+ assert_equal([ :Recent ], imap_store.call(seqno, '-FLAGS', [ :Answered, :Deleted, :Draft ])[0].attr['FLAGS'])
1618
+ assert_equal([ :Recent ], imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'])
1619
+
1620
+ assert_nil(imap_store.call(seqno, '+FLAGS.SILENT', [ :Flagged, :Seen ]))
1621
+ assert_equal([ :Flagged, :Seen, :Recent ], imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'])
1622
+
1623
+ assert_nil(imap_store.call(seqno, '-FLAGS.SILENT', [ :Flagged, :Seen ]))
1624
+ assert_equal([ :Recent ], imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'])
1625
+ }
1626
+ assert_imap_store_seqno = lambda{ assert_imap_store.call(false) }
1627
+ assert_imap_store_uid = lambda{ assert_imap_store.call(true) }
1628
+
1629
+ assert_imap_store_read_only = lambda{|uid|
1630
+ if (uid) then
1631
+ imap_store = imap.method(:uid_store)
1632
+ seqno = uid_offset + 3
1633
+ else
1634
+ imap_store = imap.method(:store)
1635
+ seqno = 3
1636
+ end
1637
+
1638
+ assert_imap_no_response[/cannot store in read-only mode/] {
1639
+ imap_store.call(seqno, 'FLAGS', [ :Answered, :Flagged, :Deleted, :Seen, :Draft ])
1640
+ }
1641
+ assert_imap_no_response[/cannot store in read-only mode/] {
1642
+ imap_store.call(seqno, 'FLAGS.SILENT', [])
1643
+ }
1644
+ assert_imap_no_response[/cannot store in read-only mode/] {
1645
+ imap_store.call(seqno, '+FLAGS', [ :Answered, :Deleted, :Draft ])
1646
+ }
1647
+ assert_imap_no_response[/cannot store in read-only mode/] {
1648
+ imap_store.call(seqno, '-FLAGS', [ :Answered, :Deleted, :Draft ])
1649
+ }
1650
+ assert_imap_no_response[/cannot store in read-only mode/] {
1651
+ imap_store.call(seqno, '+FLAGS.SILENT', [ :Flagged, :Seen ])
1652
+ }
1653
+ assert_imap_no_response[/cannot store in read-only mode/] {
1654
+ imap_store.call(seqno, '-FLAGS.SILENT', [ :Flagged, :Seen ])
1655
+ }
1656
+ }
1657
+ assert_imap_store_read_only_seqno = lambda{ assert_imap_store_read_only.call(false) }
1658
+ assert_imap_store_read_only_uid = lambda{ assert_imap_store_read_only.call(true) }
1659
+
1660
+ assert_imap_fetch_seen = lambda{|uid, read_only|
1661
+ if (uid) then
1662
+ imap_fetch = imap.method(:uid_fetch)
1663
+ imap_store = imap.method(:uid_store)
1664
+ seqno = uid_offset + 3
1665
+ fetch_data = lambda{|attr| attr.merge({ 'UID' => seqno }) }
1666
+ else
1667
+ imap_fetch = imap.method(:fetch)
1668
+ imap_store = imap.method(:store)
1669
+ seqno = 3
1670
+ fetch_data = lambda{|attr| attr }
1671
+ end
1672
+
1673
+ if (read_only) then
1674
+ assert_fetch = lambda{|attribute, expected_fetch_data|
1675
+ assert_equal(fetch_data[
1676
+ { attribute => expected_fetch_data }
1677
+ ],
1678
+ imap_fetch.call(seqno, attribute)[0].attr,
1679
+ attribute)
1680
+ assert_not_include(imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'], :Seen, attribute)
1681
+ }
1682
+ else
1683
+ assert_fetch = lambda{|attribute, expected_fetch_data|
1684
+ assert_equal(fetch_data[
1685
+ { attribute => expected_fetch_data,
1686
+ 'FLAGS' => [ :Seen, :Recent ]
1687
+ }
1688
+ ],
1689
+ imap_fetch.call(seqno, attribute)[0].attr,
1690
+ attribute)
1691
+ assert_include(imap_fetch.call(seqno, 'FLAGS')[0].attr['FLAGS'], :Seen, attribute)
1692
+ imap_store.call(seqno, '-FLAGS.SILENT', [ :Seen ])
1693
+ }
1694
+ end
1695
+
1696
+ assert_fetch.call('BODY[]', @mime_subject_mail.raw_source)
1697
+ assert_fetch.call('RFC822', @mime_subject_mail.raw_source)
1698
+ assert_fetch.call('RFC822.TEXT', @mime_subject_mail.body.raw_source)
1699
+ }
1700
+ assert_imap_fetch_seen_seqno = lambda{ assert_imap_fetch_seen.call(false, false) }
1701
+ assert_imap_fetch_seen_uid = lambda{ assert_imap_fetch_seen.call(true, false) }
1702
+ assert_imap_fetch_seen_read_only_seqno = lambda{ assert_imap_fetch_seen.call(false, true) }
1703
+ assert_imap_fetch_seen_read_only_uid = lambda{ assert_imap_fetch_seen.call(true, true) }
1704
+
1705
+ # State: Authenticated -> Selected (read-only)
1706
+ imap.examine('INBOX')
1707
+
1708
+ # IMAP commands for Any State
1709
+ assert_equal(%w[ IMAP4REV1 UIDPLUS IDLE AUTH=PLAIN AUTH=CRAM-MD5 ], imap.capability)
1710
+ imap.noop
1711
+
1712
+ # IMAP commands for Selected State
1713
+ imap.check
1714
+ assert_imap_search_seqno.call
1715
+ assert_imap_search_uid.call
1716
+ assert_imap_fetch_read_only_seqno.call
1717
+ assert_imap_fetch_read_only_uid.call
1718
+ assert_imap_store_read_only_seqno.call
1719
+ assert_imap_store_read_only_uid.call
1720
+ assert_imap_fetch_seen_read_only_seqno.call
1721
+ assert_imap_fetch_seen_read_only_uid.call
1722
+
1723
+ # State: Authenticated <- Selected
1724
+ imap.close
1725
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1726
+
1727
+ # State: Authenticated -> Selected
1728
+ imap.select('INBOX')
1729
+
1730
+ # IMAP commands for Any State
1731
+ assert_equal(%w[ IMAP4REV1 UIDPLUS IDLE AUTH=PLAIN AUTH=CRAM-MD5 ], imap.capability)
1732
+ imap.noop
1733
+
1734
+ # IMAP commands for Selected State
1735
+ imap.check
1736
+ assert_imap_search_seqno.call
1737
+ assert_imap_search_uid.call
1738
+ assert_imap_fetch_read_only_seqno.call
1739
+ assert_imap_fetch_read_only_uid.call
1740
+ assert_imap_store_seqno.call
1741
+ assert_imap_store_uid.call
1742
+ assert_imap_fetch_seen_seqno.call
1743
+ assert_imap_fetch_seen_uid.call
1744
+
1745
+ # State: Authenticated <- Selected
1746
+ imap.close
1747
+ status['RECENT'] = 0
1748
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1749
+
1750
+ # IMAP commands for Selected State
1751
+ assert_no_response_selected_state_imap_commands.call(/not selected/)
1752
+
1753
+ imap_copy_count = 0
1754
+ imap.create('COPY')
1755
+ assert_imap_copy = lambda{|uid, read_only|
1756
+ imap_copy_count += 1
1757
+
1758
+ if (uid) then
1759
+ imap_copy = imap.method(:uid_copy)
1760
+ seqno = uid_offset + 1
1761
+ else
1762
+ imap_copy = imap.method(:copy)
1763
+ seqno = 1
1764
+ end
1765
+
1766
+ if (read_only) then
1767
+ imap_select = imap.method(:examine)
1768
+ else
1769
+ imap_select = imap.method(:select)
1770
+ end
1771
+
1772
+ imap_select.call('INBOX')
1773
+ imap_copy.call(seqno, 'COPY')
1774
+ imap.close
1775
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1776
+
1777
+ imap.examine('COPY')
1778
+ res = imap.fetch('*', %w(BODY[] INTERNALDATE FLAGS))
1779
+ assert_equal(1, res.length)
1780
+ assert_equal(imap_copy_count, res[0].seqno)
1781
+ assert_equal(3, res[0].attr.size)
1782
+ assert_equal(@simple_mail.raw_source, res[0].attr['BODY[]'])
1783
+ assert_equal(@simple_mail.date.getutc.strftime(imap_date_fmt), res[0].attr['INTERNALDATE'])
1784
+ assert_equal([ :Answered, :Flagged ], res[0].attr['FLAGS'])
1785
+ imap.close
1786
+ }
1787
+ assert_imap_copy_seqno = lambda{ assert_imap_copy.call(false, false) }
1788
+ assert_imap_copy_uid = lambda{ assert_imap_copy.call(true, false) }
1789
+ assert_imap_copy_read_only_seqno = lambda{ assert_imap_copy.call(false, true) }
1790
+ assert_imap_copy_read_only_uid = lambda{ assert_imap_copy.call(true, true) }
1791
+
1792
+ # IMAP copy command
1793
+ assert_imap_copy_read_only_seqno.call
1794
+ assert_imap_copy_read_only_uid.call
1795
+ assert_imap_copy_seqno.call
1796
+ assert_imap_copy_uid.call
1797
+
1798
+ # IMAP idle command
1799
+ assert_imap_idle = lambda{|read_only|
1800
+ if (read_only) then
1801
+ imap.examine('INBOX')
1802
+ else
1803
+ imap.select('INBOX')
1804
+ end
1805
+ imap_connect(use_ssl) {|another_imap|
1806
+ start_imap_idle_thread = lambda{
1807
+ mutex = Mutex.new
1808
+ spin_lock = true
1809
+
1810
+ th = Thread.new{
1811
+ response_list = []
1812
+ imap.idle{|res|
1813
+ mutex.synchronize{ spin_lock = false } # unlock by continuation request
1814
+ response_list << res
1815
+ }
1816
+ response_list
1817
+ }
1818
+
1819
+ timeout(10) {
1820
+ while (mutex.synchronize{ spin_lock })
1821
+ sleep(0.1)
1822
+ end
1823
+ }
1824
+
1825
+ th
1826
+ }
1827
+
1828
+ imap_idle_done = lambda{
1829
+ # ad hoc way to avoid the race condition between `Net::IMAP#add_response_handler' and `Net::IMAP#idle_done'
1830
+ sleep(0.1)
1831
+
1832
+ imap.idle_done
1833
+ }
1834
+
1835
+ another_imap.login('foo', 'foo')
1836
+ another_imap.select('INBOX')
1837
+
1838
+ th = start_imap_idle_thread.call
1839
+ another_imap.append('INBOX', 'test', [ :Deleted ])
1840
+ imap_idle_done.call
1841
+
1842
+ response_list = th.value
1843
+ assert_equal(3, response_list.length)
1844
+ assert_instance_of(Net::IMAP::ContinuationRequest, response_list[0])
1845
+ assert_equal([ 'EXISTS', status['MESSAGES'] + 1 ], response_list[1].to_h.values_at(:name, :data))
1846
+ assert_equal([ 'RECENT', status['RECENT'] + 1 ], response_list[2].to_h.values_at(:name, :data))
1847
+
1848
+ th = start_imap_idle_thread.call
1849
+ another_imap.copy('*', 'INBOX')
1850
+ imap_idle_done.call
1851
+
1852
+ response_list = th.value
1853
+ assert_equal(3, response_list.length)
1854
+ assert_instance_of(Net::IMAP::ContinuationRequest, response_list[0])
1855
+ assert_equal([ 'EXISTS', status['MESSAGES'] + 2 ], response_list[1].to_h.values_at(:name, :data))
1856
+ assert_equal([ 'RECENT', status['RECENT'] + 2 ], response_list[2].to_h.values_at(:name, :data))
1857
+
1858
+ th = start_imap_idle_thread.call
1859
+ another_imap.store('*', '+FLAGS.SILENT', [ :Deleted ])
1860
+ another_imap.expunge
1861
+ imap_idle_done.call
1862
+
1863
+ response_list = th.value
1864
+ assert_equal(3, response_list.length)
1865
+ assert_instance_of(Net::IMAP::ContinuationRequest, response_list[0])
1866
+ assert_equal([ 'EXPUNGE', status['MESSAGES'] + 2 ], response_list[1].to_h.values_at(:name, :data))
1867
+ assert_equal([ 'EXPUNGE', status['MESSAGES'] + 1 ], response_list[2].to_h.values_at(:name, :data))
1868
+
1869
+ another_imap.close
1870
+ another_imap.logout
1871
+ }
1872
+ imap.close
1873
+ }
1874
+ assert_imap_idle.call(true)
1875
+ assert_imap_idle.call(false)
1876
+ status['UIDNEXT'] += 2 * 2
1877
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1878
+
1879
+ # mail delivery user
1880
+ assert_not_include(imap.capability, 'X-RIMS-MAIL-DELIVERY-USER')
1881
+ imap_connect(use_ssl) {|post_mail|
1882
+ assert_not_include(post_mail.capability, 'X-RIMS-MAIL-DELIVERY-USER')
1883
+
1884
+ post_mail.login('#postman', '#postman')
1885
+ assert_include(post_mail.capability, 'X-RIMS-MAIL-DELIVERY-USER')
1886
+
1887
+ post_mail.append(RIMS::Protocol::Decoder.encode_delivery_target_mailbox('foo', 'INBOX'),
1888
+ 'mail delivery test')
1889
+ status['MESSAGES'] += 1
1890
+ status['RECENT'] += 1
1891
+ status['UNSEEN'] += 1
1892
+ status['UIDNEXT'] += 1
1893
+ assert_equal(status, imap.status('INBOX', %w[ MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN ]))
1894
+
1895
+ post_mail.logout
1896
+ }
1897
+
1898
+ imap.examine('INBOX')
1899
+ assert_equal('mail delivery test', imap.fetch('*', 'RFC822')[0].attr['RFC822'])
1900
+ imap.close
1901
+ }
1902
+ end
1903
+
1904
+ data('default' => {},
1905
+ 'use_ssl' => { use_ssl: true },
1906
+ 'multi-process' => { process_num: 4 },
1907
+ 'use_ssl,multi-process' => {
1908
+ use_ssl: true,
1909
+ process_num: 4
1910
+ })
1911
+ def test_system_autologout(data)
1912
+ use_ssl = (data.key? :use_ssl) ? data[:use_ssl] : false
1913
+ process_num = data[:process_num] || 0
1914
+
1915
+ command_wait_timeout_seconds = 0.1
1916
+ config = {
1917
+ server: {
1918
+ process_num: process_num
1919
+ },
1920
+ drb_services: {
1921
+ process_num: process_num
1922
+ },
1923
+ connection: {
1924
+ read_polling_interval_seconds: command_wait_timeout_seconds / 100,
1925
+ command_wait_timeout_seconds: command_wait_timeout_seconds
1926
+ }
1927
+ }
1928
+
1929
+ run_server(use_ssl: use_ssl, optional: config) {
1930
+ # Not Authenticated State
1931
+ imap_connect(use_ssl) {|imap|
1932
+ assert_not_include(imap.responses, 'BYE')
1933
+ sleep(command_wait_timeout_seconds * 1.5)
1934
+ assert_include(imap.responses, 'BYE')
1935
+ assert_match(/autologout/, imap.responses['BYE'].last.text)
1936
+ assert(imap.disconnected?)
1937
+ }
1938
+
1939
+ # Authenticated State
1940
+ imap_connect(use_ssl) {|imap|
1941
+ imap.login('foo', 'foo')
1942
+ assert_not_include(imap.responses, 'BYE')
1943
+ sleep(command_wait_timeout_seconds * 1.5)
1944
+ assert_include(imap.responses, 'BYE')
1945
+ assert_match(/autologout/, imap.responses['BYE'].last.text)
1946
+ assert(imap.disconnected?)
1947
+ }
1948
+
1949
+ # Selected State (read-only)
1950
+ imap_connect(use_ssl) {|imap|
1951
+ imap.login('foo', 'foo')
1952
+ imap.examine('INBOX')
1953
+ assert_not_include(imap.responses, 'BYE')
1954
+ sleep(command_wait_timeout_seconds * 1.5)
1955
+ assert_include(imap.responses, 'BYE')
1956
+ assert_match(/autologout/, imap.responses['BYE'].last.text)
1957
+ assert(imap.disconnected?)
1958
+ }
1959
+
1960
+ # Selected State
1961
+ imap_connect(use_ssl) {|imap|
1962
+ imap.login('foo', 'foo')
1963
+ imap.select('INBOX')
1964
+ assert_not_include(imap.responses, 'BYE')
1965
+ sleep(command_wait_timeout_seconds * 1.5)
1966
+ assert_include(imap.responses, 'BYE')
1967
+ assert_match(/autologout/, imap.responses['BYE'].last.text)
1968
+ assert(imap.disconnected?)
1969
+ }
1970
+
1971
+ # IMAP IDLE command
1972
+ imap_connect(use_ssl) {|imap|
1973
+ imap.login('foo', 'foo')
1974
+ imap.select('INBOX')
1975
+ assert_not_include(imap.responses, 'BYE')
1976
+ timeout(command_wait_timeout_seconds * 10) {
1977
+ error = assert_raise(Net::IMAP::ByeResponseError) {
1978
+ imap.idle{
1979
+ # nothing to do
1980
+ }
1981
+ }
1982
+ assert_match(/autologout/, error.message)
1983
+ }
1984
+ assert_include(imap.responses, 'BYE')
1985
+ assert_match(/autologout/, imap.responses['BYE'].last.text)
1986
+ assert(imap.disconnected?)
1987
+ }
1988
+ }
1989
+ end
995
1990
  end
996
1991
  end
997
1992