net-imap 0.4.17 → 0.5.2
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.
Potentially problematic release.
This version of net-imap might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +7 -1
- data/README.md +7 -3
- data/docs/styles.css +70 -14
- data/lib/net/imap/authenticators.rb +2 -2
- data/lib/net/imap/command_data.rb +32 -51
- data/lib/net/imap/config.rb +36 -10
- data/lib/net/imap/data_encoding.rb +3 -3
- data/lib/net/imap/data_lite.rb +225 -0
- data/lib/net/imap/deprecated_client_options.rb +6 -3
- data/lib/net/imap/errors.rb +6 -0
- data/lib/net/imap/esearch_result.rb +140 -0
- data/lib/net/imap/response_data.rb +7 -93
- data/lib/net/imap/response_parser/parser_utils.rb +5 -0
- data/lib/net/imap/response_parser.rb +77 -18
- 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 +1 -1
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +213 -51
- data/lib/net/imap/sasl/login_authenticator.rb +2 -1
- data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
- data/lib/net/imap/sasl.rb +6 -3
- data/lib/net/imap/sasl_adapter.rb +0 -1
- data/lib/net/imap/sequence_set.rb +18 -23
- data/lib/net/imap.rb +538 -150
- data/net-imap.gemspec +1 -1
- data/rakelib/string_prep_tables_generator.rb +2 -0
- metadata +6 -4
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, +
|
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.
|
726
|
+
VERSION = "0.5.2"
|
723
727
|
|
724
728
|
# Aliases for supported capabilities, to be used with the #enable command.
|
725
729
|
ENABLE_ALIASES = {
|
@@ -946,9 +950,6 @@ module Net
|
|
946
950
|
@sock = tcp_socket(@host, @port)
|
947
951
|
start_tls_session if ssl_ctx
|
948
952
|
start_imap_connection
|
949
|
-
|
950
|
-
# DEPRECATED: to remove in next version
|
951
|
-
@client_thread = Thread.current
|
952
953
|
end
|
953
954
|
|
954
955
|
# Returns true after the TLS negotiation has completed and the remote
|
@@ -956,11 +957,6 @@ module Net
|
|
956
957
|
# but peer verification was disabled.
|
957
958
|
def tls_verified?; @tls_verified end
|
958
959
|
|
959
|
-
def client_thread # :nodoc:
|
960
|
-
warn "Net::IMAP#client_thread is deprecated and will be removed soon."
|
961
|
-
@client_thread
|
962
|
-
end
|
963
|
-
|
964
960
|
# Disconnects from the server.
|
965
961
|
#
|
966
962
|
# Related: #logout, #logout!
|
@@ -1131,7 +1127,7 @@ module Net
|
|
1131
1127
|
#
|
1132
1128
|
# See [ID[https://tools.ietf.org/html/rfc2971]] for field definitions.
|
1133
1129
|
#
|
1134
|
-
#
|
1130
|
+
# ==== Capabilities
|
1135
1131
|
#
|
1136
1132
|
# The server's capabilities must include +ID+
|
1137
1133
|
# [RFC2971[https://tools.ietf.org/html/rfc2971]].
|
@@ -1213,7 +1209,7 @@ module Net
|
|
1213
1209
|
#
|
1214
1210
|
# Related: Net::IMAP.new, #login, #authenticate
|
1215
1211
|
#
|
1216
|
-
#
|
1212
|
+
# ==== Capability
|
1217
1213
|
# Clients should not call #starttls unless the server advertises the
|
1218
1214
|
# +STARTTLS+ capability.
|
1219
1215
|
#
|
@@ -1244,6 +1240,9 @@ module Net
|
|
1244
1240
|
# +SASL-IR+ capability, below). Defaults to the #config value for
|
1245
1241
|
# {sasl_ir}[rdoc-ref:Config#sasl_ir], which defaults to +true+.
|
1246
1242
|
#
|
1243
|
+
# The +registry+ kwarg can be used to select the mechanism implementation
|
1244
|
+
# from a custom registry. See SASL.authenticator and SASL::Authenticators.
|
1245
|
+
#
|
1247
1246
|
# All other arguments are forwarded to the registered SASL authenticator for
|
1248
1247
|
# the requested mechanism. <em>The documentation for each individual
|
1249
1248
|
# mechanism must be consulted for its specific parameters.</em>
|
@@ -1338,29 +1337,9 @@ module Net
|
|
1338
1337
|
# Previously cached #capabilities will be cleared when this method
|
1339
1338
|
# completes. If the TaggedResponse to #authenticate includes updated
|
1340
1339
|
# capabilities, they will be cached.
|
1341
|
-
def authenticate(
|
1342
|
-
|
1343
|
-
|
1344
|
-
mechanism = mechanism.to_s.tr("_", "-").upcase
|
1345
|
-
authenticator = SASL.authenticator(mechanism, *creds, **props, &callback)
|
1346
|
-
cmdargs = ["AUTHENTICATE", mechanism]
|
1347
|
-
if sasl_ir && capable?("SASL-IR") && auth_capable?(mechanism) &&
|
1348
|
-
authenticator.respond_to?(:initial_response?) &&
|
1349
|
-
authenticator.initial_response?
|
1350
|
-
response = authenticator.process(nil)
|
1351
|
-
cmdargs << (response.empty? ? "=" : [response].pack("m0"))
|
1352
|
-
end
|
1353
|
-
result = send_command_with_continuations(*cmdargs) {|data|
|
1354
|
-
challenge = data.unpack1("m")
|
1355
|
-
response = authenticator.process challenge
|
1356
|
-
[response].pack("m0")
|
1357
|
-
}
|
1358
|
-
if authenticator.respond_to?(:done?) && !authenticator.done?
|
1359
|
-
logout!
|
1360
|
-
raise SASL::AuthenticationIncomplete, result
|
1361
|
-
end
|
1362
|
-
@capabilities = capabilities_from_resp_code result
|
1363
|
-
result
|
1340
|
+
def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
|
1341
|
+
sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
|
1342
|
+
.tap { @capabilities = capabilities_from_resp_code _1 }
|
1364
1343
|
end
|
1365
1344
|
|
1366
1345
|
# Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
|
@@ -1377,16 +1356,12 @@ module Net
|
|
1377
1356
|
#
|
1378
1357
|
# Related: #authenticate, #starttls
|
1379
1358
|
#
|
1380
|
-
#
|
1359
|
+
# ==== Capabilities
|
1381
1360
|
#
|
1382
1361
|
# An IMAP client MUST NOT call #login when the server advertises the
|
1383
|
-
# +LOGINDISABLED+ capability.
|
1384
|
-
#
|
1385
|
-
#
|
1386
|
-
# raise "Remote server has disabled the login command"
|
1387
|
-
# else
|
1388
|
-
# imap.login username, password
|
1389
|
-
# end
|
1362
|
+
# +LOGINDISABLED+ capability. By default, Net::IMAP will raise a
|
1363
|
+
# LoginDisabledError when that capability is present. See
|
1364
|
+
# Config#enforce_logindisabled.
|
1390
1365
|
#
|
1391
1366
|
# Server capabilities may change after #starttls, #login, and #authenticate.
|
1392
1367
|
# Cached capabilities _must_ be invalidated after this method completes.
|
@@ -1394,6 +1369,9 @@ module Net
|
|
1394
1369
|
# ResponseCode.
|
1395
1370
|
#
|
1396
1371
|
def login(user, password)
|
1372
|
+
if enforce_logindisabled? && capability?("LOGINDISABLED")
|
1373
|
+
raise LoginDisabledError
|
1374
|
+
end
|
1397
1375
|
send_command("LOGIN", user, password)
|
1398
1376
|
.tap { @capabilities = capabilities_from_resp_code _1 }
|
1399
1377
|
end
|
@@ -1419,7 +1397,7 @@ module Net
|
|
1419
1397
|
#
|
1420
1398
|
# Related: #examine
|
1421
1399
|
#
|
1422
|
-
#
|
1400
|
+
# ==== Capabilities
|
1423
1401
|
#
|
1424
1402
|
# If [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]] is supported,
|
1425
1403
|
# the server may return an untagged "NO" response with a "UIDNOTSTICKY"
|
@@ -1537,7 +1515,7 @@ module Net
|
|
1537
1515
|
#
|
1538
1516
|
# Related: #lsub, MailboxList
|
1539
1517
|
#
|
1540
|
-
#
|
1518
|
+
# ==== For example:
|
1541
1519
|
#
|
1542
1520
|
# imap.create("foo/bar")
|
1543
1521
|
# imap.create("foo/baz")
|
@@ -1588,7 +1566,7 @@ module Net
|
|
1588
1566
|
#
|
1589
1567
|
# Related: #list, Namespaces, Namespace
|
1590
1568
|
#
|
1591
|
-
#
|
1569
|
+
# ==== For example:
|
1592
1570
|
#
|
1593
1571
|
# if capable?("NAMESPACE")
|
1594
1572
|
# namespaces = imap.namespace
|
@@ -1602,7 +1580,7 @@ module Net
|
|
1602
1580
|
# end
|
1603
1581
|
# end
|
1604
1582
|
#
|
1605
|
-
#
|
1583
|
+
# ==== Capabilities
|
1606
1584
|
#
|
1607
1585
|
# The server's capabilities must include +NAMESPACE+
|
1608
1586
|
# [RFC2342[https://tools.ietf.org/html/rfc2342]].
|
@@ -1641,7 +1619,7 @@ module Net
|
|
1641
1619
|
#
|
1642
1620
|
# Related: #list, MailboxList
|
1643
1621
|
#
|
1644
|
-
#
|
1622
|
+
# ==== Capabilities
|
1645
1623
|
#
|
1646
1624
|
# The server's capabilities must include +XLIST+,
|
1647
1625
|
# a deprecated Gmail extension (replaced by +SPECIAL-USE+).
|
@@ -1664,7 +1642,7 @@ module Net
|
|
1664
1642
|
#
|
1665
1643
|
# Related: #getquota, #setquota, MailboxQuotaRoot, MailboxQuota
|
1666
1644
|
#
|
1667
|
-
#
|
1645
|
+
# ==== Capabilities
|
1668
1646
|
#
|
1669
1647
|
# The server's capabilities must include +QUOTA+
|
1670
1648
|
# [RFC2087[https://tools.ietf.org/html/rfc2087]].
|
@@ -1685,7 +1663,7 @@ module Net
|
|
1685
1663
|
#
|
1686
1664
|
# Related: #getquotaroot, #setquota, MailboxQuota
|
1687
1665
|
#
|
1688
|
-
#
|
1666
|
+
# ==== Capabilities
|
1689
1667
|
#
|
1690
1668
|
# The server's capabilities must include +QUOTA+
|
1691
1669
|
# [RFC2087[https://tools.ietf.org/html/rfc2087]].
|
@@ -1703,7 +1681,7 @@ module Net
|
|
1703
1681
|
#
|
1704
1682
|
# Related: #getquota, #getquotaroot
|
1705
1683
|
#
|
1706
|
-
#
|
1684
|
+
# ==== Capabilities
|
1707
1685
|
#
|
1708
1686
|
# The server's capabilities must include +QUOTA+
|
1709
1687
|
# [RFC2087[https://tools.ietf.org/html/rfc2087]].
|
@@ -1723,7 +1701,7 @@ module Net
|
|
1723
1701
|
#
|
1724
1702
|
# Related: #getacl
|
1725
1703
|
#
|
1726
|
-
#
|
1704
|
+
# ==== Capabilities
|
1727
1705
|
#
|
1728
1706
|
# The server's capabilities must include +ACL+
|
1729
1707
|
# [RFC4314[https://tools.ietf.org/html/rfc4314]].
|
@@ -1741,7 +1719,7 @@ module Net
|
|
1741
1719
|
#
|
1742
1720
|
# Related: #setacl, MailboxACLItem
|
1743
1721
|
#
|
1744
|
-
#
|
1722
|
+
# ==== Capabilities
|
1745
1723
|
#
|
1746
1724
|
# The server's capabilities must include +ACL+
|
1747
1725
|
# [RFC4314[https://tools.ietf.org/html/rfc4314]].
|
@@ -1778,7 +1756,7 @@ module Net
|
|
1778
1756
|
# for +mailbox+ cannot be returned; for instance, because it
|
1779
1757
|
# does not exist.
|
1780
1758
|
#
|
1781
|
-
#
|
1759
|
+
# ==== Supported attributes
|
1782
1760
|
#
|
1783
1761
|
# +MESSAGES+:: The number of messages in the mailbox.
|
1784
1762
|
#
|
@@ -1809,12 +1787,12 @@ module Net
|
|
1809
1787
|
# Unsupported attributes may be requested. The attribute value will be
|
1810
1788
|
# either an Integer or an ExtensionData object.
|
1811
1789
|
#
|
1812
|
-
#
|
1790
|
+
# ==== For example:
|
1813
1791
|
#
|
1814
1792
|
# p imap.status("inbox", ["MESSAGES", "RECENT"])
|
1815
1793
|
# #=> {"RECENT"=>0, "MESSAGES"=>44}
|
1816
1794
|
#
|
1817
|
-
#
|
1795
|
+
# ==== Capabilities
|
1818
1796
|
#
|
1819
1797
|
# +SIZE+ requires the server's capabilities to include either +IMAP4rev2+ or
|
1820
1798
|
# <tt>STATUS=SIZE</tt>
|
@@ -1854,7 +1832,7 @@ module Net
|
|
1854
1832
|
# not exist (it is not created automatically), or if the flags,
|
1855
1833
|
# date_time, or message arguments contain errors.
|
1856
1834
|
#
|
1857
|
-
#
|
1835
|
+
# ==== Capabilities
|
1858
1836
|
#
|
1859
1837
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
1860
1838
|
# supported and the destination supports persistent UIDs, the server's
|
@@ -1903,7 +1881,7 @@ module Net
|
|
1903
1881
|
#
|
1904
1882
|
# Related: #close
|
1905
1883
|
#
|
1906
|
-
#
|
1884
|
+
# ==== Capabilities
|
1907
1885
|
#
|
1908
1886
|
# The server's capabilities must include +UNSELECT+
|
1909
1887
|
# [RFC3691[https://tools.ietf.org/html/rfc3691]].
|
@@ -1944,88 +1922,406 @@ module Net
|
|
1944
1922
|
#
|
1945
1923
|
# Related: #expunge
|
1946
1924
|
#
|
1947
|
-
#
|
1925
|
+
# ==== Capabilities
|
1948
1926
|
#
|
1949
1927
|
# The server's capabilities must include +UIDPLUS+
|
1950
1928
|
# [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]].
|
1951
1929
|
def uid_expunge(uid_set)
|
1952
1930
|
synchronize do
|
1953
|
-
send_command("UID EXPUNGE",
|
1931
|
+
send_command("UID EXPUNGE", SequenceSet.new(uid_set))
|
1954
1932
|
clear_responses("EXPUNGE")
|
1955
1933
|
end
|
1956
1934
|
end
|
1957
1935
|
|
1958
|
-
#
|
1959
|
-
#
|
1960
|
-
#
|
1961
|
-
# string holding the entire search string, or a single-dimension array of
|
1962
|
-
# search keywords and arguments.
|
1936
|
+
# :call-seq:
|
1937
|
+
# search(criteria, charset = nil) -> result
|
1938
|
+
# search(criteria, charset: nil, return: nil) -> result
|
1963
1939
|
#
|
1964
|
-
#
|
1965
|
-
#
|
1966
|
-
#
|
1940
|
+
# Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
|
1941
|
+
# to search the mailbox for messages that match the given search +criteria+,
|
1942
|
+
# and returns either a SearchResult or an ESearchResult. SearchResult
|
1943
|
+
# inherits from Array (for backward compatibility) but adds
|
1944
|
+
# SearchResult#modseq when the +CONDSTORE+ capability has been enabled.
|
1945
|
+
# ESearchResult also implements to_a{rdoc-ref:ESearchResult#to_a}, for
|
1946
|
+
# compatibility with SearchResult.
|
1947
|
+
#
|
1948
|
+
# +criteria+ is one or more search keys and their arguments, which may be
|
1949
|
+
# provided as an array or a string.
|
1950
|
+
# See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
|
1951
|
+
# and {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
|
1952
|
+
#
|
1953
|
+
# +return+ options control what kind of information is returned about
|
1954
|
+
# messages matching the search +criteria+. Specifying +return+ should force
|
1955
|
+
# the server to return an ESearchResult instead of a SearchResult, but some
|
1956
|
+
# servers disobey this requirement. <em>Requires an extended search
|
1957
|
+
# capability, such as +ESEARCH+ or +IMAP4rev2+.</em>
|
1958
|
+
# See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
|
1959
|
+
# and {"Return options"}[rdoc-ref:#search@Return+options], below.
|
1960
|
+
#
|
1961
|
+
# +charset+ is the name of the {registered character
|
1962
|
+
# set}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
|
1963
|
+
# used by strings in the search +criteria+. When +charset+ isn't specified,
|
1964
|
+
# either <tt>"US-ASCII"</tt> or <tt>"UTF-8"</tt> is assumed, depending on
|
1965
|
+
# the server's capabilities.
|
1966
|
+
#
|
1967
|
+
# _NOTE:_ Return options and charset may be sent as part of +criteria+. Do
|
1968
|
+
# not use the +return+ or +charset+ arguments when either return options or
|
1969
|
+
# charset are embedded in +criteria+.
|
1967
1970
|
#
|
1968
1971
|
# Related: #uid_search
|
1969
1972
|
#
|
1970
|
-
#
|
1973
|
+
# ==== For example:
|
1974
|
+
#
|
1975
|
+
# imap.search(["SUBJECT", "hello", "NOT", "SEEN"])
|
1976
|
+
# #=> [1, 6, 7, 8]
|
1971
1977
|
#
|
1972
|
-
#
|
1978
|
+
# The following assumes the server supports +ESEARCH+ and +CONDSTORE+:
|
1979
|
+
#
|
1980
|
+
# result = imap.uid_search(["UID", 12345.., "MODSEQ", 620_162_338],
|
1981
|
+
# return: %w(all count min max))
|
1982
|
+
# # => #<data Net::IMAP::ESearchResult tag="RUBY0123", uid=true,
|
1983
|
+
# # data=[["ALL", Net::IMAP::SequenceSet["12346:12349,22222:22230"]],
|
1984
|
+
# # ["COUNT", 13], ["MIN", 12346], ["MAX", 22230],
|
1985
|
+
# # ["MODSEQ", 917162488]]>
|
1986
|
+
# result.to_a # => [12346, 12347, 12348, 12349, 22222, 22223, 22224,
|
1987
|
+
# # 22225, 22226, 22227, 22228, 22229, 22230]
|
1988
|
+
# result.uid? # => true
|
1989
|
+
# result.count # => 13
|
1990
|
+
# result.min # => 12346
|
1991
|
+
# result.max # => 22230
|
1992
|
+
# result.modseq # => 917162488
|
1993
|
+
#
|
1994
|
+
# Using +return+ options to limit the result to only min, max, and count:
|
1995
|
+
#
|
1996
|
+
# result = imap.uid_search(["UID", 12345..,], return: %w(count min max))
|
1997
|
+
# # => #<data Net::IMAP::ESearchResult tag="RUBY0124", uid=true,
|
1998
|
+
# # data=[["COUNT", 13], ["MIN", 12346], ["MAX", 22230]]>
|
1999
|
+
# result.to_a # => []
|
2000
|
+
# result.count # => 13
|
2001
|
+
# result.min # => 12346
|
2002
|
+
# result.max # => 22230
|
2003
|
+
#
|
2004
|
+
# Return options and charset may be sent as keyword args or embedded in the
|
2005
|
+
# +criteria+ arg, but they must be in the correct order: <tt>"RETURN (...)
|
2006
|
+
# CHARSET ... criteria..."</tt>. The following searches
|
2007
|
+
# send the exact same command to the server:
|
2008
|
+
#
|
2009
|
+
# # Return options and charset as keyword arguments (preferred)
|
2010
|
+
# imap.search(%w(OR UNSEEN FLAGGED), return: %w(MIN MAX), charset: "UTF-8")
|
2011
|
+
# # Embedding return and charset in the criteria array
|
2012
|
+
# imap.search(["RETURN", %w(MIN MAX), "CHARSET", "UTF-8", *%w(OR UNSEEN FLAGGED)])
|
2013
|
+
# # Embedding return and charset in the criteria string
|
2014
|
+
# imap.search("RETURN (MIN MAX) CHARSET UTF-8 OR UNSEEN FLAGGED")
|
2015
|
+
#
|
2016
|
+
# Sending charset as the second positional argument is supported for
|
2017
|
+
# backward compatibility. Future versions may print a deprecation warning:
|
2018
|
+
# imap.search(%w(OR UNSEEN FLAGGED), "UTF-8", return: %w(MIN MAX))
|
2019
|
+
#
|
2020
|
+
# ==== Argument translation
|
2021
|
+
#
|
2022
|
+
# [+return+ options]
|
2023
|
+
# Must be an Array. Return option names may be either strings or symbols.
|
2024
|
+
# +Range+ elements which begin and end with negative integers are encoded
|
2025
|
+
# for use with +PARTIAL+--any other ranges are converted to SequenceSet.
|
2026
|
+
# Unlike +criteria+, other return option arguments are not automatically
|
2027
|
+
# converted to SequenceSet.
|
2028
|
+
#
|
2029
|
+
# [When +criteria+ is an Array]
|
2030
|
+
# When the array begins with <tt>"RETURN"</tt> (case insensitive), the
|
2031
|
+
# second array element is translated like the +return+ parameter (as
|
2032
|
+
# described above).
|
2033
|
+
#
|
2034
|
+
# Every other member is a +SEARCH+ command argument:
|
2035
|
+
# [SequenceSet]
|
2036
|
+
# Encoded as an \IMAP +sequence-set+ with SequenceSet#valid_string.
|
2037
|
+
# [Set, Range, <tt>-1</tt>, +:*+, responds to +#to_sequence_set+]
|
2038
|
+
# Converted to SequenceSet for validation and encoding.
|
2039
|
+
# [nested sequence-set +Array+]
|
2040
|
+
# When every element in a nested array is one of the above types, a
|
2041
|
+
# positive +Integer+, a sequence-set formatted +String+, or a deeply
|
2042
|
+
# nested +Array+ of these same types, the array will be converted to
|
2043
|
+
# SequenceSet for validation and encoding.
|
2044
|
+
# [Any other nested +Array+]
|
2045
|
+
# Otherwise, a nested array is encoded as a parenthesized list, to
|
2046
|
+
# combine multiple search keys (e.g., for use with +OR+ and +NOT+).
|
2047
|
+
# [+String+]
|
2048
|
+
# Sent verbatim when it is a valid \IMAP +atom+, and encoded as an \IMAP
|
2049
|
+
# +quoted+ or +literal+ string otherwise. Every standard search key
|
2050
|
+
# name is a valid \IMAP +atom+ and every standard search key string
|
2051
|
+
# argument is an +astring+ which may be encoded as +atom+, +quoted+, or
|
2052
|
+
# +literal+.
|
2053
|
+
#
|
2054
|
+
# *Note:* <tt>*</tt> is not a valid \IMAP +atom+ character. Any string
|
2055
|
+
# containing <tt>*</tt> will be encoded as a +quoted+ string, _not_ a
|
2056
|
+
# +sequence-set+.
|
2057
|
+
# [+Integer+ (except for <tt>-1</tt>)]
|
2058
|
+
# Encoded using +#to_s+.
|
2059
|
+
# [+Date+]
|
2060
|
+
# Encoded as an \IMAP date (see ::encode_date).
|
2061
|
+
#
|
2062
|
+
# [When +criteria+ is a String]
|
2063
|
+
# +criteria+ will be sent directly to the server <em>without any
|
2064
|
+
# validation or encoding</em>.
|
2065
|
+
#
|
2066
|
+
# <em>*WARNING:* This is vulnerable to injection attacks when external
|
2067
|
+
# inputs are used.</em>
|
2068
|
+
#
|
2069
|
+
# ==== Return options
|
2070
|
+
#
|
2071
|
+
# For full definitions of the standard return options and return data, see
|
2072
|
+
# the relevant RFCs.
|
2073
|
+
#
|
2074
|
+
# ===== +ESEARCH+ or +IMAP4rev2+
|
2075
|
+
#
|
2076
|
+
# The following return options require either +ESEARCH+ or +IMAP4rev2+.
|
2077
|
+
# See [{RFC4731 §3.1}[https://rfc-editor.org/rfc/rfc4731#section-3.1]] or
|
2078
|
+
# [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]].
|
2079
|
+
#
|
2080
|
+
# [+ALL+]
|
2081
|
+
# Returns ESearchResult#all with a SequenceSet of all matching sequence
|
2082
|
+
# numbers or UIDs. This is the default, when return options are empty.
|
2083
|
+
#
|
2084
|
+
# For compatibility with SearchResult, ESearchResult#to_a returns an
|
2085
|
+
# Array of message sequence numbers or UIDs.
|
2086
|
+
# [+COUNT+]
|
2087
|
+
# Returns ESearchResult#count with the number of matching messages.
|
2088
|
+
# [+MAX+]
|
2089
|
+
# Returns ESearchResult#max with the highest matching sequence number or
|
2090
|
+
# UID.
|
2091
|
+
# [+MIN+]
|
2092
|
+
# Returns ESearchResult#min with the lowest matching sequence number or
|
2093
|
+
# UID.
|
2094
|
+
#
|
2095
|
+
# ===== +CONDSTORE+
|
2096
|
+
#
|
2097
|
+
# ESearchResult#modseq return data does not have a corresponding return
|
2098
|
+
# option. Instead, it is returned if the +MODSEQ+ search key is used or
|
2099
|
+
# when the +CONDSTORE+ extension is enabled for the selected mailbox.
|
2100
|
+
# See [{RFC4731 §3.2}[https://www.rfc-editor.org/rfc/rfc4731#section-3.2]]
|
2101
|
+
# or [{RFC7162 §2.1.5}[https://www.rfc-editor.org/rfc/rfc7162#section-3.1.5]].
|
2102
|
+
#
|
2103
|
+
# ===== +RFC4466+ compatible extensions
|
2104
|
+
#
|
2105
|
+
# {RFC4466 §2.6}[https://www.rfc-editor.org/rfc/rfc4466.html#section-2.6]
|
2106
|
+
# defines standard syntax for search extensions. Net::IMAP allows sending
|
2107
|
+
# unknown search return options and will parse unknown search extensions'
|
2108
|
+
# return values into ExtensionData. Please note that this is an
|
2109
|
+
# intentionally _unstable_ API. Future releases may return different
|
2110
|
+
# (incompatible) objects, <em>without deprecation or warning</em>.
|
2111
|
+
#
|
2112
|
+
# ==== Search keys
|
2113
|
+
#
|
2114
|
+
# For full definitions of the standard search +criteria+,
|
1973
2115
|
# see [{IMAP4rev1 §6.4.4}[https://www.rfc-editor.org/rfc/rfc3501.html#section-6.4.4]],
|
1974
2116
|
# or [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]],
|
1975
2117
|
# in addition to documentation for
|
1976
|
-
# any
|
1977
|
-
# reported by #capabilities which may define additional search filters, e.g:
|
2118
|
+
# any #capabilities which may define additional search filters, such as
|
1978
2119
|
# +CONDSTORE+, +WITHIN+, +FILTERS+, <tt>SEARCH=FUZZY</tt>, +OBJECTID+, or
|
1979
|
-
# +SAVEDATE+.
|
2120
|
+
# +SAVEDATE+.
|
1980
2121
|
#
|
1981
|
-
#
|
1982
|
-
#
|
1983
|
-
#
|
2122
|
+
# With the exception of <em>sequence-set</em> and <em>parenthesized
|
2123
|
+
# list</em>, all search keys are composed of prefix label with zero or more
|
2124
|
+
# arguments. The number and type of arguments is specific to each search
|
2125
|
+
# key.
|
1984
2126
|
#
|
1985
|
-
#
|
1986
|
-
# <b><date></b>. The date argument has a format similar
|
1987
|
-
# to <tt>8-Aug-2002</tt>, and can be formatted using
|
1988
|
-
# Net::IMAP.format_date.
|
2127
|
+
# ===== Search keys that match all messages
|
1989
2128
|
#
|
1990
|
-
#
|
2129
|
+
# [+ALL+]
|
2130
|
+
# The default initial key. Matches every message in the mailbox.
|
1991
2131
|
#
|
1992
|
-
#
|
2132
|
+
# [+SAVEDATESUPPORTED+]
|
2133
|
+
# Matches every message in the mailbox when the mailbox supports the save
|
2134
|
+
# date attribute. Otherwise, it matches no messages.
|
1993
2135
|
#
|
1994
|
-
#
|
2136
|
+
# <em>Requires +SAVEDATE+ capability</em>.
|
2137
|
+
# {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
|
1995
2138
|
#
|
1996
|
-
#
|
2139
|
+
# ===== Sequence set search keys
|
1997
2140
|
#
|
1998
|
-
#
|
2141
|
+
# [_sequence-set_]
|
2142
|
+
# Matches messages with message sequence numbers in _sequence-set_.
|
1999
2143
|
#
|
2000
|
-
#
|
2144
|
+
# _Note:_ this search key has no label.
|
2001
2145
|
#
|
2002
|
-
#
|
2003
|
-
#
|
2146
|
+
# <em>+UIDONLY+ must *not* be enabled.</em>
|
2147
|
+
# {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.html]
|
2004
2148
|
#
|
2005
|
-
#
|
2149
|
+
# [+UID+ _sequence-set_]
|
2150
|
+
# Matches messages with a UID in _sequence-set_.
|
2006
2151
|
#
|
2007
|
-
#
|
2152
|
+
# ===== Compound search keys
|
2008
2153
|
#
|
2009
|
-
#
|
2154
|
+
# [(_search-key_ _search-key_...)]
|
2155
|
+
# Combines one or more _search-key_ arguments to match
|
2156
|
+
# messages which match all contained search keys. Useful for +OR+, +NOT+,
|
2157
|
+
# and other search keys with _search-key_ arguments.
|
2010
2158
|
#
|
2011
|
-
#
|
2159
|
+
# _Note:_ this search key has no label.
|
2012
2160
|
#
|
2013
|
-
#
|
2014
|
-
#
|
2161
|
+
# [+OR+ _search-key_ _search-key_]
|
2162
|
+
# Matches messages which match either _search-key_ argument.
|
2163
|
+
#
|
2164
|
+
# [+NOT+ _search-key_]
|
2165
|
+
# Matches messages which do not match _search-key_.
|
2166
|
+
#
|
2167
|
+
# [+FUZZY+ _search-key_]
|
2168
|
+
# Uses fuzzy matching for the specified search key.
|
2169
|
+
#
|
2170
|
+
# <em>Requires <tt>SEARCH=FUZZY</tt> capability.</em>
|
2171
|
+
# {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
|
2172
|
+
#
|
2173
|
+
# ===== Flags search keys
|
2174
|
+
#
|
2175
|
+
# [+ANSWERED+, +UNANSWERED+]
|
2176
|
+
# Matches messages with or without the <tt>\\Answered</tt> flag.
|
2177
|
+
# [+DELETED+, +UNDELETED+]
|
2178
|
+
# Matches messages with or without the <tt>\\Deleted</tt> flag.
|
2179
|
+
# [+DRAFT+, +UNDRAFT+]
|
2180
|
+
# Matches messages with or without the <tt>\\Draft</tt> flag.
|
2181
|
+
# [+FLAGGED+, +UNFLAGGED+]
|
2182
|
+
# Matches messages with or without the <tt>\\Flagged</tt> flag.
|
2183
|
+
# [+SEEN+, +UNSEEN+]
|
2184
|
+
# Matches messages with or without the <tt>\\Seen</tt> flag.
|
2185
|
+
# [+KEYWORD+ _keyword_, +UNKEYWORD+ _keyword_]
|
2186
|
+
# Matches messages with or without the specified _keyword_.
|
2187
|
+
#
|
2188
|
+
# [+RECENT+, +UNRECENT+]
|
2189
|
+
# Matches messages with or without the <tt>\\Recent</tt> flag.
|
2190
|
+
#
|
2191
|
+
# *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
|
2192
|
+
# [+NEW+]
|
2193
|
+
# Equivalent to <tt>(RECENT UNSEEN)</tt>.
|
2194
|
+
#
|
2195
|
+
# *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
|
2196
|
+
#
|
2197
|
+
# ===== Header field substring search keys
|
2198
|
+
#
|
2199
|
+
# [+BCC+ _substring_]
|
2200
|
+
# Matches when _substring_ is in the envelope's +BCC+ field.
|
2201
|
+
# [+CC+ _substring_]
|
2202
|
+
# Matches when _substring_ is in the envelope's +CC+ field.
|
2203
|
+
# [+FROM+ _substring_]
|
2204
|
+
# Matches when _substring_ is in the envelope's +FROM+ field.
|
2205
|
+
# [+SUBJECT+ _substring_]
|
2206
|
+
# Matches when _substring_ is in the envelope's +SUBJECT+ field.
|
2207
|
+
# [+TO+ _substring_]
|
2208
|
+
# Matches when _substring_ is in the envelope's +TO+ field.
|
2209
|
+
#
|
2210
|
+
# [+HEADER+ _field_ _substring_]
|
2211
|
+
# Matches when _substring_ is in the specified header _field_.
|
2212
|
+
#
|
2213
|
+
# ===== Body text search keys
|
2214
|
+
# [+BODY+ _string_]
|
2215
|
+
# Matches when _string_ is in the body of the message.
|
2216
|
+
# Does not match on header fields.
|
2217
|
+
#
|
2218
|
+
# The server _may_ use flexible matching, rather than simple substring
|
2219
|
+
# matches. For example, this may use stemming or match only full words.
|
2220
|
+
#
|
2221
|
+
# [+TEXT+ _string_]
|
2222
|
+
# Matches when _string_ is in the header or body of the message.
|
2223
|
+
#
|
2224
|
+
# The server _may_ use flexible matching, rather than simple substring
|
2225
|
+
# matches. For example, this may use stemming or match only full words.
|
2226
|
+
#
|
2227
|
+
# ===== Date/Time search keys
|
2228
|
+
#
|
2229
|
+
# [+SENTBEFORE+ _date_]
|
2230
|
+
# [+SENTON+ _date_]
|
2231
|
+
# [+SENTSINCE+ _date_]
|
2232
|
+
# Matches when the +Date+ header is earlier than, on, or later than _date_.
|
2233
|
+
#
|
2234
|
+
# [+BEFORE+ _date_]
|
2235
|
+
# [+ON+ _date_]
|
2236
|
+
# [+SINCE+ _date_]
|
2237
|
+
# Matches when the +INTERNALDATE+ is earlier than, on, or later than
|
2238
|
+
# _date_.
|
2239
|
+
#
|
2240
|
+
# [+OLDER+ _interval_]
|
2241
|
+
# [+YOUNGER+ _interval_]
|
2242
|
+
# Matches when the +INTERNALDATE+ is more/less than _interval_ seconds ago.
|
2243
|
+
#
|
2244
|
+
# <em>Requires +WITHIN+ capability</em>.
|
2245
|
+
# {[RFC5032]}[https://www.rfc-editor.org/rfc/rfc5032.html]
|
2015
2246
|
#
|
2016
|
-
#
|
2247
|
+
# [+SAVEDBEFORE+ _date_]
|
2248
|
+
# [+SAVEDON+ _date_]
|
2249
|
+
# [+SAVEDSINCE+ _date_]
|
2250
|
+
# Matches when the save date is earlier than, on, or later than _date_.
|
2017
2251
|
#
|
2018
|
-
#
|
2252
|
+
# <em>Requires +SAVEDATE+ capability.</em>
|
2253
|
+
# {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
|
2254
|
+
#
|
2255
|
+
# ===== Other message attribute search keys
|
2256
|
+
#
|
2257
|
+
# [+SMALLER+ _bytes_]
|
2258
|
+
# [+LARGER+ _bytes_]
|
2259
|
+
# Matches when +RFC822.SIZE+ is smaller or larger than _bytes_.
|
2260
|
+
#
|
2261
|
+
# [+ANNOTATION+ _entry_ _attr_ _value_]
|
2262
|
+
# Matches messages that have annotations with entries matching _entry_,
|
2263
|
+
# attributes matching _attr_, and _value_ in the attribute's values.
|
2264
|
+
#
|
2265
|
+
# <em>Requires +ANNOTATE-EXPERIMENT-1+ capability</em>.
|
2266
|
+
# {[RFC5257]}[https://www.rfc-editor.org/rfc/rfc5257.html].
|
2267
|
+
#
|
2268
|
+
# [+FILTER+ _filter_]
|
2269
|
+
# References a _filter_ that is stored on the server and matches all
|
2270
|
+
# messages which would be matched by that filter's search criteria.
|
2271
|
+
#
|
2272
|
+
# <em>Requires +FILTERS+ capability</em>.
|
2273
|
+
# {[RFC5466]}[https://www.rfc-editor.org/rfc/rfc5466.html#section-3.1]
|
2274
|
+
#
|
2275
|
+
# [+MODSEQ+ _modseq_]
|
2276
|
+
# Matches when +MODSEQ+ is greater than or equal to _modseq_.
|
2277
|
+
#
|
2278
|
+
# <em>Requires +CONDSTORE+ capability</em>.
|
2279
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
|
2280
|
+
#
|
2281
|
+
# [+MODSEQ+ _entry_ _entry-type_ _modseq_]
|
2282
|
+
# Matches when a specific metadata _entry_ has been updated since
|
2283
|
+
# _modseq_.
|
2284
|
+
#
|
2285
|
+
# For flags, the corresponding _entry_ name is
|
2286
|
+
# <tt>"/flags/#{flag_name}"</tt>, where _flag_name_ includes the
|
2287
|
+
# <tt>\\</tt> prefix. _entry-type_ can be one of <tt>"shared"</tt>,
|
2288
|
+
# <tt>"priv"</tt> (private), or <tt>"all"</tt>.
|
2289
|
+
#
|
2290
|
+
# <em>Requires +CONDSTORE+ capability</em>.
|
2291
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
|
2292
|
+
#
|
2293
|
+
# [+EMAILID+ _objectid_]
|
2294
|
+
# [+THREADID+ _objectid_]
|
2295
|
+
# Matches when +EMAILID+/+THREADID+ is equal to _objectid_
|
2296
|
+
# (substring matches are not supported).
|
2297
|
+
#
|
2298
|
+
# <em>Requires +OBJECTID+ capability</em>.
|
2299
|
+
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-6]
|
2300
|
+
#
|
2301
|
+
# ==== Capabilities
|
2302
|
+
#
|
2303
|
+
# Return options should only be specified when the server supports
|
2304
|
+
# +IMAP4rev2+ or an extension that allows them, such as +ESEARCH+
|
2305
|
+
# [RFC4731[https://rfc-editor.org/rfc/rfc4731#section-3.1]].
|
2306
|
+
#
|
2307
|
+
# When +IMAP4rev2+ is enabled, or when the server supports +IMAP4rev2+ but
|
2308
|
+
# not +IMAP4rev1+, ESearchResult is always returned instead of SearchResult.
|
2309
|
+
#
|
2310
|
+
# If CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html] is supported
|
2019
2311
|
# and enabled for the selected mailbox, a non-empty SearchResult will
|
2020
2312
|
# include a +MODSEQ+ value.
|
2021
2313
|
# imap.select("mbox", condstore: true)
|
2022
|
-
# result = imap.search(["SUBJECT", "hi there", "not", "new")
|
2314
|
+
# result = imap.search(["SUBJECT", "hi there", "not", "new"])
|
2023
2315
|
# #=> Net::IMAP::SearchResult[1, 6, 7, 8, modseq: 5594]
|
2024
2316
|
# result.modseq # => 5594
|
2025
|
-
def search(
|
2026
|
-
|
2317
|
+
def search(...)
|
2318
|
+
search_internal("SEARCH", ...)
|
2027
2319
|
end
|
2028
2320
|
|
2321
|
+
# :call-seq:
|
2322
|
+
# uid_search(criteria, charset = nil) -> result
|
2323
|
+
# uid_search(criteria, charset: nil, return: nil) -> result
|
2324
|
+
#
|
2029
2325
|
# Sends a {UID SEARCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
|
2030
2326
|
# to search the mailbox for messages that match the given searching
|
2031
2327
|
# criteria, and returns unique identifiers (<tt>UID</tt>s).
|
@@ -2034,9 +2330,9 @@ module Net
|
|
2034
2330
|
# backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
|
2035
2331
|
# capability has been enabled.
|
2036
2332
|
#
|
2037
|
-
# See #search for documentation of
|
2038
|
-
def uid_search(
|
2039
|
-
|
2333
|
+
# See #search for documentation of parameters.
|
2334
|
+
def uid_search(...)
|
2335
|
+
search_internal("UID SEARCH", ...)
|
2040
2336
|
end
|
2041
2337
|
|
2042
2338
|
# :call-seq:
|
@@ -2064,7 +2360,7 @@ module Net
|
|
2064
2360
|
#
|
2065
2361
|
# Related: #uid_search, FetchData
|
2066
2362
|
#
|
2067
|
-
#
|
2363
|
+
# ==== For example:
|
2068
2364
|
#
|
2069
2365
|
# p imap.fetch(6..8, "UID")
|
2070
2366
|
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
|
@@ -2082,7 +2378,7 @@ module Net
|
|
2082
2378
|
# p data.attr["UID"]
|
2083
2379
|
# #=> 98
|
2084
2380
|
#
|
2085
|
-
#
|
2381
|
+
# ==== Capabilities
|
2086
2382
|
#
|
2087
2383
|
# Many extensions define new message +attr+ names. See FetchData for a list
|
2088
2384
|
# of supported extension fields.
|
@@ -2111,7 +2407,7 @@ module Net
|
|
2111
2407
|
#
|
2112
2408
|
# Related: #fetch, FetchData
|
2113
2409
|
#
|
2114
|
-
#
|
2410
|
+
# ==== Capabilities
|
2115
2411
|
# Same as #fetch.
|
2116
2412
|
def uid_fetch(set, attr, mod = nil, changedsince: nil)
|
2117
2413
|
fetch_internal("UID FETCH", set, attr, mod, changedsince: changedsince)
|
@@ -2145,14 +2441,14 @@ module Net
|
|
2145
2441
|
#
|
2146
2442
|
# Related: #uid_store
|
2147
2443
|
#
|
2148
|
-
#
|
2444
|
+
# ==== For example:
|
2149
2445
|
#
|
2150
2446
|
# p imap.store(6..8, "+FLAGS", [:Deleted])
|
2151
2447
|
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
|
2152
2448
|
# #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
|
2153
2449
|
# #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
|
2154
2450
|
#
|
2155
|
-
#
|
2451
|
+
# ==== Capabilities
|
2156
2452
|
#
|
2157
2453
|
# Extensions may define new data items to be used with #store.
|
2158
2454
|
#
|
@@ -2176,7 +2472,7 @@ module Net
|
|
2176
2472
|
#
|
2177
2473
|
# Related: #store
|
2178
2474
|
#
|
2179
|
-
#
|
2475
|
+
# ==== Capabilities
|
2180
2476
|
# Same as #store.
|
2181
2477
|
def uid_store(set, attr, flags, unchangedsince: nil)
|
2182
2478
|
store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince)
|
@@ -2189,7 +2485,7 @@ module Net
|
|
2189
2485
|
#
|
2190
2486
|
# Related: #uid_copy
|
2191
2487
|
#
|
2192
|
-
#
|
2488
|
+
# ==== Capabilities
|
2193
2489
|
#
|
2194
2490
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
2195
2491
|
# supported, the server's response should include a +COPYUID+ response code
|
@@ -2206,7 +2502,7 @@ module Net
|
|
2206
2502
|
#
|
2207
2503
|
# Similar to #copy, but +set+ contains unique identifiers.
|
2208
2504
|
#
|
2209
|
-
#
|
2505
|
+
# ==== Capabilities
|
2210
2506
|
#
|
2211
2507
|
# +UIDPLUS+ affects #uid_copy the same way it affects #copy.
|
2212
2508
|
def uid_copy(set, mailbox)
|
@@ -2221,7 +2517,7 @@ module Net
|
|
2221
2517
|
#
|
2222
2518
|
# Related: #uid_move
|
2223
2519
|
#
|
2224
|
-
#
|
2520
|
+
# ==== Capabilities
|
2225
2521
|
#
|
2226
2522
|
# The server's capabilities must include +MOVE+
|
2227
2523
|
# [RFC6851[https://tools.ietf.org/html/rfc6851]].
|
@@ -2245,7 +2541,7 @@ module Net
|
|
2245
2541
|
#
|
2246
2542
|
# Related: #move
|
2247
2543
|
#
|
2248
|
-
#
|
2544
|
+
# ==== Capabilities
|
2249
2545
|
#
|
2250
2546
|
# Same as #move: The server's capabilities must include +MOVE+
|
2251
2547
|
# [RFC6851[https://tools.ietf.org/html/rfc6851]]. +UIDPLUS+ also affects
|
@@ -2265,14 +2561,14 @@ module Net
|
|
2265
2561
|
#
|
2266
2562
|
# Related: #uid_sort, #search, #uid_search, #thread, #uid_thread
|
2267
2563
|
#
|
2268
|
-
#
|
2564
|
+
# ==== For example:
|
2269
2565
|
#
|
2270
2566
|
# p imap.sort(["FROM"], ["ALL"], "US-ASCII")
|
2271
2567
|
# #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
|
2272
2568
|
# p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
|
2273
2569
|
# #=> [6, 7, 8, 1]
|
2274
2570
|
#
|
2275
|
-
#
|
2571
|
+
# ==== Capabilities
|
2276
2572
|
#
|
2277
2573
|
# The server's capabilities must include +SORT+
|
2278
2574
|
# [RFC5256[https://tools.ietf.org/html/rfc5256]].
|
@@ -2287,7 +2583,7 @@ module Net
|
|
2287
2583
|
#
|
2288
2584
|
# Related: #sort, #search, #uid_search, #thread, #uid_thread
|
2289
2585
|
#
|
2290
|
-
#
|
2586
|
+
# ==== Capabilities
|
2291
2587
|
#
|
2292
2588
|
# The server's capabilities must include +SORT+
|
2293
2589
|
# [RFC5256[https://tools.ietf.org/html/rfc5256]].
|
@@ -2312,7 +2608,7 @@ module Net
|
|
2312
2608
|
#
|
2313
2609
|
# Related: #uid_thread, #search, #uid_search, #sort, #uid_sort
|
2314
2610
|
#
|
2315
|
-
#
|
2611
|
+
# ==== Capabilities
|
2316
2612
|
#
|
2317
2613
|
# The server's capabilities must include +THREAD+
|
2318
2614
|
# [RFC5256[https://tools.ietf.org/html/rfc5256]].
|
@@ -2326,7 +2622,7 @@ module Net
|
|
2326
2622
|
#
|
2327
2623
|
# Related: #thread, #search, #uid_search, #sort, #uid_sort
|
2328
2624
|
#
|
2329
|
-
#
|
2625
|
+
# ==== Capabilities
|
2330
2626
|
#
|
2331
2627
|
# The server's capabilities must include +THREAD+
|
2332
2628
|
# [RFC5256[https://tools.ietf.org/html/rfc5256]].
|
@@ -2345,7 +2641,7 @@ module Net
|
|
2345
2641
|
#
|
2346
2642
|
# Related: #capable?, #capabilities, #capability
|
2347
2643
|
#
|
2348
|
-
#
|
2644
|
+
# ==== Capabilities
|
2349
2645
|
#
|
2350
2646
|
# The server's capabilities must include
|
2351
2647
|
# +ENABLE+ [RFC5161[https://tools.ietf.org/html/rfc5161]]
|
@@ -2447,7 +2743,7 @@ module Net
|
|
2447
2743
|
#
|
2448
2744
|
# Related: #idle_done, #noop, #check
|
2449
2745
|
#
|
2450
|
-
#
|
2746
|
+
# ==== Capabilities
|
2451
2747
|
#
|
2452
2748
|
# The server's capabilities must include +IDLE+
|
2453
2749
|
# [RFC2177[https://tools.ietf.org/html/rfc2177]].
|
@@ -2564,7 +2860,7 @@ module Net
|
|
2564
2860
|
#
|
2565
2861
|
# Related: #extract_responses, #clear_responses, #response_handlers, #greeting
|
2566
2862
|
#
|
2567
|
-
#
|
2863
|
+
# ==== Thread safety
|
2568
2864
|
# >>>
|
2569
2865
|
# *Note:* Access to the responses hash is synchronized for thread-safety.
|
2570
2866
|
# The receiver thread and response_handlers cannot process new responses
|
@@ -2578,7 +2874,7 @@ module Net
|
|
2578
2874
|
# thread, but will not modify any responses after adding them to the
|
2579
2875
|
# responses hash.
|
2580
2876
|
#
|
2581
|
-
#
|
2877
|
+
# ==== Clearing responses
|
2582
2878
|
#
|
2583
2879
|
# Previously unhandled responses are automatically cleared before entering a
|
2584
2880
|
# mailbox with #select or #examine. Long-lived connections can receive many
|
@@ -2587,7 +2883,7 @@ module Net
|
|
2587
2883
|
# the block, or remove responses with #extract_responses, #clear_responses,
|
2588
2884
|
# or #add_response_handler.
|
2589
2885
|
#
|
2590
|
-
#
|
2886
|
+
# ==== Missing responses
|
2591
2887
|
#
|
2592
2888
|
# Only non-+nil+ data is stored. Many important response codes have no data
|
2593
2889
|
# of their own, but are used as "tags" on the ResponseText object they are
|
@@ -2608,7 +2904,7 @@ module Net
|
|
2608
2904
|
when :raise
|
2609
2905
|
raise ArgumentError, RESPONSES_DEPRECATION_MSG
|
2610
2906
|
when :warn
|
2611
|
-
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1)
|
2907
|
+
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1, category: :deprecated)
|
2612
2908
|
when :frozen_dup
|
2613
2909
|
synchronize {
|
2614
2910
|
responses = @responses.transform_values(&:freeze)
|
@@ -2957,19 +3253,100 @@ module Net
|
|
2957
3253
|
end
|
2958
3254
|
end
|
2959
3255
|
|
2960
|
-
def
|
2961
|
-
if
|
2962
|
-
|
3256
|
+
def enforce_logindisabled?
|
3257
|
+
if config.enforce_logindisabled == :when_capabilities_cached
|
3258
|
+
capabilities_cached?
|
2963
3259
|
else
|
2964
|
-
|
3260
|
+
config.enforce_logindisabled
|
3261
|
+
end
|
3262
|
+
end
|
3263
|
+
|
3264
|
+
RETURN_WHOLE = /\ARETURN\z/i
|
3265
|
+
RETURN_START = /\ARETURN\b/i
|
3266
|
+
private_constant :RETURN_WHOLE, :RETURN_START
|
3267
|
+
|
3268
|
+
def search_args(keys, charset_arg = nil, return: nil, charset: nil)
|
3269
|
+
{return:} => {return: return_kw}
|
3270
|
+
case [return_kw, keys]
|
3271
|
+
in [nil, Array[RETURN_WHOLE, return_opts, *keys]]
|
3272
|
+
return_opts = convert_return_opts(return_opts)
|
3273
|
+
esearch = true
|
3274
|
+
in [nil => return_opts, RETURN_START]
|
3275
|
+
esearch = true
|
3276
|
+
in [nil => return_opts, keys]
|
3277
|
+
esearch = false
|
3278
|
+
in [_, Array[RETURN_WHOLE, _, *] | RETURN_START]
|
3279
|
+
raise ArgumentError, "conflicting return options"
|
3280
|
+
in [_, Array[RETURN_WHOLE, _, *]] # workaround for https://bugs.ruby-lang.org/issues/20956
|
3281
|
+
raise ArgumentError, "conflicting return options"
|
3282
|
+
in [_, RETURN_START] # workaround for https://bugs.ruby-lang.org/issues/20956
|
3283
|
+
raise ArgumentError, "conflicting return options"
|
3284
|
+
in [return_opts, keys]
|
3285
|
+
return_opts = convert_return_opts(return_opts)
|
3286
|
+
esearch = true
|
2965
3287
|
end
|
3288
|
+
if charset && charset_arg
|
3289
|
+
raise ArgumentError, "multiple charset arguments"
|
3290
|
+
end
|
3291
|
+
charset ||= charset_arg
|
3292
|
+
# NOTE: not handling combined RETURN and CHARSET for raw strings
|
3293
|
+
if charset && keys in /\ACHARSET\b/i | Array[/\ACHARSET\z/i, *]
|
3294
|
+
raise ArgumentError, "multiple charset arguments"
|
3295
|
+
end
|
3296
|
+
args = normalize_searching_criteria(keys)
|
3297
|
+
args.prepend("CHARSET", charset) if charset
|
3298
|
+
args.prepend("RETURN", return_opts) if return_opts
|
3299
|
+
return args, esearch
|
3300
|
+
end
|
3301
|
+
|
3302
|
+
def convert_return_opts(unconverted)
|
3303
|
+
return_opts = Array.try_convert(unconverted) or
|
3304
|
+
raise TypeError, "expected return options to be Array, got %s" % [
|
3305
|
+
unconverted.class
|
3306
|
+
]
|
3307
|
+
return_opts.map {|opt|
|
3308
|
+
case opt
|
3309
|
+
when Symbol then opt.to_s
|
3310
|
+
when Range then partial_range_last_or_seqset(opt)
|
3311
|
+
else opt
|
3312
|
+
end
|
3313
|
+
}
|
3314
|
+
end
|
3315
|
+
|
3316
|
+
def partial_range_last_or_seqset(range)
|
3317
|
+
case [range.begin, range.end]
|
3318
|
+
in [Integer => first, Integer => last] if first.negative? && last.negative?
|
3319
|
+
# partial-range-last [RFC9394]
|
3320
|
+
first <= last or raise DataFormatError, "empty range: %p" % [range]
|
3321
|
+
"#{first}:#{last}"
|
3322
|
+
else
|
3323
|
+
SequenceSet[range]
|
3324
|
+
end
|
3325
|
+
end
|
3326
|
+
|
3327
|
+
def search_internal(cmd, ...)
|
3328
|
+
args, esearch = search_args(...)
|
2966
3329
|
synchronize do
|
2967
|
-
|
2968
|
-
|
3330
|
+
tagged = send_command(cmd, *args)
|
3331
|
+
tag = tagged.tag
|
3332
|
+
# Only the last ESEARCH or SEARCH is used. Excess results are ignored.
|
3333
|
+
esearch_result = extract_responses("ESEARCH") {|response|
|
3334
|
+
response in ESearchResult(tag: ^tag)
|
3335
|
+
}.last
|
3336
|
+
search_result = clear_responses("SEARCH").last
|
3337
|
+
if esearch_result
|
3338
|
+
# silently ignore SEARCH results, if any
|
3339
|
+
esearch_result
|
3340
|
+
elsif search_result
|
3341
|
+
# warn EXPECTED_ESEARCH_RESULT if esearch
|
3342
|
+
search_result
|
3343
|
+
elsif esearch
|
3344
|
+
# warn NO_SEARCH_RESPONSE
|
3345
|
+
ESearchResult[tag:, uid: cmd.start_with?("UID ")]
|
2969
3346
|
else
|
2970
|
-
|
3347
|
+
# warn NO_SEARCH_RESPONSE
|
3348
|
+
SearchResult[]
|
2971
3349
|
end
|
2972
|
-
clear_responses("SEARCH").last || []
|
2973
3350
|
end
|
2974
3351
|
end
|
2975
3352
|
|
@@ -2990,9 +3367,9 @@ module Net
|
|
2990
3367
|
synchronize do
|
2991
3368
|
clear_responses("FETCH")
|
2992
3369
|
if mod
|
2993
|
-
send_command(cmd,
|
3370
|
+
send_command(cmd, SequenceSet.new(set), attr, mod)
|
2994
3371
|
else
|
2995
|
-
send_command(cmd,
|
3372
|
+
send_command(cmd, SequenceSet.new(set), attr)
|
2996
3373
|
end
|
2997
3374
|
clear_responses("FETCH")
|
2998
3375
|
end
|
@@ -3000,7 +3377,7 @@ module Net
|
|
3000
3377
|
|
3001
3378
|
def store_internal(cmd, set, attr, flags, unchangedsince: nil)
|
3002
3379
|
attr = RawData.new(attr) if attr.instance_of?(String)
|
3003
|
-
args = [
|
3380
|
+
args = [SequenceSet.new(set)]
|
3004
3381
|
args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
|
3005
3382
|
args << attr << flags
|
3006
3383
|
synchronize do
|
@@ -3011,15 +3388,11 @@ module Net
|
|
3011
3388
|
end
|
3012
3389
|
|
3013
3390
|
def copy_internal(cmd, set, mailbox)
|
3014
|
-
send_command(cmd,
|
3391
|
+
send_command(cmd, SequenceSet.new(set), mailbox)
|
3015
3392
|
end
|
3016
3393
|
|
3017
3394
|
def sort_internal(cmd, sort_keys, search_keys, charset)
|
3018
|
-
|
3019
|
-
search_keys = [RawData.new(search_keys)]
|
3020
|
-
else
|
3021
|
-
normalize_searching_criteria(search_keys)
|
3022
|
-
end
|
3395
|
+
search_keys = normalize_searching_criteria(search_keys)
|
3023
3396
|
synchronize do
|
3024
3397
|
send_command(cmd, sort_keys, charset, *search_keys)
|
3025
3398
|
clear_responses("SORT").last || []
|
@@ -3027,25 +3400,39 @@ module Net
|
|
3027
3400
|
end
|
3028
3401
|
|
3029
3402
|
def thread_internal(cmd, algorithm, search_keys, charset)
|
3030
|
-
|
3031
|
-
search_keys = [RawData.new(search_keys)]
|
3032
|
-
else
|
3033
|
-
normalize_searching_criteria(search_keys)
|
3034
|
-
end
|
3403
|
+
search_keys = normalize_searching_criteria(search_keys)
|
3035
3404
|
synchronize do
|
3036
3405
|
send_command(cmd, algorithm, charset, *search_keys)
|
3037
3406
|
clear_responses("THREAD").last || []
|
3038
3407
|
end
|
3039
3408
|
end
|
3040
3409
|
|
3041
|
-
def normalize_searching_criteria(
|
3042
|
-
|
3043
|
-
|
3044
|
-
|
3045
|
-
|
3410
|
+
def normalize_searching_criteria(criteria)
|
3411
|
+
return [RawData.new(criteria)] if criteria.is_a?(String)
|
3412
|
+
criteria.map {|i|
|
3413
|
+
if coerce_search_arg_to_seqset?(i)
|
3414
|
+
SequenceSet[i]
|
3046
3415
|
else
|
3047
3416
|
i
|
3048
3417
|
end
|
3418
|
+
}
|
3419
|
+
end
|
3420
|
+
|
3421
|
+
def coerce_search_arg_to_seqset?(obj)
|
3422
|
+
case obj
|
3423
|
+
when Set, -1, :* then true
|
3424
|
+
when Range then true
|
3425
|
+
when Array then obj.all? { coerce_search_array_arg_to_seqset? _1 }
|
3426
|
+
else obj.respond_to?(:to_sequence_set)
|
3427
|
+
end
|
3428
|
+
end
|
3429
|
+
|
3430
|
+
def coerce_search_array_arg_to_seqset?(obj)
|
3431
|
+
case obj
|
3432
|
+
when Integer then obj.positive? || obj == -1
|
3433
|
+
when String then ResponseParser::Patterns::SEQUENCE_SET_STR.match?(obj.b)
|
3434
|
+
else
|
3435
|
+
coerce_search_arg_to_seqset?(obj)
|
3049
3436
|
end
|
3050
3437
|
end
|
3051
3438
|
|
@@ -3099,6 +3486,7 @@ require_relative "imap/errors"
|
|
3099
3486
|
require_relative "imap/config"
|
3100
3487
|
require_relative "imap/command_data"
|
3101
3488
|
require_relative "imap/data_encoding"
|
3489
|
+
require_relative "imap/data_lite"
|
3102
3490
|
require_relative "imap/flags"
|
3103
3491
|
require_relative "imap/response_data"
|
3104
3492
|
require_relative "imap/response_parser"
|