net-imap 0.4.12 → 0.5.5

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -1
  3. data/README.md +10 -4
  4. data/docs/styles.css +75 -14
  5. data/lib/net/imap/authenticators.rb +2 -2
  6. data/lib/net/imap/command_data.rb +61 -48
  7. data/lib/net/imap/config/attr_accessors.rb +75 -0
  8. data/lib/net/imap/config/attr_inheritance.rb +90 -0
  9. data/lib/net/imap/config/attr_type_coercion.rb +61 -0
  10. data/lib/net/imap/config.rb +402 -0
  11. data/lib/net/imap/data_encoding.rb +3 -3
  12. data/lib/net/imap/data_lite.rb +226 -0
  13. data/lib/net/imap/deprecated_client_options.rb +8 -5
  14. data/lib/net/imap/errors.rb +6 -0
  15. data/lib/net/imap/esearch_result.rb +180 -0
  16. data/lib/net/imap/fetch_data.rb +126 -47
  17. data/lib/net/imap/response_data.rb +126 -193
  18. data/lib/net/imap/response_parser/parser_utils.rb +11 -6
  19. data/lib/net/imap/response_parser.rb +159 -21
  20. data/lib/net/imap/sasl/anonymous_authenticator.rb +3 -3
  21. data/lib/net/imap/sasl/authentication_exchange.rb +52 -20
  22. data/lib/net/imap/sasl/authenticators.rb +8 -4
  23. data/lib/net/imap/sasl/client_adapter.rb +77 -26
  24. data/lib/net/imap/sasl/cram_md5_authenticator.rb +4 -4
  25. data/lib/net/imap/sasl/digest_md5_authenticator.rb +218 -56
  26. data/lib/net/imap/sasl/external_authenticator.rb +2 -2
  27. data/lib/net/imap/sasl/gs2_header.rb +7 -7
  28. data/lib/net/imap/sasl/login_authenticator.rb +4 -3
  29. data/lib/net/imap/sasl/oauthbearer_authenticator.rb +6 -6
  30. data/lib/net/imap/sasl/plain_authenticator.rb +7 -7
  31. data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
  32. data/lib/net/imap/sasl/scram_authenticator.rb +8 -8
  33. data/lib/net/imap/sasl.rb +7 -4
  34. data/lib/net/imap/sasl_adapter.rb +0 -1
  35. data/lib/net/imap/search_result.rb +2 -2
  36. data/lib/net/imap/sequence_set.rb +28 -24
  37. data/lib/net/imap/stringprep/nameprep.rb +1 -1
  38. data/lib/net/imap/stringprep/trace.rb +4 -4
  39. data/lib/net/imap/vanished_data.rb +56 -0
  40. data/lib/net/imap.rb +1001 -319
  41. data/net-imap.gemspec +3 -3
  42. data/rakelib/rfcs.rake +2 -0
  43. data/rakelib/string_prep_tables_generator.rb +2 -0
  44. metadata +11 -10
  45. data/.github/dependabot.yml +0 -6
  46. data/.github/workflows/pages.yml +0 -46
  47. data/.github/workflows/push_gem.yml +0 -48
  48. data/.github/workflows/test.yml +0 -31
  49. data/.gitignore +0 -12
  50. data/.mailmap +0 -13
data/lib/net/imap.rb CHANGED
@@ -25,8 +25,8 @@ module Net
25
25
 
26
26
  # Net::IMAP implements Internet Message Access Protocol (\IMAP) client
27
27
  # functionality. The protocol is described
28
- # in {IMAP4rev1 [RFC3501]}[https://tools.ietf.org/html/rfc3501]
29
- # and {IMAP4rev2 [RFC9051]}[https://tools.ietf.org/html/rfc9051].
28
+ # in {IMAP4rev1 [RFC3501]}[https://www.rfc-editor.org/rfc/rfc3501]
29
+ # and {IMAP4rev2 [RFC9051]}[https://www.rfc-editor.org/rfc/rfc9051].
30
30
  #
31
31
  # == \IMAP Overview
32
32
  #
@@ -288,6 +288,8 @@ module Net
288
288
  # pre-authenticated connection.
289
289
  # - #responses: Yields unhandled UntaggedResponse#data and <em>non-+nil+</em>
290
290
  # ResponseCode#data.
291
+ # - #extract_responses: Removes and returns the responses for which the block
292
+ # returns a true value.
291
293
  # - #clear_responses: Deletes unhandled data from #responses and returns it.
292
294
  # - #add_response_handler: Add a block to be called inside the receiver thread
293
295
  # with every server response.
@@ -297,15 +299,15 @@ module Net
297
299
  # === Core \IMAP commands
298
300
  #
299
301
  # The following commands are defined either by
300
- # the [IMAP4rev1[https://tools.ietf.org/html/rfc3501]] base specification, or
302
+ # the [IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501]] base specification, or
301
303
  # by one of the following extensions:
302
- # [IDLE[https://tools.ietf.org/html/rfc2177]],
303
- # [NAMESPACE[https://tools.ietf.org/html/rfc2342]],
304
- # [UNSELECT[https://tools.ietf.org/html/rfc3691]],
305
- # [ENABLE[https://tools.ietf.org/html/rfc5161]],
306
- # [MOVE[https://tools.ietf.org/html/rfc6851]].
304
+ # [IDLE[https://www.rfc-editor.org/rfc/rfc2177]],
305
+ # [NAMESPACE[https://www.rfc-editor.org/rfc/rfc2342]],
306
+ # [UNSELECT[https://www.rfc-editor.org/rfc/rfc3691]],
307
+ # [ENABLE[https://www.rfc-editor.org/rfc/rfc5161]],
308
+ # [MOVE[https://www.rfc-editor.org/rfc/rfc6851]].
307
309
  # These extensions are widely supported by modern IMAP4rev1 servers and have
308
- # all been integrated into [IMAP4rev2[https://tools.ietf.org/html/rfc9051]].
310
+ # all been integrated into [IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]].
309
311
  # <em>*NOTE:* Net::IMAP doesn't support IMAP4rev2 yet.</em>
310
312
  #
311
313
  # ==== Any state
@@ -402,7 +404,7 @@ module Net
402
404
  #
403
405
  # ==== RFC9051: +IMAP4rev2+
404
406
  #
405
- # Although IMAP4rev2[https://tools.ietf.org/html/rfc9051] is not supported
407
+ # Although IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] is not supported
406
408
  # yet, Net::IMAP supports several extensions that have been folded into it:
407
409
  # +ENABLE+, +IDLE+, +MOVE+, +NAMESPACE+, +SASL-IR+, +UIDPLUS+, +UNSELECT+,
408
410
  # <tt>STATUS=SIZE</tt>, and the fetch side of +BINARY+.
@@ -412,7 +414,7 @@ module Net
412
414
  # >>>
413
415
  # <em>The following are folded into +IMAP4rev2+ but are currently
414
416
  # unsupported or incompletely supported by</em> Net::IMAP<em>: RFC4466
415
- # extensions, +ESEARCH+, +SEARCHRES+, +LIST-EXTENDED+, +LIST-STATUS+,
417
+ # extensions, +SEARCHRES+, +LIST-EXTENDED+, +LIST-STATUS+,
416
418
  # +LITERAL-+, and +SPECIAL-USE+.</em>
417
419
  #
418
420
  # ==== RFC2087: +QUOTA+
@@ -422,13 +424,13 @@ module Net
422
424
  # - #setquota: sets the resource limits for a given quota root.
423
425
  #
424
426
  # ==== RFC2177: +IDLE+
425
- # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
427
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
426
428
  # above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
427
429
  # - #idle: Allows the server to send updates to the client, without the client
428
430
  # needing to poll using #noop.
429
431
  #
430
432
  # ==== RFC2342: +NAMESPACE+
431
- # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
433
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
432
434
  # above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
433
435
  # - #namespace: Returns mailbox namespaces, with path prefixes and delimiters.
434
436
  #
@@ -437,7 +439,7 @@ module Net
437
439
  #
438
440
  # ==== RFC3516: +BINARY+
439
441
  # The fetch side of +BINARY+ has been folded into
440
- # IMAP4rev2[https://tools.ietf.org/html/rfc9051].
442
+ # IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
441
443
  # - Updates #fetch and #uid_fetch with the +BINARY+, +BINARY.PEEK+, and
442
444
  # +BINARY.SIZE+ items. See FetchData#binary and FetchData#binary_size.
443
445
  #
@@ -445,7 +447,7 @@ module Net
445
447
  # *NOTE:* The binary extension the #append command is _not_ supported yet.
446
448
  #
447
449
  # ==== RFC3691: +UNSELECT+
448
- # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
450
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
449
451
  # above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
450
452
  # - #unselect: Closes the mailbox and returns to the "_authenticated_" state,
451
453
  # without expunging any messages.
@@ -457,19 +459,23 @@ module Net
457
459
  # *NOTE:* +DELETEACL+, +LISTRIGHTS+, and +MYRIGHTS+ are not supported yet.
458
460
  #
459
461
  # ==== RFC4315: +UIDPLUS+
460
- # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
462
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
461
463
  # above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
462
464
  # - #uid_expunge: Restricts #expunge to only remove the specified UIDs.
463
465
  # - Updates #select, #examine with the +UIDNOTSTICKY+ ResponseCode
464
466
  # - Updates #append with the +APPENDUID+ ResponseCode
465
467
  # - Updates #copy, #move with the +COPYUID+ ResponseCode
466
468
  #
469
+ # ==== RFC4731: +ESEARCH+
470
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
471
+ # - Updates #search, #uid_search with +return+ options and ESearchResult.
472
+ #
467
473
  # ==== RFC4959: +SASL-IR+
468
- # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051].
474
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
469
475
  # - Updates #authenticate with the option to send an initial response.
470
476
  #
471
477
  # ==== RFC5161: +ENABLE+
472
- # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
478
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
473
479
  # above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
474
480
  # - #enable: Enables backwards incompatible server extensions.
475
481
  #
@@ -493,7 +499,7 @@ module Net
493
499
  # +X-GM-THRID+, but Gmail does not support it (as of 2023-11-10).
494
500
  #
495
501
  # ==== RFC6851: +MOVE+
496
- # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
502
+ # Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
497
503
  # above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
498
504
  # - #move, #uid_move: Moves the specified messages to the end of the
499
505
  # specified destination mailbox, expunging them from the current mailbox.
@@ -528,6 +534,17 @@ module Net
528
534
  # See FetchData#emailid and FetchData#emailid.
529
535
  # - Updates #status with support for the +MAILBOXID+ status attribute.
530
536
  #
537
+ # ==== RFC9394: +PARTIAL+
538
+ # - Updates #search, #uid_search with the +PARTIAL+ return option which adds
539
+ # ESearchResult#partial return data.
540
+ # - Updates #uid_fetch with the +partial+ modifier.
541
+ #
542
+ # ==== RFC9586: +UIDONLY+
543
+ # - Updates #enable with +UIDONLY+ parameter.
544
+ # - Updates #uid_fetch and #uid_store to return +UIDFETCH+ response.
545
+ # - Updates #expunge and #uid_expunge to return +VANISHED+ response.
546
+ # - Prohibits use of message sequence numbers in responses or requests.
547
+ #
531
548
  # == References
532
549
  #
533
550
  # [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501.html]]::
@@ -558,57 +575,57 @@ module Net
558
575
  # Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC 2180, DOI
559
576
  # 10.17487/RFC2180, July 1997, <https://www.rfc-editor.org/info/rfc2180>.
560
577
  #
561
- # [UTF7[https://tools.ietf.org/html/rfc2152]]::
578
+ # [UTF7[https://www.rfc-editor.org/rfc/rfc2152]]::
562
579
  # Goldsmith, D. and M. Davis, "UTF-7 A Mail-Safe Transformation Format of
563
580
  # Unicode", RFC 2152, DOI 10.17487/RFC2152, May 1997,
564
581
  # <https://www.rfc-editor.org/info/rfc2152>.
565
582
  #
566
583
  # === Message envelope and body structure
567
584
  #
568
- # [RFC5322[https://tools.ietf.org/html/rfc5322]]::
585
+ # [RFC5322[https://www.rfc-editor.org/rfc/rfc5322]]::
569
586
  # Resnick, P., Ed., "Internet Message Format",
570
587
  # RFC 5322, DOI 10.17487/RFC5322, October 2008,
571
588
  # <https://www.rfc-editor.org/info/rfc5322>.
572
589
  #
573
590
  # <em>Note: obsoletes</em>
574
- # RFC-2822[https://tools.ietf.org/html/rfc2822]<em> (April 2001) and</em>
575
- # RFC-822[https://tools.ietf.org/html/rfc822]<em> (August 1982).</em>
591
+ # RFC-2822[https://www.rfc-editor.org/rfc/rfc2822]<em> (April 2001) and</em>
592
+ # RFC-822[https://www.rfc-editor.org/rfc/rfc822]<em> (August 1982).</em>
576
593
  #
577
- # [CHARSET[https://tools.ietf.org/html/rfc2978]]::
594
+ # [CHARSET[https://www.rfc-editor.org/rfc/rfc2978]]::
578
595
  # Freed, N. and J. Postel, "IANA Charset Registration Procedures", BCP 19,
579
596
  # RFC 2978, DOI 10.17487/RFC2978, October 2000,
580
597
  # <https://www.rfc-editor.org/info/rfc2978>.
581
598
  #
582
- # [DISPOSITION[https://tools.ietf.org/html/rfc2183]]::
599
+ # [DISPOSITION[https://www.rfc-editor.org/rfc/rfc2183]]::
583
600
  # Troost, R., Dorner, S., and K. Moore, Ed., "Communicating Presentation
584
601
  # Information in Internet Messages: The Content-Disposition Header
585
602
  # Field", RFC 2183, DOI 10.17487/RFC2183, August 1997,
586
603
  # <https://www.rfc-editor.org/info/rfc2183>.
587
604
  #
588
- # [MIME-IMB[https://tools.ietf.org/html/rfc2045]]::
605
+ # [MIME-IMB[https://www.rfc-editor.org/rfc/rfc2045]]::
589
606
  # Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions
590
607
  # (MIME) Part One: Format of Internet Message Bodies",
591
608
  # RFC 2045, DOI 10.17487/RFC2045, November 1996,
