net-imap 0.5.1 → 0.5.3

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

Potentially problematic release.


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

data/lib/net/imap.rb CHANGED
@@ -414,7 +414,7 @@ module Net
414
414
  # >>>
415
415
  # <em>The following are folded into +IMAP4rev2+ but are currently
416
416
  # unsupported or incompletely supported by</em> Net::IMAP<em>: RFC4466
417
- # extensions, +ESEARCH+, +SEARCHRES+, +LIST-EXTENDED+, +LIST-STATUS+,
417
+ # extensions, +SEARCHRES+, +LIST-EXTENDED+, +LIST-STATUS+,
418
418
  # +LITERAL-+, and +SPECIAL-USE+.</em>
419
419
  #
420
420
  # ==== RFC2087: +QUOTA+
@@ -466,6 +466,10 @@ module Net
466
466
  # - Updates #append with the +APPENDUID+ ResponseCode
467
467
  # - Updates #copy, #move with the +COPYUID+ ResponseCode
468
468
  #
469
+ # ==== RFC4731: +ESEARCH+
470
+ # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051].
471
+ # - Updates #search, #uid_search with +return+ options and ESearchResult.
472
+ #
469
473
  # ==== RFC4959: +SASL-IR+
470
474
  # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051].
471
475
  # - Updates #authenticate with the option to send an initial response.
@@ -719,7 +723,7 @@ module Net
719
723
  # * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
720
724
  #
721
725
  class IMAP < Protocol
722
- VERSION = "0.5.1"
726
+ VERSION = "0.5.3"
723
727
 
724
728
  # Aliases for supported capabilities, to be used with the #enable command.
