net-imap 0.4.17 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.

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: aceea6e339f24fafdd1920f2b25d863b47823c5654528441e4c7d173e414f3c2
4
- data.tar.gz: 6258659759ae4c6b7ea63f7dddf0fb4a7231c3242ebad72188ba43bb7a2f3165
3
+ metadata.gz: d271261a2609a31b8c84ae74913bf57d5046e95318db7660b3230940bdbff447
4
+ data.tar.gz: 771baa4b8a6c3f83f6ef4f320dda8dc5ea9f2fa2ace15fd9b0c1c1b3a594363a
5
5
  SHA512:
6
- metadata.gz: 003561bf18250b9237f10d5ba5ce20ea285dea1d0380f4612d08429fe31ceea14d84fef76dc4e6c5ba47ff2e798b20a7767d85f6cdeb79f7abfcdb25df39093f
7
- data.tar.gz: 42702bd43a0f9e778c88017e1553a5ddd058c0b702f1c39843c845ef0fba935b2f3ee636dc10a700e23b89c3e9a9e5b9c80b8bff836e65985bc59ca73c2a6255
6
+ metadata.gz: 230d40d8d183b1c69f63050990df140b49aa5731d0868713e44d2da68c2713ede4fd8d4b1aff60103c25ac6586076e220973b774a43cd5a7b3eaad4e49e7bf3b
7
+ data.tar.gz: 156e6c86f6fe39a76de89275bfcd3c57b5adcd375de6add45cd00a30bf92bbf04a2b475702db33cae0509fc0b7b3e015518d4991cd5c467f833cacb0f75d3ca6
data/Gemfile CHANGED
@@ -13,4 +13,10 @@ gem "rdoc"
13
13
  gem "test-unit"
14
14
  gem "test-unit-ruby-core", git: "https://github.com/ruby/test-unit-ruby-core"
15
15
 
16
- gem "benchmark-driver"
16
+ gem "benchmark-driver", require: false
17
+
18
+ group :test do
19
+ gem "simplecov", require: false
20
+ gem "simplecov-html", require: false
21
+ gem "simplecov-json", require: false
22
+ end
data/README.md CHANGED
@@ -50,12 +50,16 @@ end
50
50
 
51
51
  ```ruby
52
52
  imap.select('Mail/sent-mail')
53
- if not imap.list('Mail/', 'sent-apr03')
53
+ if imap.list('Mail/', 'sent-apr03').empty?
54
54
  imap.create('Mail/sent-apr03')
55
55
  end
56
56
  imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id|
57
- imap.copy(message_id, "Mail/sent-apr03")
58
- imap.store(message_id, "+FLAGS", [:Deleted])
57
+ if imap.capable?(:move) || imap.capable?(:IMAP4rev2)
58
+ imap.move(message_id, "Mail/sent-apr03")
59
+ else
60
+ imap.copy(message_id, "Mail/sent-apr03")
61
+ imap.store(message_id, "+FLAGS", [:Deleted])
62
+ end
59
63
  end
60
64
  imap.expunge
61
65
  ```
data/docs/styles.css CHANGED
@@ -1,24 +1,80 @@
1
1
  /* this is a work in progress. :) */
2
2
 