592
609
  # <https://www.rfc-editor.org/info/rfc2045>.
593
610
  #
594
- # [MIME-IMT[https://tools.ietf.org/html/rfc2046]]::
611
+ # [MIME-IMT[https://www.rfc-editor.org/rfc/rfc2046]]::
595
612
  # Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions
596
613
  # (MIME) Part Two: Media Types", RFC 2046, DOI 10.17487/RFC2046,
597
614
  # November 1996, <https://www.rfc-editor.org/info/rfc2046>.
598
615
  #
599
- # [MIME-HDRS[https://tools.ietf.org/html/rfc2047]]::
616
+ # [MIME-HDRS[https://www.rfc-editor.org/rfc/rfc2047]]::
600
617
  # Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Three:
601
618
  # Message Header Extensions for Non-ASCII Text",
602
619
  # RFC 2047, DOI 10.17487/RFC2047, November 1996,
603
620
  # <https://www.rfc-editor.org/info/rfc2047>.
604
621
  #
605
- # [RFC2231[https://tools.ietf.org/html/rfc2231]]::
622
+ # [RFC2231[https://www.rfc-editor.org/rfc/rfc2231]]::
606
623
  # Freed, N. and K. Moore, "MIME Parameter Value and Encoded Word
607
624
  # Extensions: Character Sets, Languages, and Continuations",
608
625
  # RFC 2231, DOI 10.17487/RFC2231, November 1997,
609
626
  # <https://www.rfc-editor.org/info/rfc2231>.
610
627
  #
611
- # [I18n-HDRS[https://tools.ietf.org/html/rfc6532]]::
628
+ # [I18n-HDRS[https://www.rfc-editor.org/rfc/rfc6532]]::
612
629
  # Yang, A., Steele, S., and N. Freed, "Internationalized Email Headers",
613
630
  # RFC 6532, DOI 10.17487/RFC6532, February 2012,
614
631
  # <https://www.rfc-editor.org/info/rfc6532>.
@@ -624,12 +641,12 @@ module Net
624
641
  # RFC 2557, DOI 10.17487/RFC2557, March 1999,
625
642
  # <https://www.rfc-editor.org/info/rfc2557>.
626
643
  #
627
- # [MD5[https://tools.ietf.org/html/rfc1864]]::
644
+ # [MD5[https://www.rfc-editor.org/rfc/rfc1864]]::
628
645
  # Myers, J. and M. Rose, "The Content-MD5 Header Field",
629
646
  # RFC 1864, DOI 10.17487/RFC1864, October 1995,
630
647
  # <https://www.rfc-editor.org/info/rfc1864>.
631
648
  #
632
- # [RFC3503[https://tools.ietf.org/html/rfc3503]]::
649
+ # [RFC3503[https://www.rfc-editor.org/rfc/rfc3503]]::
633
650
  # Melnikov, A., "Message Disposition Notification (MDN)
634
651
  # profile for Internet Message Access Protocol (IMAP)",
635
652
  # RFC 3503, DOI 10.17487/RFC3503, March 2003,
@@ -637,27 +654,27 @@ module Net
637
654
  #
638
655
  # === \IMAP Extensions
639
656
  #
640
- # [QUOTA[https://tools.ietf.org/html/rfc9208]]::
657
+ # [QUOTA[https://www.rfc-editor.org/rfc/rfc9208]]::
641
658
  # Melnikov, A., "IMAP QUOTA Extension", RFC 9208, DOI 10.17487/RFC9208,
642
659
  # March 2022, <https://www.rfc-editor.org/info/rfc9208>.
643
660
  #
644
661
  # <em>Note: obsoletes</em>
645
- # RFC-2087[https://tools.ietf.org/html/rfc2087]<em> (January 1997)</em>.
662
+ # RFC-2087[https://www.rfc-editor.org/rfc/rfc2087]<em> (January 1997)</em>.
646
663
  # <em>Net::IMAP does not fully support the RFC9208 updates yet.</em>
647
- # [IDLE[https://tools.ietf.org/html/rfc2177]]::
664
+ # [IDLE[https://www.rfc-editor.org/rfc/rfc2177]]::
648
665
  # Leiba, B., "IMAP4 IDLE command", RFC 2177, DOI 10.17487/RFC2177,
649
666
  # June 1997, <https://www.rfc-editor.org/info/rfc2177>.
650
- # [NAMESPACE[https://tools.ietf.org/html/rfc2342]]::
667
+ # [NAMESPACE[https://www.rfc-editor.org/rfc/rfc2342]]::
651
668
  # Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342,
652
669
  # DOI 10.17487/RFC2342, May 1998, <https://www.rfc-editor.org/info/rfc2342>.
653
- # [ID[https://tools.ietf.org/html/rfc2971]]::
670
+ # [ID[https://www.rfc-editor.org/rfc/rfc2971]]::
654
671
  # Showalter, T., "IMAP4 ID extension", RFC 2971, DOI 10.17487/RFC2971,
655
672
  # October 2000, <https://www.rfc-editor.org/info/rfc2971>.
656
- # [BINARY[https://tools.ietf.org/html/rfc3516]]::
673
+ # [BINARY[https://www.rfc-editor.org/rfc/rfc3516]]::
657
674
  # Nerenberg, L., "IMAP4 Binary Content Extension", RFC 3516,
658
675
  # DOI 10.17487/RFC3516, April 2003,
659
676
  # <https://www.rfc-editor.org/info/rfc3516>.
660
- # [ACL[https://tools.ietf.org/html/rfc4314]]::
677
+ # [ACL[https://www.rfc-editor.org/rfc/rfc4314]]::
661
678
  # Melnikov, A., "IMAP4 Access Control List (ACL) Extension", RFC 4314,
662
679
  # DOI 10.17487/RFC4314, December 2005,
663
680
  # <https://www.rfc-editor.org/info/rfc4314>.
@@ -665,36 +682,46 @@ module Net
665
682
  # Crispin, M., "Internet Message Access Protocol (\IMAP) - UIDPLUS
666
683
  # extension", RFC 4315, DOI 10.17487/RFC4315, December 2005,
667
684
  # <https://www.rfc-editor.org/info/rfc4315>.
668
- # [SORT[https://tools.ietf.org/html/rfc5256]]::
685
+ # [SORT[https://www.rfc-editor.org/rfc/rfc5256]]::
669
686
  # Crispin, M. and K. Murchison, "Internet Message Access Protocol - SORT and
670
687
  # THREAD Extensions", RFC 5256, DOI 10.17487/RFC5256, June 2008,
671
688
  # <https://www.rfc-editor.org/info/rfc5256>.
672
- # [THREAD[https://tools.ietf.org/html/rfc5256]]::
689
+ # [THREAD[https://www.rfc-editor.org/rfc/rfc5256]]::
673
690
  # Crispin, M. and K. Murchison, "Internet Message Access Protocol - SORT and
674
691
  # THREAD Extensions", RFC 5256, DOI 10.17487/RFC5256, June 2008,
675
692
  # <https://www.rfc-editor.org/info/rfc5256>.
676
693
  # [RFC5530[https://www.rfc-editor.org/rfc/rfc5530.html]]::
677
694
  # Gulbrandsen, A., "IMAP Response Codes", RFC 5530, DOI 10.17487/RFC5530,
678
695
  # May 2009, <https://www.rfc-editor.org/info/rfc5530>.
679
- # [MOVE[https://tools.ietf.org/html/rfc6851]]::
696
+ # [MOVE[https://www.rfc-editor.org/rfc/rfc6851]]::
680
697
  # Gulbrandsen, A. and N. Freed, Ed., "Internet Message Access Protocol
681
698
  # (\IMAP) - MOVE Extension", RFC 6851, DOI 10.17487/RFC6851, January 2013,
682
699
  # <https://www.rfc-editor.org/info/rfc6851>.
683
- # [UTF8=ACCEPT[https://tools.ietf.org/html/rfc6855]]::
684
- # [UTF8=ONLY[https://tools.ietf.org/html/rfc6855]]::
700
+ # [UTF8=ACCEPT[https://www.rfc-editor.org/rfc/rfc6855]]::
701
+ # [UTF8=ONLY[https://www.rfc-editor.org/rfc/rfc6855]]::
685
702
  # Resnick, P., Ed., Newman, C., Ed., and S. Shen, Ed.,
686
703
  # "IMAP Support for UTF-8", RFC 6855, DOI 10.17487/RFC6855, March 2013,
687
704
  # <https://www.rfc-editor.org/info/rfc6855>.
688
- # [CONDSTORE[https://tools.ietf.org/html/rfc7162]]::
689
- # [QRESYNC[https://tools.ietf.org/html/rfc7162]]::
705
+ # [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162]]::
706
+ # [QRESYNC[https://www.rfc-editor.org/rfc/rfc7162]]::
690
707
  # Melnikov, A. and D. Cridland, "IMAP Extensions: Quick Flag Changes
691
708
  # Resynchronization (CONDSTORE) and Quick Mailbox Resynchronization
692
709
  # (QRESYNC)", RFC 7162, DOI 10.17487/RFC7162, May 2014,
693
710
  # <https://www.rfc-editor.org/info/rfc7162>.
694
- # [OBJECTID[https://tools.ietf.org/html/rfc8474]]::
711
+ # [OBJECTID[https://www.rfc-editor.org/rfc/rfc8474]]::
695
712
  # Gondwana, B., Ed., "IMAP Extension for Object Identifiers",
696
713
  # RFC 8474, DOI 10.17487/RFC8474, September 2018,
697
714
  # <https://www.rfc-editor.org/info/rfc8474>.
715
+ # [PARTIAL[https://www.rfc-editor.org/info/rfc9394]]::
716
+ # Melnikov, A., Achuthan, A., Nagulakonda, V., and L. Alves,
717
+ # "IMAP PARTIAL Extension for Paged SEARCH and FETCH", RFC 9394,
718
+ # DOI 10.17487/RFC9394, June 2023,
719
+ # <https://www.rfc-editor.org/info/rfc9394>.
720
+ # [UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.pdf]]::
721
+ # Melnikov, A., Achuthan, A., Nagulakonda, V., Singh, A., and L. Alves,
722
+ # "\IMAP Extension for Using and Returning Unique Identifiers (UIDs) Only",
723
+ # RFC 9586, DOI 10.17487/RFC9586, May 2024,
724
+ # <https://www.rfc-editor.org/info/rfc9586>.
698
725
  #
699
726
  # === IANA registries
700
727
  # * {IMAP Capabilities}[http://www.iana.org/assignments/imap4-capabilities]
@@ -708,7 +735,7 @@ module Net
708
735
  # * {GSSAPI/Kerberos/SASL Service Names}[https://www.iana.org/assignments/gssapi-service-names/gssapi-service-names.xhtml]:
709
736
  # +imap+
710
737
  # * {Character sets}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
711
- # ===== For currently unsupported features:
738
+ # ==== For currently unsupported features:
712
739
  # * {IMAP Quota Resource Types}[http://www.iana.org/assignments/imap4-capabilities#imap-capabilities-2]
713
740
  # * {LIST-EXTENDED options and responses}[https://www.iana.org/assignments/imap-list-extended/imap-list-extended.xhtml]
714
741
  # * {IMAP METADATA Server Entry and Mailbox Entry Registries}[https://www.iana.org/assignments/imap-metadata/imap-metadata.xhtml]
@@ -717,7 +744,7 @@ module Net
717
744
  # * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
718
745
  #
719
746
  class IMAP < Protocol
720
- VERSION = "0.4.12"
747
+ VERSION = "0.5.5"
721
748
 
722
749
  # Aliases for supported capabilities, to be used with the #enable command.
723
750
  ENABLE_ALIASES = {
@@ -735,14 +762,15 @@ module Net
735
762
  include SSL
736
763
  end
737
764
 
738
- # Returns the debug mode.
739
- def self.debug
740
- return @@debug
741
- end
765
+ # Returns the global Config object
766
+ def self.config; Config.global end
742
767
 
743
- # Sets the debug mode.
768
+ # Returns the global debug mode.
769
+ def self.debug; config.debug end
770
+
771
+ # Sets the global debug mode.
744
772
  def self.debug=(val)
745
- return @@debug = val
773
+ config.debug = val
746
774
  end
747
775
 
748
776
  # The default port for IMAP connections, port 143
@@ -764,13 +792,19 @@ module Net
764
792
  # Returns the initial greeting the server, an UntaggedResponse.
765
793
  attr_reader :greeting
766
794
 
795
+ # The client configuration. See Net::IMAP::Config.
796
+ #
797
+ # By default, the client's local configuration inherits from the global
798
+ # Net::IMAP.config.
799
+ attr_reader :config
800
+
767
801
  # Seconds to wait until a connection is opened.
768
802
  # If the IMAP object cannot open a connection within this time,
769
803
  # it raises a Net::OpenTimeout exception. The default value is 30 seconds.
770
- attr_reader :open_timeout
804
+ def open_timeout; config.open_timeout end
771
805
 
772
806
  # Seconds to wait until an IDLE response is received.
773
- attr_reader :idle_response_timeout
807
+ def idle_response_timeout; config.idle_response_timeout end
774
808
 
775
809
  # The hostname this client connected to
776
810
  attr_reader :host
@@ -809,14 +843,40 @@ module Net
809
843
  # If +ssl+ is a hash, it's passed to
810
844
  # {OpenSSL::SSL::SSLContext#set_params}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-set_params];
811
845
  # the keys are names of attribute assignment methods on
812
- # SSLContext[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html].
846
+ # SSLContext[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html]. For example:
847
+ #
848
+ # [{ca_file}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#attribute-i-ca_file]]
849
+ # The path to a file containing a PEM-format CA certificate.
850
+ # [{ca_path}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#attribute-i-ca_path]]
851
+ # The path to a directory containing CA certificates in PEM format.
852
+ # [{min_version}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D]]
853
+ # Sets the lower bound on the supported SSL/TLS protocol version. Set to
854
+ # an +OpenSSL+ constant such as +OpenSSL::SSL::TLS1_2_VERSION+,
855
+ # [{verify_mode}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#attribute-i-verify_mode]]
856
+ # SSL session verification mode. Valid modes include
857
+ # +OpenSSL::SSL::VERIFY_PEER+ and +OpenSSL::SSL::VERIFY_NONE+.
858
+ #
859
+ # See {OpenSSL::SSL::SSLContext}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html] for other valid SSL context params.
860
+ #
861
+ # See DeprecatedClientOptions.new for deprecated SSL arguments.
862
+ #
863
+ # [config]
864
+ # A Net::IMAP::Config object to use as the basis for #config. By default,
865
+ # the global Net::IMAP.config is used.
866
+ #
867
+ # >>>
868
+ # *NOTE:* +config+ does not set #config directly---it sets the _parent_
869
+ # config for inheritance. Every client creates its own unique #config.
870
+ #
871
+ # All other keyword arguments are forwarded to Net::IMAP::Config.new, to
872
+ # initialize the client's #config. For example:
813
873
  #
814
- # [open_timeout]
815
- # Seconds to wait until a connection is opened
816
- # [idle_response_timeout]
817
- # Seconds to wait until an IDLE response is received
874
+ # [{open_timeout}[rdoc-ref:Config#open_timeout]]
875
+ # Seconds to wait until a connection is opened
876
+ # [{idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]]
877
+ # Seconds to wait until an IDLE response is received
818
878
  #
819
- # See DeprecatedClientOptions.new for deprecated arguments.
879
+ # See Net::IMAP::Config for other valid options.
820
880
  #
821
881
  # ==== Examples
822
882
  #
@@ -872,13 +932,12 @@ module Net
872
932
  # Connected to the host successfully, but it immediately said goodbye.
873
933
  #
874
934
  def initialize(host, port: nil, ssl: nil,
875
- open_timeout: 30, idle_response_timeout: 5)
935
+ config: Config.global, **config_options)
876
936
  super()
