net-imap 0.4.12 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +8 -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 +470 -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 +124 -237
  18. data/lib/net/imap/response_parser/parser_utils.rb +11 -6
  19. data/lib/net/imap/response_parser.rb +187 -34
  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 +221 -82
  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/uidplus_data.rb +244 -0
  40. data/lib/net/imap/vanished_data.rb +56 -0
  41. data/lib/net/imap.rb +1010 -320
  42. data/net-imap.gemspec +3 -3
  43. data/rakelib/rfcs.rake +2 -0
  44. data/rakelib/string_prep_tables_generator.rb +2 -0
  45. metadata +12 -10
  46. data/.github/dependabot.yml +0 -6
  47. data/.github/workflows/pages.yml +0 -46
  48. data/.github/workflows/push_gem.yml +0 -48
  49. data/.github/workflows/test.yml +0 -31
  50. data/.gitignore +0 -12
  51. 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.6"
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:
813
847
  #
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
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+.
818
858
  #
819
- # See DeprecatedClientOptions.new for deprecated arguments.
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:
873
+ #
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
878
+ #
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
  #
@@ -1188,17 +1239,25 @@ module Net
1188
1239
  #
1189
1240
  def starttls(**options)
1190
1241
  @ssl_ctx_params, @ssl_ctx = build_ssl_ctx(options)
1191
- send_command("STARTTLS") do |resp|
1242
+ error = nil
1243
+ ok = send_command("STARTTLS") do |resp|
1192
1244
  if resp.kind_of?(TaggedResponse) && resp.name == "OK"
1193
1245
  clear_cached_capabilities
1194
1246
  clear_responses
1195
1247
  start_tls_session
1196
1248
  end
1249
+ rescue Exception => error
1250
+ raise # note that the error backtrace is in the receiver_thread
1197
1251
  end
1252
+ if error
1253
+ disconnect
1254
+ raise error
1255
+ end
1256
+ ok
1198
1257
  end
1199
1258
 
1200
1259
  # :call-seq:
1201
- # authenticate(mechanism, *, sasl_ir: true, registry: Net::IMAP::SASL.authenticators, **, &) -> ok_resp
1260
+ # authenticate(mechanism, *, sasl_ir: config.sasl_ir, registry: Net::IMAP::SASL.authenticators, **, &) -> ok_resp
1202
1261
  #
1203
1262
  # Sends an {AUTHENTICATE command [IMAP4rev1 §6.2.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.2]
1204
1263
  # to authenticate the client. If successful, the connection enters the
@@ -1207,7 +1266,11 @@ module Net
1207
1266
  # +mechanism+ is the name of the \SASL authentication mechanism to be used.
1208
1267
  #
1209
1268
  # +sasl_ir+ allows or disallows sending an "initial response" (see the
1210
- # +SASL-IR+ capability, below).
1269
+ # +SASL-IR+ capability, below). Defaults to the #config value for
1270
+ # {sasl_ir}[rdoc-ref:Config#sasl_ir], which defaults to +true+.
1271
+ #
1272
+ # The +registry+ kwarg can be used to select the mechanism implementation
1273
+ # from a custom registry. See SASL.authenticator and SASL::Authenticators.
1211
1274
  #
1212
1275
  # All other arguments are forwarded to the registered SASL authenticator for
1213
1276
  # the requested mechanism. <em>The documentation for each individual
@@ -1303,27 +1366,9 @@ module Net
1303
1366
  # Previously cached #capabilities will be cleared when this method
1304
1367
  # completes. If the TaggedResponse to #authenticate includes updated
1305
1368
  # 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
1369
+ def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
1370
+ sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
1371
+ .tap { @capabilities = capabilities_from_resp_code _1 }
1327
1372
  end
1328
1373
 
1329
1374
  # Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
@@ -1340,16 +1385,12 @@ module Net
1340
1385
  #
1341
1386
  # Related: #authenticate, #starttls
1342
1387
  #
1343
- # ===== Capabilities
1388
+ # ==== Capabilities
1344
1389
  #
1345
1390
  # 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
1391
+ # +LOGINDISABLED+ capability. By default, Net::IMAP will raise a
1392
+ # LoginDisabledError when that capability is present. See
1393
+ # Config#enforce_logindisabled.
1353
1394
  #
1354
1395
  # Server capabilities may change after #starttls, #login, and #authenticate.
1355
1396
  # Cached capabilities _must_ be invalidated after this method completes.
@@ -1357,6 +1398,9 @@ module Net
1357
1398
  # ResponseCode.
1358
1399
  #
1359
1400
  def login(user, password)
1401
+ if enforce_logindisabled? && capability?("LOGINDISABLED")
1402
+ raise LoginDisabledError
1403
+ end
1360
1404
  send_command("LOGIN", user, password)
1361
1405
  .tap { @capabilities = capabilities_from_resp_code _1 }
1362
1406
  end
@@ -1382,7 +1426,7 @@ module Net
1382
1426
  #
1383
1427
  # Related: #examine
1384
1428
  #
1385
- # ===== Capabilities
1429
+ # ==== Capabilities
1386
1430
  #
1387
1431
  # If [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]] is supported,
1388
1432
  # the server may return an untagged "NO" response with a "UIDNOTSTICKY"
@@ -1500,7 +1544,7 @@ module Net
1500
1544
  #
1501
1545
  # Related: #lsub, MailboxList
1502
1546
  #
1503
- # ===== For example:
1547
+ # ==== For example:
1504
1548
  #
1505
1549
  # imap.create("foo/bar")
1506
1550
  # imap.create("foo/baz")
@@ -1538,7 +1582,7 @@ module Net
1538
1582
  # servers, then folder creation (and listing, moving, etc) can lead to
1539
1583
  # errors.
1540
1584
  #
1541
- # From RFC2342[https://tools.ietf.org/html/rfc2342]:
1585
+ # From RFC2342[https://www.rfc-editor.org/rfc/rfc2342]:
1542
1586
  # >>>
1543
1587
  # <em>Although typically a server will support only a single Personal
1544
1588
  # Namespace, and a single Other User's Namespace, circumstances exist
@@ -1551,7 +1595,7 @@ module Net
1551
1595
  #
1552
1596
  # Related: #list, Namespaces, Namespace
1553
1597
  #
1554
- # ===== For example:
1598
+ # ==== For example:
1555
1599
  #
1556
1600
  # if capable?("NAMESPACE")
1557
1601
  # namespaces = imap.namespace
@@ -1565,10 +1609,10 @@ module Net
1565
1609
  # end
1566
1610
  # end
1567
1611
  #
1568
- # ===== Capabilities
1612
+ # ==== Capabilities
1569
1613
  #
1570
- # The server's capabilities must include +NAMESPACE+
1571
- # [RFC2342[https://tools.ietf.org/html/rfc2342]].
1614
+ # The server's capabilities must include either +IMAP4rev2+ or +NAMESPACE+
1615
+ # [RFC2342[https://www.rfc-editor.org/rfc/rfc2342]].
1572
1616
  def namespace
1573
1617
  synchronize do
1574
1618
  send_command("NAMESPACE")
@@ -1604,7 +1648,7 @@ module Net
1604
1648
  #
1605
1649
  # Related: #list, MailboxList
1606
1650
  #
1607
- # ===== Capabilities
1651
+ # ==== Capabilities
1608
1652
  #
1609
1653
  # The server's capabilities must include +XLIST+,
1610
1654
  # a deprecated Gmail extension (replaced by +SPECIAL-USE+).
@@ -1627,10 +1671,10 @@ module Net
1627
1671
  #
1628
1672
  # Related: #getquota, #setquota, MailboxQuotaRoot, MailboxQuota
1629
1673
  #
1630
- # ===== Capabilities
1674
+ # ==== Capabilities
1631
1675
  #
1632
1676
  # The server's capabilities must include +QUOTA+
1633
- # [RFC2087[https://tools.ietf.org/html/rfc2087]].
1677
+ # [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
1634
1678
  def getquotaroot(mailbox)
1635
1679
  synchronize do
1636
1680
  send_command("GETQUOTAROOT", mailbox)
@@ -1648,10 +1692,10 @@ module Net
1648
1692
  #
1649
1693
  # Related: #getquotaroot, #setquota, MailboxQuota
1650
1694
  #
1651
- # ===== Capabilities
1695
+ # ==== Capabilities
1652
1696
  #
1653
1697
  # The server's capabilities must include +QUOTA+
1654
- # [RFC2087[https://tools.ietf.org/html/rfc2087]].
1698
+ # [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
1655
1699
  def getquota(mailbox)
1656
1700
  synchronize do
1657
1701
  send_command("GETQUOTA", mailbox)
@@ -1666,10 +1710,10 @@ module Net
1666
1710
  #
1667
1711
  # Related: #getquota, #getquotaroot
1668
1712
  #
1669
- # ===== Capabilities
1713
+ # ==== Capabilities
1670
1714
  #
1671
1715
  # The server's capabilities must include +QUOTA+
1672
- # [RFC2087[https://tools.ietf.org/html/rfc2087]].
1716
+ # [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
1673
1717
  def setquota(mailbox, quota)
1674
1718
  if quota.nil?
1675
1719
  data = '()'
@@ -1686,10 +1730,10 @@ module Net
1686
1730
  #
1687
1731
  # Related: #getacl
1688
1732
  #
1689
- # ===== Capabilities
1733
+ # ==== Capabilities
1690
1734
  #
1691
1735
  # The server's capabilities must include +ACL+
1692
- # [RFC4314[https://tools.ietf.org/html/rfc4314]].
1736
+ # [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
1693
1737
  def setacl(mailbox, user, rights)
1694
1738
  if rights.nil?
1695
1739
  send_command("SETACL", mailbox, user, "")
@@ -1704,10 +1748,10 @@ module Net
1704
1748
  #
