net-imap 0.4.16 → 0.5.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 +4 -4
- data/Gemfile +7 -1
- data/lib/net/imap/authenticators.rb +2 -2
- data/lib/net/imap/command_data.rb +11 -0
- data/lib/net/imap/config.rb +96 -35
- data/lib/net/imap/data_encoding.rb +3 -3
- data/lib/net/imap/deprecated_client_options.rb +6 -3
- data/lib/net/imap/errors.rb +6 -0
- data/lib/net/imap/response_data.rb +6 -93
- data/lib/net/imap/response_parser.rb +5 -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 +21 -20
- data/lib/net/imap.rb +133 -63
- data/net-imap.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c89d97e842bce303df112c3fbc0f048f20a2ff1dbf3b85bb2314ea0d2e207c5
|
4
|
+
data.tar.gz: 11d6ec196e1e768f61a17b0ce7f385a11eb03e3e92af8ab327ba9a90699ee940
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca70e20c3c70f4ca57822f70936546adb3129dd7c0771ef2d054b0356ed4f6a994b7453803cc06bd25ebb37dc0ed10f60b5541bc56749dee38a6126264344599
|
7
|
+
data.tar.gz: 2921a79dbdab7bd0476d883c18db50150388d587c711270faac99ad4505574a23e6532fe61a4fb48f51c8bddea6641d96f81d9dcbe245b4d4f4542fcc7418566
|
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
|
@@ -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
|
@@ -179,6 +179,7 @@ module Net
|
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
|
+
# *DEPRECATED*. Replaced by SequenceSet.
|
182
183
|
class MessageSet # :nodoc:
|
183
184
|
def send_data(imap, tag)
|
184
185
|
imap.__send__(:put_string, format_internal(@data))
|
@@ -192,6 +193,16 @@ module Net
|
|
192
193
|
|
193
194
|
def initialize(data)
|
194
195
|
@data = data
|
196
|
+
warn("DEPRECATED: #{MessageSet} should be replaced with #{SequenceSet}.",
|
197
|
+
uplevel: 1, category: :deprecated)
|
198
|
+
begin
|
199
|
+
# to ensure the input works with SequenceSet, too
|
200
|
+
SequenceSet.new(data)
|
201
|
+
rescue
|
202
|
+
warn "MessageSet input is incompatible with SequenceSet: [%s] %s" % [
|
203
|
+
$!.class, $!.message
|
204
|
+
]
|
205
|
+
end
|
195
206
|
end
|
196
207
|
|
197
208
|
def format_internal(data)
|
data/lib/net/imap/config.rb
CHANGED
@@ -7,10 +7,10 @@ require_relative "config/attr_type_coercion"
|
|
7
7
|
module Net
|
8
8
|
class IMAP
|
9
9
|
|
10
|
-
# Net::IMAP::Config
|
11
|
-
#
|
12
|
-
# Net::IMAP::Config.global, and the
|
13
|
-
# seen at Net::IMAP#config.
|
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
14
|
#
|
15
15
|
# When creating a new client, all unhandled keyword arguments to
|
16
16
|
# Net::IMAP.new are delegated to Config.new. Every client has its own
|
@@ -128,7 +128,7 @@ module Net
|
|
128
128
|
# The global config object. Also available from Net::IMAP.config.
|
129
129
|
def self.global; @global if defined?(@global) end
|
130
130
|
|
131
|
-
# A hash of hard-coded configurations, indexed by version number.
|
131
|
+
# A hash of hard-coded configurations, indexed by version number or name.
|
132
132
|
def self.version_defaults; @version_defaults end
|
133
133
|
@version_defaults = {}
|
134
134
|
|
@@ -172,9 +172,16 @@ module Net
|
|
172
172
|
include AttrInheritance
|
173
173
|
include AttrTypeCoercion
|
174
174
|
|
175
|
-
# The debug mode (boolean)
|
175
|
+
# The debug mode (boolean). The default value is +false+.
|
176
176
|
#
|
177
|
-
#
|
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.
|
178
185
|
attr_accessor :debug, type: :boolean
|
179
186
|
|
180
187
|
# method: debug?
|
@@ -200,34 +207,84 @@ module Net
|
|
200
207
|
# The default value is +5+ seconds.
|
201
208
|
attr_accessor :idle_response_timeout, type: Integer
|
202
209
|
|
203
|
-
# :markup: markdown
|
204
|
-
#
|
205
210
|
# Whether to use the +SASL-IR+ extension when the server and \SASL
|
206
|
-
# mechanism both support it.
|
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
|
207
217
|
#
|
208
|
-
#
|
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.
|
209
221
|
#
|
210
|
-
#
|
211
|
-
#
|
212
|
-
# | _original_ | +false+ <em>(extension unsupported)</em> |
|
213
|
-
# | v0.4 | +true+ <em>(support added)</em> |
|
222
|
+
# [+true+ <em>(default since +v0.4+)</em>]
|
223
|
+
# Use +SASL-IR+ when it is supported by the server and the mechanism.
|
214
224
|
attr_accessor :sasl_ir, type: :boolean
|
215
225
|
|
216
|
-
#
|
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
|
217
254
|
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
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>
|
221
258
|
#
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
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.
|
227
276
|
attr_accessor :responses_without_block, type: [
|
228
|
-
:silence_deprecation_warning, :warn, :raise,
|
277
|
+
:silence_deprecation_warning, :warn, :frozen_dup, :raise,
|
229
278
|
]
|
230
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
|
+
|
231
288
|
# Creates a new config object and initialize its attribute with +attrs+.
|
232
289
|
#
|
233
290
|
# If +parent+ is not given, the global config is used by default.
|
@@ -306,32 +363,36 @@ module Net
|
|
306
363
|
open_timeout: 30,
|
307
364
|
idle_response_timeout: 5,
|
308
365
|
sasl_ir: true,
|
309
|
-
|
366
|
+
enforce_logindisabled: true,
|
367
|
+
responses_without_block: :warn,
|
310
368
|
).freeze
|
311
369
|
|
312
370
|
@global = default.new
|
313
371
|
|
314
|
-
version_defaults[
|
372
|
+
version_defaults[:default] = Config[default.send(:defaults_hash)]
|
373
|
+
version_defaults[:current] = Config[:default]
|
315
374
|
|
316
|
-
version_defaults[0] = Config[
|
375
|
+
version_defaults[0] = Config[:current].dup.update(
|
317
376
|
sasl_ir: false,
|
377
|
+
responses_without_block: :silence_deprecation_warning,
|
378
|
+
enforce_logindisabled: false,
|
318
379
|
).freeze
|
319
380
|
version_defaults[0.0] = Config[0]
|
320
381
|
version_defaults[0.1] = Config[0]
|
321
382
|
version_defaults[0.2] = Config[0]
|
322
383
|
version_defaults[0.3] = Config[0]
|
323
384
|
|
324
|
-
version_defaults[0.
|
325
|
-
|
385
|
+
version_defaults[0.4] = Config[0.3].dup.update(
|
386
|
+
sasl_ir: true,
|
326
387
|
).freeze
|
327
388
|
|
328
|
-
version_defaults[
|
329
|
-
version_defaults[:current] = Config[0.4]
|
330
|
-
version_defaults[:next] = Config[0.5]
|
389
|
+
version_defaults[0.5] = Config[:current]
|
331
390
|
|
332
|
-
version_defaults[
|
333
|
-
responses_without_block: :
|
391
|
+
version_defaults[0.6] = Config[0.5].dup.update(
|
392
|
+
responses_without_block: :frozen_dup,
|
334
393
|
).freeze
|
394
|
+
version_defaults[:next] = Config[0.6]
|
395
|
+
version_defaults[:future] = Config[:next]
|
335
396
|
|
336
397
|
version_defaults.freeze
|
337
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
|
@@ -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
|
@@ -1317,31 +1317,19 @@ module Net
|
|
1317
1317
|
# header-fld-name = astring
|
1318
1318
|
#
|
1319
1319
|
# NOTE: Previously, Net::IMAP recreated the raw original source string.
|
1320
|
-
# Now, it
|
1321
|
-
#
|
1322
|
-
#
|
1323
|
-
# standard header field names are valid atoms:
|
1320
|
+
# Now, it returns the decoded astring value. Although this is technically
|
1321
|
+
# incompatible, it should almost never make a difference: all standard
|
1322
|
+
# header field names are valid atoms:
|
1324
1323
|
#
|
1325
1324
|
# https://www.iana.org/assignments/message-headers/message-headers.xhtml
|
1326
1325
|
#
|
1327
|
-
#
|
1328
|
-
# or more of the printable US-ASCII characters, except SP and colon. So
|
1329
|
-
# empty string isn't valid, and literals aren't needed and should not be
|
1330
|
-
# used. This is explicitly unchanged by [I18N-HDRS] (RFC6532).
|
1331
|
-
#
|
1332
|
-
# RFC5233:
|
1326
|
+
# See also RFC5233:
|
1333
1327
|
# optional-field = field-name ":" unstructured CRLF
|
1334
1328
|
# field-name = 1*ftext
|
1335
1329
|
# ftext = %d33-57 / ; Printable US-ASCII
|
1336
1330
|
# %d59-126 ; characters not including
|
1337
1331
|
# ; ":".
|
1338
|
-
|
1339
|
-
assert_no_lookahead
|
1340
|
-
start = @pos
|
1341
|
-
astring
|
1342
|
-
end_pos = @token ? @pos - 1 : @pos
|
1343
|
-
@str[start...end_pos]
|
1344
|
-
end
|
1332
|
+
alias header_fld_name astring
|
1345
1333
|
|
1346
1334
|
# mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list /
|
1347
1335
|
# "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
|
@@ -4,44 +4,76 @@ module Net
|
|
4
4
|
class IMAP
|
5
5
|
module SASL
|
6
6
|
|
7
|
-
#
|
7
|
+
# AuthenticationExchange is used internally by Net::IMAP#authenticate.
|
8
|
+
# But the API is still *experimental*, and may change.
|
8
9
|
#
|
9
10
|
# TODO: catch exceptions in #process and send #cancel_response.
|
10
11
|
# TODO: raise an error if the command succeeds after being canceled.
|
11
12
|
# TODO: use with more clients, to verify the API can accommodate them.
|
13
|
+
# TODO: pass ClientAdapter#service to SASL.authenticator
|
12
14
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# ).authenticate
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# private
|
15
|
+
# An AuthenticationExchange represents a single attempt to authenticate
|
16
|
+
# a SASL client to a SASL server. It is created from a client adapter, a
|
17
|
+
# mechanism name, and a mechanism authenticator. When #authenticate is
|
18
|
+
# called, it will send the appropriate authenticate command to the server,
|
19
|
+
# returning the client response on success and raising an exception on
|
20
|
+
# failure.
|
23
21
|
#
|
24
|
-
#
|
22
|
+
# In most cases, the client will not need to use
|
23
|
+
# SASL::AuthenticationExchange directly at all. Instead, use
|
24
|
+
# SASL::ClientAdapter#authenticate. If customizations are needed, the
|
25
|
+
# custom client adapter is probably the best place for that code.
|
25
26
|
#
|
26
|
-
# Or delegate creation of the authenticator to ::build:
|
27
27
|
# def authenticate(...)
|
28
|
-
#
|
29
|
-
# .authenticate
|
28
|
+
# MyClient::SASLAdapter.new(self).authenticate(...)
|
30
29
|
# end
|
31
30
|
#
|
32
|
-
#
|
31
|
+
# SASL::ClientAdapter#authenticate delegates to ::authenticate, like so:
|
32
|
+
#
|
33
33
|
# def authenticate(...)
|
34
|
+
# sasl_adapter = MyClient::SASLAdapter.new(self)
|
34
35
|
# SASL::AuthenticationExchange.authenticate(sasl_adapter, ...)
|
35
36
|
# end
|
36
37
|
#
|
37
|
-
#
|
38
|
-
#
|
38
|
+
# ::authenticate simply delegates to ::build and #authenticate, like so:
|
39
|
+
#
|
40
|
+
# def authenticate(...)
|
41
|
+
# sasl_adapter = MyClient::SASLAdapter.new(self)
|
42
|
+
# SASL::AuthenticationExchange
|
43
|
+
# .build(sasl_adapter, ...)
|
44
|
+
# .authenticate
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# And ::build delegates to SASL.authenticator and ::new, like so:
|
48
|
+
#
|
49
|
+
# def authenticate(mechanism, ...)
|
50
|
+
# sasl_adapter = MyClient::SASLAdapter.new(self)
|
51
|
+
# authenticator = SASL.authenticator(mechanism, ...)
|
52
|
+
# SASL::AuthenticationExchange
|
53
|
+
# .new(sasl_adapter, mechanism, authenticator)
|
54
|
+
# .authenticate
|
55
|
+
# end
|
39
56
|
#
|
40
57
|
class AuthenticationExchange
|
41
58
|
# Convenience method for <tt>build(...).authenticate</tt>
|
59
|
+
#
|
60
|
+
# See also: SASL::ClientAdapter#authenticate
|
42
61
|
def self.authenticate(...) build(...).authenticate end
|
43
62
|
|
44
|
-
#
|
63
|
+
# Convenience method to combine the creation of a new authenticator and
|
64
|
+
# a new Authentication exchange.
|
65
|
+
#
|
66
|
+
# +client+ must be an instance of SASL::ClientAdapter.
|
67
|
+
#
|
68
|
+
# +mechanism+ must be a SASL mechanism name, as a string or symbol.
|
69
|
+
#
|
70
|
+
# +sasl_ir+ allows or disallows sending an "initial response", depending
|
71
|
+
# also on whether the server capabilities, mechanism authenticator, and
|
72
|
+
# client adapter all support it. Defaults to +true+.
|
73
|
+
#
|
74
|
+
# +mechanism+, +args+, +kwargs+, and +block+ are all forwarded to
|
75
|
+
# SASL.authenticator. Use the +registry+ kwarg to override the global
|
76
|
+
# SASL::Authenticators registry.
|
45
77
|
def self.build(client, mechanism, *args, sasl_ir: true, **kwargs, &block)
|
46
78
|
authenticator = SASL.authenticator(mechanism, *args, **kwargs, &block)
|
47
79
|
new(client, mechanism, authenticator, sasl_ir: sasl_ir)
|
@@ -51,7 +83,7 @@ module Net
|
|
51
83
|
|
52
84
|
def initialize(client, mechanism, authenticator, sasl_ir: true)
|
53
85
|
@client = client
|
54
|
-
@mechanism =
|
86
|
+
@mechanism = Authenticators.normalize_name(mechanism)
|
55
87
|
@authenticator = authenticator
|
56
88
|
@sasl_ir = sasl_ir
|
57
89
|
@processed = false
|
@@ -21,6 +21,10 @@ module Net::IMAP::SASL
|
|
21
21
|
# ScramSHA1Authenticator for examples.
|
22
22
|
class Authenticators
|
23
23
|
|
24
|
+
# Normalize the mechanism name as an uppercase string, with underscores
|
25
|
+
# converted to dashes.
|
26
|
+
def self.normalize_name(mechanism) -(mechanism.to_s.upcase.tr(?_, ?-)) end
|
27
|
+
|
24
28
|
# Create a new Authenticators registry.
|
25
29
|
#
|
26
30
|
# This class is usually not instantiated directly. Use SASL.authenticators
|
@@ -65,7 +69,6 @@ module Net::IMAP::SASL
|
|
65
69
|
# lazily loaded from <tt>Net::IMAP::SASL::#{name}Authenticator</tt> (case is
|
66
70
|
# preserved and non-alphanumeric characters are removed..
|
67
71
|
def add_authenticator(name, authenticator = nil)
|
68
|
-
key = -name.to_s.upcase.tr(?_, ?-)
|
69
72
|
authenticator ||= begin
|
70
73
|
class_name = "#{name.gsub(/[^a-zA-Z0-9]/, "")}Authenticator".to_sym
|
71
74
|
auth_class = nil
|
@@ -74,17 +77,18 @@ module Net::IMAP::SASL
|
|
74
77
|
auth_class.new(*creds, **props, &block)
|
75
78
|
}
|
76
79
|
end
|
80
|
+
key = Authenticators.normalize_name(name)
|
77
81
|
@authenticators[key] = authenticator
|
78
82
|
end
|
79
83
|
|
80
84
|
# Removes the authenticator registered for +name+
|
81
85
|
def remove_authenticator(name)
|
82
|
-
key =
|
86
|
+
key = Authenticators.normalize_name(name)
|
83
87
|
@authenticators.delete(key)
|
84
88
|
end
|
85
89
|
|
86
90
|
def mechanism?(name)
|
87
|
-
key =
|
91
|
+
key = Authenticators.normalize_name(name)
|
88
92
|
@authenticators.key?(key)
|
89
93
|
end
|
90
94
|
|
@@ -105,7 +109,7 @@ module Net::IMAP::SASL
|
|
105
109
|
# only. Protocol client users should see refer to their client's
|
106
110
|
# documentation, e.g. Net::IMAP#authenticate.
|
107
111
|
def authenticator(mechanism, ...)
|
108
|
-
key =
|
112
|
+
key = Authenticators.normalize_name(mechanism)
|
109
113
|
auth = @authenticators.fetch(key) do
|
110
114
|
raise ArgumentError, 'unknown auth type - "%s"' % key
|
111
115
|
end
|