rims 0.2.9 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/lib/rims.rb +31 -29
- data/lib/rims/cmd.rb +38 -1
- data/lib/rims/protocol.rb +28 -7
- data/lib/rims/protocol/decoder.rb +132 -78
- data/lib/rims/protocol/parser.rb +82 -32
- data/lib/rims/service.rb +31 -1
- data/lib/rims/test.rb +1 -2
- data/lib/rims/version.rb +1 -1
- data/rims.gemspec +1 -1
- data/test/cmd/test_command.rb +6 -0
- data/test/test_error.rb +1 -1
- data/test/test_passwd.rb +1 -1
- data/test/test_protocol_decoder.rb +273 -8
- data/test/test_protocol_request.rb +305 -280
- data/test/test_service.rb +39 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 302a70ed845d6af656e11c2a6fde78cfda71a33b1d5673654594634b7fe92f63
|
4
|
+
data.tar.gz: 468e136c3796d1ea15d9e554be3f6dd38b5d34fe3089c7db71a0d7a87d73e9cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96c2d58c1990e724743581436c0e373bcb147e4afd799f8c9860146cf2c4fa33b5652a2937a4185590a5b7a79c2309bf899d16268eeed92765b08572c74d3884
|
7
|
+
data.tar.gz: 816e5242fbf6c361d81306f516c27eab7046d73829ae7a08065a44788ef28afba71923b0eb6b200d7a0b6f2791fda24e8f7c4a6d481ff9502333fa4fc2179c03
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,29 @@
|
|
1
1
|
Change Log
|
2
2
|
==========
|
3
3
|
|
4
|
+
<!--
|
5
|
+
subsections:
|
6
|
+
### Added
|
7
|
+
### Changed
|
8
|
+
### Removed
|
9
|
+
### Fixed
|
10
|
+
-->
|
11
|
+
|
12
|
+
0.3.0
|
13
|
+
-----
|
14
|
+
|
15
|
+
### Added
|
16
|
+
- Input size limits.
|
17
|
+
[#34](https://github.com/y10k/rims/issues/34)
|
18
|
+
- Configurable bulk_response_size parameter.
|
19
|
+
[#36](https://github.com/y10k/rims/issues/36)
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
- Ready to Ruby 2.7.
|
23
|
+
[#35](https://github.com/y10k/rims/issues/35)
|
24
|
+
- Semantic versioning.
|
25
|
+
[#37](https://github.com/y10k/rims/issues/37)
|
26
|
+
|
4
27
|
0.2.9
|
5
28
|
-----
|
6
29
|
Released on 2019-12-12.
|
data/lib/rims.rb
CHANGED
@@ -5,35 +5,37 @@ require "rims/version"
|
|
5
5
|
autoload :OpenSSL, 'openssl'
|
6
6
|
|
7
7
|
module RIMS
|
8
|
-
autoload :Authentication,
|
9
|
-
autoload :Checksum_KeyValueStore,
|
10
|
-
autoload :Cmd,
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
autoload :Hash_KeyValueStore,
|
16
|
-
autoload :IllegalLockError,
|
17
|
-
autoload :KeyValueStore,
|
18
|
-
autoload :
|
19
|
-
autoload :
|
20
|
-
autoload :
|
21
|
-
autoload :
|
22
|
-
autoload :
|
23
|
-
autoload :MessageSetSyntaxError,
|
24
|
-
autoload :Password,
|
25
|
-
autoload :Protocol,
|
26
|
-
autoload :ProtocolError,
|
27
|
-
autoload :RFC822,
|
28
|
-
autoload :ReadLockError,
|
29
|
-
autoload :ReadLockTimeoutError,
|
30
|
-
autoload :
|
31
|
-
autoload :
|
32
|
-
autoload :
|
33
|
-
autoload :
|
34
|
-
autoload :
|
35
|
-
autoload :
|
36
|
-
autoload :
|
8
|
+
autoload :Authentication, 'rims/auth'
|
9
|
+
autoload :Checksum_KeyValueStore, 'rims/cksum_kvs'
|
10
|
+
autoload :Cmd, 'rims/cmd'
|
11
|
+
autoload :CommandSizeTooLargeError, 'rims/protocol'
|
12
|
+
autoload :DB, 'rims/db'
|
13
|
+
autoload :Error, 'rims/error'
|
14
|
+
autoload :GDBM_KeyValueStore, 'rims/gdbm_kvs'
|
15
|
+
autoload :Hash_KeyValueStore, 'rims/hash_kvs'
|
16
|
+
autoload :IllegalLockError, 'rims/lock'
|
17
|
+
autoload :KeyValueStore, 'rims/kvs'
|
18
|
+
autoload :LineTooLongError, 'rims/protocol'
|
19
|
+
autoload :LiteralSizeTooLargeError, 'rims/protocol'
|
20
|
+
autoload :LockError, 'rims/lock'
|
21
|
+
autoload :MailFolder, 'rims/mail_store'
|
22
|
+
autoload :MailStore, 'rims/mail_store'
|
23
|
+
autoload :MessageSetSyntaxError, 'rims/protocol'
|
24
|
+
autoload :Password, 'rims/passwd'
|
25
|
+
autoload :Protocol, 'rims/protocol'
|
26
|
+
autoload :ProtocolError, 'rims/protocol'
|
27
|
+
autoload :RFC822, 'rims/rfc822'
|
28
|
+
autoload :ReadLockError, 'rims/lock'
|
29
|
+
autoload :ReadLockTimeoutError, 'rims/lock'
|
30
|
+
autoload :ReadSizeError, 'rims/protocol'
|
31
|
+
autoload :ReadWriteLock, 'rims/lock'
|
32
|
+
autoload :RecoverableReadSizeError, 'rims/protocol'
|
33
|
+
autoload :ServerResponseChannel, 'rims/channel'
|
34
|
+
autoload :Service, 'rims/service'
|
35
|
+
autoload :SyntaxError, 'rims/protocol'
|
36
|
+
autoload :Test, 'rims/test'
|
37
|
+
autoload :WriteLockError, 'rims/lock'
|
38
|
+
autoload :WriteLockTimeoutError, 'rims/lock'
|
37
39
|
end
|
38
40
|
|
39
41
|
# Local Variables:
|
data/lib/rims/cmd.rb
CHANGED
@@ -472,6 +472,33 @@ module RIMS
|
|
472
472
|
})
|
473
473
|
}
|
474
474
|
end
|
475
|
+
options.on('--line-length-limit=SIZE',
|
476
|
+
Integer
|
477
|
+
) do |size|
|
478
|
+
build.chain{|c|
|
479
|
+
c.load(protocol: {
|
480
|
+
line_length_limit: size
|
481
|
+
})
|
482
|
+
}
|
483
|
+
end
|
484
|
+
options.on('--literal-size-limit=SIZE',
|
485
|
+
Integer
|
486
|
+
) do |size|
|
487
|
+
build.chain{|c|
|
488
|
+
c.load(protocol: {
|
489
|
+
literal_size_limit: size
|
490
|
+
})
|
491
|
+
}
|
492
|
+
end
|
493
|
+
options.on('--command-size-limit=SIZE',
|
494
|
+
Integer
|
495
|
+
) do |size|
|
496
|
+
build.chain{|c|
|
497
|
+
c.load(protocol: {
|
498
|
+
command_size_limit: size
|
499
|
+
})
|
500
|
+
}
|
501
|
+
end
|
475
502
|
options.on('--[no-]use-default-charset-aliases'
|
476
503
|
) do |use_default_aliases|
|
477
504
|
build.chain{|c|
|
@@ -533,7 +560,7 @@ module RIMS
|
|
533
560
|
})
|
534
561
|
}
|
535
562
|
end
|
536
|
-
options.on('--drb-load-limit=
|
563
|
+
options.on('--drb-load-limit=SIZE',
|
537
564
|
Integer
|
538
565
|
) do |size|
|
539
566
|
build.chain{|c|
|
@@ -552,6 +579,16 @@ module RIMS
|
|
552
579
|
})
|
553
580
|
}
|
554
581
|
end
|
582
|
+
options.on('--bulk-response-size=SIZE',
|
583
|
+
Integer) do |size|
|
584
|
+
build.chain{|c|
|
585
|
+
c.load(drb_services: {
|
586
|
+
engine: {
|
587
|
+
bulk_response_size: size
|
588
|
+
}
|
589
|
+
})
|
590
|
+
}
|
591
|
+
end
|
555
592
|
options.on('--read-lock-timeout=SECONDS',
|
556
593
|
Float
|
557
594
|
) do |seconds|
|
data/lib/rims/protocol.rb
CHANGED
@@ -4,6 +4,27 @@ module RIMS
|
|
4
4
|
class ProtocolError < Error
|
5
5
|
end
|
6
6
|
|
7
|
+
class ReadSizeError < ProtocolError
|
8
|
+
end
|
9
|
+
|
10
|
+
class LineTooLongError < ReadSizeError
|
11
|
+
end
|
12
|
+
|
13
|
+
class RecoverableReadSizeError < ReadSizeError
|
14
|
+
def initialize(message=nil, command_tag=nil, **kw_args)
|
15
|
+
super(message, **kw_args)
|
16
|
+
@command_tag = command_tag
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :command_tag
|
20
|
+
end
|
21
|
+
|
22
|
+
class LiteralSizeTooLargeError < RecoverableReadSizeError
|
23
|
+
end
|
24
|
+
|
25
|
+
class CommandSizeTooLargeError < RecoverableReadSizeError
|
26
|
+
end
|
27
|
+
|
7
28
|
class SyntaxError < ProtocolError
|
8
29
|
end
|
9
30
|
|
@@ -57,14 +78,14 @@ module RIMS
|
|
57
78
|
end
|
58
79
|
module_function :decode_base64
|
59
80
|
|
60
|
-
autoload :FetchBody,
|
61
|
-
autoload :RequestReader,
|
81
|
+
autoload :FetchBody, 'rims/protocol/parser'
|
82
|
+
autoload :RequestReader, 'rims/protocol/parser'
|
62
83
|
autoload :AuthenticationReader, 'rims/protocol/parser'
|
63
|
-
autoload :SearchParser,
|
64
|
-
autoload :FetchParser,
|
65
|
-
autoload :ConnectionLimits,
|
66
|
-
autoload :ConnectionTimer,
|
67
|
-
autoload :Decoder,
|
84
|
+
autoload :SearchParser, 'rims/protocol/parser'
|
85
|
+
autoload :FetchParser, 'rims/protocol/parser'
|
86
|
+
autoload :ConnectionLimits, 'rims/protocol/connection'
|
87
|
+
autoload :ConnectionTimer, 'rims/protocol/connection'
|
88
|
+
autoload :Decoder, 'rims/protocol/decoder'
|
68
89
|
|
69
90
|
def body(symbol: nil, option: nil, section: nil, section_list: nil, partial_origin: nil, partial_size: nil)
|
70
91
|
FetchBody.new(symbol, option, section, section_list, partial_origin, partial_size)
|
@@ -37,7 +37,6 @@ module RIMS
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def self.repl(decoder, limits, input, output, logger)
|
40
|
-
input_gets = input.method(:gets)
|
41
40
|
output_write = lambda{|data|
|
42
41
|
begin
|
43
42
|
if (data == :flush) then
|
@@ -85,90 +84,112 @@ module RIMS
|
|
85
84
|
apply_imap_command.call(:ok_greeting)
|
86
85
|
|
87
86
|
conn_timer = ConnectionTimer.new(limits, input.to_io)
|
88
|
-
request_reader =
|
87
|
+
request_reader = decoder.make_requrest_reader(input, output)
|
88
|
+
input_gets = request_reader.method(:gets)
|
89
89
|
|
90
|
-
|
91
|
-
conn_timer.
|
90
|
+
begin
|
91
|
+
until (conn_timer.command_wait_timeout?)
|
92
|
+
conn_timer.command_wait or break
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
94
|
+
begin
|
95
|
+
atom_list = request_reader.read_command
|
96
|
+
rescue LineTooLongError
|
97
|
+
raise
|
98
|
+
rescue LiteralSizeTooLargeError
|
99
|
+
logger.error('literal size too large error.')
|
100
|
+
logging_error_chain($!, logger)
|
101
|
+
response_write.call("#{request_reader.command_tag || '*'} BAD literal size too large\r\n")
|
102
|
+
next
|
103
|
+
rescue CommandSizeTooLargeError
|
104
|
+
logger.error('command size too large error.')
|
105
|
+
logging_error_chain($!, logger)
|
106
|
+
response_write.call("#{request_reader.command_tag || '*'} BAD command size too large\r\n")
|
107
|
+
next
|
108
|
+
rescue
|
109
|
+
logger.error('invalid client command.')
|
110
|
+
logging_error_chain($!, logger)
|
111
|
+
response_write.call("#{request_reader.command_tag || '*'} BAD client command syntax error\r\n")
|
112
|
+
next
|
113
|
+
end
|
101
114
|
|
102
|
-
|
115
|
+
break unless atom_list
|
103
116
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
log_opt_args = opt_args.dup
|
111
|
-
log_opt_args[-1] = '********'
|
112
|
-
when 'AUTHENTICATE'
|
113
|
-
if (opt_args[1]) then
|
117
|
+
tag, command, *opt_args = atom_list
|
118
|
+
normalized_command = imap_command_normalize(command)
|
119
|
+
logger.info("client command: #{tag} #{command}")
|
120
|
+
if (logger.debug?) then
|
121
|
+
case (normalized_command)
|
122
|
+
when 'LOGIN'
|
114
123
|
log_opt_args = opt_args.dup
|
115
|
-
log_opt_args[1] = '********'
|
124
|
+
log_opt_args[-1] = '********'
|
125
|
+
when 'AUTHENTICATE'
|
126
|
+
if (opt_args[1]) then
|
127
|
+
log_opt_args = opt_args.dup
|
128
|
+
log_opt_args[1] = '********'
|
129
|
+
else
|
130
|
+
log_opt_args = opt_args
|
131
|
+
end
|
116
132
|
else
|
117
133
|
log_opt_args = opt_args
|
118
134
|
end
|
119
|
-
|
120
|
-
log_opt_args = opt_args
|
135
|
+
logger.debug("client command parameter: #{log_opt_args.inspect}")
|
121
136
|
end
|
122
|
-
logger.debug("client command parameter: #{log_opt_args.inspect}")
|
123
|
-
end
|
124
137
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
138
|
+
begin
|
139
|
+
if (name = IMAP_CMDs[normalized_command]) then
|
140
|
+
case (name)
|
141
|
+
when :uid
|
142
|
+
unless (opt_args.empty?) then
|
143
|
+
uid_command, *uid_args = opt_args
|
144
|
+
logger.info("uid command: #{uid_command}")
|
145
|
+
logger.debug("uid parameter: #{uid_args}") if logger.debug?
|
146
|
+
if (uid_name = UID_CMDs[imap_command_normalize(uid_command)]) then
|
147
|
+
apply_imap_command.call(uid_name, tag, *uid_args, uid: true)
|
148
|
+
else
|
149
|
+
logger.error("unknown uid command: #{uid_command}")
|
150
|
+
response_write.call("#{tag} BAD unknown uid command\r\n")
|
151
|
+
end
|
135
152
|
else
|
136
|
-
logger.error(
|
137
|
-
response_write.call("#{tag} BAD
|
153
|
+
logger.error('empty uid parameter.')
|
154
|
+
response_write.call("#{tag} BAD empty uid parameter\r\n")
|
138
155
|
end
|
156
|
+
when :authenticate
|
157
|
+
apply_imap_command.call(:authenticate, tag, input_gets, server_output_write, *opt_args)
|
158
|
+
when :idle
|
159
|
+
apply_imap_command.call(:idle, tag, input_gets, server_output_write, conn_timer, *opt_args)
|
139
160
|
else
|
140
|
-
|
141
|
-
response_write.call("#{tag} BAD empty uid parameter\r\n")
|
161
|
+
apply_imap_command.call(name, tag, *opt_args)
|
142
162
|
end
|
143
|
-
when :authenticate
|
144
|
-
apply_imap_command.call(:authenticate, tag, input_gets, server_output_write, *opt_args)
|
145
|
-
when :idle
|
146
|
-
apply_imap_command.call(:idle, tag, input_gets, server_output_write, conn_timer, *opt_args)
|
147
163
|
else
|
148
|
-
|
164
|
+
logger.error("unknown command: #{command}")
|
165
|
+
response_write.call("#{tag} BAD unknown command\r\n")
|
149
166
|
end
|
150
|
-
|
151
|
-
|
152
|
-
|
167
|
+
rescue LineTooLongError
|
168
|
+
raise
|
169
|
+
rescue
|
170
|
+
logger.error('unexpected error.')
|
171
|
+
logging_error_chain($!, logger)
|
172
|
+
response_write.call("#{tag} BAD unexpected error\r\n")
|
153
173
|
end
|
154
|
-
rescue
|
155
|
-
logger.error('unexpected error.')
|
156
|
-
logging_error_chain($!, logger)
|
157
|
-
response_write.call("#{tag} BAD unexpected error\r\n")
|
158
|
-
end
|
159
|
-
|
160
|
-
if (normalized_command == 'LOGOUT') then
|
161
|
-
break
|
162
|
-
end
|
163
174
|
|
164
|
-
|
165
|
-
|
175
|
+
if (normalized_command == 'LOGOUT') then
|
176
|
+
break
|
177
|
+
end
|
166
178
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
179
|
+
decoder = decoder.next_decoder
|
180
|
+
end
|
181
|
+
rescue LineTooLongError
|
182
|
+
logger.error('line too long error.')
|
183
|
+
logging_error_chain($!, logger)
|
184
|
+
response_write.call("* BAD line too long\r\n")
|
185
|
+
response_write.call("* BYE server autologout: connection terminated\r\n")
|
186
|
+
else
|
187
|
+
if (conn_timer.command_wait_timeout?) then
|
188
|
+
if (limits.command_wait_timeout_seconds > 0) then
|
189
|
+
response_write.call("* BYE server autologout: idle for too long\r\n")
|
190
|
+
else
|
191
|
+
response_write.call("* BYE server autologout: shutdown\r\n")
|
192
|
+
end
|
172
193
|
end
|
173
194
|
end
|
174
195
|
|
@@ -198,6 +219,8 @@ module RIMS
|
|
198
219
|
else
|
199
220
|
__send__(imap_command, tag, *args, **kw_args, &block)
|
200
221
|
end
|
222
|
+
rescue LineTooLongError
|
223
|
+
raise
|
201
224
|
rescue SyntaxError
|
202
225
|
@logger.error('client command syntax error.')
|
203
226
|
logging_error_chain($!)
|
@@ -334,13 +357,26 @@ module RIMS
|
|
334
357
|
end
|
335
358
|
|
336
359
|
def initialize(drb_services, auth, logger,
|
337
|
-
mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user
|
360
|
+
mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user,
|
361
|
+
line_length_limit: Service::DEFAULT_CONFIG.protocol_line_length_limit,
|
362
|
+
literal_size_limit: Service::DEFAULT_CONFIG.protocol_literal_size_limit,
|
363
|
+
command_size_limit: Service::DEFAULT_CONFIG.protocol_command_size_limit)
|
338
364
|
super(auth, logger)
|
339
365
|
@drb_services = drb_services
|
340
366
|
@mail_delivery_user = mail_delivery_user
|
367
|
+
@line_length_limit = line_length_limit
|
368
|
+
@literal_size_limit = literal_size_limit
|
369
|
+
@command_size_limit = command_size_limit
|
341
370
|
@logger.debug("RIMS::Protocol::InitialDecoder#initialize at #{self}") if @logger.debug?
|
342
371
|
end
|
343
372
|
|
373
|
+
def make_requrest_reader(input, output)
|
374
|
+
RequestReader.new(input, output, @logger,
|
375
|
+
line_length_limit: @line_length_limit,
|
376
|
+
literal_size_limit: @literal_size_limit,
|
377
|
+
command_size_limit: @command_size_limit)
|
378
|
+
end
|
379
|
+
|
344
380
|
def auth?
|
345
381
|
false
|
346
382
|
end
|
@@ -868,22 +904,40 @@ module RIMS
|
|
868
904
|
|
869
905
|
class << self
|
870
906
|
def imap_command_authenticated(name, **guard_optional)
|
907
|
+
name = name.to_sym
|
871
908
|
orig_name = "_#{name}".to_sym
|
872
909
|
alias_method orig_name, name
|
873
|
-
|
874
|
-
|
875
|
-
}
|
876
|
-
|
910
|
+
|
911
|
+
guard_options_name = "_#{name}_guard_options".to_sym
|
912
|
+
define_method guard_options_name, lambda{ guard_optional }
|
913
|
+
private guard_options_name
|
914
|
+
|
915
|
+
class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
916
|
+
def #{name}(token, tag, *args, **kw_args, &block)
|
917
|
+
guard_authenticated(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block)
|
918
|
+
end
|
919
|
+
EOF
|
920
|
+
|
921
|
+
name
|
877
922
|
end
|
878
923
|
private :imap_command_authenticated
|
879
924
|
|
880
925
|
def imap_command_selected(name, **guard_optional)
|
926
|
+
name = name.to_sym
|
881
927
|
orig_name = "_#{name}".to_sym
|
882
928
|
alias_method orig_name, name
|
883
|
-
|
884
|
-
|
885
|
-
}
|
886
|
-
|
929
|
+
|
930
|
+
guard_options_name = "_#{name}_guard_options".to_sym
|
931
|
+
define_method guard_options_name, lambda{ guard_optional }
|
932
|
+
private guard_options_name
|
933
|
+
|
934
|
+
class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
935
|
+
def #{name}(token, tag, *args, **kw_args, &block)
|
936
|
+
guard_selected(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block)
|
937
|
+
end
|
938
|
+
EOF
|
939
|
+
|
940
|
+
name
|
887
941
|
end
|
888
942
|
private :imap_command_selected
|
889
943
|
end
|
@@ -1884,7 +1938,7 @@ module RIMS
|
|
1884
1938
|
end
|
1885
1939
|
imap_command :check
|
1886
1940
|
|
1887
|
-
def close(tag
|
1941
|
+
def close(tag)
|
1888
1942
|
ret_val = nil
|
1889
1943
|
old_token = @token
|
1890
1944
|
@token = nil
|
@@ -1946,7 +2000,7 @@ module RIMS
|
|
1946
2000
|
end
|
1947
2001
|
imap_command :store
|
1948
2002
|
|
1949
|
-
def copy(tag, msg_set, mbox_name, uid: false
|
2003
|
+
def copy(tag, msg_set, mbox_name, uid: false)
|
1950
2004
|
ret_val = nil
|
1951
2005
|
@engine.copy(@token, tag, msg_set, mbox_name, uid: uid) {|res|
|
1952
2006
|
for response in res
|
@@ -1958,7 +2012,7 @@ module RIMS
|
|
1958
2012
|
end
|
1959
2013
|
imap_command :copy
|
1960
2014
|
|
1961
|
-
def idle(tag, client_input_gets, server_output_write, connection_timer
|
2015
|
+
def idle(tag, client_input_gets, server_output_write, connection_timer)
|
1962
2016
|
ret_val = nil
|
1963
2017
|
@engine.idle(@token, tag, client_input_gets, server_output_write, connection_timer) {|res|
|
1964
2018
|
for response in res
|