1705
1749
  # Related: #setacl, MailboxACLItem
1706
1750
  #
1707
- # ===== Capabilities
1751
+ # ==== Capabilities
1708
1752
  #
1709
1753
  # The server's capabilities must include +ACL+
1710
- # [RFC4314[https://tools.ietf.org/html/rfc4314]].
1754
+ # [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
1711
1755
  def getacl(mailbox)
1712
1756
  synchronize do
1713
1757
  send_command("GETACL", mailbox)
@@ -1741,7 +1785,7 @@ module Net
1741
1785
  # for +mailbox+ cannot be returned; for instance, because it
1742
1786
  # does not exist.
1743
1787
  #
1744
- # ===== Supported attributes
1788
+ # ==== Supported attributes
1745
1789
  #
1746
1790
  # +MESSAGES+:: The number of messages in the mailbox.
1747
1791
  #
@@ -1772,12 +1816,12 @@ module Net
1772
1816
  # Unsupported attributes may be requested. The attribute value will be
1773
1817
  # either an Integer or an ExtensionData object.
1774
1818
  #
1775
- # ===== For example:
1819
+ # ==== For example:
1776
1820
  #
1777
1821
  # p imap.status("inbox", ["MESSAGES", "RECENT"])
1778
1822
  # #=> {"RECENT"=>0, "MESSAGES"=>44}
1779
1823
  #
1780
- # ===== Capabilities
1824
+ # ==== Capabilities
1781
1825
  #
1782
1826
  # +SIZE+ requires the server's capabilities to include either +IMAP4rev2+ or
1783
1827
  # <tt>STATUS=SIZE</tt>
@@ -1817,7 +1861,7 @@ module Net
1817
1861
  # not exist (it is not created automatically), or if the flags,
1818
1862
  # date_time, or message arguments contain errors.
1819
1863
  #
1820
- # ===== Capabilities
1864
+ # ==== Capabilities
1821
1865
  #
1822
1866
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
1823
1867
  # supported and the destination supports persistent UIDs, the server's
@@ -1866,129 +1910,492 @@ module Net
1866
1910
  #
1867
1911
  # Related: #close
1868
1912
  #
1869
- # ===== Capabilities
1913
+ # ==== Capabilities
1870
1914
  #
1871
- # The server's capabilities must include +UNSELECT+
1872
- # [RFC3691[https://tools.ietf.org/html/rfc3691]].
1915
+ # The server's capabilities must include either +IMAP4rev2+ or +UNSELECT+
1916
+ # [RFC3691[https://www.rfc-editor.org/rfc/rfc3691]].
1873
1917
  def unselect
1874
1918
  send_command("UNSELECT")
1875
1919
  end
1876
1920
 
1921
+ # call-seq:
1922
+ # expunge -> array of message sequence numbers
1923
+ # expunge -> VanishedData of UIDs
1924
+ #
1877
1925
  # 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.
1926
+ # to permanently remove all messages with the +\Deleted+ flag from the
1927
+ # currently selected mailbox.
1928
+ #
1929
+ # Returns either an array of expunged message <em>sequence numbers</em> or
1930
+ # (when the appropriate capability is enabled) VanishedData of expunged
1931
+ # UIDs. Previously unhandled +EXPUNGE+ or +VANISHED+ responses are merged
1932
+ # with the direct response to this command. <tt>VANISHED (EARLIER)</tt>
1933
+ # responses will _not_ be merged.
1934
+ #
1935
+ # When no messages have been expunged, an empty array is returned,
1936
+ # regardless of which extensions are enabled. In a future release, an empty
1937
+ # VanishedData may be returned, based on the currently enabled extensions.
1880
1938
  #
1881
1939
  # Related: #uid_expunge
1940
+ #
1941
+ # ==== Capabilities
1942
+ #
1943
+ # When either QRESYNC[https://www.rfc-editor.org/rfc/rfc7162] or
1944
+ # UIDONLY[https://www.rfc-editor.org/rfc/rfc9586] are enabled, #expunge
1945
+ # returns VanishedData, which contains UIDs---<em>not message sequence
1946
+ # numbers</em>.
1882
1947
  def expunge
1883
- synchronize do
1884
- send_command("EXPUNGE")
1885
- clear_responses("EXPUNGE")
1886
- end
1948
+ expunge_internal("EXPUNGE")
1887
1949
  end
1888
1950
 
1951
+ # call-seq:
1952
+ # uid_expunge{uid_set) -> array of message sequence numbers
1953
+ # uid_expunge{uid_set) -> VanishedData of UIDs
1954
+ #
1889
1955
  # Sends a {UID EXPUNGE command [RFC4315 §2.1]}[https://www.rfc-editor.org/rfc/rfc4315#section-2.1]
1890
1956
  # {[IMAP4rev2 §6.4.9]}[https://www.rfc-editor.org/rfc/rfc9051#section-6.4.9]
1891
1957
  # to permanently remove all messages that have both the <tt>\\Deleted</tt>
1892
1958
  # flag set and a UID that is included in +uid_set+.
1893
1959
  #
1960
+ # Returns the same result type as #expunge.
1961
+ #
1894
1962
  # By using #uid_expunge instead of #expunge when resynchronizing with
1895
1963
  # the server, the client can ensure that it does not inadvertantly
1896
1964
  # remove any messages that have been marked as <tt>\\Deleted</tt> by other
1897
1965
  # clients between the time that the client was last connected and
1898
1966
  # the time the client resynchronizes.
1899
1967
  #
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
1968
  # Related: #expunge
1909
1969
  #
1910
- # ===== Capabilities
1970
+ # ==== Capabilities
1911
1971
  #
1912
- # The server's capabilities must include +UIDPLUS+
1972
+ # The server's capabilities must include either +IMAP4rev2+ or +UIDPLUS+
1913
1973
  # [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]].
1974
+ #
1975
+ # Otherwise, #uid_expunge is updated by extensions in the same way as
1976
+ # #expunge.
1914
1977
  def uid_expunge(uid_set)
1915
- synchronize do
1916
- send_command("UID EXPUNGE", MessageSet.new(uid_set))
1917
- clear_responses("EXPUNGE")
1918
- end
1978
+ expunge_internal("UID EXPUNGE", SequenceSet.new(uid_set))
1919
1979
  end
1920
1980
 
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.
1981
+ # :call-seq:
1982
+ # search(criteria, charset = nil) -> result
1983
+ # search(criteria, charset: nil, return: nil) -> result
1926
1984
  #
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.
1985
+ # Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
1986
+ # to search the mailbox for messages that match the given search +criteria+,
1987
+ # and returns either a SearchResult or an ESearchResult. SearchResult
1988
+ # inherits from Array (for backward compatibility) but adds
1989
+ # SearchResult#modseq when the +CONDSTORE+ capability has been enabled.
1990
+ # ESearchResult also implements {#to_a}[rdoc-ref:ESearchResult#to_a], for
1991
+ # compatibility with SearchResult.
1992
+ #
1993
+ # +criteria+ is one or more search keys and their arguments, which may be
1994
+ # provided as an array or a string.
1995
+ # See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
1996
+ # and {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
1997
+ #
1998
+ # +return+ options control what kind of information is returned about
1999
+ # messages matching the search +criteria+. Specifying +return+ should force
2000
+ # the server to return an ESearchResult instead of a SearchResult, but some
2001
+ # servers disobey this requirement. <em>Requires an extended search
2002
+ # capability, such as +ESEARCH+ or +IMAP4rev2+.</em>
2003
+ # See {"Argument translation"}[rdoc-ref:#search@Argument+translation] and
2004
+ # {"Supported return options"}[rdoc-ref:#search@Supported+return+options],
2005
+ # below.
2006
+ #
2007
+ # +charset+ is the name of the {registered character
2008
+ # set}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
2009
+ # used by strings in the search +criteria+. When +charset+ isn't specified,
2010
+ # either <tt>"US-ASCII"</tt> or <tt>"UTF-8"</tt> is assumed, depending on
2011
+ # the server's capabilities.
2012
+ #
2013
+ # _NOTE:_ Return options and charset may be sent as part of +criteria+. Do
2014
+ # not use the +return+ or +charset+ arguments when either return options or
2015
+ # charset are embedded in +criteria+.
1930
2016
  #
1931
2017
  # Related: #uid_search
1932
2018
  #
1933
- # ===== Search criteria
2019
+ # ==== For example:
2020
+ #
2021
+ # imap.search(["SUBJECT", "hello", "NOT", "SEEN"])
2022
+ # #=> [1, 6, 7, 8]
1934
2023
  #