3
- main .method-header {
4
- background: rgba(27,31,35,0.05);
5
- border: 1px solid #6C8C22;
3
+ /***********************************************
4
+ * Method descriptions
5
+ ***********************************************/
6
+
7
+ main .method-detail {
8
+ display: grid;
9
+ grid-template-areas: "header controls"
10
+ "description description";
11
+ grid-template-columns: 1fr min-content;
12
+ justify-content: space-between;
13
+ }
14
+
15
+ main .method-header, main .method-controls {
6
16
  padding: 0.5em;
7
- border-radius: 4px;
8
- /* padding: 0 0.5em; */
9
- /* border-width: 0 1px; */
10
- /* border-color: #6C8C22; */
11
- /* border-style: solid; */
17
+ /* border: 1px solid var(--highlight-color); */
18
+ background: var(--table-header-background-color);
19
+ line-height: 1.6;
20
+ }
21
+
22
+ main .method-header {
23
+ grid-area: "header";
24
+ border-right: none;
25
+ border-radius: 4px 0 0 4px;
26
+ }
27
+
28
+ main .method-controls {
29
+ grid-area: "controls";
30
+ border-left: none;
31
+ border-radius: 0 4px 4px 0;
12
32
  }
13
33
 
14
34
  main .method-description, main .aliases {
35
+ grid-area: "description";
36
+ grid-column: 1 / span 2;
15
37
  padding-left: 1em;
16
38
  }
17
39
 
18
- body {
19
- /*
20
- * The default (300) can be too low contrast. Also, many fonts don't
21
- * distinguish between 300->400, so <em>...</em> had no effect.
22
- */
23
- font-weight: 400;
40
+ @media (max-width: 700px) {
41
+ main .method-header, main .method-controls, main .method-description {
42
+ grid-column: 1 / span 2;
43
+ margin: 0;
44
+ }
45
+ main .method-controls {
46
+ background: none;
47
+ }
48
+ }
49
+
50
+ /***********************************************
51
+ * Description lists
52
+ ***********************************************/
53
+
54
+ main dt {
55
+ margin-bottom: 0; /* override rdoc 6.8 */
56
+ float: unset; /* override rdoc 6.8 */
57
+ line-height: 1.5; /* matches `main p` */
58
+ }
59
+
60
+ main dl.note-list dt {
61
+ margin-right: 1em;
62
+ float: left;
63
+ }
64
+
65
+ main dl.note-list dt:has(+ dt) {
66
+ margin-right: 0.25em;
67
+ }
68
+
69
+ main dl.note-list dt:has(+ dt)::after {
70
+ content: ', ';
71
+ font-weight: normal;
72
+ }
73
+
74
+ main dd {
75
+ margin: 0 0 1em 1em;
76
+ }
77
+
78
+ main dd p:first-child {
79
+ margin-top: 0;
24
80
  }
@@ -9,7 +9,7 @@ module Net::IMAP::Authenticators
9
9
  "%s.%s is deprecated. Use %s.%s instead." % [
10
10
  Net::IMAP, __method__, Net::IMAP::SASL, __method__
11
11
  ],
12
- uplevel: 1
12
+ uplevel: 1, category: :deprecated
13
13
  )
14
14
  Net::IMAP::SASL.add_authenticator(...)
15
15
  end
@@ -20,7 +20,7 @@ module Net::IMAP::Authenticators
20
20
  "%s.%s is deprecated. Use %s.%s instead." % [
21
21
  Net::IMAP, __method__, Net::IMAP::SASL, __method__
22
22
  ],
23
- uplevel: 1
23
+ uplevel: 1, category: :deprecated
24
24
  )
25
25
  Net::IMAP::SASL.authenticator(...)
26
26
  end
@@ -3,6 +3,7 @@
3
3
  require "date"
4
4
 
5
5
  require_relative "errors"
6
+ require_relative "data_lite"
6
7
 
7
8
  module Net
8
9
  class IMAP < Protocol
@@ -119,79 +120,63 @@ module Net
119
120
  put_string("\\" + symbol.to_s)
120
121
  end
121
122
 
122
- class RawData # :nodoc:
123
+ CommandData = Data.define(:data) do # :nodoc:
123
124
  def send_data(imap, tag)
124
- imap.__send__(:put_string, @data)
125
+ raise NoMethodError, "#{self.class} must implement #{__method__}"
125
126
  end
126
127
 
127
128
  def validate
128
129
  end
129
-
130
- private
131
-
132
- def initialize(data)
133
- @data = data
134
- end
135
130
  end
136
131
 
