net-imap 0.4.19 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

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