net-imap 0.4.18 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f71a5476fad0d1bbe6dd52a510fa083ef6b35cb98f27af536a5991ebe9f31244
4
- data.tar.gz: 10082ff774cfccf2b0b43c58cf62bdb99b3e2e75cf7ff7fcb9c508cde8dc33ed
3
+ metadata.gz: 2c89d97e842bce303df112c3fbc0f048f20a2ff1dbf3b85bb2314ea0d2e207c5
4
+ data.tar.gz: 11d6ec196e1e768f61a17b0ce7f385a11eb03e3e92af8ab327ba9a90699ee940
5
5
  SHA512:
6
- metadata.gz: c98013c4ad6493bb0e455cced96388e35214567eb0359085e5023beffc9d748472ff729dc70718a3e66ba86a78e5a1d5de803fc68e5012a6da852e57f951398c
7
- data.tar.gz: bd5b766443689dad66eb1caf4479763f8181d38e64b3db7fdf415b277d27721fda9d4ce634e4638ab4f0860e3a82f63a37581830e81a617fe08baaff07262694
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)
@@ -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
@@ -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
@@ -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", uplevel: 1)
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", uplevel: 1)
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", uplevel: 1)
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 grabs the raw encoded value using @str and @pos. A future
1321
- # version may simply return the decoded astring value. Although that is
1322
- # technically incompatible, it should almost never make a difference: all
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
- # Although RFC3501 allows any astring, RFC5322-valid header names are one
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
- def header_fld_name
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
- # This API is *experimental*, and may change.
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
- # Create an AuthenticationExchange from a client adapter and a mechanism
14
- # authenticator:
15
- # def authenticate(mechanism, ...)
16
- # authenticator = SASL.authenticator(mechanism, ...)
17
- # SASL::AuthenticationExchange.new(
18
- # sasl_adapter, mechanism, authenticator
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
- # def sasl_adapter = MyClientAdapter.new(self, &method(:send_command))
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
- # SASL::AuthenticationExchange.build(sasl_adapter, ...)
29
- # .authenticate
28
+ # MyClient::SASLAdapter.new(self).authenticate(...)
30
29
  # end
31
30
  #
32
- # As a convenience, ::authenticate combines ::build and #authenticate:
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
- # Likewise, ClientAdapter#authenticate delegates to #authenticate:
38
- # def authenticate(...) = sasl_adapter.authenticate(...)
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
- # Use +registry+ to override the global Authenticators registry.
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 = -mechanism.to_s.upcase.tr(?_, ?-)
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 = -name.to_s.upcase.tr(?_, ?-)
86
+ key = Authenticators.normalize_name(name)
83
87
  @authenticators.delete(key)
84
88
  end
85
89
 
86
90
  def mechanism?(name)
87
- key = -name.to_s.upcase.tr(?_, ?-)
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 = -mechanism.to_s.upcase.tr(?_, ?-)
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