877
937
  # Config options
878
938
  @host = host
939
+ @config = Config.new(config, **config_options)
879
940
  @port = port || (ssl ? SSL_PORT : PORT)
880
- @open_timeout = Integer(open_timeout)
881
- @idle_response_timeout = Integer(idle_response_timeout)
882
941
  @ssl_ctx_params, @ssl_ctx = build_ssl_ctx(ssl)
883
942
 
884
943
  # Basic Client State
@@ -889,7 +948,7 @@ module Net
889
948
  @capabilities = nil
890
949
 
891
950
  # Client Protocol Receiver
892
- @parser = ResponseParser.new
951
+ @parser = ResponseParser.new(config: @config)
893
952
  @responses = Hash.new {|h, k| h[k] = [] }
894
953
  @response_handlers = []
895
954
  @receiver_thread = nil
@@ -912,9 +971,6 @@ module Net
912
971
  @sock = tcp_socket(@host, @port)
913
972
  start_tls_session if ssl_ctx
914
973
  start_imap_connection
915
-
916
- # DEPRECATED: to remove in next version
917
- @client_thread = Thread.current
918
974
  end
919
975
 
920
976
  # Returns true after the TLS negotiation has completed and the remote
@@ -922,11 +978,6 @@ module Net
922
978
  # but peer verification was disabled.
923
979
  def tls_verified?; @tls_verified end
924
980
 
925
- def client_thread # :nodoc:
926
- warn "Net::IMAP#client_thread is deprecated and will be removed soon."
927
- @client_thread
928
- end
929
-
930
981
  # Disconnects from the server.
931
982
  #
932
983
  # Related: #logout, #logout!
@@ -1095,12 +1146,12 @@ module Net
1095
1146
  # )
1096
1147
  # end
1097
1148
  #
1098
- # See [ID[https://tools.ietf.org/html/rfc2971]] for field definitions.
1149
+ # See [ID[https://www.rfc-editor.org/rfc/rfc2971]] for field definitions.
1099
1150
  #
1100
- # ===== Capabilities
1151
+ # ==== Capabilities
1101
1152
  #
1102
1153
  # The server's capabilities must include +ID+
1103
- # [RFC2971[https://tools.ietf.org/html/rfc2971]].
1154
+ # [RFC2971[https://www.rfc-editor.org/rfc/rfc2971]].
1104
1155
  def id(client_id=nil)
1105
1156
  synchronize do
1106
1157
  send_command("ID", ClientID.new(client_id))
@@ -1179,7 +1230,7 @@ module Net
1179
1230
  #
1180
1231
  # Related: Net::IMAP.new, #login, #authenticate
1181
1232
  #
1182
- # ===== Capability
1233
+ # ==== Capability
1183
1234
  # Clients should not call #starttls unless the server advertises the
1184
1235
  # +STARTTLS+ capability.
1185
1236
  #
@@ -1198,7 +1249,7 @@ module Net
1198
1249
  end
1199
1250
 
1200
1251
  # :call-seq:
1201
- # authenticate(mechanism, *, sasl_ir: true, registry: Net::IMAP::SASL.authenticators, **, &) -> ok_resp
1252
+ # authenticate(mechanism, *, sasl_ir: config.sasl_ir, registry: Net::IMAP::SASL.authenticators, **, &) -> ok_resp
1202
1253
  #
1203
1254
  # Sends an {AUTHENTICATE command [IMAP4rev1 §6.2.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.2]
1204
1255
  # to authenticate the client. If successful, the connection enters the
@@ -1207,7 +1258,11 @@ module Net
1207
1258
  # +mechanism+ is the name of the \SASL authentication mechanism to be used.
1208
1259
  #
1209
1260
  # +sasl_ir+ allows or disallows sending an "initial response" (see the
1210
- # +SASL-IR+ capability, below).
1261
+ # +SASL-IR+ capability, below). Defaults to the #config value for
1262
+ # {sasl_ir}[rdoc-ref:Config#sasl_ir], which defaults to +true+.
1263
+ #
1264
+ # The +registry+ kwarg can be used to select the mechanism implementation
1265
+ # from a custom registry. See SASL.authenticator and SASL::Authenticators.
1211
1266
  #
1212
1267
  # All other arguments are forwarded to the registered SASL authenticator for
1213
1268
  # the requested mechanism. <em>The documentation for each individual
@@ -1303,27 +1358,9 @@ module Net
1303
1358
  # Previously cached #capabilities will be cleared when this method
1304
1359
  # completes. If the TaggedResponse to #authenticate includes updated
1305
1360
  # capabilities, they will be cached.
1306
- def authenticate(mechanism, *creds, sasl_ir: true, **props, &callback)
1307
- mechanism = mechanism.to_s.tr("_", "-").upcase
1308
- authenticator = SASL.authenticator(mechanism, *creds, **props, &callback)
1309
- cmdargs = ["AUTHENTICATE", mechanism]
1310
- if sasl_ir && capable?("SASL-IR") && auth_capable?(mechanism) &&
1311
- authenticator.respond_to?(:initial_response?) &&
1312
- authenticator.initial_response?
1313
- response = authenticator.process(nil)
1314
- cmdargs << (response.empty? ? "=" : [response].pack("m0"))
1315
- end
1316
- result = send_command_with_continuations(*cmdargs) {|data|
1317
- challenge = data.unpack1("m")
1318
- response = authenticator.process challenge
1319
- [response].pack("m0")
1320
- }
1321
- if authenticator.respond_to?(:done?) && !authenticator.done?
1322
- logout!
1323
- raise SASL::AuthenticationIncomplete, result
1324
- end
1325
- @capabilities = capabilities_from_resp_code result
1326
- result
1361
+ def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
1362
+ sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
1363
+ .tap { @capabilities = capabilities_from_resp_code _1 }
1327
1364
  end
1328
1365
 
1329
1366
  # Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
@@ -1340,16 +1377,12 @@ module Net
1340
1377
  #
1341
1378
  # Related: #authenticate, #starttls
1342
1379
  #
1343
- # ===== Capabilities
1380
+ # ==== Capabilities
1344
1381
  #
1345
1382
  # An IMAP client MUST NOT call #login when the server advertises the
1346
- # +LOGINDISABLED+ capability.
1347
- #
1348
- # if imap.capability? "LOGINDISABLED"
1349
- # raise "Remote server has disabled the login command"
1350
- # else
1351
- # imap.login username, password
1352
- # end
1383
+ # +LOGINDISABLED+ capability. By default, Net::IMAP will raise a
1384
+ # LoginDisabledError when that capability is present. See
1385
+ # Config#enforce_logindisabled.
1353
1386
  #
1354
1387
  # Server capabilities may change after #starttls, #login, and #authenticate.
1355
1388
  # Cached capabilities _must_ be invalidated after this method completes.
@@ -1357,6 +1390,9 @@ module Net
1357
1390
  # ResponseCode.
1358
1391
  #
1359
1392
  def login(user, password)
1393
+ if enforce_logindisabled? && capability?("LOGINDISABLED")
1394
+ raise LoginDisabledError
1395
+ end
1360
1396
  send_command("LOGIN", user, password)
1361
1397
  .tap { @capabilities = capabilities_from_resp_code _1 }
1362
1398
  end
@@ -1382,7 +1418,7 @@ module Net
1382
1418
  #
1383
1419
  # Related: #examine
1384
1420
  #
1385
- # ===== Capabilities
1421
+ # ==== Capabilities
1386
1422
  #
1387
1423
  # If [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]] is supported,
1388
1424
  # the server may return an untagged "NO" response with a "UIDNOTSTICKY"
@@ -1500,7 +1536,7 @@ module Net
1500
1536
  #
1501
1537
  # Related: #lsub, MailboxList
1502
1538
  #
1503
- # ===== For example:
1539
+ # ==== For example:
1504
1540
  #
1505
1541
  # imap.create("foo/bar")
1506
1542
  # imap.create("foo/baz")
@@ -1538,7 +1574,7 @@ module Net
1538
1574
  # servers, then folder creation (and listing, moving, etc) can lead to
1539
1575
  # errors.
1540
1576
  #
1541
- # From RFC2342[https://tools.ietf.org/html/rfc2342]:
1577
+ # From RFC2342[https://www.rfc-editor.org/rfc/rfc2342]:
1542
1578
  # >>>
1543
1579
  # <em>Although typically a server will support only a single Personal
1544
1580
  # Namespace, and a single Other User's Namespace, circumstances exist
@@ -1551,7 +1587,7 @@ module Net
1551
1587
  #
1552
1588
  # Related: #list, Namespaces, Namespace
1553
1589
  #
1554
- # ===== For example:
1590
+ # ==== For example:
1555
1591
  #
1556
1592
  # if capable?("NAMESPACE")
1557
1593
  # namespaces = imap.namespace
@@ -1565,10 +1601,10 @@ module Net
1565
1601
  # end
1566
1602
  # end
1567
1603
  #
1568
- # ===== Capabilities
1604
+ # ==== Capabilities
1569
1605
  #
1570
- # The server's capabilities must include +NAMESPACE+
1571
- # [RFC2342[https://tools.ietf.org/html/rfc2342]].
1606
+ # The server's capabilities must include either +IMAP4rev2+ or +NAMESPACE+
1607
+ # [RFC2342[https://www.rfc-editor.org/rfc/rfc2342]].
1572
1608
  def namespace
1573
1609
  synchronize do
1574
1610
  send_command("NAMESPACE")
@@ -1604,7 +1640,7 @@ module Net
1604
1640
  #
1605
1641
  # Related: #list, MailboxList
1606
1642
  #
1607
- # ===== Capabilities
1643
+ # ==== Capabilities
1608
1644
  #
1609
1645
  # The server's capabilities must include +XLIST+,
1610
1646
  # a deprecated Gmail extension (replaced by +SPECIAL-USE+).
@@ -1627,10 +1663,10 @@ module Net
1627
1663
  #
1628
1664
  # Related: #getquota, #setquota, MailboxQuotaRoot, MailboxQuota
1629
1665
  #
1630
- # ===== Capabilities
1666
+ # ==== Capabilities
1631
1667
  #
1632
1668
  # The server's capabilities must include +QUOTA+
1633
- # [RFC2087[https://tools.ietf.org/html/rfc2087]].
1669
+ # [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
1634
1670
  def getquotaroot(mailbox)
1635
1671
  synchronize do
1636
1672
  send_command("GETQUOTAROOT", mailbox)
@@ -1648,10 +1684,10 @@ module Net
1648
1684
  #
1649
1685
  # Related: #getquotaroot, #setquota, MailboxQuota
1650
1686
  #
1651
- # ===== Capabilities
1687
+ # ==== Capabilities
1652
1688
  #
1653
1689
  # The server's capabilities must include +QUOTA+
1654
- # [RFC2087[https://tools.ietf.org/html/rfc2087]].
1690
+ # [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
1655
1691
  def getquota(mailbox)
1656
1692
  synchronize do
1657
1693
  send_command("GETQUOTA", mailbox)
@@ -1666,10 +1702,10 @@ module Net
1666
1702
  #
1667
1703
  # Related: #getquota, #getquotaroot
1668
1704
  #
1669
- # ===== Capabilities
1705
+ # ==== Capabilities
1670
1706
  #
1671
1707
  # The server's capabilities must include +QUOTA+
1672
- # [RFC2087[https://tools.ietf.org/html/rfc2087]].
1708
+ # [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
1673
1709
  def setquota(mailbox, quota)
1674
1710
  if quota.nil?
1675
1711
  data = '()'
@@ -1686,10 +1722,10 @@ module Net
1686
1722
  #
1687
1723
  # Related: #getacl
1688
1724
  #
1689
- # ===== Capabilities
1725
+ # ==== Capabilities
1690
1726
  #
1691
1727
  # The server's capabilities must include +ACL+
1692
- # [RFC4314[https://tools.ietf.org/html/rfc4314]].
1728
+ # [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
1693
1729
  def setacl(mailbox, user, rights)
1694
1730
  if rights.nil?
1695
1731
  send_command("SETACL", mailbox, user, "")
@@ -1704,10 +1740,10 @@ module Net
1704
1740
  #
1705
1741
  # Related: #setacl, MailboxACLItem
1706
1742
  #
1707
- # ===== Capabilities
1743
+ # ==== Capabilities
1708
1744
  #
1709
1745
  # The server's capabilities must include +ACL+
1710
- # [RFC4314[https://tools.ietf.org/html/rfc4314]].
1746
+ # [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
1711
1747
  def getacl(mailbox)
1712
1748
  synchronize do
1713
1749
  send_command("GETACL", mailbox)
@@ -1741,7 +1777,7 @@ module Net
1741
1777
  # for +mailbox+ cannot be returned; for instance, because it
1742
1778
  # does not exist.
1743
1779
  #
