Skip to content

Commit 647a745

Browse files
committed
✨ Add condstore kwarg to #select, #examine
Fixes #122.
1 parent 207fe5f commit 647a745

File tree

4 files changed

+45
-8
lines changed

4 files changed

+45
-8
lines changed

lib/net/imap.rb

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,8 @@ module Net
505505
# ==== RFC7162: +CONDSTORE+
506506
#
507507
# - Updates #status with the +HIGHESTMODSEQ+ status attribute.
508+
# - Updates #select and #examine with the +condstore+ modifier, and adds
509+
# either a +HIGHESTMODSEQ+ or +NOMODSEQ+ ResponseCode to the responses.
508510
# - Updates #search, #uid_search, #sort, and #uid_sort with the +MODSEQ+
509511
# search criterion, and adds SearchResult#modseq to the search response.
510512
# - Updates #thread and #uid_thread with the +MODSEQ+ search criterion
@@ -1353,6 +1355,12 @@ def login(user, password)
13531355
# or when existing messages are expunged; see #add_response_handler for a
13541356
# way to detect these events.
13551357
#
1358+
# When the +condstore+ keyword argument is true, the server is told to
1359+
# enable the extension. If +mailbox+ supports persistence of mod-sequences,
1360+
# the +HIGHESTMODSEQ+ ResponseCode will be sent as an untagged response to
1361+
# #select and all `FETCH` responses will include FetchData#modseq.
1362+
# Otherwise, the +NOMODSEQ+ ResponseCode will be sent.
1363+
#
13561364
# A Net::IMAP::NoResponseError is raised if the mailbox does not
13571365
# exist or is for some reason non-selectable.
13581366
#
@@ -1365,10 +1373,17 @@ def login(user, password)
13651373
# response code indicating that the mailstore does not support persistent
13661374
# UIDs:
13671375
# imap.responses("NO", &:last)&.code&.name == "UIDNOTSTICKY"
1368-
def select(mailbox)
1376+
#
1377+
# If [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html]] is supported,
1378+
# the +condstore+ keyword parameter may be used.
1379+
# imap.select("mbox", condstore: true)
1380+
# modseq = imap.responses("HIGHESTMODSEQ", &:last)
1381+
def select(mailbox, condstore: false)
1382+
args = ["SELECT", mailbox]
1383+
args << ["CONDSTORE"] if condstore
13691384
synchronize do
13701385
@responses.clear
1371-
send_command("SELECT", mailbox)
1386+
send_command(*args)
13721387
end
13731388
end
13741389

@@ -1381,10 +1396,12 @@ def select(mailbox)
13811396
# exist or is for some reason non-examinable.
13821397
#
13831398
# Related: #select
1384-
def examine(mailbox)
1399+
def examine(mailbox, condstore: false)
1400+
args = ["EXAMINE", mailbox]
1401+
args << ["CONDSTORE"] if condstore
13851402
synchronize do
13861403
@responses.clear
1387-
send_command("EXAMINE", mailbox)
1404+
send_command(*args)
13881405
end
13891406
end
13901407

test/net/imap/fake_server/command_reader.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def parse(buf)
3333
/\A([^ ]+) ((?:UID )?\w+)(?: (.+))?\r\n\z/min =~ buf or
3434
raise "bad request: %p" [buf]
3535
case $2.upcase
36-
when "LOGIN", "SELECT", "ENABLE", "AUTHENTICATE"
36+
when "LOGIN", "SELECT", "EXAMINE", "ENABLE", "AUTHENTICATE"
3737
Command.new $1, $2, scan_astrings($3), buf
3838
else
3939
Command.new $1, $2, $3, buf # TODO...

test/net/imap/fake_server/command_router.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ def handler_for(command)
132132
permanentflags: %i[Deleted Seen *].freeze,
133133
}.freeze
134134

135-
on "SELECT" do |resp|
135+
def select_handler(command, resp)
136136
state.user or return resp.fail_bad_state(state)
137137
name, args = resp.args
138138
name or return resp.fail_bad_args
139139
name = name.upcase if name.to_s.casecmp? "inbox"
140140
mbox = config.mailboxes[name]
141-
mbox or return resp.fail_no "invalid mailbox"
141+
mbox or return resp.fail_no "invalid mailbox %p" % [name]
142142
state.select mbox: mbox, args: args
143143
attrs = RFC3501_6_3_1_SELECT_EXAMPLE_DATA.merge mbox.to_h
144144
resp.untagged "%{exists} EXISTS" % attrs
@@ -153,9 +153,13 @@ def handler_for(command)
153153
resp.untagged "OK [PERMANENTFLAGS (%s)] Limited" % [
154154
flags(attrs[:permanentflags])
155155
]
156-
resp.done_ok code: "READ-WRITE"
156+
code = command == "SELECT" ? "READ-WRITE" : "READ-ONLY"
157+
resp.done_ok code: code
157158
end
158159

160+
on "SELECT" do |resp| select_handler "SELECT", resp end
161+
on "EXAMINE" do |resp| select_handler "EXAMINE", resp end
162+
159163
on "CLOSE", "UNSELECT" do |resp|
160164
resp.args.nil? or return resp.fail_bad_args
161165
state.unselect

test/net/imap/test_imap.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,22 @@ def test_clear_responses
11351135
end
11361136
end
11371137

1138+
test "#select with condstore" do
1139+
with_fake_server do |server, imap|
1140+
imap.select "inbox", condstore: true
1141+
assert_equal("RUBY0001 SELECT inbox (CONDSTORE)",
1142+
server.commands.pop.raw.strip)
1143+
end
1144+
end
1145+
1146+
test "#examine with condstore" do
1147+
with_fake_server do |server, imap|
1148+
imap.examine "inbox", condstore: true
1149+
assert_equal("RUBY0001 EXAMINE inbox (CONDSTORE)",
1150+
server.commands.pop.raw.strip)
1151+
end
1152+
end
1153+
11381154
def test_close
11391155
with_fake_server(select: "inbox") do |server, imap|
11401156
resp = imap.close

0 commit comments

Comments
 (0)