net-imap 0.3.7 → 0.4.9

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.

Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/pages.yml +46 -0
  3. data/.github/workflows/test.yml +5 -12
  4. data/.gitignore +2 -0
  5. data/Gemfile +3 -0
  6. data/README.md +15 -4
  7. data/Rakefile +0 -7
  8. data/docs/styles.css +0 -12
  9. data/lib/net/imap/authenticators.rb +26 -57
  10. data/lib/net/imap/command_data.rb +13 -6
  11. data/lib/net/imap/data_encoding.rb +14 -2
  12. data/lib/net/imap/deprecated_client_options.rb +139 -0
  13. data/lib/net/imap/errors.rb +20 -0
  14. data/lib/net/imap/fetch_data.rb +518 -0
  15. data/lib/net/imap/response_data.rb +178 -255
  16. data/lib/net/imap/response_parser/parser_utils.rb +240 -0
  17. data/lib/net/imap/response_parser.rb +1722 -1193
  18. data/lib/net/imap/sasl/anonymous_authenticator.rb +69 -0
  19. data/lib/net/imap/sasl/authentication_exchange.rb +107 -0
  20. data/lib/net/imap/sasl/authenticators.rb +118 -0
  21. data/lib/net/imap/sasl/client_adapter.rb +72 -0
  22. data/lib/net/imap/{authenticators/cram_md5.rb → sasl/cram_md5_authenticator.rb} +21 -11
  23. data/lib/net/imap/sasl/digest_md5_authenticator.rb +180 -0
  24. data/lib/net/imap/sasl/external_authenticator.rb +83 -0
  25. data/lib/net/imap/sasl/gs2_header.rb +80 -0
  26. data/lib/net/imap/{authenticators/login.rb → sasl/login_authenticator.rb} +25 -16
  27. data/lib/net/imap/sasl/oauthbearer_authenticator.rb +199 -0
  28. data/lib/net/imap/sasl/plain_authenticator.rb +101 -0
  29. data/lib/net/imap/sasl/protocol_adapters.rb +45 -0
  30. data/lib/net/imap/sasl/scram_algorithm.rb +58 -0
  31. data/lib/net/imap/sasl/scram_authenticator.rb +287 -0
  32. data/lib/net/imap/sasl/stringprep.rb +6 -66
  33. data/lib/net/imap/sasl/xoauth2_authenticator.rb +106 -0
  34. data/lib/net/imap/sasl.rb +144 -43
  35. data/lib/net/imap/sasl_adapter.rb +21 -0
  36. data/lib/net/imap/search_result.rb +150 -0
  37. data/lib/net/imap/sequence_set.rb +1414 -0
  38. data/lib/net/imap/stringprep/nameprep.rb +70 -0
  39. data/lib/net/imap/stringprep/saslprep.rb +69 -0
  40. data/lib/net/imap/stringprep/saslprep_tables.rb +96 -0
  41. data/lib/net/imap/stringprep/tables.rb +146 -0
  42. data/lib/net/imap/stringprep/trace.rb +85 -0
  43. data/lib/net/imap/stringprep.rb +159 -0
  44. data/lib/net/imap.rb +1213 -636
  45. data/net-imap.gemspec +5 -3
  46. data/rakelib/benchmarks.rake +91 -0
  47. data/rakelib/saslprep.rake +4 -4
  48. data/rakelib/string_prep_tables_generator.rb +82 -60
  49. metadata +34 -14
  50. data/benchmarks/stringprep.yml +0 -65
  51. data/benchmarks/table-regexps.yml +0 -39
  52. data/lib/net/imap/authenticators/digest_md5.rb +0 -115
  53. data/lib/net/imap/authenticators/plain.rb +0 -41
  54. data/lib/net/imap/authenticators/xoauth2.rb +0 -20
  55. data/lib/net/imap/sasl/saslprep.rb +0 -55
  56. data/lib/net/imap/sasl/saslprep_tables.rb +0 -98
  57. data/lib/net/imap/sasl/stringprep_tables.rb +0 -153
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Net
4
4
  class IMAP < Protocol
5
+ autoload :FetchData, "#{__dir__}/fetch_data"
6
+ autoload :SearchResult, "#{__dir__}/search_result"
7
+ autoload :SequenceSet, "#{__dir__}/sequence_set"
5
8
 
