net-imap 0.4.19 → 0.5.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.

Potentially problematic release.


This version of net-imap might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d13d2ec5aeab6f5fce9d77841e77c690a2849d2d6393d4bac0847fcec6dcf2b
4
- data.tar.gz: 2821ba41ca70465fdfc38005908ae2fa2828ecd5c3425bf407df27f2e949ea2b
3
+ metadata.gz: 2c89d97e842bce303df112c3fbc0f048f20a2ff1dbf3b85bb2314ea0d2e207c5
4
+ data.tar.gz: 11d6ec196e1e768f61a17b0ce7f385a11eb03e3e92af8ab327ba9a90699ee940
5
5
  SHA512:
6
- metadata.gz: 45bb4a741d80d2097e487b3d1ca31196f97322d6104967c6cad6410d65321e372667a6ff5bbb5bf9aafbdddc7906c7fc05b88c2fff06984dc9efd8a309802ecc
7
- data.tar.gz: '08acdba3fdc323f01bc593ac7fde03ed5e06f1265be821263213fd53714b647e81305713d6829b67adba55dfb541a231e8c0a2303ad83e3efada4088e10c8419'
6
+ metadata.gz: ca70e20c3c70f4ca57822f70936546adb3129dd7c0771ef2d054b0356ed4f6a994b7453803cc06bd25ebb37dc0ed10f60b5541bc56749dee38a6126264344599
7
+ data.tar.gz: 2921a79dbdab7bd0476d883c18db50150388d587c711270faac99ad4505574a23e6532fe61a4fb48f51c8bddea6641d96f81d9dcbe245b4d4f4542fcc7418566
data/Gemfile CHANGED
@@ -13,4 +13,10 @@ gem "rdoc"
13
13
  gem "test-unit"
14
14
  gem "test-unit-ruby-core", git: "https://github.com/ruby/test-unit-ruby-core"
15
15
 
16
- gem "benchmark-driver"
16
+ gem "benchmark-driver", require: false
17
+
18
+ group :test do
19
+ gem "simplecov", require: false
20
+ gem "simplecov-html", require: false
21
+ gem "simplecov-json", require: false
22
+ end
@@ -9,7 +9,7 @@ module Net::IMAP::Authenticators
9
9
  "%s.%s is deprecated. Use %s.%s instead." % [
10
10
  Net::IMAP, __method__, Net::IMAP::SASL, __method__
11
11
  ],
12
- uplevel: 1
12
+ uplevel: 1, category: :deprecated
13
13
  )
14
14
  Net::IMAP::SASL.add_authenticator(...)
15
15
  end
@@ -20,7 +20,7 @@ module Net::IMAP::Authenticators
20
20
  "%s.%s is deprecated. Use %s.%s instead." % [
21
21
  Net::IMAP, __method__, Net::IMAP::SASL, __method__
22
22
  ],
23
- uplevel: 1
23
+ uplevel: 1, category: :deprecated
24
24
  )
25
25
  Net::IMAP::SASL.authenticator(...)
26
26
  end
@@ -179,6 +179,7 @@ module Net
179
179
  end
180
180
  end
181
181
 
182
+ # *DEPRECATED*. Replaced by SequenceSet.
182
183
  class MessageSet # :nodoc:
183
184
  def send_data(imap, tag)
184
185
  imap.__send__(:put_string, format_internal(@data))
@@ -192,6 +193,16 @@ module Net
192
193
 
193
194
  def initialize(data)
194
195
  @data = data
196
+ warn("DEPRECATED: #{MessageSet} should be replaced with #{SequenceSet}.",
197
+ uplevel: 1, category: :deprecated)
198
+ begin
199
+ # to ensure the input works with SequenceSet, too
200
+ SequenceSet.new(data)
201
+ rescue
202
+ warn "MessageSet input is incompatible with SequenceSet: [%s] %s" % [
203
+ $!.class, $!.message
204
+ ]
205
+ end
195
206
  end
196
207
 
197
208
  def format_internal(data)
@@ -223,6 +223,29 @@ module Net
223
223
  # Use +SASL-IR+ when it is supported by the server and the mechanism.
224
224
  attr_accessor :sasl_ir, type: :boolean
