@@ -502,6 +502,22 @@ module Net
502
502
#
503
503
# - See #enable for information about support for UTF-8 string encoding.
504
504
#
505
+ # ==== RFC7162: +CONDSTORE+
506
+ #
507
+ # - Updates #enable with +CONDSTORE+ parameter. +CONDSTORE+ will also be
508
+ # enabled by using any of the extension's command parameters, listed below.
509
+ # - Updates #status with the +HIGHESTMODSEQ+ status attribute.
510
+ # - Updates #select and #examine with the +condstore+ modifier, and adds
511
+ # either a +HIGHESTMODSEQ+ or +NOMODSEQ+ ResponseCode to the responses.
512
+ # - Updates #search, #uid_search, #sort, and #uid_sort with the +MODSEQ+
513
+ # search criterion, and adds SearchResult#modseq to the search response.
514
+ # - Updates #thread and #uid_thread with the +MODSEQ+ search criterion
515
+ # <em>(but thread responses are unchanged)</em>.
516
+ # - Updates #fetch and #uid_fetch with the +changedsince+ modifier and
517
+ # +MODSEQ+ FetchData attribute.
518
+ # - Updates #store and #uid_store with the +unchangedsince+ modifier and adds
519
+ # the +MODIFIED+ ResponseCode to the tagged response.
520
+ #
505
521
# ==== RFC8438: <tt>STATUS=SIZE</tt>
506
522
# - Updates #status with the +SIZE+ status attribute.
507
523
#
@@ -669,6 +685,16 @@ module Net
669
685
# Resnick, P., Ed., Newman, C., Ed., and S. Shen, Ed.,
670
686
# "IMAP Support for UTF-8", RFC 6855, DOI 10.17487/RFC6855, March 2013,
671
687
# <https://www.rfc-editor.org/info/rfc6855>.
688
+ # [CONDSTORE[https://tools.ietf.org/html/rfc7162]]::
689
+ # [QRESYNC[https://tools.ietf.org/html/rfc7162]]::
690
+ # Melnikov, A. and D. Cridland, "IMAP Extensions: Quick Flag Changes
691
+ # Resynchronization (CONDSTORE) and Quick Mailbox Resynchronization
692
+ # (QRESYNC)", RFC 7162, DOI 10.17487/RFC7162, May 2014,
693
+ # <https://www.rfc-editor.org/info/rfc7162>.
694
+ # [OBJECTID[https://tools.ietf.org/html/rfc8474]]::
695
+ # Gondwana, B., Ed., "IMAP Extension for Object Identifiers",
696
+ # RFC 8474, DOI 10.17487/RFC8474, September 2018,
697
+ # <https://www.rfc-editor.org/info/rfc8474>.
672
698
#
673
699
# === IANA registries
674
700
# * {IMAP Capabilities}[http://www.iana.org/assignments/imap4-capabilities]
@@ -1345,6 +1371,12 @@ def login(user, password)
1345
1371
# or when existing messages are expunged; see #add_response_handler for a
1346
1372
# way to detect these events.
1347
1373
#
1374
+ # When the +condstore+ keyword argument is true, the server is told to
1375
+ # enable the extension. If +mailbox+ supports persistence of mod-sequences,
1376
+ # the +HIGHESTMODSEQ+ ResponseCode will be sent as an untagged response to
1377
+ # #select and all `FETCH` responses will include FetchData#modseq.
1378
+ # Otherwise, the +NOMODSEQ+ ResponseCode will be sent.
1379
+ #
1348
1380
# A Net::IMAP::NoResponseError is raised if the mailbox does not
1349
1381
# exist or is for some reason non-selectable.
1350
1382
#
@@ -1357,10 +1389,17 @@ def login(user, password)
1357
1389
# response code indicating that the mailstore does not support persistent
1358
1390
# UIDs:
1359
1391
# imap.responses("NO", &:last)&.code&.name == "UIDNOTSTICKY"
1360
- def select ( mailbox )
1392
+ #
1393
+ # If [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html]] is supported,
1394
+ # the +condstore+ keyword parameter may be used.
1395
+ # imap.select("mbox", condstore: true)
1396
+ # modseq = imap.responses("HIGHESTMODSEQ", &:last)
1397
+ def select ( mailbox , condstore : false )
1398
+ args = [ "SELECT" , mailbox ]
1399
+ args << [ "CONDSTORE" ] if condstore
1361
1400
synchronize do
1362
1401
@responses . clear
1363
- send_command ( "SELECT" , mailbox )
1402
+ send_command ( * args )
1364
1403
end
1365
1404
end
1366
1405
@@ -1373,10 +1412,12 @@ def select(mailbox)
1373
1412
# exist or is for some reason non-examinable.
1374
1413
#
1375
1414
# Related: #select
1376
- def examine ( mailbox )
1415
+ def examine ( mailbox , condstore : false )
1416
+ args = [ "EXAMINE" , mailbox ]
1417
+ args << [ "CONDSTORE" ] if condstore
1377
1418
synchronize do
1378
1419
@responses . clear
1379
- send_command ( "EXAMINE" , mailbox )
1420
+ send_command ( * args )
1380
1421
end
1381
1422
end
1382
1423
@@ -1689,7 +1730,7 @@ def lsub(refname, mailbox)
1689
1730
end
1690
1731
end
1691
1732
1692
- # Sends a {STATUS commands [IMAP4rev1 §6.3.10]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.3.10]
1733
+ # Sends a {STATUS command [IMAP4rev1 §6.3.10]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.3.10]
1693
1734
# and returns the status of the indicated +mailbox+. +attr+ is a list of one
1694
1735
# or more attributes whose statuses are to be requested.
1695
1736
#
@@ -1716,10 +1757,13 @@ def lsub(refname, mailbox)
1716
1757
# The approximate size of the mailbox---must be greater than or equal to
1717
1758
# the sum of all messages' +RFC822.SIZE+ fetch item values.
1718
1759
#
1760
+ # +HIGHESTMODSEQ+::
1761
+ # The highest mod-sequence value of all messages in the mailbox. See
1762
+ # +CONDSTORE+ {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
1763
+ #
1719
1764
# +MAILBOXID+::
1720
- # A server-allocated unique _string_ identifier for the mailbox.
1721
- # See +OBJECTID+
1722
- # {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-4].
1765
+ # A server-allocated unique _string_ identifier for the mailbox. See
1766
+ # +OBJECTID+ {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
1723
1767
#
1724
1768
# +RECENT+::
1725
1769
# The number of messages with the <tt>\Recent</tt> flag.
@@ -1741,6 +1785,9 @@ def lsub(refname, mailbox)
1741
1785
#
1742
1786
# +DELETED+ requires the server's capabilities to include +IMAP4rev2+.
1743
1787
#
1788
+ # +HIGHESTMODSEQ+ requires the server's capabilities to include +CONDSTORE+
1789
+ # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
1790
+ #
1744
1791
# +MAILBOXID+ requires the server's capabilities to include +OBJECTID+
1745
1792
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html].
1746
1793
def status ( mailbox , attr )
@@ -1877,6 +1924,10 @@ def uid_expunge(uid_set)
1877
1924
# string holding the entire search string, or a single-dimension array of
1878
1925
# search keywords and arguments.
1879
1926
#
1927
+ # Returns a SearchResult object. SearchResult inherits from Array (for
1928
+ # backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
1929
+ # capability has been enabled.
1930
+ #
1880
1931
# Related: #uid_search
1881
1932
#
1882
1933
# ===== Search criteria
@@ -1925,6 +1976,15 @@ def uid_expunge(uid_set)
1925
1976
# p imap.search(["SUBJECT", "hello", "NOT", "NEW"])
1926
1977
# #=> [1, 6, 7, 8]
1927
1978
#
1979
+ # ===== Capabilities
1980
+ #
1981
+ # If [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html]] is supported
1982
+ # and enabled for the selected mailbox, a non-empty SearchResult will
1983
+ # include a +MODSEQ+ value.
1984
+ # imap.select("mbox", condstore: true)
1985
+ # result = imap.search(["SUBJECT", "hi there", "not", "new")
1986
+ # #=> Net::IMAP::SearchResult[1, 6, 7, 8, modseq: 5594]
1987
+ # result.modseq # => 5594
1928
1988
def search ( keys , charset = nil )
1929
1989
return search_internal ( "SEARCH" , keys , charset )
1930
1990
end
@@ -1933,11 +1993,18 @@ def search(keys, charset = nil)
1933
1993
# to search the mailbox for messages that match the given searching
1934
1994
# criteria, and returns unique identifiers (<tt>UID</tt>s).
1935
1995
#
1996
+ # Returns a SearchResult object. SearchResult inherits from Array (for
1997
+ # backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
1998
+ # capability has been enabled.
1999
+ #
1936
2000
# See #search for documentation of search criteria.
1937
2001
def uid_search ( keys , charset = nil )
1938
2002
return search_internal ( "UID SEARCH" , keys , charset )
1939
2003
end
1940
2004
2005
+ # :call-seq:
2006
+ # fetch(set, attr, changedsince: nil) -> array of FetchData
2007
+ #
1941
2008
# Sends a {FETCH command [IMAP4rev1 §6.4.5]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.5]
1942
2009
# to retrieve data associated with a message in the mailbox.
1943
2010
#
@@ -1953,6 +2020,9 @@ def uid_search(keys, charset = nil)
1953
2020
# +attr+ is a list of attributes to fetch; see the documentation
1954
2021
# for FetchData for a list of valid attributes.
1955
2022
#
2023
+ # +changedsince+ is an optional integer mod-sequence. It limits results to
2024
+ # messages with a mod-sequence greater than +changedsince+.
2025
+ #
1956
2026
# The return value is an array of FetchData.
1957
2027
#
1958
2028
# Related: #uid_search, FetchData
@@ -1974,10 +2044,23 @@ def uid_search(keys, charset = nil)
1974
2044
# #=> "12-Oct-2000 22:40:59 +0900"
1975
2045
# p data.attr["UID"]
1976
2046
# #=> 98
1977
- def fetch ( set , attr , mod = nil )
1978
- return fetch_internal ( "FETCH" , set , attr , mod )
2047
+ #
2048
+ # ===== Capabilities
2049
+ #
2050
+ # Many extensions define new message +attr+ names. See FetchData for a list
2051
+ # of supported extension fields.
2052
+ #
2053
+ # The server's capabilities must include +CONDSTORE+
2054
+ # {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2055
+ # +changedsince+ argument. Using +changedsince+ implicitly enables the
2056
+ # +CONDSTORE+ extension.
2057
+ def fetch ( set , attr , mod = nil , changedsince : nil )
2058
+ fetch_internal ( "FETCH" , set , attr , mod , changedsince : changedsince )
1979
2059
end
1980
2060
2061
+ # :call-seq:
2062
+ # uid_fetch(set, attr, changedsince: nil) -> array of FetchData
2063
+ #
1981
2064
# Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
1982
2065
# to retrieve data associated with a message in the mailbox.
1983
2066
#
@@ -1990,17 +2073,36 @@ def fetch(set, attr, mod = nil)
1990
2073
# whether a +UID+ was specified as a message data item to the +FETCH+.
1991
2074
#
1992
2075
# Related: #fetch, FetchData
1993
- def uid_fetch ( set , attr , mod = nil )
1994
- return fetch_internal ( "UID FETCH" , set , attr , mod )
2076
+ #
2077
+ # ===== Capabilities
2078
+ # Same as #fetch.
2079
+ def uid_fetch ( set , attr , mod = nil , changedsince : nil )
2080
+ fetch_internal ( "UID FETCH" , set , attr , mod , changedsince : changedsince )
1995
2081
end
1996
2082
2083
+ # :call-seq:
2084
+ # store(set, attr, value, unchangedsince: nil) -> array of FetchData
2085
+ #
1997
2086
# Sends a {STORE command [IMAP4rev1 §6.4.6]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.6]
1998
2087
# to alter data associated with messages in the mailbox, in particular their
1999
- # flags. The +set+ parameter is a number, an array of numbers, or a Range
2000
- # object. Each number is a message sequence number. +attr+ is the name of a
2001
- # data item to store: <tt>"FLAGS"</tt> will replace the message's flag list
2002
- # with the provided one, <tt>"+FLAGS"</tt> will add the provided flags, and
2003
- # <tt>"-FLAGS"</tt> will remove them. +flags+ is a list of flags.
2088
+ # flags.
2089
+ #
2090
+ # +set+ is a number, an array of numbers, or a Range object. Each number is
2091
+ # a message sequence number.
2092
+ #
2093
+ # +attr+ is the name of a data item to store. The semantics of +value+
2094
+ # varies based on +attr+:
2095
+ # * When +attr+ is <tt>"FLAGS"</tt>, the flags in +value+ replace the
2096
+ # message's flag list.
2097
+ # * When +attr+ is <tt>"+FLAGS"</tt>, the flags in +value+ are added to
2098
+ # the flags for the message.
2099
+ # * When +attr+ is <tt>"-FLAGS"</tt>, the flags in +value+ are removed
2100
+ # from the message.
2101
+ #
2102
+ # +unchangedsince+ is an optional integer mod-sequence. It prohibits any
2103
+ # changes to messages with +mod-sequence+ greater than the specified
2104
+ # +unchangedsince+ value. A SequenceSet of any messages that fail this
2105
+ # check will be returned in a +MODIFIED+ ResponseCode.
2004
2106
#
2005
2107
# The return value is an array of FetchData.
2006
2108
#
@@ -2009,13 +2111,25 @@ def uid_fetch(set, attr, mod = nil)
2009
2111
# ===== For example:
2010
2112
#
2011
2113
# p imap.store(6..8, "+FLAGS", [:Deleted])
2012
- # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
2013
- # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
2114
+ # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2115
+ # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2014
2116
# #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
2015
- def store ( set , attr , flags )
2016
- return store_internal ( "STORE" , set , attr , flags )
2117
+ #
2118
+ # ===== Capabilities
2119
+ #
2120
+ # Extensions may define new data items to be used with #store.
2121
+ #
2122
+ # The server's capabilities must include +CONDSTORE+
2123
+ # {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2124
+ # +unchangedsince+ argument. Using +unchangedsince+ implicitly enables the
2125
+ # +CONDSTORE+ extension.
2126
+ def store ( set , attr , flags , unchangedsince : nil )
2127
+ store_internal ( "STORE" , set , attr , flags , unchangedsince : unchangedsince )
2017
2128
end
2018
2129
2130
+ # :call-seq:
2131
+ # uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData
2132
+ #
2019
2133
# Sends a {UID STORE command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
2020
2134
# to alter data associated with messages in the mailbox, in particular their
2021
2135
# flags.
@@ -2024,8 +2138,11 @@ def store(set, attr, flags)
2024
2138
# message sequence numbers.
2025
2139
#
2026
2140
# Related: #store
2027
- def uid_store ( set , attr , flags )
2028
- return store_internal ( "UID STORE" , set , attr , flags )
2141
+ #
2142
+ # ===== Capabilities
2143
+ # Same as #store.
2144
+ def uid_store ( set , attr , flags , unchangedsince : nil )
2145
+ store_internal ( "UID STORE" , set , attr , flags , unchangedsince : unchangedsince )
2029
2146
end
2030
2147
2031
2148
# Sends a {COPY command [IMAP4rev1 §6.4.7]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.7]
@@ -2201,6 +2318,13 @@ def uid_thread(algorithm, search_keys, charset)
2201
2318
# each enabled extension (usually the same name as the enabled extension).
2202
2319
# The following capabilities may be enabled:
2203
2320
#
2321
+ # [+CONDSTORE+ {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html]]
2322
+ #
2323
+ # Updates various commands to return +CONDSTORE+ extension responses. It
2324
+ # is not necessary to explicitly enable +CONDSTORE+—using any of the
2325
+ # command parameters defined by the extension will implicitly enable it.
2326
+ # See {[RFC7162 §3.1]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1].
2327
+ #
2204
2328
# [+:utf8+ --- an alias for <tt>"UTF8=ACCEPT"</tt>]
2205
2329
#
2206
2330
# In a future release, <tt>enable(:utf8)</tt> will enable either
@@ -2712,7 +2836,11 @@ def search_internal(cmd, keys, charset)
2712
2836
end
2713
2837
end
2714
2838
2715
- def fetch_internal ( cmd , set , attr , mod = nil )
2839
+ def fetch_internal ( cmd , set , attr , mod = nil , changedsince : nil )
2840
+ if changedsince
2841
+ mod ||= [ ]
2842
+ mod << "CHANGEDSINCE" << Integer ( changedsince )
2843
+ end
2716
2844
case attr
2717
2845
when String then
2718
2846
attr = RawData . new ( attr )
@@ -2733,13 +2861,14 @@ def fetch_internal(cmd, set, attr, mod = nil)
2733
2861
end
2734
2862
end
2735
2863
2736
- def store_internal ( cmd , set , attr , flags )
2737
- if attr . instance_of? ( String )
2738
- attr = RawData . new ( attr )
2739
- end
2864
+ def store_internal ( cmd , set , attr , flags , unchangedsince : nil )
2865
+ attr = RawData . new ( attr ) if attr . instance_of? ( String )
2866
+ args = [ MessageSet . new ( set ) ]
2867
+ args << [ "UNCHANGEDSINCE" , Integer ( unchangedsince ) ] if unchangedsince
2868
+ args << attr << flags
2740
2869
synchronize do
2741
2870
clear_responses ( "FETCH" )
2742
- send_command ( cmd , MessageSet . new ( set ) , attr , flags )
2871
+ send_command ( cmd , * args )
2743
2872
clear_responses ( "FETCH" )
2744
2873
end
2745
2874
end
0 commit comments