net-imap 0.5.14 → 0.6.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/net/imap/command_data.rb +12 -223
- data/lib/net/imap/config/attr_inheritance.rb +14 -1
- data/lib/net/imap/config/attr_version_defaults.rb +1 -1
- data/lib/net/imap/config.rb +175 -35
- data/lib/net/imap/connection_state.rb +1 -1
- data/lib/net/imap/data_encoding.rb +77 -28
- data/lib/net/imap/esearch_result.rb +6 -0
- data/lib/net/imap/response_data.rb +5 -23
- data/lib/net/imap/response_parser.rb +8 -13
- data/lib/net/imap/response_reader.rb +5 -11
- data/lib/net/imap/sasl/scram_authenticator.rb +0 -74
- data/lib/net/imap/search_result.rb +6 -0
- data/lib/net/imap/sequence_set.rb +622 -327
- data/lib/net/imap/uidplus_data.rb +2 -63
- data/lib/net/imap.rb +49 -132
- data/net-imap.gemspec +1 -1
- metadata +3 -4
- data/lib/net/imap/data_lite.rb +0 -226
|
@@ -155,57 +155,106 @@ module Net
|
|
|
155
155
|
|
|
156
156
|
# Common validators of number and nz_number types
|
|
157
157
|
module NumValidator # :nodoc
|
|
158
|
+
NUMBER_RE = /\A(?:0|[1-9]\d*)\z/
|
|
158
159
|
module_function
|
|
159
160
|
|
|
160
|
-
# Check is
|
|
161
|
+
# Check if argument is a valid 'number' according to RFC 3501
|
|
162
|
+
# number = 1*DIGIT
|
|
163
|
+
# ; Unsigned 32-bit integer
|
|
164
|
+
# ; (0 <= n < 4,294,967,296)
|
|
161
165
|
def valid_number?(num)
|
|
162
|
-
|
|
163
|
-
# number = 1*DIGIT
|
|
164
|
-
# ; Unsigned 32-bit integer
|
|
165
|
-
# ; (0 <= n < 4,294,967,296)
|
|
166
|
-
num >= 0 && num < 4294967296
|
|
166
|
+
0 <= num && num <= 0xffff_ffff
|
|
167
167
|
end
|
|
168
168
|
|
|
169
|
-
# Check is
|
|
169
|
+
# Check if argument is a valid 'nz-number' according to RFC 3501
|
|
170
|
+
# nz-number = digit-nz *DIGIT
|
|
171
|
+
# ; Non-zero unsigned 32-bit integer
|
|
172
|
+
# ; (0 < n < 4,294,967,296)
|
|
170
173
|
def valid_nz_number?(num)
|
|
171
|
-
|
|
172
|
-
# nz-number = digit-nz *DIGIT
|
|
173
|
-
# ; Non-zero unsigned 32-bit integer
|
|
174
|
-
# ; (0 < n < 4,294,967,296)
|
|
175
|
-
num != 0 && valid_number?(num)
|
|
174
|
+
0 < num && num <= 0xffff_ffff
|
|
176
175
|
end
|
|
177
176
|
|
|
178
|
-
# Check is
|
|
177
|
+
# Check if argument is a valid 'mod-sequence-value' according to RFC 4551
|
|
178
|
+
# mod-sequence-value = 1*DIGIT
|
|
179
|
+
# ; Positive unsigned 64-bit integer
|
|
180
|
+
# ; (mod-sequence)
|
|
181
|
+
# ; (1 <= n < 18,446,744,073,709,551,615)
|
|
179
182
|
def valid_mod_sequence_value?(num)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
1 <= num && num < 0xffff_ffff_ffff_ffff
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Check if argument is a valid 'mod-sequence-valzer' according to RFC 4551
|
|
187
|
+
# mod-sequence-valzer = "0" / mod-sequence-value
|
|
188
|
+
def valid_mod_sequence_valzer?(num)
|
|
189
|
+
0 <= num && num < 0xffff_ffff_ffff_ffff
|
|
185
190
|
end
|
|
186
191
|
|
|
187
192
|
# Ensure argument is 'number' or raise DataFormatError
|
|
188
193
|
def ensure_number(num)
|
|
189
194
|
return num if valid_number?(num)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
raise DataFormatError, msg
|
|
195
|
+
raise DataFormatError,
|
|
196
|
+
"number must be unsigned 32-bit integer: #{num}"
|
|
193
197
|
end
|
|
194
198
|
|
|
195
|
-
# Ensure argument is '
|
|
199
|
+
# Ensure argument is 'nz-number' or raise DataFormatError
|
|
196
200
|
def ensure_nz_number(num)
|
|
197
201
|
return num if valid_nz_number?(num)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
raise DataFormatError, msg
|
|
202
|
+
raise DataFormatError,
|
|
203
|
+
"nz-number must be non-zero unsigned 32-bit integer: #{num}"
|
|
201
204
|
end
|
|
202
205
|
|
|
203
|
-
# Ensure argument is '
|
|
206
|
+
# Ensure argument is 'mod-sequence-value' or raise DataFormatError
|
|
204
207
|
def ensure_mod_sequence_value(num)
|
|
205
208
|
return num if valid_mod_sequence_value?(num)
|
|
209
|
+
raise DataFormatError,
|
|
210
|
+
"mod-sequence-value must be non-zero unsigned 64-bit integer: #{num}"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Ensure argument is 'mod-sequence-valzer' or raise DataFormatError
|
|
214
|
+
def ensure_mod_sequence_valzer(num)
|
|
215
|
+
return num if valid_mod_sequence_valzer?(num)
|
|
216
|
+
raise DataFormatError,
|
|
217
|
+
"mod-sequence-valzer must be unsigned 64-bit integer: #{num}"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Like #ensure_number, but usable with numeric String input.
|
|
221
|
+
def coerce_number(num)
|
|
222
|
+
case num
|
|
223
|
+
when Integer then ensure_number num
|
|
224
|
+
when NUMBER_RE then ensure_number Integer num
|
|
225
|
+
else
|
|
226
|
+
raise DataFormatError, "%p is not a valid number" % [num]
|
|
227
|
+
end
|
|
228
|
+
end
|
|
206
229
|
|
|
207
|
-
|
|
208
|
-
|
|
230
|
+
# Like #ensure_nz_number, but usable with numeric String input.
|
|
231
|
+
def coerce_nz_number(num)
|
|
232
|
+
case num
|
|
233
|
+
when Integer then ensure_nz_number num
|
|
234
|
+
when NUMBER_RE then ensure_nz_number Integer num
|
|
235
|
+
else
|
|
236
|
+
raise DataFormatError, "%p is not a valid nz-number" % [num]
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Like #ensure_mod_sequence_value, but usable with numeric String input.
|
|
241
|
+
def coerce_mod_sequence_value(num)
|
|
242
|
+
case num
|
|
243
|
+
when Integer then ensure_mod_sequence_value num
|
|
244
|
+
when NUMBER_RE then ensure_mod_sequence_value Integer num
|
|
245
|
+
else
|
|
246
|
+
raise DataFormatError, "%p is not a valid mod-sequence-value" % [num]
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Like #ensure_mod_sequence_valzer, but usable with numeric String input.
|
|
251
|
+
def coerce_mod_sequence_valzer(num)
|
|
252
|
+
case num
|
|
253
|
+
when Integer then ensure_mod_sequence_valzer num
|
|
254
|
+
when NUMBER_RE then ensure_mod_sequence_valzer Integer num
|
|
255
|
+
else
|
|
256
|
+
raise DataFormatError, "%p is not a valid mod-sequence-valzer" % [num]
|
|
257
|
+
end
|
|
209
258
|
end
|
|
210
259
|
|
|
211
260
|
end
|
|
@@ -25,6 +25,12 @@ module Net
|
|
|
25
25
|
# Some search extensions may result in the server sending ESearchResult
|
|
26
26
|
# responses after the initiating command has completed. Use
|
|
27
27
|
# IMAP#add_response_handler to handle these responses.
|
|
28
|
+
#
|
|
29
|
+
# ==== Compatibility with SearchResult
|
|
30
|
+
#
|
|
31
|
+
# Note that both SearchResult and ESearchResult implement +each+, +to_a+,
|
|
32
|
+
# and +to_sequence_set+. These methods can be used regardless of whether
|
|
33
|
+
# the server returns +SEARCH+ or +ESEARCH+ data (or no data).
|
|
28
34
|
class ESearchResult < Data.define(:tag, :uid, :data)
|
|
29
35
|
def initialize(tag: nil, uid: nil, data: nil)
|
|
30
36
|
tag => String | nil; tag = -tag if tag
|
|
@@ -6,7 +6,6 @@ module Net
|
|
|
6
6
|
autoload :FetchData, "#{__dir__}/fetch_data"
|
|
7
7
|
autoload :UIDFetchData, "#{__dir__}/fetch_data"
|
|
8
8
|
autoload :SearchResult, "#{__dir__}/search_result"
|
|
9
|
-
autoload :UIDPlusData, "#{__dir__}/uidplus_data"
|
|
10
9
|
autoload :AppendUIDData, "#{__dir__}/uidplus_data"
|
|
11
10
|
autoload :CopyUIDData, "#{__dir__}/uidplus_data"
|
|
12
11
|
autoload :VanishedData, "#{__dir__}/vanished_data"
|
|
@@ -260,8 +259,8 @@ module Net
|
|
|
260
259
|
#
|
|
261
260
|
# === +UIDPLUS+ extension
|
|
262
261
|
# See {[RFC4315 §3]}[https://www.rfc-editor.org/rfc/rfc4315#section-3].
|
|
263
|
-
# * +APPENDUID+, #data is
|
|
264
|
-
# * +COPYUID+, #data is
|
|
262
|
+
# * +APPENDUID+, #data is AppendUIDData. See IMAP#append.
|
|
263
|
+
# * +COPYUID+, #data is CopyUIDData. See IMAP#copy.
|
|
265
264
|
# * +UIDNOTSTICKY+, #data is +nil+. See IMAP#select.
|
|
266
265
|
#
|
|
267
266
|
# === +SEARCHRES+ extension
|
|
@@ -307,14 +306,6 @@ module Net
|
|
|
307
306
|
# because the server doesn't allow deletion of mailboxes with children.
|
|
308
307
|
# #data is +nil+.
|
|
309
308
|
#
|
|
310
|
-
# === <tt>QUOTA=RES-*</tt> response codes
|
|
311
|
-
# See {[RFC9208]}[https://www.rfc-editor.org/rfc/rfc9208.html#section-4.3].
|
|
312
|
-
# * +OVERQUOTA+ (also in RFC5530[https://www.rfc-editor.org/rfc/rfc5530]),
|
|
313
|
-
# with a tagged +NO+ response to an +APPEND+/+COPY+/+MOVE+ command when
|
|
314
|
-
# the command would put the target mailbox over any quota, and with an
|
|
315
|
-
# untagged +NO+ when a mailbox exceeds a soft quota (which may be caused
|
|
316
|
-
# be external events). #data is +nil+.
|
|
317
|
-
#
|
|
318
309
|
# === +CONDSTORE+ extension
|
|
319
310
|
# See {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
|
|
320
311
|
# * +NOMODSEQ+, when selecting a mailbox that does not support
|
|
@@ -392,23 +383,14 @@ module Net
|
|
|
392
383
|
# and MailboxQuota objects.
|
|
393
384
|
#
|
|
394
385
|
# == Required capability
|
|
395
|
-
#
|
|
396
386
|
# Requires +QUOTA+ [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]]
|
|
397
|
-
#
|
|
398
|
-
# [RFC9208[https://www.rfc-editor.org/rfc/rfc9208]] capability.
|
|
387
|
+
# capability.
|
|
399
388
|
class MailboxQuota < Struct.new(:mailbox, :usage, :quota)
|
|
400
389
|
##
|
|
401
390
|
# method: mailbox
|
|
402
391
|
# :call-seq: mailbox -> string
|
|
403
392
|
#
|
|
404
|
-
# The
|
|
405
|
-
#
|
|
406
|
-
# NOTE: this was mistakenly named "mailbox". But the quota root's name may
|
|
407
|
-
# differ from the mailbox. A single quota root may cover multiple
|
|
408
|
-
# mailboxes, and a single mailbox may be governed by multiple quota roots.
|
|
409
|
-
|
|
410
|
-
# The quota root with the associated quota.
|
|
411
|
-
alias quota_root mailbox
|
|
393
|
+
# The mailbox with the associated quota.
|
|
412
394
|
|
|
413
395
|
##
|
|
414
396
|
# method: usage
|
|
@@ -420,7 +402,7 @@ module Net
|
|
|
420
402
|
# method: quota
|
|
421
403
|
# :call-seq: quota -> Integer
|
|
422
404
|
#
|
|
423
|
-
#
|
|
405
|
+
# Quota limit imposed on the mailbox.
|
|
424
406
|
#
|
|
425
407
|
end
|
|
426
408
|
|
|
@@ -2017,24 +2017,19 @@ module Net
|
|
|
2017
2017
|
CopyUID(validity, src_uids, dst_uids)
|
|
2018
2018
|
end
|
|
2019
2019
|
|
|
2020
|
-
def AppendUID(...) DeprecatedUIDPlus(...) || AppendUIDData.new(...) end
|
|
2021
|
-
def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end
|
|
2022
|
-
|
|
2023
2020
|
# TODO: remove this code in the v0.6.0 release
|
|
2024
2021
|
def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids)
|
|
2025
2022
|
return unless config.parser_use_deprecated_uidplus_data
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
dst_uids = dst_uids.each_ordered_number.to_a
|
|
2032
|
-
UIDPlusData.new(validity, src_uids, dst_uids)
|
|
2033
|
-
elsif config.parser_use_deprecated_uidplus_data != :up_to_max_size
|
|
2034
|
-
parse_error("uid-set is too large: %d > %d", count, max)
|
|
2035
|
-
end
|
|
2023
|
+
warn("#{Config}#parser_use_deprecated_uidplus_data is ignored " \
|
|
2024
|
+
"since v0.6.0. Disable this warning by setting " \
|
|
2025
|
+
"config.parser_use_deprecated_uidplus_data = false.",
|
|
2026
|
+
category: :deprecated, uplevel: 9)
|
|
2027
|
+
nil
|
|
2036
2028
|
end
|
|
2037
2029
|
|
|
2030
|
+
def AppendUID(...) DeprecatedUIDPlus(...) || AppendUIDData.new(...) end
|
|
2031
|
+
def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end
|
|
2032
|
+
|
|
2038
2033
|
ADDRESS_REGEXP = /\G
|
|
2039
2034
|
\( (?: NIL | #{Patterns::QUOTED_rev2} ) # 1: NAME
|
|
2040
2035
|
\s (?: NIL | #{Patterns::QUOTED_rev2} ) # 2: ROUTE
|
|
@@ -8,7 +8,6 @@ module Net
|
|
|
8
8
|
|
|
9
9
|
def initialize(client, sock)
|
|
10
10
|
@client, @sock = client, sock
|
|
11
|
-
@buff = @literal_size = nil
|
|
12
11
|
end
|
|
13
12
|
|
|
14
13
|
def read_response_buffer
|
|
@@ -16,13 +15,13 @@ module Net
|
|
|
16
15
|
catch :eof do
|
|
17
16
|
while true
|
|
18
17
|
read_line
|
|
19
|
-
break unless literal_size
|
|
18
|
+
break unless (@literal_size = get_literal_size)
|
|
20
19
|
read_literal
|
|
21
20
|
end
|
|
22
21
|
end
|
|
23
22
|
buff
|
|
24
23
|
ensure
|
|
25
|
-
@buff =
|
|
24
|
+
@buff = nil
|
|
26
25
|
end
|
|
27
26
|
|
|
28
27
|
private
|
|
@@ -31,18 +30,13 @@ module Net
|
|
|
31
30
|
|
|
32
31
|
def bytes_read = buff.bytesize
|
|
33
32
|
def empty? = buff.empty?
|
|
34
|
-
def done? = line_done? && !
|
|
33
|
+
def done? = line_done? && !get_literal_size
|
|
35
34
|
def line_done? = buff.end_with?(CRLF)
|
|
36
|
-
|
|
37
|
-
def get_literal_size(buff)
|
|
38
|
-
buff.end_with?("}\r\n") && buff.rindex(/\{(\d+)\}\r\n\z/n) && $1.to_i
|
|
39
|
-
end
|
|
35
|
+
def get_literal_size = /\{(\d+)\}\r\n\z/n =~ buff && $1.to_i
|
|
40
36
|
|
|
41
37
|
def read_line
|
|
42
|
-
|
|
43
|
-
buff << line
|
|
38
|
+
buff << (@sock.gets(CRLF, read_limit) or throw :eof)
|
|
44
39
|
max_response_remaining! unless line_done?
|
|
45
|
-
@literal_size = get_literal_size(line)
|
|
46
40
|
end
|
|
47
41
|
|
|
48
42
|
def read_literal
|
|
@@ -75,19 +75,13 @@ module Net
|
|
|
75
75
|
# * #password ― Password or passphrase associated with this #username.
|
|
76
76
|
# * _optional_ #authzid ― Alternate identity to act as or on behalf of.
|
|
77
77
|
# * _optional_ #min_iterations - Overrides the default value (4096).
|
|
78
|
-
# * _optional_ #max_iterations - Overrides the default value (2³¹ - 1).
|
|
79
78
|
#
|
|
80
79
|
# Any other keyword parameters are quietly ignored.
|
|
81
|
-
#
|
|
82
|
-
# *NOTE:* <em>It is the user's responsibility</em> to enforce minimum
|
|
83
|
-
# and maximum iteration counts that are appropriate for their security
|
|
84
|
-
# context.
|
|
85
80
|
def initialize(username_arg = nil, password_arg = nil,
|
|
86
81
|
authcid: nil, username: nil,
|
|
87
82
|
authzid: nil,
|
|
88
83
|
password: nil, secret: nil,
|
|
89
84
|
min_iterations: 4096, # see both RFC5802 and RFC7677
|
|
90
|
-
max_iterations: 2**31 - 1, # max int32
|
|
91
85
|
cnonce: nil, # must only be set in tests
|
|
92
86
|
**options)
|
|
93
87
|
@username = username || username_arg || authcid or
|
|
@@ -100,22 +94,7 @@ module Net
|
|
|
100
94
|
@min_iterations.positive? or
|
|
101
95
|
raise ArgumentError, "min_iterations must be positive"
|
|
102
96
|
|
|
103
|
-
@max_iterations = Integer max_iterations.to_int
|
|
104
|
-
@min_iterations <= @max_iterations or
|
|
105
|
-
raise ArgumentError, "max_iterations must be more than min_iterations"
|
|
106
|
-
|
|
107
97
|
@cnonce = cnonce || SecureRandom.base64(32)
|
|
108
|
-
|
|
109
|
-
# These attrs are set from the server challenges
|
|
110
|
-
@server_first_message = @snonce = @salt = @iterations = nil
|
|
111
|
-
@server_error = nil
|
|
112
|
-
|
|
113
|
-
# Memoized after @salt and @iterations have been sent.
|
|
114
|
-
@salted_password = @client_key = @server_key = nil
|
|
115
|
-
|
|
116
|
-
# These values are created and cached in response to server challenges
|
|
117
|
-
@client_first_message_bare = nil
|
|
118
|
-
@client_final_message_without_proof = nil
|
|
119
98
|
end
|
|
120
99
|
|
|
121
100
|
# Authentication identity: the identity that matches the #password.
|
|
@@ -148,43 +127,8 @@ module Net
|
|
|
148
127
|
|
|
149
128
|
# The minimal allowed iteration count. Lower #iterations will raise an
|
|
150
129
|
# Error.
|
|
151
|
-
#
|
|
152
|
-
# *WARNING:* The default value (4096) is set to match guidance from
|
|
153
|
-
# both {RFC5802}[https://www.rfc-editor.org/rfc/rfc5802#page-12]
|
|
154
|
-
# and RFC7677[https://www.rfc-editor.org/rfc/rfc7677#section-4], but
|
|
155
|
-
# {modern recommendations}[https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2]
|
|
156
|
-
# are significantly higher.
|
|
157
|
-
#
|
|
158
|
-
# It is ultimately the server's responsibility to securely store
|
|
159
|
-
# password hashes. While this parameter can alert the user to
|
|
160
|
-
# insecure password storage and prevent insecure authentication
|
|
161
|
-
# exchange, updating the iteration count generally requires resetting
|
|
162
|
-
# the password on the server.
|
|
163
130
|
attr_reader :min_iterations
|
|
164
131
|
|
|
165
|
-
# The maximal allowed iteration count. Higher #iterations will raise an
|
|
166
|
-
# Error.
|
|
167
|
-
#
|
|
168
|
-
# As noted in {RFC5802}[https://www.rfc-editor.org/rfc/rfc5802#section-9]
|
|
169
|
-
# >>>
|
|
170
|
-
# A hostile server can perform a computational denial-of-service
|
|
171
|
-
# attack on clients by sending a big iteration count value.
|
|
172
|
-
#
|
|
173
|
-
# *WARNING:* The default value is <tt>2³¹ - 1</tt>, the maximum signed
|
|
174
|
-
# 32-bit integer. This is large enough for the computation to take
|
|
175
|
-
# several minutes, and insufficient protection against hostile servers.
|
|
176
|
-
#
|
|
177
|
-
# Note that <tt>OpenSSL::KDF.pbkdf2_hmac</tt> is implemented by a
|
|
178
|
-
# blocking C function, and cannot be interrupted by +Timeout+ or
|
|
179
|
-
# <tt>Thread.raise</tt>. And it keeps the Global VM lock, as of v4.0 of
|
|
180
|
-
# the +openssl+ gem, so other ruby threads will not be able to run.
|
|
181
|
-
#
|
|
182
|
-
# <em>To prevent a denial of service attack,</em> this must be set to a
|
|
183
|
-
# safe value, depending on hardware and version of OpenSSL. <em>It is
|
|
184
|
-
# the user's responsibility</em> to enforce minimum and maximum
|
|
185
|
-
# iteration counts that are appropriate for their security context.
|
|
186
|
-
attr_reader :max_iterations
|
|
187
|
-
|
|
188
132
|
# The client nonce, generated by SecureRandom
|
|
189
133
|
attr_reader :cnonce
|
|
190
134
|
|
|
@@ -203,15 +147,6 @@ module Net
|
|
|
203
147
|
# Net::IMAP::NoResponseError.
|
|
204
148
|
attr_reader :server_error
|
|
205
149
|
|
|
206
|
-
# Memoized ScramAlgorithm#salted_password (needs #salt and #iterations)
|
|
207
|
-
def salted_password; @salted_password ||= compute_salted { super } end
|
|
208
|
-
|
|
209
|
-
# Memoized ScramAlgorithm#client_key (needs #salt and #iterations)
|
|
210
|
-
def client_key; @client_key ||= compute_salted { super } end
|
|
211
|
-
|
|
212
|
-
# Memoized ScramAlgorithm#server_key (needs #salt and #iterations)
|
|
213
|
-
def server_key; @server_key ||= compute_salted { super } end
|
|
214
|
-
|
|
215
150
|
# Returns a new OpenSSL::Digest object, set to the appropriate hash
|
|
216
151
|
# function for the chosen mechanism.
|
|
217
152
|
#
|
|
@@ -251,13 +186,6 @@ module Net
|
|
|
251
186
|
|
|
252
187
|
private
|
|
253
188
|
|
|
254
|
-
# Checks for +salt+ and +iterations+ before yielding
|
|
255
|
-
def compute_salted
|
|
256
|
-
salt in String or raise Error, "unknown salt"
|
|
257
|
-
iterations in Integer or raise Error, "unknown iterations"
|
|
258
|
-
yield
|
|
259
|
-
end
|
|
260
|
-
|
|
261
189
|
# Need to store this for auth_message
|
|
262
190
|
attr_reader :server_first_message
|
|
263
191
|
|
|
@@ -274,8 +202,6 @@ module Net
|
|
|
274
202
|
raise Error, "server did not send iteration count"
|
|
275
203
|
min_iterations <= iterations or
|
|
276
204
|
raise Error, "too few iterations: %d" % [iterations]
|
|
277
|
-
max_iterations.nil? || iterations <= max_iterations or
|
|
278
|
-
raise Error, "too many iterations: %d" % [iterations]
|
|
279
205
|
mext = sparams["m"] and
|
|
280
206
|
raise Error, "mandatory extension: %p" % [mext]
|
|
281
207
|
snonce.start_with? cnonce or
|
|
@@ -7,6 +7,12 @@ module Net
|
|
|
7
7
|
# identifiers returned by Net::IMAP#uid_search.
|
|
8
8
|
#
|
|
9
9
|
# For backward compatibility, SearchResult inherits from Array.
|
|
10
|
+
#
|
|
11
|
+
# ==== Compatibility with ESearchResult
|
|
12
|
+
#
|
|
13
|
+
# Note that both SearchResult and ESearchResult implement +each+, +to_a+,
|
|
14
|
+
# and +to_sequence_set+. These methods can be used regardless of whether
|
|
15
|
+
# the server returns +SEARCH+ or +ESEARCH+ data (or no data).
|
|
10
16
|
class SearchResult < Array
|
|
11
17
|
|
|
12
18
|
# Returns a SearchResult populated with the given +seq_nums+.
|