225
225
 
226
+ # Controls the behavior of Net::IMAP#login when the +LOGINDISABLED+
227
+ # capability is present. When enforced, Net::IMAP will raise a
228
+ # LoginDisabledError when that capability is present.
229
+ #
230
+ # <em>(Support for +LOGINDISABLED+ was added in +v0.5.0+.)</em>
231
+ #
232
+ # ==== Valid options
233
+ #
234
+ # [+false+ <em>(original behavior, before support was added)</em>]
235
+ # Send the +LOGIN+ command without checking for +LOGINDISABLED+.
236
+ #
237
+ # [+:when_capabilities_cached+]
238
+ # Enforce the requirement when Net::IMAP#capabilities_cached? is true,
239
+ # but do not send a +CAPABILITY+ command to discover the capabilities.
240
+ #
241
+ # [+true+ <em>(default since +v0.5+)</em>]
242
+ # Only send the +LOGIN+ command if the +LOGINDISABLED+ capability is not
243
+ # present. When capabilities are unknown, Net::IMAP will automatically
244
+ # send a +CAPABILITY+ command first before sending +LOGIN+.
245
+ #
246
+ attr_accessor :enforce_logindisabled, type: [
247
+ false, :when_capabilities_cached, true
248
+ ]
226
249
 
227
250
  # Controls the behavior of Net::IMAP#responses when called without any
228
251
  # arguments (+type+ or +block+).
@@ -262,67 +285,6 @@ module Net
262
285
  #
263
286
  # Alias for responses_without_block
264
287
 
265
- # Whether ResponseParser should use the deprecated UIDPlusData or
266
- # CopyUIDData for +COPYUID+ response codes, and UIDPlusData or
267
- # AppendUIDData for +APPENDUID+ response codes.
268
- #
269
- # UIDPlusData stores its data in arrays of numbers, which is vulnerable to
270
- # a memory exhaustion denial of service attack from an untrusted or
271
- # compromised server. Set this option to +false+ to completely block this
272
- # vulnerability. Otherwise, parser_max_deprecated_uidplus_data_size
273
- # mitigates this vulnerability.
274
- #
275
- # AppendUIDData and CopyUIDData are _mostly_ backward-compatible with
276
- # UIDPlusData. Most applications should be able to upgrade with little
277
- # or no changes.
278
- #
279
- # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
280
- #
281
- # <em>(Config option added in +v0.4.19+ and +v0.5.6+.)</em>
282
- #
283
- # <em>UIDPlusData will be removed in +v0.6+ and this config setting will
284
- # be ignored.</em>
285
- #
286
- # ==== Valid options
287
- #
288
- # [+true+ <em>(original default)</em>]
289
- # ResponseParser only uses UIDPlusData.
290
- #
291
- # [+:up_to_max_size+ <em>(default since +v0.5.6+)</em>]
292
- # ResponseParser uses UIDPlusData when the +uid-set+ size is below
293
- # parser_max_deprecated_uidplus_data_size. Above that size,
294
- # ResponseParser uses AppendUIDData or CopyUIDData.
295
- #
296
- # [+false+ <em>(planned default for +v0.6+)</em>]
297
- # ResponseParser _only_ uses AppendUIDData and CopyUIDData.
298
- attr_accessor :parser_use_deprecated_uidplus_data, type: [
299
- true, :up_to_max_size, false
300
- ]
301
-
302
- # The maximum +uid-set+ size that ResponseParser will parse into
303
- # deprecated UIDPlusData. This limit only applies when
304
- # parser_use_deprecated_uidplus_data is not +false+.
305
- #
306
- # <em>(Parser support for +UIDPLUS+ added in +v0.3.2+.)</em>
307
- #
308
- # <em>Support for limiting UIDPlusData to a maximum size was added in
309
- # +v0.3.8+, +v0.4.19+, and +v0.5.6+.</em>
310
- #
311
- # <em>UIDPlusData will be removed in +v0.6+.</em>
312
- #
313
- # ==== Versioned Defaults
314
- #
315
- # Because this limit guards against a remote server causing catastrophic
316
- # memory exhaustion, the versioned default (used by #load_defaults) also
317
- # applies to versions without the feature.
318
- #
319
- # * +0.3+ and prior: <tt>10,000</tt>
320
- # * +0.4+: <tt>1,000</tt>
321
- # * +0.5+: <tt>100</tt>
322
- # * +0.6+: <tt>0</tt>
323
- #
324
- attr_accessor :parser_max_deprecated_uidplus_data_size, type: Integer
325
-
326
288
  # Creates a new config object and initialize its attribute with +attrs+.