6
9
  # Net::IMAP::ContinuationRequest represents command continuation requests.
7
10
  #
@@ -55,17 +58,71 @@ module Net
55
58
 
56
59
  # Net::IMAP::IgnoredResponse represents intentionally ignored responses.
57
60
  #
58
- # This includes untagged response "NOOP" sent by eg. Zimbra to avoid some
59
- # clients to close the connection.
61
+ # This includes untagged response "NOOP" sent by eg. Zimbra to avoid
62
+ # some clients to close the connection.
60
63
  #
61
64
  # It matches no IMAP standard.
65
+ class IgnoredResponse < UntaggedResponse
66
+ end
67
+
68
+ # **Note:** This represents an intentionally _unstable_ API. Where
69
+ # instances of this class are returned, future releases may return a
70
+ # different (incompatible) object <em>without deprecation or warning</em>.
71
+ #
72
+ # Net::IMAP::UnparsedData represents data for unknown response types or
73
+ # unknown extensions to response types without a well-defined extension
74
+ # grammar.
62
75
  #
63
- class IgnoredResponse < Struct.new(:raw_data)
76
+ # See also: UnparsedNumericResponseData, ExtensionData, IgnoredResponse
77
+ class UnparsedData < Struct.new(:unparsed_data)
64
78
  ##
65
- # method: raw_data
66
- # :call-seq: raw_data -> string
79
+ # method: unparsed_data
80
+ # :call-seq: unparsed_data -> string
67
81
  #
68
- # The raw response data.
82
+ # The unparsed data
83
+ end
84
+
85
+ # **Note:** This represents an intentionally _unstable_ API. Where
86
+ # instances of this class are returned, future releases may return a
87
+ # different (incompatible) object <em>without deprecation or warning</em>.
88
+ #
89
+ # Net::IMAP::UnparsedNumericResponseData represents data for unhandled
90
+ # response types with a numeric prefix. See the documentation for #number.
91
+ #
92
+ # See also: UnparsedData, ExtensionData, IgnoredResponse
93
+ class UnparsedNumericResponseData < Struct.new(:number, :unparsed_data)
94
+ ##
95
+ # method: number
96
+ # :call-seq: number -> integer
97
+ #
98
+ # Returns a numeric response data prefix, when available.
99
+ #
100
+ # Many response types are prefixed with a non-negative #number. For
101
+ # message data, #number may represent a sequence number or a UID. For
102
+ # mailbox data, #number may represent a message count.
103
+
104
+ ##
105
+ # method: unparsed_data
106
+ # :call-seq: unparsed_data -> string
107
+ #
108
+ # The unparsed data, not including #number or UntaggedResponse#name.
109
+ end
110
+
111
+ # **Note:** This represents an intentionally _unstable_ API. Where
112
+ # instances of this class are returned, future releases may return a
113
+ # different (incompatible) object <em>without deprecation or warning</em>.
114
+ #
115
+ # Net::IMAP::ExtensionData represents data that is parsable according to the
116
+ # forward-compatible extension syntax in RFC3501, RFC4466, or RFC9051, but
117
+ # isn't directly known or understood by Net::IMAP yet.
118
+ #
119
+ # See also: UnparsedData, UnparsedNumericResponseData, IgnoredResponse
120
+ class ExtensionData < Struct.new(:data)
121
+ ##
122
+ # method: data
123
+ # :call-seq: data -> string
124
+ #
125
+ # The parsed extension data.
69
126
  end
70
127
 
71
128
  # Net::IMAP::TaggedResponse represents tagged responses.
@@ -108,6 +165,9 @@ module Net
108
165
  # UntaggedResponse#data when the response type is a "condition" ("OK", "NO",
109
166
  # "BAD", "PREAUTH", or "BYE").
110
167
  class ResponseText < Struct.new(:code, :text)
168
+ # Used to avoid an allocation when ResponseText is empty
169
+ EMPTY = new(nil, "").freeze
170
+
111
171
  ##
112
172
  # method: code
113
173
  # :call-seq: code -> ResponseCode or nil
@@ -146,6 +206,7 @@ module Net
146
206
  # defines them. When unknown response code data is encountered, #data
