net-imap 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of net-imap might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c96e58708687b3fb8ded9def89a66e3ca9d1d83717c76c1579928ed60fb2b52
4
- data.tar.gz: 56c64b20eab875d49b03e7a18f46988850e38865fbd756b0e6db3d7ecaec5975
3
+ metadata.gz: a91d908ae16db12c507a6cf5c0e5eef57e18c97473b2a13a0ab14cf655e9bcb7
4
+ data.tar.gz: 1bdab36cf0779d14e2f414e00aee90d95d2584bfc8d591c11d5104b4071bebb8
5
5
  SHA512:
6
- metadata.gz: 6dc72eab65ac59b09328cad6d1ad9bcc86e4565f05416b6b7de952d2d9d4634f8f272b6e2bf36a0f386ae0acb46de506d28c3856e1a53058fa83f30edfd7275c
7
- data.tar.gz: 6deb8133dd67519bd082ba287db7eda44500048ef30f6e25f43e6955ed4b82f96c690633375dad56af8590b578ea6df846422a8ae54d40e359bfd2795f2d4125
6
+ metadata.gz: 65133026b0746efbdc55a64bd1091da0524e5b922672767f334cec1d0357b31b973380bc8e787ff2430b831375f52050004d718b6308fa9203c9f6710ac2444b
7
+ data.tar.gz: 7e5e9fcac352549585e38b5a86b0198cc1c5996ad129cf9e53ca92f2ef63ea4b37d26ab8c5efd641b19711b2ea04e42622ead203c3afcaa8d420ceaaaa9893c8
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -7,7 +7,7 @@ jobs:
7
7
  name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
8
  strategy:
9
9
  matrix:
10
- ruby: [ head, '3.3', '3.2', '3.1', '3.0', '2.7' ]
10
+ ruby: [ head, '3.1', '3.0', '2.7' ]
11
11
  os: [ ubuntu-latest, macos-latest ]
12
12
  experimental: [false]
13
13
  include:
@@ -20,7 +20,7 @@ jobs:
20
20
  runs-on: ${{ matrix.os }}
21
21
  continue-on-error: ${{ matrix.experimental }}
22
22
  steps:
23
- - uses: actions/checkout@v2
23
+ - uses: actions/checkout@v3
24
24
  - name: Set up Ruby
25
25
  uses: ruby/setup-ruby@v1
26
26
  with:
data/LICENSE.txt CHANGED
@@ -20,3 +20,65 @@ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
20
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
21
  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
22
  SUCH DAMAGE.
