net-imap 0.5.1 → 0.5.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf511b8683c6931cf9ec2d3aa4a55ef634a2cc0e670590a4142d9895594b9191
4
- data.tar.gz: db4ca0b7230553258e0d81a8a5b5cbed4273e30245200db661145ba430af20d0
3
+ metadata.gz: ee48ac78f129043fd8ccb4f6e0b42535cc0ef3a6acd8ea1067cbd9b512815e49
4
+ data.tar.gz: 5bfae3bf0ee2e63c5b61c19d30187fe722adfe8018746e64d583124531de87a8
5
5
  SHA512:
6
- metadata.gz: b61a04c6992df7d6ffcf0e5396723966c3f3a5a1c6a596caf413c63d355100c8d2c28096a2261045d52ada4d8e995bba1c4f12864bf65fe1355c331df236eb85
7
- data.tar.gz: 0bc68ec15c5d53f0f437eab5318bf8cdd428dcdc650a98f66e961658ed361b125e866db2d41954e50ce66de5ec143d108e9135f554bd240ff0d7057724d16416
6
+ metadata.gz: f90a4500f3c218dd3a51cca84a76c620fa8f8488f2ca73486b538a43e67e21e0b897d23d957f490afe1590fd755c692f2e0dede562460ed2cfcd7f4d9bec3262
7
+ data.tar.gz: 22abb3cf5699bb715c33c69b596ead46ff400109925f58d633ecdc82797be9b80fbbd040c02aa7cd9286f3aa9c697e9fc426f1115b9019455b2ac4e6667cc236
data/Gemfile CHANGED
@@ -8,6 +8,7 @@ gem "digest"
8
8
  gem "strscan"
9
9
  gem "base64"
10
10
 
11
+ gem "irb"
11
12
  gem "rake"
12
13
  gem "rdoc"
13
14
  gem "test-unit"
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # Net::IMAP
2
2
 
3
3
  Net::IMAP implements Internet Message Access Protocol (IMAP) client