725
729
  ENABLE_ALIASES = {
@@ -1123,7 +1127,7 @@ module Net
1123
1127
  #
1124
1128
  # See [ID[https://tools.ietf.org/html/rfc2971]] for field definitions.
1125
1129
  #
1126
- # ===== Capabilities
1130
+ # ==== Capabilities
1127
1131
  #
1128
1132
  # The server's capabilities must include +ID+
1129
1133
  # [RFC2971[https://tools.ietf.org/html/rfc2971]].
@@ -1205,7 +1209,7 @@ module Net
1205
1209
  #
1206
1210
  # Related: Net::IMAP.new, #login, #authenticate
1207
1211
  #
1208
- # ===== Capability
1212
+ # ==== Capability
1209
1213
  # Clients should not call #starttls unless the server advertises the
1210
1214
  # +STARTTLS+ capability.
1211
1215
  #
@@ -1352,7 +1356,7 @@ module Net
1352
1356
  #
1353
1357
  # Related: #authenticate, #starttls
1354
1358
  #
1355
- # ===== Capabilities
1359
+ # ==== Capabilities
1356
1360
  #
1357
1361
  # An IMAP client MUST NOT call #login when the server advertises the
1358
1362
  # +LOGINDISABLED+ capability. By default, Net::IMAP will raise a
@@ -1393,7 +1397,7 @@ module Net
1393
1397
  #
1394
1398
  # Related: #examine
1395
1399
  #
1396
- # ===== Capabilities
1400
+ # ==== Capabilities
1397
1401
  #
1398
1402
  # If [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]] is supported,
1399
1403
  # the server may return an untagged "NO" response with a "UIDNOTSTICKY"
@@ -1511,7 +1515,7 @@ module Net
1511
1515
  #
1512
1516
  # Related: #lsub, MailboxList
1513
1517
  #
1514
- # ===== For example:
1518
+ # ==== For example:
1515
1519
  #
1516
1520
  # imap.create("foo/bar")
1517
1521
  # imap.create("foo/baz")
@@ -1562,7 +1566,7 @@ module Net
1562
1566
  #
1563
1567
  # Related: #list, Namespaces, Namespace
1564
1568
  #
1565
- # ===== For example:
1569
+ # ==== For example:
1566
1570
  #
1567
1571
  # if capable?("NAMESPACE")
1568
1572
  # namespaces = imap.namespace
@@ -1576,7 +1580,7 @@ module Net
1576
1580
  # end
1577
1581
  # end
1578
1582
  #
1579
- # ===== Capabilities
1583
+ # ==== Capabilities
1580
1584
  #
1581
1585
  # The server's capabilities must include +NAMESPACE+
1582
1586
  # [RFC2342[https://tools.ietf.org/html/rfc2342]].
@@ -1615,7 +1619,7 @@ module Net
1615
1619
  #
1616
1620
  # Related: #list, MailboxList
1617
1621
  #
1618
- # ===== Capabilities
1622
+ # ==== Capabilities
1619
1623
  #
1620
1624
  # The server's capabilities must include +XLIST+,
1621
1625
  # a deprecated Gmail extension (replaced by +SPECIAL-USE+).
@@ -1638,7 +1642,7 @@ module Net
1638
1642
  #
1639
1643
  # Related: #getquota, #setquota, MailboxQuotaRoot, MailboxQuota
1640
1644
  #
1641
- # ===== Capabilities
1645
+ # ==== Capabilities
1642
1646
  #
1643
1647
  # The server's capabilities must include +QUOTA+
1644
1648
  # [RFC2087[https://tools.ietf.org/html/rfc2087]].
@@ -1659,7 +1663,7 @@ module Net
1659
1663
  #
1660
1664
  # Related: #getquotaroot, #setquota, MailboxQuota
1661
1665
  #
1662
- # ===== Capabilities
1666
+ # ==== Capabilities
1663
1667
  #
1664
1668
  # The server's capabilities must include +QUOTA+
1665
1669
  # [RFC2087[https://tools.ietf.org/html/rfc2087]].
@@ -1677,7 +1681,7 @@ module Net
1677
1681
  #
1678
1682
  # Related: #getquota, #getquotaroot
1679
1683
  #
1680
- # ===== Capabilities
1684
+ # ==== Capabilities
1681
1685
  #
1682
1686
  # The server's capabilities must include +QUOTA+
1683
1687
  # [RFC2087[https://tools.ietf.org/html/rfc2087]].
@@ -1697,7 +1701,7 @@ module Net
1697
1701
  #
1698
1702
  # Related: #getacl
1699
1703
  #
1700
- # ===== Capabilities
1704
+ # ==== Capabilities
1701
1705
  #
1702
1706
  # The server's capabilities must include +ACL+
1703
1707
  # [RFC4314[https://tools.ietf.org/html/rfc4314]].
@@ -1715,7 +1719,7 @@ module Net
1715
1719
  #
1716
1720
  # Related: #setacl, MailboxACLItem
1717
1721
  #
1718
- # ===== Capabilities
1722
+ # ==== Capabilities
1719
1723
  #
1720
1724
  # The server's capabilities must include +ACL+
1721
1725
  # [RFC4314[https://tools.ietf.org/html/rfc4314]].
@@ -1752,7 +1756,7 @@ module Net
1752
1756
  # for +mailbox+ cannot be returned; for instance, because it
1753
1757
  # does not exist.
1754
1758
  #
1755
- # ===== Supported attributes
1759
+ # ==== Supported attributes
1756
1760
  #
1757
1761
  # +MESSAGES+:: The number of messages in the mailbox.
1758
1762
  #
@@ -1783,12 +1787,12 @@ module Net
1783
1787
  # Unsupported attributes may be requested. The attribute value will be
1784
1788
  # either an Integer or an ExtensionData object.
1785
1789
  #
1786
- # ===== For example:
1790
+ # ==== For example:
1787
1791
  #
1788
1792
  # p imap.status("inbox", ["MESSAGES", "RECENT"])
1789
1793
  # #=> {"RECENT"=>0, "MESSAGES"=>44}
1790
1794
  #
1791
- # ===== Capabilities
1795
+ # ==== Capabilities
1792
1796
  #
1793
1797
  # +SIZE+ requires the server's capabilities to include either +IMAP4rev2+ or
1794
1798
  # <tt>STATUS=SIZE</tt>
@@ -1828,7 +1832,7 @@ module Net
1828
1832
  # not exist (it is not created automatically), or if the flags,
1829
1833
  # date_time, or message arguments contain errors.
1830
1834
  #
1831
- # ===== Capabilities
1835
+ # ==== Capabilities
1832
1836
  #
1833
1837
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
1834
1838
  # supported and the destination supports persistent UIDs, the server's
@@ -1877,7 +1881,7 @@ module Net
1877
1881
  #
1878
1882
  # Related: #close
1879
1883
  #
1880
- # ===== Capabilities
1884
+ # ==== Capabilities
1881
1885
  #
1882
1886
  # The server's capabilities must include +UNSELECT+
1883
1887
  # [RFC3691[https://tools.ietf.org/html/rfc3691]].
@@ -1885,110 +1889,243 @@ module Net
1885
1889
  send_command("UNSELECT")
1886
1890
  end
1887
1891
 
1892
+ # call-seq:
1893
+ # expunge -> array of message sequence numbers
1894
+ # expunge -> VanishedData of UIDs
1895
+ #
1888
1896
  # Sends an {EXPUNGE command [IMAP4rev1 §6.4.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.3]
1889
- # Sends a EXPUNGE command to permanently remove from the currently
1890
- # selected mailbox all messages that have the \Deleted flag set.
1897
+ # to permanently remove all messages with the +\Deleted+ flag from the
1898
+ # currently selected mailbox.
1899
+ #
1900
+ # Returns either an array of expunged message <em>sequence numbers</em> or
1901
+ # (when the appropriate capability is enabled) VanishedData of expunged
1902
+ # UIDs. Previously unhandled +EXPUNGE+ or +VANISHED+ responses are merged
1903
+ # with the direct response to this command. <tt>VANISHED (EARLIER)</tt>
1904
+ # responses will _not_ be merged.
1905
+ #
1906
+ # When no messages have been expunged, an empty array is returned,
1907
+ # regardless of which extensions are enabled. In a future release, an empty
1908
+ # VanishedData may be returned, based on the currently enabled extensions.
1891
1909
  #
1892
1910
  # Related: #uid_expunge
1911
+ #
1912
+ # ==== Capabilities
1913
+ #
1914
+ # When either QRESYNC[https://tools.ietf.org/html/rfc7162] or
1915
+ # UIDONLY[https://tools.ietf.org/html/rfc9586] are enabled, #expunge
1916
+ # returns VanishedData, which contains UIDs---<em>not message sequence
1917
+ # numbers</em>.
1893
1918
  def expunge
1894
- synchronize do
1895
- send_command("EXPUNGE")
1896
- clear_responses("EXPUNGE")
1897
- end
1919
+ expunge_internal("EXPUNGE")
1898
1920
  end
1899
1921
 
1922
+ # call-seq:
1923
+ # uid_expunge{uid_set) -> array of message sequence numbers
1924
+ # uid_expunge{uid_set) -> VanishedData of UIDs
1925
+ #
1900
1926
  # Sends a {UID EXPUNGE command [RFC4315 §2.1]}[https://www.rfc-editor.org/rfc/rfc4315#section-2.1]
1901
1927
  # {[IMAP4rev2 §6.4.9]}[https://www.rfc-editor.org/rfc/rfc9051#section-6.4.9]
1902
1928
  # to permanently remove all messages that have both the <tt>\\Deleted</tt>
1903
1929
  # flag set and a UID that is included in +uid_set+.
1904
1930
  #
1931
+ # Returns the same result type as #expunge.
1932
+ #
1905
1933
  # By using #uid_expunge instead of #expunge when resynchronizing with
1906
1934
  # the server, the client can ensure that it does not inadvertantly
1907
1935
  # remove any messages that have been marked as <tt>\\Deleted</tt> by other
1908
1936
  # clients between the time that the client was last connected and
1909
1937
  # the time the client resynchronizes.
1910
1938
  #
1911
- # *Note:*
1912
- # >>>
1913
- # Although the command takes a set of UIDs for its argument, the
1914
- # server still returns regular EXPUNGE responses, which contain
1915
- # a <em>sequence number</em>. These will be deleted from
1916
- # #responses and this method returns them as an array of
1917
- # <em>sequence number</em> integers.
1918
- #
1919
1939
  # Related: #expunge
1920
1940
  #
1921
- # ===== Capabilities
1941
+ # ==== Capabilities
1922
1942
  #
1923
- # The server's capabilities must include +UIDPLUS+
1943
+ # The server's capabilities must include either +IMAP4rev2+ or +UIDPLUS+
1924
1944
  # [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]].
1945
+ #
1946
+ # Otherwise, #uid_expunge is updated by extensions in the same way as
1947
+ # #expunge.
1925
1948
  def uid_expunge(uid_set)
1926
- synchronize do
1927
- send_command("UID EXPUNGE", SequenceSet.new(uid_set))
1928
- clear_responses("EXPUNGE")
1929
- end
1949
+ expunge_internal("UID EXPUNGE", SequenceSet.new(uid_set))
1930
1950
  end
1931
1951
 
1932
1952
  # :call-seq:
1933
1953
  # search(criteria, charset = nil) -> result
1954
+ # search(criteria, charset: nil, return: nil) -> result
1934
1955
  #
1935
1956
  # Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
1936
1957
  # to search the mailbox for messages that match the given search +criteria+,
1937
- # and returns a SearchResult. SearchResult inherits from Array (for
1938
- # backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
1939
- # capability has been enabled.
1958
+ # and returns either a SearchResult or an ESearchResult. SearchResult
1959
+ # inherits from Array (for backward compatibility) but adds
1960
+ # SearchResult#modseq when the +CONDSTORE+ capability has been enabled.
1961
+ # ESearchResult also implements {#to_a}[rdoc-ref:ESearchResult#to_a], for
1962
+ # compatibility with SearchResult.
1940
1963
  #
1941
1964
  # +criteria+ is one or more search keys and their arguments, which may be
1942
1965
  # provided as an array or a string.
1943
- # See {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
1944
- #
1945
- # * When +criteria+ is an array, each member is a +SEARCH+ command argument:
1946
- # * Any SequenceSet sends SequenceSet#valid_string.
1947
- # These types are converted to SequenceSet for validation and encoding:
1948
- # * +Set+
1949
- # * +Range+
1950
- # * <tt>-1</tt> and +:*+ -- both translate to <tt>*</tt>
1951
- # * responds to +#to_sequence_set+
1952
- # * +Array+, when each element is one of the above types, a positive
1953
- # +Integer+, a sequence-set formatted +String+, or a deeply nested
1954
- # +Array+ of these same types.
1955
- # * Any +String+ is sent verbatim when it is a valid \IMAP atom,
1956
- # and encoded as an \IMAP quoted or literal string otherwise.
1957
- # * Any other nested +Array+ is encoded as a parenthesized list, to group
1958
- # multiple search keys (e.g., for use with +OR+ and +NOT+).
1959
- # * Any other +Integer+ (besides <tt>-1</tt>) will be sent as +#to_s+.
1960
- # * +Date+ objects will be encoded as an \IMAP date (see ::encode_date).
1961
- #
1962
- # * When +criteria+ is a string, it will be sent directly to the server
1963
- # <em>without any validation or encoding</em>. *WARNING:* This is
1964
- # vulnerable to injection attacks when external inputs are used.
1966
+ # See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
1967
+ # and {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
1968
+ #
1969
+ # +return+ options control what kind of information is returned about
1970
+ # messages matching the search +criteria+. Specifying +return+ should force
1971
+ # the server to return an ESearchResult instead of a SearchResult, but some
1972
+ # servers disobey this requirement. <em>Requires an extended search
1973
+ # capability, such as +ESEARCH+ or +IMAP4rev2+.</em>
1974
+ # See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
1975
+ # and {"Return options"}[rdoc-ref:#search@Return+options], below.
1965
1976
  #
1966
1977
  # +charset+ is the name of the {registered character
1967
1978
  # set}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
1968
1979
  # used by strings in the search +criteria+. When +charset+ isn't specified,
1969
1980
  # either <tt>"US-ASCII"</tt> or <tt>"UTF-8"</tt> is assumed, depending on
1970
- # the server's capabilities. +charset+ may be sent inside +criteria+
1971
- # instead of as a separate argument.
1981
+ # the server's capabilities.
1982
+ #
1983
+ # _NOTE:_ Return options and charset may be sent as part of +criteria+. Do
1984
+ # not use the +return+ or +charset+ arguments when either return options or
1985
+ # charset are embedded in +criteria+.
1972
1986
  #
1973
1987
  # Related: #uid_search
1974
1988
  #
1975
- # ===== For example:
1989
+ # ==== For example:
1976
1990
  #
1977
- # p imap.search(["SUBJECT", "hello", "NOT", "SEEN"])
1991
+ # imap.search(["SUBJECT", "hello", "NOT", "SEEN"])
1978
1992
  # #=> [1, 6, 7, 8]
1979
1993
  #
1980
- # The following searches send the exact same command to the server:
1981
- #
1982
- # # criteria array, charset arg
1983
- # imap.search(["OR", "UNSEEN", %w(FLAGGED SUBJECT foo)], "UTF-8")
1984
- # # criteria string, charset arg
1985
- # imap.search("OR UNSEEN (FLAGGED SUBJECT foo)", "UTF-8")
1986
- # # criteria array contains charset arg
1987
- # imap.search([*%w[CHARSET UTF-8], "OR", "UNSEEN", %w(FLAGGED SUBJECT foo)])
1988
- # # criteria string contains charset arg
1989
- # imap.search("CHARSET UTF-8 OR UNSEEN (FLAGGED SUBJECT foo)")
1990
- #
1991
- # ===== Search keys
1994
+ # The following assumes the server supports +ESEARCH+ and +CONDSTORE+:
1995
+ #
1996
+ # result = imap.uid_search(["UID", 12345.., "MODSEQ", 620_162_338],
1997
+ # return: %w(all count min max))
1998
+ # # => #<data Net::IMAP::ESearchResult tag="RUBY0123", uid=true,
1999
+ # # data=[["ALL", Net::IMAP::SequenceSet["12346:12349,22222:22230"]],
2000
+ # # ["COUNT", 13], ["MIN", 12346], ["MAX", 22230],
2001
+ # # ["MODSEQ", 917162488]]>
2002
+ # result.to_a # => [12346, 12347, 12348, 12349, 22222, 22223, 22224,
2003
+ # # 22225, 22226, 22227, 22228, 22229, 22230]
2004
+ # result.uid? # => true
2005
+ # result.count # => 13
2006
+ # result.min # => 12346
2007
+ # result.max # => 22230
2008
+ # result.modseq # => 917162488
2009
+ #
2010
+ # Using +return+ options to limit the result to only min, max, and count:
2011
+ #
2012
+ # result = imap.uid_search(["UID", 12345..,], return: %w(count min max))
2013
+ # # => #<data Net::IMAP::ESearchResult tag="RUBY0124", uid=true,
2014
+ # # data=[["COUNT", 13], ["MIN", 12346], ["MAX", 22230]]>
2015
+ # result.to_a # => []
2016
+ # result.count # => 13
2017
+ # result.min # => 12346
2018
+ # result.max # => 22230
2019
+ #
2020
+ # Return options and charset may be sent as keyword args or embedded in the
2021
+ # +criteria+ arg, but they must be in the correct order: <tt>"RETURN (...)
2022
+ # CHARSET ... criteria..."</tt>. The following searches
2023
+ # send the exact same command to the server:
2024
+ #
2025
+ # # Return options and charset as keyword arguments (preferred)
2026
+ # imap.search(%w(OR UNSEEN FLAGGED), return: %w(MIN MAX), charset: "UTF-8")
2027
+ # # Embedding return and charset in the criteria array
2028
+ # imap.search(["RETURN", %w(MIN MAX), "CHARSET", "UTF-8", *%w(OR UNSEEN FLAGGED)])
2029
+ # # Embedding return and charset in the criteria string
2030
+ # imap.search("RETURN (MIN MAX) CHARSET UTF-8 OR UNSEEN FLAGGED")
2031
+ #
2032
+ # Sending charset as the second positional argument is supported for
2033
+ # backward compatibility. Future versions may print a deprecation warning:
2034
+ # imap.search(%w(OR UNSEEN FLAGGED), "UTF-8", return: %w(MIN MAX))
2035
+ #
2036
+ # ==== Argument translation
2037
+ #
2038
+ # [+return+ options]
2039
+ # Must be an Array. Return option names may be either strings or symbols.
2040
+ # +Range+ elements which begin and end with negative integers are encoded
2041
+ # for use with +PARTIAL+--any other ranges are converted to SequenceSet.
2042
+ # Unlike +criteria+, other return option arguments are not automatically
2043
+ # converted to SequenceSet.
2044
+ #
2045
+ # [When +criteria+ is an Array]
2046
+ # When the array begins with <tt>"RETURN"</tt> (case insensitive), the
2047
+ # second array element is translated like the +return+ parameter (as
2048
+ # described above).
2049
+ #
2050
+ # Every other member is a +SEARCH+ command argument:
2051
+ # [SequenceSet]
2052
+ # Encoded as an \IMAP +sequence-set+ with SequenceSet#valid_string.
2053
+ # [Set, Range, <tt>-1</tt>, +:*+, responds to +#to_sequence_set+]
2054
+ # Converted to SequenceSet for validation and encoding.
2055
+ # [nested sequence-set +Array+]
2056
+ # When every element in a nested array is one of the above types, a
2057
+ # positive +Integer+, a sequence-set formatted +String+, or a deeply
2058
+ # nested +Array+ of these same types, the array will be converted to
2059
+ # SequenceSet for validation and encoding.
2060
+ # [Any other nested +Array+]
2061
+ # Otherwise, a nested array is encoded as a parenthesized list, to
2062
+ # combine multiple search keys (e.g., for use with +OR+ and +NOT+).
2063
+ # [+String+]
2064
+ # Sent verbatim when it is a valid \IMAP +atom+, and encoded as an \IMAP
2065
+ # +quoted+ or +literal+ string otherwise. Every standard search key
2066
+ # name is a valid \IMAP +atom+ and every standard search key string
2067
+ # argument is an +astring+ which may be encoded as +atom+, +quoted+, or
2068
+ # +literal+.
2069
+ #
2070
+ # *Note:* <tt>*</tt> is not a valid \IMAP +atom+ character. Any string
2071
+ # containing <tt>*</tt> will be encoded as a +quoted+ string, _not_ a
2072
+ # +sequence-set+.
2073
+ # [+Integer+ (except for <tt>-1</tt>)]
2074
+ # Encoded using +#to_s+.
2075
+ # [+Date+]
2076
+ # Encoded as an \IMAP date (see ::encode_date).
2077
+ #
2078
+ # [When +criteria+ is a String]
2079
+ # +criteria+ will be sent directly to the server <em>without any
2080
+ # validation or encoding</em>.
2081
+ #
2082
+ # <em>*WARNING:* This is vulnerable to injection attacks when external
2083
+ # inputs are used.</em>
2084
+ #
2085
+ # ==== Return options
2086
+ #
2087
+ # For full definitions of the standard return options and return data, see
2088
+ # the relevant RFCs.
2089
+ #
2090
+ # ===== +ESEARCH+ or +IMAP4rev2+
2091
+ #
2092
+ # The following return options require either +ESEARCH+ or +IMAP4rev2+.
2093
+ # See [{RFC4731 §3.1}[https://rfc-editor.org/rfc/rfc4731#section-3.1]] or
2094
+ # [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]].
2095
+ #
2096
+ # [+ALL+]
2097
+ # Returns ESearchResult#all with a SequenceSet of all matching sequence
2098
+ # numbers or UIDs. This is the default, when return options are empty.
2099
+ #
2100
+ # For compatibility with SearchResult, ESearchResult#to_a returns an
2101
+ # Array of message sequence numbers or UIDs.
2102
+ # [+COUNT+]
2103
+ # Returns ESearchResult#count with the number of matching messages.
2104
+ # [+MAX+]
2105
+ # Returns ESearchResult#max with the highest matching sequence number or
2106
+ # UID.
2107
+ # [+MIN+]
2108
+ # Returns ESearchResult#min with the lowest matching sequence number or
2109
+ # UID.
2110
+ #
2111
+ # ===== +CONDSTORE+
2112
+ #
2113
+ # ESearchResult#modseq return data does not have a corresponding return
2114
+ # option. Instead, it is returned if the +MODSEQ+ search key is used or
2115
+ # when the +CONDSTORE+ extension is enabled for the selected mailbox.
2116
+ # See [{RFC4731 §3.2}[https://www.rfc-editor.org/rfc/rfc4731#section-3.2]]
2117
+ # or [{RFC7162 §2.1.5}[https://www.rfc-editor.org/rfc/rfc7162#section-3.1.5]].
2118
+ #
2119
+ # ===== +RFC4466+ compatible extensions
2120
+ #
2121
+ # {RFC4466 §2.6}[https://www.rfc-editor.org/rfc/rfc4466.html#section-2.6]
2122
+ # defines standard syntax for search extensions. Net::IMAP allows sending
2123
+ # unknown search return options and will parse unknown search extensions'
2124
+ # return values into ExtensionData. Please note that this is an
2125
+ # intentionally _unstable_ API. Future releases may return different
2126
+ # (incompatible) objects, <em>without deprecation or warning</em>.
2127
+ #
2128
+ # ==== Search keys
1992
2129
  #
1993
2130
  # For full definitions of the standard search +criteria+,
1994
2131
  # see [{IMAP4rev1 §6.4.4}[https://www.rfc-editor.org/rfc/rfc3501.html#section-6.4.4]],
@@ -2003,23 +2140,21 @@ module Net
2003
2140
  # arguments. The number and type of arguments is specific to each search
2004
2141
  # key.
2005
2142
  #
2006
- # +ALL+::
2007
- # Matches every message in the mailbox.
2143
+ # ===== Search keys that match all messages
2008
2144
  #
2009
- # (_search-key_ _search-key_...)::
2010
- # Combines one or more _search-key_ arguments to match
2011
- # messages which match all contained search keys. Useful for +OR+, +NOT+,
2012
- # and other search keys with _search-key_ arguments.
2145
+ # [+ALL+]
2146
+ # The default initial key. Matches every message in the mailbox.
2013
2147
  #
2014
- # _Note:_ this search key has no label.
2148
+ # [+SAVEDATESUPPORTED+]
2149
+ # Matches every message in the mailbox when the mailbox supports the save
2150
+ # date attribute. Otherwise, it matches no messages.
2015
2151
  #
2016
- # +OR+ _search-key_ _search-key_::
2017
- # Matches messages which match either _search-key_ argument.
2152
+ # <em>Requires +SAVEDATE+ capability</em>.
2153
+ # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
2018
2154
  #
2019
- # +NOT+ _search-key_::
2020
- # Matches messages which do not match _search-key_.
2155
+ # ===== Sequence set search keys
2021
2156
  #
2022
- # _sequence-set_::
2157
+ # [_sequence-set_]
2023
2158
  # Matches messages with message sequence numbers in _sequence-set_.
2024
2159
  #
2025
2160
  # _Note:_ this search key has no label.
@@ -2027,121 +2162,139 @@ module Net
2027
2162
  # <em>+UIDONLY+ must *not* be enabled.</em>
2028
2163
  # {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.html]
2029
2164
  #
2030
- # +UID+ _sequence-set_::
2165
+ # [+UID+ _sequence-set_]
2031
2166
  # Matches messages with a UID in _sequence-set_.
2032
2167
  #
2033
- # +ANSWERED+::
2034
- # +UNANSWERED+::
2168
+ # ===== Compound search keys
2169
+ #
2170
+ # [(_search-key_ _search-key_...)]
2171
+ # Combines one or more _search-key_ arguments to match
2172
+ # messages which match all contained search keys. Useful for +OR+, +NOT+,
2173
+ # and other search keys with _search-key_ arguments.
2174
+ #
2175
+ # _Note:_ this search key has no label.
2176
+ #
2177
+ # [+OR+ _search-key_ _search-key_]
2178
+ # Matches messages which match either _search-key_ argument.
2179
+ #
2180
+ # [+NOT+ _search-key_]
2181
+ # Matches messages which do not match _search-key_.
2182
+ #
2183
+ # [+FUZZY+ _search-key_]
2184
+ # Uses fuzzy matching for the specified search key.
2185
+ #
2186
+ # <em>Requires <tt>SEARCH=FUZZY</tt> capability.</em>
2187
+ # {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
2188
+ #
2189
+ # ===== Flags search keys
2190
+ #
2191
+ # [+ANSWERED+, +UNANSWERED+]
2035
2192
  # Matches messages with or without the <tt>\\Answered</tt> flag.
2036
- # +DELETED+::
2037
- # +UNDELETED+::
2193
+ # [+DELETED+, +UNDELETED+]
2038
2194
  # Matches messages with or without the <tt>\\Deleted</tt> flag.
2039
- # +DRAFT+::
2040
- # +UNDRAFT+::
2195
+ # [+DRAFT+, +UNDRAFT+]
2041
2196
  # Matches messages with or without the <tt>\\Draft</tt> flag.
2042
- # +FLAGGED+::
2043
- # +UNFLAGGED+::
2197
+ # [+FLAGGED+, +UNFLAGGED+]
2044
2198
  # Matches messages with or without the <tt>\\Flagged</tt> flag.
2045
- # +SEEN+::
2046
- # +UNSEEN+::
2199
+ # [+SEEN+, +UNSEEN+]
2047
2200
  # Matches messages with or without the <tt>\\Seen</tt> flag.
2048
- #
2049
- # +KEYWORD+ _keyword_::
2050
- # +UNKEYWORD+ _keyword_::
2201
+ # [+KEYWORD+ _keyword_, +UNKEYWORD+ _keyword_]
2051
2202
  # Matches messages with or without the specified _keyword_.
2052
2203
  #
2053
- # +BCC+ _substring_::
2054
- # Matches when _substring_ is in the envelope's BCC field.
2055
- # +CC+ _substring_::
2056
- # Matches when _substring_ is in the envelope's CC field.
2057
- # +FROM+ _substring_::
2058
- # Matches when _substring_ is in the envelope's FROM field.
2059
- # +SUBJECT+ _substring_::
2060
- # Matches when _substring_ is in the envelope's SUBJECT field.
2061
- # +TO+ _substring_::
2062
- # Matches when _substring_ is in the envelope's TO field.
2063
- #
2064
- # +HEADER+ _field_ _substring_::
2204
+ # [+RECENT+, +UNRECENT+]
2205
+ # Matches messages with or without the <tt>\\Recent</tt> flag.
2206
+ #
2207
+ # *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
2208
+ # [+NEW+]
2209
+ # Equivalent to <tt>(RECENT UNSEEN)</tt>.
2210
+ #
2211
+ # *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
2212
+ #
2213
+ # ===== Header field substring search keys
2214
+ #
2215
+ # [+BCC+ _substring_]
2216
+ # Matches when _substring_ is in the envelope's +BCC+ field.
2217
+ # [+CC+ _substring_]
2218
+ # Matches when _substring_ is in the envelope's +CC+ field.
2219
+ # [+FROM+ _substring_]
2220
+ # Matches when _substring_ is in the envelope's +FROM+ field.
2221
+ # [+SUBJECT+ _substring_]
2222
+ # Matches when _substring_ is in the envelope's +SUBJECT+ field.
2223
+ # [+TO+ _substring_]
2224
+ # Matches when _substring_ is in the envelope's +TO+ field.
2225
+ #
2226
+ # [+HEADER+ _field_ _substring_]
2065
2227
  # Matches when _substring_ is in the specified header _field_.
2066
2228
  #
2067
- # +BODY+ _string_::
2229
+ # ===== Body text search keys
2230
+ # [+BODY+ _string_]
2068
2231
  # Matches when _string_ is in the body of the message.
2069
2232
  # Does not match on header fields.
2070
2233
  #
2071
2234
  # The server _may_ use flexible matching, rather than simple substring
2072
2235
  # matches. For example, this may use stemming or match only full words.
2073
2236
  #
2074
- # +TEXT+ _string_::
2237
+ # [+TEXT+ _string_]
2075
2238
  # Matches when _string_ is in the header or body of the message.
2076
2239
  #
2077
2240
  # The server _may_ use flexible matching, rather than simple substring
2078
2241
  # matches. For example, this may use stemming or match only full words.
2079
2242
  #
2080
- # +BEFORE+ _date_::
2081
- # +ON+ _date_::
2082
- # +SINCE+ _date_::
2083
- # Matches when the +INTERNALDATE+ is earlier than, on, or later than
2084
- # _date_.
2243
+ # ===== Date/Time search keys
2085
2244
  #
2086
- # +SENTBEFORE+ _date_::
2087
- # +SENTON+ _date_::
2088
- # +SENTSINCE+ _date_::
2245
+ # [+SENTBEFORE+ _date_]
2246
+ # [+SENTON+ _date_]
2247
+ # [+SENTSINCE+ _date_]
2089
2248
  # Matches when the +Date+ header is earlier than, on, or later than _date_.
2090
2249
  #
2091
- # +SMALLER+ _bytes_::
2092
- # +LARGER+ _bytes_::
2093
- # Matches when +RFC822.SIZE+ is smaller/larger than _bytes_.
2094
- #
2095
- # ====== Removed from +IMAP4rev2+
2096
- #
2097
- # The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+. So these
2098
- # search keys require the +IMAP4rev1+ capability.
2250
+ # [+BEFORE+ _date_]
2251
+ # [+ON+ _date_]
2252
+ # [+SINCE+ _date_]
2253
+ # Matches when the +INTERNALDATE+ is earlier than, on, or later than
2254
+ # _date_.
2099
2255
  #
2100
- # +RECENT+::
2101
- # +UNRECENT+::
2102
- # Matches messages with or without the <tt>\\Recent</tt> flag.
2256
+ # [+OLDER+ _interval_]
2257
+ # [+YOUNGER+ _interval_]
2258
+ # Matches when the +INTERNALDATE+ is more/less than _interval_ seconds ago.
2103
2259
  #
2104
- # +NEW+::
2105
- # Equivalent to <tt>(RECENT UNSEEN)</tt>.
2260
+ # <em>Requires +WITHIN+ capability</em>.
2261
+ # {[RFC5032]}[https://www.rfc-editor.org/rfc/rfc5032.html]
2106
2262
  #
2107
- # ====== Extension search keys
2263
+ # [+SAVEDBEFORE+ _date_]
2264
+ # [+SAVEDON+ _date_]
2265
+ # [+SAVEDSINCE+ _date_]
2266
+ # Matches when the save date is earlier than, on, or later than _date_.
2108
2267
  #
2109
- # The search keys described below are defined by standard \IMAP extensions.
2268
+ # <em>Requires +SAVEDATE+ capability.</em>
2269
+ # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
2110
2270
  #
2111
- # +OLDER+ _interval_::
2112
- # +YOUNGER+ _interval_::
2113
- # Matches when +INTERNALDATE+ is more/less than _interval_ seconds ago.
2271
+ # ===== Other message attribute search keys
2114
2272
  #
2115
- # <em>Requires the +WITHIN+ capability</em>.
2116
- # {[RFC5032]}[https://www.rfc-editor.org/rfc/rfc5032.html]
2273
+ # [+SMALLER+ _bytes_]
2274
+ # [+LARGER+ _bytes_]
2275
+ # Matches when +RFC822.SIZE+ is smaller or larger than _bytes_.
2117
2276
  #
2118
- # +ANNOTATION+ _entry_ _attr_ _value_::
2277
+ # [+ANNOTATION+ _entry_ _attr_ _value_]
2119
2278
  # Matches messages that have annotations with entries matching _entry_,
2120
2279
  # attributes matching _attr_, and _value_ in the attribute's values.
2121
2280
  #
2122
- # <em>Requires the +ANNOTATE-EXPERIMENT-1+ capability</em>.
2281
+ # <em>Requires +ANNOTATE-EXPERIMENT-1+ capability</em>.
2123
2282
  # {[RFC5257]}[https://www.rfc-editor.org/rfc/rfc5257.html].
2124
2283
  #
2125
- # +FILTER+ _filter_::
2284
+ # [+FILTER+ _filter_]
2126
2285
  # References a _filter_ that is stored on the server and matches all
2127
2286
  # messages which would be matched by that filter's search criteria.
2128
2287
  #
2129
- # <em>Requires the +FILTERS+ capability</em>.
2288
+ # <em>Requires +FILTERS+ capability</em>.
2130
2289
  # {[RFC5466]}[https://www.rfc-editor.org/rfc/rfc5466.html#section-3.1]
2131
2290
  #
2132
- # +FUZZY+ _search-key_::
2133
- # Uses fuzzy matching for the specified search key.
2134
- #
2135
- # <em>Requires the <tt>SEARCH=FUZZY</tt> capability.</em>
2136
- # {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
2137
- #
2138
- # +MODSEQ+ _modseq_::
2291
+ # [+MODSEQ+ _modseq_]
2139
2292
  # Matches when +MODSEQ+ is greater than or equal to _modseq_.
2140
2293
  #
2141
- # <em>Requires the +CONDSTORE+ capability</em>.
2294
+ # <em>Requires +CONDSTORE+ capability</em>.
2142
2295
  # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
2143
2296
  #
2144
- # +MODSEQ+ _entry_ _entry-type_ _modseq_::
2297
+ # [+MODSEQ+ _entry_ _entry-type_ _modseq_]
2145
2298
  # Matches when a specific metadata _entry_ has been updated since
2146
2299
  # _modseq_.
2147
2300
  #
@@ -2150,33 +2303,25 @@ module Net
2150
2303
  # <tt>\\</tt> prefix. _entry-type_ can be one of <tt>"shared"</tt>,
2151
2304
  # <tt>"priv"</tt> (private), or <tt>"all"</tt>.
2152
2305
  #
2153
- # <em>Requires the +CONDSTORE+ capability</em>.
2306
+ # <em>Requires +CONDSTORE+ capability</em>.
2154
2307
  # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
2155
2308
  #
2156
- # +EMAILID+ _objectid_::
2157
- # +THREADID+ _objectid_::
2309
+ # [+EMAILID+ _objectid_]
2310
+ # [+THREADID+ _objectid_]
2158
2311
  # Matches when +EMAILID+/+THREADID+ is equal to _objectid_
2159
2312
  # (substring matches are not supported).
2160
2313
  #
2161
- # <em>Requires the +OBJECTID+ capability</em>.
2314
+ # <em>Requires +OBJECTID+ capability</em>.
2162
2315
  # {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-6]
2163
2316
  #
2164
- # +SAVEDATESUPPORTED+::
2165
- # Matches every message in the mailbox when the mailbox supports the save
2166
- # date attribute. Otherwise, it matches no messages.
2167
- #
2168
- # <em>Requires the +SAVEDATE+ capability</em>.
2169
- # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
2170
- #
2171
- # +SAVEDBEFORE+ _date_::
2172
- # +SAVEDON+ _date_::
2173
- # +SAVEDSINCE+ _date_::
2174
- # Matches when the save date is earlier than, on, or later than _date_.
2317
+ # ==== Capabilities
2175
2318
  #
2176
- # <em>Requires the +SAVEDATE+ capability.</em>
2177
- # {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
2319
+ # Return options should only be specified when the server supports
2320
+ # +IMAP4rev2+ or an extension that allows them, such as +ESEARCH+
2321
+ # [RFC4731[https://rfc-editor.org/rfc/rfc4731#section-3.1]].
2178
2322
  #
2179
- # ===== Capabilities
2323
+ # When +IMAP4rev2+ is enabled, or when the server supports +IMAP4rev2+ but
2324
+ # not +IMAP4rev1+, ESearchResult is always returned instead of SearchResult.
2180
2325
  #
2181
2326
  # If CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html] is supported
2182
2327
  # and enabled for the selected mailbox, a non-empty SearchResult will
@@ -2191,6 +2336,7 @@ module Net
2191
2336
 
2192
2337
  # :call-seq:
2193
2338
  # uid_search(criteria, charset = nil) -> result
2339
+ # uid_search(criteria, charset: nil, return: nil) -> result
2194
2340
  #
2195
2341
  # Sends a {UID SEARCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2196
2342
  # to search the mailbox for messages that match the given searching
@@ -2230,7 +2376,7 @@ module Net
2230
2376
  #
2231
2377
  # Related: #uid_search, FetchData
2232
2378
  #
2233
- # ===== For example:
2379
+ # ==== For example:
2234
2380
  #
2235
2381
  # p imap.fetch(6..8, "UID")
2236
2382
  # #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
@@ -2248,7 +2394,7 @@ module Net
2248
2394
  # p data.attr["UID"]
2249
2395
  # #=> 98
2250
2396
  #
2251
- # ===== Capabilities
2397
+ # ==== Capabilities
2252
2398
  #
2253
2399
  # Many extensions define new message +attr+ names. See FetchData for a list
2254
2400
  # of supported extension fields.
@@ -2277,7 +2423,7 @@ module Net
2277
2423
  #
2278
2424
  # Related: #fetch, FetchData
2279
2425
  #
2280
- # ===== Capabilities
2426
+ # ==== Capabilities
2281
2427
  # Same as #fetch.
2282
2428
  def uid_fetch(set, attr, mod = nil, changedsince: nil)
2283
2429
  fetch_internal("UID FETCH", set, attr, mod, changedsince: changedsince)
@@ -2311,14 +2457,14 @@ module Net
2311
2457
  #
2312
2458
  # Related: #uid_store
2313
2459
  #
2314
- # ===== For example:
2460
+ # ==== For example:
2315
2461
  #
2316
2462
  # p imap.store(6..8, "+FLAGS", [:Deleted])
2317
2463
  # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2318
2464
  # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2319
2465
  # #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
2320
2466
  #
2321
- # ===== Capabilities
2467
+ # ==== Capabilities
2322
2468
  #
2323
2469
  # Extensions may define new data items to be used with #store.
2324
2470
  #
@@ -2342,7 +2488,7 @@ module Net
2342
2488
  #
2343
2489
  # Related: #store
2344
2490
  #
2345
- # ===== Capabilities
2491
+ # ==== Capabilities
2346
2492
  # Same as #store.
2347
2493
  def uid_store(set, attr, flags, unchangedsince: nil)
2348
2494
  store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince)
