diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index 4ac9d7a8..551dc534 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -1556,6 +1556,9 @@ def login(user, password)
.tap do state_authenticated! _1 end
end
+ # :call-seq:
+ # select(mailbox, condstore: false, qresync: nil) -> result
+ #
# Sends a {SELECT command [IMAP4rev1 §6.3.1]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.3.1]
# to select a +mailbox+ so that messages in the +mailbox+ can be accessed.
#
@@ -1569,8 +1572,29 @@ def login(user, password)
# When the +condstore+ keyword argument is true, the server is told to
# enable the extension. If +mailbox+ supports persistence of mod-sequences,
# the +HIGHESTMODSEQ+ ResponseCode will be sent as an untagged response to
- # #select and all `FETCH` responses will include FetchData#modseq.
+ # #select and all +FETCH+ responses will include FetchStruct#modseq.
# Otherwise, the +NOMODSEQ+ ResponseCode will be sent.
+ # Requires the +CONDSTORE+ capabability.
+ # {[RFC7162]}[https://rfc-editor.org/rfc/rfc7162]
+ #
+ # imap.select("mbox", condstore: true)
+ # modseq = imap.responses("HIGHESTMODSEQ", &:last)
+ #
+ # The optional +qresync+ argument can provide quick resynchronization
+ # parameters: the last known UIDVALIDITY, the last known MODSEQ,
+ # known UIDs (optional), and message sequence match data
+ # (optional). When +qresync+ is provided, a SelectResult object
+ # is returned with +UIDVALIDITY+, +HIGHESTMODSEQ+, +VANISHED+, and +FETCH+
+ # results. Sending +qresync+ implicitly enables +condstore+, too.
+ # Requires the +QRESYNC+ capabability.
+ # {[RFC7162]}[https://rfc-editor.org/rfc/rfc7162]
+ #
+ # imap.enable("QRESYNC") # must enable before selecting the mailbox
+ # qresync = imap.select("INBOX", qresync: [uidvalidity, modseq, known_uids])
+ # qresync => { uidvalidity: ^uidvalidity, highestmodseq: modseq,
+ # vanished:, updated: }
+ # vanished.each do delete_message _1 end
+ # updated .each do update_message _1.uid, flags: _1.flags, modseq: _1.modseq end
#
# A Net::IMAP::NoResponseError is raised if the mailbox does not
# exist or is for some reason non-selectable.
@@ -1579,7 +1603,8 @@ def login(user, password)
#
# ==== Capabilities
#
- # If [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]] is supported,
+ # If either [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]]
+ # or [IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051.html]] is supported,
# the server may return an untagged "NO" response with a "UIDNOTSTICKY"
# response code indicating that the mailstore does not support persistent
# UIDs:
@@ -1587,19 +1612,16 @@ def login(user, password)
#
# If [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html]] is supported,
# the +condstore+ keyword parameter may be used.
- # imap.select("mbox", condstore: true)
- # modseq = imap.responses("HIGHESTMODSEQ", &:last)
- def select(mailbox, condstore: false)
- args = ["SELECT", mailbox]
- args << ["CONDSTORE"] if condstore
- synchronize do
- state_unselected! # implicitly closes current mailbox
- @responses.clear
- send_command(*args)
- .tap do state_selected! end
- end
+ #
+ # If [QRESYNC[https://www.rfc-editor.org/rfc/rfc7162.html]] is enabled,
+ # the +qresync+ keyword parameter may be used.
+ def select(...)
+ select_internal("SELECT", ...)
end
+ # :call-seq:
+ # examine(mailbox, condstore: false, qresync: nil) -> result
+ #
# Sends a {EXAMINE command [IMAP4rev1 §6.3.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.3.2]
# to select a +mailbox+ so that messages in the +mailbox+ can be accessed.
# Behaves the same as #select, except that the selected +mailbox+ is
@@ -1609,15 +1631,8 @@ def select(mailbox, condstore: false)
# exist or is for some reason non-examinable.
#
# Related: #select
- def examine(mailbox, condstore: false)
- args = ["EXAMINE", mailbox]
- args << ["CONDSTORE"] if condstore
- synchronize do
- state_unselected! # implicitly closes current mailbox
- @responses.clear
- send_command(*args)
- .tap do state_selected! end
- end
+ def examine(...)
+ select_internal("EXAMINE", ...)
end
# Sends a {CREATE command [IMAP4rev1 §6.3.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.3.3]
@@ -2959,9 +2974,7 @@ def uid_thread(algorithm, search_keys, charset)
# See {[RFC7162 §3.1]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1].
#
# [+QRESYNC+ {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html]]
- # *NOTE:* Enabling QRESYNC will replace +EXPUNGE+ with +VANISHED+, but
- # the extension arguments to #select, #examine, and #uid_fetch are not
- # supported yet.
+ # *NOTE:* The +QRESYNC+ argument to #uid_fetch is not supported yet.
#
# Adds quick resynchronization options to #select, #examine, and
# #uid_fetch. +QRESYNC+ _must_ be explicitly enabled before using any of
@@ -3585,6 +3598,20 @@ def enforce_logindisabled?
end
end
+ def select_internal(command, mailbox, condstore: false, qresync: nil)
+ args = [command, mailbox]
+ params = []
+ params << "CONDSTORE" if condstore
+ params << "QRESYNC" << qresync if qresync # TODO: validate qresync params
+ args << params unless params.empty?
+ synchronize do
+ state_unselected! # implicitly closes current mailbox
+ @responses.clear
+ send_command(*args)
+ .tap do state_selected! end
+ end
+ end
+
def expunge_internal(...)
synchronize do
send_command(...)