From 3bb21086c35979ebe75f61a46bea7a0ce594b8b1 Mon Sep 17 00:00:00 2001 From: nick evans Date: Thu, 28 Sep 2023 13:10:18 -0400 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20`send=5Fcommand?= =?UTF-8?q?=5Fwith=5Fcontinuations`=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- lib/net/imap.rb | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/net/imap.rb b/lib/net/imap.rb index e3d6b0dd..69fdc3f1 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -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 @@ -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|