1744
- # ===== Supported attributes
1780
+ # ==== Supported attributes
1745
1781
  #
1746
1782
  # +MESSAGES+:: The number of messages in the mailbox.
1747
1783
  #
@@ -1772,12 +1808,12 @@ module Net
1772
1808
  # Unsupported attributes may be requested. The attribute value will be
1773
1809
  # either an Integer or an ExtensionData object.
1774
1810
  #
1775
- # ===== For example:
1811
+ # ==== For example:
1776
1812
  #
1777
1813
  # p imap.status("inbox", ["MESSAGES", "RECENT"])
1778
1814
  # #=> {"RECENT"=>0, "MESSAGES"=>44}
1779
1815
  #
1780
- # ===== Capabilities
1816
+ # ==== Capabilities
1781
1817
  #
1782
1818
  # +SIZE+ requires the server's capabilities to include either +IMAP4rev2+ or
1783
1819
  # <tt>STATUS=SIZE</tt>
@@ -1817,7 +1853,7 @@ module Net
1817
1853
  # not exist (it is not created automatically), or if the flags,
1818
1854
  # date_time, or message arguments contain errors.
1819
1855
  #
1820
- # ===== Capabilities
1856
+ # ==== Capabilities
1821
1857
  #
1822
1858
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
1823
1859
  # supported and the destination supports persistent UIDs, the server's
@@ -1866,129 +1902,492 @@ module Net
1866
1902
  #
1867
1903
  # Related: #close
1868
1904
  #
1869
- # ===== Capabilities
1905
+ # ==== Capabilities
1870
1906
  #
1871
- # The server's capabilities must include +UNSELECT+
1872
- # [RFC3691[https://tools.ietf.org/html/rfc3691]].
1907
+ # The server's capabilities must include either +IMAP4rev2+ or +UNSELECT+
1908
+ # [RFC3691[https://www.rfc-editor.org/rfc/rfc3691]].
1873
1909
  def unselect
1874
1910
  send_command("UNSELECT")
1875
1911
  end
1876
1912
 
1913
+ # call-seq:
1914
+ # expunge -> array of message sequence numbers
1915
+ # expunge -> VanishedData of UIDs
1916
+ #
1877
1917
  # Sends an {EXPUNGE command [IMAP4rev1 §6.4.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.3]
1878
- # Sends a EXPUNGE command to permanently remove from the currently
1879
- # selected mailbox all messages that have the \Deleted flag set.
1918
+ # to permanently remove all messages with the +\Deleted+ flag from the
1919
+ # currently selected mailbox.
1920
+ #
1921
+ # Returns either an array of expunged message <em>sequence numbers</em> or
1922
+ # (when the appropriate capability is enabled) VanishedData of expunged
1923
+ # UIDs. Previously unhandled +EXPUNGE+ or +VANISHED+ responses are merged
1924
+ # with the direct response to this command. <tt>VANISHED (EARLIER)</tt>
1925
+ # responses will _not_ be merged.
1926
+ #
1927
+ # When no messages have been expunged, an empty array is returned,
1928
+ # regardless of which extensions are enabled. In a future release, an empty
1929
+ # VanishedData may be returned, based on the currently enabled extensions.
1880
1930
  #
1881
1931
  # Related: #uid_expunge
1932
+ #
1933
+ # ==== Capabilities
1934
+ #
1935
+ # When either QRESYNC[https://www.rfc-editor.org/rfc/rfc7162] or
1936
+ # UIDONLY[https://www.rfc-editor.org/rfc/rfc9586] are enabled, #expunge
1937
+ # returns VanishedData, which contains UIDs---<em>not message sequence
1938
+ # numbers</em>.
1882
1939
  def expunge
1883
- synchronize do
1884
- send_command("EXPUNGE")
1885
- clear_responses("EXPUNGE")
1886
- end
1940
+ expunge_internal("EXPUNGE")
1887
1941
  end
1888
1942
 
1943
+ # call-seq:
1944
+ # uid_expunge{uid_set) -> array of message sequence numbers
1945
+ # uid_expunge{uid_set) -> VanishedData of UIDs
1946
+ #
1889
1947
  # Sends a {UID EXPUNGE command [RFC4315 §2.1]}[https://www.rfc-editor.org/rfc/rfc4315#section-2.1]
1890
1948
  # {[IMAP4rev2 §6.4.9]}[https://www.rfc-editor.org/rfc/rfc9051#section-6.4.9]
1891
1949
  # to permanently remove all messages that have both the <tt>\\Deleted</tt>
1892
1950
  # flag set and a UID that is included in +uid_set+.
1893
1951
  #
1952
+ # Returns the same result type as #expunge.
1953
+ #
1894
1954
  # By using #uid_expunge instead of #expunge when resynchronizing with
1895
1955
  # the server, the client can ensure that it does not inadvertantly
1896
1956
  # remove any messages that have been marked as <tt>\\Deleted</tt> by other
1897
1957
  # clients between the time that the client was last connected and
1898
1958
  # the time the client resynchronizes.
1899
1959
  #
1900
- # *Note:*
1901
- # >>>
1902
- # Although the command takes a set of UIDs for its argument, the
1903
- # server still returns regular EXPUNGE responses, which contain
1904
- # a <em>sequence number</em>. These will be deleted from
1905
- # #responses and this method returns them as an array of
1906
- # <em>sequence number</em> integers.
1907
- #
1908
1960
  # Related: #expunge
1909
1961
  #
1910
- # ===== Capabilities
1962
+ # ==== Capabilities
1911
1963
  #
1912
- # The server's capabilities must include +UIDPLUS+
1964
+ # The server's capabilities must include either +IMAP4rev2+ or +UIDPLUS+
1913
1965
  # [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]].
1966
+ #
1967
+ # Otherwise, #uid_expunge is updated by extensions in the same way as
1968
+ # #expunge.
1914
1969
  def uid_expunge(uid_set)
1915
- synchronize do
1916
- send_command("UID EXPUNGE", MessageSet.new(uid_set))
1917
- clear_responses("EXPUNGE")
1918
- end
1970
+ expunge_internal("UID EXPUNGE", SequenceSet.new(uid_set))
1919
1971
  end
1920
1972
 
1921
- # Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
1922
- # to search the mailbox for messages that match the given searching
1923
- # criteria, and returns message sequence numbers. +keys+ can either be a
1924
- # string holding the entire search string, or a single-dimension array of
1925
- # search keywords and arguments.
1973
+ # :call-seq:
1974
+ # search(criteria, charset = nil) -> result
1975
+ # search(criteria, charset: nil, return: nil) -> result
1926
1976
  #
1927
- # Returns a SearchResult object. SearchResult inherits from Array (for
1928
- # backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
1929
- # capability has been enabled.
1977
+ # Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
1978
+ # to search the mailbox for messages that match the given search +criteria+,
1979
+ # and returns either a SearchResult or an ESearchResult. SearchResult
1980
+ # inherits from Array (for backward compatibility) but adds
1981
+ # SearchResult#modseq when the +CONDSTORE+ capability has been enabled.
1982
+ # ESearchResult also implements {#to_a}[rdoc-ref:ESearchResult#to_a], for
1983
+ # compatibility with SearchResult.
1984
+ #
1985
+ # +criteria+ is one or more search keys and their arguments, which may be
1986
+ # provided as an array or a string.
1987
+ # See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
1988
+ # and {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
1989
+ #
1990
+ # +return+ options control what kind of information is returned about
1991
+ # messages matching the search +criteria+. Specifying +return+ should force
1992
+ # the server to return an ESearchResult instead of a SearchResult, but some
1993
+ # servers disobey this requirement. <em>Requires an extended search
1994
+ # capability, such as +ESEARCH+ or +IMAP4rev2+.</em>
1995
+ # See {"Argument translation"}[rdoc-ref:#search@Argument+translation] and
1996
+ # {"Supported return options"}[rdoc-ref:#search@Supported+return+options],
1997
+ # below.
1998
+ #
1999
+ # +charset+ is the name of the {registered character
2000
+ # set}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
2001
+ # used by strings in the search +criteria+. When +charset+ isn't specified,
2002
+ # either <tt>"US-ASCII"</tt> or <tt>"UTF-8"</tt> is assumed, depending on
2003
+ # the server's capabilities.
2004
+ #
2005
+ # _NOTE:_ Return options and charset may be sent as part of +criteria+. Do
2006
+ # not use the +return+ or +charset+ arguments when either return options or
2007
+ # charset are embedded in +criteria+.
1930
2008
  #
1931
2009
  # Related: #uid_search
1932
2010
  #
1933
- # ===== Search criteria
2011
+ # ==== For example:
2012
+ #
2013
+ # imap.search(["SUBJECT", "hello", "NOT", "SEEN"])
2014
+ # #=> [1, 6, 7, 8]
1934
2015
  #
1935
- # For a full list of search criteria,
2016
+ # The following assumes the server supports +ESEARCH+ and +CONDSTORE+:
2017
+ #
2018
+ # result = imap.uid_search(["UID", 12345.., "MODSEQ", 620_162_338],
2019
+ # return: %w(all count min max))
2020
+ # # => #<data Net::IMAP::ESearchResult tag="RUBY0123", uid=true,
2021
+ # # data=[["ALL", Net::IMAP::SequenceSet["12346:12349,22222:22230"]],
2022
+ # # ["COUNT", 13], ["MIN", 12346], ["MAX", 22230],
2023
+ # # ["MODSEQ", 917162488]]>
2024
+ # result.to_a # => [12346, 12347, 12348, 12349, 22222, 22223, 22224,
2025
+ # # 22225, 22226, 22227, 22228, 22229, 22230]
2026
+ # result.uid? # => true
2027
+ # result.count # => 13
2028
+ # result.min # => 12346
2029
+ # result.max # => 22230
2030
+ # result.modseq # => 917162488
2031
+ #
2032
+ # Using +return+ options to limit the result to only min, max, and count:
2033
+ #
2034
+ # result = imap.uid_search(["UID", 12345..,], return: %w(count min max))
2035
+ # # => #<data Net::IMAP::ESearchResult tag="RUBY0124", uid=true,
2036
+ # # data=[["COUNT", 13], ["MIN", 12346], ["MAX", 22230]]>
2037
+ # result.to_a # => []
2038
+ # result.count # => 13
2039
+ # result.min # => 12346
2040
+ # result.max # => 22230
2041
+ #
2042
+ # Return options and charset may be sent as keyword args or embedded in the
2043
+ # +criteria+ arg, but they must be in the correct order: <tt>"RETURN (...)
2044
+ # CHARSET ... criteria..."</tt>. The following searches
2045
+ # send the exact same command to the server:
2046
+ #
2047
+ # # Return options and charset as keyword arguments (preferred)
2048
+ # imap.search(%w(OR UNSEEN FLAGGED), return: %w(MIN MAX), charset: "UTF-8")
2049
+ # # Embedding return and charset in the criteria array
2050
+ # imap.search(["RETURN", %w(MIN MAX), "CHARSET", "UTF-8", *%w(OR UNSEEN FLAGGED)])
2051
+ # # Embedding return and charset in the criteria string
2052
+ # imap.search("RETURN (MIN MAX) CHARSET UTF-8 OR UNSEEN FLAGGED")
2053
+ #
2054
+ # Sending charset as the second positional argument is supported for
2055
+ # backward compatibility. Future versions may print a deprecation warning:
2056
+ # imap.search(%w(OR UNSEEN FLAGGED), "UTF-8", return: %w(MIN MAX))
2057
+ #
2058
+ # ==== Argument translation
2059
+ #
2060
+ # [+return+ options]
2061
+ # Must be an Array. Return option names may be either strings or symbols.
2062
+ # +Range+ elements which begin and end with negative integers are encoded
2063
+ # for use with +PARTIAL+--any other ranges are converted to SequenceSet.
2064
+ # Unlike +criteria+, other return option arguments are not automatically
2065
+ # converted to SequenceSet.
2066
+ #
2067
+ # [When +criteria+ is an Array]
2068
+ # When the array begins with <tt>"RETURN"</tt> (case insensitive), the
2069
+ # second array element is translated like the +return+ parameter (as
2070
+ # described above).
2071
+ #
2072
+ # Every other member is a +SEARCH+ command argument:
2073
+ # [SequenceSet]
2074
+ # Encoded as an \IMAP +sequence-set+ with SequenceSet#valid_string.
2075
+ # [Set, Range, <tt>-1</tt>, +:*+, responds to +#to_sequence_set+]
2076
+ # Converted to SequenceSet for validation and encoding.
2077
+ # [nested sequence-set +Array+]
2078
+ # When every element in a nested array is one of the above types, a
2079
+ # positive +Integer+, a sequence-set formatted +String+, or a deeply
2080
+ # nested +Array+ of these same types, the array will be converted to
2081
+ # SequenceSet for validation and encoding.
2082
+ # [Any other nested +Array+]
2083
+ # Otherwise, a nested array is encoded as a parenthesized list, to
2084
+ # combine multiple search keys (e.g., for use with +OR+ and +NOT+).
2085
+ # [+String+]
2086
+ # Sent verbatim when it is a valid \IMAP +atom+, and encoded as an \IMAP
2087
+ # +quoted+ or +literal+ string otherwise. Every standard search key
2088
+ # name is a valid \IMAP +atom+ and every standard search key string
2089
+ # argument is an +astring+ which may be encoded as +atom+, +quoted+, or
2090
+ # +literal+.
2091
+ #
2092
+ # *Note:* <tt>*</tt> is not a valid \IMAP +atom+ character. Any string
2093
+ # containing <tt>*</tt> will be encoded as a +quoted+ string, _not_ a
2094
+ # +sequence-set+.
2095
+ # [+Integer+ (except for <tt>-1</tt>)]
2096
+ # Encoded using +#to_s+.
2097
+ # [+Date+]
2098
+ # Encoded as an \IMAP date (see ::encode_date).
2099
+ #
2100
+ # [When +criteria+ is a String]
2101
+ # +criteria+ will be sent directly to the server <em>without any
2102
+ # validation or encoding</em>.
2103
+ #
2104
+ # <em>*WARNING:* This is vulnerable to injection attacks when external
2105
+ # inputs are used.</em>
2106
+ #
2107
+ # ==== Supported return options
2108
+ #
2109
+ # For full definitions of the standard return options and return data, see
2110
+ # the relevant RFCs.
2111
+ #
2112
+ # [+ALL+]
2113
+ # Returns ESearchResult#all with a SequenceSet of all matching sequence
2114
+ # numbers or UIDs. This is the default, when return options are empty.
2115
+ #
2116
+ # For compatibility with SearchResult, ESearchResult#to_a returns an
2117
+ # Array of message sequence numbers or UIDs.
2118
+ #
2119
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2120
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2121
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2122
+ #
2123
+ # [+COUNT+]
2124
+ # Returns ESearchResult#count with the number of matching messages.
2125
+ #
2126
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2127
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2128
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2129
+ #
2130
+ # [+MAX+]
2131
+ # Returns ESearchResult#max with the highest matching sequence number or
2132
+ # UID.
2133
+ #
2134
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2135
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2136
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2137
+ #
2138
+ # [+MIN+]
2139
+ # Returns ESearchResult#min with the lowest matching sequence number or
2140
+ # UID.
2141
+ #
2142
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2143
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2144
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2145
+ #
2146
+ # [+PARTIAL+ _range_]
2147
+ # Returns ESearchResult#partial with a SequenceSet of a subset of
2148
+ # matching sequence numbers or UIDs, as selected by _range_. As with
2149
+ # sequence numbers, the first result is +1+: <tt>1..500</tt> selects the
2150
+ # first 500 search results (in mailbox order), <tt>501..1000</tt> the
2151
+ # second 500, and so on. _range_ may also be negative: <tt>-500..-1</tt>
2152
+ # selects the last 500 search results.
2153
+ #
2154
+ # <em>Requires either the <tt>CONTEXT=SEARCH</tt> or +PARTIAL+ capabability.</em>
2155
+ # {[RFC5267]}[https://rfc-editor.org/rfc/rfc5267]
2156
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2157
+ #
2158
+ # ===== +MODSEQ+ return data
2159
+ #
2160
+ # ESearchResult#modseq return data does not have a corresponding return
2161
+ # option. Instead, it is returned if the +MODSEQ+ search key is used or
2162
+ # when the +CONDSTORE+ extension is enabled for the selected mailbox.
2163
+ # See [{RFC4731 §3.2}[https://www.rfc-editor.org/rfc/rfc4731#section-3.2]]
2164
+ # or [{RFC7162 §2.1.5}[https://www.rfc-editor.org/rfc/rfc7162#section-3.1.5]].
2165
+ #
2166
+ # ===== +RFC4466+ compatible extensions
2167
+ #
2168
+ # {RFC4466 §2.6}[https://www.rfc-editor.org/rfc/rfc4466.html#section-2.6]
2169
+ # defines standard syntax for search extensions. Net::IMAP allows sending
2170
+ # unsupported search return options and will parse unsupported search
2171
+ # extensions' return values into ExtensionData. Please note that this is an
2172
+ # intentionally _unstable_ API. Future releases may return different
2173
+ # (incompatible) objects, <em>without deprecation or warning</em>.
2174
+ #
2175
+ # ==== Search keys
2176
+ #
2177
+ # For full definitions of the standard search +criteria+,
1936
2178
  # see [{IMAP4rev1 §6.4.4}[https://www.rfc-editor.org/rfc/rfc3501.html#section-6.4.4]],
