Skip to content

Commit

Permalink
🔀 Merge pull request #345 from ruby/search-parenthesized-lists
Browse files Browse the repository at this point in the history
✨ Enable parenthesized lists in search criteria
  • Loading branch information
nevans authored Nov 8, 2024
2 parents 799cc94 + 1d9afd5 commit 2d6dbde
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
25 changes: 19 additions & 6 deletions lib/net/imap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1949,9 +1949,13 @@ def uid_expunge(uid_set)
# * +Range+
# * <tt>-1</tt> and +:*+ -- both translate to <tt>*</tt>
# * responds to +#to_sequence_set+
# * nested +Array+
# * +Array+, when each element is one of the above types, a positive
# +Integer+, a sequence-set formatted +String+, or a deeply nested
# +Array+ of these same types.
# * Any +String+ is sent verbatim when it is a valid \IMAP atom,
# and encoded as an \IMAP quoted or literal string otherwise.
# * Any other nested +Array+ is encoded as a parenthesized list, to group
# multiple search keys (e.g., for use with +OR+ and +NOT+).
# * Any other +Integer+ (besides <tt>-1</tt>) will be sent as +#to_s+.
# * +Date+ objects will be encoded as an \IMAP date (see ::encode_date).
#
Expand All @@ -1976,13 +1980,13 @@ def uid_expunge(uid_set)
# The following searches send the exact same command to the server:
#
# # criteria array, charset arg
# imap.search(%w[OR UNSEEN FLAGGED SUBJECT foo], "UTF-8")
# imap.search(["OR", "UNSEEN", %w(FLAGGED SUBJECT foo)], "UTF-8")
# # criteria string, charset arg
# imap.search("OR UNSEEN FLAGGED SUBJECT foo", "UTF-8")
# imap.search("OR UNSEEN (FLAGGED SUBJECT foo)", "UTF-8")
# # criteria array contains charset arg
# imap.search(%w[CHARSET UTF-8 OR UNSEEN FLAGGED SUBJECT foo])
# imap.search([*%w[CHARSET UTF-8], "OR", "UNSEEN", %w(FLAGGED SUBJECT foo)])
# # criteria string contains charset arg
# imap.search("CHARSET UTF-8 OR UNSEEN FLAGGED SUBJECT foo")
# imap.search("CHARSET UTF-8 OR UNSEEN (FLAGGED SUBJECT foo)")
#
# ===== Search keys
#
Expand Down Expand Up @@ -3208,11 +3212,20 @@ def coerce_search_arg_to_seqset?(obj)
case obj
when Set, -1, :* then true
when Range then true
when Array then true
when Array then obj.all? { coerce_search_array_arg_to_seqset? _1 }
else obj.respond_to?(:to_sequence_set)
end
end

def coerce_search_array_arg_to_seqset?(obj)
case obj
when Integer then obj.positive? || obj == -1
when String then ResponseParser::Patterns::SEQUENCE_SET_STR.match?(obj.b)
else
coerce_search_arg_to_seqset?(obj)
end
end

def build_ssl_ctx(ssl)
if ssl
params = (Hash.try_convert(ssl) || {}).freeze
Expand Down
12 changes: 12 additions & 0 deletions test/net/imap/test_imap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,18 @@ def seqset_coercible.to_sequence_set
[1..22, 30..-1]])
cmd = server.commands.pop
assert_equal ["UID SEARCH", "subject hello 1:22,30:*"], [cmd.name, cmd.args]

assert_equal search_result, imap.search(
"RETURN (COUNT) NOT (FLAGGED (OR SEEN ANSWERED))"
)
cmd = server.commands.pop
assert_equal "RETURN (COUNT) NOT (FLAGGED (OR SEEN ANSWERED))", cmd.args

assert_equal search_result, imap.search([
"RETURN", %w(MIN MAX COUNT), "NOT", ["FLAGGED", %w(OR SEEN ANSWERED)]
])
cmd = server.commands.pop
assert_equal "RETURN (MIN MAX COUNT) NOT (FLAGGED (OR SEEN ANSWERED))", cmd.args
end
end

Expand Down

0 comments on commit 2d6dbde

Please sign in to comment.