147
207
  # will return an unparsed string.
148
208
  #
209
+ # ==== +IMAP4rev1+ Response Codes
149
210
  # See [IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501]] {§7.1, "Server
150
211
  # Responses - Status
151
212
  # Responses"}[https://www.rfc-editor.org/rfc/rfc3501#section-7.1] for full
@@ -169,13 +230,32 @@ module Net
169
230
  # {§2.3.1.1, "Unique Identifier (UID) Message
170
231
  # Attribute}[https://www.rfc-editor.org/rfc/rfc3501#section-2.3.1.1].
171
232
  # * +UIDVALIDITY+, #data is an Integer, the UID validity value of the
172
- # mailbox See [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501]],
233
+ # mailbox. See [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501]],
173
234
  # {§2.3.1.1, "Unique Identifier (UID) Message
174
235
  # Attribute}[https://www.rfc-editor.org/rfc/rfc3501#section-2.3.1.1].
175
236
  # * +UNSEEN+, #data is an Integer, the number of messages which do not have
176
237
  # the <tt>\Seen</tt> flag set.
177
- #
178
- # See RFC5530[https://www.rfc-editor.org/rfc/rfc5530], "IMAP Response
238
+ # <em>DEPRECATED by IMAP4rev2.</em>
239
+ #
240
+ # ==== +BINARY+ extension
241
+ # See {[RFC3516]}[https://www.rfc-editor.org/rfc/rfc3516].
242
+ # * +UNKNOWN-CTE+, with a tagged +NO+ response, when the server does not
243
+ # known how to decode a CTE (content-transfer-encoding). #data is +nil+.
244
+ # See IMAP#fetch.
245
+ #
246
+ # ==== +UIDPLUS+ extension
247
+ # See {[RFC4315 §3]}[https://www.rfc-editor.org/rfc/rfc4315#section-3].
248
+ # * +APPENDUID+, #data is UIDPlusData. See IMAP#append.
249
+ # * +COPYUID+, #data is UIDPlusData. See IMAP#copy.
250
+ # * +UIDNOTSTICKY+, #data is +nil+. See IMAP#select.
251
+ #
252
+ # ==== +SEARCHRES+ extension
253
+ # See {[RFC5182]}[https://www.rfc-editor.org/rfc/rfc5182].
254
+ # * +NOTSAVED+, with a tagged +NO+ response, when the search result variable
255
+ # is not saved. #data is +nil+.
256
+ #
257
+ # ==== +RFC5530+ Response Codes
258
+ # See {[RFC5530]}[https://www.rfc-editor.org/rfc/rfc5530], "IMAP Response
179
259
  # Codes" for the definition of the following response codes, which are all
180
260
  # machine-readable annotations for the human-readable ResponseText#text, and
181
261
  # have +nil+ #data of their own:
@@ -197,6 +277,35 @@ module Net
197
277
  # * +ALREADYEXISTS+
198
278
  # * +NONEXISTENT+
199
279
  #
280
+ # ==== +QRESYNC+ extension
281
+ # See {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
282
+ # * +CLOSED+, returned when the currently selected mailbox is closed
283
+ # implicity by selecting or examining another mailbox. #data is +nil+.
284
+ #
285
+ # ==== +IMAP4rev2+ Response Codes
286
+ # See {[RFC9051]}[https://www.rfc-editor.org/rfc/rfc9051] {§7.1, "Server
287
+ # Responses - Status
288
+ # Responses"}[https://www.rfc-editor.org/rfc/rfc9051#section-7.1] for full
289
+ # descriptions of IMAP4rev2 response codes. IMAP4rev2 includes all of the
290
+ # response codes listed above (except "UNSEEN") and adds the following:
291
+ # * +HASCHILDREN+, with a tagged +NO+ response, when a mailbox delete failed
292
+ # because the server doesn't allow deletion of mailboxes with children.
293
+ # #data is +nil+.
294
+ #
295
+ # ==== +CONDSTORE+ extension
296
+ # See {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
297
+ # * +NOMODSEQ+, when selecting a mailbox that does not support
298
+ # mod-sequences. #data is +nil+. See IMAP#select.
299
+ # * +HIGHESTMODSEQ+, #data is an Integer, the highest mod-sequence value of
300
+ # all messages in the mailbox. See IMAP#select.
301
+ # * +MODIFIED+, #data is a SequenceSet, the messages that have been modified
302
+ # since the +UNCHANGEDSINCE+ mod-sequence given to +STORE+ or <tt>UID
303
+ # STORE</tt>.
304
+ #
305
+ # ==== +OBJECTID+ extension
306
+ # See {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
307
+ # * +MAILBOXID+, #data is a string
308
+ #
200
309
  class ResponseCode < Struct.new(:name, :data)
