net-imap 0.4.12 → 0.5.5

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

Potentially problematic release.


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

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"