net-imap 0.3.7 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
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