201
310
  ##
202
311
  # method: name
@@ -448,210 +557,6 @@ module Net
448
557
  # "UIDVALIDITY", "UNSEEN". Each value is a number.
449
558
  end
450
559
 
451
- # Net::IMAP::FetchData represents the contents of a FETCH response.
452
- #
453
- # Net::IMAP#fetch and Net::IMAP#uid_fetch both return an array of
454
- # FetchData objects.
455
- #
456
- # === Fetch attributes
457
- #
458
- #--
459
- # TODO: merge branch with accessor methods for each type of attr. Then
460
- # move nearly all of the +attr+ documentation onto the appropriate
461
- # accessor methods.
462
- #++
463
- #
464
- # Each key of the #attr hash is the data item name for the fetched value.
465
- # Each data item represents a message attribute, part of one, or an
466
- # interpretation of one. #seqno is not a message attribute. Most message
467
- # attributes are static and must never change for a given <tt>[server,
468
- # account, mailbox, UIDVALIDITY, UID]</tt> tuple. A few message attributes
469
- # can be dynamically changed, e.g. using the {STORE
470
- # command}[rdoc-ref:Net::IMAP#store].
471
- #
472
- # See {[IMAP4rev1] §7.4.2}[https://www.rfc-editor.org/rfc/rfc3501.html#section-7.4.2]
473
- # and {[IMAP4rev2] §7.5.2}[https://www.rfc-editor.org/rfc/rfc9051.html#section-7.5.2]
474
- # for full description of the standard fetch response data items, and
475
- # Net::IMAP@Message+envelope+and+body+structure for other relevant RFCs.
476
- #
477
- # ==== Static fetch data items
478
- #
479
- # The static data items
480
- # defined by [IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501.html]] are:
481
- #
482
- # [<tt>"UID"</tt>]
483
- # A number expressing the unique identifier of the message.
484
- #
485
- # [<tt>"BODY[]"</tt>, <tt>"BODY[]<#{offset}>"</tt>]
486
- # The [RFC5322[https://tools.ietf.org/html/rfc5322]] expression of the
487
- # entire message, as a string.
488
- #
489
- # If +offset+ is specified, this returned string is a substring of the
490
- # entire contents, starting at that origin octet. This means that
491
- # <tt>BODY[]<0></tt> MAY be truncated, but <tt>BODY[]</tt> is NEVER
492
- # truncated.
493
- #
494
- # <em>Messages can be parsed using the "mail" gem.</em>
495
- #
496
- # [Note]
497
- # When fetching <tt>BODY.PEEK[#{specifier}]</tt>, the data will be
498
- # returned in <tt>BODY[#{specifier}]</tt>, without the +PEEK+. This is
499
- # true for all of the <tt>BODY[...]</tt> attribute forms.
500
- #
501
- # [<tt>"BODY[HEADER]"</tt>, <tt>"BODY[HEADER]<#{offset}>"</tt>]
502
- # The [RFC5322[https://tools.ietf.org/html/rfc5322]] header of the
503
- # message.
504
- #
505
- # <em>Message headers can be parsed using the "mail" gem.</em>
506
- #
507
- # [<tt>"BODY[HEADER.FIELDS (#{fields.join(" ")})]"</tt>,]
508
- # [<tt>"BODY[HEADER.FIELDS (#{fields.join(" ")})]<#{offset}>"</tt>]
509
- # When field names are given, the subset contains only the header fields
510
- # that matches one of the names in the list. The field names are based
511
- # on what was requested, not on what was returned.
512
- #
513
- # [<tt>"BODY[HEADER.FIELDS.NOT (#{fields.join(" ")})]"</tt>,]
514
- # [<tt>"BODY[HEADER.FIELDS.NOT (#{fields.join(" ")})]<#{offset}>"</tt>]
515
- # When the <tt>HEADER.FIELDS.NOT</tt> is used, the subset is all of the
516
- # fields that <em>do not</em> match any names in the list.
517
- #
518
- # [<tt>"BODY[TEXT]"</tt>, <tt>"BODY[TEXT]<#{offset}>"</tt>]
519
- # The text body of the message, omitting
520
- # the [RFC5322[https://tools.ietf.org/html/rfc5322]] header.
521
- #
522
- # [<tt>"BODY[#{part}]"</tt>, <tt>"BODY[#{part}]<#{offset}>"</tt>]
523
- # The text of a particular body section, if it was fetched.
524
- #
525
- # Multiple part specifiers will be joined with <tt>"."</tt>. Numeric
526
- # part specifiers refer to the MIME part number, counting up from +1+.
527
- # Messages that don't use MIME, or MIME messages that are not multipart
528
- # and don't hold an encapsulated message, only have a part +1+.
529
- #
530
- # 8-bit textual data is permitted if
531
- # a [CHARSET[https://tools.ietf.org/html/rfc2978]] identifier is part of
532
- # the body parameter parenthesized list for this section. See
533
- # BodyTypeBasic.
534
- #
535
- # MESSAGE/RFC822 or MESSAGE/GLOBAL message, or a subset of the header, if
536
- # it was fetched.
537
- #
538
- # [<tt>"BODY[#{part}.HEADER]"</tt>,]
539
- # [<tt>"BODY[#{part}.HEADER]<#{offset}>"</tt>,]
540
- # [<tt>"BODY[#{part}.HEADER.FIELDS.NOT (#{fields.join(" ")})]"</tt>,]
541
- # [<tt>"BODY[#{part}.HEADER.FIELDS.NOT (#{fields.join(" ")})]<#{offset}>"</tt>,]
542
- # [<tt>"BODY[#{part}.TEXT]"</tt>,]
543
- # [<tt>"BODY[#{part}.TEXT]<#{offset}>"</tt>,]
544
- # [<tt>"BODY[#{part}.MIME]"</tt>,]
545
- # [<tt>"BODY[#{part}.MIME]<#{offset}>"</tt>]
546
- # +HEADER+, <tt>HEADER.FIELDS</tt>, <tt>HEADER.FIELDS.NOT</tt>, and
547
- # <tt>TEXT</tt> can be prefixed by numeric part specifiers, if it refers
548
- # to a part of type <tt>message/rfc822</tt> or <tt>message/global</tt>.
549
- #
550
- # +MIME+ refers to the [MIME-IMB[https://tools.ietf.org/html/rfc2045]]
551
- # header for this part.
552
- #
553
- # [<tt>"BODY"</tt>]
554
- # A form of +BODYSTRUCTURE+, without any extension data.
555
- #
556
- # [<tt>"BODYSTRUCTURE"</tt>]
557
- # Returns a BodyStructure object that describes
558
- # the [MIME-IMB[https://tools.ietf.org/html/rfc2045]] body structure of
559
- # a message, if it was fetched.
560
- #
561
- # [<tt>"ENVELOPE"</tt>]
562
- # An Envelope object that describes the envelope structure of a message.
563
- # See the documentation for Envelope for a description of the envelope
564
- # structure attributes.
565
- #
566
- # [<tt>"INTERNALDATE"</tt>]
567
- # The internal date and time of the message on the server. This is not
568
- # the date and time in
569
- # the [RFC5322[https://tools.ietf.org/html/rfc5322]] header, but rather
570
- # a date and time which reflects when the message was received.
571
- #
572
- # [<tt>"RFC822.SIZE"</tt>]
573
- # A number expressing the [RFC5322[https://tools.ietf.org/html/rfc5322]]
574
- # size of the message.
575
- #
576
- # [Note]
577
- # \IMAP was originally developed for the older RFC-822 standard, and
578
- # as a consequence several fetch items in \IMAP incorporate "RFC822"
579
- # in their name. With the exception of +RFC822.SIZE+, there are more
580
- # modern replacements; for example, the modern version of
581
- # +RFC822.HEADER+ is <tt>BODY.PEEK[HEADER]</tt>. In all cases,
582
- # "RFC822" should be interpreted as a reference to the
583
- # updated [RFC5322[https://tools.ietf.org/html/rfc5322]] standard.
584
- #
585
- # [<tt>"RFC822"</tt>]
586
- # Semantically equivalent to <tt>BODY[]</tt>.
587
- # [<tt>"RFC822.HEADER"</tt>]
588
- # Semantically equivalent to <tt>BODY[HEADER]</tt>.
589
- # [<tt>"RFC822.TEXT"</tt>]
590
- # Semantically equivalent to <tt>BODY[TEXT]</tt>.
591
- #
592
- # [Note:]
593
- # >>>
594
- # Additional static fields are defined in \IMAP extensions and
595
- # [IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]], but
596
- # Net::IMAP can't parse them yet.
597
- #
598
- #--
599
- # <tt>"BINARY[#{section_binary}]<#{offset}>"</tt>:: TODO...
600
- # <tt>"BINARY.SIZE[#{sectionbinary}]"</tt>:: TODO...
601
- # <tt>"EMAILID"</tt>:: TODO...
602
- # <tt>"THREADID"</tt>:: TODO...
603
- # <tt>"SAVEDATE"</tt>:: TODO...
604
- #++
605
- #
606
- # ==== Dynamic message attributes
607
- # The only dynamic item defined
608
- # by [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501.html]] is:
609
- # [<tt>"FLAGS"</tt>]
610
- # An array of flags that are set for this message. System flags are
611
- # symbols that have been capitalized by String#capitalize. Keyword
612
- # flags are strings and their case is not changed.
613
- #
614
- # \IMAP extensions define new dynamic fields, e.g.:
615
- #
616
- # [<tt>"MODSEQ"</tt>]
617
- # The modification sequence number associated with this IMAP message.
618
- #
619
- # Requires the [CONDSTORE[https://tools.ietf.org/html/rfc7162]]
620
- # server {capability}[rdoc-ref:Net::IMAP#capability].
621
- #
622
- # [Note:]
623
- # >>>
624
- # Additional dynamic fields are defined in \IMAP extensions, but
625
- # Net::IMAP can't parse them yet.
626
- #
627
- #--
628
- # <tt>"ANNOTATE"</tt>:: TODO...
629
- # <tt>"PREVIEW"</tt>:: TODO...
630
- #++
631
- #
632
- class FetchData < Struct.new(:seqno, :attr)
633
- ##
634
- # method: seqno
635
- # :call-seq: seqno -> Integer
636
- #
637
- # The message sequence number.
638
- #
639
- # [Note]
640
- # This is never the unique identifier (UID), not even for the
641
- # Net::IMAP#uid_fetch result. If it was returned, the UID is available
642
- # from <tt>attr["UID"]</tt>.
643
-
644
- ##
645
- # method: attr
646
- # :call-seq: attr -> hash
647
- #
648
- # A hash. Each key is specifies a message attribute, and the value is the
649
- # corresponding data item.
650
- #
651
- # See rdoc-ref:FetchData@Fetch+attributes for descriptions of possible
652
- # values.
653
- end
654
-
655
560
  # Net::IMAP::Envelope represents envelope structures of messages.
