Skip to content

Commit 226ec58

Browse files
committed
Merge branch 'master-3.3' into dist/3.3/noble
2 parents 6fd61b2 + dd2f417 commit 226ec58

File tree

139 files changed

+2275
-745
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

139 files changed

+2275
-745
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

.bundle/gems/net-imap-0.4.19/lib/net/imap.rb renamed to .bundle/gems/net-imap-0.4.21/lib/net/imap.rb

Lines changed: 105 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,16 @@ module Net
4343
# To work on the messages within a mailbox, the client must
4444
# first select that mailbox, using either #select or #examine
4545
# (for read-only access). Once the client has successfully
46-
# selected a mailbox, they enter the "_selected_" state, and that
46+
# selected a mailbox, they enter the +selected+ state, and that
4747
# mailbox becomes the _current_ mailbox, on which mail-item
4848
# related commands implicitly operate.
4949
#
50+
# === Connection state
51+
#
52+
# Once an IMAP connection is established, the connection is in one of four
53+
# states: <tt>not authenticated</tt>, +authenticated+, +selected+, and
54+
# +logout+. Most commands are valid only in certain states.
55+
#
5056
# === Sequence numbers and UIDs
5157
#
5258
# Messages have two sorts of identifiers: message sequence
@@ -199,6 +205,42 @@ module Net
199205
#
200206
# This script invokes the FETCH command and the SEARCH command concurrently.
201207
#
208+
# When running multiple commands, care must be taken to avoid ambiguity. For
209+
# example, SEARCH responses are ambiguous about which command they are
210+
# responding to, so search commands should not run simultaneously, unless the
211+
# server supports +ESEARCH+ {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731] or
212+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]. See {RFC9051
213+
# §5.5}[https://www.rfc-editor.org/rfc/rfc9051.html#section-5.5] for
214+
# other examples of command sequences which should not be pipelined.
215+
#
216+
# == Unbounded memory use
217+
#
218+
# Net::IMAP reads server responses in a separate receiver thread per client.
219+
# Unhandled response data is saved to #responses, and response_handlers run
220+
# inside the receiver thread. See the list of methods for {handling server
221+
# responses}[rdoc-ref:Net::IMAP@Handling+server+responses], below.
222+
#
223+
# Because the receiver thread continuously reads and saves new responses, some
224+
# scenarios must be careful to avoid unbounded memory use:
225+
#
226+
# * Commands such as #list or #fetch can have an enormous number of responses.
227+
# * Commands such as #fetch can result in an enormous size per response.
228+
# * Long-lived connections will gradually accumulate unsolicited server
229+
# responses, especially +EXISTS+, +FETCH+, and +EXPUNGE+ responses.
230+
# * A buggy or untrusted server could send inappropriate responses, which
231+
# could be very numerous, very large, and very rapid.
232+
#
233+
# Use paginated or limited versions of commands whenever possible.
234+
#
235+
# Use Config#max_response_size to impose a limit on incoming server responses
236+
# as they are being read. <em>This is especially important for untrusted
237+
# servers.</em>
238+
#
239+
# Use #add_response_handler to handle responses after each one is received.
240+
# Use the +response_handlers+ argument to ::new to assign response handlers
241+
# before the receiver thread is started. Use #extract_responses,
242+
# #clear_responses, or #responses (with a block) to prune responses.
243+
#
202244
# == Errors
203245
#
204246
# An \IMAP server can send three different types of responses to indicate
@@ -260,8 +302,9 @@ module Net
260302
#
261303
# - Net::IMAP.new: Creates a new \IMAP client which connects immediately and
262304
# waits for a successful server greeting before the method returns.
305+
# - #connection_state: Returns the connection state.
263306
# - #starttls: Asks the server to upgrade a clear-text connection to use TLS.
264-
# - #logout: Tells the server to end the session. Enters the "_logout_" state.
307+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
265308
# - #disconnect: Disconnects the connection (without sending #logout first).
266309
# - #disconnected?: True if the connection has been closed.
267310
#
@@ -317,37 +360,36 @@ module Net
317360
# <em>In general, #capable? should be used rather than explicitly sending a
318361
# +CAPABILITY+ command to the server.</em>
319362
# - #noop: Allows the server to send unsolicited untagged #responses.
320-
# - #logout: Tells the server to end the session. Enters the "_logout_" state.
363+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
321364
#
322365
# ==== Not Authenticated state
323366
#
324367
# In addition to the commands for any state, the following commands are valid
325-
# in the "<em>not authenticated</em>" state:
368+
# in the +not_authenticated+ state:
326369
#
327370
# - #starttls: Upgrades a clear-text connection to use TLS.
328371
#
329372
# <em>Requires the +STARTTLS+ capability.</em>
330373
# - #authenticate: Identifies the client to the server using the given
331374
# {SASL mechanism}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
332-
# and credentials. Enters the "_authenticated_" state.
375+
# and credentials. Enters the +authenticated+ state.
333376
#
334377
# <em>The server should list <tt>"AUTH=#{mechanism}"</tt> capabilities for
335378
# supported mechanisms.</em>
336379
# - #login: Identifies the client to the server using a plain text password.
337-
# Using #authenticate is generally preferred. Enters the "_authenticated_"
338-
# state.
380+
# Using #authenticate is preferred. Enters the +authenticated+ state.
339381
#
340382
# <em>The +LOGINDISABLED+ capability</em> <b>must NOT</b> <em>be listed.</em>
341383
#
342384
# ==== Authenticated state
343385
#
344386
# In addition to the commands for any state, the following commands are valid
345-
# in the "_authenticated_" state:
387+
# in the +authenticated+ state:
346388
#
347389
# - #enable: Enables backwards incompatible server extensions.
348390
# <em>Requires the +ENABLE+ or +IMAP4rev2+ capability.</em>
349-
# - #select: Open a mailbox and enter the "_selected_" state.
350-
# - #examine: Open a mailbox read-only, and enter the "_selected_" state.
391+
# - #select: Open a mailbox and enter the +selected+ state.
392+
# - #examine: Open a mailbox read-only, and enter the +selected+ state.
351393
# - #create: Creates a new mailbox.
352394
# - #delete: Permanently remove a mailbox.
353395
# - #rename: Change the name of a mailbox.
@@ -369,12 +411,12 @@ module Net
369411
#
370412
# ==== Selected state
371413
#
372-
# In addition to the commands for any state and the "_authenticated_"
373-
# commands, the following commands are valid in the "_selected_" state:
414+
# In addition to the commands for any state and the +authenticated+
415+
# commands, the following commands are valid in the +selected+ state:
374416
#
375-
# - #close: Closes the mailbox and returns to the "_authenticated_" state,
417+
# - #close: Closes the mailbox and returns to the +authenticated+ state,
376418
# expunging deleted messages, unless the mailbox was opened as read-only.
377-
# - #unselect: Closes the mailbox and returns to the "_authenticated_" state,
419+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
378420
# without expunging any messages.
379421
# <em>Requires the +UNSELECT+ or +IMAP4rev2+ capability.</em>
380422
# - #expunge: Permanently removes messages which have the Deleted flag set.
@@ -395,7 +437,7 @@ module Net
395437
#
396438
# ==== Logout state
397439
#
398-
# No \IMAP commands are valid in the "_logout_" state. If the socket is still
440+
# No \IMAP commands are valid in the +logout+ state. If the socket is still
399441
# open, Net::IMAP will close it after receiving server confirmation.
400442
# Exceptions will be raised by \IMAP commands that have already started and
401443
# are waiting for a response, as well as any that are called after logout.
@@ -449,7 +491,7 @@ module Net
449491
# ==== RFC3691: +UNSELECT+
450492
# Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
451493
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
452-
# - #unselect: Closes the mailbox and returns to the "_authenticated_" state,
494+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
453495
# without expunging any messages.
454496
#
455497
# ==== RFC4314: +ACL+
@@ -719,14 +761,15 @@ module Net
719761
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
720762
#
721763
class IMAP < Protocol
722-
VERSION = "0.4.19"
764+
VERSION = "0.4.21"
723765

724766
# Aliases for supported capabilities, to be used with the #enable command.
725767
ENABLE_ALIASES = {
726768
utf8: "UTF8=ACCEPT",
727769
"UTF8=ONLY" => "UTF8=ACCEPT",
728770
}.freeze
729771

772+
autoload :ResponseReader, File.expand_path("imap/response_reader", __dir__)
730773
autoload :SASL, File.expand_path("imap/sasl", __dir__)
731774
autoload :SASLAdapter, File.expand_path("imap/sasl_adapter", __dir__)
732775
autoload :StringPrep, File.expand_path("imap/stringprep", __dir__)
@@ -741,9 +784,11 @@ class IMAP < Protocol
741784
def self.config; Config.global end
742785

743786
# Returns the global debug mode.
787+
# Delegates to {Net::IMAP.config.debug}[rdoc-ref:Config#debug].
744788
def self.debug; config.debug end
745789

746790
# Sets the global debug mode.
791+
# Delegates to {Net::IMAP.config.debug=}[rdoc-ref:Config#debug=].
747792
def self.debug=(val)
748793
config.debug = val
749794
end
@@ -764,7 +809,7 @@ class << self
764809
alias default_ssl_port default_tls_port
765810
end
766811

767-
# Returns the initial greeting the server, an UntaggedResponse.
812+
# Returns the initial greeting sent by the server, an UntaggedResponse.
768813
attr_reader :greeting
769814

770815
# The client configuration. See Net::IMAP::Config.
@@ -773,13 +818,28 @@ class << self
773818
# Net::IMAP.config.
774819
attr_reader :config
775820

776-
# Seconds to wait until a connection is opened.
777-
# If the IMAP object cannot open a connection within this time,
778-
# it raises a Net::OpenTimeout exception. The default value is 30 seconds.
779-
def open_timeout; config.open_timeout end
821+
##
822+
# :attr_reader: open_timeout
823+
# Seconds to wait until a connection is opened. Also used by #starttls.
824+
# Delegates to {config.open_timeout}[rdoc-ref:Config#open_timeout].
780825

826+
##
827+
# :attr_reader: idle_response_timeout
781828
# Seconds to wait until an IDLE response is received.
782-
def idle_response_timeout; config.idle_response_timeout end
829+
# Delegates to {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout].
830+
831+
##
832+
# :attr_accessor: max_response_size
833+
#
834+
# The maximum allowed server response size, in bytes.
835+
# Delegates to {config.max_response_size}[rdoc-ref:Config#max_response_size].
836+
837+
# :stopdoc:
838+
def open_timeout; config.open_timeout end
839+
def idle_response_timeout; config.idle_response_timeout end
840+
def max_response_size; config.max_response_size end
841+
def max_response_size=(val) config.max_response_size = val end
842+
# :startdoc:
783843

784844
# The hostname this client connected to
785845
attr_reader :host
@@ -835,6 +895,12 @@ def idle_response_timeout; config.idle_response_timeout end
835895
#
836896
# See DeprecatedClientOptions.new for deprecated SSL arguments.
837897
#
898+
# [response_handlers]
899+
# A list of response handlers to be added before the receiver thread is
900+
# started. This ensures every server response is handled, including the
901+
# #greeting. Note that the greeting is handled in the current thread, but
902+
# all other responses are handled in the receiver thread.
903+
#
838904
# [config]
839905
# A Net::IMAP::Config object to use as the basis for #config. By default,
840906
# the global Net::IMAP.config is used.
@@ -906,7 +972,7 @@ def idle_response_timeout; config.idle_response_timeout end
906972
# [Net::IMAP::ByeResponseError]
907973
# Connected to the host successfully, but it immediately said goodbye.
908974
#
909-
def initialize(host, port: nil, ssl: nil,
975+
def initialize(host, port: nil, ssl: nil, response_handlers: nil,
910976
config: Config.global, **config_options)
911977
super()
912978
# Config options
@@ -929,6 +995,7 @@ def initialize(host, port: nil, ssl: nil,
929995
@receiver_thread = nil
930996
@receiver_thread_exception = nil
931997
@receiver_thread_terminating = false
998+
response_handlers&.each do add_response_handler(_1) end
932999

9331000
# Client Protocol Sender (including state for currently running commands)
9341001
@tag_prefix = "RUBY"
@@ -944,6 +1011,7 @@ def initialize(host, port: nil, ssl: nil,
9441011
# Connection
9451012
@tls_verified = false
9461013
@sock = tcp_socket(@host, @port)
1014+
@reader = ResponseReader.new(self, @sock)
9471015
start_tls_session if ssl_ctx
9481016
start_imap_connection
9491017

@@ -1204,6 +1272,10 @@ def logout!
12041272
# both successful. Any error indicates that the connection has not been
12051273
# secured.
12061274
#
1275+
# After the server agrees to start a TLS connection, this method waits up to
1276+
# {config.open_timeout}[rdoc-ref:Config#open_timeout] before raising
1277+
# +Net::OpenTimeout+.
1278+
#
12071279
# *Note:*
12081280
# >>>
12091281
# Any #response_handlers added before STARTTLS should be aware that the
@@ -2706,6 +2778,10 @@ def response_handlers
27062778
# end
27072779
# }
27082780
#
2781+
# Response handlers can also be added when the client is created before the
2782+
# receiver thread is started, by the +response_handlers+ argument to ::new.
2783+
# This ensures every server response is handled, including the #greeting.
2784+
#
27092785
# Related: #remove_response_handler, #response_handlers
27102786
def add_response_handler(handler = nil, &block)
27112787
raise ArgumentError, "two Procs are passed" if handler && block
@@ -2732,6 +2808,7 @@ def remove_response_handler(handler)
27322808
def start_imap_connection
27332809
@greeting = get_server_greeting
27342810
@capabilities = capabilities_from_resp_code @greeting
2811+
@response_handlers.each do |handler| handler.call(@greeting) end
27352812
@receiver_thread = start_receiver_thread
27362813
rescue Exception
27372814
@sock.close
@@ -2860,23 +2937,10 @@ def get_tagged_response(tag, cmd, timeout = nil)
28602937
end
28612938

28622939
def get_response
2863-
buff = String.new
2864-
while true
2865-
s = @sock.gets(CRLF)
2866-
break unless s
2867-
buff.concat(s)
2868-
if /\{(\d+)\}\r\n/n =~ s
2869-
s = @sock.read($1.to_i)
2870-
buff.concat(s)
2871-
else
2872-
break
2873-
end
2874-
end
2940+
buff = @reader.read_response_buffer
28752941
return nil if buff.length == 0
2876-
if config.debug?
2877-
$stderr.print(buff.gsub(/^/n, "S: "))
2878-
end
2879-
return @parser.parse(buff)
2942+
$stderr.print(buff.gsub(/^/n, "S: ")) if config.debug?
2943+
@parser.parse(buff)
28802944
end
28812945

28822946
#############################
@@ -3077,6 +3141,7 @@ def start_tls_session
30773141
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
30783142
raise "cannot start TLS without SSLContext" unless ssl_ctx
30793143
@sock = SSLSocket.new(@sock, ssl_ctx)
3144+
@reader = ResponseReader.new(self, @sock)
30803145
@sock.sync_close = true
30813146
@sock.hostname = @host if @sock.respond_to? :hostname=
30823147
ssl_socket_connect(@sock, open_timeout)

0 commit comments

Comments
 (0)