Skip to content

Commit f40e758

Browse files
committed
✨ Add unchangedsince kwarg to #store, #uid_store
Fixes #237.
1 parent 3d2493d commit f40e758

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

lib/net/imap.rb

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,8 @@ module Net
513513
# <em>(but thread responses are unchanged)</em>.
514514
# - Updates #fetch and #uid_fetch with the +changedsince+ modifier and
515515
# +MODSEQ+ FetchData attribute.
516+
# - Updates #store and #uid_store with the +unchangedsince+ modifier and adds
517+
# the +MODIFIED+ ResponseCode to the tagged response.
516518
#
517519
# ==== RFC8438: <tt>STATUS=SIZE</tt>
518520
# - Updates #status with the +SIZE+ status attribute.
@@ -2066,13 +2068,29 @@ def uid_fetch(set, attr, mod = nil, changedsince: nil)
20662068
fetch_internal("UID FETCH", set, attr, mod, changedsince: changedsince)
20672069
end
20682070

2071+
# :call-seq:
2072+
# store(set, attr, value, unchangedsince: nil) -> array of FetchData
2073+
#
20692074
# Sends a {STORE command [IMAP4rev1 §6.4.6]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.6]
20702075
# to alter data associated with messages in the mailbox, in particular their
2071-
# flags. The +set+ parameter is a number, an array of numbers, or a Range
2072-
# object. Each number is a message sequence number. +attr+ is the name of a
2073-
# data item to store: <tt>"FLAGS"</tt> will replace the message's flag list
2074-
# with the provided one, <tt>"+FLAGS"</tt> will add the provided flags, and
2075-
# <tt>"-FLAGS"</tt> will remove them. +flags+ is a list of flags.
2076+
# flags.
2077+
#
2078+
# +set+ is a number, an array of numbers, or a Range object. Each number is
2079+
# a message sequence number.
2080+
#
2081+
# +attr+ is the name of a data item to store. The semantics of +value+
2082+
# varies based on +attr+:
2083+
# * When +attr+ is <tt>"FLAGS"</tt>, the flags in +value+ replace the
2084+
# message's flag list.
2085+
# * When +attr+ is <tt>"+FLAGS"</tt>, the flags in +value+ are added to
2086+
# the flags for the message.
2087+
# * When +attr+ is <tt>"-FLAGS"</tt>, the flags in +value+ are removed
2088+
# from the message.
2089+
#
2090+
# +unchangedsince+ is an optional integer mod-sequence. It prohibits any
2091+
# changes to messages with +mod-sequence+ greater than the specified
2092+
# +unchangedsince+ value. A SequenceSet of any messages that fail this
2093+
# check will be returned in a +MODIFIED+ ResponseCode.
20762094
#
20772095
# The return value is an array of FetchData.
20782096
#
@@ -2081,13 +2099,25 @@ def uid_fetch(set, attr, mod = nil, changedsince: nil)
20812099
# ===== For example:
20822100
#
20832101
# p imap.store(6..8, "+FLAGS", [:Deleted])
2084-
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
2085-
# #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
2102+
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
2103+
# #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
20862104
# #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
2087-
def store(set, attr, flags)
2088-
return store_internal("STORE", set, attr, flags)
2105+
#
2106+
# ===== Capabilities
2107+
#
2108+
# Extensions may define new data items to be used with #store.
2109+
#
2110+
# The server's capabilities must include +CONDSTORE+
2111+
# {[RFC7162]}[https://tools.ietf.org/html/rfc7162] in order to use the
2112+
# +unchangedsince+ argument. Using +unchangedsince+ implicitly enables the
2113+
# +CONDSTORE+ extension.
2114+
def store(set, attr, flags, unchangedsince: nil)
2115+
store_internal("STORE", set, attr, flags, unchangedsince: unchangedsince)
20892116
end
20902117

2118+
# :call-seq:
2119+
# uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData
2120+
#
20912121
# Sends a {UID STORE command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
20922122
# to alter data associated with messages in the mailbox, in particular their
20932123
# flags.
@@ -2096,8 +2126,11 @@ def store(set, attr, flags)
20962126
# message sequence numbers.
20972127
#
20982128
# Related: #store
2099-
def uid_store(set, attr, flags)
2100-
return store_internal("UID STORE", set, attr, flags)
2129+
#
2130+
# ===== Capabilities
2131+
# Same as #store.
2132+
def uid_store(set, attr, flags, unchangedsince: nil)
2133+
store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince)
21012134
end
21022135

21032136
# Sends a {COPY command [IMAP4rev1 §6.4.7]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.7]
@@ -2809,13 +2842,14 @@ def fetch_internal(cmd, set, attr, mod = nil, changedsince: nil)
28092842
end
28102843
end
28112844

2812-
def store_internal(cmd, set, attr, flags)
2813-
if attr.instance_of?(String)
2814-
attr = RawData.new(attr)
2815-
end
2845+
def store_internal(cmd, set, attr, flags, unchangedsince: nil)
2846+
attr = RawData.new(attr) if attr.instance_of?(String)
2847+
args = [MessageSet.new(set)]
2848+
args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
2849+
args << attr << flags
28162850
synchronize do
28172851
clear_responses("FETCH")
2818-
send_command(cmd, MessageSet.new(set), attr, flags)
2852+
send_command(cmd, *args)
28192853
clear_responses("FETCH")
28202854
end
28212855
end

test/net/imap/test_imap.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,28 @@ def test_clear_responses
11691169
end
11701170
end
11711171

1172+
test "#store with unchangedsince" do
1173+
with_fake_server select: "inbox" do |server, imap|
1174+
server.on("STORE", &:done_ok)
1175+
imap.store 1..-1, "FLAGS", %i[Deleted], unchangedsince: 12345
1176+
assert_equal(
1177+
"RUBY0002 STORE 1:* (UNCHANGEDSINCE 12345) FLAGS (\\Deleted)",
1178+
server.commands.pop.raw.strip
1179+
)
1180+
end
1181+
end
1182+
1183+
test "#uid_store with changedsince" do
1184+
with_fake_server select: "inbox" do |server, imap|
1185+
server.on("UID STORE", &:done_ok)
1186+
imap.uid_store 1..-1, "FLAGS", %i[Deleted], unchangedsince: 987
1187+
assert_equal(
1188+
"RUBY0002 UID STORE 1:* (UNCHANGEDSINCE 987) FLAGS (\\Deleted)",
1189+
server.commands.pop.raw.strip
1190+
)
1191+
end
1192+
end
1193+
11721194
def test_close
11731195
with_fake_server(select: "inbox") do |server, imap|
11741196
resp = imap.close

0 commit comments

Comments
 (0)