1937
2179
  # or [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]],
1938
2180
  # in addition to documentation for
1939
- # any [CAPABILITIES[https://www.iana.org/assignments/imap-capabilities/imap-capabilities.xhtml]]
1940
- # reported by #capabilities which may define additional search filters, e.g:
2181
+ # any #capabilities which may define additional search filters, such as
1941
2182
  # +CONDSTORE+, +WITHIN+, +FILTERS+, <tt>SEARCH=FUZZY</tt>, +OBJECTID+, or
1942
- # +SAVEDATE+. The following are some common search criteria:
2183
+ # +SAVEDATE+.
1943
2184
  #
1944
- # <message set>:: a set of message sequence numbers. "<tt>,</tt>" indicates
1945
- # an interval, "+:+" indicates a range. For instance,
1946
- # "<tt>2,10:12,15</tt>" means "<tt>2,10,11,12,15</tt>".
2185
+ # With the exception of <em>sequence-set</em> and <em>parenthesized
2186
+ # list</em>, all search keys are composed of prefix label with zero or more
2187
+ # arguments. The number and type of arguments is specific to each search
2188
+ # key.
1947
2189
  #
1948
- # BEFORE <date>:: messages with an internal date strictly before
1949
- # <b><date></b>. The date argument has a format similar
1950
- # to <tt>8-Aug-2002</tt>, and can be formatted using
1951
- # Net::IMAP.format_date.
2190
+ # ===== Search keys that match all messages
1952
2191
  #
1953
- # BODY <string>:: messages that contain <string> within their body.
2192
+ # [+ALL+]
2193
+ # The default initial key. Matches every message in the mailbox.
1954
2194
  #
1955
- # CC <string>:: messages containing <string> in their CC field.
2195
+ # [+SAVEDATESUPPORTED+]
2196
+ # Matches every message in the mailbox when the mailbox supports the save
2197
+ # date attribute. Otherwise, it matches no messages.
1956
2198
  #
1957
- # FROM <string>:: messages that contain <string> in their FROM field.
2199
+ # <em>Requires +SAVEDATE+ capability</em>.
2200
+ # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
1958
2201
  #
1959
- # NEW:: messages with the \Recent, but not the \Seen, flag set.
2202
+ # ===== Sequence set search keys
1960
2203
  #
1961
- # NOT <search-key>:: negate the following search key.
2204
+ # [_sequence-set_]
2205
+ # Matches messages with message sequence numbers in _sequence-set_.
1962
2206
  #
1963
- # OR <search-key> <search-key>:: "or" two search keys together.
2207
+ # _Note:_ this search key has no label.
1964
2208
  #
1965
- # ON <date>:: messages with an internal date exactly equal to <date>,
1966
- # which has a format similar to 8-Aug-2002.
2209
+ # <em>+UIDONLY+ must *not* be enabled.</em>
2210
+ # {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.html]
1967
2211
  #
1968
- # SINCE <date>:: messages with an internal date on or after <date>.
2212
+ # [+UID+ _sequence-set_]
2213
+ # Matches messages with a UID in _sequence-set_.
1969
2214
  #
1970
- # SUBJECT <string>:: messages with <string> in their subject.
2215
+ # ===== Compound search keys
1971
2216
  #
1972
- # TO <string>:: messages with <string> in their TO field.
2217
+ # [(_search-key_ _search-key_...)]
2218
+ # Combines one or more _search-key_ arguments to match
2219
+ # messages which match all contained search keys. Useful for +OR+, +NOT+,
2220
+ # and other search keys with _search-key_ arguments.
1973
2221
  #
1974
- # ===== For example:
2222
+ # _Note:_ this search key has no label.
1975
2223
  #
1976
- # p imap.search(["SUBJECT", "hello", "NOT", "NEW"])
1977
- # #=> [1, 6, 7, 8]
2224
+ # [+OR+ _search-key_ _search-key_]
2225
+ # Matches messages which match either _search-key_ argument.
2226
+ #
2227
+ # [+NOT+ _search-key_]
2228
+ # Matches messages which do not match _search-key_.
2229
+ #
2230
+ # [+FUZZY+ _search-key_]
2231
+ # Uses fuzzy matching for the specified search key.
2232
+ #
2233
+ # <em>Requires <tt>SEARCH=FUZZY</tt> capability.</em>
2234
+ # {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
2235
+ #
2236
+ # ===== Flags search keys
2237
+ #
2238
+ # [+ANSWERED+, +UNANSWERED+]
2239
+ # Matches messages with or without the <tt>\\Answered</tt> flag.
2240
+ # [+DELETED+, +UNDELETED+]
2241
+ # Matches messages with or without the <tt>\\Deleted</tt> flag.
2242
+ # [+DRAFT+, +UNDRAFT+]
2243
+ # Matches messages with or without the <tt>\\Draft</tt> flag.
2244
+ # [+FLAGGED+, +UNFLAGGED+]
2245
+ # Matches messages with or without the <tt>\\Flagged</tt> flag.
2246
+ # [+SEEN+, +UNSEEN+]
2247
+ # Matches messages with or without the <tt>\\Seen</tt> flag.
2248
+ # [+KEYWORD+ _keyword_, +UNKEYWORD+ _keyword_]
2249
+ # Matches messages with or without the specified _keyword_.
2250
+ #
2251
+ # [+RECENT+, +UNRECENT+]
2252
+ # Matches messages with or without the <tt>\\Recent</tt> flag.
2253
+ #
2254
+ # *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
2255
+ # [+NEW+]
2256
+ # Equivalent to <tt>(RECENT UNSEEN)</tt>.
2257
+ #
2258
+ # *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
2259
+ #
2260
+ # ===== Header field substring search keys
2261
+ #
2262
+ # [+BCC+ _substring_]
2263
+ # Matches when _substring_ is in the envelope's +BCC+ field.
2264
+ # [+CC+ _substring_]
2265
+ # Matches when _substring_ is in the envelope's +CC+ field.
2266
+ # [+FROM+ _substring_]
2267
+ # Matches when _substring_ is in the envelope's +FROM+ field.
2268
+ # [+SUBJECT+ _substring_]
2269
+ # Matches when _substring_ is in the envelope's +SUBJECT+ field.
2270
+ # [+TO+ _substring_]
2271
+ # Matches when _substring_ is in the envelope's +TO+ field.
2272
+ #
2273
+ # [+HEADER+ _field_ _substring_]
2274
+ # Matches when _substring_ is in the specified header _field_.
2275
+ #
2276
+ # ===== Body text search keys
2277
+ # [+BODY+ _string_]
2278
+ # Matches when _string_ is in the body of the message.
2279
+ # Does not match on header fields.
2280
+ #
2281
+ # The server _may_ use flexible matching, rather than simple substring
2282
+ # matches. For example, this may use stemming or match only full words.
2283
+ #
2284
+ # [+TEXT+ _string_]
2285
+ # Matches when _string_ is in the header or body of the message.
2286
+ #
2287
+ # The server _may_ use flexible matching, rather than simple substring
2288
+ # matches. For example, this may use stemming or match only full words.
2289
+ #
2290
+ # ===== Date/Time search keys
2291
+ #
2292
+ # [+SENTBEFORE+ _date_]
2293
+ # [+SENTON+ _date_]
2294
+ # [+SENTSINCE+ _date_]
2295
+ # Matches when the +Date+ header is earlier than, on, or later than _date_.
2296
+ #
2297
+ # [+BEFORE+ _date_]
2298
+ # [+ON+ _date_]
2299
+ # [+SINCE+ _date_]
2300
+ # Matches when the +INTERNALDATE+ is earlier than, on, or later than
2301
+ # _date_.
2302
+ #
2303
+ # [+OLDER+ _interval_]
2304
+ # [+YOUNGER+ _interval_]
2305
+ # Matches when the +INTERNALDATE+ is more/less than _interval_ seconds ago.
2306
+ #
2307
+ # <em>Requires +WITHIN+ capability</em>.
2308
+ # {[RFC5032]}[https://www.rfc-editor.org/rfc/rfc5032.html]
2309
+ #
2310
+ # [+SAVEDBEFORE+ _date_]
2311
+ # [+SAVEDON+ _date_]
2312
+ # [+SAVEDSINCE+ _date_]
2313
+ # Matches when the save date is earlier than, on, or later than _date_.
2314
+ #
2315
+ # <em>Requires +SAVEDATE+ capability.</em>
2316
+ # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
2317
+ #
2318
+ # ===== Other message attribute search keys
2319
+ #
2320
+ # [+SMALLER+ _bytes_]
2321
+ # [+LARGER+ _bytes_]
2322
+ # Matches when +RFC822.SIZE+ is smaller or larger than _bytes_.
2323
+ #
2324
+ # [+ANNOTATION+ _entry_ _attr_ _value_]
2325
+ # Matches messages that have annotations with entries matching _entry_,
2326
+ # attributes matching _attr_, and _value_ in the attribute's values.
2327
+ #
2328
+ # <em>Requires +ANNOTATE-EXPERIMENT-1+ capability</em>.
2329
+ # {[RFC5257]}[https://www.rfc-editor.org/rfc/rfc5257.html].
2330
+ #
2331
+ # [+FILTER+ _filter_]
2332
+ # References a _filter_ that is stored on the server and matches all
2333
+ # messages which would be matched by that filter's search criteria.
2334
+ #
2335
+ # <em>Requires +FILTERS+ capability</em>.
2336
+ # {[RFC5466]}[https://www.rfc-editor.org/rfc/rfc5466.html#section-3.1]
2337
+ #
2338
+ # [+MODSEQ+ _modseq_]
2339
+ # Matches when +MODSEQ+ is greater than or equal to _modseq_.
2340
+ #
2341
+ # <em>Requires +CONDSTORE+ capability</em>.
2342
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
2343
+ #
2344
+ # [+MODSEQ+ _entry_ _entry-type_ _modseq_]
2345
+ # Matches when a specific metadata _entry_ has been updated since
2346
+ # _modseq_.
2347
+ #
2348
+ # For flags, the corresponding _entry_ name is
2349
+ # <tt>"/flags/#{flag_name}"</tt>, where _flag_name_ includes the
2350
+ # <tt>\\</tt> prefix. _entry-type_ can be one of <tt>"shared"</tt>,
2351
+ # <tt>"priv"</tt> (private), or <tt>"all"</tt>.
2352
+ #
2353
+ # <em>Requires +CONDSTORE+ capability</em>.
2354
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
2355
+ #
2356
+ # [+EMAILID+ _objectid_]
2357
+ # [+THREADID+ _objectid_]
2358
+ # Matches when +EMAILID+/+THREADID+ is equal to _objectid_
2359
+ # (substring matches are not supported).
2360
+ #
2361
+ # <em>Requires +OBJECTID+ capability</em>.
2362
+ # {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-6]
2363
+ #
2364
+ # ==== Capabilities
2365
+ #
2366
+ # Return options should only be specified when the server supports
2367
+ # +IMAP4rev2+ or an extension that allows them, such as +ESEARCH+
2368
+ # [RFC4731[https://rfc-editor.org/rfc/rfc4731#section-3.1]].
1978
2369
  #