23
+
24
+ -------------------------------------------------------------------------
25
+
26
+ This software includes documentation which has been copied from the relevant
27
+ RFCs. The copied documentation is covered by the following licenses:
28
+
29
+ RFC 3501 (Editor: M. Crispin)
30
+ Full Copyright Statement
31
+
32
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
33
+
34
+ This document and translations of it may be copied and furnished to
35
+ others, and derivative works that comment on or otherwise explain it
36
+ or assist in its implementation may be prepared, copied, published
37
+ and distributed, in whole or in part, without restriction of any
38
+ kind, provided that the above copyright notice and this paragraph are
39
+ included on all such copies and derivative works. However, this
40
+ document itself may not be modified in any way, such as by removing
41
+ the copyright notice or references to the Internet Society or other
42
+ Internet organizations, except as needed for the purpose of
43
+ developing Internet standards in which case the procedures for
44
+ copyrights defined in the Internet Standards process must be
45
+ followed, or as required to translate it into languages other than
46
+ English.
47
+
48
+ The limited permissions granted above are perpetual and will not be
49
+ revoked by the Internet Society or its successors or assigns. v This
50
+ document and the information contained herein is provided on an "AS
51
+ IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
52
+ FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
53
+ LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL
54
+ NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY
55
+ OR FITNESS FOR A PARTICULAR PURPOSE.
56
+
57
+
58
+ RFC9051 (Editors: A. Melnikov, B. Leiba)
59
+ Copyright Notice
60
+
61
+ Copyright (c) 2021 IETF Trust and the persons identified as the
62
+ document authors. All rights reserved.
63
+
64
+ This document is subject to BCP 78 and the IETF Trust's Legal
65
+ Provisions Relating to IETF Documents
66
+ (https://trustee.ietf.org/license-info) in effect on the date of
67
+ publication of this document. Please review these documents
68
+ carefully, as they describe your rights and restrictions with respect
69
+ to this document. Code Components extracted from this document must
70
+ include Simplified BSD License text as described in Section 4.e of
71
+ the Trust Legal Provisions and are provided without warranty as
72
+ described in the Simplified BSD License.
73
+
74
+ This document may contain material from IETF Documents or IETF
75
+ Contributions published or made publicly available before November
76
+ 10, 2008. The person(s) controlling the copyright in some of this
77
+ material may not have granted the IETF Trust the right to allow
78
+ modifications of such material outside the IETF Standards Process.
79
+ Without obtaining an adequate license from the person(s) controlling
80
+ the copyright in such materials, this document may not be modified
81
+ outside the IETF Standards Process, and derivative works of it may
82
+ not be created outside the IETF Standards Process, except to format
83
+ it for publication as an RFC or to translate it into languages other
84
+ than English.
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest/md5"
4
-
5
3
  # Authenticator for the "+CRAM-MD5+" SASL mechanism, specified in
6
4
  # RFC2195[https://tools.ietf.org/html/rfc2195]. See Net::IMAP#authenticate.
7
5
  #
@@ -23,7 +21,11 @@ class Net::IMAP::CramMD5Authenticator
23
21
 
24
22
  private
25
23
 
26
- def initialize(user, password)
24
+ def initialize(user, password, warn_deprecation: true, **_ignored)
25
+ if warn_deprecation
26
+ warn "WARNING: CRAM-MD5 mechanism is deprecated." # TODO: recommend SCRAM
27
+ end
28
+ require "digest/md5"
27
29
  @user = user
28
30
  @password = password
29
31
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest/md5"
4
- require "strscan"
5
-
6
3
  # Net::IMAP authenticator for the "`DIGEST-MD5`" SASL mechanism type, specified
7
4
  # in RFC2831(https://tools.ietf.org/html/rfc2831). See Net::IMAP#authenticate.
8
5
  #
@@ -29,8 +26,8 @@ class Net::IMAP::DigestMD5Authenticator
29
26
  sparams[k] = v
30
27
  end
31
28
 
32
- raise DataFormatError, "Bad Challenge: '#{challenge}'" unless c.rest.size == 0
33
- raise Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
29
+ raise Net::IMAP::DataFormatError, "Bad Challenge: '#{challenge}'" unless c.eos?
30
+ raise Net::IMAP::Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
34
31
 
35
32
  response = {
36
33
  :nonce => sparams['nonce'],
@@ -77,11 +74,18 @@ class Net::IMAP::DigestMD5Authenticator
77
74
  end
78
75
  end
79
76
 
80
- def initialize(user, password, authname = nil)
77
+ def initialize(user, password, authname = nil, warn_deprecation: true)
78
+ if warn_deprecation
79
+ warn "WARNING: DIGEST-MD5 SASL mechanism was deprecated by RFC6331."
80
+ # TODO: recommend SCRAM instead.
81
+ end
82
+ require "digest/md5"
83
+ require "strscan"
81
84
  @user, @password, @authname = user, password, authname
82
85
  @nc, @stage = {}, STAGE_ONE
83
86
  end
84
87
 
88
+
85
89
  private
86
90
 
87
91
  STAGE_ONE = :stage_one
@@ -100,7 +104,7 @@ class Net::IMAP::DigestMD5Authenticator
100
104
  def qdval(k, v)
101
105
  return if k.nil? or v.nil?
102
106
  if %w"username authzid realm nonce cnonce digest-uri qop".include? k
103
- v.gsub!(/([\\"])/, "\\\1")
107
+ v = v.gsub(/([\\"])/, "\\\1")
104
108
  return '%s="%s"' % [k, v]
105
109
  else
106
110
  return '%s=%s' % [k, v]
@@ -33,7 +33,10 @@ class Net::IMAP::LoginAuthenticator
33
33
  STATE_USER = :USER
34
34
  STATE_PASSWORD = :PASSWORD
35
35
 
36
- def initialize(user, password)
36
+ def initialize(user, password, warn_deprecation: true, **_ignored)
37
+ if warn_deprecation
38
+ warn "WARNING: LOGIN SASL mechanism is deprecated. Use PLAIN instead."
39
+ end
37
40
  @user = user
38
41
  @password = password
39
42
  @state = STATE_USER
@@ -19,13 +19,15 @@ module Net::IMAP::Authenticators
19
19
 
20
20
  # Builds an authenticator for Net::IMAP#authenticate. +args+ will be passed
21
21
  # directly to the chosen authenticator's +#initialize+.
22
- def authenticator(auth_type, *args)
23
- auth_type = auth_type.upcase
24
- unless authenticators.has_key?(auth_type)
25
- raise ArgumentError,
26
- format('unknown auth type - "%s"', auth_type)
22
+ def authenticator(mechanism, *authargs, **properties, &callback)
23
+ authenticator = authenticators.fetch(mechanism.upcase) do
24
+ raise ArgumentError, 'unknown auth type - "%s"' % mechanism
25
+ end
26
+ if authenticator.respond_to?(:new)
27
+ authenticator.new(*authargs, **properties, &callback)
28
+ else
29
+ authenticator.call(*authargs, **properties, &callback)
27
30
  end
28
- authenticators[auth_type].new(*args)
29
31
  end
30
32
 
31
33
  private
@@ -38,7 +40,8 @@ end
38
40
 
39
41
  Net::IMAP.extend Net::IMAP::Authenticators
40
42
 
41
- require_relative "authenticators/login"
42
43
  require_relative "authenticators/plain"
44
+
45
+ require_relative "authenticators/login"
43
46
  require_relative "authenticators/cram_md5"
44
47
  require_relative "authenticators/digest_md5"
@@ -11,40 +11,6 @@ module Net
11
11
  class DataFormatError < Error
12
12
  end
13
13
 
14
- # Error raised when the socket cannot be read, due to a configured limit.
15
- class ResponseReadError < Error
16
- end
17
-
18
- # Error raised when a response is larger than IMAP#max_response_size.
19
- class ResponseTooLargeError < ResponseReadError
20
- attr_reader :bytes_read, :literal_size
21
- attr_reader :max_response_size
22
-
23
- def initialize(msg = nil, *args,
24
- bytes_read: nil,
25
- literal_size: nil,
26
- max_response_size: nil,
27
- **kwargs)
28
- @bytes_read = bytes_read
29
- @literal_size = literal_size
30
- @max_response_size = max_response_size
31
- msg ||= [
32
- "Response size", response_size_msg, "exceeds max_response_size",
33
- max_response_size && "(#{max_response_size}B)",
34
- ].compact.join(" ")
35
- return super(msg, *args) if kwargs.empty? # ruby 2.6 compatibility
36
- super(msg, *args, **kwargs)
37
- end
38
-
39
- private
40
-
41
- def response_size_msg
42
- if bytes_read && literal_size
43
- "(#{bytes_read}B read + #{literal_size}B literal)"
44
- end
45
- end
46
- end
47
-
48
14
  # Error raised when a response from the server is non-parseable.
49
15
  class ResponseParseError < Error
50
16
  end
data/lib/net/imap.rb CHANGED
@@ -106,41 +106,6 @@ module Net
106
106
  #
107
107
  # This script invokes the FETCH command and the SEARCH command concurrently.
108
108
  #
109
- # When running multiple commands, care must be taken to avoid ambiguity. For
110
- # example, SEARCH responses are ambiguous about which command they are
111
- # responding to, so search commands should not run simultaneously, unless the
112
- # server supports +ESEARCH+ {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731] or
113
- # IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]. See {RFC9051
114
- # §5.5}[https://www.rfc-editor.org/rfc/rfc9051.html#section-5.5] for
115
- # other examples of command sequences which should not be pipelined.
116
- #
117
- # == Unbounded memory use
118
- #
119
- # Net::IMAP reads server responses in a separate receiver thread per client.
120
- # Unhandled response data is saved to #responses, and response_handlers run
121
- # inside the receiver thread. See the list of methods for {handling server
122
- # responses}[rdoc-ref:Net::IMAP@Handling+server+responses], below.
123
- #
124
- # Because the receiver thread continuously reads and saves new responses, some
125
- # scenarios must be careful to avoid unbounded memory use:
126
- #
127
- # * Commands such as #list or #fetch can have an enormous number of responses.
128
- # * Commands such as #fetch can result in an enormous size per response.
129
- # * Long-lived connections will gradually accumulate unsolicited server
130
- # responses, especially +EXISTS+, +FETCH+, and +EXPUNGE+ responses.
131
- # * A buggy or untrusted server could send inappropriate responses, which
132
- # could be very numerous, very large, and very rapid.
133
- #
134
- # Use paginated or limited versions of commands whenever possible.
135
- #
136
- # Use #max_response_size to impose a limit on incoming server responses
137
- # as they are being read. <em>This is especially important for untrusted
138
- # servers.</em>
139
- #
140
- # Use #add_response_handler to handle responses after each one is received.
141
- # Use the +response_handlers+ argument to ::new to assign response handlers
142
- # before the receiver thread is started.
143
- #
144
109
  # == Errors
145
110
  #
146
111
  # An IMAP server can send three different types of responses to indicate
@@ -255,9 +220,7 @@ module Net
255
220
  # Unicode", RFC-2152[https://tools.ietf.org/html/rfc2152], May 1997.
256
221
  #
257
222
  class IMAP < Protocol
258
- VERSION = "0.2.5"
259
-
260
- autoload :ResponseReader, File.expand_path("imap/response_reader", __dir__)
223
+ VERSION = "0.3.0"
261
224
 
262
225
  include MonitorMixin
263
226
  if defined?(OpenSSL::SSL)
@@ -288,40 +251,6 @@ module Net
288
251
  # Seconds to wait until an IDLE response is received.
289
252
  attr_reader :idle_response_timeout
290
253
 
291
- # The maximum allowed server response size. When +nil+, there is no limit
292
- # on response size.
293
- #
294
- # The default value is _unlimited_ (after +v0.5.8+, the default is 512 MiB).
295
- # A _much_ lower value should be used with untrusted servers (for example,
296
- # when connecting to a user-provided hostname). When using a lower limit,
297
- # message bodies should be fetched in chunks rather than all at once.
298
- #
299
- # <em>Please Note:</em> this only limits the size per response. It does
300
- # not prevent a flood of individual responses and it does not limit how
301
- # many unhandled responses may be stored on the responses hash. See
302
- # Net::IMAP@Unbounded+memory+use.
303
- #
304
- # Socket reads are limited to the maximum remaining bytes for the current
305
- # response: max_response_size minus the bytes that have already been read.
306
- # When the limit is reached, or reading a +literal+ _would_ go over the
307
- # limit, ResponseTooLargeError is raised and the connection is closed.
308
- # See also #socket_read_limit.
309
- #
310
- # Note that changes will not take effect immediately, because the receiver
311
- # thread may already be waiting for the next response using the previous
312
- # value. Net::IMAP#noop can force a response and enforce the new setting
313
- # immediately.
314
- #
315
- # ==== Versioned Defaults
316
- #
317
- # Net::IMAP#max_response_size <em>was added in +v0.2.5+ and +v0.3.9+ as an
318
- # attr_accessor, and in +v0.4.20+ and +v0.5.7+ as a delegator to a config
319
- # attribute.</em>
320
- #
321
- # * original: +nil+ <em>(no limit)</em>
322
- # * +0.5+: 512 MiB
323
- attr_accessor :max_response_size
324
-
325
254
  # The thread to receive exceptions.
326
255
  attr_accessor :client_thread
327
256
 
@@ -449,28 +378,37 @@ module Net
449
378
  # Sends an AUTHENTICATE command to authenticate the client.
450
379
  # The +auth_type+ parameter is a string that represents
451
380
  # the authentication mechanism to be used. Currently Net::IMAP
452
- # supports the authentication mechanisms:
453
- #
454
- # LOGIN:: login using cleartext user and password.
455
- # CRAM-MD5:: login with cleartext user and encrypted password
456
- # (see [RFC-2195] for a full description). This
457
- # mechanism requires that the server have the user's
458
- # password stored in clear-text password.
459
- #
460
- # For both of these mechanisms, there should be two +args+: username
461
- # and (cleartext) password. A server may not support one or the other
462
- # of these mechanisms; check #capability for a capability of
463
- # the form "AUTH=LOGIN" or "AUTH=CRAM-MD5".
464
- #
465
- # Authentication is done using the appropriate authenticator object:
466
- # see +add_authenticator+ for more information on plugging in your own
467
- # authenticator.
381
+ # supports the following mechanisms:
382
+ #
383
+ # PLAIN:: Login using cleartext user and password. Secure with TLS.
384
+ # See Net::IMAP::PlainAuthenticator.
385
+ # CRAM-MD5:: DEPRECATED: Use PLAIN (or DIGEST-MD5) with TLS.
386
+ # DIGEST-MD5:: DEPRECATED by RFC6331. Must be secured using TLS.
387
+ # See Net::IMAP::DigestMD5Authenticator.
388
+ # LOGIN:: DEPRECATED: Use PLAIN.
389
+ #
390
+ # Most mechanisms require two args: authentication identity (e.g. username)
391
+ # and credentials (e.g. a password). But each mechanism requires and allows
392
+ # different arguments; please consult the documentation for the specific
393
+ # mechanisms you are using. <em>Several obsolete mechanisms are available
394
+ # for backwards compatibility. Using deprecated mechanisms will issue
395
+ # warnings.</em>
396
+ #
397
+ # Servers do not support all mechanisms and clients must not attempt to use
398
+ # a mechanism unless "AUTH=#{mechanism}" is listed as a #capability.
399
+ # Clients must not attempt to authenticate or #login when +LOGINDISABLED+ is
400
+ # listed with the capabilities. Server capabilities, especially auth
401
+ # mechanisms, do change after calling #starttls so they need to be checked
402
+ # again.
468
403
  #
469
404
  # For example:
470
405
  #
471
- # imap.authenticate('LOGIN', user, password)
406
+ # imap.authenticate('PLAIN', user, password)
472
407
  #
473
408
  # A Net::IMAP::NoResponseError is raised if authentication fails.
409
+ #
410
+ # See +Net::IMAP::Authenticators+ for more information on plugging in your
411
+ # own authenticator.
474
412
  def authenticate(auth_type, *args)
475
413
  authenticator = self.class.authenticator(auth_type, *args)
476
414
  send_command("AUTHENTICATE", auth_type) do |resp|
@@ -1026,11 +964,6 @@ module Net
1026
964
  # end
1027
965
  # }
1028
966
  #
1029
- # Response handlers can also be added when the client is created before the
1030
- # receiver thread is started, by the +response_handlers+ argument to ::new.
1031
- # This ensures every server response is handled, including the #greeting.
1032
- #
1033
- # Related: #remove_response_handler, #response_handlers
1034
967
  def add_response_handler(handler = nil, &block)
1035
968
  raise ArgumentError, "two Procs are passed" if handler && block
1036
969
  @response_handlers.push(block || handler)
@@ -1146,13 +1079,6 @@ module Net
1146
1079
  # OpenSSL::SSL::SSLContext#set_params as parameters.
1147
1080
  # open_timeout:: Seconds to wait until a connection is opened
1148
1081
  # idle_response_timeout:: Seconds to wait until an IDLE response is received
1149
- # response_handlers:: A list of response handlers to be added before the
1150
- # receiver thread is started. This ensures every server
1151
- # response is handled, including the #greeting. Note
1152
- # that the greeting is handled in the current thread,
1153
- # but all other responses are handled in the receiver
1154
- # thread.
1155
- # max_response_size:: See #max_response_size.
1156
1082
  #
1157
1083
  # The most common errors are:
1158
1084
  #
@@ -1183,10 +1109,8 @@ module Net
1183
1109
  @tagno = 0
1184
1110
  @open_timeout = options[:open_timeout] || 30
1185
1111
  @idle_response_timeout = options[:idle_response_timeout] || 5
1186
- @max_response_size = options[:max_response_size]
1187
1112
  @parser = ResponseParser.new
1188
1113
  @sock = tcp_socket(@host, @port)
1189
- @reader = ResponseReader.new(self, @sock)
1190
1114
  begin
1191
1115
  if options[:ssl]
1192
1116
  start_tls_session(options[:ssl])
@@ -1197,7 +1121,6 @@ module Net
1197
1121
  @responses = Hash.new([].freeze)
1198
1122
  @tagged_responses = {}
1199
1123
  @response_handlers = []
1200
- options[:response_handlers]&.each do |h| add_response_handler(h) end
1201
1124
  @tagged_response_arrival = new_cond
1202
1125
  @continued_command_tag = nil
1203
1126
  @continuation_request_arrival = new_cond
@@ -1214,7 +1137,6 @@ module Net
1214
1137
  if @greeting.name == "BYE"
1215
1138
  raise ByeResponseError, @greeting
1216
1139
  end
1217
- @response_handlers.each do |handler| handler.call(@greeting) end
1218
1140
 
1219
1141
  @client_thread = Thread.current
1220
1142
  @receiver_thread = Thread.start {
@@ -1338,14 +1260,25 @@ module Net
1338
1260
  end
1339
1261
 
1340
1262
  def get_response
1341
- buff = @reader.read_response_buffer
1263
+ buff = String.new
1264
+ while true
1265
+ s = @sock.gets(CRLF)
1266
+ break unless s
1267
+ buff.concat(s)
1268
+ if /\{(\d+)\}\r\n/n =~ s
1269
+ s = @sock.read($1.to_i)
1270
+ buff.concat(s)
1271
+ else
1272
+ break
1273
+ end
1274
+ end
1342
1275
  return nil if buff.length == 0
1343
- $stderr.print(buff.gsub(/^/n, "S: ")) if @@debug
1344
- @parser.parse(buff)
1276
+ if @@debug
1277
+ $stderr.print(buff.gsub(/^/n, "S: "))
1278
+ end
1279
+ return @parser.parse(buff)
1345
1280
  end
1346
1281
 
1347
- #############################
1348
-
1349
1282
  def record_response(name, data)
1350
1283
  unless @responses.has_key?(name)
1351
1284
  @responses[name] = []
@@ -1523,7 +1456,6 @@ module Net
1523
1456
  context.verify_callback = VerifyCallbackProc
1524
1457
  end
1525
1458
  @sock = SSLSocket.new(@sock, context)
1526
- @reader = ResponseReader.new(self, @sock)
1527
1459
  @sock.sync_close = true
1528
1460
  @sock.hostname = @host if @sock.respond_to? :hostname=
1529
1461
  ssl_socket_connect(@sock, @open_timeout)
data/net-imap.gemspec CHANGED
@@ -10,8 +10,8 @@ end
10
10
  Gem::Specification.new do |spec|
11
11
  spec.name = name
12
12
  spec.version = version
13
- spec.authors = ["Shugo Maeda"]
14
- spec.email = ["shugo@ruby-lang.org"]
13
+ spec.authors = ["Shugo Maeda", "nicholas a. evans"]
14
+ spec.email = ["shugo@ruby-lang.org", "nick@ekenosen.net"]
15
15
 
16
16
  spec.summary = %q{Ruby client api for Internet Message Access Protocol}
17
17
  spec.description = %q{Ruby client api for Internet Message Access Protocol}
@@ -32,6 +32,6 @@ Gem::Specification.new do |spec|
32
32
  spec.require_paths = ["lib"]
33
33
 
34
34
  spec.add_dependency "net-protocol"
35
- spec.add_dependency "digest"
36
- spec.add_dependency "strscan"
35
+ spec.add_development_dependency "digest"
36
+ spec.add_development_dependency "strscan"
37
37
  end
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-imap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
8
+ - nicholas a. evans
9
+ autorequire:
8
10
  bindir: exe
9
11
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
12
+ date: 2022-09-28 00:00:00.000000000 Z
11
13
  dependencies:
12
14
  - !ruby/object:Gem::Dependency
13
15
  name: net-protocol
@@ -30,7 +32,7 @@ dependencies:
30
32
  - - ">="
31
33
  - !ruby/object:Gem::Version
32
34
  version: '0'
33
- type: :runtime
35
+ type: :development
34
36
  prerelease: false
35
37
  version_requirements: !ruby/object:Gem::Requirement
36
38
  requirements:
@@ -44,7 +46,7 @@ dependencies:
44
46
  - - ">="
45
47
  - !ruby/object:Gem::Version
46
48
  version: '0'
47
- type: :runtime
49
+ type: :development
48
50
  prerelease: false
49
51
  version_requirements: !ruby/object:Gem::Requirement
50
52
  requirements:
@@ -54,10 +56,12 @@ dependencies:
54
56
  description: Ruby client api for Internet Message Access Protocol
55
57
  email:
56
58
  - shugo@ruby-lang.org
59
+ - nick@ekenosen.net
57
60
  executables: []
58
61
  extensions: []
59
62
  extra_rdoc_files: []
60
63
  files:
64
+ - ".github/dependabot.yml"
61
65
  - ".github/workflows/test.yml"
62
66
  - ".gitignore"
63
67
  - Gemfile
@@ -76,7 +80,6 @@ files:
76
80
  - lib/net/imap/flags.rb
77
81
  - lib/net/imap/response_data.rb
78
82
  - lib/net/imap/response_parser.rb
79
- - lib/net/imap/response_reader.rb
80
83
  - net-imap.gemspec
81
84
  homepage: https://github.com/ruby/net-imap
82
85
  licenses:
@@ -85,6 +88,7 @@ licenses:
85
88
  metadata:
86
89
  homepage_uri: https://github.com/ruby/net-imap
87
90
  source_code_uri: https://github.com/ruby/net-imap
91
+ post_install_message:
88
92
  rdoc_options: []
89
93
  require_paths:
90
94
  - lib
@@ -99,7 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
103
  - !ruby/object:Gem::Version
100
104
  version: '0'
101
105
  requirements: []
102
- rubygems_version: 3.6.8
106
+ rubygems_version: 3.4.0.dev
107
+ signing_key:
103
108
  specification_version: 4
104
109
  summary: Ruby client api for Internet Message Access Protocol
105
110
  test_files: []
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Net
4
- class IMAP
5
- # See https://www.rfc-editor.org/rfc/rfc9051#section-2.2.2
6
- class ResponseReader # :nodoc:
7
- attr_reader :client
8
-
9
- def initialize(client, sock)
10
- @client, @sock = client, sock
11
- end
12
-
13
- def read_response_buffer
14
- @buff = String.new
15
- catch :eof do
16
- while true
17
- read_line
18
- break unless (@literal_size = get_literal_size)
19
- read_literal
20
- end
21
- end
22
- buff
23
- ensure
24
- @buff = nil
25
- end
26
-
27
- private
28
-
29
- attr_reader :buff, :literal_size
30
-
31
- def bytes_read; buff.bytesize end
32
- def empty?; buff.empty? end
33
- def done?; line_done? && !get_literal_size end
34
- def line_done?; buff.end_with?(CRLF) end
35
- def get_literal_size; /\{(\d+)\}\r\n\z/n =~ buff && $1.to_i end
36
-
37
- def read_line
38
- buff << (@sock.gets(CRLF, read_limit) or throw :eof)
39
- max_response_remaining! unless line_done?
40
- end
41
-
42
- def read_literal
43
- # check before allocating memory for literal
44
- max_response_remaining!
45
- literal = String.new(capacity: literal_size)
46
- buff << (@sock.read(read_limit(literal_size), literal) or throw :eof)
47
- ensure
48
- @literal_size = nil
49
- end
50
-
51
- def read_limit(limit = nil)
52
- [limit, max_response_remaining!].compact.min
53
- end
54
-
55
- def max_response_size; client.max_response_size end
56
- def max_response_remaining; max_response_size &.- bytes_read end
57
- def response_too_large?; max_response_size &.< min_response_size end
58
- def min_response_size; bytes_read + min_response_remaining end
59
-
60
- def min_response_remaining
61
- empty? ? 3 : done? ? 0 : (literal_size || 0) + 2
62
- end
63
-
64
- def max_response_remaining!
65
- return max_response_remaining unless response_too_large?
66
- raise ResponseTooLargeError.new(
67
- max_response_size: max_response_size,
68
- bytes_read: bytes_read,
69
- literal_size: literal_size,
70
- )
71
- end
72
-
73
- end
74
- end
75
- end