From 8e2e403293287f9a7bf5341094be6206a745754f Mon Sep 17 00:00:00 2001
From: nick evans <nick@rubinick.dev>
Date: Wed, 2 Apr 2025 20:50:15 -0400
Subject: [PATCH 13/23] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20ResponseRe?=
 =?UTF-8?q?ader=20from=20get=5Fresponse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

It's nice to extract a little bit of the complexity from the core
`Net::IMAP` class.  But my primary motivation was so that I could
directly test this code quickly and in isolation from needing to
simulate a full IMAP connection.
---
 .bundle/gems/net-imap-0.3.8/lib/net/imap.rb                       | 24 +++----------
 .bundle/gems/net-imap-0.3.8/lib/net/imap/response_reader.rb       | 38 +++++++++++++++++++++
 2 files changed, 43 insertions(+), 19 deletions(-)
 create mode 100644 .bundle/gems/net-imap-0.3.8/lib/net/imap/response_reader.rb

diff --git a/.bundle/gems/net-imap-0.3.8/lib/net/imap.rb b/lib/net/imap.rb
index 1370317..9560d07 100644
--- a/.bundle/gems/net-imap-0.3.8/lib/net/imap.rb
+++ b/.bundle/gems/net-imap-0.3.8/lib/net/imap.rb
@@ -737,6 +737,8 @@ module Net
   class IMAP < Protocol
     VERSION = "0.3.8"
 
+    autoload :ResponseReader, File.expand_path("imap/response_reader", __dir__)
+
     include MonitorMixin
     if defined?(OpenSSL::SSL)
       include OpenSSL
@@ -2074,6 +2076,7 @@ module Net
       @idle_response_timeout = options[:idle_response_timeout] || 5
       @parser = ResponseParser.new
       @sock = tcp_socket(@host, @port)
+      @reader = ResponseReader.new(self, @sock)
       begin
         if options[:ssl]
           start_tls_session(options[:ssl])
@@ -2225,30 +2228,12 @@ module Net
     end
 
     def get_response
-      buff = String.new
-      catch :eof do
-        while true
-          get_response_line(buff)
-          break unless /\{(\d+)\}\r\n\z/n =~ buff
-          get_response_literal(buff, $1.to_i)
-        end
-      end
+      buff = @reader.read_response_buffer
       return nil if buff.length == 0
       $stderr.print(buff.gsub(/^/n, "S: ")) if @@debug
       @parser.parse(buff)
     end
 
-    def get_response_line(buff)
-      line = @sock.gets(CRLF) or throw :eof
-      buff << line
-    end
-
-    def get_response_literal(buff, literal_size)
-      literal = String.new(capacity: literal_size)
-      @sock.read(literal_size, literal) or throw :eof
-      buff << literal
-    end
-
     #############################
 
     def record_response(name, data)
@@ -2428,6 +2413,7 @@ module Net
         context.verify_callback = VerifyCallbackProc
       end
       @sock = SSLSocket.new(@sock, context)
+      @reader = ResponseReader.new(self, @sock)
       @sock.sync_close = true
       @sock.hostname = @host if @sock.respond_to? :hostname=
       ssl_socket_connect(@sock, @open_timeout)
diff --git a/.bundle/gems/net-imap-0.3.8/lib/net/imap/response_reader.rb b/lib/net/imap/response_reader.rb
new file mode 100644
index 0000000..57770e3
--- /dev/null
+++ b/.bundle/gems/net-imap-0.3.8/lib/net/imap/response_reader.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Net
+  class IMAP
+    # See https://www.rfc-editor.org/rfc/rfc9051#section-2.2.2
+    class ResponseReader # :nodoc:
+      attr_reader :client
+
+      def initialize(client, sock)
+        @client, @sock = client, sock
+      end
+
+      def read_response_buffer
+        buff = String.new
+        catch :eof do
+          while true
+            read_line(buff)
+            break unless /\{(\d+)\}\r\n\z/n =~ buff
+            read_literal(buff, $1.to_i)
+          end
+        end
+        buff
+      end
+
+      private
+
+      def read_line(buff)
+        buff << (@sock.gets(CRLF) or throw :eof)
+      end
+
+      def read_literal(buff, literal_size)
+        literal = String.new(capacity: literal_size)
+        buff << (@sock.read(literal_size, literal) or throw :eof)
+      end
+
+    end
+  end
+end
-- 
2.27.0