1979
- # ===== Capabilities
2370
+ # When +IMAP4rev2+ is enabled, or when the server supports +IMAP4rev2+ but
2371
+ # not +IMAP4rev1+, ESearchResult is always returned instead of SearchResult.
1980
2372
  #
1981
- # If [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html]] is supported
2373
+ # If CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html] is supported
1982
2374
  # and enabled for the selected mailbox, a non-empty SearchResult will
1983
2375
  # include a +MODSEQ+ value.
1984
2376
  # imap.select("mbox", condstore: true)
1985
- # result = imap.search(["SUBJECT", "hi there", "not", "new")
2377
+ # result = imap.search(["SUBJECT", "hi there", "not", "new"])
1986
2378
  # #=> Net::IMAP::SearchResult[1, 6, 7, 8, modseq: 5594]
1987
2379
  # result.modseq # => 5594
1988
- def search(keys, charset = nil)
1989
- return search_internal("SEARCH", keys, charset)
2380
+ #
2381
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2382
+ # the +SEARCH+ command is prohibited. Use #uid_search instead.
2383
+ def search(...)
2384
+ search_internal("SEARCH", ...)
1990
2385
  end
1991
2386
 
2387
+ # :call-seq:
2388
+ # uid_search(criteria, charset = nil) -> result
2389
+ # uid_search(criteria, charset: nil, return: nil) -> result
2390
+ #
1992
2391
  # Sends a {UID SEARCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
1993
2392
  # to search the mailbox for messages that match the given searching
1994
2393
  # criteria, and returns unique identifiers (<tt>UID</tt>s).
@@ -1997,9 +2396,19 @@ module Net
1997
2396
  # backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
1998
2397
  # capability has been enabled.
1999
2398
  #
2000
- # See #search for documentation of search criteria.
2001
- def uid_search(keys, charset = nil)
2002
- return search_internal("UID SEARCH", keys, charset)
2399
+ # See #search for documentation of parameters.
2400
+ #
2401
+ # ==== Capabilities
2402
+ #
2403
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2404
+ # #uid_search must be used instead of #search, and the <tt><message
2405
+ # set></tt> search criterion is prohibited. Use +ALL+ or <tt>UID
2406
+ # sequence-set</tt> instead.
2407
+ #
2408
+ # Otherwise, #uid_search is updated by extensions in the same way as
2409
+ # #search.
2410
+ def uid_search(...)
2411
+ search_internal("UID SEARCH", ...)
2003
2412
  end
2004
2413
 
2005
2414
  # :call-seq:
@@ -2008,26 +2417,21 @@ module Net
2008
2417
  # Sends a {FETCH command [IMAP4rev1 §6.4.5]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.5]
2009
2418
  # to retrieve data associated with a message in the mailbox.
2010
2419
  #
2011
- # The +set+ parameter is a number or a range between two numbers,
2012
- # or an array of those. The number is a message sequence number,
2013
- # where -1 represents a '*' for use in range notation like 100..-1
2014
- # being interpreted as '100:*'. Beware that the +exclude_end?+
2015
- # property of a Range object is ignored, and the contents of a
2016
- # range are independent of the order of the range endpoints as per
2017
- # the protocol specification, so 1...5, 5..1 and 5...1 are all
2018
- # equivalent to 1..5.
2420
+ # +set+ is the message sequence numbers to fetch, and may be any valid input
2421
+ # to {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
2422
+ # (For UIDs, use #uid_fetch instead.)
2019
2423
  #
2020
- # +attr+ is a list of attributes to fetch; see the documentation
2021
- # for FetchData for a list of valid attributes.
2424
+ # +attr+ is a list of attributes to fetch; see FetchStruct documentation for
2425
+ # a list of supported attributes.
2022
2426
  #
2023
2427
  # +changedsince+ is an optional integer mod-sequence. It limits results to
2024
2428
  # messages with a mod-sequence greater than +changedsince+.
2025
2429
  #
2026
2430
  # The return value is an array of FetchData.
2027
2431
  #
2028
- # Related: #uid_search, FetchData
2432
+ # Related: #uid_fetch, FetchData
2029
2433
  #
2030
- # ===== For example:
2434
+ # ==== For example:
2031
2435
  #
2032
2436
  # p imap.fetch(6..8, "UID")
2033
2437
  # #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
@@ -2045,39 +2449,82 @@ module Net
2045
2449
  # p data.attr["UID"]
2046
2450
  # #=> 98
2047
2451
  #
2048
- # ===== Capabilities
2452
+ # ==== Capabilities
2049
2453
  #
2050
- # Many extensions define new message +attr+ names. See FetchData for a list
2051
- # of supported extension fields.
2454
+ # Many extensions define new message +attr+ names. See FetchStruct for a
2455
+ # list of supported extension fields.
2052
2456
  #
2053
2457
  # The server's capabilities must include +CONDSTORE+
2054
- # {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2458
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
2055
2459
  # +changedsince+ argument. Using +changedsince+ implicitly enables the
2056
2460
  # +CONDSTORE+ extension.
2057
- def fetch(set, attr, mod = nil, changedsince: nil)
2058
- fetch_internal("FETCH", set, attr, mod, changedsince: changedsince)
2461
+ #
2462
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2463
+ # +FETCH+ command is prohibited. Use #uid_fetch instead.
2464
+ def fetch(...)
2465
+ fetch_internal("FETCH", ...)
2059
2466
  end
2060
2467
 
2061
2468
  # :call-seq:
2062
- # uid_fetch(set, attr, changedsince: nil) -> array of FetchData
2469
+ # uid_fetch(set, attr, changedsince: nil, partial: nil) -> array of FetchData (or UIDFetchData)
2063
2470
  #
2064
2471
  # Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2065
2472
  # to retrieve data associated with a message in the mailbox.
2066
2473
  #
2067
- # Similar to #fetch, but the +set+ parameter contains unique identifiers
2068
- # instead of message sequence numbers.
2474
+ # +set+ is the message UIDs to fetch, and may be any valid input to
2475
+ # {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
2476
+ # (For message sequence numbers, use #fetch instead.)
2069
2477
  #
2478
+ # +attr+ behaves the same as with #fetch.
2070
2479
  # >>>
2071
2480
  # *Note:* Servers _MUST_ implicitly include the +UID+ message data item as
2072
2481
  # part of any +FETCH+ response caused by a +UID+ command, regardless of
2073
2482
  # whether a +UID+ was specified as a message data item to the +FETCH+.
2074
2483
  #
2484
+ # +changedsince+ (optional) behaves the same as with #fetch.
2485
+ #
2486
+ # +partial+ is an optional range to limit the number of results returned.
2487
+ # It's useful when +set+ contains an unknown number of messages.
2488
+ # <tt>1..500</tt> returns the first 500 messages in +set+ (in mailbox
2489
+ # order), <tt>501..1000</tt> the second 500, and so on. +partial+ may also
2490
+ # be negative: <tt>-500..-1</tt> selects the last 500 messages in +set+.
2491
+ # <em>Requires the +PARTIAL+ capabability.</em>
2492
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2493
+ #
2494
+ # For example:
2495
+ #
2496
+ # # Without partial, the size of the results may be unknown beforehand:
2497
+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS))
2498
+ # # ... maybe wait for a long time ... and allocate a lot of memory ...
2499
+ # results.size # => 0..2**32-1
2500
+ # process results # may also take a long time and use a lot of memory...
2501
+ #
2502
+ # # Using partial, the results may be paginated:
2503
+ # loop do
2504
+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS),
2505
+ # partial: 1..500)
2506
+ # # fetch should return quickly and allocate little memory
2507
+ # results.size # => 0..500
2508
+ # break if results.empty?
2509
+ # next_uid_to_fetch = results.last.uid + 1
2510
+ # process results
2511
+ # end
2512
+ #
2075
2513
  # Related: #fetch, FetchData
2076
2514
  #
2077
- # ===== Capabilities
2078
- # Same as #fetch.
2079
- def uid_fetch(set, attr, mod = nil, changedsince: nil)
2080
- fetch_internal("UID FETCH", set, attr, mod, changedsince: changedsince)
2515
+ # ==== Capabilities
2516
+ #
2517
+ # The server's capabilities must include +PARTIAL+
2518
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394] in order to use the
2519
+ # +partial+ argument.
2520
+ #
2521
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2522
+ # #uid_fetch must be used instead of #fetch, and UIDFetchData will be
2523
+ # returned instead of FetchData.
2524
+ #
2525
+ # Otherwise, #uid_fetch is updated by extensions in the same way as #fetch.
2526
+ def uid_fetch(...)
2527
+ fetch_internal("UID FETCH", ...)
2081
2528
  end
2082
2529
 
2083
2530
  # :call-seq:
@@ -2108,27 +2555,30 @@ module Net
2108
2555
  #
2109
2556
  # Related: #uid_store
2110
2557
  #
2111
- # ===== For example:
2558
+ # ==== For example:
2112
2559
  #
2113
2560
  # p imap.store(6..8, "+FLAGS", [:Deleted])
2114
2561
  # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2115
2562
  # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2116
2563
  # #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
2117
2564
  #
2118
- # ===== Capabilities
2565
+ # ==== Capabilities
2119
2566
  #
2120
2567
  # Extensions may define new data items to be used with #store.
2121
2568
  #
2122
2569
  # The server's capabilities must include +CONDSTORE+
2123
- # {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2570
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
2124
2571
  # +unchangedsince+ argument. Using +unchangedsince+ implicitly enables the
2125
2572
  # +CONDSTORE+ extension.
2573
+ #
2574
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2575
+ # +STORE+ command is prohibited. Use #uid_store instead.
2126
2576
  def store(set, attr, flags, unchangedsince: nil)
2127
2577
  store_internal("STORE", set, attr, flags, unchangedsince: unchangedsince)
2128
2578
  end
2129
2579
 
2130
2580
  # :call-seq:
2131
- # uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData
2581
+ # uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData (or UIDFetchData)
2132
2582
  #
2133
2583
  # Sends a {UID STORE command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2134
2584
  # to alter data associated with messages in the mailbox, in particular their
@@ -2139,8 +2589,13 @@ module Net
2139
2589
  #
2140
2590
  # Related: #store
2141
2591
  #
2142
- # ===== Capabilities
2143
- # Same as #store.
2592
+ # ==== Capabilities
2593
+ #
2594
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2595
+ # #uid_store must be used instead of #store, and UIDFetchData will be
2596
+ # returned instead of FetchData.
2597
+ #
2598
+ # Otherwise, #uid_store is updated by extensions in the same way as #store.
2144
2599
  def uid_store(set, attr, flags, unchangedsince: nil)
2145
2600
  store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince)
2146
2601
  end
@@ -2152,13 +2607,16 @@ module Net
2152
2607
  #
2153
2608
  # Related: #uid_copy
2154
2609
  #
2155
- # ===== Capabilities
2610
+ # ==== Capabilities
2156
2611
  #
2157
2612
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2158
2613
  # supported, the server's response should include a +COPYUID+ response code
2159
2614
  # with UIDPlusData. This will report the UIDVALIDITY of the destination
2160
2615
  # mailbox, the UID set of the source messages, and the assigned UID set of
2161
2616
  # the moved messages.
2617
+ #
2618
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2619
+ # +COPY+ command is prohibited. Use #uid_copy instead.
2162
2620
  def copy(set, mailbox)
2163
2621
  copy_internal("COPY", set, mailbox)
2164
2622
  end
@@ -2169,9 +2627,12 @@ module Net
2169
2627
  #
2170
2628
  # Similar to #copy, but +set+ contains unique identifiers.
2171
2629
  #
2172
- # ===== Capabilities
2630
+ # ==== Capabilities
2631
+ #
2632
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] in enabled,
2633
+ # #uid_copy must be used instead of #copy.
2173
2634
  #
2174
- # +UIDPLUS+ affects #uid_copy the same way it affects #copy.
2635
+ # Otherwise, #uid_copy is updated by extensions in the same way as #copy.
2175
2636
  def uid_copy(set, mailbox)
2176
2637
  copy_internal("UID COPY", set, mailbox)
2177
2638
  end
@@ -2184,10 +2645,10 @@ module Net
2184
2645
  #
2185
2646
  # Related: #uid_move
2186
2647
  #
2187
- # ===== Capabilities
2648
+ # ==== Capabilities
2188
2649
  #
2189
- # The server's capabilities must include +MOVE+
2190
- # [RFC6851[https://tools.ietf.org/html/rfc6851]].
2650
+ # The server's capabilities must include either +IMAP4rev2+ or +MOVE+
2651
+ # [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
2191
2652
  #
2192
2653
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2193
2654
  # supported, the server's response should include a +COPYUID+ response code
@@ -2195,6 +2656,8 @@ module Net
2195
2656
  # mailbox, the UID set of the source messages, and the assigned UID set of
2196
2657
  # the moved messages.
2197
2658
  #
2659
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2660
+ # +MOVE+ command is prohibited. Use #uid_move instead.
2198
2661
  def move(set, mailbox)
2199
2662
  copy_internal("MOVE", set, mailbox)
2200
2663
  end
@@ -2208,11 +2671,15 @@ module Net
2208
2671
  #
2209
2672
  # Related: #move
2210
2673
  #
2211
- # ===== Capabilities
2674
+ # ==== Capabilities
2675
+ #
2676
+ # The server's capabilities must include either +IMAP4rev2+ or +MOVE+
2677
+ # [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
2212
2678
  #
2213
- # Same as #move: The server's capabilities must include +MOVE+
2214
- # [RFC6851[https://tools.ietf.org/html/rfc6851]]. +UIDPLUS+ also affects
2215
- # #uid_move the same way it affects #move.
2679
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2680
+ # #uid_move must be used instead of #move.
2681
+ #
2682
+ # Otherwise, #uid_move is updated by extensions in the same way as #move.
2216
2683
  def uid_move(set, mailbox)
2217
2684
  copy_internal("UID MOVE", set, mailbox)
2218
2685
  end
@@ -2228,17 +2695,17 @@ module Net
2228
2695
  #
2229
2696
  # Related: #uid_sort, #search, #uid_search, #thread, #uid_thread
2230
2697
  #
2231
- # ===== For example:
2698
+ # ==== For example:
2232
2699
  #
2233
2700
  # p imap.sort(["FROM"], ["ALL"], "US-ASCII")