656
561
  #
657
562
  # [Note]
@@ -665,6 +570,7 @@ module Net
665
570
  # for full description of the envelope fields, and
666
571
  # Net::IMAP@Message+envelope+and+body+structure for other relevant RFCs.
667
572
  #
573
+ # Returned by FetchData#envelope
668
574
  class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to,
669
575
  :to, :cc, :bcc, :in_reply_to, :message_id)
670
576
  ##
@@ -868,6 +774,19 @@ module Net
868
774
  #
869
775
  # An array of Net::IMAP::ThreadMember objects for mail items that are
870
776
  # children of this in the thread.
777
+
778
+ # Returns a SequenceSet containing #seqno and all #children's seqno,
779
+ # recursively.
780
+ def to_sequence_set
781
+ SequenceSet.new all_seqnos
782
+ end
783
+
784
+ protected
785
+
786
+ def all_seqnos(node = self)
787
+ [node.seqno].concat node.children.flat_map { _1.all_seqnos }
788
+ end
789
+
871
790
  end
872
791
 
873
792
  # Net::IMAP::BodyStructure is included by all of the structs that can be
@@ -891,13 +810,6 @@ module Net
891
810
  # should use BodyTypeBasic.
892
811
  # BodyTypeMultipart:: for <tt>multipart/*</tt> parts