@@ -2355,7 +2501,7 @@ module Net
2355
2501
  #
2356
2502
  # Related: #uid_copy
2357
2503
  #
2358
- # ===== Capabilities
2504
+ # ==== Capabilities
2359
2505
  #
2360
2506
  # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
2361
2507
  # supported, the server's response should include a +COPYUID+ response code
@@ -2372,7 +2518,7 @@ module Net
2372
2518
  #
2373
2519
  # Similar to #copy, but +set+ contains unique identifiers.
2374
2520
  #
2375
- # ===== Capabilities
2521
+ # ==== Capabilities
2376
2522
  #
2377
2523
  # +UIDPLUS+ affects #uid_copy the same way it affects #copy.
2378
2524
  def uid_copy(set, mailbox)
@@ -2387,7 +2533,7 @@ module Net
2387
2533
  #
2388
2534
  # Related: #uid_move
2389
2535
  #
2390
- # ===== Capabilities
2536
+ # ==== Capabilities
2391
2537
  #
2392
2538
  # The server's capabilities must include +MOVE+
2393
2539
  # [RFC6851[https://tools.ietf.org/html/rfc6851]].
@@ -2411,7 +2557,7 @@ module Net
2411
2557
  #
2412
2558
  # Related: #move
2413
2559
  #