2234
2701
  # #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
2235
2702
  # p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
2236
2703
  # #=> [6, 7, 8, 1]
2237
2704
  #
2238
- # ===== Capabilities
2705
+ # ==== Capabilities
2239
2706
  #
2240
2707
  # The server's capabilities must include +SORT+
2241
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2708
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2242
2709
  def sort(sort_keys, search_keys, charset)
2243
2710
  return sort_internal("SORT", sort_keys, search_keys, charset)
2244
2711
  end
@@ -2250,10 +2717,10 @@ module Net
2250
2717
  #
2251
2718
  # Related: #sort, #search, #uid_search, #thread, #uid_thread
2252
2719
  #
2253
- # ===== Capabilities
2720
+ # ==== Capabilities
2254
2721
  #
2255
2722
  # The server's capabilities must include +SORT+
2256
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2723
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2257
2724
  def uid_sort(sort_keys, search_keys, charset)
2258
2725
  return sort_internal("UID SORT", sort_keys, search_keys, charset)
2259
2726
  end
@@ -2275,10 +2742,10 @@ module Net
2275
2742
  #
2276
2743
  # Related: #uid_thread, #search, #uid_search, #sort, #uid_sort
2277
2744
  #
2278
- # ===== Capabilities
2745
+ # ==== Capabilities
2279
2746
  #
2280
2747
  # The server's capabilities must include +THREAD+
2281
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2748
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2282
2749
  def thread(algorithm, search_keys, charset)
2283
2750
  return thread_internal("THREAD", algorithm, search_keys, charset)
2284
2751
  end
@@ -2289,10 +2756,10 @@ module Net
2289
2756
  #
2290
2757
  # Related: #thread, #search, #uid_search, #sort, #uid_sort
2291
2758
  #
2292
- # ===== Capabilities
2759
+ # ==== Capabilities
2293
2760
  #
2294
2761
  # The server's capabilities must include +THREAD+
2295
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2762
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2296
2763
  def uid_thread(algorithm, search_keys, charset)
2297
2764
  return thread_internal("UID THREAD", algorithm, search_keys, charset)
2298
2765
  end
@@ -2308,11 +2775,11 @@ module Net
2308
2775
  #
2309
2776
  # Related: #capable?, #capabilities, #capability
2310
2777
  #
2311
- # ===== Capabilities
2778
+ # ==== Capabilities
2312
2779
  #
2313
2780
  # The server's capabilities must include
2314
- # +ENABLE+ [RFC5161[https://tools.ietf.org/html/rfc5161]]
2315
- # or +IMAP4REV2+ [RFC9051[https://tools.ietf.org/html/rfc9051]].
2781
+ # +ENABLE+ [RFC5161[https://www.rfc-editor.org/rfc/rfc5161]]
2782
+ # or +IMAP4REV2+ [RFC9051[https://www.rfc-editor.org/rfc/rfc9051]].
2316
2783
  #
2317
2784
  # Additionally, the server capabilities must include a capability matching
2318
2785
  # each enabled extension (usually the same name as the enabled extension).
@@ -2331,7 +2798,7 @@ module Net
2331
2798
  # <tt>"UTF8=ACCEPT"</tt> or <tt>"IMAP4rev2"</tt>, depending on server
2332
2799
  # capabilities.
2333
2800
  #
2334
- # [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://tools.ietf.org/html/rfc6855]]]
2801
+ # [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
2335
2802
  #
2336
2803
  # The server's capabilities must include <tt>UTF8=ACCEPT</tt> _or_
2337
2804
  # <tt>UTF8=ONLY</tt>.
@@ -2350,13 +2817,23 @@ module Net
2350
2817
  # encoding, even if they generally contain UTF-8 data, if they are
2351
2818
  # text at all.
2352
2819
  #
2353
- # [<tt>"UTF8=ONLY"</tt> [RFC6855[https://tools.ietf.org/html/rfc6855]]]
2820
+ # [<tt>"UTF8=ONLY"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
2354
2821
  #
2355
2822
  # A server that reports the <tt>UTF8=ONLY</tt> capability _requires_ that
2356
2823
  # the client <tt>enable("UTF8=ACCEPT")</tt> before any mailboxes may be
2357
2824
  # selected. For convenience, <tt>enable("UTF8=ONLY")</tt> is aliased to
2358
2825
  # <tt>enable("UTF8=ACCEPT")</tt>.
2359
2826
  #
2827
+ # [+UIDONLY+ {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.pdf]]
2828
+ #
2829
+ # When UIDONLY is enabled, the #fetch, #store, #search, #copy, and #move
2830
+ # commands are prohibited and result in a tagged BAD response. Clients
2831
+ # should instead use uid_fetch, uid_store, uid_search, uid_copy, or
2832
+ # uid_move, respectively. All +FETCH+ responses that would be returned are
2833
+ # replaced by +UIDFETCH+ responses. All +EXPUNGED+ responses that would be
2834
+ # returned are replaced by +VANISHED+ responses. The "<sequence set>"
2835
+ # uid_search criterion is prohibited.
2836
+ #
2360
2837
  # ===== Unsupported capabilities
2361
2838
  #
2362
2839
  # *Note:* Some extensions that use ENABLE permit the server to send syntax
@@ -2397,17 +2874,23 @@ module Net
2397
2874
  # checks the connection for each 60 seconds.
2398
2875
  #
2399
2876
  # loop do
2400
- # imap.idle(60) do |res|
2401
- # ...
2877
+ # imap.idle(60) do |response|
2878
+ # do_something_with(response)
2879
+ # imap.idle_done if some_condition?(response)
2402
2880
  # end
2403
2881
  # end
2404
2882
  #
2883
+ # Returns the server's response to indicate the IDLE state has ended.
2884
+ # Returns +nil+ if the server does not respond to #idle_done within
2885
+ # {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]
2886
+ # seconds.
2887
+ #
2405
2888
  # Related: #idle_done, #noop, #check
2406
2889
  #
2407
- # ===== Capabilities
2890
+ # ==== Capabilities
2408
2891
  #
2409
- # The server's capabilities must include +IDLE+
2410
- # [RFC2177[https://tools.ietf.org/html/rfc2177]].
2892
+ # The server's capabilities must include either +IMAP4rev2+ or +IDLE+
2893
+ # [RFC2177[https://www.rfc-editor.org/rfc/rfc2177]].
2411
2894
  def idle(timeout = nil, &response_handler)
2412
2895
  raise LocalJumpError, "no block given" unless response_handler
2413
2896
 
@@ -2429,7 +2912,7 @@ module Net
2429
2912
  unless @receiver_thread_terminating
2430
2913
  remove_response_handler(response_handler)
2431
2914
  put_string("DONE#{CRLF}")
2432
- response = get_tagged_response(tag, "IDLE", @idle_response_timeout)
2915
+ response = get_tagged_response(tag, "IDLE", idle_response_timeout)
2433
2916
  end
2434
2917
  end
2435
2918
  end
@@ -2437,7 +2920,11 @@ module Net
2437
2920
  return response
2438
2921
  end
2439
2922
 
2440
- # Leaves IDLE.
2923
+ # Leaves IDLE, allowing #idle to return.
2924
+ #
2925
+ # If the server does not respond within
2926
+ # {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]
2927
+ # seconds, #idle will return +nil+.
2441
2928
  #
2442
2929
  # Related: #idle
2443
2930
  def idle_done
@@ -2449,40 +2936,98 @@ module Net
2449
2936
  end
2450
2937
  end
2451
2938
 
2939
+ RESPONSES_DEPRECATION_MSG =
2940
+ "Pass a type or block to #responses, " \
2941
+ "set config.responses_without_block to :frozen_dup " \
2942
+ "or :silence_deprecation_warning, " \
2943
+ "or use #extract_responses or #clear_responses."
2944
+ private_constant :RESPONSES_DEPRECATION_MSG
2945
+
2452
2946
  # :call-seq:
2947
+ # responses -> hash of {String => Array} (see config.responses_without_block)
2948
+ # responses(type) -> frozen array
2453
2949
  # responses {|hash| ...} -> block result
2454
2950
  # responses(type) {|array| ...} -> block result
2455
2951
  #
2456
- # Yields unhandled responses and returns the result of the block.
2952
+ # Yields or returns unhandled server responses. Unhandled responses are
2953
+ # stored in a hash, with arrays of UntaggedResponse#data keyed by
2954
+ # UntaggedResponse#name and <em>non-+nil+</em> untagged ResponseCode#data
2955
+ # keyed by ResponseCode#name.
2956
+ #
2957
+ # When a block is given, yields unhandled responses and returns the block's
2958
+ # result. Without a block, returns the unhandled responses.
2457
2959
  #
2458
- # Unhandled responses are stored in a hash, with arrays of
2459
- # <em>non-+nil+</em> UntaggedResponse#data keyed by UntaggedResponse#name
2460
- # and ResponseCode#data keyed by ResponseCode#name. Call without +type+ to
2461
- # yield the entire responses hash. Call with +type+ to yield only the array
2462
- # of responses for that type.
2960
+ # [With +type+]
2961
+ # Yield or return only the array of responses for that +type+.
2962
+ # When no block is given, the returned array is a frozen copy.
2963
+ # [Without +type+]
2964
+ # Yield or return the entire responses hash.
2965
+ #
2966
+ # When no block is given, the behavior is determined by
2967
+ # Config#responses_without_block:
2968
+ # >>>
2969
+ # [+:silence_deprecation_warning+ <em>(original behavior)</em>]
2970
+ # Returns the mutable responses hash (without any warnings).
2971
+ # <em>This is not thread-safe.</em>
2972
+ #
2973
+ # [+:warn+ <em>(default since +v0.5+)</em>]
2974
+ # Prints a warning and returns the mutable responses hash.
2975
+ # <em>This is not thread-safe.</em>
2976
+ #
2977
+ # [+:frozen_dup+ <em>(planned default for +v0.6+)</em>]
2978
+ # Returns a frozen copy of the unhandled responses hash, with frozen
2979
+ # array values.
2980
+ #
2981
+ # [+:raise+]
2982
+ # Raise an +ArgumentError+ with the deprecation warning.
2463
2983
  #
2464
2984
  # For example:
2465
2985
  #
2466
2986
  # imap.select("inbox")
2467
- # p imap.responses("EXISTS", &:last)
2987
+ # p imap.responses("EXISTS").last
2468
2988
  # #=> 2
2989
+ # p imap.responses("UIDNEXT", &:last)
2990
+ # #=> 123456
2469
2991
  # p imap.responses("UIDVALIDITY", &:last)
2470
2992
  # #=> 968263756
2993
+ # p imap.responses {|responses|
2994
+ # {
2995
+ # exists: responses.delete("EXISTS").last,
2996
+ # uidnext: responses.delete("UIDNEXT").last,
2997
+ # uidvalidity: responses.delete("UIDVALIDITY").last,
2998
+ # }
2999
+ # }
3000
+ # #=> {:exists=>2, :uidnext=>123456, :uidvalidity=>968263756}
3001
+ # # "EXISTS", "UIDNEXT", and "UIDVALIDITY" have been removed:
3002
+ # p imap.responses(&:keys)
3003
+ # #=> ["FLAGS", "OK", "PERMANENTFLAGS", "RECENT", "HIGHESTMODSEQ"]
3004
+ #
3005
+ # Related: #extract_responses, #clear_responses, #response_handlers, #greeting
2471
3006
  #
3007
+ # ==== Thread safety
2472
3008
  # >>>
2473
3009
  # *Note:* Access to the responses hash is synchronized for thread-safety.
2474
3010
  # The receiver thread and response_handlers cannot process new responses
2475
3011
  # until the block completes. Accessing either the response hash or its
2476
- # response type arrays outside of the block is unsafe.
3012
+ # response type arrays outside of the block is unsafe. They can be safely
3013
+ # updated inside the block. Consider using #clear_responses or
3014
+ # #extract_responses instead.
2477
3015
  #
2478
- # Calling without a block is unsafe and deprecated. Future releases will
2479
- # raise ArgumentError unless a block is given.
3016
+ # Net::IMAP will add and remove responses from the responses hash and its
3017
+ # array values, in the calling threads for commands and in the receiver
3018
+ # thread, but will not modify any responses after adding them to the
3019
+ # responses hash.
3020
+ #
3021
+ # ==== Clearing responses
2480
3022
  #
2481
3023
  # Previously unhandled responses are automatically cleared before entering a
2482
3024
  # mailbox with #select or #examine. Long-lived connections can receive many
2483
3025
  # unhandled server responses, which must be pruned or they will continually
2484
3026
  # consume more memory. Update or clear the responses hash or arrays inside
2485
- # the block, or use #clear_responses.
3027
+ # the block, or remove responses with #extract_responses, #clear_responses,
3028
+ # or #add_response_handler.
3029
+ #
3030
+ # ==== Missing responses
2486
3031
  #
2487
3032
  # Only non-+nil+ data is stored. Many important response codes have no data
2488
3033
  # of their own, but are used as "tags" on the ResponseText object they are
@@ -2493,15 +3038,25 @@ module Net
2493
3038
  # ResponseCode#data on tagged responses. Although some command methods do
2494
3039
  # return the TaggedResponse directly, #add_response_handler must be used to
2495
3040
  # handle all response codes.
2496
- #
2497
- # Related: #clear_responses, #response_handlers, #greeting
2498
3041
  def responses(type = nil)
2499
3042
  if block_given?
2500
3043
  synchronize { yield(type ? @responses[type.to_s.upcase] : @responses) }
2501
3044
  elsif type
2502
- raise ArgumentError, "Pass a block or use #clear_responses"
3045
+ synchronize { @responses[type.to_s.upcase].dup.freeze }
2503
3046
  else
2504
- # warn("DEPRECATED: pass a block or use #clear_responses", uplevel: 1)
3047
+ case config.responses_without_block
3048
+ when :raise
3049
+ raise ArgumentError, RESPONSES_DEPRECATION_MSG
3050
+ when :warn
3051
+ warn(RESPONSES_DEPRECATION_MSG, uplevel: 1, category: :deprecated)
3052
+ when :frozen_dup
3053
+ synchronize {
3054
+ responses = @responses.transform_values(&:freeze)
3055
+ responses.default_proc = nil
3056
+ responses.default = [].freeze
3057
+ return responses.freeze
3058
+ }
3059
+ end
2505
3060
  @responses
