rims 0.2.4 → 0.2.5

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.
@@ -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