137
- class Atom # :nodoc:
132
+ class RawData < CommandData # :nodoc:
138
133
  def send_data(imap, tag)
139
- imap.__send__(:put_string, @data)
140
- end
141
-
142
- def validate
143
- end
144
-
145
- private
146
-
147
- def initialize(data)
148
- @data = data
134
+ imap.__send__(:put_string, data)
149
135
  end
150
136
  end
151
137
 
152
- class QuotedString # :nodoc:
138
+ class Atom < CommandData # :nodoc:
153
139
  def send_data(imap, tag)
154
- imap.__send__(:send_quoted_string, @data)
155
- end
156
-
157
- def validate
158
- end
159
-
160
- private
161
-
162
- def initialize(data)
163
- @data = data
140
+ imap.__send__(:put_string, data)
164
141
  end
165
142
  end
166
143
 
167
- class Literal # :nodoc:
144
+ class QuotedString < CommandData # :nodoc:
168
145
  def send_data(imap, tag)
169
- imap.__send__(:send_literal, @data, tag)
146
+ imap.__send__(:send_quoted_string, data)
170
147
  end
148
+ end
171
149
 
172
- def validate
173
- end
174
-
175
- private
176
-
177
- def initialize(data)
178
- @data = data
150
+ class Literal < CommandData # :nodoc:
151
+ def send_data(imap, tag)
152
+ imap.__send__(:send_literal, data, tag)
179
153
  end
180
154
  end
181
155
 
182
- class MessageSet # :nodoc:
156
+ # *DEPRECATED*. Replaced by SequenceSet.
157
+ class MessageSet < CommandData # :nodoc:
183
158
  def send_data(imap, tag)
184
- imap.__send__(:put_string, format_internal(@data))
159
+ imap.__send__(:put_string, format_internal(data))
185
160
  end
186
161
 
187
162
  def validate
188
- validate_internal(@data)
163
+ validate_internal(data)
189
164
  end
190
165
 
191
166
  private
192
167
 
193
- def initialize(data)
194
- @data = data
168
+ def initialize(data:)
169
+ super
170
+ warn("DEPRECATED: #{MessageSet} should be replaced with #{SequenceSet}.",
171
+ uplevel: 1, category: :deprecated)
172
+ begin
173
+ # to ensure the input works with SequenceSet, too
174
+ SequenceSet.new(data)
175
+ rescue
176
+ warn "MessageSet input is incompatible with SequenceSet: [%s] %s" % [
177
+ $!.class, $!.message
178
+ ]
179
+ end
195
180
  end
196
181
 
197
182
  def format_internal(data)
@@ -235,22 +220,18 @@ module Net
235
220
  end
236
221
  end
237
222
 
238
- class ClientID # :nodoc:
223
+ class ClientID < CommandData # :nodoc:
239
224
 
240
225
  def send_data(imap, tag)
241
- imap.__send__(:send_data, format_internal(@data), tag)
226
+ imap.__send__(:send_data, format_internal(data), tag)
242
227
  end
243
228
 
244
229
  def validate
245
- validate_internal(@data)
230
+ validate_internal(data)
246
231
  end
247
232
 
248
233
  private
249
234
 
250
- def initialize(data)
251
- @data = data
252
- end
253
-
254
235
  def validate_internal(client_id)
255
236
  client_id.to_h.each do |k,v|
256
237
  unless StringFormatter.valid_string?(k)
@@ -223,6 +223,29 @@ module Net
223
223
  # Use +SASL-IR+ when it is supported by the server and the mechanism.
224
224
  attr_accessor :sasl_ir, type: :boolean
225
225
 