2506
3061
  end
2507
3062
  end
@@ -2516,7 +3071,7 @@ module Net
2516
3071
  # Clearing responses is synchronized with other threads. The lock is
2517
3072
  # released before returning.
2518
3073
  #
2519
- # Related: #responses, #response_handlers
3074
+ # Related: #extract_responses, #responses, #response_handlers
2520
3075
  def clear_responses(type = nil)
2521
3076
  synchronize {
2522
3077
  if type
@@ -2530,6 +3085,30 @@ module Net
2530
3085
  .freeze
2531
3086
  end
2532
3087
 
3088
+ # :call-seq:
3089
+ # extract_responses(type) {|response| ... } -> array
3090
+ #
3091
+ # Yields all of the unhandled #responses for a single response +type+.
3092
+ # Removes and returns the responses for which the block returns a true
3093
+ # value.
3094
+ #
3095
+ # Extracting responses is synchronized with other threads. The lock is
3096
+ # released before returning.
3097
+ #
3098
+ # Related: #responses, #clear_responses
3099
+ def extract_responses(type)
3100
+ type = String.try_convert(type) or
3101
+ raise ArgumentError, "type must be a string"
3102
+ raise ArgumentError, "must provide a block" unless block_given?
3103
+ extracted = []
3104
+ responses(type) do |all|
3105
+ all.reject! do |response|
3106
+ extracted << response if yield response
3107
+ end
3108
+ end
3109
+ extracted
3110
+ end
3111
+
2533
3112
  # Returns all response handlers, including those that are added internally
2534
3113
  # by commands. Each response handler will be called with every new
2535
3114
  # UntaggedResponse, TaggedResponse, and ContinuationRequest.
@@ -2582,8 +3161,6 @@ module Net
2582
3161
  PORT = 143 # :nodoc:
2583
3162
  SSL_PORT = 993 # :nodoc:
2584
3163
 
2585
- @@debug = false
2586
-
2587
3164
  def start_imap_connection
2588
3165
  @greeting = get_server_greeting
2589
3166
  @capabilities = capabilities_from_resp_code @greeting
@@ -2611,12 +3188,12 @@ module Net
2611
3188
  end
2612
3189
 
2613
3190
  def tcp_socket(host, port)
2614
- s = Socket.tcp(host, port, :connect_timeout => @open_timeout)
3191
+ s = Socket.tcp(host, port, :connect_timeout => open_timeout)
2615
3192
  s.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, true)
2616
3193
  s
2617
3194
  rescue Errno::ETIMEDOUT
2618
3195
  raise Net::OpenTimeout, "Timeout to open TCP connection to " +
2619
- "#{host}:#{port} (exceeds #{@open_timeout} seconds)"
3196
+ "#{host}:#{port} (exceeds #{open_timeout} seconds)"
2620
3197
  end
2621
3198
 
2622
3199
  def receive_responses
@@ -2728,7 +3305,7 @@ module Net
2728
3305
  end
2729
3306
  end
2730
3307
  return nil if buff.length == 0
2731
- if @@debug
3308
+ if config.debug?
2732
3309
  $stderr.print(buff.gsub(/^/n, "S: "))
2733
3310
  end
2734
3311
  return @parser.parse(buff)
@@ -2807,7 +3384,7 @@ module Net
2807
3384
 
2808
3385
  def put_string(str)
2809
3386
  @sock.print(str)
2810
- if @@debug
3387
+ if config.debug?
2811
3388
  if @debug_output_bol
2812
3389
  $stderr.print("C: ")
2813
3390
  end
@@ -2820,23 +3397,115 @@ module Net
2820
3397
  end
2821
3398
  end
2822
3399
 
2823
- def search_internal(cmd, keys, charset)
2824
- if keys.instance_of?(String)
2825
- keys = [RawData.new(keys)]
3400
+ def enforce_logindisabled?
3401
+ if config.enforce_logindisabled == :when_capabilities_cached
3402
+ capabilities_cached?
2826
3403
  else
2827
- normalize_searching_criteria(keys)
3404
+ config.enforce_logindisabled
2828
3405
  end
3406
+ end
3407
+
3408
+ def expunge_internal(...)
2829
3409
  synchronize do
2830
- if charset
2831
- send_command(cmd, "CHARSET", charset, *keys)
3410
+ send_command(...)
3411
+ expunged_array = clear_responses("EXPUNGE")
3412
+ vanished_array = extract_responses("VANISHED") { !_1.earlier? }
3413
+ if vanished_array.empty?
3414
+ expunged_array
3415
+ elsif vanished_array.length == 1
3416
+ vanished_array.first
2832
3417
  else
2833
- send_command(cmd, *keys)
3418
+ merged_uids = SequenceSet[*vanished_array.map(&:uids)]
3419
+ VanishedData[uids: merged_uids, earlier: false]
2834
3420
  end
2835
- clear_responses("SEARCH").last || []
2836
3421
  end
2837
3422
  end
2838
3423
 
2839
- def fetch_internal(cmd, set, attr, mod = nil, changedsince: nil)
3424
+ RETURN_WHOLE = /\ARETURN\z/i
3425
+ RETURN_START = /\ARETURN\b/i
3426
+ private_constant :RETURN_WHOLE, :RETURN_START
3427
+
3428
+ def search_args(keys, charset_arg = nil, return: nil, charset: nil)
3429
+ {return:} => {return: return_kw}
3430
+ case [return_kw, keys]
3431
+ in [nil, Array[RETURN_WHOLE, return_opts, *keys]]
3432
+ return_opts = convert_return_opts(return_opts)
3433
+ esearch = true
3434
+ in [nil => return_opts, RETURN_START]
3435
+ esearch = true
3436
+ in [nil => return_opts, keys]
3437
+ esearch = false
3438
+ in [_, Array[RETURN_WHOLE, _, *] | RETURN_START]
3439
+ raise ArgumentError, "conflicting return options"
3440
+ in [_, Array[RETURN_WHOLE, _, *]] # workaround for https://bugs.ruby-lang.org/issues/20956
3441
+ raise ArgumentError, "conflicting return options"
3442
+ in [_, RETURN_START] # workaround for https://bugs.ruby-lang.org/issues/20956
3443
+ raise ArgumentError, "conflicting return options"
3444
+ in [return_opts, keys]
3445
+ return_opts = convert_return_opts(return_opts)
3446
+ esearch = true
3447
+ end
3448
+ if charset && charset_arg
3449
+ raise ArgumentError, "multiple charset arguments"
3450
+ end
3451
+ charset ||= charset_arg
3452
+ # NOTE: not handling combined RETURN and CHARSET for raw strings
3453
+ if charset && keys in /\ACHARSET\b/i | Array[/\ACHARSET\z/i, *]
3454
+ raise ArgumentError, "multiple charset arguments"
3455
+ end
3456
+ args = normalize_searching_criteria(keys)
3457
+ args.prepend("CHARSET", charset) if charset
3458
+ args.prepend("RETURN", return_opts) if return_opts
3459
+ return args, esearch
3460
+ end
3461
+
3462
+ def convert_return_opts(unconverted)
3463
+ return_opts = Array.try_convert(unconverted) or
3464
+ raise TypeError, "expected return options to be Array, got %s" % [
3465
+ unconverted.class
3466
+ ]
3467
+ return_opts.map {|opt|
3468
+ case opt
3469
+ when Symbol then opt.to_s
3470
+ when PartialRange::Negative then PartialRange[opt]
3471
+ when Range then SequenceSet[opt]
3472
+ else opt
3473
+ end
3474
+ }
3475
+ end
3476
+
3477
+ def search_internal(cmd, ...)
3478
+ args, esearch = search_args(...)
3479
+ synchronize do
3480
+ tagged = send_command(cmd, *args)
3481
+ tag = tagged.tag
3482
+ # Only the last ESEARCH or SEARCH is used. Excess results are ignored.
3483
+ esearch_result = extract_responses("ESEARCH") {|response|
3484
+ response in ESearchResult(tag: ^tag)
3485
+ }.last
3486
+ search_result = clear_responses("SEARCH").last
3487
+ if esearch_result
3488
+ # silently ignore SEARCH results, if any
3489
+ esearch_result
3490
+ elsif search_result
3491
+ # warn EXPECTED_ESEARCH_RESULT if esearch
3492
+ search_result
3493
+ elsif esearch
3494
+ # warn NO_SEARCH_RESPONSE
3495
+ ESearchResult[tag:, uid: cmd.start_with?("UID ")]
3496
+ else
3497
+ # warn NO_SEARCH_RESPONSE
3498
+ SearchResult[]
3499
+ end
3500
+ end
3501
+ end
3502
+
3503
+ def fetch_internal(cmd, set, attr, mod = nil, partial: nil, changedsince: nil)
3504
+ set = SequenceSet[set]
3505
+ if partial
3506
+ mod ||= []
3507
+ mod << "PARTIAL" << PartialRange[partial]
3508
+ end
2840
3509
  if changedsince
2841
3510
  mod ||= []
2842
3511
  mod << "CHANGEDSINCE" << Integer(changedsince)
@@ -2850,39 +3519,36 @@ module Net
2850
3519
  }
2851
3520
  end
2852
3521
 
2853
- synchronize do
2854
- clear_responses("FETCH")
2855
- if mod
2856
- send_command(cmd, MessageSet.new(set), attr, mod)
2857
- else
2858
- send_command(cmd, MessageSet.new(set), attr)
2859
- end
2860
- clear_responses("FETCH")
2861
- end
3522
+ args = [cmd, set, attr]
3523
+ args << mod if mod
3524
+ send_command_returning_fetch_results(*args)
2862
3525
  end
2863
3526
 
2864
3527
  def store_internal(cmd, set, attr, flags, unchangedsince: nil)
2865
3528
  attr = RawData.new(attr) if attr.instance_of?(String)
2866
- args = [MessageSet.new(set)]
3529
+ args = [SequenceSet.new(set)]
2867
3530
  args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
2868
3531
  args << attr << flags
3532
+ send_command_returning_fetch_results(cmd, *args)
3533
+ end
3534
+
3535
+ def send_command_returning_fetch_results(...)
2869
3536
  synchronize do
2870
3537
  clear_responses("FETCH")
2871
- send_command(cmd, *args)
2872
- clear_responses("FETCH")
3538
+ clear_responses("UIDFETCH")
3539
+ send_command(...)
3540
+ fetches = clear_responses("FETCH")
3541
+ uidfetches = clear_responses("UIDFETCH")
3542
+ uidfetches.any? ? uidfetches : fetches
2873
3543
  end
2874
3544
  end
2875
3545
 
2876
3546
  def copy_internal(cmd, set, mailbox)
2877
- send_command(cmd, MessageSet.new(set), mailbox)
3547
+ send_command(cmd, SequenceSet.new(set), mailbox)
2878
3548
  end
2879
3549
 
2880
3550
  def sort_internal(cmd, sort_keys, search_keys, charset)
2881
- if search_keys.instance_of?(String)
2882
- search_keys = [RawData.new(search_keys)]
2883
- else
2884
- normalize_searching_criteria(search_keys)
2885
- end
3551
+ search_keys = normalize_searching_criteria(search_keys)
2886
3552
  synchronize do
2887
3553
  send_command(cmd, sort_keys, charset, *search_keys)
2888
3554
  clear_responses("SORT").last || []
@@ -2890,25 +3556,39 @@ module Net
2890
3556
  end
2891
3557
 
2892
3558
  def thread_internal(cmd, algorithm, search_keys, charset)
2893
- if search_keys.instance_of?(String)
2894
- search_keys = [RawData.new(search_keys)]
2895
- else
2896
- normalize_searching_criteria(search_keys)
2897
- end
3559
+ search_keys = normalize_searching_criteria(search_keys)
2898
3560
  synchronize do
2899
3561
  send_command(cmd, algorithm, charset, *search_keys)
2900
3562
  clear_responses("THREAD").last || []
2901
3563
  end
2902
3564
  end
2903
3565
 
2904
- def normalize_searching_criteria(keys)
2905
- keys.collect! do |i|
2906
- case i
2907
- when -1, Range, Array
2908
- MessageSet.new(i)
3566
+ def normalize_searching_criteria(criteria)
3567
+ return [RawData.new(criteria)] if criteria.is_a?(String)
3568
+ criteria.map {|i|
3569
+ if coerce_search_arg_to_seqset?(i)
3570
+ SequenceSet[i]
2909
3571
  else
2910
3572
  i
2911
3573
  end
3574
+ }
3575
+ end
3576
+
3577
+ def coerce_search_arg_to_seqset?(obj)
3578
+ case obj
3579
+ when Set, -1, :* then true
3580
+ when Range then true
3581
+ when Array then obj.all? { coerce_search_array_arg_to_seqset? _1 }
3582
+ else obj.respond_to?(:to_sequence_set)
3583
+ end
3584
+ end
3585
+
3586
+ def coerce_search_array_arg_to_seqset?(obj)
3587
+ case obj
3588
+ when Integer then obj.positive? || obj == -1
3589
+ when String then ResponseParser::Patterns::SEQUENCE_SET_STR.match?(obj.b)
3590
+ else
3591
+ coerce_search_arg_to_seqset?(obj)
2912
3592
  end
2913
3593
  end
2914
3594
 
@@ -2934,7 +3614,7 @@ module Net
2934
3614
  @sock = SSLSocket.new(@sock, ssl_ctx)
2935
3615
  @sock.sync_close = true
2936
3616
  @sock.hostname = @host if @sock.respond_to? :hostname=
2937
- ssl_socket_connect(@sock, @open_timeout)
3617
+ ssl_socket_connect(@sock, open_timeout)
2938
3618
  if ssl_ctx.verify_mode != VERIFY_NONE
2939
3619
  @sock.post_connection_check(@host)
2940
3620
  @tls_verified = true
@@ -2959,8 +3639,10 @@ module Net
2959
3639
  end
2960
3640
 
2961
3641
  require_relative "imap/errors"
3642
+ require_relative "imap/config"
2962
3643
  require_relative "imap/command_data"
2963
3644
  require_relative "imap/data_encoding"
3645
+ require_relative "imap/data_lite"
2964
3646
  require_relative "imap/flags"
2965
3647
  require_relative "imap/response_data"
2966
3648
  require_relative "imap/response_parser"