Skip to content

Commit

Permalink
♻️ Extract send_command_with_continuations method
Browse files Browse the repository at this point in the history
Abstracts running a command with a continuation handler.

In the base specifications (both RFC-3501 and RFC-9051), the only
command to need this is `AUTHENTICATE`.  The only other continuations
are for sending literals, which are simple command arguments.  Are there
any IMAP extensions that use continuations in this way?

Even with only one command, this still makes that code a little more
readable.  More importantly, it also simplifies the creation of a
generic SASL protocol adapter, for use by `net-sasl`, `net-pop`, and
others.
  • Loading branch information
nevans committed Sep 29, 2023
1 parent 80c6e96 commit 3bb2108
Showing 1 changed file with 17 additions and 8 deletions.
25 changes: 17 additions & 8 deletions lib/net/imap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1256,14 +1256,11 @@ def authenticate(mechanism, *creds, sasl_ir: true, **props, &callback)
response = authenticator.process(nil)
cmdargs << (response.empty? ? "=" : [response].pack("m0"))
end
result = send_command(*cmdargs) do |resp|
if resp.instance_of?(ContinuationRequest)
challenge = resp.data.text.unpack1("m")
response = authenticator.process(challenge)
response = [response].pack("m0")
put_string(response + CRLF)
end
end
result = send_command_with_continuations(*cmdargs) {|data|
challenge = data.unpack1("m")
response = authenticator.process challenge
[response].pack("m0")
}
if authenticator.respond_to?(:done?) && !authenticator.done?
logout!
raise SASL::AuthenticationIncomplete, result
Expand Down Expand Up @@ -2571,6 +2568,18 @@ def capabilities_from_resp_code(resp)

#############################

# Calls send_command, yielding the text of each ContinuationRequest and
# responding with each block result. Returns TaggedResponse. Raises
# NoResponseError or BadResponseError.
def send_command_with_continuations(cmd, *args)
send_command(cmd, *args) do |server_response|
if server_response.instance_of?(ContinuationRequest)
client_response = yield server_response.data.text
put_string(client_response + CRLF)
end
end
end

def send_command(cmd, *args, &block)
synchronize do
args.each do |i|
Expand Down

0 comments on commit 3bb2108

Please sign in to comment.