net-imap 0.4.22 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +12 -2
- data/README.md +10 -4
- data/docs/styles.css +75 -14
- data/lib/net/imap/authenticators.rb +2 -2
- data/lib/net/imap/command_data.rb +40 -95
- data/lib/net/imap/config/attr_accessors.rb +8 -9
- data/lib/net/imap/config/attr_inheritance.rb +64 -1
- data/lib/net/imap/config/attr_type_coercion.rb +22 -10
- data/lib/net/imap/config/attr_version_defaults.rb +90 -0
- data/lib/net/imap/config.rb +241 -125
- data/lib/net/imap/connection_state.rb +48 -0
- data/lib/net/imap/data_encoding.rb +80 -31
- data/lib/net/imap/deprecated_client_options.rb +6 -3
- data/lib/net/imap/errors.rb +158 -0
- data/lib/net/imap/esearch_result.rb +225 -0
- data/lib/net/imap/fetch_data.rb +126 -47
- data/lib/net/imap/flags.rb +1 -1
- data/lib/net/imap/response_data.rb +123 -187
- data/lib/net/imap/response_parser/parser_utils.rb +19 -23
- data/lib/net/imap/response_parser.rb +182 -38
- data/lib/net/imap/response_reader.rb +10 -12
- data/lib/net/imap/sasl/anonymous_authenticator.rb +3 -3
- data/lib/net/imap/sasl/authentication_exchange.rb +52 -20
- data/lib/net/imap/sasl/authenticators.rb +8 -4
- data/lib/net/imap/sasl/client_adapter.rb +77 -26
- data/lib/net/imap/sasl/cram_md5_authenticator.rb +4 -4
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +218 -56
- data/lib/net/imap/sasl/external_authenticator.rb +2 -2
- data/lib/net/imap/sasl/gs2_header.rb +7 -7
- data/lib/net/imap/sasl/login_authenticator.rb +4 -3
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +6 -6
- data/lib/net/imap/sasl/plain_authenticator.rb +7 -7
- data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
- data/lib/net/imap/sasl/scram_authenticator.rb +8 -8
- data/lib/net/imap/sasl.rb +7 -4
- data/lib/net/imap/sasl_adapter.rb +0 -1
- data/lib/net/imap/search_result.rb +10 -5
- data/lib/net/imap/sequence_set.rb +1104 -421
- data/lib/net/imap/stringprep/nameprep.rb +1 -1
- data/lib/net/imap/stringprep/trace.rb +4 -4
- data/lib/net/imap/uidplus_data.rb +4 -147
- data/lib/net/imap/vanished_data.rb +65 -0
- data/lib/net/imap.rb +1002 -313
- data/net-imap.gemspec +1 -1
- data/rakelib/rfcs.rake +2 -0
- data/rakelib/string_prep_tables_generator.rb +6 -2
- metadata +7 -3
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://
|
|
29
|
-
# and {IMAP4rev2 [RFC9051]}[https://
|
|
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
|
#
|
|
@@ -53,6 +53,8 @@ module Net
|
|
|
53
53
|
# states: <tt>not authenticated</tt>, +authenticated+, +selected+, and
|
|
54
54
|
# +logout+. Most commands are valid only in certain states.
|
|
55
55
|
#
|
|
56
|
+
# See #connection_state.
|
|
57
|
+
#
|
|
56
58
|
# === Sequence numbers and UIDs
|
|
57
59
|
#
|
|
58
60
|
# Messages have two sorts of identifiers: message sequence
|
|
@@ -342,23 +344,23 @@ module Net
|
|
|
342
344
|
# === Core \IMAP commands
|
|
343
345
|
#
|
|
344
346
|
# The following commands are defined either by
|
|
345
|
-
# the [IMAP4rev1[https://
|
|
347
|
+
# the [IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501]] base specification, or
|
|
346
348
|
# by one of the following extensions:
|
|
347
|
-
# [IDLE[https://
|
|
348
|
-
# [NAMESPACE[https://
|
|
349
|
-
# [UNSELECT[https://
|
|
350
|
-
# [ENABLE[https://
|
|
351
|
-
# [MOVE[https://
|
|
349
|
+
# [IDLE[https://www.rfc-editor.org/rfc/rfc2177]],
|
|
350
|
+
# [NAMESPACE[https://www.rfc-editor.org/rfc/rfc2342]],
|
|
351
|
+
# [UNSELECT[https://www.rfc-editor.org/rfc/rfc3691]],
|
|
352
|
+
# [ENABLE[https://www.rfc-editor.org/rfc/rfc5161]],
|
|
353
|
+
# [MOVE[https://www.rfc-editor.org/rfc/rfc6851]].
|
|
352
354
|
# These extensions are widely supported by modern IMAP4rev1 servers and have
|
|
353
|
-
# all been integrated into [IMAP4rev2[https://
|
|
355
|
+
# all been integrated into [IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]].
|
|
354
356
|
# <em>*NOTE:* Net::IMAP doesn't support IMAP4rev2 yet.</em>
|
|
355
357
|
#
|
|
356
358
|
# ==== Any state
|
|
357
359
|
#
|
|
358
360
|
# - #capability: Returns the server's capabilities as an array of strings.
|
|
359
361
|
#
|
|
360
|
-
# <em>In general
|
|
361
|
-
# +CAPABILITY+ command to the server.</em>
|
|
362
|
+
# <em>In general,</em> #capable? <em>should be used rather than explicitly
|
|
363
|
+
# sending a +CAPABILITY+ command to the server.</em>
|
|
362
364
|
# - #noop: Allows the server to send unsolicited untagged #responses.
|
|
363
365
|
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
|
364
366
|
#
|
|
@@ -446,7 +448,7 @@ module Net
|
|
|
446
448
|
#
|
|
447
449
|
# ==== RFC9051: +IMAP4rev2+
|
|
448
450
|
#
|
|
449
|
-
# Although IMAP4rev2[https://
|
|
451
|
+
# Although IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] is not supported
|
|
450
452
|
# yet, Net::IMAP supports several extensions that have been folded into it:
|
|
451
453
|
# +ENABLE+, +IDLE+, +MOVE+, +NAMESPACE+, +SASL-IR+, +UIDPLUS+, +UNSELECT+,
|
|
452
454
|
# <tt>STATUS=SIZE</tt>, and the fetch side of +BINARY+.
|
|
@@ -456,7 +458,7 @@ module Net
|
|
|
456
458
|
# >>>
|
|
457
459
|
# <em>The following are folded into +IMAP4rev2+ but are currently
|
|
458
460
|
# unsupported or incompletely supported by</em> Net::IMAP<em>: RFC4466
|
|
459
|
-
# extensions, +
|
|
461
|
+
# extensions, +SEARCHRES+, +LIST-EXTENDED+, +LIST-STATUS+,
|
|
460
462
|
# +LITERAL-+, and +SPECIAL-USE+.</em>
|
|
461
463
|
#
|
|
462
464
|
# ==== RFC2087: +QUOTA+
|
|
@@ -466,13 +468,13 @@ module Net
|
|
|
466
468
|
# - #setquota: sets the resource limits for a given quota root.
|
|
467
469
|
#
|
|
468
470
|
# ==== RFC2177: +IDLE+
|
|
469
|
-
# Folded into IMAP4rev2[https://
|
|
471
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
470
472
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
471
473
|
# - #idle: Allows the server to send updates to the client, without the client
|
|
472
474
|
# needing to poll using #noop.
|
|
473
475
|
#
|
|
474
476
|
# ==== RFC2342: +NAMESPACE+
|
|
475
|
-
# Folded into IMAP4rev2[https://
|
|
477
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
476
478
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
477
479
|
# - #namespace: Returns mailbox namespaces, with path prefixes and delimiters.
|
|
478
480
|
#
|
|
@@ -481,7 +483,7 @@ module Net
|
|
|
481
483
|
#
|
|
482
484
|
# ==== RFC3516: +BINARY+
|
|
483
485
|
# The fetch side of +BINARY+ has been folded into
|
|
484
|
-
# IMAP4rev2[https://
|
|
486
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
|
|
485
487
|
# - Updates #fetch and #uid_fetch with the +BINARY+, +BINARY.PEEK+, and
|
|
486
488
|
# +BINARY.SIZE+ items. See FetchData#binary and FetchData#binary_size.
|
|
487
489
|
#
|
|
@@ -489,7 +491,7 @@ module Net
|
|
|
489
491
|
# *NOTE:* The binary extension the #append command is _not_ supported yet.
|
|
490
492
|
#
|
|
491
493
|
# ==== RFC3691: +UNSELECT+
|
|
492
|
-
# Folded into IMAP4rev2[https://
|
|
494
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
493
495
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
494
496
|
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
|
495
497
|
# without expunging any messages.
|
|
@@ -501,19 +503,23 @@ module Net
|
|
|
501
503
|
# *NOTE:* +DELETEACL+, +LISTRIGHTS+, and +MYRIGHTS+ are not supported yet.
|
|
502
504
|
#
|
|
503
505
|
# ==== RFC4315: +UIDPLUS+
|
|
504
|
-
# Folded into IMAP4rev2[https://
|
|
506
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
505
507
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
506
508
|
# - #uid_expunge: Restricts #expunge to only remove the specified UIDs.
|
|
507
509
|
# - Updates #select, #examine with the +UIDNOTSTICKY+ ResponseCode
|
|
508
510
|
# - Updates #append with the +APPENDUID+ ResponseCode
|
|
509
511
|
# - Updates #copy, #move with the +COPYUID+ ResponseCode
|
|
510
512
|
#
|
|
513
|
+
# ==== RFC4731: +ESEARCH+
|
|
514
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
|
|
515
|
+
# - Updates #search, #uid_search with +return+ options and ESearchResult.
|
|
516
|
+
#
|
|
511
517
|
# ==== RFC4959: +SASL-IR+
|
|
512
|
-
# Folded into IMAP4rev2[https://
|
|
518
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
|
|
513
519
|
# - Updates #authenticate with the option to send an initial response.
|
|
514
520
|
#
|
|
515
521
|
# ==== RFC5161: +ENABLE+
|
|
516
|
-
# Folded into IMAP4rev2[https://
|
|
522
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
517
523
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
518
524
|
# - #enable: Enables backwards incompatible server extensions.
|
|
519
525
|
#
|
|
@@ -537,7 +543,7 @@ module Net
|
|
|
537
543
|
# +X-GM-THRID+, but Gmail does not support it (as of 2023-11-10).
|
|
538
544
|
#
|
|
539
545
|
# ==== RFC6851: +MOVE+
|
|
540
|
-
# Folded into IMAP4rev2[https://
|
|
546
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
541
547
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
542
548
|
# - #move, #uid_move: Moves the specified messages to the end of the
|
|
543
549
|
# specified destination mailbox, expunging them from the current mailbox.
|
|
@@ -572,6 +578,17 @@ module Net
|
|
|
572
578
|
# See FetchData#emailid and FetchData#emailid.
|
|
573
579
|
# - Updates #status with support for the +MAILBOXID+ status attribute.
|
|
574
580
|
#
|
|
581
|
+
# ==== RFC9394: +PARTIAL+
|
|
582
|
+
# - Updates #search, #uid_search with the +PARTIAL+ return option which adds
|
|
583
|
+
# ESearchResult#partial return data.
|
|
584
|
+
# - Updates #uid_fetch with the +partial+ modifier.
|
|
585
|
+
#
|
|
586
|
+
# ==== RFC9586: +UIDONLY+
|
|
587
|
+
# - Updates #enable with +UIDONLY+ parameter.
|
|
588
|
+
# - Updates #uid_fetch and #uid_store to return +UIDFETCH+ response.
|
|
589
|
+
# - Updates #expunge and #uid_expunge to return +VANISHED+ response.
|
|
590
|
+
# - Prohibits use of message sequence numbers in responses or requests.
|
|
591
|
+
#
|
|
575
592
|
# == References
|
|
576
593
|
#
|
|
577
594
|
# [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501.html]]::
|
|
@@ -602,57 +619,57 @@ module Net
|
|
|
602
619
|
# Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC 2180, DOI
|
|
603
620
|
# 10.17487/RFC2180, July 1997, <https://www.rfc-editor.org/info/rfc2180>.
|
|
604
621
|
#
|
|
605
|
-
# [UTF7[https://
|
|
622
|
+
# [UTF7[https://www.rfc-editor.org/rfc/rfc2152]]::
|
|
606
623
|
# Goldsmith, D. and M. Davis, "UTF-7 A Mail-Safe Transformation Format of
|
|
607
624
|
# Unicode", RFC 2152, DOI 10.17487/RFC2152, May 1997,
|
|
608
625
|
# <https://www.rfc-editor.org/info/rfc2152>.
|
|
609
626
|
#
|
|
610
627
|
# === Message envelope and body structure
|
|
611
628
|
#
|
|
612
|
-
# [RFC5322[https://
|
|
629
|
+
# [RFC5322[https://www.rfc-editor.org/rfc/rfc5322]]::
|
|
613
630
|
# Resnick, P., Ed., "Internet Message Format",
|
|
614
631
|
# RFC 5322, DOI 10.17487/RFC5322, October 2008,
|
|
615
632
|
# <https://www.rfc-editor.org/info/rfc5322>.
|
|
616
633
|
#
|
|
617
634
|
# <em>Note: obsoletes</em>
|
|
618
|
-
# RFC-2822[https://
|
|
619
|
-
# RFC-822[https://
|
|
635
|
+
# RFC-2822[https://www.rfc-editor.org/rfc/rfc2822]<em> (April 2001) and</em>
|
|
636
|
+
# RFC-822[https://www.rfc-editor.org/rfc/rfc822]<em> (August 1982).</em>
|
|
620
637
|
#
|
|
621
|
-
# [CHARSET[https://
|
|
638
|
+
# [CHARSET[https://www.rfc-editor.org/rfc/rfc2978]]::
|
|
622
639
|
# Freed, N. and J. Postel, "IANA Charset Registration Procedures", BCP 19,
|
|
623
640
|
# RFC 2978, DOI 10.17487/RFC2978, October 2000,
|
|
624
641
|
# <https://www.rfc-editor.org/info/rfc2978>.
|
|
625
642
|
#
|
|
626
|
-
# [DISPOSITION[https://
|
|
643
|
+
# [DISPOSITION[https://www.rfc-editor.org/rfc/rfc2183]]::
|
|
627
644
|
# Troost, R., Dorner, S., and K. Moore, Ed., "Communicating Presentation
|
|
628
645
|
# Information in Internet Messages: The Content-Disposition Header
|
|
629
646
|
# Field", RFC 2183, DOI 10.17487/RFC2183, August 1997,
|
|
630
647
|
# <https://www.rfc-editor.org/info/rfc2183>.
|
|
631
648
|
#
|
|
632
|
-
# [MIME-IMB[https://
|
|
649
|
+
# [MIME-IMB[https://www.rfc-editor.org/rfc/rfc2045]]::
|
|
633
650
|
# Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions
|
|
634
651
|
# (MIME) Part One: Format of Internet Message Bodies",
|
|
635
652
|
# RFC 2045, DOI 10.17487/RFC2045, November 1996,
|
|
636
653
|
# <https://www.rfc-editor.org/info/rfc2045>.
|
|
637
654
|
#
|
|
638
|
-
# [MIME-IMT[https://
|
|
655
|
+
# [MIME-IMT[https://www.rfc-editor.org/rfc/rfc2046]]::
|
|
639
656
|
# Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions
|
|
640
657
|
# (MIME) Part Two: Media Types", RFC 2046, DOI 10.17487/RFC2046,
|
|
641
658
|
# November 1996, <https://www.rfc-editor.org/info/rfc2046>.
|
|
642
659
|
#
|
|
643
|
-
# [MIME-HDRS[https://
|
|
660
|
+
# [MIME-HDRS[https://www.rfc-editor.org/rfc/rfc2047]]::
|
|
644
661
|
# Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Three:
|
|
645
662
|
# Message Header Extensions for Non-ASCII Text",
|
|
646
663
|
# RFC 2047, DOI 10.17487/RFC2047, November 1996,
|
|
647
664
|
# <https://www.rfc-editor.org/info/rfc2047>.
|
|
648
665
|
#
|
|
649
|
-
# [RFC2231[https://
|
|
666
|
+
# [RFC2231[https://www.rfc-editor.org/rfc/rfc2231]]::
|
|
650
667
|
# Freed, N. and K. Moore, "MIME Parameter Value and Encoded Word
|
|
651
668
|
# Extensions: Character Sets, Languages, and Continuations",
|
|
652
669
|
# RFC 2231, DOI 10.17487/RFC2231, November 1997,
|
|
653
670
|
# <https://www.rfc-editor.org/info/rfc2231>.
|
|
654
671
|
#
|
|
655
|
-
# [I18n-HDRS[https://
|
|
672
|
+
# [I18n-HDRS[https://www.rfc-editor.org/rfc/rfc6532]]::
|
|
656
673
|
# Yang, A., Steele, S., and N. Freed, "Internationalized Email Headers",
|
|
657
674
|
# RFC 6532, DOI 10.17487/RFC6532, February 2012,
|
|
658
675
|
# <https://www.rfc-editor.org/info/rfc6532>.
|
|
@@ -668,12 +685,12 @@ module Net
|
|
|
668
685
|
# RFC 2557, DOI 10.17487/RFC2557, March 1999,
|
|
669
686
|
# <https://www.rfc-editor.org/info/rfc2557>.
|
|
670
687
|
#
|
|
671
|
-
# [MD5[https://
|
|
688
|
+
# [MD5[https://www.rfc-editor.org/rfc/rfc1864]]::
|
|
672
689
|
# Myers, J. and M. Rose, "The Content-MD5 Header Field",
|
|
673
690
|
# RFC 1864, DOI 10.17487/RFC1864, October 1995,
|
|
674
691
|
# <https://www.rfc-editor.org/info/rfc1864>.
|
|
675
692
|
#
|
|
676
|
-
# [RFC3503[https://
|
|
693
|
+
# [RFC3503[https://www.rfc-editor.org/rfc/rfc3503]]::
|
|
677
694
|
# Melnikov, A., "Message Disposition Notification (MDN)
|
|
678
695
|
# profile for Internet Message Access Protocol (IMAP)",
|
|
679
696
|
# RFC 3503, DOI 10.17487/RFC3503, March 2003,
|
|
@@ -681,27 +698,27 @@ module Net
|
|
|
681
698
|
#
|
|
682
699
|
# === \IMAP Extensions
|
|
683
700
|
#
|
|
684
|
-
# [QUOTA[https://
|
|
701
|
+
# [QUOTA[https://www.rfc-editor.org/rfc/rfc9208]]::
|
|
685
702
|
# Melnikov, A., "IMAP QUOTA Extension", RFC 9208, DOI 10.17487/RFC9208,
|
|
686
703
|
# March 2022, <https://www.rfc-editor.org/info/rfc9208>.
|
|
687
704
|
#
|
|
688
705
|
# <em>Note: obsoletes</em>
|
|
689
|
-
# RFC-2087[https://
|
|
706
|
+
# RFC-2087[https://www.rfc-editor.org/rfc/rfc2087]<em> (January 1997)</em>.
|
|
690
707
|
# <em>Net::IMAP does not fully support the RFC9208 updates yet.</em>
|
|
691
|
-
# [IDLE[https://
|
|
708
|
+
# [IDLE[https://www.rfc-editor.org/rfc/rfc2177]]::
|
|
692
709
|
# Leiba, B., "IMAP4 IDLE command", RFC 2177, DOI 10.17487/RFC2177,
|
|
693
710
|
# June 1997, <https://www.rfc-editor.org/info/rfc2177>.
|
|
694
|
-
# [NAMESPACE[https://
|
|
711
|
+
# [NAMESPACE[https://www.rfc-editor.org/rfc/rfc2342]]::
|
|
695
712
|
# Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342,
|
|
696
713
|
# DOI 10.17487/RFC2342, May 1998, <https://www.rfc-editor.org/info/rfc2342>.
|
|
697
|
-
# [ID[https://
|
|
714
|
+
# [ID[https://www.rfc-editor.org/rfc/rfc2971]]::
|
|
698
715
|
# Showalter, T., "IMAP4 ID extension", RFC 2971, DOI 10.17487/RFC2971,
|
|
699
716
|
# October 2000, <https://www.rfc-editor.org/info/rfc2971>.
|
|
700
|
-
# [BINARY[https://
|
|
717
|
+
# [BINARY[https://www.rfc-editor.org/rfc/rfc3516]]::
|
|
701
718
|
# Nerenberg, L., "IMAP4 Binary Content Extension", RFC 3516,
|
|
702
719
|
# DOI 10.17487/RFC3516, April 2003,
|
|
703
720
|
# <https://www.rfc-editor.org/info/rfc3516>.
|
|
704
|
-
# [ACL[https://
|
|
721
|
+
# [ACL[https://www.rfc-editor.org/rfc/rfc4314]]::
|
|
705
722
|
# Melnikov, A., "IMAP4 Access Control List (ACL) Extension", RFC 4314,
|
|
706
723
|
# DOI 10.17487/RFC4314, December 2005,
|
|
707
724
|
# <https://www.rfc-editor.org/info/rfc4314>.
|
|
@@ -709,36 +726,46 @@ module Net
|
|
|
709
726
|
# Crispin, M., "Internet Message Access Protocol (\IMAP) - UIDPLUS
|
|
710
727
|
# extension", RFC 4315, DOI 10.17487/RFC4315, December 2005,
|
|
711
728
|
# <https://www.rfc-editor.org/info/rfc4315>.
|
|
712
|
-
# [SORT[https://
|
|
729
|
+
# [SORT[https://www.rfc-editor.org/rfc/rfc5256]]::
|
|
713
730
|
# Crispin, M. and K. Murchison, "Internet Message Access Protocol - SORT and
|
|
714
731
|
# THREAD Extensions", RFC 5256, DOI 10.17487/RFC5256, June 2008,
|
|
715
732
|
# <https://www.rfc-editor.org/info/rfc5256>.
|
|
716
|
-
# [THREAD[https://
|
|
733
|
+
# [THREAD[https://www.rfc-editor.org/rfc/rfc5256]]::
|
|
717
734
|
# Crispin, M. and K. Murchison, "Internet Message Access Protocol - SORT and
|
|
718
735
|
# THREAD Extensions", RFC 5256, DOI 10.17487/RFC5256, June 2008,
|
|
719
736
|
# <https://www.rfc-editor.org/info/rfc5256>.
|
|
720
737
|
# [RFC5530[https://www.rfc-editor.org/rfc/rfc5530.html]]::
|
|
721
738
|
# Gulbrandsen, A., "IMAP Response Codes", RFC 5530, DOI 10.17487/RFC5530,
|
|
722
739
|
# May 2009, <https://www.rfc-editor.org/info/rfc5530>.
|
|
723
|
-
# [MOVE[https://
|
|
740
|
+
# [MOVE[https://www.rfc-editor.org/rfc/rfc6851]]::
|
|
724
741
|
# Gulbrandsen, A. and N. Freed, Ed., "Internet Message Access Protocol
|
|
725
742
|
# (\IMAP) - MOVE Extension", RFC 6851, DOI 10.17487/RFC6851, January 2013,
|
|
726
743
|
# <https://www.rfc-editor.org/info/rfc6851>.
|
|
727
|
-
# [UTF8=ACCEPT[https://
|
|
728
|
-
# [UTF8=ONLY[https://
|
|
744
|
+
# [UTF8=ACCEPT[https://www.rfc-editor.org/rfc/rfc6855]]::
|
|
745
|
+
# [UTF8=ONLY[https://www.rfc-editor.org/rfc/rfc6855]]::
|
|
729
746
|
# Resnick, P., Ed., Newman, C., Ed., and S. Shen, Ed.,
|
|
730
747
|
# "IMAP Support for UTF-8", RFC 6855, DOI 10.17487/RFC6855, March 2013,
|
|
731
748
|
# <https://www.rfc-editor.org/info/rfc6855>.
|
|
732
|
-
# [CONDSTORE[https://
|
|
733
|
-
# [QRESYNC[https://
|
|
749
|
+
# [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162]]::
|
|
750
|
+
# [QRESYNC[https://www.rfc-editor.org/rfc/rfc7162]]::
|
|
734
751
|
# Melnikov, A. and D. Cridland, "IMAP Extensions: Quick Flag Changes
|
|
735
752
|
# Resynchronization (CONDSTORE) and Quick Mailbox Resynchronization
|
|
736
753
|
# (QRESYNC)", RFC 7162, DOI 10.17487/RFC7162, May 2014,
|
|
737
754
|
# <https://www.rfc-editor.org/info/rfc7162>.
|
|
738
|
-
# [OBJECTID[https://
|
|
755
|
+
# [OBJECTID[https://www.rfc-editor.org/rfc/rfc8474]]::
|
|
739
756
|
# Gondwana, B., Ed., "IMAP Extension for Object Identifiers",
|
|
740
757
|
# RFC 8474, DOI 10.17487/RFC8474, September 2018,
|
|
741
758
|
# <https://www.rfc-editor.org/info/rfc8474>.
|
|
759
|
+
# [PARTIAL[https://www.rfc-editor.org/info/rfc9394]]::
|
|
760
|
+
# Melnikov, A., Achuthan, A., Nagulakonda, V., and L. Alves,
|
|
761
|
+
# "IMAP PARTIAL Extension for Paged SEARCH and FETCH", RFC 9394,
|
|
762
|
+
# DOI 10.17487/RFC9394, June 2023,
|
|
763
|
+
# <https://www.rfc-editor.org/info/rfc9394>.
|
|
764
|
+
# [UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.pdf]]::
|
|
765
|
+
# Melnikov, A., Achuthan, A., Nagulakonda, V., Singh, A., and L. Alves,
|
|
766
|
+
# "\IMAP Extension for Using and Returning Unique Identifiers (UIDs) Only",
|
|
767
|
+
# RFC 9586, DOI 10.17487/RFC9586, May 2024,
|
|
768
|
+
# <https://www.rfc-editor.org/info/rfc9586>.
|
|
742
769
|
#
|
|
743
770
|
# === IANA registries
|
|
744
771
|
# * {IMAP Capabilities}[http://www.iana.org/assignments/imap4-capabilities]
|
|
@@ -752,7 +779,7 @@ module Net
|
|
|
752
779
|
# * {GSSAPI/Kerberos/SASL Service Names}[https://www.iana.org/assignments/gssapi-service-names/gssapi-service-names.xhtml]:
|
|
753
780
|
# +imap+
|
|
754
781
|
# * {Character sets}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
|
|
755
|
-
#
|
|
782
|
+
# ==== For currently unsupported features:
|
|
756
783
|
# * {IMAP Quota Resource Types}[http://www.iana.org/assignments/imap4-capabilities#imap-capabilities-2]
|
|
757
784
|
# * {LIST-EXTENDED options and responses}[https://www.iana.org/assignments/imap-list-extended/imap-list-extended.xhtml]
|
|
758
785
|
# * {IMAP METADATA Server Entry and Mailbox Entry Registries}[https://www.iana.org/assignments/imap-metadata/imap-metadata.xhtml]
|
|
@@ -761,7 +788,7 @@ module Net
|
|
|
761
788
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
|
762
789
|
#
|
|
763
790
|
class IMAP < Protocol
|
|
764
|
-
VERSION = "0.
|
|
791
|
+
VERSION = "0.6.3"
|
|
765
792
|
|
|
766
793
|
# Aliases for supported capabilities, to be used with the #enable command.
|
|
767
794
|
ENABLE_ALIASES = {
|
|
@@ -769,15 +796,30 @@ module Net
|
|
|
769
796
|
"UTF8=ONLY" => "UTF8=ACCEPT",
|
|
770
797
|
}.freeze
|
|
771
798
|
|
|
772
|
-
|
|
773
|
-
autoload :
|
|
774
|
-
autoload :
|
|
775
|
-
autoload :
|
|
799
|
+
dir = File.expand_path("imap", __dir__)
|
|
800
|
+
autoload :ConnectionState, "#{dir}/connection_state"
|
|
801
|
+
autoload :ResponseReader, "#{dir}/response_reader"
|
|
802
|
+
autoload :SASL, "#{dir}/sasl"
|
|
803
|
+
autoload :SASLAdapter, "#{dir}/sasl_adapter"
|
|
804
|
+
autoload :SequenceSet, "#{dir}/sequence_set"
|
|
805
|
+
autoload :StringPrep, "#{dir}/stringprep"
|
|
776
806
|
|
|
777
807
|
include MonitorMixin
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
808
|
+
|
|
809
|
+
# :call-seq:
|
|
810
|
+
# Net::IMAP::SequenceSet(set = nil) -> SequenceSet
|
|
811
|
+
#
|
|
812
|
+
# Coerces +set+ into a SequenceSet, using either SequenceSet.try_convert or
|
|
813
|
+
# SequenceSet.new.
|
|
814
|
+
#
|
|
815
|
+
# * When +set+ is a SequenceSet, that same set is returned.
|
|
816
|
+
# * When +set+ responds to +to_sequence_set+, +set.to_sequence_set+ is
|
|
817
|
+
# returned.
|
|
818
|
+
# * Otherwise, returns the result from calling SequenceSet.new with +set+.
|
|
819
|
+
#
|
|
820
|
+
# Related: SequenceSet.try_convert, SequenceSet.new, SequenceSet::[]
|
|
821
|
+
def self.SequenceSet(set = nil)
|
|
822
|
+
SequenceSet.try_convert(set) || SequenceSet.new(set)
|
|
781
823
|
end
|
|
782
824
|
|
|
783
825
|
# Returns the global Config object
|
|
@@ -862,6 +904,67 @@ module Net
|
|
|
862
904
|
# Returns +false+ for a plaintext connection.
|
|
863
905
|
attr_reader :ssl_ctx_params
|
|
864
906
|
|
|
907
|
+
# Returns the current connection state.
|
|
908
|
+
#
|
|
909
|
+
# Once an IMAP connection is established, the connection is in one of four
|
|
910
|
+
# states: +not_authenticated+, +authenticated+, +selected+, and +logout+.
|
|
911
|
+
# Most commands are valid only in certain states.
|
|
912
|
+
#
|
|
913
|
+
# The connection state object responds to +to_sym+ and +name+ with the name
|
|
914
|
+
# of the current connection state, as a Symbol or String. Future versions
|
|
915
|
+
# of +net-imap+ may store additional information on the state object.
|
|
916
|
+
#
|
|
917
|
+
# From {RFC9051}[https://www.rfc-editor.org/rfc/rfc9051#section-3]:
|
|
918
|
+
# +----------------------+
|
|
919
|
+
# |connection established|
|
|
920
|
+
# +----------------------+
|
|
921
|
+
# ||
|
|
922
|
+
# \/
|
|
923
|
+
# +--------------------------------------+
|
|
924
|
+
# | server greeting |
|
|
925
|
+
# +--------------------------------------+
|
|
926
|
+
# || (1) || (2) || (3)
|
|
927
|
+
# \/ || ||
|
|
928
|
+
# +-----------------+ || ||
|
|
929
|
+
# |Not Authenticated| || ||
|
|
930
|
+
# +-----------------+ || ||
|
|
931
|
+
# || (7) || (4) || ||
|
|
932
|
+
# || \/ \/ ||
|
|
933
|
+
# || +----------------+ ||
|
|
934
|
+
# || | Authenticated |<=++ ||
|
|
935
|
+
# || +----------------+ || ||
|
|
936
|
+
# || || (7) || (5) || (6) ||
|
|
937
|
+
# || || \/ || ||
|
|
938
|
+
# || || +--------+ || ||
|
|
939
|
+
# || || |Selected|==++ ||
|
|
940
|
+
# || || +--------+ ||
|
|
941
|
+
# || || || (7) ||
|
|
942
|
+
# \/ \/ \/ \/
|
|
943
|
+
# +--------------------------------------+
|
|
944
|
+
# | Logout |
|
|
945
|
+
# +--------------------------------------+
|
|
946
|
+
# ||
|
|
947
|
+
# \/
|
|
948
|
+
# +-------------------------------+
|
|
949
|
+
# |both sides close the connection|
|
|
950
|
+
# +-------------------------------+
|
|
951
|
+
#
|
|
952
|
+
# >>>
|
|
953
|
+
# Legend for the above diagram:
|
|
954
|
+
#
|
|
955
|
+
# 1. connection without pre-authentication (+OK+ #greeting)
|
|
956
|
+
# 2. pre-authenticated connection (+PREAUTH+ #greeting)
|
|
957
|
+
# 3. rejected connection (+BYE+ #greeting)
|
|
958
|
+
# 4. successful #login or #authenticate command
|
|
959
|
+
# 5. successful #select or #examine command
|
|
960
|
+
# 6. #close or #unselect command, unsolicited +CLOSED+ response code, or
|
|
961
|
+
# failed #select or #examine command
|
|
962
|
+
# 7. #logout command, server shutdown, or connection closed
|
|
963
|
+
#
|
|
964
|
+
# Before the server greeting, the state is +not_authenticated+.
|
|
965
|
+
# After the connection closes, the state remains +logout+.
|
|
966
|
+
attr_reader :connection_state
|
|
967
|
+
|
|
865
968
|
# Creates a new Net::IMAP object and connects it to the specified
|
|
866
969
|
# +host+.
|
|
867
970
|
#
|
|
@@ -987,6 +1090,8 @@ module Net
|
|
|
987
1090
|
@exception = nil
|
|
988
1091
|
@greeting = nil
|
|
989
1092
|
@capabilities = nil
|
|
1093
|
+
@tls_verified = false
|
|
1094
|
+
@connection_state = ConnectionState::NotAuthenticated.new
|
|
990
1095
|
|
|
991
1096
|
# Client Protocol Receiver
|
|
992
1097
|
@parser = ResponseParser.new(config: @config)
|
|
@@ -1009,14 +1114,10 @@ module Net
|
|
|
1009
1114
|
@logout_command_tag = nil
|
|
1010
1115
|
|
|
1011
1116
|
# Connection
|
|
1012
|
-
@tls_verified = false
|
|
1013
1117
|
@sock = tcp_socket(@host, @port)
|
|
1014
1118
|
@reader = ResponseReader.new(self, @sock)
|
|
1015
1119
|
start_tls_session if ssl_ctx
|
|
1016
1120
|
start_imap_connection
|
|
1017
|
-
|
|
1018
|
-
# DEPRECATED: to remove in next version
|
|
1019
|
-
@client_thread = Thread.current
|
|
1020
1121
|
end
|
|
1021
1122
|
|
|
1022
1123
|
# Returns true after the TLS negotiation has completed and the remote
|
|
@@ -1024,34 +1125,29 @@ module Net
|
|
|
1024
1125
|
# but peer verification was disabled.
|
|
1025
1126
|
def tls_verified?; @tls_verified end
|
|
1026
1127
|
|
|
1027
|
-
def client_thread # :nodoc:
|
|
1028
|
-
warn "Net::IMAP#client_thread is deprecated and will be removed soon."
|
|
1029
|
-
@client_thread
|
|
1030
|
-
end
|
|
1031
|
-
|
|
1032
1128
|
# Disconnects from the server.
|
|
1033
1129
|
#
|
|
1130
|
+
# Waits for receiver thread to close before returning. Slow or stuck
|
|
1131
|
+
# response handlers can cause #disconnect to hang until they complete.
|
|
1132
|
+
#
|
|
1034
1133
|
# Related: #logout, #logout!
|
|
1035
1134
|
def disconnect
|
|
1135
|
+
in_logout_state = try_state_logout?
|
|
1036
1136
|
return if disconnected?
|
|
1037
1137
|
begin
|
|
1038
|
-
|
|
1039
|
-
# try to call SSL::SSLSocket#io.
|
|
1040
|
-
@sock.io.shutdown
|
|
1041
|
-
rescue NoMethodError
|
|
1042
|
-
# @sock is not an SSL::SSLSocket.
|
|
1043
|
-
@sock.shutdown
|
|
1044
|
-
end
|
|
1138
|
+
@sock.to_io.shutdown
|
|
1045
1139
|
rescue Errno::ENOTCONN
|
|
1046
1140
|
# ignore `Errno::ENOTCONN: Socket is not connected' on some platforms.
|
|
1047
1141
|
rescue Exception => e
|
|
1048
1142
|
@receiver_thread.raise(e)
|
|
1049
1143
|
end
|
|
1144
|
+
@sock.close
|
|
1050
1145
|
@receiver_thread.join
|
|
1051
|
-
synchronize do
|
|
1052
|
-
@sock.close
|
|
1053
|
-
end
|
|
1054
1146
|
raise e if e
|
|
1147
|
+
ensure
|
|
1148
|
+
# Try again after shutting down the receiver thread. With no reciever
|
|
1149
|
+
# left to wait for, any remaining locks should be _very_ brief.
|
|
1150
|
+
state_logout! unless in_logout_state
|
|
1055
1151
|
end
|
|
1056
1152
|
|
|
1057
1153
|
# Returns true if disconnected from the server.
|
|
@@ -1197,12 +1293,12 @@ module Net
|
|
|
1197
1293
|
# )
|
|
1198
1294
|
# end
|
|
1199
1295
|
#
|
|
1200
|
-
# See [ID[https://
|
|
1296
|
+
# See [ID[https://www.rfc-editor.org/rfc/rfc2971]] for field definitions.
|
|
1201
1297
|
#
|
|
1202
|
-
#
|
|
1298
|
+
# ==== Capabilities
|
|
1203
1299
|
#
|
|
1204
1300
|
# The server's capabilities must include +ID+
|
|
1205
|
-
# [RFC2971[https://
|
|
1301
|
+
# [RFC2971[https://www.rfc-editor.org/rfc/rfc2971]].
|
|
1206
1302
|
def id(client_id=nil)
|
|
1207
1303
|
synchronize do
|
|
1208
1304
|
send_command("ID", ClientID.new(client_id))
|
|
@@ -1285,7 +1381,7 @@ module Net
|
|
|
1285
1381
|
#
|
|
1286
1382
|
# Related: Net::IMAP.new, #login, #authenticate
|
|
1287
1383
|
#
|
|
1288
|
-
#
|
|
1384
|
+
# ==== Capability
|
|
1289
1385
|
# Clients should not call #starttls unless the server advertises the
|
|
1290
1386
|
# +STARTTLS+ capability.
|
|
1291
1387
|
#
|
|
@@ -1324,6 +1420,9 @@ module Net
|
|
|
1324
1420
|
# +SASL-IR+ capability, below). Defaults to the #config value for
|
|
1325
1421
|
# {sasl_ir}[rdoc-ref:Config#sasl_ir], which defaults to +true+.
|
|
1326
1422
|
#
|
|
1423
|
+
# The +registry+ kwarg can be used to select the mechanism implementation
|
|
1424
|
+
# from a custom registry. See SASL.authenticator and SASL::Authenticators.
|
|
1425
|
+
#
|
|
1327
1426
|
# All other arguments are forwarded to the registered SASL authenticator for
|
|
1328
1427
|
# the requested mechanism. <em>The documentation for each individual
|
|
1329
1428
|
# mechanism must be consulted for its specific parameters.</em>
|
|
@@ -1418,29 +1517,10 @@ module Net
|
|
|
1418
1517
|
# Previously cached #capabilities will be cleared when this method
|
|
1419
1518
|
# completes. If the TaggedResponse to #authenticate includes updated
|
|
1420
1519
|
# capabilities, they will be cached.
|
|
1421
|
-
def authenticate(
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
authenticator = SASL.authenticator(mechanism, *creds, **props, &callback)
|
|
1426
|
-
cmdargs = ["AUTHENTICATE", mechanism]
|
|
1427
|
-
if sasl_ir && capable?("SASL-IR") && auth_capable?(mechanism) &&
|
|
1428
|
-
authenticator.respond_to?(:initial_response?) &&
|
|
1429
|
-
authenticator.initial_response?
|
|
1430
|
-
response = authenticator.process(nil)
|
|
1431
|
-
cmdargs << (response.empty? ? "=" : [response].pack("m0"))
|
|
1432
|
-
end
|
|
1433
|
-
result = send_command_with_continuations(*cmdargs) {|data|
|
|
1434
|
-
challenge = data.unpack1("m")
|
|
1435
|
-
response = authenticator.process challenge
|
|
1436
|
-
[response].pack("m0")
|
|
1437
|
-
}
|
|
1438
|
-
if authenticator.respond_to?(:done?) && !authenticator.done?
|
|
1439
|
-
logout!
|
|
1440
|
-
raise SASL::AuthenticationIncomplete, result
|
|
1441
|
-
end
|
|
1442
|
-
@capabilities = capabilities_from_resp_code result
|
|
1443
|
-
result
|
|
1520
|
+
def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
|
|
1521
|
+
sasl_ir = may_depend_on_capabilities_cached?(sasl_ir)
|
|
1522
|
+
sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
|
|
1523
|
+
.tap do state_authenticated! _1 end
|
|
1444
1524
|
end
|
|
1445
1525
|
|
|
1446
1526
|
# Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
|
|
@@ -1457,16 +1537,12 @@ module Net
|
|
|
1457
1537
|
#
|
|
1458
1538
|
# Related: #authenticate, #starttls
|
|
1459
1539
|
#
|
|
1460
|
-
#
|
|
1540
|
+
# ==== Capabilities
|
|
1461
1541
|
#
|
|
1462
1542
|
# An IMAP client MUST NOT call #login when the server advertises the
|
|
1463
|
-
# +LOGINDISABLED+ capability.
|
|
1464
|
-
#
|
|
1465
|
-
#
|
|
1466
|
-
# raise "Remote server has disabled the login command"
|
|
1467
|
-
# else
|
|
1468
|
-
# imap.login username, password
|
|
1469
|
-
# end
|
|
1543
|
+
# +LOGINDISABLED+ capability. By default, Net::IMAP will raise a
|
|
1544
|
+
# LoginDisabledError when that capability is present. See
|
|
1545
|
+
# Config#enforce_logindisabled.
|
|
1470
1546
|
#
|
|
1471
1547
|
# Server capabilities may change after #starttls, #login, and #authenticate.
|
|
1472
1548
|
# Cached capabilities _must_ be invalidated after this method completes.
|
|
@@ -1474,8 +1550,11 @@ module Net
|
|
|
1474
1550
|
# ResponseCode.
|
|
1475
1551
|
#
|
|
1476
1552
|
def login(user, password)
|
|
1553
|
+
if enforce_logindisabled? && capability?("LOGINDISABLED")
|
|
1554
|
+
raise LoginDisabledError
|
|
1555
|
+
end
|
|
1477
1556
|
send_command("LOGIN", user, password)
|
|
1478
|
-
.tap
|
|
1557
|
+
.tap do state_authenticated! _1 end
|
|
1479
1558
|
end
|
|
1480
1559
|
|
|
1481
1560
|
# Sends a {SELECT command [IMAP4rev1 §6.3.1]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.3.1]
|
|
@@ -1491,7 +1570,7 @@ module Net
|
|
|
1491
1570
|
# When the +condstore+ keyword argument is true, the server is told to
|
|
1492
1571
|
# enable the extension. If +mailbox+ supports persistence of mod-sequences,
|
|
1493
1572
|
# the +HIGHESTMODSEQ+ ResponseCode will be sent as an untagged response to
|
|
1494
|
-
# #select and all
|
|
1573
|
+
# #select and all +FETCH+ responses will include FetchData#modseq.
|
|
1495
1574
|
# Otherwise, the +NOMODSEQ+ ResponseCode will be sent.
|
|
1496
1575
|
#
|
|
1497
1576
|
# A Net::IMAP::NoResponseError is raised if the mailbox does not
|
|
@@ -1499,7 +1578,7 @@ module Net
|
|
|
1499
1578
|
#
|
|
1500
1579
|
# Related: #examine
|
|
1501
1580
|
#
|
|
1502
|
-
#
|
|
1581
|
+
# ==== Capabilities
|
|
1503
1582
|
#
|
|
1504
1583
|
# If [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]] is supported,
|
|
1505
1584
|
# the server may return an untagged "NO" response with a "UIDNOTSTICKY"
|
|
@@ -1515,8 +1594,10 @@ module Net
|
|
|
1515
1594
|
args = ["SELECT", mailbox]
|
|
1516
1595
|
args << ["CONDSTORE"] if condstore
|
|
1517
1596
|
synchronize do
|
|
1597
|
+
state_unselected! # implicitly closes current mailbox
|
|
1518
1598
|
@responses.clear
|
|
1519
1599
|
send_command(*args)
|
|
1600
|
+
.tap do state_selected! end
|
|
1520
1601
|
end
|
|
1521
1602
|
end
|
|
1522
1603
|
|
|
@@ -1533,8 +1614,10 @@ module Net
|
|
|
1533
1614
|
args = ["EXAMINE", mailbox]
|
|
1534
1615
|
args << ["CONDSTORE"] if condstore
|
|
1535
1616
|
synchronize do
|
|
1617
|
+
state_unselected! # implicitly closes current mailbox
|
|
1536
1618
|
@responses.clear
|
|
1537
1619
|
send_command(*args)
|
|
1620
|
+
.tap do state_selected! end
|
|
1538
1621
|
end
|
|
1539
1622
|
end
|
|
1540
1623
|
|
|
@@ -1617,7 +1700,7 @@ module Net
|
|
|
1617
1700
|
#
|
|
1618
1701
|
# Related: #lsub, MailboxList
|
|
1619
1702
|
#
|
|
1620
|
-
#
|
|
1703
|
+
# ==== For example:
|
|
1621
1704
|
#
|
|
1622
1705
|
# imap.create("foo/bar")
|
|
1623
1706
|
# imap.create("foo/baz")
|
|
@@ -1655,7 +1738,7 @@ module Net
|
|
|
1655
1738
|
# servers, then folder creation (and listing, moving, etc) can lead to
|
|
1656
1739
|
# errors.
|
|
1657
1740
|
#
|
|
1658
|
-
# From RFC2342[https://
|
|
1741
|
+
# From RFC2342[https://www.rfc-editor.org/rfc/rfc2342]:
|
|
1659
1742
|
# >>>
|
|
1660
1743
|
# <em>Although typically a server will support only a single Personal
|
|
1661
1744
|
# Namespace, and a single Other User's Namespace, circumstances exist
|
|
@@ -1668,7 +1751,7 @@ module Net
|
|
|
1668
1751
|
#
|
|
1669
1752
|
# Related: #list, Namespaces, Namespace
|
|
1670
1753
|
#
|
|
1671
|
-
#
|
|
1754
|
+
# ==== For example:
|
|
1672
1755
|
#
|
|
1673
1756
|
# if capable?("NAMESPACE")
|
|
1674
1757
|
# namespaces = imap.namespace
|
|
@@ -1682,10 +1765,10 @@ module Net
|
|
|
1682
1765
|
# end
|
|
1683
1766
|
# end
|
|
1684
1767
|
#
|
|
1685
|
-
#
|
|
1768
|
+
# ==== Capabilities
|
|
1686
1769
|
#
|
|
1687
|
-
# The server's capabilities must include +NAMESPACE+
|
|
1688
|
-
# [RFC2342[https://
|
|
1770
|
+
# The server's capabilities must include either +IMAP4rev2+ or +NAMESPACE+
|
|
1771
|
+
# [RFC2342[https://www.rfc-editor.org/rfc/rfc2342]].
|
|
1689
1772
|
def namespace
|
|
1690
1773
|
synchronize do
|
|
1691
1774
|
send_command("NAMESPACE")
|
|
@@ -1721,7 +1804,7 @@ module Net
|
|
|
1721
1804
|
#
|
|
1722
1805
|
# Related: #list, MailboxList
|
|
1723
1806
|
#
|
|
1724
|
-
#
|
|
1807
|
+
# ==== Capabilities
|
|
1725
1808
|
#
|
|
1726
1809
|
# The server's capabilities must include +XLIST+,
|
|
1727
1810
|
# a deprecated Gmail extension (replaced by +SPECIAL-USE+).
|
|
@@ -1744,10 +1827,10 @@ module Net
|
|
|
1744
1827
|
#
|
|
1745
1828
|
# Related: #getquota, #setquota, MailboxQuotaRoot, MailboxQuota
|
|
1746
1829
|
#
|
|
1747
|
-
#
|
|
1830
|
+
# ==== Capabilities
|
|
1748
1831
|
#
|
|
1749
1832
|
# The server's capabilities must include +QUOTA+
|
|
1750
|
-
# [RFC2087[https://
|
|
1833
|
+
# [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
|
|
1751
1834
|
def getquotaroot(mailbox)
|
|
1752
1835
|
synchronize do
|
|
1753
1836
|
send_command("GETQUOTAROOT", mailbox)
|
|
@@ -1765,10 +1848,10 @@ module Net
|
|
|
1765
1848
|
#
|
|
1766
1849
|
# Related: #getquotaroot, #setquota, MailboxQuota
|
|
1767
1850
|
#
|
|
1768
|
-
#
|
|
1851
|
+
# ==== Capabilities
|
|
1769
1852
|
#
|
|
1770
1853
|
# The server's capabilities must include +QUOTA+
|
|
1771
|
-
# [RFC2087[https://
|
|
1854
|
+
# [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
|
|
1772
1855
|
def getquota(mailbox)
|
|
1773
1856
|
synchronize do
|
|
1774
1857
|
send_command("GETQUOTA", mailbox)
|
|
@@ -1783,10 +1866,10 @@ module Net
|
|
|
1783
1866
|
#
|
|
1784
1867
|
# Related: #getquota, #getquotaroot
|
|
1785
1868
|
#
|
|
1786
|
-
#
|
|
1869
|
+
# ==== Capabilities
|
|
1787
1870
|
#
|
|
1788
1871
|
# The server's capabilities must include +QUOTA+
|
|
1789
|
-
# [RFC2087[https://
|
|
1872
|
+
# [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
|
|
1790
1873
|
def setquota(mailbox, quota)
|
|
1791
1874
|
if quota.nil?
|
|
1792
1875
|
data = '()'
|
|
@@ -1803,10 +1886,10 @@ module Net
|
|
|
1803
1886
|
#
|
|
1804
1887
|
# Related: #getacl
|
|
1805
1888
|
#
|
|
1806
|
-
#
|
|
1889
|
+
# ==== Capabilities
|
|
1807
1890
|
#
|
|
1808
1891
|
# The server's capabilities must include +ACL+
|
|
1809
|
-
# [RFC4314[https://
|
|
1892
|
+
# [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
|
|
1810
1893
|
def setacl(mailbox, user, rights)
|
|
1811
1894
|
if rights.nil?
|
|
1812
1895
|
send_command("SETACL", mailbox, user, "")
|
|
@@ -1821,10 +1904,10 @@ module Net
|
|
|
1821
1904
|
#
|
|
1822
1905
|
# Related: #setacl, MailboxACLItem
|
|
1823
1906
|
#
|
|
1824
|
-
#
|
|
1907
|
+
# ==== Capabilities
|
|
1825
1908
|
#
|
|
1826
1909
|
# The server's capabilities must include +ACL+
|
|
1827
|
-
# [RFC4314[https://
|
|
1910
|
+
# [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
|
|
1828
1911
|
def getacl(mailbox)
|
|
1829
1912
|
synchronize do
|
|
1830
1913
|
send_command("GETACL", mailbox)
|
|
@@ -1858,7 +1941,7 @@ module Net
|
|
|
1858
1941
|
# for +mailbox+ cannot be returned; for instance, because it
|
|
1859
1942
|
# does not exist.
|
|
1860
1943
|
#
|
|
1861
|
-
#
|
|
1944
|
+
# ==== Supported attributes
|
|
1862
1945
|
#
|
|
1863
1946
|
# +MESSAGES+:: The number of messages in the mailbox.
|
|
1864
1947
|
#
|
|
@@ -1889,12 +1972,12 @@ module Net
|
|
|
1889
1972
|
# Unsupported attributes may be requested. The attribute value will be
|
|
1890
1973
|
# either an Integer or an ExtensionData object.
|
|
1891
1974
|
#
|
|
1892
|
-
#
|
|
1975
|
+
# ==== For example:
|
|
1893
1976
|
#
|
|
1894
1977
|
# p imap.status("inbox", ["MESSAGES", "RECENT"])
|
|
1895
1978
|
# #=> {"RECENT"=>0, "MESSAGES"=>44}
|
|
1896
1979
|
#
|
|
1897
|
-
#
|
|
1980
|
+
# ==== Capabilities
|
|
1898
1981
|
#
|
|
1899
1982
|
# +SIZE+ requires the server's capabilities to include either +IMAP4rev2+ or
|
|
1900
1983
|
# <tt>STATUS=SIZE</tt>
|
|
@@ -1934,11 +2017,11 @@ module Net
|
|
|
1934
2017
|
# not exist (it is not created automatically), or if the flags,
|
|
1935
2018
|
# date_time, or message arguments contain errors.
|
|
1936
2019
|
#
|
|
1937
|
-
#
|
|
2020
|
+
# ==== Capabilities
|
|
1938
2021
|
#
|
|
1939
2022
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
1940
2023
|
# supported and the destination supports persistent UIDs, the server's
|
|
1941
|
-
# response should include an +APPENDUID+ response code with
|
|
2024
|
+
# response should include an +APPENDUID+ response code with AppendUIDData.
|
|
1942
2025
|
# This will report the UIDVALIDITY of the destination mailbox and the
|
|
1943
2026
|
# assigned UID of the appended message.
|
|
1944
2027
|
#
|
|
@@ -1973,6 +2056,7 @@ module Net
|
|
|
1973
2056
|
# Related: #unselect
|
|
1974
2057
|
def close
|
|
1975
2058
|
send_command("CLOSE")
|
|
2059
|
+
.tap do state_authenticated! end
|
|
1976
2060
|
end
|
|
1977
2061
|
|
|
1978
2062
|
# Sends an {UNSELECT command [RFC3691 §2]}[https://www.rfc-editor.org/rfc/rfc3691#section-3]
|
|
@@ -1983,129 +2067,493 @@ module Net
|
|
|
1983
2067
|
#
|
|
1984
2068
|
# Related: #close
|
|
1985
2069
|
#
|
|
1986
|
-
#
|
|
2070
|
+
# ==== Capabilities
|
|
1987
2071
|
#
|
|
1988
|
-
# The server's capabilities must include +UNSELECT+
|
|
1989
|
-
# [RFC3691[https://
|
|
2072
|
+
# The server's capabilities must include either +IMAP4rev2+ or +UNSELECT+
|
|
2073
|
+
# [RFC3691[https://www.rfc-editor.org/rfc/rfc3691]].
|
|
1990
2074
|
def unselect
|
|
1991
2075
|
send_command("UNSELECT")
|
|
2076
|
+
.tap do state_authenticated! end
|
|
1992
2077
|
end
|
|
1993
2078
|
|
|
2079
|
+
# call-seq:
|
|
2080
|
+
# expunge -> array of message sequence numbers
|
|
2081
|
+
# expunge -> VanishedData of UIDs
|
|
2082
|
+
#
|
|
1994
2083
|
# Sends an {EXPUNGE command [IMAP4rev1 §6.4.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.3]
|
|
1995
|
-
#
|
|
1996
|
-
# selected mailbox
|
|
2084
|
+
# to permanently remove all messages with the +\Deleted+ flag from the
|
|
2085
|
+
# currently selected mailbox.
|
|
2086
|
+
#
|
|
2087
|
+
# Returns either an array of expunged message <em>sequence numbers</em> or
|
|
2088
|
+
# (when the appropriate capability is enabled) VanishedData of expunged
|
|
2089
|
+
# UIDs. Previously unhandled +EXPUNGE+ or +VANISHED+ responses are merged
|
|
2090
|
+
# with the direct response to this command. <tt>VANISHED (EARLIER)</tt>
|
|
2091
|
+
# responses will _not_ be merged.
|
|
2092
|
+
#
|
|
2093
|
+
# When no messages have been expunged, an empty array is returned,
|
|
2094
|
+
# regardless of which extensions are enabled. In a future release, an empty
|
|
2095
|
+
# VanishedData may be returned, based on the currently enabled extensions.
|
|
1997
2096
|
#
|
|
1998
2097
|
# Related: #uid_expunge
|
|
2098
|
+
#
|
|
2099
|
+
# ==== Capabilities
|
|
2100
|
+
#
|
|
2101
|
+
# When either QRESYNC[https://www.rfc-editor.org/rfc/rfc7162] or
|
|
2102
|
+
# UIDONLY[https://www.rfc-editor.org/rfc/rfc9586] are enabled, #expunge
|
|
2103
|
+
# returns VanishedData, which contains UIDs---<em>not message sequence
|
|
2104
|
+
# numbers</em>.
|
|
1999
2105
|
def expunge
|
|
2000
|
-
|
|
2001
|
-
send_command("EXPUNGE")
|
|
2002
|
-
clear_responses("EXPUNGE")
|
|
2003
|
-
end
|
|
2106
|
+
expunge_internal("EXPUNGE")
|
|
2004
2107
|
end
|
|
2005
2108
|
|
|
2109
|
+
# call-seq:
|
|
2110
|
+
# uid_expunge(uid_set) -> array of message sequence numbers
|
|
2111
|
+
# uid_expunge(uid_set) -> VanishedData of UIDs
|
|
2112
|
+
#
|
|
2006
2113
|
# Sends a {UID EXPUNGE command [RFC4315 §2.1]}[https://www.rfc-editor.org/rfc/rfc4315#section-2.1]
|
|
2007
2114
|
# {[IMAP4rev2 §6.4.9]}[https://www.rfc-editor.org/rfc/rfc9051#section-6.4.9]
|
|
2008
2115
|
# to permanently remove all messages that have both the <tt>\\Deleted</tt>
|
|
2009
2116
|
# flag set and a UID that is included in +uid_set+.
|
|
2010
2117
|
#
|
|
2118
|
+
# Returns the same result type as #expunge.
|
|
2119
|
+
#
|
|
2011
2120
|
# By using #uid_expunge instead of #expunge when resynchronizing with
|
|
2012
2121
|
# the server, the client can ensure that it does not inadvertantly
|
|
2013
2122
|
# remove any messages that have been marked as <tt>\\Deleted</tt> by other
|
|
2014
2123
|
# clients between the time that the client was last connected and
|
|
2015
2124
|
# the time the client resynchronizes.
|
|
2016
2125
|
#
|
|
2017
|
-
# *Note:*
|
|
2018
|
-
# >>>
|
|
2019
|
-
# Although the command takes a set of UIDs for its argument, the
|
|
2020
|
-
# server still returns regular EXPUNGE responses, which contain
|
|
2021
|
-
# a <em>sequence number</em>. These will be deleted from
|
|
2022
|
-
# #responses and this method returns them as an array of
|
|
2023
|
-
# <em>sequence number</em> integers.
|
|
2024
|
-
#
|
|
2025
2126
|
# Related: #expunge
|
|
2026
2127
|
#
|
|
2027
|
-
#
|
|
2128
|
+
# ==== Capabilities
|
|
2028
2129
|
#
|
|
2029
|
-
# The server's capabilities must include +UIDPLUS+
|
|
2130
|
+
# The server's capabilities must include either +IMAP4rev2+ or +UIDPLUS+
|
|
2030
2131
|
# [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]].
|
|
2132
|
+
#
|
|
2133
|
+
# Otherwise, #uid_expunge is updated by extensions in the same way as
|
|
2134
|
+
# #expunge.
|
|
2031
2135
|
def uid_expunge(uid_set)
|
|
2032
|
-
|
|
2033
|
-
send_command("UID EXPUNGE", MessageSet.new(uid_set))
|
|
2034
|
-
clear_responses("EXPUNGE")
|
|
2035
|
-
end
|
|
2136
|
+
expunge_internal("UID EXPUNGE", SequenceSet.new(uid_set))
|
|
2036
2137
|
end
|
|
2037
2138
|
|
|
2038
|
-
#
|
|
2039
|
-
#
|
|
2040
|
-
#
|
|
2041
|
-
# string holding the entire search string, or a single-dimension array of
|
|
2042
|
-
# search keywords and arguments.
|
|
2139
|
+
# :call-seq:
|
|
2140
|
+
# search(criteria, charset = nil) -> result
|
|
2141
|
+
# search(criteria, charset: nil, return: nil) -> result
|
|
2043
2142
|
#
|
|
2044
|
-
#
|
|
2045
|
-
#
|
|
2046
|
-
#
|
|
2143
|
+
# Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
|
|
2144
|
+
# to search the mailbox for messages that match the given search +criteria+,
|
|
2145
|
+
# and returns either a SearchResult or an ESearchResult. SearchResult
|
|
2146
|
+
# inherits from Array (for backward compatibility) but adds
|
|
2147
|
+
# SearchResult#modseq when the +CONDSTORE+ capability has been enabled.
|
|
2148
|
+
# ESearchResult also implements {#to_a}[rdoc-ref:ESearchResult#to_a], for
|
|
2149
|
+
# compatibility with SearchResult.
|
|
2150
|
+
#
|
|
2151
|
+
# +criteria+ is one or more search keys and their arguments, which may be
|
|
2152
|
+
# provided as an array or a string.
|
|
2153
|
+
# See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
|
|
2154
|
+
# and {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
|
|
2155
|
+
#
|
|
2156
|
+
# +return+ options control what kind of information is returned about
|
|
2157
|
+
# messages matching the search +criteria+. Specifying +return+ should force
|
|
2158
|
+
# the server to return an ESearchResult instead of a SearchResult, but some
|
|
2159
|
+
# servers disobey this requirement. <em>Requires an extended search
|
|
2160
|
+
# capability, such as +ESEARCH+ or +IMAP4rev2+.</em>
|
|
2161
|
+
# See {"Argument translation"}[rdoc-ref:#search@Argument+translation] and
|
|
2162
|
+
# {"Supported return options"}[rdoc-ref:#search@Supported+return+options],
|
|
2163
|
+
# below.
|
|
2164
|
+
#
|
|
2165
|
+
# +charset+ is the name of the {registered character
|
|
2166
|
+
# set}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
|
|
2167
|
+
# used by strings in the search +criteria+. When +charset+ isn't specified,
|
|
2168
|
+
# either <tt>"US-ASCII"</tt> or <tt>"UTF-8"</tt> is assumed, depending on
|
|
2169
|
+
# the server's capabilities.
|
|
2170
|
+
#
|
|
2171
|
+
# _NOTE:_ Return options and charset may be sent as part of +criteria+. Do
|
|
2172
|
+
# not use the +return+ or +charset+ arguments when either return options or
|
|
2173
|
+
# charset are embedded in +criteria+.
|
|
2047
2174
|
#
|
|
2048
2175
|
# Related: #uid_search
|
|
2049
2176
|
#
|
|
2050
|
-
#
|
|
2177
|
+
# ==== For example:
|
|
2051
2178
|
#
|
|
2052
|
-
#
|
|
2179
|
+
# imap.search(["SUBJECT", "hello", "NOT", "SEEN"])
|
|
2180
|
+
# #=> [1, 6, 7, 8]
|
|
2181
|
+
#
|
|
2182
|
+
# The following assumes the server supports +ESEARCH+ and +CONDSTORE+:
|
|
2183
|
+
#
|
|
2184
|
+
# result = imap.uid_search(["UID", 12345.., "MODSEQ", 620_162_338],
|
|
2185
|
+
# return: %w(all count min max))
|
|
2186
|
+
# # => #<data Net::IMAP::ESearchResult tag="RUBY0123", uid=true,
|
|
2187
|
+
# # data=[["ALL", Net::IMAP::SequenceSet["12346:12349,22222:22230"]],
|
|
2188
|
+
# # ["COUNT", 13], ["MIN", 12346], ["MAX", 22230],
|
|
2189
|
+
# # ["MODSEQ", 917162488]]>
|
|
2190
|
+
# result.to_a # => [12346, 12347, 12348, 12349, 22222, 22223, 22224,
|
|
2191
|
+
# # 22225, 22226, 22227, 22228, 22229, 22230]
|
|
2192
|
+
# result.uid? # => true
|
|
2193
|
+
# result.count # => 13
|
|
2194
|
+
# result.min # => 12346
|
|
2195
|
+
# result.max # => 22230
|
|
2196
|
+
# result.modseq # => 917162488
|
|
2197
|
+
#
|
|
2198
|
+
# Using +return+ options to limit the result to only min, max, and count:
|
|
2199
|
+
#
|
|
2200
|
+
# result = imap.uid_search(["UID", 12345..,], return: %w(count min max))
|
|
2201
|
+
# # => #<data Net::IMAP::ESearchResult tag="RUBY0124", uid=true,
|
|
2202
|
+
# # data=[["COUNT", 13], ["MIN", 12346], ["MAX", 22230]]>
|
|
2203
|
+
# result.to_a # => []
|
|
2204
|
+
# result.count # => 13
|
|
2205
|
+
# result.min # => 12346
|
|
2206
|
+
# result.max # => 22230
|
|
2207
|
+
#
|
|
2208
|
+
# Return options and charset may be sent as keyword args or embedded in the
|
|
2209
|
+
# +criteria+ arg, but they must be in the correct order: <tt>"RETURN (...)
|
|
2210
|
+
# CHARSET ... criteria..."</tt>. The following searches
|
|
2211
|
+
# send the exact same command to the server:
|
|
2212
|
+
#
|
|
2213
|
+
# # Return options and charset as keyword arguments (preferred)
|
|
2214
|
+
# imap.search(%w(OR UNSEEN FLAGGED), return: %w(MIN MAX), charset: "UTF-8")
|
|
2215
|
+
# # Embedding return and charset in the criteria array
|
|
2216
|
+
# imap.search(["RETURN", %w(MIN MAX), "CHARSET", "UTF-8", *%w(OR UNSEEN FLAGGED)])
|
|
2217
|
+
# # Embedding return and charset in the criteria string
|
|
2218
|
+
# imap.search("RETURN (MIN MAX) CHARSET UTF-8 OR UNSEEN FLAGGED")
|
|
2219
|
+
#
|
|
2220
|
+
# Sending charset as the second positional argument is supported for
|
|
2221
|
+
# backward compatibility. Future versions may print a deprecation warning:
|
|
2222
|
+
# imap.search(%w(OR UNSEEN FLAGGED), "UTF-8", return: %w(MIN MAX))
|
|
2223
|
+
#
|
|
2224
|
+
# ==== Argument translation
|
|
2225
|
+
#
|
|
2226
|
+
# [+return+ options]
|
|
2227
|
+
# Must be an Array. Return option names may be either strings or symbols.
|
|
2228
|
+
# +Range+ elements which begin and end with negative integers are encoded
|
|
2229
|
+
# for use with +PARTIAL+--any other ranges are converted to SequenceSet.
|
|
2230
|
+
# Unlike +criteria+, other return option arguments are not automatically
|
|
2231
|
+
# converted to SequenceSet.
|
|
2232
|
+
#
|
|
2233
|
+
# [When +criteria+ is an Array]
|
|
2234
|
+
# When the array begins with <tt>"RETURN"</tt> (case insensitive), the
|
|
2235
|
+
# second array element is translated like the +return+ parameter (as
|
|
2236
|
+
# described above).
|
|
2237
|
+
#
|
|
2238
|
+
# Every other member is a +SEARCH+ command argument:
|
|
2239
|
+
# [SequenceSet]
|
|
2240
|
+
# Encoded as an \IMAP +sequence-set+ with SequenceSet#valid_string.
|
|
2241
|
+
# [Set, Range, <tt>-1</tt>, +:*+, responds to +#to_sequence_set+]
|
|
2242
|
+
# Converted to SequenceSet for validation and encoding.
|
|
2243
|
+
# [nested sequence-set +Array+]
|
|
2244
|
+
# When every element in a nested array is one of the above types, a
|
|
2245
|
+
# positive +Integer+, a sequence-set formatted +String+, or a deeply
|
|
2246
|
+
# nested +Array+ of these same types, the array will be converted to
|
|
2247
|
+
# SequenceSet for validation and encoding.
|
|
2248
|
+
# [Any other nested +Array+]
|
|
2249
|
+
# Otherwise, a nested array is encoded as a parenthesized list, to
|
|
2250
|
+
# combine multiple search keys (e.g., for use with +OR+ and +NOT+).
|
|
2251
|
+
# [+String+]
|
|
2252
|
+
# Sent verbatim when it is a valid \IMAP +atom+, and encoded as an \IMAP
|
|
2253
|
+
# +quoted+ or +literal+ string otherwise. Every standard search key
|
|
2254
|
+
# name is a valid \IMAP +atom+ and every standard search key string
|
|
2255
|
+
# argument is an +astring+ which may be encoded as +atom+, +quoted+, or
|
|
2256
|
+
# +literal+.
|
|
2257
|
+
#
|
|
2258
|
+
# *Note:* <tt>*</tt> is not a valid \IMAP +atom+ character. Any string
|
|
2259
|
+
# containing <tt>*</tt> will be encoded as a +quoted+ string, _not_ a
|
|
2260
|
+
# +sequence-set+.
|
|
2261
|
+
# [+Integer+ (except for <tt>-1</tt>)]
|
|
2262
|
+
# Encoded using +#to_s+.
|
|
2263
|
+
# [+Date+]
|
|
2264
|
+
# Encoded as an \IMAP date (see ::encode_date).
|
|
2265
|
+
#
|
|
2266
|
+
# [When +criteria+ is a String]
|
|
2267
|
+
# +criteria+ will be sent directly to the server <em>without any
|
|
2268
|
+
# validation or encoding</em>.
|
|
2269
|
+
#
|
|
2270
|
+
# <em>*WARNING:* This is vulnerable to injection attacks when external
|
|
2271
|
+
# inputs are used.</em>
|
|
2272
|
+
#
|
|
2273
|
+
# ==== Supported return options
|
|
2274
|
+
#
|
|
2275
|
+
# For full definitions of the standard return options and return data, see
|
|
2276
|
+
# the relevant RFCs.
|
|
2277
|
+
#
|
|
2278
|
+
# [+ALL+]
|
|
2279
|
+
# Returns ESearchResult#all with a SequenceSet of all matching sequence
|
|
2280
|
+
# numbers or UIDs. This is the default, when return options are empty.
|
|
2281
|
+
#
|
|
2282
|
+
# For compatibility with SearchResult, ESearchResult#to_a returns an
|
|
2283
|
+
# Array of message sequence numbers or UIDs.
|
|
2284
|
+
#
|
|
2285
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2286
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2287
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2288
|
+
#
|
|
2289
|
+
# [+COUNT+]
|
|
2290
|
+
# Returns ESearchResult#count with the number of matching messages.
|
|
2291
|
+
#
|
|
2292
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2293
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2294
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2295
|
+
#
|
|
2296
|
+
# [+MAX+]
|
|
2297
|
+
# Returns ESearchResult#max with the highest matching sequence number or
|
|
2298
|
+
# UID.
|
|
2299
|
+
#
|
|
2300
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2301
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2302
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2303
|
+
#
|
|
2304
|
+
# [+MIN+]
|
|
2305
|
+
# Returns ESearchResult#min with the lowest matching sequence number or
|
|
2306
|
+
# UID.
|
|
2307
|
+
#
|
|
2308
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2309
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2310
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2311
|
+
#
|
|
2312
|
+
# [+PARTIAL+ _range_]
|
|
2313
|
+
# Returns ESearchResult#partial with a SequenceSet of a subset of
|
|
2314
|
+
# matching sequence numbers or UIDs, as selected by _range_. As with
|
|
2315
|
+
# sequence numbers, the first result is +1+: <tt>1..500</tt> selects the
|
|
2316
|
+
# first 500 search results (in mailbox order), <tt>501..1000</tt> the
|
|
2317
|
+
# second 500, and so on. _range_ may also be negative: <tt>-500..-1</tt>
|
|
2318
|
+
# selects the last 500 search results.
|
|
2319
|
+
#
|
|
2320
|
+
# <em>Requires either the <tt>CONTEXT=SEARCH</tt> or +PARTIAL+ capabability.</em>
|
|
2321
|
+
# {[RFC5267]}[https://rfc-editor.org/rfc/rfc5267]
|
|
2322
|
+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
|
|
2323
|
+
#
|
|
2324
|
+
# ===== +MODSEQ+ return data
|
|
2325
|
+
#
|
|
2326
|
+
# ESearchResult#modseq return data does not have a corresponding return
|
|
2327
|
+
# option. Instead, it is returned if the +MODSEQ+ search key is used or
|
|
2328
|
+
# when the +CONDSTORE+ extension is enabled for the selected mailbox.
|
|
2329
|
+
# See [{RFC4731 §3.2}[https://www.rfc-editor.org/rfc/rfc4731#section-3.2]]
|
|
2330
|
+
# or [{RFC7162 §2.1.5}[https://www.rfc-editor.org/rfc/rfc7162#section-3.1.5]].
|
|
2331
|
+
#
|
|
2332
|
+
# ===== +RFC4466+ compatible extensions
|
|
2333
|
+
#
|
|
2334
|
+
# {RFC4466 §2.6}[https://www.rfc-editor.org/rfc/rfc4466.html#section-2.6]
|
|
2335
|
+
# defines standard syntax for search extensions. Net::IMAP allows sending
|
|
2336
|
+
# unsupported search return options and will parse unsupported search
|
|
2337
|
+
# extensions' return values into ExtensionData. Please note that this is an
|
|
2338
|
+
# intentionally _unstable_ API. Future releases may return different
|
|
2339
|
+
# (incompatible) objects, <em>without deprecation or warning</em>.
|
|
2340
|
+
#
|
|
2341
|
+
# ==== Search keys
|
|
2342
|
+
#
|
|
2343
|
+
# For full definitions of the standard search +criteria+,
|
|
2053
2344
|
# see [{IMAP4rev1 §6.4.4}[https://www.rfc-editor.org/rfc/rfc3501.html#section-6.4.4]],
|
|
2054
2345
|
# or [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]],
|
|
2055
2346
|
# in addition to documentation for
|
|
2056
|
-
# any
|
|
2057
|
-
# reported by #capabilities which may define additional search filters, e.g:
|
|
2347
|
+
# any #capabilities which may define additional search filters, such as
|
|
2058
2348
|
# +CONDSTORE+, +WITHIN+, +FILTERS+, <tt>SEARCH=FUZZY</tt>, +OBJECTID+, or
|
|
2059
|
-
# +SAVEDATE+.
|
|
2349
|
+
# +SAVEDATE+.
|
|
2060
2350
|
#
|
|
2061
|
-
#
|
|
2062
|
-
#
|
|
2063
|
-
#
|
|
2351
|
+
# With the exception of <em>sequence-set</em> and <em>parenthesized
|
|
2352
|
+
# list</em>, all search keys are composed of prefix label with zero or more
|
|
2353
|
+
# arguments. The number and type of arguments is specific to each search
|
|
2354
|
+
# key.
|
|
2064
2355
|
#
|
|
2065
|
-
#
|
|
2066
|
-
# <b><date></b>. The date argument has a format similar
|
|
2067
|
-
# to <tt>8-Aug-2002</tt>, and can be formatted using
|
|
2068
|
-
# Net::IMAP.format_date.
|
|
2356
|
+
# ===== Search keys that match all messages
|
|
2069
2357
|
#
|
|
2070
|
-
#
|
|
2358
|
+
# [+ALL+]
|
|
2359
|
+
# The default initial key. Matches every message in the mailbox.
|
|
2071
2360
|
#
|
|
2072
|
-
#
|
|
2361
|
+
# [+SAVEDATESUPPORTED+]
|
|
2362
|
+
# Matches every message in the mailbox when the mailbox supports the save
|
|
2363
|
+
# date attribute. Otherwise, it matches no messages.
|
|
2073
2364
|
#
|
|
2074
|
-
#
|
|
2365
|
+
# <em>Requires +SAVEDATE+ capability</em>.
|
|
2366
|
+
# {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
|
|
2075
2367
|
#
|
|
2076
|
-
#
|
|
2368
|
+
# ===== Sequence set search keys
|
|
2077
2369
|
#
|
|
2078
|
-
#
|
|
2370
|
+
# [_sequence-set_]
|
|
2371
|
+
# Matches messages with message sequence numbers in _sequence-set_.
|
|
2079
2372
|
#
|
|
2080
|
-
#
|
|
2373
|
+
# _Note:_ this search key has no label.
|
|
2081
2374
|
#
|
|
2082
|
-
#
|
|
2083
|
-
#
|
|
2375
|
+
# <em>+UIDONLY+ must *not* be enabled.</em>
|
|
2376
|
+
# {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.html]
|
|
2084
2377
|
#
|
|
2085
|
-
#
|
|
2378
|
+
# [+UID+ _sequence-set_]
|
|
2379
|
+
# Matches messages with a UID in _sequence-set_.
|
|
2086
2380
|
#
|
|
2087
|
-
#
|
|
2381
|
+
# ===== Compound search keys
|
|
2088
2382
|
#
|
|
2089
|
-
#
|
|
2383
|
+
# [(_search-key_ _search-key_...)]
|
|
2384
|
+
# Combines one or more _search-key_ arguments to match
|
|
2385
|
+
# messages which match all contained search keys. Useful for +OR+, +NOT+,
|
|
2386
|
+
# and other search keys with _search-key_ arguments.
|
|
2090
2387
|
#
|
|
2091
|
-
#
|
|
2388
|
+
# _Note:_ this search key has no label.
|
|
2092
2389
|
#
|
|
2093
|
-
#
|
|
2094
|
-
#
|
|
2390
|
+
# [+OR+ _search-key_ _search-key_]
|
|
2391
|
+
# Matches messages which match either _search-key_ argument.
|
|
2392
|
+
#
|
|
2393
|
+
# [+NOT+ _search-key_]
|
|
2394
|
+
# Matches messages which do not match _search-key_.
|
|
2395
|
+
#
|
|
2396
|
+
# [+FUZZY+ _search-key_]
|
|
2397
|
+
# Uses fuzzy matching for the specified search key.
|
|
2398
|
+
#
|
|
2399
|
+
# <em>Requires <tt>SEARCH=FUZZY</tt> capability.</em>
|
|
2400
|
+
# {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
|
|
2401
|
+
#
|
|
2402
|
+
# ===== Flags search keys
|
|
2403
|
+
#
|
|
2404
|
+
# [+ANSWERED+, +UNANSWERED+]
|
|
2405
|
+
# Matches messages with or without the <tt>\\Answered</tt> flag.
|
|
2406
|
+
# [+DELETED+, +UNDELETED+]
|
|
2407
|
+
# Matches messages with or without the <tt>\\Deleted</tt> flag.
|
|
2408
|
+
# [+DRAFT+, +UNDRAFT+]
|
|
2409
|
+
# Matches messages with or without the <tt>\\Draft</tt> flag.
|
|
2410
|
+
# [+FLAGGED+, +UNFLAGGED+]
|
|
2411
|
+
# Matches messages with or without the <tt>\\Flagged</tt> flag.
|
|
2412
|
+
# [+SEEN+, +UNSEEN+]
|
|
2413
|
+
# Matches messages with or without the <tt>\\Seen</tt> flag.
|
|
2414
|
+
# [+KEYWORD+ _keyword_, +UNKEYWORD+ _keyword_]
|
|
2415
|
+
# Matches messages with or without the specified _keyword_.
|
|
2416
|
+
#
|
|
2417
|
+
# [+RECENT+, +UNRECENT+]
|
|
2418
|
+
# Matches messages with or without the <tt>\\Recent</tt> flag.
|
|
2419
|
+
#
|
|
2420
|
+
# *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
|
|
2421
|
+
# [+NEW+]
|
|
2422
|
+
# Equivalent to <tt>(RECENT UNSEEN)</tt>.
|
|
2423
|
+
#
|
|
2424
|
+
# *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
|
|
2425
|
+
#
|
|
2426
|
+
# ===== Header field substring search keys
|
|
2427
|
+
#
|
|
2428
|
+
# [+BCC+ _substring_]
|
|
2429
|
+
# Matches when _substring_ is in the envelope's +BCC+ field.
|
|
2430
|
+
# [+CC+ _substring_]
|
|
2431
|
+
# Matches when _substring_ is in the envelope's +CC+ field.
|
|
2432
|
+
# [+FROM+ _substring_]
|
|
2433
|
+
# Matches when _substring_ is in the envelope's +FROM+ field.
|
|
2434
|
+
# [+SUBJECT+ _substring_]
|
|
2435
|
+
# Matches when _substring_ is in the envelope's +SUBJECT+ field.
|
|
2436
|
+
# [+TO+ _substring_]
|
|
2437
|
+
# Matches when _substring_ is in the envelope's +TO+ field.
|
|
2438
|
+
#
|
|
2439
|
+
# [+HEADER+ _field_ _substring_]
|
|
2440
|
+
# Matches when _substring_ is in the specified header _field_.
|
|
2441
|
+
#
|
|
2442
|
+
# ===== Body text search keys
|
|
2443
|
+
# [+BODY+ _string_]
|
|
2444
|
+
# Matches when _string_ is in the body of the message.
|
|
2445
|
+
# Does not match on header fields.
|
|
2446
|
+
#
|
|
2447
|
+
# The server _may_ use flexible matching, rather than simple substring
|
|
2448
|
+
# matches. For example, this may use stemming or match only full words.
|
|
2449
|
+
#
|
|
2450
|
+
# [+TEXT+ _string_]
|
|
2451
|
+
# Matches when _string_ is in the header or body of the message.
|
|
2452
|
+
#
|
|
2453
|
+
# The server _may_ use flexible matching, rather than simple substring
|
|
2454
|
+
# matches. For example, this may use stemming or match only full words.
|
|
2455
|
+
#
|
|
2456
|
+
# ===== Date/Time search keys
|
|
2457
|
+
#
|
|
2458
|
+
# [+SENTBEFORE+ _date_]
|
|
2459
|
+
# [+SENTON+ _date_]
|
|
2460
|
+
# [+SENTSINCE+ _date_]
|
|
2461
|
+
# Matches when the +Date+ header is earlier than, on, or later than _date_.
|
|
2462
|
+
#
|
|
2463
|
+
# [+BEFORE+ _date_]
|
|
2464
|
+
# [+ON+ _date_]
|
|
2465
|
+
# [+SINCE+ _date_]
|
|
2466
|
+
# Matches when the +INTERNALDATE+ is earlier than, on, or later than
|
|
2467
|
+
# _date_.
|
|
2468
|
+
#
|
|
2469
|
+
# [+OLDER+ _interval_]
|
|
2470
|
+
# [+YOUNGER+ _interval_]
|
|
2471
|
+
# Matches when the +INTERNALDATE+ is more/less than _interval_ seconds ago.
|
|
2472
|
+
#
|
|
2473
|
+
# <em>Requires +WITHIN+ capability</em>.
|
|
2474
|
+
# {[RFC5032]}[https://www.rfc-editor.org/rfc/rfc5032.html]
|
|
2475
|
+
#
|
|
2476
|
+
# [+SAVEDBEFORE+ _date_]
|
|
2477
|
+
# [+SAVEDON+ _date_]
|
|
2478
|
+
# [+SAVEDSINCE+ _date_]
|
|
2479
|
+
# Matches when the save date is earlier than, on, or later than _date_.
|
|
2480
|
+
#
|
|
2481
|
+
# <em>Requires +SAVEDATE+ capability.</em>
|
|
2482
|
+
# {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
|
|
2483
|
+
#
|
|
2484
|
+
# ===== Other message attribute search keys
|
|
2485
|
+
#
|
|
2486
|
+
# [+SMALLER+ _bytes_]
|
|
2487
|
+
# [+LARGER+ _bytes_]
|
|
2488
|
+
# Matches when +RFC822.SIZE+ is smaller or larger than _bytes_.
|
|
2489
|
+
#
|
|
2490
|
+
# [+ANNOTATION+ _entry_ _attr_ _value_]
|
|
2491
|
+
# Matches messages that have annotations with entries matching _entry_,
|
|
2492
|
+
# attributes matching _attr_, and _value_ in the attribute's values.
|
|
2493
|
+
#
|
|
2494
|
+
# <em>Requires +ANNOTATE-EXPERIMENT-1+ capability</em>.
|
|
2495
|
+
# {[RFC5257]}[https://www.rfc-editor.org/rfc/rfc5257.html].
|
|
2496
|
+
#
|
|
2497
|
+
# [+FILTER+ _filter_]
|
|
2498
|
+
# References a _filter_ that is stored on the server and matches all
|
|
2499
|
+
# messages which would be matched by that filter's search criteria.
|
|
2500
|
+
#
|
|
2501
|
+
# <em>Requires +FILTERS+ capability</em>.
|
|
2502
|
+
# {[RFC5466]}[https://www.rfc-editor.org/rfc/rfc5466.html#section-3.1]
|
|
2503
|
+
#
|
|
2504
|
+
# [+MODSEQ+ _modseq_]
|
|
2505
|
+
# Matches when +MODSEQ+ is greater than or equal to _modseq_.
|
|
2506
|
+
#
|
|
2507
|
+
# <em>Requires +CONDSTORE+ capability</em>.
|
|
2508
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
|
|
2509
|
+
#
|
|
2510
|
+
# [+MODSEQ+ _entry_ _entry-type_ _modseq_]
|
|
2511
|
+
# Matches when a specific metadata _entry_ has been updated since
|
|
2512
|
+
# _modseq_.
|
|
2513
|
+
#
|
|
2514
|
+
# For flags, the corresponding _entry_ name is
|
|
2515
|
+
# <tt>"/flags/#{flag_name}"</tt>, where _flag_name_ includes the
|
|
2516
|
+
# <tt>\\</tt> prefix. _entry-type_ can be one of <tt>"shared"</tt>,
|
|
2517
|
+
# <tt>"priv"</tt> (private), or <tt>"all"</tt>.
|
|
2518
|
+
#
|
|
2519
|
+
# <em>Requires +CONDSTORE+ capability</em>.
|
|
2520
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
|
|
2521
|
+
#
|
|
2522
|
+
# [+EMAILID+ _objectid_]
|
|
2523
|
+
# [+THREADID+ _objectid_]
|
|
2524
|
+
# Matches when +EMAILID+/+THREADID+ is equal to _objectid_
|
|
2525
|
+
# (substring matches are not supported).
|
|
2095
2526
|
#
|
|
2096
|
-
#
|
|
2527
|
+
# <em>Requires +OBJECTID+ capability</em>.
|
|
2528
|
+
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-6]
|
|
2097
2529
|
#
|
|
2098
|
-
#
|
|
2530
|
+
# ==== Capabilities
|
|
2531
|
+
#
|
|
2532
|
+
# Return options should only be specified when the server supports
|
|
2533
|
+
# +IMAP4rev2+ or an extension that allows them, such as +ESEARCH+
|
|
2534
|
+
# [RFC4731[https://rfc-editor.org/rfc/rfc4731#section-3.1]].
|
|
2535
|
+
#
|
|
2536
|
+
# When +IMAP4rev2+ is enabled, or when the server supports +IMAP4rev2+ but
|
|
2537
|
+
# not +IMAP4rev1+, ESearchResult is always returned instead of SearchResult.
|
|
2538
|
+
#
|
|
2539
|
+
# If CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html] is supported
|
|
2099
2540
|
# and enabled for the selected mailbox, a non-empty SearchResult will
|
|
2100
2541
|
# include a +MODSEQ+ value.
|
|
2101
2542
|
# imap.select("mbox", condstore: true)
|
|
2102
|
-
# result = imap.search(["SUBJECT", "hi there", "not", "new")
|
|
2543
|
+
# result = imap.search(["SUBJECT", "hi there", "not", "new"])
|
|
2103
2544
|
# #=> Net::IMAP::SearchResult[1, 6, 7, 8, modseq: 5594]
|
|
2104
2545
|
# result.modseq # => 5594
|
|
2105
|
-
|
|
2106
|
-
|
|
2546
|
+
#
|
|
2547
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2548
|
+
# the +SEARCH+ command is prohibited. Use #uid_search instead.
|
|
2549
|
+
def search(...)
|
|
2550
|
+
search_internal("SEARCH", ...)
|
|
2107
2551
|
end
|
|
2108
2552
|
|
|
2553
|
+
# :call-seq:
|
|
2554
|
+
# uid_search(criteria, charset = nil) -> result
|
|
2555
|
+
# uid_search(criteria, charset: nil, return: nil) -> result
|
|
2556
|
+
#
|
|
2109
2557
|
# Sends a {UID SEARCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
|
|
2110
2558
|
# to search the mailbox for messages that match the given searching
|
|
2111
2559
|
# criteria, and returns unique identifiers (<tt>UID</tt>s).
|
|
@@ -2114,9 +2562,19 @@ module Net
|
|
|
2114
2562
|
# backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
|
|
2115
2563
|
# capability has been enabled.
|
|
2116
2564
|
#
|
|
2117
|
-
# See #search for documentation of
|
|
2118
|
-
|
|
2119
|
-
|
|
2565
|
+
# See #search for documentation of parameters.
|
|
2566
|
+
#
|
|
2567
|
+
# ==== Capabilities
|
|
2568
|
+
#
|
|
2569
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2570
|
+
# #uid_search must be used instead of #search, and the <tt><message
|
|
2571
|
+
# set></tt> search criterion is prohibited. Use +ALL+ or <tt>UID
|
|
2572
|
+
# sequence-set</tt> instead.
|
|
2573
|
+
#
|
|
2574
|
+
# Otherwise, #uid_search is updated by extensions in the same way as
|
|
2575
|
+
# #search.
|
|
2576
|
+
def uid_search(...)
|
|
2577
|
+
search_internal("UID SEARCH", ...)
|
|
2120
2578
|
end
|
|
2121
2579
|
|
|
2122
2580
|
# :call-seq:
|
|
@@ -2125,26 +2583,21 @@ module Net
|
|
|
2125
2583
|
# Sends a {FETCH command [IMAP4rev1 §6.4.5]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.5]
|
|
2126
2584
|
# to retrieve data associated with a message in the mailbox.
|
|
2127
2585
|
#
|
|
2128
|
-
#
|
|
2129
|
-
#
|
|
2130
|
-
#
|
|
2131
|
-
# being interpreted as '100:*'. Beware that the +exclude_end?+
|
|
2132
|
-
# property of a Range object is ignored, and the contents of a
|
|
2133
|
-
# range are independent of the order of the range endpoints as per
|
|
2134
|
-
# the protocol specification, so 1...5, 5..1 and 5...1 are all
|
|
2135
|
-
# equivalent to 1..5.
|
|
2586
|
+
# +set+ is the message sequence numbers to fetch, and may be any valid input
|
|
2587
|
+
# to {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
|
|
2588
|
+
# (For UIDs, use #uid_fetch instead.)
|
|
2136
2589
|
#
|
|
2137
|
-
# +attr+ is a list of attributes to fetch; see
|
|
2138
|
-
#
|
|
2590
|
+
# +attr+ is a list of attributes to fetch; see FetchStruct documentation for
|
|
2591
|
+
# a list of supported attributes.
|
|
2139
2592
|
#
|
|
2140
2593
|
# +changedsince+ is an optional integer mod-sequence. It limits results to
|
|
2141
2594
|
# messages with a mod-sequence greater than +changedsince+.
|
|
2142
2595
|
#
|
|
2143
2596
|
# The return value is an array of FetchData.
|
|
2144
2597
|
#
|
|
2145
|
-
# Related: #
|
|
2598
|
+
# Related: #uid_fetch, FetchData
|
|
2146
2599
|
#
|
|
2147
|
-
#
|
|
2600
|
+
# ==== For example:
|
|
2148
2601
|
#
|
|
2149
2602
|
# p imap.fetch(6..8, "UID")
|
|
2150
2603
|
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
|
|
@@ -2162,39 +2615,83 @@ module Net
|
|
|
2162
2615
|
# p data.attr["UID"]
|
|
2163
2616
|
# #=> 98
|
|
2164
2617
|
#
|
|
2165
|
-
#
|
|
2618
|
+
# ==== Capabilities
|
|
2166
2619
|
#
|
|
2167
|
-
# Many extensions define new message +attr+ names. See
|
|
2168
|
-
# of supported extension fields.
|
|
2620
|
+
# Many extensions define new message +attr+ names. See FetchStruct for a
|
|
2621
|
+
# list of supported extension fields.
|
|
2169
2622
|
#
|
|
2170
2623
|
# The server's capabilities must include +CONDSTORE+
|
|
2171
|
-
# {[RFC7162]}[https://
|
|
2624
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
|
|
2172
2625
|
# +changedsince+ argument. Using +changedsince+ implicitly enables the
|
|
2173
2626
|
# +CONDSTORE+ extension.
|
|
2174
|
-
|
|
2175
|
-
|
|
2627
|
+
#
|
|
2628
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2629
|
+
# +FETCH+ command is prohibited. Use #uid_fetch instead.
|
|
2630
|
+
def fetch(...)
|
|
2631
|
+
fetch_internal("FETCH", ...)
|
|
2176
2632
|
end
|
|
2177
2633
|
|
|
2178
2634
|
# :call-seq:
|
|
2179
|
-
# uid_fetch(set, attr, changedsince: nil) -> array of FetchData
|
|
2635
|
+
# uid_fetch(set, attr, changedsince: nil, partial: nil) -> array of FetchData (or UIDFetchData)
|
|
2180
2636
|
#
|
|
2181
2637
|
# Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
|
|
2182
2638
|
# to retrieve data associated with a message in the mailbox.
|
|
2183
2639
|
#
|
|
2184
|
-
#
|
|
2185
|
-
#
|
|
2640
|
+
# +set+ is the message UIDs to fetch, and may be any valid input to
|
|
2641
|
+
# {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
|
|
2642
|
+
# (For message sequence numbers, use #fetch instead.)
|
|
2186
2643
|
#
|
|
2644
|
+
# +attr+ behaves the same as with #fetch.
|
|
2187
2645
|
# >>>
|
|
2188
2646
|
# *Note:* Servers _MUST_ implicitly include the +UID+ message data item as
|
|
2189
2647
|
# part of any +FETCH+ response caused by a +UID+ command, regardless of
|
|
2190
2648
|
# whether a +UID+ was specified as a message data item to the +FETCH+.
|
|
2191
2649
|
#
|
|
2650
|
+
# +changedsince+ (optional) behaves the same as with #fetch.
|
|
2651
|
+
#
|
|
2652
|
+
# +partial+ is an optional range to limit the number of results returned.
|
|
2653
|
+
# It's useful when +set+ contains an unknown number of messages.
|
|
2654
|
+
# <tt>1..500</tt> returns the first 500 messages in +set+ (in mailbox
|
|
2655
|
+
# order), <tt>501..1000</tt> the second 500, and so on. +partial+ may also
|
|
2656
|
+
# be negative: <tt>-500..-1</tt> selects the last 500 messages in +set+.
|
|
2657
|
+
# <em>Requires the +PARTIAL+ capabability.</em>
|
|
2658
|
+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
|
|
2659
|
+
#
|
|
2660
|
+
# For example:
|
|
2661
|
+
#
|
|
2662
|
+
# # Without partial, the size of the results may be unknown beforehand:
|
|
2663
|
+
# results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS))
|
|
2664
|
+
# # ... maybe wait for a long time ... and allocate a lot of memory ...
|
|
2665
|
+
# results.size # => 0..2**32-1
|
|
2666
|
+
# process results # may also take a long time and use a lot of memory...
|
|
2667
|
+
#
|
|
2668
|
+
# # Using partial, the results may be paginated:
|
|
2669
|
+
# loop do
|
|
2670
|
+
# results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS),
|
|
2671
|
+
# partial: 1..500)
|
|
2672
|
+
# # fetch should return quickly and allocate little memory
|
|
2673
|
+
# results.size # => 0..500
|
|
2674
|
+
# break if results.empty?
|
|
2675
|
+
# results.sort_by!(&:uid) # server may return results out of order
|
|
2676
|
+
# next_uid_to_fetch = results.last.uid + 1
|
|
2677
|
+
# process results
|
|
2678
|
+
# end
|
|
2679
|
+
#
|
|
2192
2680
|
# Related: #fetch, FetchData
|
|
2193
2681
|
#
|
|
2194
|
-
#
|
|
2195
|
-
#
|
|
2196
|
-
|
|
2197
|
-
|
|
2682
|
+
# ==== Capabilities
|
|
2683
|
+
#
|
|
2684
|
+
# The server's capabilities must include +PARTIAL+
|
|
2685
|
+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394] in order to use the
|
|
2686
|
+
# +partial+ argument.
|
|
2687
|
+
#
|
|
2688
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2689
|
+
# #uid_fetch must be used instead of #fetch, and UIDFetchData will be
|
|
2690
|
+
# returned instead of FetchData.
|
|
2691
|
+
#
|
|
2692
|
+
# Otherwise, #uid_fetch is updated by extensions in the same way as #fetch.
|
|
2693
|
+
def uid_fetch(...)
|
|
2694
|
+
fetch_internal("UID FETCH", ...)
|
|
2198
2695
|
end
|
|
2199
2696
|
|
|
2200
2697
|
# :call-seq:
|
|
@@ -2225,27 +2722,30 @@ module Net
|
|
|
2225
2722
|
#
|
|
2226
2723
|
# Related: #uid_store
|
|
2227
2724
|
#
|
|
2228
|
-
#
|
|
2725
|
+
# ==== For example:
|
|
2229
2726
|
#
|
|
2230
2727
|
# p imap.store(6..8, "+FLAGS", [:Deleted])
|
|
2231
2728
|
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
|
|
2232
2729
|
# #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
|
|
2233
2730
|
# #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
|
|
2234
2731
|
#
|
|
2235
|
-
#
|
|
2732
|
+
# ==== Capabilities
|
|
2236
2733
|
#
|
|
2237
2734
|
# Extensions may define new data items to be used with #store.
|
|
2238
2735
|
#
|
|
2239
2736
|
# The server's capabilities must include +CONDSTORE+
|
|
2240
|
-
# {[RFC7162]}[https://
|
|
2737
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
|
|
2241
2738
|
# +unchangedsince+ argument. Using +unchangedsince+ implicitly enables the
|
|
2242
2739
|
# +CONDSTORE+ extension.
|
|
2740
|
+
#
|
|
2741
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2742
|
+
# +STORE+ command is prohibited. Use #uid_store instead.
|
|
2243
2743
|
def store(set, attr, flags, unchangedsince: nil)
|
|
2244
2744
|
store_internal("STORE", set, attr, flags, unchangedsince: unchangedsince)
|
|
2245
2745
|
end
|
|
2246
2746
|
|
|
2247
2747
|
# :call-seq:
|
|
2248
|
-
# uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData
|
|
2748
|
+
# uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData (or UIDFetchData)
|
|
2249
2749
|
#
|
|
2250
2750
|
# Sends a {UID STORE command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
|
|
2251
2751
|
# to alter data associated with messages in the mailbox, in particular their
|
|
@@ -2256,8 +2756,13 @@ module Net
|
|
|
2256
2756
|
#
|
|
2257
2757
|
# Related: #store
|
|
2258
2758
|
#
|
|
2259
|
-
#
|
|
2260
|
-
#
|
|
2759
|
+
# ==== Capabilities
|
|
2760
|
+
#
|
|
2761
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2762
|
+
# #uid_store must be used instead of #store, and UIDFetchData will be
|
|
2763
|
+
# returned instead of FetchData.
|
|
2764
|
+
#
|
|
2765
|
+
# Otherwise, #uid_store is updated by extensions in the same way as #store.
|
|
2261
2766
|
def uid_store(set, attr, flags, unchangedsince: nil)
|
|
2262
2767
|
store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince)
|
|
2263
2768
|
end
|
|
@@ -2269,13 +2774,16 @@ module Net
|
|
|
2269
2774
|
#
|
|
2270
2775
|
# Related: #uid_copy
|
|
2271
2776
|
#
|
|
2272
|
-
#
|
|
2777
|
+
# ==== Capabilities
|
|
2273
2778
|
#
|
|
2274
2779
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2275
2780
|
# supported, the server's response should include a +COPYUID+ response code
|
|
2276
|
-
# with
|
|
2781
|
+
# with CopyUIDData. This will report the UIDVALIDITY of the destination
|
|
2277
2782
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2278
2783
|
# the moved messages.
|
|
2784
|
+
#
|
|
2785
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2786
|
+
# +COPY+ command is prohibited. Use #uid_copy instead.
|
|
2279
2787
|
def copy(set, mailbox)
|
|
2280
2788
|
copy_internal("COPY", set, mailbox)
|
|
2281
2789
|
end
|
|
@@ -2286,9 +2794,12 @@ module Net
|
|
|
2286
2794
|
#
|
|
2287
2795
|
# Similar to #copy, but +set+ contains unique identifiers.
|
|
2288
2796
|
#
|
|
2289
|
-
#
|
|
2797
|
+
# ==== Capabilities
|
|
2798
|
+
#
|
|
2799
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] in enabled,
|
|
2800
|
+
# #uid_copy must be used instead of #copy.
|
|
2290
2801
|
#
|
|
2291
|
-
#
|
|
2802
|
+
# Otherwise, #uid_copy is updated by extensions in the same way as #copy.
|
|
2292
2803
|
def uid_copy(set, mailbox)
|
|
2293
2804
|
copy_internal("UID COPY", set, mailbox)
|
|
2294
2805
|
end
|
|
@@ -2301,17 +2812,19 @@ module Net
|
|
|
2301
2812
|
#
|
|
2302
2813
|
# Related: #uid_move
|
|
2303
2814
|
#
|
|
2304
|
-
#
|
|
2815
|
+
# ==== Capabilities
|
|
2305
2816
|
#
|
|
2306
|
-
# The server's capabilities must include +MOVE+
|
|
2307
|
-
# [RFC6851[https://
|
|
2817
|
+
# The server's capabilities must include either +IMAP4rev2+ or +MOVE+
|
|
2818
|
+
# [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
|
|
2308
2819
|
#
|
|
2309
2820
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2310
2821
|
# supported, the server's response should include a +COPYUID+ response code
|
|
2311
|
-
# with
|
|
2822
|
+
# with CopyUIDData. This will report the UIDVALIDITY of the destination
|
|
2312
2823
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2313
2824
|
# the moved messages.
|
|
2314
2825
|
#
|
|
2826
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2827
|
+
# +MOVE+ command is prohibited. Use #uid_move instead.
|
|
2315
2828
|
def move(set, mailbox)
|
|
2316
2829
|
copy_internal("MOVE", set, mailbox)
|
|
2317
2830
|
end
|
|
@@ -2325,11 +2838,15 @@ module Net
|
|
|
2325
2838
|
#
|
|
2326
2839
|
# Related: #move
|
|
2327
2840
|
#
|
|
2328
|
-
#
|
|
2841
|
+
# ==== Capabilities
|
|
2842
|
+
#
|
|
2843
|
+
# The server's capabilities must include either +IMAP4rev2+ or +MOVE+
|
|
2844
|
+
# [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
|
|
2329
2845
|
#
|
|
2330
|
-
#
|
|
2331
|
-
#
|
|
2332
|
-
#
|
|
2846
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2847
|
+
# #uid_move must be used instead of #move.
|
|
2848
|
+
#
|
|
2849
|
+
# Otherwise, #uid_move is updated by extensions in the same way as #move.
|
|
2333
2850
|
def uid_move(set, mailbox)
|
|
2334
2851
|
copy_internal("UID MOVE", set, mailbox)
|
|
2335
2852
|
end
|
|
@@ -2345,17 +2862,17 @@ module Net
|
|
|
2345
2862
|
#
|
|
2346
2863
|
# Related: #uid_sort, #search, #uid_search, #thread, #uid_thread
|
|
2347
2864
|
#
|
|
2348
|
-
#
|
|
2865
|
+
# ==== For example:
|
|
2349
2866
|
#
|
|
2350
2867
|
# p imap.sort(["FROM"], ["ALL"], "US-ASCII")
|
|
2351
2868
|
# #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
|
|
2352
2869
|
# p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
|
|
2353
2870
|
# #=> [6, 7, 8, 1]
|
|
2354
2871
|
#
|
|
2355
|
-
#
|
|
2872
|
+
# ==== Capabilities
|
|
2356
2873
|
#
|
|
2357
2874
|
# The server's capabilities must include +SORT+
|
|
2358
|
-
# [RFC5256[https://
|
|
2875
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2359
2876
|
def sort(sort_keys, search_keys, charset)
|
|
2360
2877
|
return sort_internal("SORT", sort_keys, search_keys, charset)
|
|
2361
2878
|
end
|
|
@@ -2367,10 +2884,10 @@ module Net
|
|
|
2367
2884
|
#
|
|
2368
2885
|
# Related: #sort, #search, #uid_search, #thread, #uid_thread
|
|
2369
2886
|
#
|
|
2370
|
-
#
|
|
2887
|
+
# ==== Capabilities
|
|
2371
2888
|
#
|
|
2372
2889
|
# The server's capabilities must include +SORT+
|
|
2373
|
-
# [RFC5256[https://
|
|
2890
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2374
2891
|
def uid_sort(sort_keys, search_keys, charset)
|
|
2375
2892
|
return sort_internal("UID SORT", sort_keys, search_keys, charset)
|
|
2376
2893
|
end
|
|
@@ -2392,10 +2909,10 @@ module Net
|
|
|
2392
2909
|
#
|
|
2393
2910
|
# Related: #uid_thread, #search, #uid_search, #sort, #uid_sort
|
|
2394
2911
|
#
|
|
2395
|
-
#
|
|
2912
|
+
# ==== Capabilities
|
|
2396
2913
|
#
|
|
2397
2914
|
# The server's capabilities must include +THREAD+
|
|
2398
|
-
# [RFC5256[https://
|
|
2915
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2399
2916
|
def thread(algorithm, search_keys, charset)
|
|
2400
2917
|
return thread_internal("THREAD", algorithm, search_keys, charset)
|
|
2401
2918
|
end
|
|
@@ -2406,10 +2923,10 @@ module Net
|
|
|
2406
2923
|
#
|
|
2407
2924
|
# Related: #thread, #search, #uid_search, #sort, #uid_sort
|
|
2408
2925
|
#
|
|
2409
|
-
#
|
|
2926
|
+
# ==== Capabilities
|
|
2410
2927
|
#
|
|
2411
2928
|
# The server's capabilities must include +THREAD+
|
|
2412
|
-
# [RFC5256[https://
|
|
2929
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2413
2930
|
def uid_thread(algorithm, search_keys, charset)
|
|
2414
2931
|
return thread_internal("UID THREAD", algorithm, search_keys, charset)
|
|
2415
2932
|
end
|
|
@@ -2425,11 +2942,11 @@ module Net
|
|
|
2425
2942
|
#
|
|
2426
2943
|
# Related: #capable?, #capabilities, #capability
|
|
2427
2944
|
#
|
|
2428
|
-
#
|
|
2945
|
+
# ==== Capabilities
|
|
2429
2946
|
#
|
|
2430
2947
|
# The server's capabilities must include
|
|
2431
|
-
# +ENABLE+ [RFC5161[https://
|
|
2432
|
-
# or +IMAP4REV2+ [RFC9051[https://
|
|
2948
|
+
# +ENABLE+ [RFC5161[https://www.rfc-editor.org/rfc/rfc5161]]
|
|
2949
|
+
# or +IMAP4REV2+ [RFC9051[https://www.rfc-editor.org/rfc/rfc9051]].
|
|
2433
2950
|
#
|
|
2434
2951
|
# Additionally, the server capabilities must include a capability matching
|
|
2435
2952
|
# each enabled extension (usually the same name as the enabled extension).
|
|
@@ -2442,13 +2959,25 @@ module Net
|
|
|
2442
2959
|
# command parameters defined by the extension will implicitly enable it.
|
|
2443
2960
|
# See {[RFC7162 §3.1]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1].
|
|
2444
2961
|
#
|
|
2962
|
+
# [+QRESYNC+ {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html]]
|
|
2963
|
+
# *NOTE:* Enabling QRESYNC will replace +EXPUNGE+ with +VANISHED+, but
|
|
2964
|
+
# the extension arguments to #select, #examine, and #uid_fetch are not
|
|
2965
|
+
# supported yet.
|
|
2966
|
+
#
|
|
2967
|
+
# Adds quick resynchronization options to #select, #examine, and
|
|
2968
|
+
# #uid_fetch. +QRESYNC+ _must_ be explicitly enabled before using any of
|
|
2969
|
+
# the extension's command parameters. All +EXPUNGE+ responses will be
|
|
2970
|
+
# replaced with +VANISHED+ responses. Enabling +QRESYNC+ implicitly
|
|
2971
|
+
# enables +CONDSTORE+ as well.
|
|
2972
|
+
# See {[RFC7162 §3.2]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.2].
|
|
2973
|
+
#
|
|
2445
2974
|
# [+:utf8+ --- an alias for <tt>"UTF8=ACCEPT"</tt>]
|
|
2446
2975
|
#
|
|
2447
2976
|
# In a future release, <tt>enable(:utf8)</tt> will enable either
|
|
2448
2977
|
# <tt>"UTF8=ACCEPT"</tt> or <tt>"IMAP4rev2"</tt>, depending on server
|
|
2449
2978
|
# capabilities.
|
|
2450
2979
|
#
|
|
2451
|
-
# [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://
|
|
2980
|
+
# [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
|
|
2452
2981
|
#
|
|
2453
2982
|
# The server's capabilities must include <tt>UTF8=ACCEPT</tt> _or_
|
|
2454
2983
|
# <tt>UTF8=ONLY</tt>.
|
|
@@ -2467,13 +2996,23 @@ module Net
|
|
|
2467
2996
|
# encoding, even if they generally contain UTF-8 data, if they are
|
|
2468
2997
|
# text at all.
|
|
2469
2998
|
#
|
|
2470
|
-
# [<tt>"UTF8=ONLY"</tt> [RFC6855[https://
|
|
2999
|
+
# [<tt>"UTF8=ONLY"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
|
|
2471
3000
|
#
|
|
2472
3001
|
# A server that reports the <tt>UTF8=ONLY</tt> capability _requires_ that
|
|
2473
3002
|
# the client <tt>enable("UTF8=ACCEPT")</tt> before any mailboxes may be
|
|
2474
3003
|
# selected. For convenience, <tt>enable("UTF8=ONLY")</tt> is aliased to
|
|
2475
3004
|
# <tt>enable("UTF8=ACCEPT")</tt>.
|
|
2476
3005
|
#
|
|
3006
|
+
# [+UIDONLY+ {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.pdf]]
|
|
3007
|
+
#
|
|
3008
|
+
# When UIDONLY is enabled, the #fetch, #store, #search, #copy, and #move
|
|
3009
|
+
# commands are prohibited and result in a tagged BAD response. Clients
|
|
3010
|
+
# should instead use uid_fetch, uid_store, uid_search, uid_copy, or
|
|
3011
|
+
# uid_move, respectively. All +FETCH+ responses that would be returned are
|
|
3012
|
+
# replaced by +UIDFETCH+ responses. All +EXPUNGED+ responses that would be
|
|
3013
|
+
# returned are replaced by +VANISHED+ responses. The "<sequence set>"
|
|
3014
|
+
# uid_search criterion is prohibited.
|
|
3015
|
+
#
|
|
2477
3016
|
# ===== Unsupported capabilities
|
|
2478
3017
|
#
|
|
2479
3018
|
# *Note:* Some extensions that use ENABLE permit the server to send syntax
|
|
@@ -2527,10 +3066,10 @@ module Net
|
|
|
2527
3066
|
#
|
|
2528
3067
|
# Related: #idle_done, #noop, #check
|
|
2529
3068
|
#
|
|
2530
|
-
#
|
|
3069
|
+
# ==== Capabilities
|
|
2531
3070
|
#
|
|
2532
|
-
# The server's capabilities must include +IDLE+
|
|
2533
|
-
# [RFC2177[https://
|
|
3071
|
+
# The server's capabilities must include either +IMAP4rev2+ or +IDLE+
|
|
3072
|
+
# [RFC2177[https://www.rfc-editor.org/rfc/rfc2177]].
|
|
2534
3073
|
def idle(timeout = nil, &response_handler)
|
|
2535
3074
|
raise LocalJumpError, "no block given" unless response_handler
|
|
2536
3075
|
|
|
@@ -2549,8 +3088,8 @@ module Net
|
|
|
2549
3088
|
raise @exception || Net::IMAP::Error.new("connection closed")
|
|
2550
3089
|
end
|
|
2551
3090
|
ensure
|
|
3091
|
+
remove_response_handler(response_handler)
|
|
2552
3092
|
unless @receiver_thread_terminating
|
|
2553
|
-
remove_response_handler(response_handler)
|
|
2554
3093
|
put_string("DONE#{CRLF}")
|
|
2555
3094
|
response = get_tagged_response(tag, "IDLE", idle_response_timeout)
|
|
2556
3095
|
end
|
|
@@ -2644,7 +3183,7 @@ module Net
|
|
|
2644
3183
|
#
|
|
2645
3184
|
# Related: #extract_responses, #clear_responses, #response_handlers, #greeting
|
|
2646
3185
|
#
|
|
2647
|
-
#
|
|
3186
|
+
# ==== Thread safety
|
|
2648
3187
|
# >>>
|
|
2649
3188
|
# *Note:* Access to the responses hash is synchronized for thread-safety.
|
|
2650
3189
|
# The receiver thread and response_handlers cannot process new responses
|
|
@@ -2658,7 +3197,7 @@ module Net
|
|
|
2658
3197
|
# thread, but will not modify any responses after adding them to the
|
|
2659
3198
|
# responses hash.
|
|
2660
3199
|
#
|
|
2661
|
-
#
|
|
3200
|
+
# ==== Clearing responses
|
|
2662
3201
|
#
|
|
2663
3202
|
# Previously unhandled responses are automatically cleared before entering a
|
|
2664
3203
|
# mailbox with #select or #examine. Long-lived connections can receive many
|
|
@@ -2667,7 +3206,7 @@ module Net
|
|
|
2667
3206
|
# the block, or remove responses with #extract_responses, #clear_responses,
|
|
2668
3207
|
# or #add_response_handler.
|
|
2669
3208
|
#
|
|
2670
|
-
#
|
|
3209
|
+
# ==== Missing responses
|
|
2671
3210
|
#
|
|
2672
3211
|
# Only non-+nil+ data is stored. Many important response codes have no data
|
|
2673
3212
|
# of their own, but are used as "tags" on the ResponseText object they are
|
|
@@ -2688,10 +3227,10 @@ module Net
|
|
|
2688
3227
|
when :raise
|
|
2689
3228
|
raise ArgumentError, RESPONSES_DEPRECATION_MSG
|
|
2690
3229
|
when :warn
|
|
2691
|
-
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1)
|
|
3230
|
+
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1, category: :deprecated)
|
|
2692
3231
|
when :frozen_dup
|
|
2693
3232
|
synchronize {
|
|
2694
|
-
responses = @responses.transform_values
|
|
3233
|
+
responses = @responses.transform_values { _1.dup.freeze }
|
|
2695
3234
|
responses.default_proc = nil
|
|
2696
3235
|
responses.default = [].freeze
|
|
2697
3236
|
return responses.freeze
|
|
@@ -2811,6 +3350,7 @@ module Net
|
|
|
2811
3350
|
@response_handlers.each do |handler| handler.call(@greeting) end
|
|
2812
3351
|
@receiver_thread = start_receiver_thread
|
|
2813
3352
|
rescue Exception
|
|
3353
|
+
state_logout!
|
|
2814
3354
|
@sock.close
|
|
2815
3355
|
raise
|
|
2816
3356
|
end
|
|
@@ -2819,7 +3359,10 @@ module Net
|
|
|
2819
3359
|
greeting = get_response
|
|
2820
3360
|
raise Error, "No server greeting - connection closed" unless greeting
|
|
2821
3361
|
record_untagged_response_code greeting
|
|
2822
|
-
|
|
3362
|
+
case greeting.name
|
|
3363
|
+
when "PREAUTH" then state_authenticated!
|
|
3364
|
+
when "BYE" then state_logout!; raise ByeResponseError, greeting
|
|
3365
|
+
end
|
|
2823
3366
|
greeting
|
|
2824
3367
|
end
|
|
2825
3368
|
|
|
@@ -2851,6 +3394,7 @@ module Net
|
|
|
2851
3394
|
resp = get_response
|
|
2852
3395
|
rescue Exception => e
|
|
2853
3396
|
synchronize do
|
|
3397
|
+
state_logout!
|
|
2854
3398
|
@sock.close
|
|
2855
3399
|
@exception = e
|
|
2856
3400
|
end
|
|
@@ -2870,6 +3414,7 @@ module Net
|
|
|
2870
3414
|
@tagged_response_arrival.broadcast
|
|
2871
3415
|
case resp.tag
|
|
2872
3416
|
when @logout_command_tag
|
|
3417
|
+
state_logout!
|
|
2873
3418
|
return
|
|
2874
3419
|
when @continued_command_tag
|
|
2875
3420
|
@continuation_request_exception =
|
|
@@ -2879,6 +3424,7 @@ module Net
|
|
|
2879
3424
|
when UntaggedResponse
|
|
2880
3425
|
record_untagged_response(resp)
|
|
2881
3426
|
if resp.name == "BYE" && @logout_command_tag.nil?
|
|
3427
|
+
state_logout!
|
|
2882
3428
|
@sock.close
|
|
2883
3429
|
@exception = ByeResponseError.new(resp)
|
|
2884
3430
|
connection_closed = true
|
|
@@ -2886,6 +3432,7 @@ module Net
|
|
|
2886
3432
|
when ContinuationRequest
|
|
2887
3433
|
@continuation_request_arrival.signal
|
|
2888
3434
|
end
|
|
3435
|
+
state_unselected! if resp in {data: {code: {name: "CLOSED"}}}
|
|
2889
3436
|
@response_handlers.each do |handler|
|
|
2890
3437
|
handler.call(resp)
|
|
2891
3438
|
end
|
|
@@ -2906,6 +3453,8 @@ module Net
|
|
|
2906
3453
|
@idle_done_cond.signal
|
|
2907
3454
|
end
|
|
2908
3455
|
end
|
|
3456
|
+
ensure
|
|
3457
|
+
state_logout!
|
|
2909
3458
|
end
|
|
2910
3459
|
|
|
2911
3460
|
def get_tagged_response(tag, cmd, timeout = nil)
|
|
@@ -3029,23 +3578,118 @@ module Net
|
|
|
3029
3578
|
end
|
|
3030
3579
|
end
|
|
3031
3580
|
|
|
3032
|
-
def
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3581
|
+
def enforce_logindisabled?
|
|
3582
|
+
may_depend_on_capabilities_cached?(config.enforce_logindisabled)
|
|
3583
|
+
end
|
|
3584
|
+
|
|
3585
|
+
def may_depend_on_capabilities_cached?(value)
|
|
3586
|
+
value == :when_capabilities_cached ? capabilities_cached? : value
|
|
3587
|
+
end
|
|
3588
|
+
|
|
3589
|
+
def expunge_internal(...)
|
|
3590
|
+
synchronize do
|
|
3591
|
+
send_command(...)
|
|
3592
|
+
expunged_array = clear_responses("EXPUNGE")
|
|
3593
|
+
vanished_array = extract_responses("VANISHED") { !_1.earlier? }
|
|
3594
|
+
if vanished_array.empty?
|
|
3595
|
+
expunged_array
|
|
3596
|
+
elsif vanished_array.length == 1
|
|
3597
|
+
vanished_array.first
|
|
3598
|
+
else
|
|
3599
|
+
merged_uids = SequenceSet[*vanished_array.map(&:uids)]
|
|
3600
|
+
VanishedData[uids: merged_uids, earlier: false]
|
|
3601
|
+
end
|
|
3602
|
+
end
|
|
3603
|
+
end
|
|
3604
|
+
|
|
3605
|
+
RETURN_WHOLE = /\ARETURN\z/i
|
|
3606
|
+
RETURN_START = /\ARETURN\b/i
|
|
3607
|
+
private_constant :RETURN_WHOLE, :RETURN_START
|
|
3608
|
+
|
|
3609
|
+
def search_args(keys, charset_arg = nil, return: nil, charset: nil)
|
|
3610
|
+
{return:} => {return: return_kw}
|
|
3611
|
+
case [return_kw, keys]
|
|
3612
|
+
in [nil, Array[RETURN_WHOLE, return_opts, *keys]]
|
|
3613
|
+
return_opts = convert_return_opts(return_opts)
|
|
3614
|
+
esearch = true
|
|
3615
|
+
in [nil => return_opts, RETURN_START]
|
|
3616
|
+
esearch = true
|
|
3617
|
+
in [nil => return_opts, keys]
|
|
3618
|
+
esearch = false
|
|
3619
|
+
in [_, Array[RETURN_WHOLE, _, *] | RETURN_START]
|
|
3620
|
+
raise ArgumentError, "conflicting return options"
|
|
3621
|
+
in [_, Array[RETURN_WHOLE, _, *]] # workaround for https://bugs.ruby-lang.org/issues/20956
|
|
3622
|
+
raise ArgumentError, "conflicting return options"
|
|
3623
|
+
in [_, RETURN_START] # workaround for https://bugs.ruby-lang.org/issues/20956
|
|
3624
|
+
raise ArgumentError, "conflicting return options"
|
|
3625
|
+
in [return_opts, keys]
|
|
3626
|
+
return_opts = convert_return_opts(return_opts)
|
|
3627
|
+
esearch = true
|
|
3628
|
+
end
|
|
3629
|
+
if charset && charset_arg
|
|
3630
|
+
raise ArgumentError, "multiple charset arguments"
|
|
3037
3631
|
end
|
|
3632
|
+
charset ||= charset_arg
|
|
3633
|
+
# NOTE: not handling combined RETURN and CHARSET for raw strings
|
|
3634
|
+
if charset && keys in /\ACHARSET\b/i | Array[/\ACHARSET\z/i, *]
|
|
3635
|
+
raise ArgumentError, "multiple charset arguments"
|
|
3636
|
+
end
|
|
3637
|
+
args = normalize_searching_criteria(keys)
|
|
3638
|
+
args.prepend("CHARSET", charset) if charset
|
|
3639
|
+
args.prepend("RETURN", return_opts) if return_opts
|
|
3640
|
+
return args, esearch
|
|
3641
|
+
end
|
|
3642
|
+
|
|
3643
|
+
def convert_return_opts(unconverted)
|
|
3644
|
+
return_opts = Array.try_convert(unconverted) or
|
|
3645
|
+
raise TypeError, "expected return options to be Array, got %s" % [
|
|
3646
|
+
unconverted.class
|
|
3647
|
+
]
|
|
3648
|
+
return_opts.map {|opt|
|
|
3649
|
+
case opt
|
|
3650
|
+
when Symbol then opt.to_s
|
|
3651
|
+
when PartialRange::Negative then PartialRange[opt]
|
|
3652
|
+
when Range then SequenceSet[opt]
|
|
3653
|
+
else opt
|
|
3654
|
+
end
|
|
3655
|
+
}
|
|
3656
|
+
end
|
|
3657
|
+
|
|
3658
|
+
def search_internal(cmd, ...)
|
|
3659
|
+
args, esearch = search_args(...)
|
|
3038
3660
|
synchronize do
|
|
3039
|
-
|
|
3040
|
-
|
|
3661
|
+
tagged = send_command(cmd, *args)
|
|
3662
|
+
tag = tagged.tag
|
|
3663
|
+
# Only the last ESEARCH or SEARCH is used. Excess results are ignored.
|
|
3664
|
+
esearch_result = extract_responses("ESEARCH") {|response|
|
|
3665
|
+
response in ESearchResult(tag: ^tag)
|
|
3666
|
+
}.last
|
|
3667
|
+
search_result = clear_responses("SEARCH").last
|
|
3668
|
+
if esearch_result
|
|
3669
|
+
# silently ignore SEARCH results, if any
|
|
3670
|
+
esearch_result
|
|
3671
|
+
elsif search_result
|
|
3672
|
+
# warn EXPECTED_ESEARCH_RESULT if esearch
|
|
3673
|
+
search_result
|
|
3674
|
+
elsif esearch
|
|
3675
|
+
# warn NO_SEARCH_RESPONSE
|
|
3676
|
+
ESearchResult[tag:, uid: cmd.start_with?("UID ")]
|
|
3041
3677
|
else
|
|
3042
|
-
|
|
3678
|
+
# warn NO_SEARCH_RESPONSE
|
|
3679
|
+
SearchResult[]
|
|
3043
3680
|
end
|
|
3044
|
-
clear_responses("SEARCH").last || []
|
|
3045
3681
|
end
|
|
3046
3682
|
end
|
|
3047
3683
|
|
|
3048
|
-
def fetch_internal(cmd, set, attr, mod = nil, changedsince: nil)
|
|
3684
|
+
def fetch_internal(cmd, set, attr, mod = nil, partial: nil, changedsince: nil)
|
|
3685
|
+
if partial && !cmd.start_with?("UID ")
|
|
3686
|
+
raise ArgumentError, "partial can only be used with uid_fetch"
|
|
3687
|
+
end
|
|
3688
|
+
set = SequenceSet[set]
|
|
3689
|
+
if partial
|
|
3690
|
+
mod ||= []
|
|
3691
|
+
mod << "PARTIAL" << PartialRange[partial]
|
|
3692
|
+
end
|
|
3049
3693
|
if changedsince
|
|
3050
3694
|
mod ||= []
|
|
3051
3695
|
mod << "CHANGEDSINCE" << Integer(changedsince)
|
|
@@ -3059,39 +3703,36 @@ module Net
|
|
|
3059
3703
|
}
|
|
3060
3704
|
end
|
|
3061
3705
|
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
send_command(cmd, MessageSet.new(set), attr, mod)
|
|
3066
|
-
else
|
|
3067
|
-
send_command(cmd, MessageSet.new(set), attr)
|
|
3068
|
-
end
|
|
3069
|
-
clear_responses("FETCH")
|
|
3070
|
-
end
|
|
3706
|
+
args = [cmd, set, attr]
|
|
3707
|
+
args << mod if mod
|
|
3708
|
+
send_command_returning_fetch_results(*args)
|
|
3071
3709
|
end
|
|
3072
3710
|
|
|
3073
3711
|
def store_internal(cmd, set, attr, flags, unchangedsince: nil)
|
|
3074
3712
|
attr = RawData.new(attr) if attr.instance_of?(String)
|
|
3075
|
-
args = [
|
|
3713
|
+
args = [SequenceSet.new(set)]
|
|
3076
3714
|
args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
|
|
3077
3715
|
args << attr << flags
|
|
3716
|
+
send_command_returning_fetch_results(cmd, *args)
|
|
3717
|
+
end
|
|
3718
|
+
|
|
3719
|
+
def send_command_returning_fetch_results(...)
|
|
3078
3720
|
synchronize do
|
|
3079
3721
|
clear_responses("FETCH")
|
|
3080
|
-
|
|
3081
|
-
|
|
3722
|
+
clear_responses("UIDFETCH")
|
|
3723
|
+
send_command(...)
|
|
3724
|
+
fetches = clear_responses("FETCH")
|
|
3725
|
+
uidfetches = clear_responses("UIDFETCH")
|
|
3726
|
+
uidfetches.any? ? uidfetches : fetches
|
|
3082
3727
|
end
|
|
3083
3728
|
end
|
|
3084
3729
|
|
|
3085
3730
|
def copy_internal(cmd, set, mailbox)
|
|
3086
|
-
send_command(cmd,
|
|
3731
|
+
send_command(cmd, SequenceSet.new(set), mailbox)
|
|
3087
3732
|
end
|
|
3088
3733
|
|
|
3089
3734
|
def sort_internal(cmd, sort_keys, search_keys, charset)
|
|
3090
|
-
|
|
3091
|
-
search_keys = [RawData.new(search_keys)]
|
|
3092
|
-
else
|
|
3093
|
-
normalize_searching_criteria(search_keys)
|
|
3094
|
-
end
|
|
3735
|
+
search_keys = normalize_searching_criteria(search_keys)
|
|
3095
3736
|
synchronize do
|
|
3096
3737
|
send_command(cmd, sort_keys, charset, *search_keys)
|
|
3097
3738
|
clear_responses("SORT").last || []
|
|
@@ -3099,36 +3740,47 @@ module Net
|
|
|
3099
3740
|
end
|
|
3100
3741
|
|
|
3101
3742
|
def thread_internal(cmd, algorithm, search_keys, charset)
|
|
3102
|
-
|
|
3103
|
-
search_keys = [RawData.new(search_keys)]
|
|
3104
|
-
else
|
|
3105
|
-
normalize_searching_criteria(search_keys)
|
|
3106
|
-
end
|
|
3743
|
+
search_keys = normalize_searching_criteria(search_keys)
|
|
3107
3744
|
synchronize do
|
|
3108
3745
|
send_command(cmd, algorithm, charset, *search_keys)
|
|
3109
3746
|
clear_responses("THREAD").last || []
|
|
3110
3747
|
end
|
|
3111
3748
|
end
|
|
3112
3749
|
|
|
3113
|
-
def normalize_searching_criteria(
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3750
|
+
def normalize_searching_criteria(criteria)
|
|
3751
|
+
return [RawData.new(criteria)] if criteria.is_a?(String)
|
|
3752
|
+
criteria.map {|i|
|
|
3753
|
+
if coerce_search_arg_to_seqset?(i)
|
|
3754
|
+
SequenceSet[i]
|
|
3118
3755
|
else
|
|
3119
3756
|
i
|
|
3120
3757
|
end
|
|
3758
|
+
}
|
|
3759
|
+
end
|
|
3760
|
+
|
|
3761
|
+
def coerce_search_arg_to_seqset?(obj)
|
|
3762
|
+
case obj
|
|
3763
|
+
when Set, -1, :* then true
|
|
3764
|
+
when Range then true
|
|
3765
|
+
when Array then obj.all? { coerce_search_array_arg_to_seqset? _1 }
|
|
3766
|
+
else obj.respond_to?(:to_sequence_set)
|
|
3767
|
+
end
|
|
3768
|
+
end
|
|
3769
|
+
|
|
3770
|
+
def coerce_search_array_arg_to_seqset?(obj)
|
|
3771
|
+
case obj
|
|
3772
|
+
when Integer then obj.positive? || obj == -1
|
|
3773
|
+
when String then ResponseParser::Patterns::SEQUENCE_SET_STR.match?(obj.b)
|
|
3774
|
+
else
|
|
3775
|
+
coerce_search_arg_to_seqset?(obj)
|
|
3121
3776
|
end
|
|
3122
3777
|
end
|
|
3123
3778
|
|
|
3124
3779
|
def build_ssl_ctx(ssl)
|
|
3125
3780
|
if ssl
|
|
3126
3781
|
params = (Hash.try_convert(ssl) || {}).freeze
|
|
3127
|
-
context = SSLContext.new
|
|
3782
|
+
context = OpenSSL::SSL::SSLContext.new
|
|
3128
3783
|
context.set_params(params)
|
|
3129
|
-
if defined?(VerifyCallbackProc)
|
|
3130
|
-
context.verify_callback = VerifyCallbackProc
|
|
3131
|
-
end
|
|
3132
3784
|
context.freeze
|
|
3133
3785
|
[params, context]
|
|
3134
3786
|
else
|
|
@@ -3140,17 +3792,54 @@ module Net
|
|
|
3140
3792
|
raise "SSL extension not installed" unless defined?(OpenSSL::SSL)
|
|
3141
3793
|
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
|
|
3142
3794
|
raise "cannot start TLS without SSLContext" unless ssl_ctx
|
|
3143
|
-
@sock = SSLSocket.new(@sock, ssl_ctx)
|
|
3795
|
+
@sock = OpenSSL::SSL::SSLSocket.new(@sock, ssl_ctx)
|
|
3144
3796
|
@reader = ResponseReader.new(self, @sock)
|
|
3145
3797
|
@sock.sync_close = true
|
|
3146
3798
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
|
3147
3799
|
ssl_socket_connect(@sock, open_timeout)
|
|
3148
|
-
if ssl_ctx.verify_mode != VERIFY_NONE
|
|
3800
|
+
if ssl_ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
|
3149
3801
|
@sock.post_connection_check(@host)
|
|
3150
3802
|
@tls_verified = true
|
|
3151
3803
|
end
|
|
3152
3804
|
end
|
|
3153
3805
|
|
|
3806
|
+
def state_authenticated!(resp = nil)
|
|
3807
|
+
synchronize do
|
|
3808
|
+
@capabilities = capabilities_from_resp_code resp if resp
|
|
3809
|
+
@connection_state = ConnectionState::Authenticated.new
|
|
3810
|
+
end
|
|
3811
|
+
end
|
|
3812
|
+
|
|
3813
|
+
def state_selected!
|
|
3814
|
+
synchronize do
|
|
3815
|
+
@connection_state = ConnectionState::Selected.new
|
|
3816
|
+
end
|
|
3817
|
+
end
|
|
3818
|
+
|
|
3819
|
+
def state_unselected!
|
|
3820
|
+
synchronize do
|
|
3821
|
+
state_authenticated! if connection_state.to_sym == :selected
|
|
3822
|
+
end
|
|
3823
|
+
end
|
|
3824
|
+
|
|
3825
|
+
def state_logout!
|
|
3826
|
+
return true if connection_state in [:logout, *]
|
|
3827
|
+
synchronize do
|
|
3828
|
+
return true if connection_state in [:logout, *]
|
|
3829
|
+
@connection_state = ConnectionState::Logout.new
|
|
3830
|
+
end
|
|
3831
|
+
end
|
|
3832
|
+
|
|
3833
|
+
# don't wait to aqcuire the lock
|
|
3834
|
+
def try_state_logout?
|
|
3835
|
+
return true if connection_state in [:logout, *]
|
|
3836
|
+
return false unless acquired_lock = mon_try_enter
|
|
3837
|
+
state_logout!
|
|
3838
|
+
true
|
|
3839
|
+
ensure
|
|
3840
|
+
mon_exit if acquired_lock
|
|
3841
|
+
end
|
|
3842
|
+
|
|
3154
3843
|
def sasl_adapter
|
|
3155
3844
|
SASLAdapter.new(self, &method(:send_command_with_continuations))
|
|
3156
3845
|
end
|