1935
- # For a full list of search criteria,
2024
+ # The following assumes the server supports +ESEARCH+ and +CONDSTORE+:
2025
+ #
2026
+ # result = imap.uid_search(["UID", 12345.., "MODSEQ", 620_162_338],
2027
+ # return: %w(all count min max))
2028
+ # # => #<data Net::IMAP::ESearchResult tag="RUBY0123", uid=true,
2029
+ # # data=[["ALL", Net::IMAP::SequenceSet["12346:12349,22222:22230"]],
2030
+ # # ["COUNT", 13], ["MIN", 12346], ["MAX", 22230],
2031
+ # # ["MODSEQ", 917162488]]>
2032
+ # result.to_a # => [12346, 12347, 12348, 12349, 22222, 22223, 22224,
2033
+ # # 22225, 22226, 22227, 22228, 22229, 22230]
2034
+ # result.uid? # => true
2035
+ # result.count # => 13
2036
+ # result.min # => 12346
2037
+ # result.max # => 22230
2038
+ # result.modseq # => 917162488
2039
+ #
2040
+ # Using +return+ options to limit the result to only min, max, and count:
2041
+ #
2042
+ # result = imap.uid_search(["UID", 12345..,], return: %w(count min max))
2043
+ # # => #<data Net::IMAP::ESearchResult tag="RUBY0124", uid=true,
2044
+ # # data=[["COUNT", 13], ["MIN", 12346], ["MAX", 22230]]>
2045
+ # result.to_a # => []
2046
+ # result.count # => 13
2047
+ # result.min # => 12346
2048
+ # result.max # => 22230
2049
+ #
2050
+ # Return options and charset may be sent as keyword args or embedded in the
2051
+ # +criteria+ arg, but they must be in the correct order: <tt>"RETURN (...)
2052
+ # CHARSET ... criteria..."</tt>. The following searches
2053
+ # send the exact same command to the server:
2054
+ #
2055
+ # # Return options and charset as keyword arguments (preferred)
2056
+ # imap.search(%w(OR UNSEEN FLAGGED), return: %w(MIN MAX), charset: "UTF-8")
2057
+ # # Embedding return and charset in the criteria array
2058
+ # imap.search(["RETURN", %w(MIN MAX), "CHARSET", "UTF-8", *%w(OR UNSEEN FLAGGED)])
2059
+ # # Embedding return and charset in the criteria string
2060
+ # imap.search("RETURN (MIN MAX) CHARSET UTF-8 OR UNSEEN FLAGGED")
2061
+ #
2062
+ # Sending charset as the second positional argument is supported for
2063
+ # backward compatibility. Future versions may print a deprecation warning:
2064
+ # imap.search(%w(OR UNSEEN FLAGGED), "UTF-8", return: %w(MIN MAX))
2065
+ #
2066
+ # ==== Argument translation
2067
+ #
2068
+ # [+return+ options]
2069
+ # Must be an Array. Return option names may be either strings or symbols.
2070
+ # +Range+ elements which begin and end with negative integers are encoded
2071
+ # for use with +PARTIAL+--any other ranges are converted to SequenceSet.
2072
+ # Unlike +criteria+, other return option arguments are not automatically
2073
+ # converted to SequenceSet.
2074
+ #
2075
+ # [When +criteria+ is an Array]
2076
+ # When the array begins with <tt>"RETURN"</tt> (case insensitive), the
2077
+ # second array element is translated like the +return+ parameter (as
2078
+ # described above).
2079
+ #
2080
+ # Every other member is a +SEARCH+ command argument:
2081
+ # [SequenceSet]
2082
+ # Encoded as an \IMAP +sequence-set+ with SequenceSet#valid_string.
2083
+ # [Set, Range, <tt>-1</tt>, +:*+, responds to +#to_sequence_set+]
2084
+ # Converted to SequenceSet for validation and encoding.
2085
+ # [nested sequence-set +Array+]
2086
+ # When every element in a nested array is one of the above types, a
2087
+ # positive +Integer+, a sequence-set formatted +String+, or a deeply
2088
+ # nested +Array+ of these same types, the array will be converted to
2089
+ # SequenceSet for validation and encoding.
2090
+ # [Any other nested +Array+]
2091
+ # Otherwise, a nested array is encoded as a parenthesized list, to
2092
+ # combine multiple search keys (e.g., for use with +OR+ and +NOT+).
2093
+ # [+String+]
2094
+ # Sent verbatim when it is a valid \IMAP +atom+, and encoded as an \IMAP
2095
+ # +quoted+ or +literal+ string otherwise. Every standard search key
2096
+ # name is a valid \IMAP +atom+ and every standard search key string
2097
+ # argument is an +astring+ which may be encoded as +atom+, +quoted+, or
2098
+ # +literal+.
2099
+ #
2100
+ # *Note:* <tt>*</tt> is not a valid \IMAP +atom+ character. Any string
2101
+ # containing <tt>*</tt> will be encoded as a +quoted+ string, _not_ a
2102
+ # +sequence-set+.
2103
+ # [+Integer+ (except for <tt>-1</tt>)]
2104
+ # Encoded using +#to_s+.
2105
+ # [+Date+]
2106
+ # Encoded as an \IMAP date (see ::encode_date).
2107
+ #
2108
+ # [When +criteria+ is a String]
2109
+ # +criteria+ will be sent directly to the server <em>without any
2110
+ # validation or encoding</em>.
2111
+ #
2112
+ # <em>*WARNING:* This is vulnerable to injection attacks when external
2113
+ # inputs are used.</em>
2114
+ #
2115
+ # ==== Supported return options
2116
+ #
2117
+ # For full definitions of the standard return options and return data, see
2118
+ # the relevant RFCs.
2119
+ #
2120
+ # [+ALL+]
2121
+ # Returns ESearchResult#all with a SequenceSet of all matching sequence
2122
+ # numbers or UIDs. This is the default, when return options are empty.
2123
+ #
2124
+ # For compatibility with SearchResult, ESearchResult#to_a returns an
2125
+ # Array of message sequence numbers or UIDs.
2126
+ #
2127
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2128
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2129
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2130
+ #
2131
+ # [+COUNT+]
2132
+ # Returns ESearchResult#count with the number of matching messages.
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
+ # [+MAX+]
2139
+ # Returns ESearchResult#max with the highest 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
+ # [+MIN+]
2147
+ # Returns ESearchResult#min with the lowest matching sequence number or
2148
+ # UID.
2149
+ #
2150
+ # <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
2151
+ # {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
2152
+ # {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
2153
+ #
2154
+ # [+PARTIAL+ _range_]
2155
+ # Returns ESearchResult#partial with a SequenceSet of a subset of
2156
+ # matching sequence numbers or UIDs, as selected by _range_. As with
2157
+ # sequence numbers, the first result is +1+: <tt>1..500</tt> selects the
2158
+ # first 500 search results (in mailbox order), <tt>501..1000</tt> the
2159
+ # second 500, and so on. _range_ may also be negative: <tt>-500..-1</tt>
2160
+ # selects the last 500 search results.
2161
+ #
2162
+ # <em>Requires either the <tt>CONTEXT=SEARCH</tt> or +PARTIAL+ capabability.</em>
2163
+ # {[RFC5267]}[https://rfc-editor.org/rfc/rfc5267]
2164
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2165
+ #
2166
+ # ===== +MODSEQ+ return data
2167
+ #
2168
+ # ESearchResult#modseq return data does not have a corresponding return
2169
+ # option. Instead, it is returned if the +MODSEQ+ search key is used or
2170
+ # when the +CONDSTORE+ extension is enabled for the selected mailbox.
2171
+ # See [{RFC4731 §3.2}[https://www.rfc-editor.org/rfc/rfc4731#section-3.2]]
2172
+ # or [{RFC7162 §2.1.5}[https://www.rfc-editor.org/rfc/rfc7162#section-3.1.5]].
2173
+ #
2174
+ # ===== +RFC4466+ compatible extensions
2175
+ #
2176
+ # {RFC4466 §2.6}[https://www.rfc-editor.org/rfc/rfc4466.html#section-2.6]
2177
+ # defines standard syntax for search extensions. Net::IMAP allows sending
2178
+ # unsupported search return options and will parse unsupported search
2179
+ # extensions' return values into ExtensionData. Please note that this is an
2180
+ # intentionally _unstable_ API. Future releases may return different
2181
+ # (incompatible) objects, <em>without deprecation or warning</em>.
2182
+ #
2183
+ # ==== Search keys
2184
+ #
2185
+ # For full definitions of the standard search +criteria+,
1936
2186
  # see [{IMAP4rev1 §6.4.4}[https://www.rfc-editor.org/rfc/rfc3501.html#section-6.4.4]],
1937
2187
  # or [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]],
1938
2188
  # 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:
2189
+ # any #capabilities which may define additional search filters, such as
1941
2190
  # +CONDSTORE+, +WITHIN+, +FILTERS+, <tt>SEARCH=FUZZY</tt>, +OBJECTID+, or
1942
- # +SAVEDATE+. The following are some common search criteria:
2191
+ # +SAVEDATE+.
1943
2192
  #
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>".
2193
+ # With the exception of <em>sequence-set</em> and <em>parenthesized
2194
+ # list</em>, all search keys are composed of prefix label with zero or more
2195
+ # arguments. The number and type of arguments is specific to each search
2196
+ # key.
1947
2197
  #
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.
2198
+ # ===== Search keys that match all messages
1952
2199
  #
1953
- # BODY <string>:: messages that contain <string> within their body.
2200
+ # [+ALL+]
2201
+ # The default initial key. Matches every message in the mailbox.
1954
2202
  #
1955
- # CC <string>:: messages containing <string> in their CC field.
2203
+ # [+SAVEDATESUPPORTED+]
2204
+ # Matches every message in the mailbox when the mailbox supports the save
2205
+ # date attribute. Otherwise, it matches no messages.
1956
2206
  #
1957
- # FROM <string>:: messages that contain <string> in their FROM field.
2207
+ # <em>Requires +SAVEDATE+ capability</em>.
2208
+ # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
1958
2209
  #
1959
- # NEW:: messages with the \Recent, but not the \Seen, flag set.
2210
+ # ===== Sequence set search keys
1960
2211
  #
1961
- # NOT <search-key>:: negate the following search key.
2212
+ # [_sequence-set_]
2213
+ # Matches messages with message sequence numbers in _sequence-set_.
1962
2214
  #
1963
- # OR <search-key> <search-key>:: "or" two search keys together.
2215
+ # _Note:_ this search key has no label.
1964
2216
  #
1965
- # ON <date>:: messages with an internal date exactly equal to <date>,
1966
- # which has a format similar to 8-Aug-2002.
2217
+ # <em>+UIDONLY+ must *not* be enabled.</em>
2218
+ # {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.html]
1967
2219
  #
1968
- # SINCE <date>:: messages with an internal date on or after <date>.
2220
+ # [+UID+ _sequence-set_]
2221
+ # Matches messages with a UID in _sequence-set_.
1969
2222
  #
1970
- # SUBJECT <string>:: messages with <string> in their subject.
2223
+ # ===== Compound search keys
1971
2224
  #