893
812
  #
894
- # ==== Deprecated BodyStructure classes
895
- # The following classes represent invalid server responses or parser bugs:
896
- # BodyTypeExtension:: parser bug: used for <tt>message/*</tt> where
897
- # BodyTypeBasic should have been used.
898
- # BodyTypeAttachment:: server bug: some servers sometimes return the
899
- # "Content-Disposition: attachment" data where the
900
- # entire body structure for a message part is expected.
901
813
  module BodyStructure
902
814
  end
903
815
 
@@ -914,6 +826,7 @@ module Net
914
826
  :param, :content_id,
915
827
  :description, :encoding, :size,
916
828
  :md5, :disposition, :language,
829
+ :location,
917
830
  :extension)
918
831
  include BodyStructure
919
832
 
@@ -1049,6 +962,7 @@ module Net
1049
962
  :description, :encoding, :size,
1050
963
  :lines,
1051
964
  :md5, :disposition, :language,
965
+ :location,
1052
966
  :extension)
1053
967
  include BodyStructure
1054
968
 
@@ -1088,12 +1002,12 @@ module Net
1088
1002
  # * description[rdoc-ref:BodyTypeBasic#description]
1089
1003
  # * encoding[rdoc-ref:BodyTypeBasic#encoding]
1090
1004
  # * size[rdoc-ref:BodyTypeBasic#size]