2414
- # ===== Capabilities
2560
+ # ==== Capabilities
2415
2561
  #
2416
2562
  # Same as #move: The server's capabilities must include +MOVE+
2417
2563
  # [RFC6851[https://tools.ietf.org/html/rfc6851]]. +UIDPLUS+ also affects
@@ -2431,14 +2577,14 @@ module Net
2431
2577
  #
2432
2578
  # Related: #uid_sort, #search, #uid_search, #thread, #uid_thread
2433
2579
  #
2434
- # ===== For example:
2580
+ # ==== For example:
2435
2581
  #
2436
2582
  # p imap.sort(["FROM"], ["ALL"], "US-ASCII")
2437
2583
  # #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
2438
2584
  # p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
2439
2585
  # #=> [6, 7, 8, 1]
2440
2586
  #
2441
- # ===== Capabilities
2587
+ # ==== Capabilities
2442
2588
  #
2443
2589
  # The server's capabilities must include +SORT+
2444
2590
  # [RFC5256[https://tools.ietf.org/html/rfc5256]].
@@ -2453,7 +2599,7 @@ module Net
2453
2599
  #
2454
2600
  # Related: #sort, #search, #uid_search, #thread, #uid_thread
2455
2601
  #
2456
- # ===== Capabilities
2602
+ # ==== Capabilities
2457
2603
  #