1972
- # TO <string>:: messages with <string> in their TO field.
2225
+ # [(_search-key_ _search-key_...)]
2226
+ # Combines one or more _search-key_ arguments to match
2227
+ # messages which match all contained search keys. Useful for +OR+, +NOT+,
2228
+ # and other search keys with _search-key_ arguments.
1973
2229
  #
1974
- # ===== For example:
2230
+ # _Note:_ this search key has no label.
1975
2231
  #
1976
- # p imap.search(["SUBJECT", "hello", "NOT", "NEW"])
1977
- # #=> [1, 6, 7, 8]
2232
+ # [+OR+ _search-key_ _search-key_]
2233
+ # Matches messages which match either _search-key_ argument.
2234
+ #
2235
+ # [+NOT+ _search-key_]
2236
+ # Matches messages which do not match _search-key_.
2237
+ #
2238
+ # [+FUZZY+ _search-key_]
2239
+ # Uses fuzzy matching for the specified search key.
2240
+ #
2241
+ # <em>Requires <tt>SEARCH=FUZZY</tt> capability.</em>
2242
+ # {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
2243
+ #
2244
+ # ===== Flags search keys
2245
+ #
2246
+ # [+ANSWERED+, +UNANSWERED+]
2247
+ # Matches messages with or without the <tt>\\Answered</tt> flag.
2248
+ # [+DELETED+, +UNDELETED+]
2249
+ # Matches messages with or without the <tt>\\Deleted</tt> flag.
2250
+ # [+DRAFT+, +UNDRAFT+]
2251
+ # Matches messages with or without the <tt>\\Draft</tt> flag.
2252
+ # [+FLAGGED+, +UNFLAGGED+]
2253
+ # Matches messages with or without the <tt>\\Flagged</tt> flag.
2254
+ # [+SEEN+, +UNSEEN+]
2255
+ # Matches messages with or without the <tt>\\Seen</tt> flag.
2256
+ # [+KEYWORD+ _keyword_, +UNKEYWORD+ _keyword_]
2257
+ # Matches messages with or without the specified _keyword_.
2258
+ #
2259
+ # [+RECENT+, +UNRECENT+]
2260
+ # Matches messages with or without the <tt>\\Recent</tt> flag.
2261
+ #
2262
+ # *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
2263
+ # [+NEW+]
2264
+ # Equivalent to <tt>(RECENT UNSEEN)</tt>.
2265
+ #
2266
+ # *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
2267
+ #
2268
+ # ===== Header field substring search keys
2269
+ #
2270
+ # [+BCC+ _substring_]
2271
+ # Matches when _substring_ is in the envelope's +BCC+ field.
2272
+ # [+CC+ _substring_]
2273
+ # Matches when _substring_ is in the envelope's +CC+ field.
2274
+ # [+FROM+ _substring_]
2275
+ # Matches when _substring_ is in the envelope's +FROM+ field.
2276
+ # [+SUBJECT+ _substring_]
2277
+ # Matches when _substring_ is in the envelope's +SUBJECT+ field.
2278
+ # [+TO+ _substring_]
2279
+ # Matches when _substring_ is in the envelope's +TO+ field.
2280
+ #
2281
+ # [+HEADER+ _field_ _substring_]
2282
+ # Matches when _substring_ is in the specified header _field_.
2283
+ #
2284
+ # ===== Body text search keys
2285
+ # [+BODY+ _string_]
2286
+ # Matches when _string_ is in the body of the message.
2287
+ # Does not match on header fields.
2288
+ #
2289
+ # The server _may_ use flexible matching, rather than simple substring
2290
+ # matches. For example, this may use stemming or match only full words.
2291
+ #
2292
+ # [+TEXT+ _string_]
2293
+ # Matches when _string_ is in the header or body of the message.
2294
+ #
2295
+ # The server _may_ use flexible matching, rather than simple substring
2296
+ # matches. For example, this may use stemming or match only full words.
2297
+ #
2298
+ # ===== Date/Time search keys
2299
+ #
2300
+ # [+SENTBEFORE+ _date_]
2301
+ # [+SENTON+ _date_]
2302
+ # [+SENTSINCE+ _date_]
2303
+ # Matches when the +Date+ header is earlier than, on, or later than _date_.
2304
+ #
2305
+ # [+BEFORE+ _date_]
2306
+ # [+ON+ _date_]
2307
+ # [+SINCE+ _date_]
2308
+ # Matches when the +INTERNALDATE+ is earlier than, on, or later than
2309
+ # _date_.
2310
+ #
2311
+ # [+OLDER+ _interval_]
2312
+ # [+YOUNGER+ _interval_]
2313
+ # Matches when the +INTERNALDATE+ is more/less than _interval_ seconds ago.
2314
+ #
2315
+ # <em>Requires +WITHIN+ capability</em>.
2316
+ # {[RFC5032]}[https://www.rfc-editor.org/rfc/rfc5032.html]
2317
+ #
2318
+ # [+SAVEDBEFORE+ _date_]
2319
+ # [+SAVEDON+ _date_]
2320
+ # [+SAVEDSINCE+ _date_]
2321
+ # Matches when the save date is earlier than, on, or later than _date_.
2322
+ #
2323
+ # <em>Requires +SAVEDATE+ capability.</em>
2324
+ # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
2325
+ #
2326
+ # ===== Other message attribute search keys
2327
+ #
2328
+ # [+SMALLER+ _bytes_]
2329
+ # [+LARGER+ _bytes_]
2330
+ # Matches when +RFC822.SIZE+ is smaller or larger than _bytes_.
2331
+ #
2332
+ # [+ANNOTATION+ _entry_ _attr_ _value_]
2333
+ # Matches messages that have annotations with entries matching _entry_,
2334
+ # attributes matching _attr_, and _value_ in the attribute's values.
2335
+ #
2336
+ # <em>Requires +ANNOTATE-EXPERIMENT-1+ capability</em>.
2337
+ # {[RFC5257]}[https://www.rfc-editor.org/rfc/rfc5257.html].
2338
+ #
2339
+ # [+FILTER+ _filter_]
2340
+ # References a _filter_ that is stored on the server and matches all
2341
+ # messages which would be matched by that filter's search criteria.
2342
+ #
2343
+ # <em>Requires +FILTERS+ capability</em>.
2344
+ # {[RFC5466]}[https://www.rfc-editor.org/rfc/rfc5466.html#section-3.1]
2345
+ #
2346
+ # [+MODSEQ+ _modseq_]
2347
+ # Matches when +MODSEQ+ is greater than or equal to _modseq_.
2348
+ #
2349
+ # <em>Requires +CONDSTORE+ capability</em>.
2350
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
2351
+ #
2352
+ # [+MODSEQ+ _entry_ _entry-type_ _modseq_]
2353
+ # Matches when a specific metadata _entry_ has been updated since
2354
+ # _modseq_.
2355
+ #
2356
+ # For flags, the corresponding _entry_ name is
2357
+ # <tt>"/flags/#{flag_name}"</tt>, where _flag_name_ includes the
2358
+ # <tt>\\</tt> prefix. _entry-type_ can be one of <tt>"shared"</tt>,
2359
+ # <tt>"priv"</tt> (private), or <tt>"all"</tt>.
2360
+ #
2361
+ # <em>Requires +CONDSTORE+ capability</em>.
2362
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
2363
+ #
2364
+ # [+EMAILID+ _objectid_]
2365
+ # [+THREADID+ _objectid_]
2366
+ # Matches when +EMAILID+/+THREADID+ is equal to _objectid_
2367
+ # (substring matches are not supported).
2368
+ #
2369
+ # <em>Requires +OBJECTID+ capability</em>.
2370
+ # {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-6]
2371
+ #
2372
+ # ==== Capabilities
1978
2373
  #
1979
- # ===== Capabilities
2374
+ # Return options should only be specified when the server supports
2375
+ # +IMAP4rev2+ or an extension that allows them, such as +ESEARCH+
2376
+ # [RFC4731[https://rfc-editor.org/rfc/rfc4731#section-3.1]].
1980
2377
  #
1981
- # If [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html]] is supported
2378
+ # When +IMAP4rev2+ is enabled, or when the server supports +IMAP4rev2+ but
2379
+ # not +IMAP4rev1+, ESearchResult is always returned instead of SearchResult.
2380
+ #
2381
+ # If CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html] is supported
1982
2382
  # and enabled for the selected mailbox, a non-empty SearchResult will
1983
2383
  # include a +MODSEQ+ value.
1984
2384
  # imap.select("mbox", condstore: true)
1985
- # result = imap.search(["SUBJECT", "hi there", "not", "new")
2385
+ # result = imap.search(["SUBJECT", "hi there", "not", "new"])
1986
2386
  # #=> Net::IMAP::SearchResult[1, 6, 7, 8, modseq: 5594]
1987
2387
  # result.modseq # => 5594
1988
- def search(keys, charset = nil)
1989
- return search_internal("SEARCH", keys, charset)
2388
+ #
2389
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2390
+ # the +SEARCH+ command is prohibited. Use #uid_search instead.
2391
+ def search(...)
2392
+ search_internal("SEARCH", ...)
1990
2393
  end
1991
2394
 
2395
+ # :call-seq:
2396
+ # uid_search(criteria, charset = nil) -> result
2397
+ # uid_search(criteria, charset: nil, return: nil) -> result
2398
+ #
1992
2399
  # Sends a {UID SEARCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
1993
2400
  # to search the mailbox for messages that match the given searching
1994
2401
  # criteria, and returns unique identifiers (<tt>UID</tt>s).
@@ -1997,9 +2404,19 @@ module Net
1997
2404
  # backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
1998
2405
  # capability has been enabled.
1999
2406
  #
