Skip to content

Commit 7dc2006

Browse files
committed
✨ Gather ESEARCH response to #search/#uid_search
* Return empty ESearchResult when no result * Clear SEARCH responses before new search. Note that we don't need to do this for ESEARCH responses, since they are tagged.
1 parent 8780b9f commit 7dc2006

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

lib/net/imap.rb

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,7 +1930,7 @@ def uid_expunge(uid_set)
19301930
end
19311931

19321932
# :call-seq:
1933-
# search(criteria, charset = nil) -> result
1933+
# search(criteria, charset = nil, esearch: false) -> result
19341934
#
19351935
# Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
19361936
# to search the mailbox for messages that match the given search +criteria+,
@@ -1966,6 +1966,11 @@ def uid_expunge(uid_set)
19661966
# "CHARSET", "UTF-8",
19671967
# %w(OR UNSEEN FLAGGED)])
19681968
#
1969+
# +esearch+ controls the return type when the server does not return any
1970+
# search results. If +esearch+ is +true+ or +criteria+ begins with
1971+
# +RETURN+, an empty ESearchResult will be returned. When +esearch+ is
1972+
# +false+, an empty SearchResult will be returned.
1973+
#
19691974
# Related: #uid_search
19701975
#
19711976
# ===== Search criteria
@@ -2974,12 +2979,24 @@ def enforce_logindisabled?
29742979
end
29752980
end
29762981

2977-
def search_internal(cmd, keys, charset = nil)
2982+
def search_internal(cmd, keys, charset = nil, esearch: false)
29782983
keys = normalize_searching_criteria(keys)
29792984
args = charset ? ["CHARSET", charset, *keys] : keys
29802985
synchronize do
2981-
send_command(cmd, *args)
2982-
clear_responses("SEARCH").last || []
2986+
clear_responses("SEARCH")
2987+
result = nil
2988+
send_command(cmd, *args) do |response, tag|
2989+
if response in data: ESearchResult(tag: ^tag) => result
2990+
responses("ESEARCH") { _1.delete(result) }
2991+
end
2992+
end
2993+
if result
2994+
result
2995+
elsif esearch || keys in RawData[/\ARETURN /] | Array[/\ARETURN\z/i, *]
2996+
ESearchResult.new
2997+
else
2998+
clear_responses("SEARCH").last || []
2999+
end
29833000
end
29843001
end
29853002

test/net/imap/test_imap.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,45 @@ def test_unselect
12341234
end
12351235
end
12361236

1237+
test("#search/#uid_search with ESEARCH or IMAP4rev2") do
1238+
with_fake_server do |server, imap|
1239+
# Example from RFC9051, 6.4.4:
1240+
# C: A282 SEARCH RETURN (MIN COUNT) FLAGGED
1241+
# SINCE 1-Feb-1994 NOT FROM "Smith"
1242+
# S: * ESEARCH (TAG "A282") MIN 2 COUNT 3
1243+
# S: A282 OK SEARCH completed
1244+
server.on "SEARCH" do |cmd|
1245+
cmd.untagged "ESEARCH", "(TAG \"unrelated1\") MIN 1 COUNT 2"
1246+
cmd.untagged "ESEARCH", "(TAG %p) MIN 2 COUNT 3" % [cmd.tag]
1247+
cmd.untagged "ESEARCH", "(TAG \"unrelated2\") MIN 222 COUNT 333"
1248+
cmd.done_ok
1249+
end
1250+
result = imap.search(
1251+
'RETURN (MIN COUNT) FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"'
1252+
)
1253+
cmd = server.commands.pop
1254+
assert_equal Net::IMAP::ESearchResult.new(
1255+
cmd.tag, false, [["MIN", 2], ["COUNT", 3]]
1256+
), result
1257+
esearch_responses = imap.clear_responses("ESEARCH")
1258+
assert_equal 2, esearch_responses.count
1259+
refute esearch_responses.include?(result)
1260+
end
1261+
end
1262+
1263+
test("missing server ESEARCH response") do
1264+
with_fake_server do |server, imap|
1265+
# Example from RFC9051, 6.4.4:
1266+
# C: A282 SEARCH RETURN (SAVE) FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"
1267+
# S: A282 OK SEARCH completed, result saved
1268+
server.on "SEARCH" do |cmd| cmd.done_ok "result saved" end
1269+
result = imap.search(
1270+
'RETURN (SAVE) FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"'
1271+
)
1272+
assert_equal Net::IMAP::ESearchResult.new, result
1273+
end
1274+
end
1275+
12371276
test("missing server SEARCH response") do
12381277
with_fake_server do |server, imap|
12391278
server.on "SEARCH", &:done_ok

0 commit comments

Comments
 (0)