2458
2604
  # The server's capabilities must include +SORT+
2459
2605
  # [RFC5256[https://tools.ietf.org/html/rfc5256]].
@@ -2478,7 +2624,7 @@ module Net
2478
2624
  #
2479
2625
  # Related: #uid_thread, #search, #uid_search, #sort, #uid_sort
2480
2626
  #
2481
- # ===== Capabilities
2627
+ # ==== Capabilities
2482
2628
  #
2483
2629
  # The server's capabilities must include +THREAD+
2484
2630
  # [RFC5256[https://tools.ietf.org/html/rfc5256]].
@@ -2492,7 +2638,7 @@ module Net
2492
2638
  #
2493
2639
  # Related: #thread, #search, #uid_search, #sort, #uid_sort
2494
2640
  #
2495
- # ===== Capabilities
2641
+ # ==== Capabilities
2496
2642
  #
2497
2643
  # The server's capabilities must include +THREAD+
2498
2644
  # [RFC5256[https://tools.ietf.org/html/rfc5256]].
@@ -2511,7 +2657,7 @@ module Net
2511
2657
  #
2512
2658
  # Related: #capable?, #capabilities, #capability
2513
2659
  #
2514
- # ===== Capabilities
2660
+ # ==== Capabilities
2515
2661
  #