2000
- # See #search for documentation of search criteria.
2001
- def uid_search(keys, charset = nil)
2002
- return search_internal("UID SEARCH", keys, charset)
2407
+ # See #search for documentation of parameters.
2408
+ #
2409
+ # ==== Capabilities
2410
+ #
2411
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2412
+ # #uid_search must be used instead of #search, and the <tt><message
2413
+ # set></tt> search criterion is prohibited. Use +ALL+ or <tt>UID
2414
+ # sequence-set</tt> instead.
2415
+ #
2416
+ # Otherwise, #uid_search is updated by extensions in the same way as
2417
+ # #search.
2418
+ def uid_search(...)
2419
+ search_internal("UID SEARCH", ...)
2003
2420
  end
2004
2421
 
2005
2422
  # :call-seq:
@@ -2008,26 +2425,21 @@ module Net
2008
2425
  # Sends a {FETCH command [IMAP4rev1 §6.4.5]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.5]
2009
2426
  # to retrieve data associated with a message in the mailbox.
2010
2427
  #
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.
2428
+ # +set+ is the message sequence numbers to fetch, and may be any valid input
2429
+ # to {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
2430
+ # (For UIDs, use #uid_fetch instead.)
2019
2431
  #
2020
- # +attr+ is a list of attributes to fetch; see the documentation
2021
- # for FetchData for a list of valid attributes.
2432
+ # +attr+ is a list of attributes to fetch; see FetchStruct documentation for
2433
+ # a list of supported attributes.
2022
2434
  #
2023
2435
  # +changedsince+ is an optional integer mod-sequence. It limits results to
2024
2436
  # messages with a mod-sequence greater than +changedsince+.
2025
2437
  #
2026
2438
  # The return value is an array of FetchData.
2027
2439
  #
2028
- # Related: #uid_search, FetchData
2440
+ # Related: #uid_fetch, FetchData
2029
2441
  #
2030
- # ===== For example:
2442
+ # ==== For example:
2031
2443
  #
2032
2444
  # p imap.fetch(6..8, "UID")
2033
2445
  # #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
@@ -2045,39 +2457,82 @@ module Net
2045
2457
  # p data.attr["UID"]
2046
2458
  # #=> 98
2047
2459
  #
2048
- # ===== Capabilities
2460
+ # ==== Capabilities
2049
2461
  #
2050
- # Many extensions define new message +attr+ names. See FetchData for a list
2051
- # of supported extension fields.
2462
+ # Many extensions define new message +attr+ names. See FetchStruct for a
2463
+ # list of supported extension fields.
2052
2464
  #
2053
2465
  # The server's capabilities must include +CONDSTORE+
2054
- # {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2466
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
2055
2467
  # +changedsince+ argument. Using +changedsince+ implicitly enables the
2056
2468
  # +CONDSTORE+ extension.
2057
- def fetch(set, attr, mod = nil, changedsince: nil)
2058
- fetch_internal("FETCH", set, attr, mod, changedsince: changedsince)
2469
+ #
2470
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2471
+ # +FETCH+ command is prohibited. Use #uid_fetch instead.
2472
+ def fetch(...)
2473
+ fetch_internal("FETCH", ...)
2059
2474
  end
2060
2475
 
2061
2476
  # :call-seq:
2062
- # uid_fetch(set, attr, changedsince: nil) -> array of FetchData
2477
+ # uid_fetch(set, attr, changedsince: nil, partial: nil) -> array of FetchData (or UIDFetchData)
2063
2478
  #
2064
2479
  # Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2065
2480
  # to retrieve data associated with a message in the mailbox.
2066
2481
  #
2067
- # Similar to #fetch, but the +set+ parameter contains unique identifiers
2068
- # instead of message sequence numbers.
2482
+ # +set+ is the message UIDs to fetch, and may be any valid input to
2483
+ # {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
2484
+ # (For message sequence numbers, use #fetch instead.)
2069
2485
  #
2486
+ # +attr+ behaves the same as with #fetch.
2070
2487
  # >>>
2071
2488
  # *Note:* Servers _MUST_ implicitly include the +UID+ message data item as
2072
2489
  # part of any +FETCH+ response caused by a +UID+ command, regardless of
2073
2490
  # whether a +UID+ was specified as a message data item to the +FETCH+.
2074
2491
  #
2492
+ # +changedsince+ (optional) behaves the same as with #fetch.
2493
+ #
2494
+ # +partial+ is an optional range to limit the number of results returned.
2495
+ # It's useful when +set+ contains an unknown number of messages.
2496
+ # <tt>1..500</tt> returns the first 500 messages in +set+ (in mailbox
2497
+ # order), <tt>501..1000</tt> the second 500, and so on. +partial+ may also
2498
+ # be negative: <tt>-500..-1</tt> selects the last 500 messages in +set+.
2499
+ # <em>Requires the +PARTIAL+ capabability.</em>
2500
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2501
+ #
2502
+ # For example:
2503
+ #
2504
+ # # Without partial, the size of the results may be unknown beforehand:
2505
+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS))
2506
+ # # ... maybe wait for a long time ... and allocate a lot of memory ...
2507
+ # results.size # => 0..2**32-1
2508
+ # process results # may also take a long time and use a lot of memory...
2509
+ #
2510
+ # # Using partial, the results may be paginated:
2511
+ # loop do
2512
+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS),
2513
+ # partial: 1..500)
2514
+ # # fetch should return quickly and allocate little memory
2515
+ # results.size # => 0..500
2516
+ # break if results.empty?
2517
+ # next_uid_to_fetch = results.last.uid + 1
2518
+ # process results
2519
+ # end
2520
+ #
2075
2521
  # Related: #fetch, FetchData
2076
2522
  #
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)
2523
+ # ==== Capabilities
2524
+ #
2525
+ # The server's capabilities must include +PARTIAL+
2526
+ # {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394] in order to use the
2527
+ # +partial+ argument.
2528
+ #
2529
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2530
+ # #uid_fetch must be used instead of #fetch, and UIDFetchData will be
2531
+ # returned instead of FetchData.
2532
+ #
2533
+ # Otherwise, #uid_fetch is updated by extensions in the same way as #fetch.
2534
+ def uid_fetch(...)
2535
+ fetch_internal("UID FETCH", ...)
2081
2536
  end
2082
2537
 
2083
2538
  # :call-seq:
@@ -2108,27 +2563,30 @@ module Net
2108
2563
  #
2109
2564
  # Related: #uid_store
2110
2565
  #
2111
- # ===== For example:
2566
+ # ==== For example:
2112
2567
  #
2113
2568
  # p imap.store(6..8, "+FLAGS", [:Deleted])
2114
2569
  # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2115
2570
  # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2116
2571
  # #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
2117
2572
  #
2118
- # ===== Capabilities
2573
+ # ==== Capabilities
2119
2574
  #
2120
2575
  # Extensions may define new data items to be used with #store.
2121
2576
  #
2122
2577
  # The server's capabilities must include +CONDSTORE+
2123
- # {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2578
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
2124
2579
  # +unchangedsince+ argument. Using +unchangedsince+ implicitly enables the
2125
2580
  # +CONDSTORE+ extension.
2581
+ #
2582
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2583
+ # +STORE+ command is prohibited. Use #uid_store instead.
2126
2584
  def store(set, attr, flags, unchangedsince: nil)
2127
2585
  store_internal("STORE", set, attr, flags, unchangedsince: unchangedsince)
2128
2586
  end
2129
2587
 
2130
2588
  # :call-seq:
2131
- # uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData
2589
+ # uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData (or UIDFetchData)
2132
2590
  #
2133
2591
  # Sends a {UID STORE command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2134
2592
  # to alter data associated with messages in the mailbox, in particular their
@@ -2139,8 +2597,13 @@ module Net
2139
2597
  #
2140
2598
  # Related: #store
2141
2599
  #
2142
- # ===== Capabilities
2143
- # Same as #store.
2600
+ # ==== Capabilities
2601
+ #
2602
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2603
+ # #uid_store must be used instead of #store, and UIDFetchData will be
2604
+ # returned instead of FetchData.
2605
+ #
2606
+ # Otherwise, #uid_store is updated by extensions in the same way as #store.
2144
2607
  def uid_store(set, attr, flags, unchangedsince: nil)
2145
2608
  store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince)
2146
2609
  end
@@ -2152,13 +2615,16 @@ module Net
2152
2615
  #
2153
2616
  # Related: #uid_copy
2154
2617
  #
2155
- # ===== Capabilities
2618
+ # ==== Capabilities
2156
2619
  #
2157
2620
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2158
2621
  # supported, the server's response should include a +COPYUID+ response code
2159
2622
  # with UIDPlusData. This will report the UIDVALIDITY of the destination
2160
2623
  # mailbox, the UID set of the source messages, and the assigned UID set of
2161
2624
  # the moved messages.
2625
+ #
2626
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2627
+ # +COPY+ command is prohibited. Use #uid_copy instead.
2162
2628
  def copy(set, mailbox)
2163
2629
  copy_internal("COPY", set, mailbox)
2164
2630
  end
@@ -2169,9 +2635,12 @@ module Net
2169
2635
  #
2170
2636
  # Similar to #copy, but +set+ contains unique identifiers.
2171
2637
  #
2172
- # ===== Capabilities
2638
+ # ==== Capabilities
2173
2639
  #
2174
- # +UIDPLUS+ affects #uid_copy the same way it affects #copy.
2640
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] in enabled,
2641
+ # #uid_copy must be used instead of #copy.
2642
+ #
2643
+ # Otherwise, #uid_copy is updated by extensions in the same way as #copy.
2175
2644
  def uid_copy(set, mailbox)
2176
2645
  copy_internal("UID COPY", set, mailbox)
2177
2646
  end
@@ -2184,10 +2653,10 @@ module Net
2184
2653
  #
2185
2654
  # Related: #uid_move
2186
2655
  #
