net-imap 0.4.12 → 0.5.1
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 +4 -4
- data/Gemfile +7 -1
- data/lib/net/imap/authenticators.rb +2 -2
- data/lib/net/imap/command_data.rb +13 -2
- data/lib/net/imap/config/attr_accessors.rb +75 -0
- data/lib/net/imap/config/attr_inheritance.rb +90 -0
- data/lib/net/imap/config/attr_type_coercion.rb +61 -0
- data/lib/net/imap/config.rb +400 -0
- data/lib/net/imap/data_encoding.rb +3 -3
- data/lib/net/imap/deprecated_client_options.rb +8 -5
- data/lib/net/imap/errors.rb +6 -0
- data/lib/net/imap/response_data.rb +6 -93
- data/lib/net/imap/response_parser/parser_utils.rb +6 -6
- data/lib/net/imap/response_parser.rb +9 -17
- data/lib/net/imap/sasl/authentication_exchange.rb +52 -20
- data/lib/net/imap/sasl/authenticators.rb +8 -4
- data/lib/net/imap/sasl/client_adapter.rb +77 -26
- data/lib/net/imap/sasl/cram_md5_authenticator.rb +1 -1
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +213 -51
- data/lib/net/imap/sasl/login_authenticator.rb +2 -1
- data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
- data/lib/net/imap/sasl.rb +6 -3
- data/lib/net/imap/sasl_adapter.rb +0 -1
- data/lib/net/imap/sequence_set.rb +28 -24
- data/lib/net/imap.rb +467 -152
- data/net-imap.gemspec +3 -3
- data/rakelib/string_prep_tables_generator.rb +2 -0
- metadata +11 -10
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/pages.yml +0 -46
- data/.github/workflows/push_gem.yml +0 -48
- data/.github/workflows/test.yml +0 -31
- data/.gitignore +0 -12
- data/.mailmap +0 -13
@@ -0,0 +1,400 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "config/attr_accessors"
|
4
|
+
require_relative "config/attr_inheritance"
|
5
|
+
require_relative "config/attr_type_coercion"
|
6
|
+
|
7
|
+
module Net
|
8
|
+
class IMAP
|
9
|
+
|
10
|
+
# Net::IMAP::Config <em>(available since +v0.4.13+)</em> stores
|
11
|
+
# configuration options for Net::IMAP clients. The global configuration can
|
12
|
+
# be seen at either Net::IMAP.config or Net::IMAP::Config.global, and the
|
13
|
+
# client-specific configuration can be seen at Net::IMAP#config.
|
14
|
+
#
|
15
|
+
# When creating a new client, all unhandled keyword arguments to
|
16
|
+
# Net::IMAP.new are delegated to Config.new. Every client has its own
|
17
|
+
# config.
|
18
|
+
#
|
19
|
+
# debug_client = Net::IMAP.new(hostname, debug: true)
|
20
|
+
# quiet_client = Net::IMAP.new(hostname, debug: false)
|
21
|
+
# debug_client.config.debug? # => true
|
22
|
+
# quiet_client.config.debug? # => false
|
23
|
+
#
|
24
|
+
# == Inheritance
|
25
|
+
#
|
26
|
+
# Configs have a parent[rdoc-ref:Config::AttrInheritance#parent] config, and
|
27
|
+
# any attributes which have not been set locally will inherit the parent's
|
28
|
+
# value. Every client creates its own specific config. By default, client
|
29
|
+
# configs inherit from Config.global.
|
30
|
+
#
|
31
|
+
# plain_client = Net::IMAP.new(hostname)
|
32
|
+
# debug_client = Net::IMAP.new(hostname, debug: true)
|
33
|
+
# quiet_client = Net::IMAP.new(hostname, debug: false)
|
34
|
+
#
|
35
|
+
# plain_client.config.inherited?(:debug) # => true
|
36
|
+
# debug_client.config.inherited?(:debug) # => false
|
37
|
+
# quiet_client.config.inherited?(:debug) # => false
|
38
|
+
#
|
39
|
+
# plain_client.config.debug? # => false
|
40
|
+
# debug_client.config.debug? # => true
|
41
|
+
# quiet_client.config.debug? # => false
|
42
|
+
#
|
43
|
+
# # Net::IMAP.debug is delegated to Net::IMAP::Config.global.debug
|
44
|
+
# Net::IMAP.debug = true
|
45
|
+
# plain_client.config.debug? # => true
|
46
|
+
# debug_client.config.debug? # => true
|
47
|
+
# quiet_client.config.debug? # => false
|
48
|
+
#
|
49
|
+
# Net::IMAP.debug = false
|
50
|
+
# plain_client.config.debug = true
|
51
|
+
# plain_client.config.inherited?(:debug) # => false
|
52
|
+
# plain_client.config.debug? # => true
|
53
|
+
# plain_client.config.reset(:debug)
|
54
|
+
# plain_client.config.inherited?(:debug) # => true
|
55
|
+
# plain_client.config.debug? # => false
|
56
|
+
#
|
57
|
+
# == Versioned defaults
|
58
|
+
#
|
59
|
+
# The effective default configuration for a specific +x.y+ version of
|
60
|
+
# +net-imap+ can be loaded with the +config+ keyword argument to
|
61
|
+
# Net::IMAP.new. Requesting default configurations for previous versions
|
62
|
+
# enables extra backward compatibility with those versions:
|
63
|
+
#
|
64
|
+
# client = Net::IMAP.new(hostname, config: 0.3)
|
65
|
+
# client.config.sasl_ir # => false
|
66
|
+
# client.config.responses_without_block # => :silence_deprecation_warning
|
67
|
+
#
|
68
|
+
# client = Net::IMAP.new(hostname, config: 0.4)
|
69
|
+
# client.config.sasl_ir # => true
|
70
|
+
# client.config.responses_without_block # => :silence_deprecation_warning
|
71
|
+
#
|
72
|
+
# client = Net::IMAP.new(hostname, config: 0.5)
|
73
|
+
# client.config.sasl_ir # => true
|
74
|
+
# client.config.responses_without_block # => :warn
|
75
|
+
#
|
76
|
+
# client = Net::IMAP.new(hostname, config: :future)
|
77
|
+
# client.config.sasl_ir # => true
|
78
|
+
# client.config.responses_without_block # => :raise
|
79
|
+
#
|
80
|
+
# The versioned default configs inherit certain specific config options from
|
81
|
+
# Config.global, for example #debug:
|
82
|
+
#
|
83
|
+
# client = Net::IMAP.new(hostname, config: 0.4)
|
84
|
+
# Net::IMAP.debug = false
|
85
|
+
# client.config.debug? # => false
|
86
|
+
#
|
87
|
+
# Net::IMAP.debug = true
|
88
|
+
# client.config.debug? # => true
|
89
|
+
#
|
90
|
+
# Use #load_defaults to globally behave like a specific version:
|
91
|
+
# client = Net::IMAP.new(hostname)
|
92
|
+
# client.config.sasl_ir # => true
|
93
|
+
# Net::IMAP.config.load_defaults 0.3
|
94
|
+
# client.config.sasl_ir # => false
|
95
|
+
#
|
96
|
+
# === Named defaults
|
97
|
+
# In addition to +x.y+ version numbers, the following aliases are supported:
|
98
|
+
#
|
99
|
+
# [+:default+]
|
100
|
+
# An alias for +:current+.
|
101
|
+
#
|
102
|
+
# >>>
|
103
|
+
# *NOTE*: This is _not_ the same as Config.default. It inherits some
|
104
|
+
# attributes from Config.global, for example: #debug.
|
105
|
+
# [+:current+]
|
106
|
+
# An alias for the current +x.y+ version's defaults.
|
107
|
+
# [+:next+]
|
108
|
+
# The _planned_ config for the next +x.y+ version.
|
109
|
+
# [+:future+]
|
110
|
+
# The _planned_ eventual config for some future +x.y+ version.
|
111
|
+
#
|
112
|
+
# For example, to raise exceptions for all current deprecations:
|
113
|
+
# client = Net::IMAP.new(hostname, config: :future)
|
114
|
+
# client.responses # raises an ArgumentError
|
115
|
+
#
|
116
|
+
# == Thread Safety
|
117
|
+
#
|
118
|
+
# *NOTE:* Updates to config objects are not synchronized for thread-safety.
|
119
|
+
#
|
120
|
+
class Config
|
121
|
+
# Array of attribute names that are _not_ loaded by #load_defaults.
|
122
|
+
DEFAULT_TO_INHERIT = %i[debug].freeze
|
123
|
+
private_constant :DEFAULT_TO_INHERIT
|
124
|
+
|
125
|
+
# The default config, which is hardcoded and frozen.
|
126
|
+
def self.default; @default end
|
127
|
+
|
128
|
+
# The global config object. Also available from Net::IMAP.config.
|
129
|
+
def self.global; @global if defined?(@global) end
|
130
|
+
|
131
|
+
# A hash of hard-coded configurations, indexed by version number or name.
|
132
|
+
def self.version_defaults; @version_defaults end
|
133
|
+
@version_defaults = {}
|
134
|
+
|
135
|
+
# :call-seq:
|
136
|
+
# Net::IMAP::Config[number] -> versioned config
|
137
|
+
# Net::IMAP::Config[symbol] -> named config
|
138
|
+
# Net::IMAP::Config[hash] -> new frozen config
|
139
|
+
# Net::IMAP::Config[config] -> same config
|
140
|
+
#
|
141
|
+
# Given a version number, returns the default configuration for the target
|
142
|
+
# version. See Config@Versioned+defaults.
|
143
|
+
#
|
144
|
+
# Given a version name, returns the default configuration for the target
|
145
|
+
# version. See Config@Named+defaults.
|
146
|
+
#
|
147
|
+
# Given a Hash, creates a new _frozen_ config which inherits from
|
148
|
+
# Config.global. Use Config.new for an unfrozen config.
|
149
|
+
#
|
150
|
+
# Given a config, returns that same config.
|
151
|
+
def self.[](config)
|
152
|
+
if config.is_a?(Config) then config
|
153
|
+
elsif config.nil? && global.nil? then nil
|
154
|
+
elsif config.respond_to?(:to_hash) then new(global, **config).freeze
|
155
|
+
else
|
156
|
+
version_defaults.fetch(config) do
|
157
|
+
case config
|
158
|
+
when Numeric
|
159
|
+
raise RangeError, "unknown config version: %p" % [config]
|
160
|
+
when Symbol
|
161
|
+
raise KeyError, "unknown config name: %p" % [config]
|
162
|
+
else
|
163
|
+
raise TypeError, "no implicit conversion of %s to %s" % [
|
164
|
+
config.class, Config
|
165
|
+
]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
include AttrAccessors
|
172
|
+
include AttrInheritance
|
173
|
+
include AttrTypeCoercion
|
174
|
+
|
175
|
+
# The debug mode (boolean). The default value is +false+.
|
176
|
+
#
|
177
|
+
# When #debug is +true+:
|
178
|
+
# * Data sent to and received from the server will be logged.
|
179
|
+
# * ResponseParser will print warnings with extra detail for parse
|
180
|
+
# errors. _This may include recoverable errors._
|
181
|
+
# * ResponseParser makes extra assertions.
|
182
|
+
#
|
183
|
+
# *NOTE:* Versioned default configs inherit #debug from Config.global, and
|
184
|
+
# #load_defaults will not override #debug.
|
185
|
+
attr_accessor :debug, type: :boolean
|
186
|
+
|
187
|
+
# method: debug?
|
188
|
+
# :call-seq: debug? -> boolean
|
189
|
+
#
|
190
|
+
# Alias for #debug
|
191
|
+
|
192
|
+
# Seconds to wait until a connection is opened.
|
193
|
+
#
|
194
|
+
# If the IMAP object cannot open a connection within this time,
|
195
|
+
# it raises a Net::OpenTimeout exception.
|
196
|
+
#
|
197
|
+
# See Net::IMAP.new.
|
198
|
+
#
|
199
|
+
# The default value is +30+ seconds.
|
200
|
+
attr_accessor :open_timeout, type: Integer
|
201
|
+
|
202
|
+
# Seconds to wait until an IDLE response is received, after
|
203
|
+
# the client asks to leave the IDLE state.
|
204
|
+
#
|
205
|
+
# See Net::IMAP#idle and Net::IMAP#idle_done.
|
206
|
+
#
|
207
|
+
# The default value is +5+ seconds.
|
208
|
+
attr_accessor :idle_response_timeout, type: Integer
|
209
|
+
|
210
|
+
# Whether to use the +SASL-IR+ extension when the server and \SASL
|
211
|
+
# mechanism both support it. Can be overridden by the +sasl_ir+ keyword
|
212
|
+
# parameter to Net::IMAP#authenticate.
|
213
|
+
#
|
214
|
+
# <em>(Support for +SASL-IR+ was added in +v0.4.0+.)</em>
|
215
|
+
#
|
216
|
+
# ==== Valid options
|
217
|
+
#
|
218
|
+
# [+false+ <em>(original behavior, before support was added)</em>]
|
219
|
+
# Do not use +SASL-IR+, even when it is supported by the server and the
|
220
|
+
# mechanism.
|
221
|
+
#
|
222
|
+
# [+true+ <em>(default since +v0.4+)</em>]
|
223
|
+
# Use +SASL-IR+ when it is supported by the server and the mechanism.
|
224
|
+
attr_accessor :sasl_ir, type: :boolean
|
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
|
+
]
|
249
|
+
|
250
|
+
# Controls the behavior of Net::IMAP#responses when called without any
|
251
|
+
# arguments (+type+ or +block+).
|
252
|
+
#
|
253
|
+
# ==== Valid options
|
254
|
+
#
|
255
|
+
# [+:silence_deprecation_warning+ <em>(original behavior)</em>]
|
256
|
+
# Returns the mutable responses hash (without any warnings).
|
257
|
+
# <em>This is not thread-safe.</em>
|
258
|
+
#
|
259
|
+
# [+:warn+ <em>(default since +v0.5+)</em>]
|
260
|
+
# Prints a warning and returns the mutable responses hash.
|
261
|
+
# <em>This is not thread-safe.</em>
|
262
|
+
#
|
263
|
+
# [+:frozen_dup+ <em>(planned default for +v0.6+)</em>]
|
264
|
+
# Returns a frozen copy of the unhandled responses hash, with frozen
|
265
|
+
# array values.
|
266
|
+
#
|
267
|
+
# Note that calling IMAP#responses with a +type+ and without a block is
|
268
|
+
# not configurable and always behaves like +:frozen_dup+.
|
269
|
+
#
|
270
|
+
# <em>(+:frozen_dup+ config option was added in +v0.4.17+)</em>
|
271
|
+
#
|
272
|
+
# [+:raise+]
|
273
|
+
# Raise an ArgumentError with the deprecation warning.
|
274
|
+
#
|
275
|
+
# Note: #responses_without_args is an alias for #responses_without_block.
|
276
|
+
attr_accessor :responses_without_block, type: [
|
277
|
+
:silence_deprecation_warning, :warn, :frozen_dup, :raise,
|
278
|
+
]
|
279
|
+
|
280
|
+
alias responses_without_args responses_without_block # :nodoc:
|
281
|
+
alias responses_without_args= responses_without_block= # :nodoc:
|
282
|
+
|
283
|
+
##
|
284
|
+
# :attr_accessor: responses_without_args
|
285
|
+
#
|
286
|
+
# Alias for responses_without_block
|
287
|
+
|
288
|
+
# Creates a new config object and initialize its attribute with +attrs+.
|
289
|
+
#
|
290
|
+
# If +parent+ is not given, the global config is used by default.
|
291
|
+
#
|
292
|
+
# If a block is given, the new config object is yielded to it.
|
293
|
+
def initialize(parent = Config.global, **attrs)
|
294
|
+
super(parent)
|
295
|
+
update(**attrs)
|
296
|
+
yield self if block_given?
|
297
|
+
end
|
298
|
+
|
299
|
+
# :call-seq: update(**attrs) -> self
|
300
|
+
#
|
301
|
+
# Assigns all of the provided +attrs+ to this config, and returns +self+.
|
302
|
+
#
|
303
|
+
# An ArgumentError is raised unless every key in +attrs+ matches an
|
304
|
+
# assignment method on Config.
|
305
|
+
#
|
306
|
+
# >>>
|
307
|
+
# *NOTE:* #update is not atomic. If an exception is raised due to an
|
308
|
+
# invalid attribute value, +attrs+ may be partially applied.
|
309
|
+
def update(**attrs)
|
310
|
+
unless (bad = attrs.keys.reject { respond_to?(:"#{_1}=") }).empty?
|
311
|
+
raise ArgumentError, "invalid config options: #{bad.join(", ")}"
|
312
|
+
end
|
313
|
+
attrs.each do send(:"#{_1}=", _2) end
|
314
|
+
self
|
315
|
+
end
|
316
|
+
|
317
|
+
# :call-seq:
|
318
|
+
# with(**attrs) -> config
|
319
|
+
# with(**attrs) {|config| } -> result
|
320
|
+
#
|
321
|
+
# Without a block, returns a new config which inherits from self. With a
|
322
|
+
# block, yields the new config and returns the block's result.
|
323
|
+
#
|
324
|
+
# If no keyword arguments are given, an ArgumentError will be raised.
|
325
|
+
#
|
326
|
+
# If +self+ is frozen, the copy will also be frozen.
|
327
|
+
def with(**attrs)
|
328
|
+
attrs.empty? and
|
329
|
+
raise ArgumentError, "expected keyword arguments, none given"
|
330
|
+
copy = new(**attrs)
|
331
|
+
copy.freeze if frozen?
|
332
|
+
block_given? ? yield(copy) : copy
|
333
|
+
end
|
334
|
+
|
335
|
+
# :call-seq: load_defaults(version) -> self
|
336
|
+
#
|
337
|
+
# Resets the current config to behave like the versioned default
|
338
|
+
# configuration for +version+. #parent will not be changed.
|
339
|
+
#
|
340
|
+
# Some config attributes default to inheriting from their #parent (which
|
341
|
+
# is usually Config.global) and are left unchanged, for example: #debug.
|
342
|
+
#
|
343
|
+
# See Config@Versioned+defaults and Config@Named+defaults.
|
344
|
+
def load_defaults(version)
|
345
|
+
[Numeric, Symbol, String].any? { _1 === version } or
|
346
|
+
raise ArgumentError, "expected number or symbol, got %p" % [version]
|
347
|
+
update(**Config[version].defaults_hash)
|
348
|
+
end
|
349
|
+
|
350
|
+
# :call-seq: to_h -> hash
|
351
|
+
#
|
352
|
+
# Returns all config attributes in a hash.
|
353
|
+
def to_h; data.members.to_h { [_1, send(_1)] } end
|
354
|
+
|
355
|
+
protected
|
356
|
+
|
357
|
+
def defaults_hash
|
358
|
+
to_h.reject {|k,v| DEFAULT_TO_INHERIT.include?(k) }
|
359
|
+
end
|
360
|
+
|
361
|
+
@default = new(
|
362
|
+
debug: false,
|
363
|
+
open_timeout: 30,
|
364
|
+
idle_response_timeout: 5,
|
365
|
+
sasl_ir: true,
|
366
|
+
enforce_logindisabled: true,
|
367
|
+
responses_without_block: :warn,
|
368
|
+
).freeze
|
369
|
+
|
370
|
+
@global = default.new
|
371
|
+
|
372
|
+
version_defaults[:default] = Config[default.send(:defaults_hash)]
|
373
|
+
version_defaults[:current] = Config[:default]
|
374
|
+
|
375
|
+
version_defaults[0] = Config[:current].dup.update(
|
376
|
+
sasl_ir: false,
|
377
|
+
responses_without_block: :silence_deprecation_warning,
|
378
|
+
enforce_logindisabled: false,
|
379
|
+
).freeze
|
380
|
+
version_defaults[0.0] = Config[0]
|
381
|
+
version_defaults[0.1] = Config[0]
|
382
|
+
version_defaults[0.2] = Config[0]
|
383
|
+
version_defaults[0.3] = Config[0]
|
384
|
+
|
385
|
+
version_defaults[0.4] = Config[0.3].dup.update(
|
386
|
+
sasl_ir: true,
|
387
|
+
).freeze
|
388
|
+
|
389
|
+
version_defaults[0.5] = Config[:current]
|
390
|
+
|
391
|
+
version_defaults[0.6] = Config[0.5].dup.update(
|
392
|
+
responses_without_block: :frozen_dup,
|
393
|
+
).freeze
|
394
|
+
version_defaults[:next] = Config[0.6]
|
395
|
+
version_defaults[:future] = Config[:next]
|
396
|
+
|
397
|
+
version_defaults.freeze
|
398
|
+
end
|
399
|
+
end
|
400
|
+
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
|
@@ -16,8 +16,8 @@ module Net
|
|
16
16
|
#
|
17
17
|
# ==== Obsolete arguments
|
18
18
|
#
|
19
|
-
#
|
20
|
-
# deprecated by a future release.
|
19
|
+
# Use of obsolete arguments does not print a warning. Obsolete arguments
|
20
|
+
# will be deprecated by a future release.
|
21
21
|
#
|
22
22
|
# If a second positional argument is given and it is a hash (or is
|
23
23
|
# convertible via +#to_hash+), it is converted to keyword arguments.
|
@@ -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
|
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
|
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
|
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
|
data/lib/net/imap/errors.rb
CHANGED
@@ -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
|
@@ -939,7 +939,8 @@ module Net
|
|
939
939
|
# for something else?
|
940
940
|
#++
|
941
941
|
def media_subtype
|
942
|
-
warn("media_subtype is obsolete, use subtype instead.\n",
|
942
|
+
warn("media_subtype is obsolete, use subtype instead.\n",
|
943
|
+
uplevel: 1, category: :deprecated)
|
943
944
|
return subtype
|
944
945
|
end
|
945
946
|
end
|
@@ -984,7 +985,8 @@ module Net
|
|
984
985
|
# generate a warning message to +stderr+, then return
|
985
986
|
# the value of +subtype+.
|
986
987
|
def media_subtype
|
987
|
-
warn("media_subtype is obsolete, use subtype instead.\n",
|
988
|
+
warn("media_subtype is obsolete, use subtype instead.\n",
|
989
|
+
uplevel: 1, category: :deprecated)
|
988
990
|
return subtype
|
989
991
|
end
|
990
992
|
end
|
@@ -1040,77 +1042,6 @@ module Net
|
|
1040
1042
|
end
|
1041
1043
|
end
|
1042
1044
|
|
1043
|
-
# BodyTypeAttachment is not used and will be removed in an upcoming release.
|
1044
|
-
#
|
1045
|
-
# === Bug Analysis
|
1046
|
-
#
|
1047
|
-
# \IMAP body structures are parenthesized lists and assign their fields
|
1048
|
-
# positionally, so missing fields change the interpretation of all
|
1049
|
-
# following fields. Additionally, different body types have a different
|
1050
|
-
# number of required fields, followed by optional "extension" fields.
|
1051
|
-
#
|
1052
|
-
# BodyTypeAttachment was previously returned when a "message/rfc822" part,
|
1053
|
-
# which should be sent as <tt>body-type-msg</tt> with ten required fields,
|
1054
|
-
# was actually sent as a <tt>body-type-basic</tt> with _seven_ required
|
1055
|
-
# fields.
|
1056
|
-
#
|
1057
|
-
# basic => type, subtype, param, id, desc, enc, octets, md5=nil, dsp=nil, lang=nil, loc=nil, *ext
|
1058
|
-
# msg => type, subtype, param, id, desc, enc, octets, envelope, body, lines, md5=nil, ...
|
1059
|
-
#
|
1060
|
-
# Normally, +envelope+ and +md5+ are incompatible, but Net::IMAP leniently
|
1061
|
-
# allowed buggy servers to send +NIL+ for +envelope+. As a result, when a
|
1062
|
-
# server sent a <tt>message/rfc822</tt> part with +NIL+ for +md5+ and a
|
1063
|
-
# non-<tt>NIL</tt> +dsp+, Net::IMAP misinterpreted the
|
1064
|
-
# <tt>Content-Disposition</tt> as if it were a strange body type. In all
|
1065
|
-
# reported cases, the <tt>Content-Disposition</tt> was "attachment", so
|
1066
|
-
# BodyTypeAttachment was created as the workaround.
|
1067
|
-
#
|
1068
|
-
# === Current behavior
|
1069
|
-
#
|
1070
|
-
# When interpreted strictly, +envelope+ and +md5+ are incompatible. So the
|
1071
|
-
# current parsing algorithm peeks ahead after it has received the seventh
|
1072
|
-
# body field. If the next token is not the start of an +envelope+, we assume
|
1073
|
-
# the server has incorrectly sent us a <tt>body-type-basic</tt> and return
|
1074
|
-
# BodyTypeBasic. As a result, what was previously BodyTypeMessage#body =>
|
1075
|
-
# BodyTypeAttachment is now BodyTypeBasic#disposition => ContentDisposition.
|
1076
|
-
#
|
1077
|
-
class BodyTypeAttachment < Struct.new(:dsp_type, :_unused_, :param)
|
1078
|
-
# *invalid for BodyTypeAttachment*
|
1079
|
-
def media_type
|
1080
|
-
warn(<<~WARN, uplevel: 1)
|
1081
|
-
BodyTypeAttachment#media_type is obsolete. Use dsp_type instead.
|
1082
|
-
WARN
|
1083
|
-
dsp_type
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
# *invalid for BodyTypeAttachment*
|
1087
|
-
def subtype
|
1088
|
-
warn("BodyTypeAttachment#subtype is obsolete.\n", uplevel: 1)
|
1089
|
-
nil
|
1090
|
-
end
|
1091
|
-
|
1092
|
-
##
|
1093
|
-
# method: dsp_type
|
1094
|
-
# :call-seq: dsp_type -> string
|
1095
|
-
#
|
1096
|
-
# Returns the content disposition type, as defined by
|
1097
|
-
# [DISPOSITION[https://tools.ietf.org/html/rfc2183]].
|
1098
|
-
|
1099
|
-
##
|
1100
|
-
# method: param
|
1101
|
-
# :call-seq: param -> hash
|
1102
|
-
#
|
1103
|
-
# Returns a hash representing parameters of the Content-Disposition
|
1104
|
-
# field, as defined by [DISPOSITION[https://tools.ietf.org/html/rfc2183]].
|
1105
|
-
|
1106
|
-
##
|
1107
|
-
def multipart?
|
1108
|
-
return false
|
1109
|
-
end
|
1110
|
-
end
|
1111
|
-
|
1112
|
-
deprecate_constant :BodyTypeAttachment
|
1113
|
-
|
1114
1045
|
# Net::IMAP::BodyTypeMultipart represents body structures of messages and
|
1115
1046
|
# message parts, when <tt>Content-Type</tt> is <tt>multipart/*</tt>.
|
1116
1047
|
class BodyTypeMultipart < Struct.new(:media_type, :subtype,
|
@@ -1182,29 +1113,11 @@ module Net
|
|
1182
1113
|
# generate a warning message to +stderr+, then return
|
1183
1114
|
# the value of +subtype+.
|
1184
1115
|
def media_subtype
|
1185
|
-
warn("media_subtype is obsolete, use subtype instead.\n",
|
1116
|
+
warn("media_subtype is obsolete, use subtype instead.\n",
|
1117
|
+
uplevel: 1, category: :deprecated)
|
1186
1118
|
return subtype
|
1187
1119
|
end
|
1188
1120
|
end
|
1189
1121
|
|
1190
|
-
# === Obsolete
|
1191
|
-
# BodyTypeExtension is not used and will be removed in an upcoming release.
|
1192
|
-
#
|
1193
|
-
# >>>
|
1194
|
-
# BodyTypeExtension was (incorrectly) used for <tt>message/*</tt> parts
|
1195
|
-
# (besides <tt>message/rfc822</tt>, which correctly uses BodyTypeMessage).
|
1196
|
-
#
|
1197
|
-
# Net::IMAP now (correctly) parses all message types (other than
|
1198
|
-
# <tt>message/rfc822</tt> or <tt>message/global</tt>) as BodyTypeBasic.
|
1199
|
-
class BodyTypeExtension < Struct.new(:media_type, :subtype,
|
1200
|
-
:params, :content_id,
|
1201
|
-
:description, :encoding, :size)
|
1202
|
-
def multipart?
|
1203
|
-
return false
|
1204
|
-
end
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
deprecate_constant :BodyTypeExtension
|
1208
|
-
|
1209
1122
|
end
|
1210
1123
|
end
|
@@ -154,7 +154,7 @@ module Net
|
|
154
154
|
end
|
155
155
|
|
156
156
|
# To be used conditionally:
|
157
|
-
# assert_no_lookahead if
|
157
|
+
# assert_no_lookahead if config.debug?
|
158
158
|
def assert_no_lookahead
|
159
159
|
@token.nil? or
|
160
160
|
parse_error("assertion failed: expected @token.nil?, actual %s: %p",
|
@@ -181,23 +181,23 @@ module Net
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def peek_str?(str)
|
184
|
-
assert_no_lookahead if
|
184
|
+
assert_no_lookahead if config.debug?
|
185
185
|
@str[@pos, str.length] == str
|
186
186
|
end
|
187
187
|
|
188
188
|
def peek_re(re)
|
189
|
-
assert_no_lookahead if
|
189
|
+
assert_no_lookahead if config.debug?
|
190
190
|
re.match(@str, @pos)
|
191
191
|
end
|
192
192
|
|
193
193
|
def accept_re(re)
|
194
|
-
assert_no_lookahead if
|
194
|
+
assert_no_lookahead if config.debug?
|
195
195
|
re.match(@str, @pos) and @pos = $~.end(0)
|
196
196
|
$~
|
197
197
|
end
|
198
198
|
|
199
199
|
def match_re(re, name)
|
200
|
-
assert_no_lookahead if
|
200
|
+
assert_no_lookahead if config.debug?
|
201
201
|
if re.match(@str, @pos)
|
202
202
|
@pos = $~.end(0)
|
203
203
|
$~
|
@@ -212,7 +212,7 @@ module Net
|
|
212
212
|
|
213
213
|
def parse_error(fmt, *args)
|
214
214
|
msg = format(fmt, *args)
|
215
|
-
if
|
215
|
+
if config.debug?
|
216
216
|
local_path = File.dirname(__dir__)
|
217
217
|
tok = @token ? "%s: %p" % [@token.symbol, @token.value] : "nil"
|
218
218
|
warn "%s %s: %s" % [self.class, __method__, msg]
|