2516
2662
  # The server's capabilities must include
2517
2663
  # +ENABLE+ [RFC5161[https://tools.ietf.org/html/rfc5161]]
@@ -2613,7 +2759,7 @@ module Net
2613
2759
  #
2614
2760
  # Related: #idle_done, #noop, #check
2615
2761
  #
2616
- # ===== Capabilities
2762
+ # ==== Capabilities
2617
2763
  #
2618
2764
  # The server's capabilities must include +IDLE+
2619
2765
  # [RFC2177[https://tools.ietf.org/html/rfc2177]].
@@ -2730,7 +2876,7 @@ module Net
2730
2876
  #
2731
2877
  # Related: #extract_responses, #clear_responses, #response_handlers, #greeting
2732
2878
  #
2733
- # ===== Thread safety
2879
+ # ==== Thread safety
2734
2880
  # >>>
2735
2881
  # *Note:* Access to the responses hash is synchronized for thread-safety.
2736
2882
  # The receiver thread and response_handlers cannot process new responses
@@ -2744,7 +2890,7 @@ module Net
2744
2890
  # thread, but will not modify any responses after adding them to the
2745
2891
  # responses hash.
2746
2892
  #
2747
- # ===== Clearing responses
2893
+ # ==== Clearing responses
2748
2894
  #