2187
- # ===== Capabilities
2656
+ # ==== Capabilities
2188
2657
  #
2189
- # The server's capabilities must include +MOVE+
2190
- # [RFC6851[https://tools.ietf.org/html/rfc6851]].
2658
+ # The server's capabilities must include either +IMAP4rev2+ or +MOVE+
2659
+ # [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
2191
2660
  #
2192
2661
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2193
2662
  # supported, the server's response should include a +COPYUID+ response code
@@ -2195,6 +2664,8 @@ module Net
2195
2664
  # mailbox, the UID set of the source messages, and the assigned UID set of
2196
2665
  # the moved messages.
2197
2666
  #
2667
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
2668
+ # +MOVE+ command is prohibited. Use #uid_move instead.
2198
2669
  def move(set, mailbox)
2199
2670
  copy_internal("MOVE", set, mailbox)
2200
2671
  end
@@ -2208,11 +2679,15 @@ module Net
2208
2679
  #
2209
2680
  # Related: #move
2210
2681
  #
2211
- # ===== Capabilities
2682
+ # ==== Capabilities
2212
2683
  #
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.
2684
+ # The server's capabilities must include either +IMAP4rev2+ or +MOVE+
2685
+ # [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
2686
+ #
2687
+ # When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
2688
+ # #uid_move must be used instead of #move.
2689
+ #
2690
+ # Otherwise, #uid_move is updated by extensions in the same way as #move.
2216
2691
  def uid_move(set, mailbox)
2217
2692
  copy_internal("UID MOVE", set, mailbox)
2218
2693
  end
@@ -2228,17 +2703,17 @@ module Net
2228
2703
  #
2229
2704
  # Related: #uid_sort, #search, #uid_search, #thread, #uid_thread
2230
2705
  #
2231
- # ===== For example:
2706
+ # ==== For example:
2232
2707
  #
2233
2708
  # p imap.sort(["FROM"], ["ALL"], "US-ASCII")
2234
2709
  # #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
2235
2710
  # p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
2236
2711
  # #=> [6, 7, 8, 1]
2237
2712
  #
2238
- # ===== Capabilities
2713
+ # ==== Capabilities
2239
2714
  #
2240
2715
  # The server's capabilities must include +SORT+
2241
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2716
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2242
2717
  def sort(sort_keys, search_keys, charset)
2243
2718
  return sort_internal("SORT", sort_keys, search_keys, charset)
2244
2719
  end
@@ -2250,10 +2725,10 @@ module Net
2250
2725
  #
2251
2726
  # Related: #sort, #search, #uid_search, #thread, #uid_thread
2252
2727
  #
2253
- # ===== Capabilities
2728
+ # ==== Capabilities
2254
2729
  #
2255
2730
  # The server's capabilities must include +SORT+
2256
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2731
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2257
2732
  def uid_sort(sort_keys, search_keys, charset)
2258
2733
  return sort_internal("UID SORT", sort_keys, search_keys, charset)
2259
2734
  end
@@ -2275,10 +2750,10 @@ module Net
2275
2750
  #
2276
2751
  # Related: #uid_thread, #search, #uid_search, #sort, #uid_sort
2277
2752
  #
2278
- # ===== Capabilities
2753
+ # ==== Capabilities
2279
2754
  #
2280
2755
  # The server's capabilities must include +THREAD+
2281
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2756
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2282
2757
  def thread(algorithm, search_keys, charset)
2283
2758
  return thread_internal("THREAD", algorithm, search_keys, charset)
2284
2759
  end
@@ -2289,10 +2764,10 @@ module Net
2289
2764
  #
2290
2765
  # Related: #thread, #search, #uid_search, #sort, #uid_sort
2291
2766
  #
2292
- # ===== Capabilities
2767
+ # ==== Capabilities
2293
2768
  #
2294
2769
  # The server's capabilities must include +THREAD+
2295
- # [RFC5256[https://tools.ietf.org/html/rfc5256]].
2770
+ # [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
2296
2771
  def uid_thread(algorithm, search_keys, charset)
2297
2772
  return thread_internal("UID THREAD", algorithm, search_keys, charset)
2298
2773
  end
@@ -2308,11 +2783,11 @@ module Net
2308
2783
  #
2309
2784
  # Related: #capable?, #capabilities, #capability
2310
2785
  #
2311
- # ===== Capabilities
2786
+ # ==== Capabilities
2312
2787
  #
2313
2788
  # 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]].
2789
+ # +ENABLE+ [RFC5161[https://www.rfc-editor.org/rfc/rfc5161]]
2790
+ # or +IMAP4REV2+ [RFC9051[https://www.rfc-editor.org/rfc/rfc9051]].
2316
2791
  #
2317
2792
  # Additionally, the server capabilities must include a capability matching
2318
2793
  # each enabled extension (usually the same name as the enabled extension).
@@ -2331,7 +2806,7 @@ module Net
2331
2806
  # <tt>"UTF8=ACCEPT"</tt> or <tt>"IMAP4rev2"</tt>, depending on server
2332
2807
  # capabilities.
2333
2808
  #
2334
- # [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://tools.ietf.org/html/rfc6855]]]
2809
+ # [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
2335
2810
  #
2336
2811
  # The server's capabilities must include <tt>UTF8=ACCEPT</tt> _or_
2337
2812
  # <tt>UTF8=ONLY</tt>.
@@ -2350,13 +2825,23 @@ module Net
2350
2825
  # encoding, even if they generally contain UTF-8 data, if they are
2351
2826
  # text at all.
2352
2827
  #
2353
- # [<tt>"UTF8=ONLY"</tt> [RFC6855[https://tools.ietf.org/html/rfc6855]]]
2828
+ # [<tt>"UTF8=ONLY"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
2354
2829
  #
2355
2830
  # A server that reports the <tt>UTF8=ONLY</tt> capability _requires_ that
2356
2831
  # the client <tt>enable("UTF8=ACCEPT")</tt> before any mailboxes may be
2357
2832
  # selected. For convenience, <tt>enable("UTF8=ONLY")</tt> is aliased to
2358
2833
  # <tt>enable("UTF8=ACCEPT")</tt>.
2359
2834
  #
2835
+ # [+UIDONLY+ {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.pdf]]
2836
+ #
2837
+ # When UIDONLY is enabled, the #fetch, #store, #search, #copy, and #move
2838
+ # commands are prohibited and result in a tagged BAD response. Clients
2839
+ # should instead use uid_fetch, uid_store, uid_search, uid_copy, or
2840
+ # uid_move, respectively. All +FETCH+ responses that would be returned are
2841
+ # replaced by +UIDFETCH+ responses. All +EXPUNGED+ responses that would be
2842
+ # returned are replaced by +VANISHED+ responses. The "<sequence set>"
2843
+ # uid_search criterion is prohibited.
2844
+ #
2360
2845
  # ===== Unsupported capabilities
2361
2846
  #
2362
2847
  # *Note:* Some extensions that use ENABLE permit the server to send syntax
@@ -2397,17 +2882,23 @@ module Net
2397
2882
  # checks the connection for each 60 seconds.
2398
2883
  #
2399
2884
  # loop do
2400
- # imap.idle(60) do |res|
2401
- # ...
2885
+ # imap.idle(60) do |response|
2886
+ # do_something_with(response)
2887
+ # imap.idle_done if some_condition?(response)
2402
2888
  # end
2403
2889
  # end
2404
2890
  #
2891
+ # Returns the server's response to indicate the IDLE state has ended.
2892
+ # Returns +nil+ if the server does not respond to #idle_done within
2893
+ # {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]
2894
+ # seconds.
2895
+ #
2405
2896
  # Related: #idle_done, #noop, #check
2406
2897
  #
2407
- # ===== Capabilities
2898
+ # ==== Capabilities
2408
2899
  #
2409
- # The server's capabilities must include +IDLE+
2410
- # [RFC2177[https://tools.ietf.org/html/rfc2177]].
2900
+ # The server's capabilities must include either +IMAP4rev2+ or +IDLE+
2901
+ # [RFC2177[https://www.rfc-editor.org/rfc/rfc2177]].
2411
2902
  def idle(timeout = nil, &response_handler)
2412
2903
  raise LocalJumpError, "no block given" unless response_handler
2413
2904
 
@@ -2429,7 +2920,7 @@ module Net
2429
2920
  unless @receiver_thread_terminating
2430
2921
  remove_response_handler(response_handler)
2431
2922
  put_string("DONE#{CRLF}")
2432
- response = get_tagged_response(tag, "IDLE", @idle_response_timeout)
2923
+ response = get_tagged_response(tag, "IDLE", idle_response_timeout)
2433
2924
  end
2434
2925
  end
2435
2926
  end
@@ -2437,7 +2928,11 @@ module Net
2437
2928
  return response
2438
2929
  end
2439
2930
 
2440
- # Leaves IDLE.
2931
+ # Leaves IDLE, allowing #idle to return.
2932
+ #
2933
+ # If the server does not respond within
2934
+ # {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]
2935
+ # seconds, #idle will return +nil+.
2441
2936
  #
2442
2937
  # Related: #idle
2443
2938
  def idle_done
@@ -2449,40 +2944,98 @@ module Net
2449
2944
  end
2450
2945
  end
2451
2946
 
2947
+ RESPONSES_DEPRECATION_MSG =
2948
+ "Pass a type or block to #responses, " \
2949
+ "set config.responses_without_block to :frozen_dup " \
2950
+ "or :silence_deprecation_warning, " \
2951
+ "or use #extract_responses or #clear_responses."
2952
+ private_constant :RESPONSES_DEPRECATION_MSG
2953
+
2452
2954
  # :call-seq:
2955
+ # responses -> hash of {String => Array} (see config.responses_without_block)
2956
+ # responses(type) -> frozen array
2453
2957
  # responses {|hash| ...} -> block result