1091
- #
1092
1005
  class BodyTypeMessage < Struct.new(:media_type, :subtype,
1093
1006
  :param, :content_id,
1094
1007
  :description, :encoding, :size,
1095
1008
  :envelope, :body, :lines,
1096
1009
  :md5, :disposition, :language,
1010
+ :location,
1097
1011
  :extension)
1098
1012
  include BodyStructure
1099
1013
 
@@ -1126,36 +1040,41 @@ module Net
1126
1040
  end
1127
1041
  end
1128
1042
 
1129
- # === WARNING
1130
- # BodyTypeAttachment represents a <tt>body-fld-dsp</tt> that is
1131
- # incorrectly in a position where the IMAP4rev1 grammar expects a nested
1132
- # +body+ structure.
1043
+ # BodyTypeAttachment is not used and will be removed in an upcoming release.
1133
1044
  #
1134
- # >>>
1135
- # \IMAP body structures are parenthesized lists and assign their fields
1136
- # positionally, so missing fields change the intepretation of all
1137
- # following fields. Buggy \IMAP servers sometimes leave fields missing
1138
- # rather than empty, which inevitably confuses parsers.
1139
- # BodyTypeAttachment was an attempt to parse a common type of buggy body
1140
- # structure without crashing.
1141
- #
1142
- # Currently, when Net::IMAP::ResponseParser sees "attachment" as the first
1143
- # entry in a <tt>body-type-1part</tt>, which is where the MIME type should
1144
- # be, it uses BodyTypeAttachment to capture the rest. "attachment" is not
1145
- # a valid MIME type, but _is_ a common <tt>Content-Disposition</tt>. What
1146
- # might have happened was that buggy server could not parse the message
1147
- # (which might have been incorrectly formatted) and output a
1148
- # <tt>body-type-dsp</tt> where a Net::IMAP::ResponseParser expected to see
1149
- # a +body+.
1150
- #
1151
- # A future release will replace this, probably with a ContentDisposition
1152
- # nested inside another body structure object, maybe BodyTypeBasic, or
1153
- # perhaps a new body structure class that represents any unparsable body
1154
- # structure.
1045
+ # === Bug Analysis
1046
+ #
1047
+ # \IMAP body structures are parenthesized lists and assign their fields
1048
+ # positionally, so missing fields change the intepretation of all
1049
+ # following fields. Additionally, different body types have a different
1050
+ # number of required fields, followed by optional "extension" fields.
1051
+ #
1052
+ # BodyTypeAttachment was previously returned when a "message/rfc822" part,
1053
+ # which should be sent as <tt>body-type-msg</tt> with ten required fields,
1054
+ # was actually sent as a <tt>body-type-basic</tt> with _seven_ required
1055
+ # fields.
1056
+ #
1057
+ # basic => type, subtype, param, id, desc, enc, octets, md5=nil, dsp=nil, lang=nil, loc=nil, *ext
1058
+ # msg => type, subtype, param, id, desc, enc, octets, envelope, body, lines, md5=nil, ...
1059
+ #
1060
+ # Normally, +envelope+ and +md5+ are incompatible, but Net::IMAP leniently
1061
+ # allowed buggy servers to send +NIL+ for +envelope+. As a result, when a
1062
+ # server sent a <tt>message/rfc822</tt> part with +NIL+ for +md5+ and a
1063
+ # non-<tt>NIL</tt> +dsp+, Net::IMAP mis-interpreted the
1064
+ # <tt>Content-Disposition</tt> as if it were a strange body type. In all
1065
+ # reported cases, the <tt>Content-Disposition</tt> was "attachment", so
1066
+ # BodyTypeAttachment was created as the workaround.
1067
+ #
1068
+ # === Current behavior
1069
+ #
1070
+ # When interpreted strictly, +envelope+ and +md5+ are incompatible. So the
1071
+ # current parsing algorithm peeks ahead after it has recieved the seventh
1072
+ # body field. If the next token is not the start of an +envelope+, we assume
1073
+ # the server has incorrectly sent us a <tt>body-type-basic</tt> and return
1074
+ # BodyTypeBasic. As a result, what was previously BodyTypeMessage#body =>
1075
+ # BodyTypeAttachment is now BodyTypeBasic#disposition => ContentDisposition.
1155
1076
  #
