Skip to content

📚 More rdoc updates, all related to capabilities #159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 22, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 94 additions & 92 deletions lib/net/imap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ module Net
# end
# imap.expunge
#
# == Server capabilities and protocol extensions
# == Capabilities
#
# Net::IMAP does not _currently_ modify its behaviour according to the
# server's advertised #capabilities. Users of this class must check that the
Expand Down Expand Up @@ -144,12 +144,12 @@ module Net
#
# === Caching +CAPABILITY+ responses
#
# Net::IMAP stores and discards capability
# data according to the requirements and recommendations in IMAP4rev2
# {§6.1.1}[https://www.rfc-editor.org/rfc/rfc9051#section-6.1.1],
# Net::IMAP automatically stores and discards capability data according to the
# the requirements and recommendations in
# {IMAP4rev2 §6.1.1}[https://www.rfc-editor.org/rfc/rfc9051#section-6.1.1],
# {§6.2}[https://www.rfc-editor.org/rfc/rfc9051#section-6.2], and
# {§7.1}[https://www.rfc-editor.org/rfc/rfc9051#section-7.1].
# Use #capable?, #auth_capable?, or #capabilities to this caching and avoid
# Use #capable?, #auth_capable?, or #capabilities to use this cache and avoid
# sending the #capability command unnecessarily.
#
# The server may advertise its initial capabilities using the +CAPABILITY+
Expand All @@ -166,6 +166,10 @@ module Net
#
# === Using IMAP4rev1 extensions
#
# See the {IANA IMAP4 capabilities
# registry}[http://www.iana.org/assignments/imap4-capabilities] for a list of
# all standard capabilities, and their reference RFCs.
#
# IMAP4rev1 servers must not activate behavior that is incompatible with the
# base specification until an explicit client action invokes a capability,
# e.g. sending a command or command argument specific to that capability.
Expand All @@ -179,7 +183,7 @@ module Net
# BadResponseError, or cause other unexpected behavior.
#
# Some capabilities must be explicitly activated using the #enable command.
# See #enable for more details.
# See #enable for details.
#
# == Thread Safety
#
Expand Down Expand Up @@ -751,66 +755,61 @@ def disconnected?
return @sock.closed?
end

# Returns the server capabilities. When available, cached capabilities are
# used without sending a new #capability command to the server.
#
# To ensure case-insensitive capability comparison, use #capable? instead.
#
# Related: #capable?, #auth_capable?, #capability
def capabilities
@capabilities || capability
end

# Returns whether the server supports a given +capability+. When available,
# cached #capabilities are used without sending a new #capability command to
# the server.
#
# See the {IANA IMAP4 capabilities
# registry}[http://www.iana.org/assignments/imap4-capabilities] for a list
# of all standard capabilities, and their reference RFCs.
#
# >>>
# <em>*NOTE:* Net::IMAP does not _currently_ modify its behaviour
# according to the server's advertised capabilities. Users of this class
# must check that the server is #capable? of extension commands or command
# arguments before sending them.</em>
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
#
# <em>Capability requirements—other than +IMAP4rev1+—are listed in the
# documentation for each command method.</em>
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #auth_capable?, #capabilities, #capability, #enable
#
# ===== Caching +CAPABILITY+ responses
#
# Servers may send their capability list unsolicited, using the +CAPABILITY+
# response code or an untagged +CAPABILITY+ response. Cached capabilities
# are discarded after #starttls, #login, or #authenticate. Caching and
# cache invalidation are handled internally by Net::IMAP.
#
def capable?(capability) capabilities.include? capability.to_s.upcase end
alias capability? capable?

# Returns the server capabilities. When available, cached capabilities are
# used without sending a new #capability command to the server.
#
# To ensure a case-insensitive comparison, #capable? can be used instead.
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
#
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #capable?, #auth_capable?, #capability
def capabilities
@capabilities || capability
end

