net-imap 0.5.15 → 0.6.0

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.
@@ -234,13 +234,26 @@ module Net
234
234
  # Do not use +SASL-IR+, even when it is supported by the server and the
235
235
  # mechanism.
236
236
  #
237
+ # [+:when_capabilities_cached+]
238
+ # Use +SASL-IR+ when Net::IMAP#capabilities_cached? is +true+ and it is
239
+ # supported by the server and the mechanism, but do not send a
240
+ # +CAPABILITY+ command to discover the server capabilities.
241
+ #
242
+ # <em>(+:when_capabilities_cached+ option was added by +v0.6.0+)</em>
243
+ #
237
244
  # [+true+ <em>(default since +v0.4+)</em>]
238
245
  # Use +SASL-IR+ when it is supported by the server and the mechanism.
239
- attr_accessor :sasl_ir, type: :boolean, defaults: {
246
+ attr_accessor :sasl_ir, type: Enum[
247
+ false, :when_capabilities_cached, true
248
+ ], defaults: {
240
249
  0.0r => false,
241
250
  0.4r => true,
242
251
  }
243
252
 
253
+ # :stopdoc:
254
+ alias sasl_ir? sasl_ir
255
+ # :startdoc:
256
+
244
257
  # Controls the behavior of Net::IMAP#login when the +LOGINDISABLED+
245
258
  # capability is present. When enforced, Net::IMAP will raise a
246
259
  # LoginDisabledError when that capability is present.
@@ -347,39 +360,32 @@ module Net
347
360
  #
348
361
  # Alias for responses_without_block
349
362
 
350
- # Whether ResponseParser should use the deprecated UIDPlusData or
351
- # CopyUIDData for +COPYUID+ response codes, and UIDPlusData or
352
- # AppendUIDData for +APPENDUID+ response codes.
363
+ # **NOTE:** <em>+UIDPlusData+ has been removed since +v0.6.0+, and this
364
+ # config option only affects deprecation warnings.
365
+ # This config option will be **removed** in +v0.7.0+.</em>
353
366
  #
354
- # UIDPlusData stores its data in arrays of numbers, which is vulnerable to
355
- # a memory exhaustion denial of service attack from an untrusted or
356
- # compromised server. Set this option to +false+ to completely block this
357
- # vulnerability. Otherwise, parser_max_deprecated_uidplus_data_size
358
- # mitigates this vulnerability.
367
+ # ResponseParser always returns CopyUIDData for +COPYUID+ response codes,
368
+ # and AppendUIDData for +APPENDUID+ response codes. Previously, this
369
+ # option determined when UIDPlusData would be returned instead.
359
370
  #
360
- # AppendUIDData and CopyUIDData are _mostly_ backward-compatible with
361
- # UIDPlusData. Most applications should be able to upgrade with little
362
- # or no changes.
371
+ # Parser support for +UIDPLUS+ added in +v0.3.2+.
363
372
  #
364
- # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
373
+ # Config option added in +v0.4.19+ and +v0.5.6+.
365
374
  #
366
- # <em>(Config option added in +v0.4.19+ and +v0.5.6+.)</em>
375
+ # <em>UIDPlusData removed in +v0.6.0+.</em>
367
376
  #
368
- # <em>UIDPlusData will be removed in +v0.6+ and this config setting will
369
- # be ignored.</em>
370
- #
371
- # ==== Valid options
377
+ # ==== Options
372
378
  #
373
379
  # [+true+ <em>(original default)</em>]
374
- # ResponseParser only uses UIDPlusData.
380
+ # <em>Since v0.6.0:</em>
381
+ # Prints a deprecation warning when parsing +COPYUID+ or +APPENDUID+.
375
382
  #
376
383
  # [+:up_to_max_size+ <em>(default since +v0.5.6+)</em>]
377
- # ResponseParser uses UIDPlusData when the +uid-set+ size is below
378
- # parser_max_deprecated_uidplus_data_size. Above that size,
379
- # ResponseParser uses AppendUIDData or CopyUIDData.
384
+ # <em>Since v0.6.0:</em>
385
+ # Prints a deprecation warning when parsing +COPYUID+ or +APPENDUID+.
380
386
  #
381
- # [+false+ <em>(planned default for +v0.6+)</em>]
382
- # ResponseParser _only_ uses AppendUIDData and CopyUIDData.
387
+ # [+false+ <em>(default since +v0.6.0+)</em>]
388
+ # This is the only supported option <em>(since v0.6.0)</em>.
383
389
  attr_accessor :parser_use_deprecated_uidplus_data, type: Enum[
384
390
  true, :up_to_max_size, false
385
391
  ], defaults: {
@@ -388,22 +394,22 @@ module Net
388
394
  0.6r => false,
389
395
  }
390
396
 
391
- # The maximum +uid-set+ size that ResponseParser will parse into
392
- # deprecated UIDPlusData. This limit only applies when
393
- # parser_use_deprecated_uidplus_data is not +false+.
397
+ # **NOTE:** <em>+UIDPlusData+ has been removed since +v0.6.0+, and this
398
+ # config option is ignored.
399
+ # This config option will be **removed** in +v0.7.0+.</em>
394
400
  #
395
- # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
401
+ # ResponseParser always returns CopyUIDData for +COPYUID+ response codes,
402
+ # and AppendUIDData for +APPENDUID+ response codes. Previously, this
403
+ # option determined when UIDPlusData would be returned instead.
396
404
  #
397
- # <em>Support for limiting UIDPlusData to a maximum size was added in
398
- # +v0.3.8+, +v0.4.19+, and +v0.5.6+.</em>
405
+ # Parser support for +UIDPLUS+ added in +v0.3.2+.
399
406
  #
400
- # <em>UIDPlusData will be removed in +v0.6+.</em>
407
+ # Support for limiting UIDPlusData to a maximum size was added in
408
+ # +v0.3.8+, +v0.4.19+, and +v0.5.6+.
401
409
  #
402
- # ==== Versioned Defaults
410
+ # <em>UIDPlusData was removed in +v0.6.0+.</em>
403
411
  #
404
- # Because this limit guards against a remote server causing catastrophic
405
- # memory exhaustion, the versioned default (used by #load_defaults) also
406
- # applies to versions without the feature.
412
+ # ==== Versioned Defaults
407
413
  #
408
414
  # * +0.3+ and prior: <tt>10,000</tt>
409
415
  # * +0.4+: <tt>1,000</tt>
@@ -485,8 +491,142 @@ module Net
485
491
  # Returns all config attributes in a hash.
486
492
  def to_h; data.members.to_h { [_1, send(_1)] } end
487
493
 
494
+ # Returns a string representation of overriden config attributes and the
495
+ # inheritance chain.
496
+ #
497
+ # Attributes overridden by ancestors are also inspected, recursively.
498
+ # Attributes that are inherited from default configs are not shown (see
499
+ # Config@Versioned+defaults and Config@Named+defaults).
500
+ #
501
+ # # (Line breaks have been added to the example output for legibility.)
502
+ #
503
+ # Net::IMAP::Config.new(0.4)
504
+ # .new(open_timeout: 10, enforce_logindisabled: true)
505
+ # .inspect
506
+ # #=> "#<Net::IMAP::Config:0x0000745871125410 open_timeout=10 enforce_logindisabled=true
507
+ # # inherits from Net::IMAP::Config[0.4]
508
+ # # inherits from Net::IMAP::Config.global
509
+ # # inherits from Net::IMAP::Config.default>"
510
+ #
511
+ # Non-default attributes are listed after the ancestor config from which
512
+ # they are inherited.
513
+ #
514
+ # # (Line breaks have been added to the example output for legibility.)
515
+ #
516
+ # config = Net::IMAP::Config.global
517
+ # .new(open_timeout: 10, idle_response_timeout: 2)
518
+ # .new(enforce_logindisabled: :when_capabilities_cached, sasl_ir: false)
519
+ # config.inspect
520
+ # #=> "#<Net::IMAP::Config:0x00007ce2a1e20e40 sasl_ir=false enforce_logindisabled=:when_capabilities_cached
521
+ # # inherits from Net::IMAP::Config:0x00007ce2a1e20f80 open_timeout=10 idle_response_timeout=2
522
+ # # inherits from Net::IMAP::Config.global
523
+ # # inherits from Net::IMAP::Config.default>"
524
+ #
525
+ # Net::IMAP.debug = true
526
+ # config.inspect
527
+ # #=> "#<Net::IMAP::Config:0x00007ce2a1e20e40 sasl_ir=false enforce_logindisabled=:when_capabilities_cached
528
+ # # inherits from Net::IMAP::Config:0x00007ce2a1e20f80 open_timeout=10 idle_response_timeout=2
529
+ # # inherits from Net::IMAP::Config.global debug=true
530
+ # # inherits from Net::IMAP::Config.default>"
531
+ #
532
+ # Use +pp+ (see #pretty_print) to inspect _all_ config attributes,
533
+ # including default values.
534
+ #
535
+ # Use #to_h to inspect all config attributes ignoring inheritance.
536
+ def inspect;
537
+ "#<#{inspect_recursive}>"
538
+ end
539
+ alias to_s inspect
540
+
541
+ # Used by PP[https://docs.ruby-lang.org/en/master/PP.html] to create a
542
+ # string representation of all config attributes and the inheritance
543
+ # chain. Inherited attributes are listed with the ancestor config from
544
+ # which they are inherited.
545
+ #
546
+ # pp Config.new[0.4].new(open_timeout: 10, idle_response_timeout: 10)
547
+ # # #<Net::IMAP::Config:0x0000745871125410
548
+ # # open_timeout=10
549
+ # # idle_response_timeout=10
550
+ # # inherits from Net::IMAP::Config[0.4]
551
+ # # responses_without_block=:silence_deprecation_warning
552
+ # # max_response_size=nil
553
+ # # sasl_ir=true
554
+ # # enforce_logindisabled=false
555
+ # # parser_use_deprecated_uidplus_data=true
556
+ # # parser_max_deprecated_uidplus_data_size=1000
557
+ # # inherits from Net::IMAP::Config.global
558
+ # # inherits from Net::IMAP::Config.default
559
+ # # debug=false>
560
+ #
561
+ # Related: #inspect, #to_h.
562
+ def pretty_print(pp)
563
+ pp.group(2, "#<", ">") do
564
+ pretty_print_recursive(pp)
565
+ end
566
+ end
567
+
568
+ # :stopdoc:
569
+
488
570
  protected
489
571
 
572
+ def named_default?
573
+ equal?(Config.default) ||
574
+ AttrVersionDefaults::VERSIONS.any? { equal? Config[_1] }
575
+ end
576
+
577
+ def name
578
+ if equal? Config.default then "#{Config}.default"
579
+ elsif equal? Config.global then "#{Config}.global"
580
+ elsif equal? Config[0.0r] then "#{Config}[:original]"
581
+ elsif equal? Config[:default] then "#{Config}[:default]"
582
+ elsif (v = AttrVersionDefaults::VERSIONS.find { equal? Config[_1] })
583
+ "%s[%0.1f]" % [Config, v]
584
+ else
585
+ Kernel.instance_method(:to_s).bind_call(self).delete("<#>")
586
+ end
587
+ end
588
+
589
+ def inspect_recursive(attrs = AttrAccessors.struct.members)
590
+ strings = [name]
591
+ assigned = assigned_attrs_hash(attrs)
592
+ strings.concat assigned.map { "%s=%p" % _1 }
593
+ if parent
594
+ if parent.equal?(Config.default)
595
+ inherited_overrides = []
596
+ elsif parent
597
+ inherited_overrides = attrs - assigned.keys
598
+ inherited_overrides &= DEFAULT_TO_INHERIT if parent.named_default?
599
+ end
600
+ strings << "inherits from #{parent.inspect_recursive(inherited_overrides)}"
601
+ end
602
+ strings.join " "
603
+ end
604
+
605
+ def pretty_print_recursive(pp, attrs = AttrAccessors.struct.members)
606
+ pp.text name
607
+ assigned = assigned_attrs_hash(attrs)
608
+ pp.breakable
609
+ pp.seplist(assigned, ->{pp.breakable}) do |key, val|
610
+ pp.text key.to_s
611
+ pp.text "="
612
+ pp.pp val
613
+ end
614
+ if parent
615
+ pp.breakable if assigned.any?
616
+ pp.nest(2) do
617
+ pp.text "inherits from "
618
+ parent.pretty_print_recursive(pp, attrs - assigned.keys)
619
+ end
620
+ elsif assigned.empty?
621
+ pp.text "(overridden)"
622
+ end
623
+ end
624
+
625
+ def assigned_attrs_hash(attrs)
626
+ own_attrs = attrs.reject { inherited?(_1) }
627
+ own_attrs.to_h { [_1, data[_1]] }
628
+ end
629
+
490
630
  def defaults_hash
491
631
  to_h.reject {|k,v| DEFAULT_TO_INHERIT.include?(k) }
492
632
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Net
4
4
  class IMAP
5
- class ConnectionState < Net::IMAP::Data # :nodoc:
5
+ class ConnectionState < Data # :nodoc:
6
6
  def self.define(symbol, *attrs)
7
7
  symbol => Symbol
8
8
  state = super(*attrs)
@@ -155,57 +155,106 @@ module Net
155
155
 
156
156
  # Common validators of number and nz_number types
157
157
  module NumValidator # :nodoc
158
+ NUMBER_RE = /\A(?:0|[1-9]\d*)\z/
158
159
  module_function
159
160
 
160
- # Check is passed argument valid 'number' in RFC 3501 terminology
161
+ # Check if argument is a valid 'number' according to RFC 3501
162
+ # number = 1*DIGIT
163
+ # ; Unsigned 32-bit integer
164
+ # ; (0 <= n < 4,294,967,296)
161
165
  def valid_number?(num)
162
- # [RFC 3501]
163
- # number = 1*DIGIT
164
- # ; Unsigned 32-bit integer
165
- # ; (0 <= n < 4,294,967,296)
166
- num >= 0 && num < 4294967296
166
+ 0 <= num && num <= 0xffff_ffff
167
167
  end
168
168
 
169
- # Check is passed argument valid 'nz_number' in RFC 3501 terminology
169
+ # Check if argument is a valid 'nz-number' according to RFC 3501
170
+ # nz-number = digit-nz *DIGIT
171
+ # ; Non-zero unsigned 32-bit integer
172
+ # ; (0 < n < 4,294,967,296)
170
173
  def valid_nz_number?(num)
171
- # [RFC 3501]
172
- # nz-number = digit-nz *DIGIT
173
- # ; Non-zero unsigned 32-bit integer
174
- # ; (0 < n < 4,294,967,296)
175
- num != 0 && valid_number?(num)
174
+ 0 < num && num <= 0xffff_ffff
176
175
  end
177
176
 
178
- # Check is passed argument valid 'mod_sequence_value' in RFC 4551 terminology
177
+ # Check if argument is a valid 'mod-sequence-value' according to RFC 4551
178
+ # mod-sequence-value = 1*DIGIT
179
+ # ; Positive unsigned 64-bit integer
180
+ # ; (mod-sequence)
181
+ # ; (1 <= n < 18,446,744,073,709,551,615)
179
182
  def valid_mod_sequence_value?(num)
180
- # mod-sequence-value = 1*DIGIT
181
- # ; Positive unsigned 64-bit integer
182
- # ; (mod-sequence)
183
- # ; (1 <= n < 18,446,744,073,709,551,615)
184
- num >= 1 && num < 18446744073709551615
183
+ 1 <= num && num < 0xffff_ffff_ffff_ffff
184
+ end
185
+
186
+ # Check if argument is a valid 'mod-sequence-valzer' according to RFC 4551
187
+ # mod-sequence-valzer = "0" / mod-sequence-value
188
+ def valid_mod_sequence_valzer?(num)
189
+ 0 <= num && num < 0xffff_ffff_ffff_ffff
185
190
  end
186
191
 
187
192
  # Ensure argument is 'number' or raise DataFormatError
188
193
  def ensure_number(num)
189
194
  return num if valid_number?(num)
190
-
191
- msg = "number must be unsigned 32-bit integer: #{num}"
192
- raise DataFormatError, msg
195
+ raise DataFormatError,
196
+ "number must be unsigned 32-bit integer: #{num}"
193
197
  end
194
198
 
195
- # Ensure argument is 'nz_number' or raise DataFormatError
199
+ # Ensure argument is 'nz-number' or raise DataFormatError
196
200
  def ensure_nz_number(num)
197
201
  return num if valid_nz_number?(num)
198
-
199
- msg = "nz_number must be non-zero unsigned 32-bit integer: #{num}"
200
- raise DataFormatError, msg
202
+ raise DataFormatError,
203
+ "nz-number must be non-zero unsigned 32-bit integer: #{num}"
201
204
  end
202
205
 
203
- # Ensure argument is 'mod_sequence_value' or raise DataFormatError
206
+ # Ensure argument is 'mod-sequence-value' or raise DataFormatError
204
207
  def ensure_mod_sequence_value(num)
205
208
  return num if valid_mod_sequence_value?(num)
209
+ raise DataFormatError,
210
+ "mod-sequence-value must be non-zero unsigned 64-bit integer: #{num}"
211
+ end
212
+
213
+ # Ensure argument is 'mod-sequence-valzer' or raise DataFormatError
214
+ def ensure_mod_sequence_valzer(num)
215
+ return num if valid_mod_sequence_valzer?(num)
216
+ raise DataFormatError,
217
+ "mod-sequence-valzer must be unsigned 64-bit integer: #{num}"
218
+ end
219
+
220
+ # Like #ensure_number, but usable with numeric String input.
221
+ def coerce_number(num)
222
+ case num
223
+ when Integer then ensure_number num
224
+ when NUMBER_RE then ensure_number Integer num
225
+ else
226
+ raise DataFormatError, "%p is not a valid number" % [num]
227
+ end
228
+ end
206
229
 
207
- msg = "mod_sequence_value must be unsigned 64-bit integer: #{num}"
208
- raise DataFormatError, msg
230
+ # Like #ensure_nz_number, but usable with numeric String input.
231
+ def coerce_nz_number(num)
232
+ case num
233
+ when Integer then ensure_nz_number num
234
+ when NUMBER_RE then ensure_nz_number Integer num
235
+ else
236
+ raise DataFormatError, "%p is not a valid nz-number" % [num]
237
+ end
238
+ end
239
+
240
+ # Like #ensure_mod_sequence_value, but usable with numeric String input.
241
+ def coerce_mod_sequence_value(num)
242
+ case num
243
+ when Integer then ensure_mod_sequence_value num
244
+ when NUMBER_RE then ensure_mod_sequence_value Integer num
245
+ else
246
+ raise DataFormatError, "%p is not a valid mod-sequence-value" % [num]
247
+ end
248
+ end
249
+
250
+ # Like #ensure_mod_sequence_valzer, but usable with numeric String input.
251
+ def coerce_mod_sequence_valzer(num)
252
+ case num
253
+ when Integer then ensure_mod_sequence_valzer num
254
+ when NUMBER_RE then ensure_mod_sequence_valzer Integer num
255
+ else
256
+ raise DataFormatError, "%p is not a valid mod-sequence-valzer" % [num]
257
+ end
209
258
  end
210
259
 
211
260
  end
@@ -25,6 +25,12 @@ module Net
25
25
  # Some search extensions may result in the server sending ESearchResult
26
26
  # responses after the initiating command has completed. Use
27
27
  # IMAP#add_response_handler to handle these responses.
28
+ #
29
+ # ==== Compatibility with SearchResult
30
+ #
31
+ # Note that both SearchResult and ESearchResult implement +each+, +to_a+,
32
+ # and +to_sequence_set+. These methods can be used regardless of whether
33
+ # the server returns +SEARCH+ or +ESEARCH+ data (or no data).
28
34
  class ESearchResult < Data.define(:tag, :uid, :data)
29
35
  def initialize(tag: nil, uid: nil, data: nil)
30
36
  tag => String | nil; tag = -tag if tag
@@ -6,7 +6,6 @@ module Net
6
6
  autoload :FetchData, "#{__dir__}/fetch_data"
7
7
  autoload :UIDFetchData, "#{__dir__}/fetch_data"
8
8
  autoload :SearchResult, "#{__dir__}/search_result"
9
- autoload :UIDPlusData, "#{__dir__}/uidplus_data"
10
9
  autoload :AppendUIDData, "#{__dir__}/uidplus_data"
11
10
  autoload :CopyUIDData, "#{__dir__}/uidplus_data"
12
11
  autoload :VanishedData, "#{__dir__}/vanished_data"
@@ -260,8 +259,8 @@ module Net
260
259
  #
261
260
  # === +UIDPLUS+ extension
262
261
  # See {[RFC4315 §3]}[https://www.rfc-editor.org/rfc/rfc4315#section-3].
263
- # * +APPENDUID+, #data is UIDPlusData. See IMAP#append.
264
- # * +COPYUID+, #data is UIDPlusData. See IMAP#copy.
262
+ # * +APPENDUID+, #data is AppendUIDData. See IMAP#append.
263
+ # * +COPYUID+, #data is CopyUIDData. See IMAP#copy.
265
264
  # * +UIDNOTSTICKY+, #data is +nil+. See IMAP#select.
266
265
  #
267
266
  # === +SEARCHRES+ extension
@@ -307,14 +306,6 @@ module Net
307
306
  # because the server doesn't allow deletion of mailboxes with children.
308
307
  # #data is +nil+.
309
308
  #
310
- # === <tt>QUOTA=RES-*</tt> response codes
311
- # See {[RFC9208]}[https://www.rfc-editor.org/rfc/rfc9208.html#section-4.3].
312
- # * +OVERQUOTA+ (also in RFC5530[https://www.rfc-editor.org/rfc/rfc5530]),
313
- # with a tagged +NO+ response to an +APPEND+/+COPY+/+MOVE+ command when
314
- # the command would put the target mailbox over any quota, and with an
315
- # untagged +NO+ when a mailbox exceeds a soft quota (which may be caused
316
- # be external events). #data is +nil+.
317
- #
318
309
  # === +CONDSTORE+ extension
319
310
  # See {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
320
311
  # * +NOMODSEQ+, when selecting a mailbox that does not support
@@ -392,23 +383,14 @@ module Net
392
383
  # and MailboxQuota objects.
393
384
  #
394
385
  # == Required capability
395
- #
396
386
  # Requires +QUOTA+ [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]]
397
- # or <tt>QUOTA=RES-STORAGE</tt>
398
- # [RFC9208[https://www.rfc-editor.org/rfc/rfc9208]] capability.
387
+ # capability.
399
388
  class MailboxQuota < Struct.new(:mailbox, :usage, :quota)
400
389
  ##
401
390
  # method: mailbox
402
391
  # :call-seq: mailbox -> string
403
392
  #
404
- # The quota root with the associated quota.
405
- #
406
- # NOTE: this was mistakenly named "mailbox". But the quota root's name may
407
- # differ from the mailbox. A single quota root may cover multiple
408
- # mailboxes, and a single mailbox may be governed by multiple quota roots.
409
-
410
- # The quota root with the associated quota.
411
- alias quota_root mailbox
393
+ # The mailbox with the associated quota.
412
394
 
413
395
  ##
414
396
  # method: usage
@@ -420,7 +402,7 @@ module Net
420
402
  # method: quota
421
403
  # :call-seq: quota -> Integer
422
404
  #
423
- # Storage limit imposed on the mailbox.
405
+ # Quota limit imposed on the mailbox.
424
406
  #
425
407
  end
426
408
 
@@ -2017,24 +2017,19 @@ module Net
2017
2017
  CopyUID(validity, src_uids, dst_uids)
2018
2018
  end
2019
2019
 
2020
- def AppendUID(...) DeprecatedUIDPlus(...) || AppendUIDData.new(...) end
2021
- def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end
2022
-
2023
2020
  # TODO: remove this code in the v0.6.0 release
2024
2021
  def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids)
