net-imap 0.4.19 → 0.4.20
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.
- checksums.yaml +4 -4
- data/lib/net/imap/config/attr_type_coercion.rb +25 -21
- data/lib/net/imap/config.rb +101 -20
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/response_reader.rb +75 -0
- data/lib/net/imap/sequence_set.rb +61 -59
- data/lib/net/imap.rb +105 -40
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b965efa83b72d27d68fe55ce65f08ffeb696e4a4fb44219e6206a4b7dea4de91
|
4
|
+
data.tar.gz: 3554d7a749873b2eccec2470142315afddb4a6dd359a1d2cd6cfeacffa27d3f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b97c154cfe1b5ce9020029908ec017f316ef36ec36a4948d637d54990ad422580c99bdb2090c4fac4533a503a9678474753d664a101896164ee729d3abaacf37
|
7
|
+
data.tar.gz: 518dc7c466a5200b5945f1b21b8e8bcb4523649a3ef5678811385613834f910f5be9a193fd80dee1a8a029882b62da61c265fd3c942a874bd5cdb43c59d5ccef
|
@@ -18,6 +18,8 @@ module Net
|
|
18
18
|
super(attr)
|
19
19
|
AttrTypeCoercion.attr_accessor(attr, type: type)
|
20
20
|
end
|
21
|
+
|
22
|
+
module_function def Integer?; NilOrInteger end
|
21
23
|
end
|
22
24
|
private_constant :Macros
|
23
25
|
|
@@ -26,34 +28,36 @@ module Net
|
|
26
28
|
end
|
27
29
|
private_class_method :included
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
elsif Array === type then enum attr, type
|
34
|
-
else raise ArgumentError, "unknown type coercion %p" % [type]
|
35
|
-
end
|
31
|
+
if defined?(Ractor.make_shareable)
|
32
|
+
def self.safe(...) Ractor.make_shareable nil.instance_eval(...).freeze end
|
33
|
+
else
|
34
|
+
def self.safe(...) nil.instance_eval(...).freeze end
|
36
35
|
end
|
36
|
+
private_class_method :safe
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
Types = Hash.new do |h, type|
|
39
|
+
type.nil? || Proc === type or raise TypeError, "type not nil or Proc"
|
40
|
+
safe{type}
|
41
41
|
end
|
42
|
+
Types[:boolean] = Boolean = safe{-> {!!_1}}
|
43
|
+
Types[Integer] = safe{->{Integer(_1)}}
|
42
44
|
|
43
|
-
def self.
|
44
|
-
|
45
|
+
def self.attr_accessor(attr, type: nil)
|
46
|
+
type = Types[type] or return
|
47
|
+
define_method :"#{attr}=" do |val| super type[val] end
|
48
|
+
define_method :"#{attr}?" do send attr end if type == Boolean
|
45
49
|
end
|
46
50
|
|
47
|
-
|
48
|
-
|
51
|
+
NilOrInteger = safe{->val { Integer val unless val.nil? }}
|
52
|
+
|
53
|
+
Enum = ->(*enum) {
|
54
|
+
enum = safe{enum}
|
49
55
|
expected = -"one of #{enum.map(&:inspect).join(", ")}"
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
56
|
+
safe{->val {
|
57
|
+
return val if enum.include?(val)
|
58
|
+
raise ArgumentError, "expected %s, got %p" % [expected, val]
|
59
|
+
}}
|
60
|
+
}
|
57
61
|
|
58
62
|
end
|
59
63
|
end
|
data/lib/net/imap/config.rb
CHANGED
@@ -129,8 +129,25 @@ module Net
|
|
129
129
|
def self.global; @global if defined?(@global) end
|
130
130
|
|
131
131
|
# A hash of hard-coded configurations, indexed by version number or name.
|
132
|
+
# Values can be accessed with any object that responds to +to_sym+ or
|
133
|
+
# +to_r+/+to_f+ with a non-zero number.
|
134
|
+
#
|
135
|
+
# Config::[] gets named or numbered versions from this hash.
|
136
|
+
#
|
137
|
+
# For example:
|
138
|
+
# Net::IMAP::Config.version_defaults[0.5] == Net::IMAP::Config[0.5]
|
139
|
+
# Net::IMAP::Config[0.5] == Net::IMAP::Config[0.5r] # => true
|
140
|
+
# Net::IMAP::Config["current"] == Net::IMAP::Config[:current] # => true
|
141
|
+
# Net::IMAP::Config["0.5.6"] == Net::IMAP::Config[0.5r] # => true
|
132
142
|
def self.version_defaults; @version_defaults end
|
133
|
-
@version_defaults = {
|
143
|
+
@version_defaults = Hash.new {|h, k|
|
144
|
+
# NOTE: String responds to both so the order is significant.
|
145
|
+
# And ignore non-numeric conversion to zero, because: "wat!?".to_r == 0
|
146
|
+
(h.fetch(k.to_r, nil) || h.fetch(k.to_f, nil) if k.is_a?(Numeric)) ||
|
147
|
+
(h.fetch(k.to_sym, nil) if k.respond_to?(:to_sym)) ||
|
148
|
+
(h.fetch(k.to_r, nil) if k.respond_to?(:to_r) && k.to_r != 0r) ||
|
149
|
+
(h.fetch(k.to_f, nil) if k.respond_to?(:to_f) && k.to_f != 0.0)
|
150
|
+
}
|
134
151
|
|
135
152
|
# :call-seq:
|
136
153
|
# Net::IMAP::Config[number] -> versioned config
|
@@ -153,18 +170,17 @@ module Net
|
|
153
170
|
elsif config.nil? && global.nil? then nil
|
154
171
|
elsif config.respond_to?(:to_hash) then new(global, **config).freeze
|
155
172
|
else
|
156
|
-
version_defaults
|
173
|
+
version_defaults[config] or
|
157
174
|
case config
|
158
175
|
when Numeric
|
159
176
|
raise RangeError, "unknown config version: %p" % [config]
|
160
|
-
when Symbol
|
177
|
+
when String, Symbol
|
161
178
|
raise KeyError, "unknown config name: %p" % [config]
|
162
179
|
else
|
163
180
|
raise TypeError, "no implicit conversion of %s to %s" % [
|
164
181
|
config.class, Config
|
165
182
|
]
|
166
183
|
end
|
167
|
-
end
|
168
184
|
end
|
169
185
|
end
|
170
186
|
|
@@ -191,10 +207,13 @@ module Net
|
|
191
207
|
|
192
208
|
# Seconds to wait until a connection is opened.
|
193
209
|
#
|
210
|
+
# Applied separately for establishing TCP connection and starting a TLS
|
211
|
+
# connection.
|
212
|
+
#
|
194
213
|
# If the IMAP object cannot open a connection within this time,
|
195
214
|
# it raises a Net::OpenTimeout exception.
|
196
215
|
#
|
197
|
-
# See Net::IMAP.new.
|
216
|
+
# See Net::IMAP.new and Net::IMAP#starttls.
|
198
217
|
#
|
199
218
|
# The default value is +30+ seconds.
|
200
219
|
attr_accessor :open_timeout, type: Integer
|
@@ -223,6 +242,40 @@ module Net
|
|
223
242
|
# Use +SASL-IR+ when it is supported by the server and the mechanism.
|
224
243
|
attr_accessor :sasl_ir, type: :boolean
|
225
244
|
|
245
|
+
# The maximum allowed server response size. When +nil+, there is no limit
|
246
|
+
# on response size.
|
247
|
+
#
|
248
|
+
# The default value (512 MiB, since +v0.5.7+) is <em>very high</em> and
|
249
|
+
# unlikely to be reached. To use a lower limit, fetch message bodies in
|
250
|
+
# chunks rather than all at once. A _much_ lower value should be used
|
251
|
+
# with untrusted servers (for example, when connecting to a user-provided
|
252
|
+
# hostname).
|
253
|
+
#
|
254
|
+
# <em>Please Note:</em> this only limits the size per response. It does
|
255
|
+
# not prevent a flood of individual responses and it does not limit how
|
256
|
+
# many unhandled responses may be stored on the responses hash. See
|
257
|
+
# Net::IMAP@Unbounded+memory+use.
|
258
|
+
#
|
259
|
+
# Socket reads are limited to the maximum remaining bytes for the current
|
260
|
+
# response: max_response_size minus the bytes that have already been read.
|
261
|
+
# When the limit is reached, or reading a +literal+ _would_ go over the
|
262
|
+
# limit, ResponseTooLargeError is raised and the connection is closed.
|
263
|
+
# See also #socket_read_limit.
|
264
|
+
#
|
265
|
+
# Note that changes will not take effect immediately, because the receiver
|
266
|
+
# thread may already be waiting for the next response using the previous
|
267
|
+
# value. Net::IMAP#noop can force a response and enforce the new setting
|
268
|
+
# immediately.
|
269
|
+
#
|
270
|
+
# ==== Versioned Defaults
|
271
|
+
#
|
272
|
+
# Net::IMAP#max_response_size <em>was added in +v0.2.5+ and +v0.3.9+ as an
|
273
|
+
# attr_accessor, and in +v0.4.20+ and +v0.5.7+ as a delegator to this
|
274
|
+
# config attribute.</em>
|
275
|
+
#
|
276
|
+
# * original: +nil+ <em>(no limit)</em>
|
277
|
+
# * +0.5+: 512 MiB
|
278
|
+
attr_accessor :max_response_size, type: Integer?
|
226
279
|
|
227
280
|
# Controls the behavior of Net::IMAP#responses when called without any
|
228
281
|
# arguments (+type+ or +block+).
|
@@ -250,7 +303,7 @@ module Net
|
|
250
303
|
# Raise an ArgumentError with the deprecation warning.
|
251
304
|
#
|
252
305
|
# Note: #responses_without_args is an alias for #responses_without_block.
|
253
|
-
attr_accessor :responses_without_block, type: [
|
306
|
+
attr_accessor :responses_without_block, type: Enum[
|
254
307
|
:silence_deprecation_warning, :warn, :frozen_dup, :raise,
|
255
308
|
]
|
256
309
|
|
@@ -295,7 +348,7 @@ module Net
|
|
295
348
|
#
|
296
349
|
# [+false+ <em>(planned default for +v0.6+)</em>]
|
297
350
|
# ResponseParser _only_ uses AppendUIDData and CopyUIDData.
|
298
|
-
attr_accessor :parser_use_deprecated_uidplus_data, type: [
|
351
|
+
attr_accessor :parser_use_deprecated_uidplus_data, type: Enum[
|
299
352
|
true, :up_to_max_size, false
|
300
353
|
]
|
301
354
|
|
@@ -401,6 +454,7 @@ module Net
|
|
401
454
|
open_timeout: 30,
|
402
455
|
idle_response_timeout: 5,
|
403
456
|
sasl_ir: true,
|
457
|
+
max_response_size: nil,
|
404
458
|
responses_without_block: :silence_deprecation_warning,
|
405
459
|
parser_use_deprecated_uidplus_data: true,
|
406
460
|
parser_max_deprecated_uidplus_data_size: 1000,
|
@@ -408,36 +462,63 @@ module Net
|
|
408
462
|
|
409
463
|
@global = default.new
|
410
464
|
|
411
|
-
version_defaults[
|
465
|
+
version_defaults[:default] = Config[default.send(:defaults_hash)]
|
412
466
|
|
413
|
-
version_defaults[
|
467
|
+
version_defaults[0r] = Config[:default].dup.update(
|
414
468
|
sasl_ir: false,
|
469
|
+
max_response_size: nil,
|
415
470
|
parser_use_deprecated_uidplus_data: true,
|
416
471
|
parser_max_deprecated_uidplus_data_size: 10_000,
|
417
472
|
).freeze
|
418
|
-
version_defaults[0.
|
419
|
-
version_defaults[0.
|
420
|
-
version_defaults[0.
|
421
|
-
version_defaults[0.
|
473
|
+
version_defaults[0.0r] = Config[0r]
|
474
|
+
version_defaults[0.1r] = Config[0r]
|
475
|
+
version_defaults[0.2r] = Config[0r]
|
476
|
+
version_defaults[0.3r] = Config[0r]
|
422
477
|
|
423
|
-
version_defaults[0.
|
478
|
+
version_defaults[0.4r] = Config[0.3r].dup.update(
|
479
|
+
sasl_ir: true,
|
480
|
+
parser_max_deprecated_uidplus_data_size: 1000,
|
481
|
+
).freeze
|
482
|
+
|
483
|
+
version_defaults[0.5r] = Config[0.4r].dup.update(
|
484
|
+
max_response_size: 512 << 20, # 512 MiB
|
424
485
|
responses_without_block: :warn,
|
425
486
|
parser_use_deprecated_uidplus_data: :up_to_max_size,
|
426
487
|
parser_max_deprecated_uidplus_data_size: 100,
|
427
488
|
).freeze
|
428
489
|
|
429
|
-
version_defaults[
|
430
|
-
version_defaults[:current] = Config[0.4]
|
431
|
-
version_defaults[:next] = Config[0.5]
|
432
|
-
|
433
|
-
version_defaults[0.6] = Config[0.5].dup.update(
|
490
|
+
version_defaults[0.6r] = Config[0.5r].dup.update(
|
434
491
|
responses_without_block: :frozen_dup,
|
435
492
|
parser_use_deprecated_uidplus_data: false,
|
436
493
|
parser_max_deprecated_uidplus_data_size: 0,
|
437
494
|
).freeze
|
438
|
-
|
495
|
+
|
496
|
+
version_defaults[0.7r] = Config[0.6r].dup.update(
|
497
|
+
).freeze
|
498
|
+
|
499
|
+
# Safe conversions one way only:
|
500
|
+
# 0.6r.to_f == 0.6 # => true
|
501
|
+
# 0.6 .to_r == 0.6r # => false
|
502
|
+
version_defaults.to_a.each do |k, v|
|
503
|
+
next unless k.is_a? Rational
|
504
|
+
version_defaults[k.to_f] = v
|
505
|
+
end
|
506
|
+
|
507
|
+
current = VERSION.to_r
|
508
|
+
version_defaults[:original] = Config[0]
|
509
|
+
version_defaults[:current] = Config[current]
|
510
|
+
version_defaults[:next] = Config[current + 0.1r]
|
511
|
+
|
512
|
+
version_defaults[:future] = Config[0.7r]
|
439
513
|
|
440
514
|
version_defaults.freeze
|
515
|
+
|
516
|
+
if ($VERBOSE || $DEBUG) && self[:current].to_h != self[:default].to_h
|
517
|
+
warn "Misconfigured Net::IMAP::Config[:current] => %p,\n" \
|
518
|
+
" not equal to Net::IMAP::Config[:default] => %p" % [
|
519
|
+
self[:current].to_h, self[:default].to_h
|
520
|
+
]
|
521
|
+
end
|
441
522
|
end
|
442
523
|
end
|
443
524
|
end
|
data/lib/net/imap/errors.rb
CHANGED
@@ -11,6 +11,39 @@ module Net
|
|
11
11
|
class DataFormatError < Error
|
12
12
|
end
|
13
13
|
|
14
|
+
# Error raised when the socket cannot be read, due to a Config limit.
|
15
|
+
class ResponseReadError < Error
|
16
|
+
end
|
17
|
+
|
18
|
+
# Error raised when a response is larger than IMAP#max_response_size.
|
19
|
+
class ResponseTooLargeError < ResponseReadError
|
20
|
+
attr_reader :bytes_read, :literal_size
|
21
|
+
attr_reader :max_response_size
|
22
|
+
|
23
|
+
def initialize(msg = nil, *args,
|
24
|
+
bytes_read: nil,
|
25
|
+
literal_size: nil,
|
26
|
+
max_response_size: nil,
|
27
|
+
**kwargs)
|
28
|
+
@bytes_read = bytes_read
|
29
|
+
@literal_size = literal_size
|
30
|
+
@max_response_size = max_response_size
|
31
|
+
msg ||= [
|
32
|
+
"Response size", response_size_msg, "exceeds max_response_size",
|
33
|
+
max_response_size && "(#{max_response_size}B)",
|
34
|
+
].compact.join(" ")
|
35
|
+
super(msg, *args, **kwargs)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def response_size_msg
|
41
|
+
if bytes_read && literal_size
|
42
|
+
"(#{bytes_read}B read + #{literal_size}B literal)"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
14
47
|
# Error raised when a response from the server is non-parsable.
|
15
48
|
class ResponseParseError < Error
|
16
49
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Net
|
4
|
+
class IMAP
|
5
|
+
# See https://www.rfc-editor.org/rfc/rfc9051#section-2.2.2
|
6
|
+
class ResponseReader # :nodoc:
|
7
|
+
attr_reader :client
|
8
|
+
|
9
|
+
def initialize(client, sock)
|
10
|
+
@client, @sock = client, sock
|
11
|
+
end
|
12
|
+
|
13
|
+
def read_response_buffer
|
14
|
+
@buff = String.new
|
15
|
+
catch :eof do
|
16
|
+
while true
|
17
|
+
read_line
|
18
|
+
break unless (@literal_size = get_literal_size)
|
19
|
+
read_literal
|
20
|
+
end
|
21
|
+
end
|
22
|
+
buff
|
23
|
+
ensure
|
24
|
+
@buff = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :buff, :literal_size
|
30
|
+
|
31
|
+
def bytes_read; buff.bytesize end
|
32
|
+
def empty?; buff.empty? end
|
33
|
+
def done?; line_done? && !get_literal_size end
|
34
|
+
def line_done?; buff.end_with?(CRLF) end
|
35
|
+
def get_literal_size; /\{(\d+)\}\r\n\z/n =~ buff && $1.to_i end
|
36
|
+
|
37
|
+
def read_line
|
38
|
+
buff << (@sock.gets(CRLF, read_limit) or throw :eof)
|
39
|
+
max_response_remaining! unless line_done?
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_literal
|
43
|
+
# check before allocating memory for literal
|
44
|
+
max_response_remaining!
|
45
|
+
literal = String.new(capacity: literal_size)
|
46
|
+
buff << (@sock.read(read_limit(literal_size), literal) or throw :eof)
|
47
|
+
ensure
|
48
|
+
@literal_size = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def read_limit(limit = nil)
|
52
|
+
[limit, max_response_remaining!].compact.min
|
53
|
+
end
|
54
|
+
|
55
|
+
def max_response_size; client.max_response_size end
|
56
|
+
def max_response_remaining; max_response_size &.- bytes_read end
|
57
|
+
def response_too_large?; max_response_size &.< min_response_size end
|
58
|
+
def min_response_size; bytes_read + min_response_remaining end
|
59
|
+
|
60
|
+
def min_response_remaining
|
61
|
+
empty? ? 3 : done? ? 0 : (literal_size || 0) + 2
|
62
|
+
end
|
63
|
+
|
64
|
+
def max_response_remaining!
|
65
|
+
return max_response_remaining unless response_too_large?
|
66
|
+
raise ResponseTooLargeError.new(
|
67
|
+
max_response_size: max_response_size,
|
68
|
+
bytes_read: bytes_read,
|
69
|
+
literal_size: literal_size,
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -178,7 +178,7 @@ module Net
|
|
178
178
|
#
|
179
179
|
# <i>Set membership:</i>
|
180
180
|
# - #include? (aliased as #member?):
|
181
|
-
# Returns whether a given
|
181
|
+
# Returns whether a given element (nz-number, range, or <tt>*</tt>) is
|
182
182
|
# contained by the set.
|
183
183
|
# - #include_star?: Returns whether the set contains <tt>*</tt>.
|
184
184
|
#
|
@@ -243,13 +243,13 @@ module Net
|
|
243
243
|
# These methods do not modify +self+.
|
244
244
|
#
|
245
245
|
# - #| (aliased as #union and #+): Returns a new set combining all members
|
246
|
-
# from +self+ with all members from the other
|
246
|
+
# from +self+ with all members from the other set.
|
247
247
|
# - #& (aliased as #intersection): Returns a new set containing all members
|
248
|
-
# common to +self+ and the other
|
248
|
+
# common to +self+ and the other set.
|
249
249
|
# - #- (aliased as #difference): Returns a copy of +self+ with all members
|
250
|
-
# in the other
|
250
|
+
# in the other set removed.
|
251
251
|
# - #^ (aliased as #xor): Returns a new set containing all members from
|
252
|
-
# +self+ and the other
|
252
|
+
# +self+ and the other set except those common to both.
|
253
253
|
# - #~ (aliased as #complement): Returns a new set containing all members
|
254
254
|
# that are not in +self+
|
255
255
|
# - #limit: Returns a copy of +self+ which has replaced <tt>*</tt> with a
|
@@ -262,17 +262,17 @@ module Net
|
|
262
262
|
#
|
263
263
|
# These methods always update #string to be fully sorted and coalesced.
|
264
264
|
#
|
265
|
-
# - #add (aliased as #<<): Adds a given
|
266
|
-
# - #add?: If the given
|
265
|
+
# - #add (aliased as #<<): Adds a given element to the set; returns +self+.
|
266
|
+
# - #add?: If the given element is not fully included the set, adds it and
|
267
267
|
# returns +self+; otherwise, returns +nil+.
|
268
|
-
# - #merge:
|
268
|
+
# - #merge: Adds all members of the given sets into this set; returns +self+.
|
269
269
|
# - #complement!: Replaces the contents of the set with its own #complement.
|
270
270
|
#
|
271
271
|
# <i>Order preserving:</i>
|
272
272
|
#
|
273
273
|
# These methods _may_ cause #string to not be sorted or coalesced.
|
274
274
|
#
|
275
|
-
# - #append: Adds
|
275
|
+
# - #append: Adds the given entry to the set, appending it to the existing
|
276
276
|
# string, and returns +self+.
|
277
277
|
# - #string=: Assigns a new #string value and replaces #elements to match.
|
278
278
|
# - #replace: Replaces the contents of the set with the contents
|
@@ -283,13 +283,14 @@ module Net
|
|
283
283
|
# sorted and coalesced.
|
284
284
|
#
|
285
285
|
# - #clear: Removes all elements in the set; returns +self+.
|
286
|
-
# - #delete: Removes a given
|
287
|
-
# - #delete?: If the given
|
286
|
+
# - #delete: Removes a given element from the set; returns +self+.
|
287
|
+
# - #delete?: If the given element is included in the set, removes it and
|
288
288
|
# returns it; otherwise, returns +nil+.
|
289
289
|
# - #delete_at: Removes the number at a given offset.
|
290
290
|
# - #slice!: Removes the number or consecutive numbers at a given offset or
|
291
291
|
# range of offsets.
|
292
|
-
# - #subtract: Removes
|
292
|
+
# - #subtract: Removes all members of the given sets from this set; returns
|
293
|
+
# +self+.
|
293
294
|
# - #limit!: Replaces <tt>*</tt> with a given maximum value and removes all
|
294
295
|
# members over that maximum; returns +self+.
|
295
296
|
#
|
@@ -326,9 +327,12 @@ module Net
|
|
326
327
|
class << self
|
327
328
|
|
328
329
|
# :call-seq:
|
329
|
-
# SequenceSet[*
|
330
|
+
# SequenceSet[*inputs] -> valid frozen sequence set
|
330
331
|
#
|
331
|
-
# Returns a frozen SequenceSet, constructed from +
|
332
|
+
# Returns a frozen SequenceSet, constructed from +inputs+.
|
333
|
+
#
|
334
|
+
# When only a single valid frozen SequenceSet is given, that same set is
|
335
|
+
# returned.
|
332
336
|
#
|
333
337
|
# An empty SequenceSet is invalid and will raise a DataFormatError.
|
334
338
|
#
|
@@ -694,7 +698,7 @@ module Net
|
|
694
698
|
alias complement :~
|
695
699
|
|
696
700
|
# :call-seq:
|
697
|
-
# add(
|
701
|
+
# add(element) -> self
|
698
702
|
# self << other -> self
|
699
703
|
#
|
700
704
|
# Adds a range or number to the set and returns +self+.
|
@@ -702,8 +706,8 @@ module Net
|
|
702
706
|
# #string will be regenerated. Use #merge to add many elements at once.
|
703
707
|
#
|
704
708
|
# Related: #add?, #merge, #union
|
705
|
-
def add(
|
706
|
-
tuple_add input_to_tuple
|
709
|
+
def add(element)
|
710
|
+
tuple_add input_to_tuple element
|
707
711
|
normalize!
|
708
712
|
end
|
709
713
|
alias << add
|
@@ -712,9 +716,9 @@ module Net
|
|
712
716
|
#
|
713
717
|
# Unlike #add, #merge, or #union, the new value is appended to #string.
|
714
718
|
# This may result in a #string which has duplicates or is out-of-order.
|
715
|
-
def append(
|
719
|
+
def append(entry)
|
716
720
|
modifying!
|
717
|
-
tuple = input_to_tuple
|
721
|
+
tuple = input_to_tuple entry
|
718
722
|
entry = tuple_to_str tuple
|
719
723
|
string unless empty? # write @string before tuple_add
|
720
724
|
tuple_add tuple
|
@@ -722,19 +726,19 @@ module Net
|
|
722
726
|
self
|
723
727
|
end
|
724
728
|
|
725
|
-
# :call-seq: add?(
|
729
|
+
# :call-seq: add?(element) -> self or nil
|
726
730
|
#
|
727
731
|
# Adds a range or number to the set and returns +self+. Returns +nil+
|
728
|
-
# when the
|
732
|
+
# when the element is already included in the set.
|
729
733
|
#
|
730
734
|
# #string will be regenerated. Use #merge to add many elements at once.
|
731
735
|
#
|
732
736
|
# Related: #add, #merge, #union, #include?
|
733
|
-
def add?(
|
734
|
-
add
|
737
|
+
def add?(element)
|
738
|
+
add element unless include? element
|
735
739
|
end
|
736
740
|
|
737
|
-
# :call-seq: delete(
|
741
|
+
# :call-seq: delete(element) -> self
|
738
742
|
#
|
739
743
|
# Deletes the given range or number from the set and returns +self+.
|
740
744
|
#
|
@@ -742,8 +746,8 @@ module Net
|
|
742
746
|
# many elements at once.
|
743
747
|
#
|
744
748
|
# Related: #delete?, #delete_at, #subtract, #difference
|
745
|
-
def delete(
|
746
|
-
tuple_subtract input_to_tuple
|
749
|
+
def delete(element)
|
750
|
+
tuple_subtract input_to_tuple element
|
747
751
|
normalize!
|
748
752
|
end
|
749
753
|
|
@@ -779,8 +783,8 @@ module Net
|
|
779
783
|
# #string will be regenerated after deletion.
|
780
784
|
#
|
781
785
|
# Related: #delete, #delete_at, #subtract, #difference, #disjoint?
|
782
|
-
def delete?(
|
783
|
-
tuple = input_to_tuple
|
786
|
+
def delete?(element)
|
787
|
+
tuple = input_to_tuple element
|
784
788
|
if tuple.first == tuple.last
|
785
789
|
return unless include_tuple? tuple
|
786
790
|
tuple_subtract tuple
|
@@ -824,33 +828,31 @@ module Net
|
|
824
828
|
deleted
|
825
829
|
end
|
826
830
|
|
827
|
-
# Merges all of the elements that appear in any of the +
|
831
|
+
# Merges all of the elements that appear in any of the +sets+ into the
|
828
832
|
# set, and returns +self+.
|
829
833
|
#
|
830
|
-
# The +
|
831
|
-
#
|
832
|
-
#
|
833
|
-
# these.
|
834
|
+
# The +sets+ may be any objects that would be accepted by ::new: non-zero
|
835
|
+
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
836
|
+
# strings, other sequence sets, or enumerables containing any of these.
|
834
837
|
#
|
835
|
-
# #string will be regenerated after all
|
838
|
+
# #string will be regenerated after all sets have been merged.
|
836
839
|
#
|
837
840
|
# Related: #add, #add?, #union
|
838
|
-
def merge(*
|
839
|
-
tuples_add input_to_tuples
|
841
|
+
def merge(*sets)
|
842
|
+
tuples_add input_to_tuples sets
|
840
843
|
normalize!
|
841
844
|
end
|
842
845
|
|
843
|
-
# Removes all of the elements that appear in any of the given +
|
844
|
-
#
|
846
|
+
# Removes all of the elements that appear in any of the given +sets+ from
|
847
|
+
# the set, and returns +self+.
|
845
848
|
#
|
846
|
-
# The +
|
847
|
-
#
|
848
|
-
#
|
849
|
-
# these.
|
849
|
+
# The +sets+ may be any objects that would be accepted by ::new: non-zero
|
850
|
+
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
851
|
+
# strings, other sequence sets, or enumerables containing any of these.
|
850
852
|
#
|
851
853
|
# Related: #difference
|
852
|
-
def subtract(*
|
853
|
-
tuples_subtract input_to_tuples
|
854
|
+
def subtract(*sets)
|
855
|
+
tuples_subtract input_to_tuples sets
|
854
856
|
normalize!
|
855
857
|
end
|
856
858
|
|
@@ -1390,29 +1392,29 @@ module Net
|
|
1390
1392
|
super
|
1391
1393
|
end
|
1392
1394
|
|
1393
|
-
def input_to_tuple(
|
1394
|
-
|
1395
|
-
case
|
1396
|
-
when *STARS, Integer then [int = to_tuple_int(
|
1397
|
-
when Range then range_to_tuple(
|
1398
|
-
when String then str_to_tuple(
|
1395
|
+
def input_to_tuple(entry)
|
1396
|
+
entry = input_try_convert entry
|
1397
|
+
case entry
|
1398
|
+
when *STARS, Integer then [int = to_tuple_int(entry), int]
|
1399
|
+
when Range then range_to_tuple(entry)
|
1400
|
+
when String then str_to_tuple(entry)
|
1399
1401
|
else
|
1400
|
-
raise DataFormatError, "expected number or range, got %p" % [
|
1402
|
+
raise DataFormatError, "expected number or range, got %p" % [entry]
|
1401
1403
|
end
|
1402
1404
|
end
|
1403
1405
|
|
1404
|
-
def input_to_tuples(
|
1405
|
-
|
1406
|
-
case
|
1407
|
-
when *STARS, Integer, Range then [input_to_tuple(
|
1408
|
-
when String then str_to_tuples
|
1409
|
-
when SequenceSet then
|
1410
|
-
when ENUMABLE then
|
1406
|
+
def input_to_tuples(set)
|
1407
|
+
set = input_try_convert set
|
1408
|
+
case set
|
1409
|
+
when *STARS, Integer, Range then [input_to_tuple(set)]
|
1410
|
+
when String then str_to_tuples set
|
1411
|
+
when SequenceSet then set.tuples
|
1412
|
+
when ENUMABLE then set.flat_map { input_to_tuples _1 }
|
1411
1413
|
when nil then []
|
1412
1414
|
else
|
1413
1415
|
raise DataFormatError,
|
1414
1416
|
"expected nz-number, range, string, or enumerable; " \
|
1415
|
-
"got %p" % [
|
1417
|
+
"got %p" % [set]
|
1416
1418
|
end
|
1417
1419
|
end
|
1418
1420
|
|
data/lib/net/imap.rb
CHANGED
@@ -43,10 +43,16 @@ module Net
|
|
43
43
|
# To work on the messages within a mailbox, the client must
|
44
44
|
# first select that mailbox, using either #select or #examine
|
45
45
|
# (for read-only access). Once the client has successfully
|
46
|
-
# selected a mailbox, they enter the
|
46
|
+
# selected a mailbox, they enter the +selected+ state, and that
|
47
47
|
# mailbox becomes the _current_ mailbox, on which mail-item
|
48
48
|
# related commands implicitly operate.
|
49
49
|
#
|
50
|
+
# === Connection state
|
51
|
+
#
|
52
|
+
# Once an IMAP connection is established, the connection is in one of four
|
53
|
+
# states: <tt>not authenticated</tt>, +authenticated+, +selected+, and
|
54
|
+
# +logout+. Most commands are valid only in certain states.
|
55
|
+
#
|
50
56
|
# === Sequence numbers and UIDs
|
51
57
|
#
|
52
58
|
# Messages have two sorts of identifiers: message sequence
|
@@ -199,6 +205,42 @@ module Net
|
|
199
205
|
#
|
200
206
|
# This script invokes the FETCH command and the SEARCH command concurrently.
|
201
207
|
#
|
208
|
+
# When running multiple commands, care must be taken to avoid ambiguity. For
|
209
|
+
# example, SEARCH responses are ambiguous about which command they are
|
210
|
+
# responding to, so search commands should not run simultaneously, unless the
|
211
|
+
# server supports +ESEARCH+ {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731] or
|
212
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]. See {RFC9051
|
213
|
+
# §5.5}[https://www.rfc-editor.org/rfc/rfc9051.html#section-5.5] for
|
214
|
+
# other examples of command sequences which should not be pipelined.
|
215
|
+
#
|
216
|
+
# == Unbounded memory use
|
217
|
+
#
|
218
|
+
# Net::IMAP reads server responses in a separate receiver thread per client.
|
219
|
+
# Unhandled response data is saved to #responses, and response_handlers run
|
220
|
+
# inside the receiver thread. See the list of methods for {handling server
|
221
|
+
# responses}[rdoc-ref:Net::IMAP@Handling+server+responses], below.
|
222
|
+
#
|
223
|
+
# Because the receiver thread continuously reads and saves new responses, some
|
224
|
+
# scenarios must be careful to avoid unbounded memory use:
|
225
|
+
#
|
226
|
+
# * Commands such as #list or #fetch can have an enormous number of responses.
|
227
|
+
# * Commands such as #fetch can result in an enormous size per response.
|
228
|
+
# * Long-lived connections will gradually accumulate unsolicited server
|
229
|
+
# responses, especially +EXISTS+, +FETCH+, and +EXPUNGE+ responses.
|
230
|
+
# * A buggy or untrusted server could send inappropriate responses, which
|
231
|
+
# could be very numerous, very large, and very rapid.
|
232
|
+
#
|
233
|
+
# Use paginated or limited versions of commands whenever possible.
|
234
|
+
#
|
235
|
+
# Use Config#max_response_size to impose a limit on incoming server responses
|
236
|
+
# as they are being read. <em>This is especially important for untrusted
|
237
|
+
# servers.</em>
|
238
|
+
#
|
239
|
+
# Use #add_response_handler to handle responses after each one is received.
|
240
|
+
# Use the +response_handlers+ argument to ::new to assign response handlers
|
241
|
+
# before the receiver thread is started. Use #extract_responses,
|
242
|
+
# #clear_responses, or #responses (with a block) to prune responses.
|
243
|
+
#
|
202
244
|
# == Errors
|
203
245
|
#
|
204
246
|
# An \IMAP server can send three different types of responses to indicate
|
@@ -260,8 +302,9 @@ module Net
|
|
260
302
|
#
|
261
303
|
# - Net::IMAP.new: Creates a new \IMAP client which connects immediately and
|
262
304
|
# waits for a successful server greeting before the method returns.
|
305
|
+
# - #connection_state: Returns the connection state.
|
263
306
|
# - #starttls: Asks the server to upgrade a clear-text connection to use TLS.
|
264
|
-
# - #logout: Tells the server to end the session.
|
307
|
+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
265
308
|
# - #disconnect: Disconnects the connection (without sending #logout first).
|
266
309
|
# - #disconnected?: True if the connection has been closed.
|
267
310
|
#
|
@@ -317,37 +360,36 @@ module Net
|
|
317
360
|
# <em>In general, #capable? should be used rather than explicitly sending a
|
318
361
|
# +CAPABILITY+ command to the server.</em>
|
319
362
|
# - #noop: Allows the server to send unsolicited untagged #responses.
|
320
|
-
# - #logout: Tells the server to end the session. Enters the
|
363
|
+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
321
364
|
#
|
322
365
|
# ==== Not Authenticated state
|
323
366
|
#
|
324
367
|
# In addition to the commands for any state, the following commands are valid
|
325
|
-
# in the
|
368
|
+
# in the +not_authenticated+ state:
|
326
369
|
#
|
327
370
|
# - #starttls: Upgrades a clear-text connection to use TLS.
|
328
371
|
#
|
329
372
|
# <em>Requires the +STARTTLS+ capability.</em>
|
330
373
|
# - #authenticate: Identifies the client to the server using the given
|
331
374
|
# {SASL mechanism}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
|
332
|
-
# and credentials. Enters the
|
375
|
+
# and credentials. Enters the +authenticated+ state.
|
333
376
|
#
|
334
377
|
# <em>The server should list <tt>"AUTH=#{mechanism}"</tt> capabilities for
|
335
378
|
# supported mechanisms.</em>
|
336
379
|
# - #login: Identifies the client to the server using a plain text password.
|
337
|
-
# Using #authenticate is
|
338
|
-
# state.
|
380
|
+
# Using #authenticate is preferred. Enters the +authenticated+ state.
|
339
381
|
#
|
340
382
|
# <em>The +LOGINDISABLED+ capability</em> <b>must NOT</b> <em>be listed.</em>
|
341
383
|
#
|
342
384
|
# ==== Authenticated state
|
343
385
|
#
|
344
386
|
# In addition to the commands for any state, the following commands are valid
|
345
|
-
# in the
|
387
|
+
# in the +authenticated+ state:
|
346
388
|
#
|
347
389
|
# - #enable: Enables backwards incompatible server extensions.
|
348
390
|
# <em>Requires the +ENABLE+ or +IMAP4rev2+ capability.</em>
|
349
|
-
# - #select: Open a mailbox and enter the
|
350
|
-
# - #examine: Open a mailbox read-only, and enter the
|
391
|
+
# - #select: Open a mailbox and enter the +selected+ state.
|
392
|
+
# - #examine: Open a mailbox read-only, and enter the +selected+ state.
|
351
393
|
# - #create: Creates a new mailbox.
|
352
394
|
# - #delete: Permanently remove a mailbox.
|
353
395
|
# - #rename: Change the name of a mailbox.
|
@@ -369,12 +411,12 @@ module Net
|
|
369
411
|
#
|
370
412
|
# ==== Selected state
|
371
413
|
#
|
372
|
-
# In addition to the commands for any state and the
|
373
|
-
# commands, the following commands are valid in the
|
414
|
+
# In addition to the commands for any state and the +authenticated+
|
415
|
+
# commands, the following commands are valid in the +selected+ state:
|
374
416
|
#
|
375
|
-
# - #close: Closes the mailbox and returns to the
|
417
|
+
# - #close: Closes the mailbox and returns to the +authenticated+ state,
|
376
418
|
# expunging deleted messages, unless the mailbox was opened as read-only.
|
377
|
-
# - #unselect: Closes the mailbox and returns to the
|
419
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
378
420
|
# without expunging any messages.
|
379
421
|
# <em>Requires the +UNSELECT+ or +IMAP4rev2+ capability.</em>
|
380
422
|
# - #expunge: Permanently removes messages which have the Deleted flag set.
|
@@ -395,7 +437,7 @@ module Net
|
|
395
437
|
#
|
396
438
|
# ==== Logout state
|
397
439
|
#
|
398
|
-
# No \IMAP commands are valid in the
|
440
|
+
# No \IMAP commands are valid in the +logout+ state. If the socket is still
|
399
441
|
# open, Net::IMAP will close it after receiving server confirmation.
|
400
442
|
# Exceptions will be raised by \IMAP commands that have already started and
|
401
443
|
# are waiting for a response, as well as any that are called after logout.
|
@@ -449,7 +491,7 @@ module Net
|
|
449
491
|
# ==== RFC3691: +UNSELECT+
|
450
492
|
# Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
|
451
493
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
452
|
-
# - #unselect: Closes the mailbox and returns to the
|
494
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
453
495
|
# without expunging any messages.
|
454
496
|
#
|
455
497
|
# ==== RFC4314: +ACL+
|
@@ -719,7 +761,7 @@ module Net
|
|
719
761
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
720
762
|
#
|
721
763
|
class IMAP < Protocol
|
722
|
-
VERSION = "0.4.
|
764
|
+
VERSION = "0.4.20"
|
723
765
|
|
724
766
|
# Aliases for supported capabilities, to be used with the #enable command.
|
725
767
|
ENABLE_ALIASES = {
|
@@ -727,6 +769,7 @@ module Net
|
|
727
769
|
"UTF8=ONLY" => "UTF8=ACCEPT",
|
728
770
|
}.freeze
|
729
771
|
|
772
|
+
autoload :ResponseReader, File.expand_path("imap/response_reader", __dir__)
|
730
773
|
autoload :SASL, File.expand_path("imap/sasl", __dir__)
|
731
774
|
autoload :SASLAdapter, File.expand_path("imap/sasl_adapter", __dir__)
|
732
775
|
autoload :StringPrep, File.expand_path("imap/stringprep", __dir__)
|
@@ -741,9 +784,11 @@ module Net
|
|
741
784
|
def self.config; Config.global end
|
742
785
|
|
743
786
|
# Returns the global debug mode.
|
787
|
+
# Delegates to {Net::IMAP.config.debug}[rdoc-ref:Config#debug].
|
744
788
|
def self.debug; config.debug end
|
745
789
|
|
746
790
|
# Sets the global debug mode.
|
791
|
+
# Delegates to {Net::IMAP.config.debug=}[rdoc-ref:Config#debug=].
|
747
792
|
def self.debug=(val)
|
748
793
|
config.debug = val
|
749
794
|
end
|
@@ -764,7 +809,7 @@ module Net
|
|
764
809
|
alias default_ssl_port default_tls_port
|
765
810
|
end
|
766
811
|
|
767
|
-
# Returns the initial greeting the server, an UntaggedResponse.
|
812
|
+
# Returns the initial greeting sent by the server, an UntaggedResponse.
|
768
813
|
attr_reader :greeting
|
769
814
|
|
770
815
|
# The client configuration. See Net::IMAP::Config.
|
@@ -773,13 +818,28 @@ module Net
|
|
773
818
|
# Net::IMAP.config.
|
774
819
|
attr_reader :config
|
775
820
|
|
776
|
-
|
777
|
-
#
|
778
|
-
#
|
779
|
-
|
821
|
+
##
|
822
|
+
# :attr_reader: open_timeout
|
823
|
+
# Seconds to wait until a connection is opened. Also used by #starttls.
|
824
|
+
# Delegates to {config.open_timeout}[rdoc-ref:Config#open_timeout].
|
780
825
|
|
826
|
+
##
|
827
|
+
# :attr_reader: idle_response_timeout
|
781
828
|
# Seconds to wait until an IDLE response is received.
|
782
|
-
|
829
|
+
# Delegates to {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout].
|
830
|
+
|
831
|
+
##
|
832
|
+
# :attr_accessor: max_response_size
|
833
|
+
#
|
834
|
+
# The maximum allowed server response size, in bytes.
|
835
|
+
# Delegates to {config.max_response_size}[rdoc-ref:Config#max_response_size].
|
836
|
+
|
837
|
+
# :stopdoc:
|
838
|
+
def open_timeout; config.open_timeout end
|
839
|
+
def idle_response_timeout; config.idle_response_timeout end
|
840
|
+
def max_response_size; config.max_response_size end
|
841
|
+
def max_response_size=(val) config.max_response_size = val end
|
842
|
+
# :startdoc:
|
783
843
|
|
784
844
|
# The hostname this client connected to
|
785
845
|
attr_reader :host
|
@@ -835,6 +895,12 @@ module Net
|
|
835
895
|
#
|
836
896
|
# See DeprecatedClientOptions.new for deprecated SSL arguments.
|
837
897
|
#
|
898
|
+
# [response_handlers]
|
899
|
+
# A list of response handlers to be added before the receiver thread is
|
900
|
+
# started. This ensures every server response is handled, including the
|
901
|
+
# #greeting. Note that the greeting is handled in the current thread, but
|
902
|
+
# all other responses are handled in the receiver thread.
|
903
|
+
#
|
838
904
|
# [config]
|
839
905
|
# A Net::IMAP::Config object to use as the basis for #config. By default,
|
840
906
|
# the global Net::IMAP.config is used.
|
@@ -906,7 +972,7 @@ module Net
|
|
906
972
|
# [Net::IMAP::ByeResponseError]
|
907
973
|
# Connected to the host successfully, but it immediately said goodbye.
|
908
974
|
#
|
909
|
-
def initialize(host, port: nil, ssl:
|
975
|
+
def initialize(host, port: nil, ssl: nil, response_handlers: nil,
|
910
976
|
config: Config.global, **config_options)
|
911
977
|
super()
|
912
978
|
# Config options
|
@@ -929,6 +995,7 @@ module Net
|
|
929
995
|
@receiver_thread = nil
|
930
996
|
@receiver_thread_exception = nil
|
931
997
|
@receiver_thread_terminating = false
|
998
|
+
response_handlers&.each do add_response_handler(_1) end
|
932
999
|
|
933
1000
|
# Client Protocol Sender (including state for currently running commands)
|
934
1001
|
@tag_prefix = "RUBY"
|
@@ -944,6 +1011,7 @@ module Net
|
|
944
1011
|
# Connection
|
945
1012
|
@tls_verified = false
|
946
1013
|
@sock = tcp_socket(@host, @port)
|
1014
|
+
@reader = ResponseReader.new(self, @sock)
|
947
1015
|
start_tls_session if ssl_ctx
|
948
1016
|
start_imap_connection
|
949
1017
|
|
@@ -1204,6 +1272,10 @@ module Net
|
|
1204
1272
|
# both successful. Any error indicates that the connection has not been
|
1205
1273
|
# secured.
|
1206
1274
|
#
|
1275
|
+
# After the server agrees to start a TLS connection, this method waits up to
|
1276
|
+
# {config.open_timeout}[rdoc-ref:Config#open_timeout] before raising
|
1277
|
+
# +Net::OpenTimeout+.
|
1278
|
+
#
|
1207
1279
|
# *Note:*
|
1208
1280
|
# >>>
|
1209
1281
|
# Any #response_handlers added before STARTTLS should be aware that the
|
@@ -2706,6 +2778,10 @@ module Net
|
|
2706
2778
|
# end
|
2707
2779
|
# }
|
2708
2780
|
#
|
2781
|
+
# Response handlers can also be added when the client is created before the
|
2782
|
+
# receiver thread is started, by the +response_handlers+ argument to ::new.
|
2783
|
+
# This ensures every server response is handled, including the #greeting.
|
2784
|
+
#
|
2709
2785
|
# Related: #remove_response_handler, #response_handlers
|
2710
2786
|
def add_response_handler(handler = nil, &block)
|
2711
2787
|
raise ArgumentError, "two Procs are passed" if handler && block
|
@@ -2732,6 +2808,7 @@ module Net
|
|
2732
2808
|
def start_imap_connection
|
2733
2809
|
@greeting = get_server_greeting
|
2734
2810
|
@capabilities = capabilities_from_resp_code @greeting
|
2811
|
+
@response_handlers.each do |handler| handler.call(@greeting) end
|
2735
2812
|
@receiver_thread = start_receiver_thread
|
2736
2813
|
rescue Exception
|
2737
2814
|
@sock.close
|
@@ -2860,23 +2937,10 @@ module Net
|
|
2860
2937
|
end
|
2861
2938
|
|
2862
2939
|
def get_response
|
2863
|
-
buff =
|
2864
|
-
while true
|
2865
|
-
s = @sock.gets(CRLF)
|
2866
|
-
break unless s
|
2867
|
-
buff.concat(s)
|
2868
|
-
if /\{(\d+)\}\r\n/n =~ s
|
2869
|
-
s = @sock.read($1.to_i)
|
2870
|
-
buff.concat(s)
|
2871
|
-
else
|
2872
|
-
break
|
2873
|
-
end
|
2874
|
-
end
|
2940
|
+
buff = @reader.read_response_buffer
|
2875
2941
|
return nil if buff.length == 0
|
2876
|
-
if config.debug?
|
2877
|
-
|
2878
|
-
end
|
2879
|
-
return @parser.parse(buff)
|
2942
|
+
$stderr.print(buff.gsub(/^/n, "S: ")) if config.debug?
|
2943
|
+
@parser.parse(buff)
|
2880
2944
|
end
|
2881
2945
|
|
2882
2946
|
#############################
|
@@ -3077,6 +3141,7 @@ module Net
|
|
3077
3141
|
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
|
3078
3142
|
raise "cannot start TLS without SSLContext" unless ssl_ctx
|
3079
3143
|
@sock = SSLSocket.new(@sock, ssl_ctx)
|
3144
|
+
@reader = ResponseReader.new(self, @sock)
|
3080
3145
|
@sock.sync_close = true
|
3081
3146
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
3082
3147
|
ssl_socket_connect(@sock, open_timeout)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-imap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
- nicholas a. evans
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-protocol
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/net/imap/response_data.rb
|
69
69
|
- lib/net/imap/response_parser.rb
|
70
70
|
- lib/net/imap/response_parser/parser_utils.rb
|
71
|
+
- lib/net/imap/response_reader.rb
|
71
72
|
- lib/net/imap/sasl.rb
|
72
73
|
- lib/net/imap/sasl/anonymous_authenticator.rb
|
73
74
|
- lib/net/imap/sasl/authentication_exchange.rb
|
@@ -124,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
125
|
- !ruby/object:Gem::Version
|
125
126
|
version: '0'
|
126
127
|
requirements: []
|
127
|
-
rubygems_version: 3.6.
|
128
|
+
rubygems_version: 3.6.7
|
128
129
|
specification_version: 4
|
129
130
|
summary: Ruby client api for Internet Message Access Protocol
|
130
131
|
test_files: []
|