# Returns the #authenticate mechanisms that the server claims to support.
# These are derived from the #capabilities with an <tt>AUTH=</tt> prefix.
#
# This may be different when the connection is cleartext or using TLS. Most
# servers will drop all <tt>AUTH=</tt> mechanisms from #capabilities after
# the connection has authenticated.
#
# Related: #auth_capable?, #capabilities
#
# ===== Example
#
# imap = Net::IMAP.new(hostname, ssl: false)
# imap.capabilities # => ["IMAP4REV1", "LOGINDISABLED"]
# imap.auth_mechanisms # => []
#
# imap.starttls
# imap.capabilities # => ["IMAP4REV1", "AUTH=PLAIN", "AUTH=XOAUTH2",
# "AUTH=OAUTHBEARER", "AUTH=SCRAM-SHA-256"]
# imap.auth_mechanisms # => ["PLAIN", "XOAUTH2", "SCRAM-SHA-256"]
# imap.authenticate("OAUTHBEARER", username, oauth2_access_token)
# # "AUTH=OAUTHBEARER"]
# imap.auth_mechanisms # => ["PLAIN", "XOAUTH2", "OAUTHBEARER"]
#
# imap.authenticate("XOAUTH2", username, oauth2_access_token)
# imap.auth_mechanisms # => []
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
#
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #auth_capable?, #capabilities
#
def auth_mechanisms
capabilities
.grep(/\AAUTH=/i)
Expand All @@ -823,12 +822,15 @@ def auth_mechanisms
# available, cached capabilities are used without sending a new #capability
# command to the server.
#
# Per {[IMAP4rev1 §6.2.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.2],
#
# imap.capable? "AUTH=PLAIN" # => true
# imap.auth_capable? "PLAIN" # => true
# imap.auth_capable? "blurdybloop" # => false
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
#
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #authenticate, #capable?, #capabilities
def auth_capable?(mechanism)
capable? "AUTH=#{mechanism}"
Expand All @@ -837,16 +839,22 @@ def auth_capable?(mechanism)
# Returns whether capabilities have been cached. When true, #capable? and
# #capabilities don't require sending a #capability command to the server.
#

# Returns whether capabilities have been cached. When true, #capable? and
# #capabilities don't require sending a #capability command to the server.
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #capable?, #capability, #clear_cached_capabilities
def capabilities_cached?
!!@capabilities
end

# Clears capabilities that are currently cached by the Net::IMAP client.
# This forces a #capability command to be sent the next time that #capable?
# or #capabilities? are called.
# Clears capabilities that have been remembered by the Net::IMAP client.
# This forces a #capability command to be sent the next time a #capabilities
# query method is called.
#
# Net::IMAP automatically discards its cached capabilities when they can
# change. Explicitly calling this _should_ be unnecessary for well-behaved
# servers.
#
# Related: #capable?, #capability, #capabilities_cached?
def clear_cached_capabilities
synchronize do
clear_responses("CAPABILITY")
Expand All @@ -856,23 +864,22 @@ def clear_cached_capabilities