2025
2022
  return unless config.parser_use_deprecated_uidplus_data
2026
- compact_uid_sets = [src_uids, dst_uids].compact
2027
- count = compact_uid_sets.map { _1.count_with_duplicates }.max
2028
- max = config.parser_max_deprecated_uidplus_data_size
2029
- if count <= max
2030
- src_uids &&= src_uids.each_ordered_number.to_a
2031
- dst_uids = dst_uids.each_ordered_number.to_a
2032
- UIDPlusData.new(validity, src_uids, dst_uids)
2033
- elsif config.parser_use_deprecated_uidplus_data != :up_to_max_size
2034
- parse_error("uid-set is too large: %d > %d", count, max)
2035
- end
2023
+ warn("#{Config}#parser_use_deprecated_uidplus_data is ignored " \
2024
+ "since v0.6.0. Disable this warning by setting " \
2025
+ "config.parser_use_deprecated_uidplus_data = false.",
2026
+ category: :deprecated, uplevel: 9)
2027
+ nil
2036
2028
  end
2037
2029
 
2030
+ def AppendUID(...) DeprecatedUIDPlus(...) || AppendUIDData.new(...) end
2031
+ def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end
2032
+
2038
2033
  ADDRESS_REGEXP = /\G
2039
2034
  \( (?: NIL | #{Patterns::QUOTED_rev2} ) # 1: NAME
2040
2035
  \s (?: NIL | #{Patterns::QUOTED_rev2} ) # 2: ROUTE
@@ -2189,7 +2184,10 @@ module Net
2189
2184
  if $1
2190
2185
  return Token.new(T_SPACE, $+)
2191
2186
  elsif $2
2192
- literal_token($+, T_LITERAL8)
2187
+ len = $+.to_i
2188
+ val = @str[@pos, len]
2189
+ @pos += len
2190
+ return Token.new(T_LITERAL8, val)
2193
2191
  elsif $3 && $7
2194
2192
  # greedily match ATOM, prefixed with NUMBER, NIL, or PLUS.
2195
2193
  return Token.new(T_ATOM, $3)
@@ -2217,7 +2215,10 @@ module Net
2217
2215
  elsif $15
2218
2216
  return Token.new(T_RBRA, $+)
2219
2217
  elsif $16
2220
- literal_token($+)
2218
+ len = $+.to_i
2219
+ val = @str[@pos, len]
2220
+ @pos += len
2221
+ return Token.new(T_LITERAL, val)
2221
2222
  elsif $17
2222
2223
  return Token.new(T_PERCENT, $+)
2223
2224
  elsif $18
@@ -2243,7 +2244,10 @@ module Net
2243
2244
  elsif $4
2244
2245
  return Token.new(T_QUOTED, Patterns.unescape_quoted($+))
2245
2246
  elsif $5
2246
- literal_token($+)
2247
+ len = $+.to_i
2248
+ val = @str[@pos, len]
2249
+ @pos += len
2250
+ return Token.new(T_LITERAL, val)
2247
2251
  elsif $6
2248
2252
  return Token.new(T_LPAR, $+)
2249
2253
  elsif $7
@@ -2258,23 +2262,6 @@ module Net
2258
2262
  else
2259
2263
  parse_error("invalid @lex_state - %s", @lex_state.inspect)
2260
2264
  end
2261
- rescue DataFormatError => error
2262
- parse_error error.message
2263
- end
2264
-
2265
- def literal_token(len, type = T_LITERAL)
2266
- len = coerce_number64 len.to_i
2267
- val = @str[@pos, len]
2268
- @pos += len
2269
- Token.new(type, val)
2270
- end
2271
-
2272
- # copied/adapted from NumValidator in v0.6
2273
- def coerce_number64(num)
2274
- int = num.to_i
2275
- return int if 0 <= int && int <= 0x7fff_ffff_ffff_ffff
2276
- raise DataFormatError,
2277
- "number64 must be unsigned 63-bit integer: #{num}"
2278
2265
  end
2279
2266
 
2280
2267
  end
@@ -4,13 +4,10 @@ module Net
4
4
  class IMAP
5
5
  # See https://www.rfc-editor.org/rfc/rfc9051#section-2.2.2
6
6
  class ResponseReader # :nodoc:
7
- include NumValidator
8
-
9
7
  attr_reader :client
10
8
 
11
9
  def initialize(client, sock)
12
10
  @client, @sock = client, sock
13
- @buff = @literal_size = nil
14
11
  end
15
12
 
16
13
  def read_response_buffer
@@ -18,13 +15,13 @@ module Net
18
15
  catch :eof do
19
16
  while true
20
17
  read_line
21
- break unless literal_size
18
+ break unless (@literal_size = get_literal_size)
22
19
  read_literal
23
20
  end
24
21
  end
25
22
  buff
26
23
  ensure
27
- @buff = @literal_size = nil
24
+ @buff = nil
28
25
  end
29
26
 
30
27
  private
@@ -33,21 +30,13 @@ module Net
33
30
 
34
31
  def bytes_read = buff.bytesize
35
32
  def empty? = buff.empty?
36
- def done? = line_done? && !literal_size
33
+ def done? = line_done? && !get_literal_size
37
34
  def line_done? = buff.end_with?(CRLF)
38
-
39
- def get_literal_size(buff)
40
- buff.end_with?("}\r\n") && buff.rindex(/\{(\d+)\}\r\n\z/n) &&
41
- coerce_number64($1)
42
- rescue DataFormatError
43
- raise DataFormatError, format("invalid response literal size (%s)", $1)
44
- end
35
+ def get_literal_size = /\{(\d+)\}\r\n\z/n =~ buff && $1.to_i
45
36
 
46
37
  def read_line
47
- line = (@sock.gets(CRLF, read_limit) or throw :eof)
48
- buff << line
38
+ buff << (@sock.gets(CRLF, read_limit) or throw :eof)
49
39
  max_response_remaining! unless line_done?
50
- @literal_size = get_literal_size(line)
51
40
  end
52
41
 
53
42
  def read_literal
@@ -79,14 +68,6 @@ module Net
79
68
  )
80
69
  end
81
70
 
82
- # copied/adapted from NumValidator in v0.6
83
- def coerce_number64(num)
84
- int = num.to_i
85
- return int if 0 <= int && int <= 0x7fff_ffff_ffff_ffff
86
- raise DataFormatError,
87
- "number64 must be unsigned 63-bit integer: #{num}"
88
- end
89
-
90
71
  end
91
72
  end
92
73
  end