2454
2958
  # responses(type) {|array| ...} -> block result
2455
2959
  #
2456
- # Yields unhandled responses and returns the result of the block.
2960
+ # Yields or returns unhandled server responses. Unhandled responses are
2961
+ # stored in a hash, with arrays of UntaggedResponse#data keyed by
2962
+ # UntaggedResponse#name and <em>non-+nil+</em> untagged ResponseCode#data
2963
+ # keyed by ResponseCode#name.
2457
2964
  #
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.
2965
+ # When a block is given, yields unhandled responses and returns the block's
2966
+ # result. Without a block, returns the unhandled responses.
2967
+ #
2968
+ # [With +type+]
2969
+ # Yield or return only the array of responses for that +type+.
2970
+ # When no block is given, the returned array is a frozen copy.
2971
+ # [Without +type+]
2972
+ # Yield or return the entire responses hash.
2973
+ #
2974
+ # When no block is given, the behavior is determined by
2975
+ # Config#responses_without_block:
2976
+ # >>>
2977
+ # [+:silence_deprecation_warning+ <em>(original behavior)</em>]
2978
+ # Returns the mutable responses hash (without any warnings).
2979
+ # <em>This is not thread-safe.</em>
2980
+ #
2981
+ # [+:warn+ <em>(default since +v0.5+)</em>]
2982
+ # Prints a warning and returns the mutable responses hash.
2983
+ # <em>This is not thread-safe.</em>
2984
+ #
2985
+ # [+:frozen_dup+ <em>(planned default for +v0.6+)</em>]
2986
+ # Returns a frozen copy of the unhandled responses hash, with frozen
2987
+ # array values.
2988
+ #
2989
+ # [+:raise+]
2990
+ # Raise an +ArgumentError+ with the deprecation warning.
2463
2991
  #
2464
2992
  # For example:
2465
2993
  #
2466
2994
  # imap.select("inbox")
2467
- # p imap.responses("EXISTS", &:last)
2995
+ # p imap.responses("EXISTS").last
2468
2996
  # #=> 2
2997
+ # p imap.responses("UIDNEXT", &:last)
2998
+ # #=> 123456
2469
2999
  # p imap.responses("UIDVALIDITY", &:last)
2470
3000
  # #=> 968263756
3001
+ # p imap.responses {|responses|
3002
+ # {
3003
+ # exists: responses.delete("EXISTS").last,
3004
+ # uidnext: responses.delete("UIDNEXT").last,
3005
+ # uidvalidity: responses.delete("UIDVALIDITY").last,
3006
+ # }
3007
+ # }
3008
+ # #=> {:exists=>2, :uidnext=>123456, :uidvalidity=>968263756}
3009
+ # # "EXISTS", "UIDNEXT", and "UIDVALIDITY" have been removed:
3010
+ # p imap.responses(&:keys)
3011
+ # #=> ["FLAGS", "OK", "PERMANENTFLAGS", "RECENT", "HIGHESTMODSEQ"]
2471
3012
  #
3013
+ # Related: #extract_responses, #clear_responses, #response_handlers, #greeting
3014
+ #
3015
+ # ==== Thread safety
2472
3016
  # >>>
2473
3017
  # *Note:* Access to the responses hash is synchronized for thread-safety.
2474
3018
  # The receiver thread and response_handlers cannot process new responses
2475
3019
  # until the block completes. Accessing either the response hash or its
2476
- # response type arrays outside of the block is unsafe.
3020
+ # response type arrays outside of the block is unsafe. They can be safely
3021
+ # updated inside the block. Consider using #clear_responses or
3022
+ # #extract_responses instead.
3023
+ #
3024
+ # Net::IMAP will add and remove responses from the responses hash and its
3025
+ # array values, in the calling threads for commands and in the receiver
3026
+ # thread, but will not modify any responses after adding them to the
3027
+ # responses hash.
2477
3028
  #
2478
- # Calling without a block is unsafe and deprecated. Future releases will
2479
- # raise ArgumentError unless a block is given.
3029
+ # ==== Clearing responses
2480
3030
  #
2481
3031
  # Previously unhandled responses are automatically cleared before entering a
2482
3032
  # mailbox with #select or #examine. Long-lived connections can receive many
2483
3033
  # unhandled server responses, which must be pruned or they will continually
2484
3034
  # consume more memory. Update or clear the responses hash or arrays inside
2485
- # the block, or use #clear_responses.
3035
+ # the block, or remove responses with #extract_responses, #clear_responses,
3036
+ # or #add_response_handler.
3037
+ #
3038
+ # ==== Missing responses
2486
3039
  #
2487
3040
  # Only non-+nil+ data is stored. Many important response codes have no data
2488
3041
  # of their own, but are used as "tags" on the ResponseText object they are
@@ -2493,15 +3046,25 @@ module Net
2493
3046
  # ResponseCode#data on tagged responses. Although some command methods do
2494
3047
  # return the TaggedResponse directly, #add_response_handler must be used to
2495
3048
  # handle all response codes.
2496
- #
2497
- # Related: #clear_responses, #response_handlers, #greeting
2498
3049
  def responses(type = nil)
2499
3050
  if block_given?
2500
3051
  synchronize { yield(type ? @responses[type.to_s.upcase] : @responses) }
2501
3052
  elsif type
2502
- raise ArgumentError, "Pass a block or use #clear_responses"
3053
+ synchronize { @responses[type.to_s.upcase].dup.freeze }
2503
3054
  else
2504
- # warn("DEPRECATED: pass a block or use #clear_responses", uplevel: 1)
3055
+ case config.responses_without_block
3056
+ when :raise
3057
+ raise ArgumentError, RESPONSES_DEPRECATION_MSG
3058
+ when :warn
3059
+ warn(RESPONSES_DEPRECATION_MSG, uplevel: 1, category: :deprecated)
3060
+ when :frozen_dup
3061
+ synchronize {
3062
+ responses = @responses.transform_values(&:freeze)
3063
+ responses.default_proc = nil
3064
+ responses.default = [].freeze
3065
+ return responses.freeze
3066
+ }
3067
+ end
2505
3068
  @responses
2506
3069
  end
2507
3070
  end
@@ -2516,7 +3079,7 @@ module Net
2516
3079
  # Clearing responses is synchronized with other threads. The lock is
2517
3080
  # released before returning.
2518
3081
  #
2519
- # Related: #responses, #response_handlers
3082
+ # Related: #extract_responses, #responses, #response_handlers
2520
3083
  def clear_responses(type = nil)
2521
3084
  synchronize {
2522
3085
  if type
@@ -2530,6 +3093,30 @@ module Net
2530
3093
  .freeze
2531
3094
  end
2532
3095
 
3096
+ # :call-seq:
3097
+ # extract_responses(type) {|response| ... } -> array
3098
+ #
3099
+ # Yields all of the unhandled #responses for a single response +type+.
3100
+ # Removes and returns the responses for which the block returns a true
3101
+ # value.
3102
+ #
3103
+ # Extracting responses is synchronized with other threads. The lock is
3104
+ # released before returning.
3105
+ #
3106
+ # Related: #responses, #clear_responses
3107
+ def extract_responses(type)
3108
+ type = String.try_convert(type) or
3109
+ raise ArgumentError, "type must be a string"
3110
+ raise ArgumentError, "must provide a block" unless block_given?
3111
+ extracted = []
3112
+ responses(type) do |all|
3113
+ all.reject! do |response|
3114
+ extracted << response if yield response
3115
+ end
3116
+ end
3117
+ extracted
3118
+ end
3119
+
2533
3120
  # Returns all response handlers, including those that are added internally
2534
3121
  # by commands. Each response handler will be called with every new
2535
3122
  # UntaggedResponse, TaggedResponse, and ContinuationRequest.
@@ -2582,8 +3169,6 @@ module Net
2582
3169
  PORT = 143 # :nodoc:
2583
3170
  SSL_PORT = 993 # :nodoc:
2584
3171
 
2585
- @@debug = false
2586
-
2587
3172
  def start_imap_connection
2588
3173
  @greeting = get_server_greeting
2589
3174
  @capabilities = capabilities_from_resp_code @greeting
@@ -2611,12 +3196,12 @@ module Net
2611
3196
  end
2612
3197
 
2613
3198
  def tcp_socket(host, port)
2614
- s = Socket.tcp(host, port, :connect_timeout => @open_timeout)
3199
+ s = Socket.tcp(host, port, :connect_timeout => open_timeout)
2615
3200
  s.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, true)
2616
3201
  s
2617
3202
  rescue Errno::ETIMEDOUT
2618
3203
  raise Net::OpenTimeout, "Timeout to open TCP connection to " +
2619
- "#{host}:#{port} (exceeds #{@open_timeout} seconds)"
3204
+ "#{host}:#{port} (exceeds #{open_timeout} seconds)"
2620
3205
  end
2621
3206
 
2622
3207
  def receive_responses
@@ -2728,7 +3313,7 @@ module Net
2728
3313
  end
2729
3314
  end
2730
3315
  return nil if buff.length == 0
2731
- if @@debug
3316
+ if config.debug?
2732
3317
  $stderr.print(buff.gsub(/^/n, "S: "))
2733
3318
  end
2734
3319
  return @parser.parse(buff)
@@ -2807,7 +3392,7 @@ module Net
2807
3392
 
2808
3393
  def put_string(str)
2809
3394
  @sock.print(str)
2810
- if @@debug
3395
+ if config.debug?
2811
3396
  if @debug_output_bol
2812
3397
  $stderr.print("C: ")
2813
3398
  end
@@ -2820,23 +3405,115 @@ module Net
2820
3405
  end
2821
3406
  end
2822
3407
 
2823
- def search_internal(cmd, keys, charset)
2824
- if keys.instance_of?(String)
2825
- keys = [RawData.new(keys)]
3408
+ def enforce_logindisabled?
3409
+ if config.enforce_logindisabled == :when_capabilities_cached
3410
+ capabilities_cached?
2826
3411
  else
