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