327
289
  #
328
290
  # If +parent+ is not given, the global config is used by default.
@@ -401,41 +363,36 @@ module Net
401
363
  open_timeout: 30,
402
364
  idle_response_timeout: 5,
403
365
  sasl_ir: true,
404
- responses_without_block: :silence_deprecation_warning,
405
- parser_use_deprecated_uidplus_data: true,
406
- parser_max_deprecated_uidplus_data_size: 1000,
366
+ enforce_logindisabled: true,
367
+ responses_without_block: :warn,
407
368
  ).freeze
408
369
 
409
370
  @global = default.new
410
371
 
411
- version_defaults[0.4] = Config[default.send(:defaults_hash)]
372
+ version_defaults[:default] = Config[default.send(:defaults_hash)]
373
+ version_defaults[:current] = Config[:default]
412
374
 
413
- version_defaults[0] = Config[0.4].dup.update(
375
+ version_defaults[0] = Config[:current].dup.update(
414
376
  sasl_ir: false,
415
- parser_use_deprecated_uidplus_data: true,
416
- parser_max_deprecated_uidplus_data_size: 10_000,
377
+ responses_without_block: :silence_deprecation_warning,
378
+ enforce_logindisabled: false,
417
379
  ).freeze
418
380
  version_defaults[0.0] = Config[0]
419
381
  version_defaults[0.1] = Config[0]
420
382
  version_defaults[0.2] = Config[0]
421
383
  version_defaults[0.3] = Config[0]
422
384
 
423
- version_defaults[0.5] = Config[0.4].dup.update(
424
- responses_without_block: :warn,
425
- parser_use_deprecated_uidplus_data: :up_to_max_size,
426
- parser_max_deprecated_uidplus_data_size: 100,
385
+ version_defaults[0.4] = Config[0.3].dup.update(
386
+ sasl_ir: true,
427
387
  ).freeze
428
388
 
429
- version_defaults[:default] = Config[0.4]
430
- version_defaults[:current] = Config[0.4]
431
- version_defaults[:next] = Config[0.5]
389
+ version_defaults[0.5] = Config[:current]
432
390
 
433
- version_defaults[0.6] = Config[0.5].dup.update(
391
+ version_defaults[0.6] = Config[0.5].dup.update(
434
392
  responses_without_block: :frozen_dup,
435
- parser_use_deprecated_uidplus_data: false,
436
- parser_max_deprecated_uidplus_data_size: 0,
437
393
  ).freeze
438
- version_defaults[:future] = Config[0.6]
394
+ version_defaults[:next] = Config[0.6]
395
+ version_defaults[:future] = Config[:next]
439
396
 
440
397
  version_defaults.freeze
441
398
  end
@@ -186,7 +186,7 @@ module Net
186
186
 
187
187
  # Ensure argument is 'number' or raise DataFormatError
188
188
  def ensure_number(num)
189
- return if valid_number?(num)
189
+ return num if valid_number?(num)
190
190
 
191
191
  msg = "number must be unsigned 32-bit integer: #{num}"
192
192
  raise DataFormatError, msg
@@ -194,7 +194,7 @@ module Net
194
194
 
195
195
  # Ensure argument is 'nz_number' or raise DataFormatError
196
196
  def ensure_nz_number(num)
197
- return if valid_nz_number?(num)
197
+ return num if valid_nz_number?(num)
198
198
 
199
199
  msg = "nz_number must be non-zero unsigned 32-bit integer: #{num}"
200
200
  raise DataFormatError, msg
@@ -202,7 +202,7 @@ module Net
202
202
 
203
203
  # Ensure argument is 'mod_sequence_value' or raise DataFormatError
204
204
  def ensure_mod_sequence_value(num)
205
- return if valid_mod_sequence_value?(num)
205
+ return num if valid_mod_sequence_value?(num)
206
206
 
207
207
  msg = "mod_sequence_value must be unsigned 64-bit integer: #{num}"
208
208
  raise DataFormatError, msg
@@ -83,10 +83,12 @@ module Net
83
83
  elsif deprecated.empty?
84
84
  super host, port: port_or_options
85
85
  elsif deprecated.shift
86
- warn "DEPRECATED: Call Net::IMAP.new with keyword options", uplevel: 1
86
+ warn("DEPRECATED: Call Net::IMAP.new with keyword options",
87
+ uplevel: 1, category: :deprecated)
87
88
  super host, port: port_or_options, ssl: create_ssl_params(*deprecated)
88
89
  else
89
- warn "DEPRECATED: Call Net::IMAP.new with keyword options", uplevel: 1
90
+ warn("DEPRECATED: Call Net::IMAP.new with keyword options",
91
+ uplevel: 1, category: :deprecated)
90
92
  super host, port: port_or_options, ssl: false
91
93
  end
92
94
  end
@@ -113,7 +115,8 @@ module Net
113
115
  elsif deprecated.first.respond_to?(:to_hash)
114
116
  super(**Hash.try_convert(deprecated.first))
115
117
  else
116
- warn "DEPRECATED: Call Net::IMAP#starttls with keyword options", uplevel: 1
118
+ warn("DEPRECATED: Call Net::IMAP#starttls with keyword options",
119
+ uplevel: 1, category: :deprecated)
117
120
  super(**create_ssl_params(*deprecated))
118
121
  end
119
122
  end
@@ -7,6 +7,12 @@ module Net
7
7
  class Error < StandardError
8
8
  end
9
9
 
10
+ class LoginDisabledError < Error
11
+ def initialize(msg = "Remote server has disabled the LOGIN command", ...)
12
+ super
13
+ end
14
+ end
15
+
10
16
  # Error raised when data is in the incorrect format.
11
17
  class DataFormatError < Error
12
18
  end
@@ -5,9 +5,6 @@ module Net
5
5
  autoload :FetchData, "#{__dir__}/fetch_data"
6
6
  autoload :SearchResult, "#{__dir__}/search_result"
7
7
  autoload :SequenceSet, "#{__dir__}/sequence_set"
8
- autoload :UIDPlusData, "#{__dir__}/uidplus_data"
9
- autoload :AppendUIDData, "#{__dir__}/uidplus_data"
10
- autoload :CopyUIDData, "#{__dir__}/uidplus_data"
11
8
 
12
9
  # Net::IMAP::ContinuationRequest represents command continuation requests.
13
10
  #
@@ -327,6 +324,60 @@ module Net
327
324
  # code data can take.
328
325
  end
329
326
 
327
+ # Net::IMAP::UIDPlusData represents the ResponseCode#data that accompanies
328
+ # the +APPENDUID+ and +COPYUID+ response codes.
329
+ #
330
+ # See [[UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]].
331
+ #
332
+ # ==== Capability requirement
333
+ #
334
+ # The +UIDPLUS+ capability[rdoc-ref:Net::IMAP#capability] must be supported.
335
+ # A server that supports +UIDPLUS+ should send a UIDPlusData object inside
336
+ # every TaggedResponse returned by the append[rdoc-ref:Net::IMAP#append],
337
+ # copy[rdoc-ref:Net::IMAP#copy], move[rdoc-ref:Net::IMAP#move], {uid
338
+ # copy}[rdoc-ref:Net::IMAP#uid_copy], and {uid
339
+ # move}[rdoc-ref:Net::IMAP#uid_move] commands---unless the destination
340
+ # mailbox reports +UIDNOTSTICKY+.
341
+ #
342
+ #--
343
+ # TODO: support MULTIAPPEND
344
+ #++
345
+ #
346
+ class UIDPlusData < Struct.new(:uidvalidity, :source_uids, :assigned_uids)
347
+ ##
348
+ # method: uidvalidity
349
+ # :call-seq: uidvalidity -> nonzero uint32
350
+ #
351
+ # The UIDVALIDITY of the destination mailbox.
352
+
353
+ ##
354
+ # method: source_uids
355
+ # :call-seq: source_uids -> nil or an array of nonzero uint32
356
+ #
357
+ # The UIDs of the copied or moved messages.
358
+ #
359
+ # Note:: Returns +nil+ for Net::IMAP#append.
360
+
361
+ ##
362
+ # method: assigned_uids
363
+ # :call-seq: assigned_uids -> an array of nonzero uint32
364
+ #
365
+ # The newly assigned UIDs of the copied, moved, or appended messages.
366
+ #
367
+ # Note:: This always returns an array, even when it contains only one UID.
368
+
369
+ ##
370
+ # :call-seq: uid_mapping -> nil or a hash
371
+ #
372
+ # Returns a hash mapping each source UID to the newly assigned destination
373
+ # UID.
374
+ #
375
+ # Note:: Returns +nil+ for Net::IMAP#append.
376
+ def uid_mapping
377
+ source_uids&.zip(assigned_uids)&.to_h
378
+ end
379
+ end
380
+
330
381
  # Net::IMAP::MailboxList represents contents of the LIST response,
331
382
  # representing a single mailbox path.
332
383
  #
@@ -888,7 +939,8 @@ module Net
888
939
  # for something else?
889
940
  #++
890
941
  def media_subtype
891
- warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
942
+ warn("media_subtype is obsolete, use subtype instead.\n",
943
+ uplevel: 1, category: :deprecated)
892
944
  return subtype
893
945
  end
894
946
  end
@@ -933,7 +985,8 @@ module Net
933
985
  # generate a warning message to +stderr+, then return
934
986
  # the value of +subtype+.
935
987
  def media_subtype
936
- warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
988
+ warn("media_subtype is obsolete, use subtype instead.\n",
989
+ uplevel: 1, category: :deprecated)
937
990
  return subtype
938
991
  end
939
992
  end
@@ -989,77 +1042,6 @@ module Net
989
1042
  end
990
1043
  end
991
1044
 
992
- # BodyTypeAttachment is not used and will be removed in an upcoming release.
993
- #
994
- # === Bug Analysis
995
- #
996
- # \IMAP body structures are parenthesized lists and assign their fields
997
- # positionally, so missing fields change the interpretation of all
998
- # following fields. Additionally, different body types have a different
999
- # number of required fields, followed by optional "extension" fields.
1000
- #
1001
- # BodyTypeAttachment was previously returned when a "message/rfc822" part,
1002
- # which should be sent as <tt>body-type-msg</tt> with ten required fields,
1003
- # was actually sent as a <tt>body-type-basic</tt> with _seven_ required
1004
- # fields.
1005
- #
1006
- # basic => type, subtype, param, id, desc, enc, octets, md5=nil, dsp=nil, lang=nil, loc=nil, *ext
1007
- # msg => type, subtype, param, id, desc, enc, octets, envelope, body, lines, md5=nil, ...
1008
- #
1009
- # Normally, +envelope+ and +md5+ are incompatible, but Net::IMAP leniently
1010
- # allowed buggy servers to send +NIL+ for +envelope+. As a result, when a
1011
- # server sent a <tt>message/rfc822</tt> part with +NIL+ for +md5+ and a
1012
- # non-<tt>NIL</tt> +dsp+, Net::IMAP misinterpreted the
1013
- # <tt>Content-Disposition</tt> as if it were a strange body type. In all
1014
- # reported cases, the <tt>Content-Disposition</tt> was "attachment", so
1015
- # BodyTypeAttachment was created as the workaround.
1016
- #
1017
- # === Current behavior
1018
- #
1019
- # When interpreted strictly, +envelope+ and +md5+ are incompatible. So the
1020
- # current parsing algorithm peeks ahead after it has received the seventh
1021
- # body field. If the next token is not the start of an +envelope+, we assume
1022
- # the server has incorrectly sent us a <tt>body-type-basic</tt> and return
1023
- # BodyTypeBasic. As a result, what was previously BodyTypeMessage#body =>
1024
- # BodyTypeAttachment is now BodyTypeBasic#disposition => ContentDisposition.
1025
- #
1026
- class BodyTypeAttachment < Struct.new(:dsp_type, :_unused_, :param)
1027
- # *invalid for BodyTypeAttachment*
1028
- def media_type
1029
- warn(<<~WARN, uplevel: 1)
1030
- BodyTypeAttachment#media_type is obsolete. Use dsp_type instead.
1031
- WARN
1032
- dsp_type
1033
- end
1034
-
1035
- # *invalid for BodyTypeAttachment*
1036
- def subtype
1037
- warn("BodyTypeAttachment#subtype is obsolete.\n", uplevel: 1)
1038
- nil
1039
- end
1040
-
1041
- ##
1042
- # method: dsp_type
1043
- # :call-seq: dsp_type -> string
1044
- #
1045
- # Returns the content disposition type, as defined by
1046
- # [DISPOSITION[https://tools.ietf.org/html/rfc2183]].
1047
-
1048
- ##
1049
- # method: param
1050
- # :call-seq: param -> hash
1051
- #
1052
- # Returns a hash representing parameters of the Content-Disposition
1053
- # field, as defined by [DISPOSITION[https://tools.ietf.org/html/rfc2183]].
1054
-
1055
- ##
1056
- def multipart?
1057
- return false
1058
- end
1059
- end
1060
-
1061
- deprecate_constant :BodyTypeAttachment
1062
-
1063
1045
  # Net::IMAP::BodyTypeMultipart represents body structures of messages and
1064
1046
  # message parts, when <tt>Content-Type</tt> is <tt>multipart/*</tt>.
1065
1047
  class BodyTypeMultipart < Struct.new(:media_type, :subtype,
@@ -1131,29 +1113,11 @@ module Net
1131
1113
  # generate a warning message to +stderr+, then return
1132
1114
  # the value of +subtype+.
1133
1115
  def media_subtype
1134
- warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
1116
+ warn("media_subtype is obsolete, use subtype instead.\n",
1117
+ uplevel: 1, category: :deprecated)
1135
1118
  return subtype
1136
1119
  end
1137
1120
  end
1138
1121
 
1139
- # === Obsolete
1140
- # BodyTypeExtension is not used and will be removed in an upcoming release.
1141
- #
1142
- # >>>
1143
- # BodyTypeExtension was (incorrectly) used for <tt>message/*</tt> parts
1144
- # (besides <tt>message/rfc822</tt>, which correctly uses BodyTypeMessage).
1145
- #
1146
- # Net::IMAP now (correctly) parses all message types (other than
1147
- # <tt>message/rfc822</tt> or <tt>message/global</tt>) as BodyTypeBasic.
1148
- class BodyTypeExtension < Struct.new(:media_type, :subtype,
1149
- :params, :content_id,
1150
- :description, :encoding, :size)
1151
- def multipart?
1152
- return false
1153
- end
1154
- end
1155
-
1156
- deprecate_constant :BodyTypeExtension
1157
-
1158
1122
  end
1159
1123
  end
@@ -13,17 +13,13 @@ module Net
13
13
 
14
14
  attr_reader :config
15
15
 
16
- # Creates a new ResponseParser.
17
- #
18
- # When +config+ is frozen or global, the parser #config inherits from it.
19
- # Otherwise, +config+ will be used directly.
16
+ # :call-seq: Net::IMAP::ResponseParser.new -> Net::IMAP::ResponseParser
20
17
  def initialize(config: Config.global)
21
18
  @str = nil
22
19
  @pos = nil
23
20
  @lex_state = nil
24
21
  @token = nil
25
22
  @config = Config[config]
26
- @config = @config.new if @config == Config.global || @config.frozen?
27
23
  end
28
24
 
29
25
  # :call-seq:
@@ -1321,31 +1317,19 @@ module Net
1321
1317
  # header-fld-name = astring
1322
1318
  #
1323
1319
  # NOTE: Previously, Net::IMAP recreated the raw original source string.
1324
- # Now, it grabs the raw encoded value using @str and @pos. A future
1325
- # version may simply return the decoded astring value. Although that is
1326
- # technically incompatible, it should almost never make a difference: all
1327
- # standard header field names are valid atoms:
1320
+ # Now, it returns the decoded astring value. Although this is technically
1321
+ # incompatible, it should almost never make a difference: all standard
1322
+ # header field names are valid atoms:
1328
1323
  #
1329
1324
  # https://www.iana.org/assignments/message-headers/message-headers.xhtml
1330
1325
  #
1331
- # Although RFC3501 allows any astring, RFC5322-valid header names are one
1332
- # or more of the printable US-ASCII characters, except SP and colon. So
1333
- # empty string isn't valid, and literals aren't needed and should not be
1334
- # used. This is explicitly unchanged by [I18N-HDRS] (RFC6532).
1335
- #
1336
- # RFC5233:
1326
+ # See also RFC5233:
1337
1327
  # optional-field = field-name ":" unstructured CRLF
1338
1328
  # field-name = 1*ftext
1339
1329
  # ftext = %d33-57 / ; Printable US-ASCII
1340
1330
  # %d59-126 ; characters not including
1341
1331
  # ; ":".
1342
- def header_fld_name
1343
- assert_no_lookahead
1344
- start = @pos
1345
- astring
1346
- end_pos = @token ? @pos - 1 : @pos
1347
- @str[start...end_pos]
1348
- end
1332
+ alias header_fld_name astring
1349
1333
 
1350
1334
  # mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list /
1351
1335
  # "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
@@ -1867,10 +1851,11 @@ module Net
1867
1851
  #
1868
1852
  # n.b, uniqueid ⊂ uid-set. To avoid inconsistent return types, we always
1869
1853
  # match uid_set even if that returns a single-member array.
1854
+ #
1870
1855
  def resp_code_apnd__data
1871
1856
  validity = number; SP!
1872
1857
  dst_uids = uid_set # uniqueid ⊂ uid-set
1873
- AppendUID(validity, dst_uids)
1858
+ UIDPlusData.new(validity, nil, dst_uids)
1874
1859
  end
1875
1860
 
1876
1861
  # already matched: "COPYUID"
@@ -1880,25 +1865,7 @@ module Net
1880
1865
  validity = number; SP!
1881
1866
  src_uids = uid_set; SP!
1882
1867
  dst_uids = uid_set
1883
- CopyUID(validity, src_uids, dst_uids)
1884
- end
1885
-
1886
- def AppendUID(...) DeprecatedUIDPlus(...) || AppendUIDData.new(...) end
1887
- def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end
1888
-
1889
- # TODO: remove this code in the v0.6.0 release
1890
- def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids)
1891
- return unless config.parser_use_deprecated_uidplus_data
1892
- compact_uid_sets = [src_uids, dst_uids].compact
1893
- count = compact_uid_sets.map { _1.count_with_duplicates }.max
1894
- max = config.parser_max_deprecated_uidplus_data_size
1895
- if count <= max
1896
- src_uids &&= src_uids.each_ordered_number.to_a
1897
- dst_uids = dst_uids.each_ordered_number.to_a
1898
- UIDPlusData.new(validity, src_uids, dst_uids)
1899
- elsif config.parser_use_deprecated_uidplus_data != :up_to_max_size
1900
- parse_error("uid-set is too large: %d > %d", count, max)
1901
- end
1868
+ UIDPlusData.new(validity, src_uids, dst_uids)
1902
1869
  end
1903
1870
 
1904
1871
  ADDRESS_REGEXP = /\G
@@ -2024,9 +1991,15 @@ module Net
2024
1991
  # uniqueid = nz-number
2025
1992
  # ; Strictly ascending
2026
1993
  def uid_set
2027
- set = sequence_set
2028
- parse_error("uid-set cannot contain '*'") if set.include_star?
2029
- set
1994
+ token = match(T_NUMBER, T_ATOM)
1995
+ case token.symbol
1996
+ when T_NUMBER then [Integer(token.value)]
1997
+ when T_ATOM
1998
+ token.value.split(",").flat_map {|range|
1999
+ range = range.split(":").map {|uniqueid| Integer(uniqueid) }
2000
+ range.size == 1 ? range : Range.new(range.min, range.max).to_a
2001
+ }
2002
+ end
2030
2003
  end
2031
2004
 
2032
2005
  def nil_atom