2749
2895
  # Previously unhandled responses are automatically cleared before entering a
2750
2896
  # mailbox with #select or #examine. Long-lived connections can receive many
@@ -2753,7 +2899,7 @@ module Net
2753
2899
  # the block, or remove responses with #extract_responses, #clear_responses,
2754
2900
  # or #add_response_handler.
2755
2901
  #
2756
- # ===== Missing responses
2902
+ # ==== Missing responses
2757
2903
  #
2758
2904
  # Only non-+nil+ data is stored. Many important response codes have no data
2759
2905
  # of their own, but are used as "tags" on the ResponseText object they are
@@ -3131,12 +3277,108 @@ module Net
3131
3277
  end
3132
3278
  end
3133
3279
 
3134
- def search_internal(cmd, keys, charset = nil)
3135
- keys = normalize_searching_criteria(keys)
3136
- args = charset ? ["CHARSET", charset, *keys] : keys
3280
+ def expunge_internal(...)
3137
3281
  synchronize do
3138
- send_command(cmd, *args)
3139
- clear_responses("SEARCH").last || []
3282
+ send_command(...)
3283
+ expunged_array = clear_responses("EXPUNGE")
3284
+ vanished_array = extract_responses("VANISHED") { !_1.earlier? }
3285
+ if vanished_array.empty?
3286
+ expunged_array
3287
+ elsif vanished_array.length == 1
3288
+ vanished_array.first
3289
+ else
3290
+ merged_uids = SequenceSet[*vanished_array.map(&:uids)]
3291
+ VanishedData[uids: merged_uids, earlier: false]
3292
+ end
3293
+ end
3294
+ end
3295
+
3296
+ RETURN_WHOLE = /\ARETURN\z/i
3297
+ RETURN_START = /\ARETURN\b/i
3298
+ private_constant :RETURN_WHOLE, :RETURN_START
3299
+
3300
+ def search_args(keys, charset_arg = nil, return: nil, charset: nil)
3301
+ {return:} => {return: return_kw}
3302
+ case [return_kw, keys]
3303
+ in [nil, Array[RETURN_WHOLE, return_opts, *keys]]
3304
+ return_opts = convert_return_opts(return_opts)
3305
+ esearch = true
3306
+ in [nil => return_opts, RETURN_START]
3307
+ esearch = true
3308
+ in [nil => return_opts, keys]
3309
+ esearch = false
3310
+ in [_, Array[RETURN_WHOLE, _, *] | RETURN_START]
3311
+ raise ArgumentError, "conflicting return options"
3312
+ in [_, Array[RETURN_WHOLE, _, *]] # workaround for https://bugs.ruby-lang.org/issues/20956
3313
+ raise ArgumentError, "conflicting return options"
3314
+ in [_, RETURN_START] # workaround for https://bugs.ruby-lang.org/issues/20956
3315
+ raise ArgumentError, "conflicting return options"
3316
+ in [return_opts, keys]
3317
+ return_opts = convert_return_opts(return_opts)
3318
+ esearch = true
3319
+ end
3320
+ if charset && charset_arg
3321
+ raise ArgumentError, "multiple charset arguments"
3322
+ end
3323
+ charset ||= charset_arg
3324
+ # NOTE: not handling combined RETURN and CHARSET for raw strings
3325
+ if charset && keys in /\ACHARSET\b/i | Array[/\ACHARSET\z/i, *]
3326
+ raise ArgumentError, "multiple charset arguments"
3327
+ end
3328
+ args = normalize_searching_criteria(keys)
3329
+ args.prepend("CHARSET", charset) if charset
3330
+ args.prepend("RETURN", return_opts) if return_opts
3331
+ return args, esearch
3332
+ end
3333
+
3334
+ def convert_return_opts(unconverted)
3335
+ return_opts = Array.try_convert(unconverted) or
3336
+ raise TypeError, "expected return options to be Array, got %s" % [
3337
+ unconverted.class
3338
+ ]
3339
+ return_opts.map {|opt|
3340
+ case opt
3341
+ when Symbol then opt.to_s
3342
+ when Range then partial_range_last_or_seqset(opt)
3343
+ else opt
3344
+ end
3345
+ }
3346
+ end
3347
+
3348
+ def partial_range_last_or_seqset(range)
3349
+ case [range.begin, range.end]
3350
+ in [Integer => first, Integer => last] if first.negative? && last.negative?
3351
+ # partial-range-last [RFC9394]
3352
+ first <= last or raise DataFormatError, "empty range: %p" % [range]
3353
+ "#{first}:#{last}"
3354
+ else
3355
+ SequenceSet[range]
3356
+ end
3357
+ end
3358
+
3359
+ def search_internal(cmd, ...)
3360
+ args, esearch = search_args(...)
3361
+ synchronize do
3362
+ tagged = send_command(cmd, *args)
3363
+ tag = tagged.tag
3364
+ # Only the last ESEARCH or SEARCH is used. Excess results are ignored.
3365
+ esearch_result = extract_responses("ESEARCH") {|response|
3366
+ response in ESearchResult(tag: ^tag)
3367
+ }.last
3368
+ search_result = clear_responses("SEARCH").last
3369
+ if esearch_result
3370
+ # silently ignore SEARCH results, if any
3371
+ esearch_result
3372
+ elsif search_result
3373
+ # warn EXPECTED_ESEARCH_RESULT if esearch
3374
+ search_result
3375
+ elsif esearch
3376
+ # warn NO_SEARCH_RESPONSE
3377
+ ESearchResult[tag:, uid: cmd.start_with?("UID ")]
3378
+ else
3379
+ # warn NO_SEARCH_RESPONSE
3380
+ SearchResult[]
3381
+ end
3140
3382
  end
3141
3383
  end
3142
3384
 
@@ -3198,7 +3440,7 @@ module Net
3198
3440
  end
3199
3441
 
3200
3442
  def normalize_searching_criteria(criteria)
3201
- return RawData.new(criteria) if criteria.is_a?(String)
3443
+ return [RawData.new(criteria)] if criteria.is_a?(String)
3202
3444
  criteria.map {|i|
3203
3445
  if coerce_search_arg_to_seqset?(i)
3204
3446
  SequenceSet[i]
@@ -3276,6 +3518,7 @@ require_relative "imap/errors"
3276
3518
  require_relative "imap/config"
3277
3519
  require_relative "imap/command_data"
3278
3520
  require_relative "imap/data_encoding"
3521
+ require_relative "imap/data_lite"
3279
3522
  require_relative "imap/flags"
3280
3523
  require_relative "imap/response_data"
3281
3524
  require_relative "imap/response_parser"