1156
1077
  class BodyTypeAttachment < Struct.new(:dsp_type, :_unused_, :param)
1157
- include BodyStructure
1158
-
1159
1078
  # *invalid for BodyTypeAttachment*
1160
1079
  def media_type
1161
1080
  warn(<<~WARN, uplevel: 1)
@@ -1190,11 +1109,14 @@ module Net
1190
1109
  end
1191
1110
  end
1192
1111
 
1112
+ deprecate_constant :BodyTypeAttachment
1113
+
1193
1114
  # Net::IMAP::BodyTypeMultipart represents body structures of messages and
1194
1115
  # message parts, when <tt>Content-Type</tt> is <tt>multipart/*</tt>.
1195
1116
  class BodyTypeMultipart < Struct.new(:media_type, :subtype,
1196
1117
  :parts,
1197
1118
  :param, :disposition, :language,
1119
+ :location,
1198
1120
  :extension)
1199
1121
  include BodyStructure
1200
1122
 
@@ -1265,23 +1187,24 @@ module Net
1265
1187
  end
1266
1188
  end
1267
1189
 
1268
- # === WARNING:
1190
+ # === Obsolete
1191
+ # BodyTypeExtension is not used and will be removed in an upcoming release.
1192
+ #
1269
1193
  # >>>
1270
- # BodyTypeExtension is (incorrectly) used for <tt>message/*</tt> parts
1194
+ # BodyTypeExtension was (incorrectly) used for <tt>message/*</tt> parts
1271
1195
  # (besides <tt>message/rfc822</tt>, which correctly uses BodyTypeMessage).
1272
1196
  #
1273
- # A future release will replace this class with:
1274
- # * BodyTypeMessage for <tt>message/rfc822</tt> and <tt>message/global</tt>
1275
- # * BodyTypeBasic for any other <tt>message/*</tt>
1197
+ # Net::IMAP now (correctly) parses all message types (other than
1198
+ # <tt>message/rfc822</tt> or <tt>message/global</tt>) as BodyTypeBasic.
1276
1199
  class BodyTypeExtension < Struct.new(:media_type, :subtype,
1277
1200
  :params, :content_id,
1278
1201
  :description, :encoding, :size)
1279
- include BodyStructure
1280
-
1281
1202
  def multipart?
1282
1203
  return false
1283
1204
  end
1284
1205
  end
1285
1206
 
1207
+ deprecate_constant :BodyTypeExtension
1208
+
1286
1209
  end
1287
1210
  end