4
- functionality. The protocol is described in [IMAP](https://tools.ietf.org/html/rfc3501).
4
+ functionality. The protocol is described in
5
+ [RFC3501](https://www.rfc-editor.org/rfc/rfc3501),
6
+ [RFC9051](https://www.rfc-editor.org/rfc/rfc9051) and various extensions.
5
7
 
6
8
  ## Installation
7
9
 
@@ -50,12 +52,16 @@ end
50
52
 
51
53
  ```ruby
52
54
  imap.select('Mail/sent-mail')
53
- if not imap.list('Mail/', 'sent-apr03')
55
+ if imap.list('Mail/', 'sent-apr03').empty?
54
56
  imap.create('Mail/sent-apr03')
55
57
  end
56
58
  imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id|
57
- imap.copy(message_id, "Mail/sent-apr03")
58
- imap.store(message_id, "+FLAGS", [:Deleted])
59
+ if imap.capable?(:move) || imap.capable?(:IMAP4rev2)
60
+ imap.move(message_id, "Mail/sent-apr03")
61
+ else
62
+ imap.copy(message_id, "Mail/sent-apr03")
63
+ imap.store(message_id, "+FLAGS", [:Deleted])
64
+ end
59
65
  end
60
66
  imap.expunge
61
67
  ```
data/docs/styles.css CHANGED
@@ -1,24 +1,85 @@
1
1
  /* this is a work in progress. :) */
2
2
 
3
- main .method-header {
4
- background: rgba(27,31,35,0.05);
5
- border: 1px solid #6C8C22;
3
+ /***********************************************
4
+ * Method descriptions
5
+ ***********************************************/
6
+
7
+ main .method-detail {
8
+ display: grid;
9
+ grid-template-columns: 1fr auto;
10
+ justify-content: space-between;
11
+ }
12
+
13
+ main .method-header,
14
+ main .method-controls,
15
+ .attribute-method-heading {
6
16
  padding: 0.5em;
7
- border-radius: 4px;
8
- /* padding: 0 0.5em; */
9
- /* border-width: 0 1px; */
10
- /* border-color: #6C8C22; */
11
- /* border-style: solid; */
17
+ /* border: 1px solid var(--highlight-color); */
18
+ background: var(--table-header-background-color);
19
+ line-height: 1.6;
20
+ }
21
+
22
+ .attribute-method-heading .attribute-access-type {
23
+ float: right;
24
+ }
25
+
26
+ main .method-header {
27
+ border-right: none;
28
+ border-radius: 4px 0 0 4px;
29
+ }
30
+
31
+ main .method-heading :any-link {
32
+ text-decoration: none;
33
+ }
34
+
35
+ main .method-controls {
36
+ border-left: none;
37
+ border-radius: 0 4px 4px 0;
12
38
  }
13
39
 
14
40
  main .method-description, main .aliases {
41
+ grid-column: 1 / span 2;
15
42
  padding-left: 1em;
16
43
  }
17
44
 
18
- body {
19
- /*
20
- * The default (300) can be too low contrast. Also, many fonts don't
21
- * distinguish between 300->400, so <em>...</em> had no effect.
22
- */
23
- font-weight: 400;
45
+ @media (max-width: 700px) {
46
+ main .method-header, main .method-controls, main .method-description {
47
+ grid-column: 1 / span 2;
48
+ margin: 0;
49
+ }
50
+ main .method-controls {
51
+ background: none;
52
+ }
53
+ }
54
+
55
+ /***********************************************
56
+ * Description lists
57
+ ***********************************************/
58
+
59
+ main dt {
60
+ margin-bottom: 0; /* override rdoc 6.8 */
61
+ float: unset; /* override rdoc 6.8 */
62
+ line-height: 1.5; /* matches `main p` */
63
+ }
64
+
65
+ main dl.note-list dt {
66
+ margin-right: 1em;
67
+ float: left;
68
+ }
69
+
70
+ main dl.note-list dt:has(+ dt) {
71
+ margin-right: 0.25em;
72
+ }
73
+
74
+ main dl.note-list dt:has(+ dt)::after {
75
+ content: ', ';
76
+ font-weight: normal;
77
+ }
78
+
79
+ main dd {
80
+ margin: 0 0 1em 1em;
81
+ }
82
+
83
+ main dd p:first-child {
84
+ margin-top: 0;
24
85
  }
@@ -3,6 +3,7 @@
3
3
  require "date"
4
4
 
5
5
  require_relative "errors"
6
+ require_relative "data_lite"
6
7
 
7
8
  module Net
8
9
  class IMAP < Protocol
@@ -119,80 +120,85 @@ module Net
119
120
  put_string("\\" + symbol.to_s)
120
121
  end
121
122
 
122
- class RawData # :nodoc:
123
+ CommandData = Data.define(:data) do # :nodoc:
123
124
  def send_data(imap, tag)
124
- imap.__send__(:put_string, @data)
125
+ raise NoMethodError, "#{self.class} must implement #{__method__}"
125
126
  end
126
127
 
127
128
  def validate
128
129
  end
129
-
130
- private
131
-
132
- def initialize(data)
133
- @data = data
134
- end
135
130
  end
136
131
 
137
- class Atom # :nodoc:
132
+ class RawData < CommandData # :nodoc:
138
133
  def send_data(imap, tag)
139
- imap.__send__(:put_string, @data)
140
- end
141
-
142
- def validate
143
- end
144
-
145
- private
146
-
147
- def initialize(data)
148
- @data = data
134
+ imap.__send__(:put_string, data)
149
135
  end
150
136
  end
151
137
 
152
- class QuotedString # :nodoc:
138
+ class Atom < CommandData # :nodoc:
153
139
  def send_data(imap, tag)
154
- imap.__send__(:send_quoted_string, @data)
155
- end
156
-
157
- def validate
140
+ imap.__send__(:put_string, data)
158
141
  end
142
+ end
159
143
 
160
- private
161
-
162
- def initialize(data)
163
- @data = data
144
+ class QuotedString < CommandData # :nodoc:
145
+ def send_data(imap, tag)
146
+ imap.__send__(:send_quoted_string, data)
164
147
  end
165
148
  end
166
149
 
167
- class Literal # :nodoc:
150
+ class Literal < CommandData # :nodoc:
168
151
  def send_data(imap, tag)
169
- imap.__send__(:send_literal, @data, tag)
152
+ imap.__send__(:send_literal, data, tag)
170
153
  end
154
+ end
171
155
 
172
- def validate
156
+ class PartialRange < CommandData # :nodoc:
157
+ uint32_max = 2**32 - 1
158
+ POS_RANGE = 1..uint32_max
159
+ NEG_RANGE = -uint32_max..-1
160
+ Positive = ->{ (_1 in Range) and POS_RANGE.cover?(_1) }
161
+ Negative = ->{ (_1 in Range) and NEG_RANGE.cover?(_1) }
162
+
163
+ def initialize(data:)
164
+ min, max = case data
165
+ in Range
166
+ data.minmax.map { Integer _1 }
167
+ in ResponseParser::Patterns::PARTIAL_RANGE
168
+ data.split(":").map { Integer _1 }.minmax
169
+ else
170
+ raise ArgumentError, "invalid partial range input: %p" % [data]
171
+ end
172
+ data = min..max
173
+ unless data in Positive | Negative
174
+ raise ArgumentError, "invalid partial-range: %p" % [data]
175
+ end
176
+ super
177
+ rescue TypeError, RangeError
178
+ raise ArgumentError, "expected range min/max to be Integers"
173
179
  end
174
180
 
175
- private
181
+ def formatted = "%d:%d" % data.minmax
176
182
 
177
- def initialize(data)
178
- @data = data
183
+ def send_data(imap, tag)
184
+ imap.__send__(:put_string, formatted)
179
185
  end
180
186
  end
181
187
 
182
188
  # *DEPRECATED*. Replaced by SequenceSet.
183
- class MessageSet # :nodoc:
189
+ class MessageSet < CommandData # :nodoc:
184
190
  def send_data(imap, tag)
185
- imap.__send__(:put_string, format_internal(@data))
191
+ imap.__send__(:put_string, format_internal(data))
186
192
  end
187
193
 
188
194
  def validate
189
- validate_internal(@data)
195
+ validate_internal(data)
190
196
  end
191
197
 
192
198
  private
193
199
 
194
- def initialize(data)
195
- @data = data
200
+ def initialize(data:)
201
+ super
196
202
  warn("DEPRECATED: #{MessageSet} should be replaced with #{SequenceSet}.",
197
203
  uplevel: 1, category: :deprecated)
198
204
  begin
@@ -246,22 +252,18 @@ module Net
246
252
  end
247
253
  end
248
254
 
249
- class ClientID # :nodoc:
255
+ class ClientID < CommandData # :nodoc:
250
256
 
251
257
  def send_data(imap, tag)
252
- imap.__send__(:send_data, format_internal(@data), tag)
258
+ imap.__send__(:send_data, format_internal(data), tag)
253
259
  end
254
260
 
255
261
  def validate
256
- validate_internal(@data)
262
+ validate_internal(data)
257
263
  end
258
264
 
259
265
  private
260
266
 
261
- def initialize(data)
262
- @data = data
263
- end
264
-
265
267
  def validate_internal(client_id)
266
268
  client_id.to_h.each do |k,v|
267
269
  unless StringFormatter.valid_string?(k)
@@ -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
21
23
  end
22
24
  private_constant :Macros
23
25
 
@@ -26,34 +28,29 @@ module Net
26
28
  end
27
29
  private_class_method :included
28
30
 
29
- def self.attr_accessor(attr, type: nil)
30
- return unless type
31
- if :boolean == type then boolean attr
32
- elsif Integer == type then integer attr
33
- elsif Array === type then enum attr, type
34
- else raise ArgumentError, "unknown type coercion %p" % [type]
35
- end
36
- end
31
+ def self.safe(...) = Ractor.make_shareable nil.instance_eval(...).freeze
32
+ private_class_method :safe
37
33
 
38
- def self.boolean(attr)
39
- define_method :"#{attr}=" do |val| super !!val end
40
- define_method :"#{attr}?" do send attr end
41
- end
34
+ Types = Hash.new do |h, type| type => Proc | nil; safe{type} end
35
+ Types[:boolean] = Boolean = safe{-> {!!_1}}
36
+ Types[Integer] = safe{->{Integer(_1)}}
42
37
 
43
- def self.integer(attr)
44
- define_method :"#{attr}=" do |val| super Integer val end
38
+ def self.attr_accessor(attr, type: nil)
39
+ type = Types[type] or return
40
+ define_method :"#{attr}=" do |val| super type[val] end
41
+ define_method :"#{attr}?" do send attr end if type == Boolean
45
42
  end
46
43
 
47
- def self.enum(attr, enum)
48
- enum = enum.dup.freeze
44
+ NilOrInteger = safe{->val { Integer val unless val.nil? }}
45
+
46
+ Enum = ->(*enum) {
47
+ enum = safe{enum}
49
48
  expected = -"one of #{enum.map(&:inspect).join(", ")}"
50
- define_method :"#{attr}=" do |val|
51
- unless enum.include?(val)
52
- raise ArgumentError, "expected %s, got %p" % [expected, val]
53
- end
54
- super val
55
- end
56
- end
49
+ safe{->val {
50
+ return val if enum.include?(val)
51
+ raise ArgumentError, "expected %s, got %p" % [expected, val]
52
+ }}
53
+ }
57
54
 
58
55
  end
59
56
  end
@@ -75,7 +75,7 @@ module Net
75
75
  #
76
76
  # client = Net::IMAP.new(hostname, config: :future)
77
77
  # client.config.sasl_ir # => true
78
- # client.config.responses_without_block # => :raise
78
+ # client.config.responses_without_block # => :frozen_dup
79
79
  #
80
80
  # The versioned default configs inherit certain specific config options from
81
81
  # Config.global, for example #debug:
@@ -109,9 +109,11 @@ module Net
109
109
  # [+:future+]
110
110
  # The _planned_ eventual config for some future +x.y+ version.
111
111
  #
112
- # For example, to raise exceptions for all current deprecations:
112
+ # For example, to disable all currently deprecated behavior:
113
113
  # client = Net::IMAP.new(hostname, config: :future)
114
- # client.responses # raises an ArgumentError
114
+ # client.config.response_without_args # => :frozen_dup
115
+ # client.responses.frozen? # => true
116
+ # client.responses.values.all?(&:frozen?) # => true
115
117
  #
116
118
  # == Thread Safety
117
119
  #
@@ -129,8 +131,25 @@ module Net
129
131
  def self.global; @global if defined?(@global) end
130
132
 
131
133
  # A hash of hard-coded configurations, indexed by version number or name.
134
+ # Values can be accessed with any object that responds to +to_sym+ or
135
+ # +to_r+/+to_f+ with a non-zero number.
136
+ #
137
+ # Config::[] gets named or numbered versions from this hash.
138
+ #
139
+ # For example:
140
+ # Net::IMAP::Config.version_defaults[0.5] == Net::IMAP::Config[0.5]
141
+ # Net::IMAP::Config[0.5] == Net::IMAP::Config[0.5r] # => true
142
+ # Net::IMAP::Config["current"] == Net::IMAP::Config[:current] # => true
143
+ # Net::IMAP::Config["0.5.6"] == Net::IMAP::Config[0.5r] # => true
132
144
  def self.version_defaults; @version_defaults end
133
- @version_defaults = {}
145
+ @version_defaults = Hash.new {|h, k|
146
+ # NOTE: String responds to both so the order is significant.
147
+ # And ignore non-numeric conversion to zero, because: "wat!?".to_r == 0
148
+ (h.fetch(k.to_r, nil) || h.fetch(k.to_f, nil) if k.is_a?(Numeric)) ||
149
+ (h.fetch(k.to_sym, nil) if k.respond_to?(:to_sym)) ||
150
+ (h.fetch(k.to_r, nil) if k.respond_to?(:to_r) && k.to_r != 0r) ||
151
+ (h.fetch(k.to_f, nil) if k.respond_to?(:to_f) && k.to_f != 0.0)
152
+ }
134
153
 
135
154
  # :call-seq:
136
155
  # Net::IMAP::Config[number] -> versioned config
@@ -153,18 +172,17 @@ module Net
153
172
  elsif config.nil? && global.nil? then nil
154
173
  elsif config.respond_to?(:to_hash) then new(global, **config).freeze
155
174
  else
156
- version_defaults.fetch(config) do
175
+ version_defaults[config] or
157
176
  case config
158
177
  when Numeric
159
178
  raise RangeError, "unknown config version: %p" % [config]
160
- when Symbol
179
+ when String, Symbol
161
180
  raise KeyError, "unknown config name: %p" % [config]
162
181
  else
163
182
  raise TypeError, "no implicit conversion of %s to %s" % [
164
183
  config.class, Config
165
184
  ]
166
185
  end
167
- end
168
186
  end
169
187
  end
170
188
 
@@ -191,10 +209,13 @@ module Net
191
209
 
192
210
  # Seconds to wait until a connection is opened.
193
211
  #
212
+ # Applied separately for establishing TCP connection and starting a TLS
213
+ # connection.
214
+ #
194
215
  # If the IMAP object cannot open a connection within this time,
195
216
  # it raises a Net::OpenTimeout exception.
196
217
  #
197
- # See Net::IMAP.new.
218
+ # See Net::IMAP.new and Net::IMAP#starttls.
198
219
  #
199
220
  # The default value is +30+ seconds.
200
221
  attr_accessor :open_timeout, type: Integer
@@ -243,10 +264,44 @@ module Net
243
264
  # present. When capabilities are unknown, Net::IMAP will automatically
244
265
  # send a +CAPABILITY+ command first before sending +LOGIN+.
245
266
  #
246
- attr_accessor :enforce_logindisabled, type: [
267
+ attr_accessor :enforce_logindisabled, type: Enum[
247
268
  false, :when_capabilities_cached, true
248
269
  ]
249
270
 
271
+ # The maximum allowed server response size. When +nil+, there is no limit
272
+ # on response size.
273
+ #
274
+ # The default value (512 MiB, since +v0.5.7+) is <em>very high</em> and
275
+ # unlikely to be reached. A _much_ lower value should be used with
276
+ # untrusted servers (for example, when connecting to a user-provided
277
+ # hostname). When using a lower limit, message bodies should be fetched
278
+ # in chunks rather than all at once.
279
+ #
280
+ # <em>Please Note:</em> this only limits the size per response. It does
281
+ # not prevent a flood of individual responses and it does not limit how
282
+ # many unhandled responses may be stored on the responses hash. See
283
+ # Net::IMAP@Unbounded+memory+use.
284
+ #
285
+ # Socket reads are limited to the maximum remaining bytes for the current
286
+ # response: max_response_size minus the bytes that have already been read.
287
+ # When the limit is reached, or reading a +literal+ _would_ go over the
288
+ # limit, ResponseTooLargeError is raised and the connection is closed.
289
+ #
290
+ # Note that changes will not take effect immediately, because the receiver
291
+ # thread may already be waiting for the next response using the previous
292
+ # value. Net::IMAP#noop can force a response and enforce the new setting
293
+ # immediately.
294
+ #
295
+ # ==== Versioned Defaults
296
+ #
297
+ # Net::IMAP#max_response_size <em>was added in +v0.2.5+ and +v0.3.9+ as an
298
+ # attr_accessor, and in +v0.4.20+ and +v0.5.7+ as a delegator to this
299
+ # config attribute.</em>
300
+ #
301
+ # * original: +nil+ <em>(no limit)</em>
302
+ # * +0.5+: 512 MiB
303
+ attr_accessor :max_response_size, type: Integer?
304
+
250
305
  # Controls the behavior of Net::IMAP#responses when called without any
251
306
  # arguments (+type+ or +block+).
252
307
  #
@@ -273,7 +328,7 @@ module Net
273
328
  # Raise an ArgumentError with the deprecation warning.
274
329
  #
275
330
  # Note: #responses_without_args is an alias for #responses_without_block.
276
- attr_accessor :responses_without_block, type: [
331
+ attr_accessor :responses_without_block, type: Enum[
277
332
  :silence_deprecation_warning, :warn, :frozen_dup, :raise,
278
333
  ]
279
334
 
@@ -285,6 +340,67 @@ module Net
285
340
  #
286
341
  # Alias for responses_without_block
287
342
 
343
+ # Whether ResponseParser should use the deprecated UIDPlusData or
344
+ # CopyUIDData for +COPYUID+ response codes, and UIDPlusData or
345
+ # AppendUIDData for +APPENDUID+ response codes.
346
+ #
347
+ # UIDPlusData stores its data in arrays of numbers, which is vulnerable to
348
+ # a memory exhaustion denial of service attack from an untrusted or
349
+ # compromised server. Set this option to +false+ to completely block this
350
+ # vulnerability. Otherwise, parser_max_deprecated_uidplus_data_size
351
+ # mitigates this vulnerability.
352
+ #
353
+ # AppendUIDData and CopyUIDData are _mostly_ backward-compatible with
354
+ # UIDPlusData. Most applications should be able to upgrade with little
355
+ # or no changes.
356
+ #
357
+ # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
358
+ #
359
+ # <em>(Config option added in +v0.4.19+ and +v0.5.6+.)</em>
360
+ #
361
+ # <em>UIDPlusData will be removed in +v0.6+ and this config setting will
362
+ # be ignored.</em>
363
+ #
364
+ # ==== Valid options
365
+ #
366
+ # [+true+ <em>(original default)</em>]
367
+ # ResponseParser only uses UIDPlusData.
368
+ #
369
+ # [+:up_to_max_size+ <em>(default since +v0.5.6+)</em>]
370
+ # ResponseParser uses UIDPlusData when the +uid-set+ size is below
371
+ # parser_max_deprecated_uidplus_data_size. Above that size,
372
+ # ResponseParser uses AppendUIDData or CopyUIDData.
373
+ #
374
+ # [+false+ <em>(planned default for +v0.6+)</em>]
375
+ # ResponseParser _only_ uses AppendUIDData and CopyUIDData.
376
+ attr_accessor :parser_use_deprecated_uidplus_data, type: Enum[
377
+ true, :up_to_max_size, false
378
+ ]
379
+
380
+ # The maximum +uid-set+ size that ResponseParser will parse into
381
+ # deprecated UIDPlusData. This limit only applies when
382
+ # parser_use_deprecated_uidplus_data is not +false+.
383
+ #
384
+ # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
385
+ #
386
+ # <em>Support for limiting UIDPlusData to a maximum size was added in
387
+ # +v0.3.8+, +v0.4.19+, and +v0.5.6+.</em>
388
+ #
389
+ # <em>UIDPlusData will be removed in +v0.6+.</em>
390
+ #
391
+ # ==== Versioned Defaults
392
+ #
393
+ # Because this limit guards against a remote server causing catastrophic
394
+ # memory exhaustion, the versioned default (used by #load_defaults) also
395
+ # applies to versions without the feature.
396
+ #
397
+ # * +0.3+ and prior: <tt>10,000</tt>
398
+ # * +0.4+: <tt>1,000</tt>
399
+ # * +0.5+: <tt>100</tt>
400
+ # * +0.6+: <tt>0</tt>
401
+ #
402
+ attr_accessor :parser_max_deprecated_uidplus_data_size, type: Integer
403
+
288
404
  # Creates a new config object and initialize its attribute with +attrs+.
289
405
  #
290
406
  # If +parent+ is not given, the global config is used by default.
@@ -364,37 +480,73 @@ module Net
364
480
  idle_response_timeout: 5,
365
481
  sasl_ir: true,
366
482
  enforce_logindisabled: true,
483
+ max_response_size: 512 << 20, # 512 MiB
367
484
  responses_without_block: :warn,
485
+ parser_use_deprecated_uidplus_data: :up_to_max_size,
486
+ parser_max_deprecated_uidplus_data_size: 100,
368
487
  ).freeze
369
488
 
370
489
  @global = default.new
371
490
 
372
491
  version_defaults[:default] = Config[default.send(:defaults_hash)]
373
- version_defaults[:current] = Config[:default]
374
492
 
375
- version_defaults[0] = Config[:current].dup.update(
493
+ version_defaults[0r] = Config[:default].dup.update(
376
494
  sasl_ir: false,
377
495
  responses_without_block: :silence_deprecation_warning,
378
496
  enforce_logindisabled: false,
497
+ max_response_size: nil,
498
+ parser_use_deprecated_uidplus_data: true,
499
+ parser_max_deprecated_uidplus_data_size: 10_000,
379
500
  ).freeze
380
- version_defaults[0.0] = Config[0]
381
- version_defaults[0.1] = Config[0]
382
- version_defaults[0.2] = Config[0]
383
- version_defaults[0.3] = Config[0]
501
+ version_defaults[0.0r] = Config[0r]
502
+ version_defaults[0.1r] = Config[0r]
503
+ version_defaults[0.2r] = Config[0r]
504
+ version_defaults[0.3r] = Config[0r]
384
505
 
385
- version_defaults[0.4] = Config[0.3].dup.update(
506
+ version_defaults[0.4r] = Config[0.3r].dup.update(
386
507
  sasl_ir: true,
508
+ parser_max_deprecated_uidplus_data_size: 1000,
387
509
  ).freeze
388
510
 
389
- version_defaults[0.5] = Config[:current]
511
+ version_defaults[0.5r] = Config[0.4r].dup.update(
512
+ enforce_logindisabled: true,
513
+ max_response_size: 512 << 20, # 512 MiB
514
+ responses_without_block: :warn,
515
+ parser_use_deprecated_uidplus_data: :up_to_max_size,
516
+ parser_max_deprecated_uidplus_data_size: 100,
517
+ ).freeze
390
518
 
391
- version_defaults[0.6] = Config[0.5].dup.update(
519
+ version_defaults[0.6r] = Config[0.5r].dup.update(
392
520
  responses_without_block: :frozen_dup,
521
+ parser_use_deprecated_uidplus_data: false,
522
+ parser_max_deprecated_uidplus_data_size: 0,
393
523
  ).freeze
394
- version_defaults[:next] = Config[0.6]
395
- version_defaults[:future] = Config[:next]
524
+
525
+ version_defaults[0.7r] = Config[0.6r].dup.update(
526
+ ).freeze
527
+
528
+ # Safe conversions one way only:
529
+ # 0.6r.to_f == 0.6 # => true
530
+ # 0.6 .to_r == 0.6r # => false
531
+ version_defaults.to_a.each do |k, v|
532
+ next unless k in Rational
533
+ version_defaults[k.to_f] = v
534
+ end
535
+
536
+ current = VERSION.to_r
537
+ version_defaults[:original] = Config[0]
538
+ version_defaults[:current] = Config[current]
539
+ version_defaults[:next] = Config[current + 0.1r]
540
+ version_defaults[:future] = Config[current + 0.2r]
396
541
 
397
542
  version_defaults.freeze
543
+
544
+ if ($VERBOSE || $DEBUG) && self[:current].to_h != self[:default].to_h
545
+ warn "Misconfigured Net::IMAP::Config[:current] => %p,\n" \
546
+ " not equal to Net::IMAP::Config[:default] => %p" % [
547
+ self[:current].to_h, self[:default].to_h
548
+ ]
549
+ end
398
550
  end
399
551
  end
400
552
  end