2827
- normalize_searching_criteria(keys)
3412
+ config.enforce_logindisabled
3413
+ end
3414
+ end
3415
+
3416
+ def expunge_internal(...)
3417
+ synchronize do
3418
+ send_command(...)
3419
+ expunged_array = clear_responses("EXPUNGE")
3420
+ vanished_array = extract_responses("VANISHED") { !_1.earlier? }
3421
+ if vanished_array.empty?
3422
+ expunged_array
3423
+ elsif vanished_array.length == 1
3424
+ vanished_array.first
3425
+ else
3426
+ merged_uids = SequenceSet[*vanished_array.map(&:uids)]
3427
+ VanishedData[uids: merged_uids, earlier: false]
3428
+ end
3429
+ end
3430
+ end
3431
+
3432
+ RETURN_WHOLE = /\ARETURN\z/i
3433
+ RETURN_START = /\ARETURN\b/i
3434
+ private_constant :RETURN_WHOLE, :RETURN_START
3435
+
3436
+ def search_args(keys, charset_arg = nil, return: nil, charset: nil)
3437
+ {return:} => {return: return_kw}
3438
+ case [return_kw, keys]
3439
+ in [nil, Array[RETURN_WHOLE, return_opts, *keys]]
3440
+ return_opts = convert_return_opts(return_opts)
3441
+ esearch = true
3442
+ in [nil => return_opts, RETURN_START]
3443
+ esearch = true
3444
+ in [nil => return_opts, keys]
3445
+ esearch = false
3446
+ in [_, Array[RETURN_WHOLE, _, *] | RETURN_START]
3447
+ raise ArgumentError, "conflicting return options"
3448
+ in [_, Array[RETURN_WHOLE, _, *]] # workaround for https://bugs.ruby-lang.org/issues/20956
3449
+ raise ArgumentError, "conflicting return options"
3450
+ in [_, RETURN_START] # workaround for https://bugs.ruby-lang.org/issues/20956
3451
+ raise ArgumentError, "conflicting return options"
3452
+ in [return_opts, keys]
3453
+ return_opts = convert_return_opts(return_opts)
3454
+ esearch = true
3455
+ end
3456
+ if charset && charset_arg
3457
+ raise ArgumentError, "multiple charset arguments"
3458
+ end
3459
+ charset ||= charset_arg
3460
+ # NOTE: not handling combined RETURN and CHARSET for raw strings
3461
+ if charset && keys in /\ACHARSET\b/i | Array[/\ACHARSET\z/i, *]
3462
+ raise ArgumentError, "multiple charset arguments"
2828
3463
  end
3464
+ args = normalize_searching_criteria(keys)
3465
+ args.prepend("CHARSET", charset) if charset
3466
+ args.prepend("RETURN", return_opts) if return_opts
3467
+ return args, esearch
3468
+ end
3469
+
3470
+ def convert_return_opts(unconverted)
3471
+ return_opts = Array.try_convert(unconverted) or
3472
+ raise TypeError, "expected return options to be Array, got %s" % [
3473
+ unconverted.class
3474
+ ]
3475
+ return_opts.map {|opt|
3476
+ case opt
3477
+ when Symbol then opt.to_s
3478
+ when PartialRange::Negative then PartialRange[opt]
3479
+ when Range then SequenceSet[opt]
3480
+ else opt
3481
+ end
3482
+ }
3483
+ end
3484
+
3485
+ def search_internal(cmd, ...)
3486
+ args, esearch = search_args(...)
2829
3487
  synchronize do
2830
- if charset
2831
- send_command(cmd, "CHARSET", charset, *keys)
3488
+ tagged = send_command(cmd, *args)
3489
+ tag = tagged.tag
3490
+ # Only the last ESEARCH or SEARCH is used. Excess results are ignored.
3491
+ esearch_result = extract_responses("ESEARCH") {|response|
3492
+ response in ESearchResult(tag: ^tag)
3493
+ }.last
3494
+ search_result = clear_responses("SEARCH").last
3495
+ if esearch_result
3496
+ # silently ignore SEARCH results, if any
3497
+ esearch_result
3498
+ elsif search_result
3499
+ # warn EXPECTED_ESEARCH_RESULT if esearch
3500
+ search_result
3501
+ elsif esearch
3502
+ # warn NO_SEARCH_RESPONSE
3503
+ ESearchResult[tag:, uid: cmd.start_with?("UID ")]
2832
3504
  else
2833
- send_command(cmd, *keys)
3505
+ # warn NO_SEARCH_RESPONSE
3506
+ SearchResult[]
2834
3507
  end
2835
- clear_responses("SEARCH").last || []
2836
3508
  end
2837
3509
  end
2838
3510
 
2839
- def fetch_internal(cmd, set, attr, mod = nil, changedsince: nil)
3511
+ def fetch_internal(cmd, set, attr, mod = nil, partial: nil, changedsince: nil)
3512
+ set = SequenceSet[set]
3513
+ if partial
3514
+ mod ||= []
3515
+ mod << "PARTIAL" << PartialRange[partial]
3516
+ end
2840
3517
  if changedsince
2841
3518
  mod ||= []
2842
3519
  mod << "CHANGEDSINCE" << Integer(changedsince)
@@ -2850,39 +3527,36 @@ module Net
2850
3527
  }
2851
3528
  end
2852
3529
 
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
3530
+ args = [cmd, set, attr]
3531
+ args << mod if mod
3532
+ send_command_returning_fetch_results(*args)
2862
3533
  end
2863
3534
 
2864
3535
  def store_internal(cmd, set, attr, flags, unchangedsince: nil)
2865
3536
  attr = RawData.new(attr) if attr.instance_of?(String)
2866
- args = [MessageSet.new(set)]
3537
+ args = [SequenceSet.new(set)]
2867
3538
  args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
2868
3539
  args << attr << flags
3540
+ send_command_returning_fetch_results(cmd, *args)
3541
+ end
3542
+
3543
+ def send_command_returning_fetch_results(...)
2869
3544
  synchronize do
2870
3545
  clear_responses("FETCH")
2871
- send_command(cmd, *args)
2872
- clear_responses("FETCH")
3546
+ clear_responses("UIDFETCH")
3547
+ send_command(...)
3548
+ fetches = clear_responses("FETCH")
3549
+ uidfetches = clear_responses("UIDFETCH")
3550
+ uidfetches.any? ? uidfetches : fetches
2873
3551
  end
2874
3552
  end
2875
3553
 
2876
3554
  def copy_internal(cmd, set, mailbox)
2877
- send_command(cmd, MessageSet.new(set), mailbox)
3555
+ send_command(cmd, SequenceSet.new(set), mailbox)
2878
3556
  end
2879
3557
 
2880
3558
  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
3559
+ search_keys = normalize_searching_criteria(search_keys)
2886
3560
  synchronize do
2887
3561
  send_command(cmd, sort_keys, charset, *search_keys)
2888
3562
  clear_responses("SORT").last || []
@@ -2890,25 +3564,39 @@ module Net
2890
3564
  end
2891
3565
 
2892
3566
  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
3567
+ search_keys = normalize_searching_criteria(search_keys)
2898
3568
  synchronize do
2899
3569
  send_command(cmd, algorithm, charset, *search_keys)
2900
3570
  clear_responses("THREAD").last || []
2901
3571
  end
2902
3572
  end
2903
3573
 
2904
- def normalize_searching_criteria(keys)
2905
- keys.collect! do |i|
2906
- case i
2907
- when -1, Range, Array
2908
- MessageSet.new(i)
3574
+ def normalize_searching_criteria(criteria)
3575
+ return [RawData.new(criteria)] if criteria.is_a?(String)
3576
+ criteria.map {|i|
3577
+ if coerce_search_arg_to_seqset?(i)
3578
+ SequenceSet[i]
2909
3579
  else
2910
3580
  i
2911
3581
  end
3582
+ }
3583
+ end
3584
+
3585
+ def coerce_search_arg_to_seqset?(obj)
3586
+ case obj
3587
+ when Set, -1, :* then true
3588
+ when Range then true
3589
+ when Array then obj.all? { coerce_search_array_arg_to_seqset? _1 }
3590
+ else obj.respond_to?(:to_sequence_set)
3591
+ end
3592
+ end
3593
+
3594
+ def coerce_search_array_arg_to_seqset?(obj)
3595
+ case obj
3596
+ when Integer then obj.positive? || obj == -1
3597
+ when String then ResponseParser::Patterns::SEQUENCE_SET_STR.match?(obj.b)
3598
+ else
3599
+ coerce_search_arg_to_seqset?(obj)
2912
3600
  end
2913
3601
  end
2914
3602
 
@@ -2934,7 +3622,7 @@ module Net
2934
3622
  @sock = SSLSocket.new(@sock, ssl_ctx)
2935
3623
  @sock.sync_close = true
2936
3624
  @sock.hostname = @host if @sock.respond_to? :hostname=
2937
- ssl_socket_connect(@sock, @open_timeout)
3625
+ ssl_socket_connect(@sock, open_timeout)
2938
3626
  if ssl_ctx.verify_mode != VERIFY_NONE
2939
3627
  @sock.post_connection_check(@host)
2940
3628
  @tls_verified = true
@@ -2959,8 +3647,10 @@ module Net
2959
3647
  end
2960
3648
 
2961
3649
  require_relative "imap/errors"
3650
+ require_relative "imap/config"
2962
3651
  require_relative "imap/command_data"
2963
3652
  require_relative "imap/data_encoding"
3653
+ require_relative "imap/data_lite"
2964
3654
  require_relative "imap/flags"
2965
3655
  require_relative "imap/response_data"
2966
3656
  require_relative "imap/response_parser"