# frozen_string_literal: truerequire"forwardable"moduleNetclassIMAPmoduleSASL# This API is *experimental*, and may change.## TODO: use with more clients, to verify the API can accommodate them.## Represents the client to a SASL::AuthenticationExchange. By default,# most methods simply delegate to #client. Clients should subclass# SASL::ClientAdapter and override methods as needed to match the# semantics of this API to their API.## Subclasses should also include a protocol adapter mixin when the default# ProtocolAdapters::Generic isn't sufficient.## === Protocol Requirements## {RFC4422 ยง4}[https://www.rfc-editor.org/rfc/rfc4422.html#section-4]# lists requirements for protocol specifications to offer SASL. Where# possible, ClientAdapter delegates the handling of these requirements to# SASL::ProtocolAdapters.classClientAdapterextendForwardableincludeProtocolAdapters::Generic# The client that handles communication with the protocol server.## Most ClientAdapter methods are simply delegated to #client by default.attr_reader:client# +command_proc+ can used to avoid exposing private methods on #client.# It's value is set by the block that is passed to ::new, and it is used# by the default implementation of #run_command. Subclasses that# override #run_command may use #command_proc for any other purpose they# find useful.## In the default implementation of #run_command, command_proc is called# with the protocols authenticate +command+ name, the +mechanism+ name,# an _optional_ +initial_response+ argument, and a +continuations+# block. command_proc must run the protocol command with the arguments# sent to it, _yield_ the payload of each continuation, respond to the# continuation with the result of each _yield_, and _return_ the# command's successful result. Non-successful results *MUST* raise# an exception.attr_reader:command_proc# By default, this simply sets the #client and #command_proc attributes.# Subclasses may override it, for example: to set the appropriate# command_proc automatically.definitialize(client,&command_proc)@client,@command_proc=client,command_procend# Attempt to authenticate #client to the server.## By default, this simply delegates to# AuthenticationExchange.authenticate.defauthenticate(...)AuthenticationExchange.authenticate(self,...)end### method: sasl_ir_capable?# Do the protocol, server, and client all support an initial response?def_delegator:client,:sasl_ir_capable?### method: auth_capable?# call-seq: auth_capable?(mechanism)## Does the server advertise support for the +mechanism+?def_delegator:client,:auth_capable?# Calls command_proc with +command_name+ (see# SASL::ProtocolAdapters::Generic#command_name),# +mechanism+, +initial_response+, and a +continuations_handler+ block.# The +initial_response+ is optional; when it's nil, it won't be sent to# command_proc.## Yields each continuation payload, responds to the server with the# result of each yield, and returns the result. Non-successful results# *MUST* raise an exception. Exceptions in the block *MUST* cause the# command to fail.## Subclasses that override this may use #command_proc differently.defrun_command(mechanism,initial_response=nil,&continuations_handler)command_procorraiseError,"initialize with block or override"args=[command_name,mechanism,initial_response].compactcommand_proc.call(*args,&continuations_handler)end### method: host# The hostname to which the client connected.def_delegator:client,:host### method: port# The destination port to which the client connected.def_delegator:client,:port# Returns an array of server responses errors raised by run_command.# Exceptions in this array won't drop the connection.defresponse_errors;[]end### method: drop_connection# Drop the connection gracefully, sending a "LOGOUT" command as needed.def_delegator:client,:drop_connection### method: drop_connection!# Drop the connection abruptly, closing the socket without logging out.def_delegator:client,:drop_connection!endendendend