226
+ # Controls the behavior of Net::IMAP#login when the +LOGINDISABLED+
227
+ # capability is present. When enforced, Net::IMAP will raise a
228
+ # LoginDisabledError when that capability is present.
229
+ #
230
+ # <em>(Support for +LOGINDISABLED+ was added in +v0.5.0+.)</em>
231
+ #
232
+ # ==== Valid options
233
+ #
234
+ # [+false+ <em>(original behavior, before support was added)</em>]
235
+ # Send the +LOGIN+ command without checking for +LOGINDISABLED+.
236
+ #
237
+ # [+:when_capabilities_cached+]
238
+ # Enforce the requirement when Net::IMAP#capabilities_cached? is true,
239
+ # but do not send a +CAPABILITY+ command to discover the capabilities.
240
+ #
241
+ # [+true+ <em>(default since +v0.5+)</em>]
242
+ # Only send the +LOGIN+ command if the +LOGINDISABLED+ capability is not
243
+ # present. When capabilities are unknown, Net::IMAP will automatically
244
+ # send a +CAPABILITY+ command first before sending +LOGIN+.
245
+ #
246
+ attr_accessor :enforce_logindisabled, type: [
247
+ false, :when_capabilities_cached, true
248
+ ]
226
249
 
227
250
  # Controls the behavior of Net::IMAP#responses when called without any
228
251
  # arguments (+type+ or +block+).
@@ -340,33 +363,36 @@ module Net
340
363
  open_timeout: 30,
341
364
  idle_response_timeout: 5,
342
365
  sasl_ir: true,
343
- responses_without_block: :silence_deprecation_warning,
366
+ enforce_logindisabled: true,
367
+ responses_without_block: :warn,
344
368
  ).freeze
345
369
 
346
370
  @global = default.new
347
371
 
348
- version_defaults[0.4] = Config[default.send(:defaults_hash)]
372
+ version_defaults[:default] = Config[default.send(:defaults_hash)]
373
+ version_defaults[:current] = Config[:default]
349
374
 