# Sends a {CAPABILITY command [IMAP4rev1 §6.1.1]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.1.1]
# and returns an array of capabilities that are supported by the server.
# The result will be stored for use by #capable? and #capabilities.
# The result is stored for use by #capable? and #capabilities.
#
# In general, #capable? or #capabilities should be used instead. They cache
# the capability result to avoid sending unnecessary commands. They also
# ensure cache invalidation is handled correctly.
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
#
# >>>
# <em>*NOTE:* Net::IMAP does not _currently_ modify its behaviour
# according to the server's advertised capabilities. Users of this class
# must check that the server is #capable? of extension commands or command
# arguments before sending them.</em>
# Net::IMAP automatically stores and discards capability data according to
# the requirements and recommendations in
# {IMAP4rev2 §6.1.1}[https://www.rfc-editor.org/rfc/rfc9051#section-6.1.1],
# {§6.2}[https://www.rfc-editor.org/rfc/rfc9051#section-6.2], and
# {§7.1}[https://www.rfc-editor.org/rfc/rfc9051#section-7.1].
# Use #capable?, #auth_capable?, or #capabilities to this cache and avoid
# sending the #capability command unnecessarily.
#
# <em>Capability requirements—other than +IMAP4rev1+—are listed in the
# documentation for each command method.</em>
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #capable?, #auth_capable?, #capability, #enable
#
def capability
synchronize do
send_command("CAPABILITY")
Expand Down Expand Up @@ -994,7 +1001,7 @@ def starttls(options = {}, verify = true)
#
# An exception Net::IMAP::NoResponseError is raised if authentication fails.
#
# Related: #login, #starttls
# Related: #login, #starttls, #auth_capable?, #auth_mechanisms
#
# ==== Supported SASL Mechanisms
#
Expand Down Expand Up @@ -1024,40 +1031,28 @@ def starttls(options = {}, verify = true)
# for information on these and other SASL mechanisms.
#
# ===== Capabilities
# Clients should not call #authenticate with mechanisms that are included in the server #capabilities as <tt>"AUTH=#{mechanism}"</tt>.
#
# The server should list <tt>"AUTH=#{mechanism}"</tt> capabilities for
# supported mechanisms. Check #auth_capable? or #auth_mechanisms before
# using a particular mechanism.
#
# if imap.auth_capable? "XOAUTH2"
# imap.authenticate "XOAUTH2", username, oauth2_access_token
# elsif imap.auth_capable? "PLAIN"
# imap.authenticate "PLAIN", username, password
# elsif imap.auth_capable? "DIGEST-MD5"
# imap.authenticate "DIGEST-MD5", username, password
# elsif !imap.capability? "LOGINDISABLED"
# imap.login username, password
# else
# raise "No acceptable authentication mechanism is available"
# end
#
# Server capabilities may change after #starttls, #login, and #authenticate.
# Cached #capabilities will be cleared when this method completes.
# If the TaggedResponse to #authenticate includes updated capabilities, they
# will be cached.
#
# ===== Example
# Use auth_capable? to discover which mechanisms are suuported by the
# server. For authenticators that ignore unhandled keyword arguments, the
# same config can be used for multiple mechanisms:
#
# password = nil # saved locally, so we don't ask more than once
# accesstok = nil # saved locally...
# creds = {
# authcid: username,
# password: proc { password ||= ui.prompt_for_password },
# oauth2_token: proc { accesstok ||= kms.fresh_access_token },
# }
# mechanism = %w[
# OAUTHBEARER XOAUTH2
# SCRAM-SHA-256 SCRAM-SHA-1
# PLAIN
# ].find {|m|
# imap.auth_capable?(m)
# }
# if mechanism
# imap.authenticate mechanism, **creds
# elsif capable? "LOGINDISABLED"
# raise "the server has disabled login"
# else
# imap.login username, password
# end
#
def authenticate(mechanism, ...)
authenticator = self.class.authenticator(mechanism, ...)
send_command("AUTHENTICATE", mechanism) do |resp|
Expand Down Expand Up @@ -1085,10 +1080,17 @@ def authenticate(mechanism, ...)
#
# Related: #authenticate, #starttls
#
# ==== Capabilities
# An IMAP client MUST NOT call #login unless the server advertises the
# ===== Capabilities
#
# An IMAP client MUST NOT call #login when the server advertises the
# +LOGINDISABLED+ capability.
#
# if imap.capability? "LOGINDISABLED"
# raise "Remote server has disabled the login command"
# else
# imap.login username, password
# end
#
# Server capabilities may change after #starttls, #login, and #authenticate.
# Cached capabilities _must_ be invalidated after this method completes.
# The TaggedResponse to #login may include updated capabilities in its
Expand Down