350
- version_defaults[0] = Config[0.4].dup.update(
375
+ version_defaults[0] = Config[:current].dup.update(
351
376
  sasl_ir: false,
377
+ responses_without_block: :silence_deprecation_warning,
378
+ enforce_logindisabled: false,
352
379
  ).freeze
353
380
  version_defaults[0.0] = Config[0]
354
381
  version_defaults[0.1] = Config[0]
355
382
  version_defaults[0.2] = Config[0]
356
383
  version_defaults[0.3] = Config[0]
357
384
 
358
- version_defaults[0.5] = Config[0.4].dup.update(
359
- responses_without_block: :warn,
385
+ version_defaults[0.4] = Config[0.3].dup.update(
386
+ sasl_ir: true,
360
387
  ).freeze
361
388
 
362
- version_defaults[:default] = Config[0.4]
363
- version_defaults[:current] = Config[0.4]
364
- version_defaults[:next] = Config[0.5]
389
+ version_defaults[0.5] = Config[:current]
365
390
 
366
- version_defaults[0.6] = Config[0.5].dup.update(
391
+ version_defaults[0.6] = Config[0.5].dup.update(
367
392
  responses_without_block: :frozen_dup,
368
393
  ).freeze
369
- version_defaults[:future] = Config[0.6]
394
+ version_defaults[:next] = Config[0.6]
395
+ version_defaults[:future] = Config[:next]
370
396
 
371
397
  version_defaults.freeze
372
398
  end
@@ -186,7 +186,7 @@ module Net
186
186
 
187
187
  # Ensure argument is 'number' or raise DataFormatError
188
188
  def ensure_number(num)
189
- return if valid_number?(num)
189
+ return num if valid_number?(num)
190
190
 
191
191
  msg = "number must be unsigned 32-bit integer: #{num}"
192
192
  raise DataFormatError, msg
@@ -194,7 +194,7 @@ module Net
194
194
 
195
195
  # Ensure argument is 'nz_number' or raise DataFormatError
196
196
  def ensure_nz_number(num)
197
- return if valid_nz_number?(num)
197
+ return num if valid_nz_number?(num)
198
198
 
199
199
  msg = "nz_number must be non-zero unsigned 32-bit integer: #{num}"
200
200
  raise DataFormatError, msg
@@ -202,7 +202,7 @@ module Net
202
202
 
203
203
  # Ensure argument is 'mod_sequence_value' or raise DataFormatError
204
204
  def ensure_mod_sequence_value(num)
205
- return if valid_mod_sequence_value?(num)
205
+ return num if valid_mod_sequence_value?(num)
206
206
 
207
207
  msg = "mod_sequence_value must be unsigned 64-bit integer: #{num}"
208
208
  raise DataFormatError, msg
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Some of the code in this file was copied from the polyfill-data gem.
4
+ #
5
+ # MIT License
6
+ #
7
+ # Copyright (c) 2023 Jim Gay, Joel Drapper, Nicholas Evans
8
+ #
9
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ # of this software and associated documentation files (the "Software"), to deal
11
+ # in the Software without restriction, including without limitation the rights
12
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ # copies of the Software, and to permit persons to whom the Software is
14
+ # furnished to do so, subject to the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included in all
17
+ # copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ # SOFTWARE.
26
+
27
+
28
+ module Net
29
+ class IMAP
30
+ data_or_object = RUBY_VERSION >= "3.2.0" ? ::Data : Object
31
+ class DataLite < data_or_object
32
+ def encode_with(coder) coder.map = attributes.transform_keys(&:to_s) end
33
+ def init_with(coder) initialize(**coder.map.transform_keys(&:to_sym)) end
34
+ end
35
+
36
+ Data = DataLite
37
+ end
38
+ end
39
+
40
+ # :nocov:
41
+ # Need to skip test coverage for the rest, because it isn't loaded by ruby 3.2+.
42
+ return if RUBY_VERSION >= "3.2.0"
43
+
44
+ module Net
45
+ class IMAP
46
+ # DataLite is a temporary substitute for ruby 3.2's +Data+ class. DataLite
47
+ # is aliased as Net::IMAP::Data, so that code using it won't need to be
48
+ # updated when it is removed.
49
+ #
50
+ # See {ruby 3.2's documentation for Data}[https://docs.ruby-lang.org/en/3.2/Data.html].
51
+ #
52
+ # [When running ruby 3.1]
53
+ # This class reimplements the API for ruby 3.2's +Data+, and should be
54
+ # compatible for nearly all use-cases. This reimplementation <em>will be
55
+ # removed</em> in +net-imap+ 0.6, when support for ruby 3.1 is dropped.
56
+ #
57
+ # _NOTE:_ +net-imap+ no longer supports ruby versions prior to 3.1.
58
+ # [When running ruby >= 3.2]
59
+ # This class inherits from +Data+ and _only_ defines the methods needed
60
+ # for YAML serialization. This will be dropped when +psych+ adds support
61
+ # for +Data+.
62
+ #
63
+ # Some of the code in this class was copied or adapted from the
64
+ # {polyfill-data gem}[https://rubygems.org/gems/polyfill-data], by Jim Gay
65
+ # and Joel Drapper, under the MIT license terms.
66
+ class DataLite
67
+ singleton_class.undef_method :new
68
+
69
+ TYPE_ERROR = "%p is not a symbol nor a string"
70
+ ATTRSET_ERROR = "invalid data member: %p"
71
+ DUP_ERROR = "duplicate member: %p"
72
+ ARITY_ERROR = "wrong number of arguments (given %d, expected %s)"
73
+ private_constant :TYPE_ERROR, :ATTRSET_ERROR, :DUP_ERROR, :ARITY_ERROR
74
+
75
+ # Defines a new Data class.
76
+ #
77
+ # _NOTE:_ Unlike ruby 3.2's +Data.define+, DataLite.define only supports
78
+ # member names which are valid local variable names. Member names can't
79
+ # be keywords (e.g: +next+ or +class+) or start with capital letters, "@",
80
+ # etc.
81
+ def self.define(*args, &block)
82
+ members = args.each_with_object({}) do |arg, members|
83
+ arg = arg.to_str unless arg in Symbol | String if arg.respond_to?(:to_str)
84
+ arg = arg.to_sym if arg in String
85
+ arg in Symbol or raise TypeError, TYPE_ERROR % [arg]
86
+ arg in %r{=} and raise ArgumentError, ATTRSET_ERROR % [arg]
87
+ members.key?(arg) and raise ArgumentError, DUP_ERROR % [arg]
88
+ members[arg] = true
89
+ end
90
+ members = members.keys.freeze
91
+
92
+ klass = ::Class.new(self)
93
+
94
+ klass.singleton_class.undef_method :define
95
+ klass.define_singleton_method(:members) { members }
96
+
97
+ def klass.new(*args, **kwargs, &block)
98
+ if kwargs.size.positive?
99
+ if args.size.positive?
100
+ raise ArgumentError, ARITY_ERROR % [args.size, 0]
101
+ end
102
+ elsif members.size < args.size
103
+ expected = members.size.zero? ? 0 : 0..members.size
104
+ raise ArgumentError, ARITY_ERROR % [args.size, expected]
105
+ else
106
+ kwargs = Hash[members.take(args.size).zip(args)]
107
+ end
108
+ allocate.tap do |instance|
109
+ instance.__send__(:initialize, **kwargs, &block)
110
+ end.freeze
111
+ end
112
+
113
+ klass.singleton_class.alias_method :[], :new
114
+ klass.attr_reader(*members)
115
+
116
+ # Dynamically defined initializer methods are in an included module,
117
+ # rather than directly on DataLite (like in ruby 3.2+):
118
+ # * simpler to handle required kwarg ArgumentErrors
119
+ # * easier to ensure consistent ivar assignment order (object shape)
120
+ # * faster than instance_variable_set
121
+ klass.include(Module.new do
122
+ if members.any?
123
+ kwargs = members.map{"#{_1.name}:"}.join(", ")
124
+ params = members.map(&:name).join(", ")
125
+ ivars = members.map{"@#{_1.name}"}.join(", ")
126
+ attrs = members.map{"attrs[:#{_1.name}]"}.join(", ")
127
+ module_eval <<~RUBY, __FILE__, __LINE__ + 1
128
+ protected
129
+ def initialize(#{kwargs}) #{ivars} = #{params}; freeze end
130
+ def marshal_load(attrs) #{ivars} = #{attrs}; freeze end
131
+ RUBY
132
+ end
133
+ end)
134
+
135
+ klass.module_eval do _1.module_eval(&block) end if block_given?
136
+
137
+ klass
138
+ end
139
+
140
+ ##
141
+ # singleton-method: new
142
+ # call-seq:
143
+ # new(*args) -> instance
144
+ # new(**kwargs) -> instance
145
+ #
146
+ # Constuctor for classes defined with ::define.
147
+ #
148
+ # Aliased as ::[].
149
+
150
+ ##
151
+ # singleton-method: []
152
+ # call-seq:
153
+ # ::[](*args) -> instance
154
+ # ::[](**kwargs) -> instance
155
+ #
156
+ # Constuctor for classes defined with ::define.
157
+ #
158
+ # Alias for ::new
159
+
160
+ ##
161
+ def members; self.class.members end
162
+ def attributes; Hash[members.map {|m| [m, send(m)] }] end
163
+ def to_h(&block) attributes.to_h(&block) end
164
+ def hash; [self.class, attributes].hash end
165
+ def ==(other) self.class == other.class && to_h == other.to_h end
166
+ def eql?(other) self.class == other.class && hash == other.hash end
167
+ def deconstruct; attributes.values end
168
+
169
+ def deconstruct_keys(keys)
170
+ raise TypeError unless keys.is_a?(Array) || keys.nil?
171
+ return attributes if keys&.first.nil?
172
+ attributes.slice(*keys)
173
+ end
174
+
175
+ def with(**kwargs)
176
+ return self if kwargs.empty?
177
+ self.class.new(**attributes.merge(kwargs))
178
+ end
179
+
180
+ def inspect
181
+ __inspect_guard__(self) do |seen|
182
+ return "#<data #{self.class}:...>" if seen
183
+ attrs = attributes.map {|kv| "%s=%p" % kv }.join(", ")
184
+ display = ["data", self.class.name, attrs].compact.join(" ")
185
+ "#<#{display}>"
186
+ end
187
+ end
188
+ alias_method :to_s, :inspect
189
+
190
+ private
191
+
192
+ def initialize_copy(source) super.freeze end
193
+ def marshal_dump; attributes end
194
+
195
+ # Yields +true+ if +obj+ has been seen already, +false+ if it hasn't.
196
+ # Marks +obj+ as seen inside the block, so circuler references don't
197
+ # recursively trigger a SystemStackError (stack level too deep).
198
+ #
199
+ # Making circular references inside a Data object _should_ be very
200
+ # uncommon, but we'll support them for the sake of completeness.
201
+ def __inspect_guard__(obj)
202
+ preexisting = Thread.current[:__net_imap_data__inspect__]
203
+ Thread.current[:__net_imap_data__inspect__] ||= {}.compare_by_identity
204
+ inspect_guard = Thread.current[:__net_imap_data__inspect__]
205
+ if inspect_guard.include?(obj)
206
+ yield true
207
+ else
208
+ begin
209
+ inspect_guard[obj] = true
210
+ yield false
211
+ ensure
212
+ inspect_guard.delete(obj)
213
+ end
214
+ end
215
+ ensure
216
+ unless preexisting.equal?(inspect_guard)
217
+ Thread.current[:__net_imap_data__inspect__] = preexisting
218
+ end
219
+ end
220
+
221
+ end
222
+
223
+ end
224
+ end
225
+ # :nocov:
@@ -83,10 +83,12 @@ module Net
83
83
  elsif deprecated.empty?
84
84
  super host, port: port_or_options
85
85
  elsif deprecated.shift
86
- warn "DEPRECATED: Call Net::IMAP.new with keyword options", uplevel: 1
86
+ warn("DEPRECATED: Call Net::IMAP.new with keyword options",
87
+ uplevel: 1, category: :deprecated)
87
88
  super host, port: port_or_options, ssl: create_ssl_params(*deprecated)
88
89
  else
89
- warn "DEPRECATED: Call Net::IMAP.new with keyword options", uplevel: 1
90
+ warn("DEPRECATED: Call Net::IMAP.new with keyword options",
91
+ uplevel: 1, category: :deprecated)
90
92
  super host, port: port_or_options, ssl: false
91
93
  end
92
94
  end
@@ -113,7 +115,8 @@ module Net
113
115
  elsif deprecated.first.respond_to?(:to_hash)
114
116
  super(**Hash.try_convert(deprecated.first))
115
117
  else
116
- warn "DEPRECATED: Call Net::IMAP#starttls with keyword options", uplevel: 1
118
+ warn("DEPRECATED: Call Net::IMAP#starttls with keyword options",
119
+ uplevel: 1, category: :deprecated)
117
120
  super(**create_ssl_params(*deprecated))
118
121
  end
119
122
  end
@@ -7,6 +7,12 @@ module Net
7
7
  class Error < StandardError
8
8
  end
9
9
 
10
+ class LoginDisabledError < Error
11
+ def initialize(msg = "Remote server has disabled the LOGIN command", ...)
12
+ super
13
+ end
14
+ end
15
+
10
16
  # Error raised when data is in the incorrect format.
11
17
  class DataFormatError < Error
12
18
  end