net-imap 0.4.12 → 0.5.5
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/README.md +10 -4
- data/docs/styles.css +75 -14
- data/lib/net/imap/authenticators.rb +2 -2
- data/lib/net/imap/command_data.rb +61 -48
- 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 +402 -0
- data/lib/net/imap/data_encoding.rb +3 -3
- data/lib/net/imap/data_lite.rb +226 -0
- data/lib/net/imap/deprecated_client_options.rb +8 -5
- data/lib/net/imap/errors.rb +6 -0
- data/lib/net/imap/esearch_result.rb +180 -0
- data/lib/net/imap/fetch_data.rb +126 -47
- data/lib/net/imap/response_data.rb +126 -193
- data/lib/net/imap/response_parser/parser_utils.rb +11 -6
- data/lib/net/imap/response_parser.rb +159 -21
- data/lib/net/imap/sasl/anonymous_authenticator.rb +3 -3
- 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 +4 -4
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +218 -56
- data/lib/net/imap/sasl/external_authenticator.rb +2 -2
- data/lib/net/imap/sasl/gs2_header.rb +7 -7
- data/lib/net/imap/sasl/login_authenticator.rb +4 -3
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +6 -6
- data/lib/net/imap/sasl/plain_authenticator.rb +7 -7
- data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
- data/lib/net/imap/sasl/scram_authenticator.rb +8 -8
- data/lib/net/imap/sasl.rb +7 -4
- data/lib/net/imap/sasl_adapter.rb +0 -1
- data/lib/net/imap/search_result.rb +2 -2
- data/lib/net/imap/sequence_set.rb +28 -24
- data/lib/net/imap/stringprep/nameprep.rb +1 -1
- data/lib/net/imap/stringprep/trace.rb +4 -4
- data/lib/net/imap/vanished_data.rb +56 -0
- data/lib/net/imap.rb +1001 -319
- data/net-imap.gemspec +3 -3
- data/rakelib/rfcs.rake +2 -0
- 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
@@ -100,10 +100,10 @@ module Net
|
|
100
100
|
# data.to_s("SORT") # => "* SORT 2 8 32 128 256 512"
|
101
101
|
# data.to_s(nil) # => "2 8 32 128 256 512"
|
102
102
|
#
|
103
|
-
# data = Net::IMAP::SearchResult[1, 3, 16, 1024, modseq: 2048]
|
103
|
+
# data = Net::IMAP::SearchResult[1, 3, 16, 1024, modseq: 2048]
|
104
104
|
# data.to_s # => "* SEARCH 1 3 16 1024 (MODSEQ 2048)"
|
105
105
|
# data.to_s("SORT") # => "* SORT 1 3 16 1024 (MODSEQ 2048)"
|
106
|
-
# data.to_s
|
106
|
+
# data.to_s(nil) # => "1 3 16 1024 (MODSEQ 2048)"
|
107
107
|
#
|
108
108
|
def to_s(type = "SEARCH")
|
109
109
|
str = +""
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "set" unless defined?(::Set)
|
4
|
+
|
3
5
|
module Net
|
4
6
|
class IMAP
|
5
7
|
|
@@ -14,13 +16,6 @@ module Net
|
|
14
16
|
# receive a SequenceSet as an argument, for example IMAP#search, IMAP#fetch,
|
15
17
|
# and IMAP#store.
|
16
18
|
#
|
17
|
-
# == EXPERIMENTAL API
|
18
|
-
#
|
19
|
-
# SequenceSet is currently experimental. Only two methods, ::[] and
|
20
|
-
# #valid_string, are considered stable. Although the API isn't expected to
|
21
|
-
# change much, any other methods may be removed or changed without
|
22
|
-
# deprecation.
|
23
|
-
#
|
24
19
|
# == Creating sequence sets
|
25
20
|
#
|
26
21
|
# SequenceSet.new with no arguments creates an empty sequence set. Note
|
@@ -37,7 +32,8 @@ module Net
|
|
37
32
|
#
|
38
33
|
# SequenceSet.new may receive a single optional argument: a non-zero 32 bit
|
39
34
|
# unsigned integer, a range, a <tt>sequence-set</tt> formatted string,
|
40
|
-
# another sequence set,
|
35
|
+
# another sequence set, a Set (containing only numbers or <tt>*</tt>), or an
|
36
|
+
# Array containing any of these (array inputs may be nested).
|
41
37
|
#
|
42
38
|
# set = Net::IMAP::SequenceSet.new(1)
|
43
39
|
# set.valid_string #=> "1"
|
@@ -286,11 +282,7 @@ module Net
|
|
286
282
|
|
287
283
|
# valid inputs for "*"
|
288
284
|
STARS = [:*, ?*, -1].freeze
|
289
|
-
private_constant :
|
290
|
-
|
291
|
-
COERCIBLE = ->{ _1.respond_to? :to_sequence_set }
|
292
|
-
ENUMABLE = ->{ _1.respond_to?(:each) && _1.respond_to?(:empty?) }
|
293
|
-
private_constant :COERCIBLE, :ENUMABLE
|
285
|
+
private_constant :STARS
|
294
286
|
|
295
287
|
class << self
|
296
288
|
|
@@ -304,7 +296,7 @@ module Net
|
|
304
296
|
# Use ::new to create a mutable or empty SequenceSet.
|
305
297
|
def [](first, *rest)
|
306
298
|
if rest.empty?
|
307
|
-
if first.is_a?(SequenceSet) &&
|
299
|
+
if first.is_a?(SequenceSet) && first.frozen? && first.valid?
|
308
300
|
first
|
309
301
|
else
|
310
302
|
new(first).validate.freeze
|
@@ -325,7 +317,7 @@ module Net
|
|
325
317
|
# raised.
|
326
318
|
def try_convert(obj)
|
327
319
|
return obj if obj.is_a?(SequenceSet)
|
328
|
-
return nil unless respond_to?(:to_sequence_set)
|
320
|
+
return nil unless obj.respond_to?(:to_sequence_set)
|
329
321
|
obj = obj.to_sequence_set
|
330
322
|
return obj if obj.is_a?(SequenceSet)
|
331
323
|
raise DataFormatError, "invalid object returned from to_sequence_set"
|
@@ -389,6 +381,10 @@ module Net
|
|
389
381
|
# Related: #valid_string, #normalized_string, #to_s
|
390
382
|
def string; @string ||= normalized_string if valid? end
|
391
383
|
|
384
|
+
# Returns an array with #normalized_string when valid and an empty array
|
385
|
+
# otherwise.
|
386
|
+
def deconstruct; valid? ? [normalized_string] : [] end
|
387
|
+
|
392
388
|
# Assigns a new string to #string and resets #elements to match. It
|
393
389
|
# cannot be set to an empty string—assign +nil+ or use #clear instead.
|
394
390
|
# The string is validated but not normalized.
|
@@ -682,6 +678,7 @@ module Net
|
|
682
678
|
# Unlike #add, #merge, or #union, the new value is appended to #string.
|
683
679
|
# This may result in a #string which has duplicates or is out-of-order.
|
684
680
|
def append(object)
|
681
|
+
modifying!
|
685
682
|
tuple = input_to_tuple object
|
686
683
|
entry = tuple_to_str tuple
|
687
684
|
tuple_add tuple
|
@@ -1271,7 +1268,8 @@ module Net
|
|
1271
1268
|
when *STARS, Integer, Range then [input_to_tuple(obj)]
|
1272
1269
|
when String then str_to_tuples obj
|
1273
1270
|
when SequenceSet then obj.tuples
|
1274
|
-
when
|
1271
|
+
when Set then obj.map { [to_tuple_int(_1)] * 2 }
|
1272
|
+
when Array then obj.flat_map { input_to_tuples _1 }
|
1275
1273
|
when nil then []
|
1276
1274
|
else
|
1277
1275
|
raise DataFormatError,
|
@@ -1284,8 +1282,7 @@ module Net
|
|
1284
1282
|
# String, Set, Array, or... any type of object.
|
1285
1283
|
def input_try_convert(input)
|
1286
1284
|
SequenceSet.try_convert(input) ||
|
1287
|
-
|
1288
|
-
input.respond_to?(:to_int) && Integer(input.to_int) ||
|
1285
|
+
Integer.try_convert(input) ||
|
1289
1286
|
String.try_convert(input) ||
|
1290
1287
|
input
|
1291
1288
|
end
|
@@ -1317,6 +1314,12 @@ module Net
|
|
1317
1314
|
range.include?(min) || range.include?(max) || (min..max).cover?(range)
|
1318
1315
|
end
|
1319
1316
|
|
1317
|
+
def modifying!
|
1318
|
+
if frozen?
|
1319
|
+
raise FrozenError, "can't modify frozen #{self.class}: %p" % [self]
|
1320
|
+
end
|
1321
|
+
end
|
1322
|
+
|
1320
1323
|
def tuples_add(tuples) tuples.each do tuple_add _1 end; self end
|
1321
1324
|
def tuples_subtract(tuples) tuples.each do tuple_subtract _1 end; self end
|
1322
1325
|
|
@@ -1331,6 +1334,7 @@ module Net
|
|
1331
1334
|
# ---------??===lower==|--|==|----|===upper===|-- join until upper
|
1332
1335
|
# ---------??===lower==|--|==|--|=====upper===|-- join to upper
|
1333
1336
|
def tuple_add(tuple)
|
1337
|
+
modifying!
|
1334
1338
|
min, max = tuple
|
1335
1339
|
lower, lower_idx = tuple_gte_with_index(min - 1)
|
1336
1340
|
if lower.nil? then tuples << tuple
|
@@ -1367,6 +1371,7 @@ module Net
|
|
1367
1371
|
# -------??=====lower====|--|====|---|====upper====|-- 7. delete until
|
1368
1372
|
# -------??=====lower====|--|====|--|=====upper====|-- 8. delete and trim
|
1369
1373
|
def tuple_subtract(tuple)
|
1374
|
+
modifying!
|
1370
1375
|
min, max = tuple
|
1371
1376
|
lower, idx = tuple_gte_with_index(min)
|
1372
1377
|
if lower.nil? then nil # case 1.
|
@@ -1407,12 +1412,11 @@ module Net
|
|
1407
1412
|
end
|
1408
1413
|
|
1409
1414
|
def nz_number(num)
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
num
|
1415
|
+
String === num && !/\A[1-9]\d*\z/.match?(num) and
|
1416
|
+
raise DataFormatError, "%p is not a valid nz-number" % [num]
|
1417
|
+
NumValidator.ensure_nz_number Integer num
|
1418
|
+
rescue TypeError # To catch errors from Integer()
|
1419
|
+
raise DataFormatError, $!.message
|
1416
1420
|
end
|
1417
1421
|
|
1418
1422
|
# intentionally defined after the class implementation
|
@@ -4,7 +4,7 @@ module Net
|
|
4
4
|
class IMAP
|
5
5
|
module StringPrep
|
6
6
|
|
7
|
-
# Defined in RFC3491[https://
|
7
|
+
# Defined in RFC3491[https://www.rfc-editor.org/rfc/rfc3491], the +nameprep+
|
8
8
|
# profile of "Stringprep" is:
|
9
9
|
# >>>
|
10
10
|
# used by the IDNA protocol for preparing domain names; it is not
|
@@ -4,11 +4,11 @@ module Net
|
|
4
4
|
class IMAP
|
5
5
|
module StringPrep
|
6
6
|
|
7
|
-
# Defined in RFC-4505[https://
|
7
|
+
# Defined in RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3, The +trace+
|
8
8
|
# profile of \StringPrep is used by the +ANONYMOUS+ \SASL mechanism.
|
9
9
|
module Trace
|
10
10
|
|
11
|
-
# Defined in RFC-4505[https://
|
11
|
+
# Defined in RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3.
|
12
12
|
STRINGPREP_PROFILE = "trace"
|
13
13
|
|
14
14
|
# >>>
|
@@ -23,7 +23,7 @@ module Net
|
|
23
23
|
# No Unicode normalization is required by this profile.
|
24
24
|
NORMALIZATION = nil
|
25
25
|
|
26
|
-
# From RFC-4505[https://
|
26
|
+
# From RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3, The "trace"
|
27
27
|
# Profile of "Stringprep":
|
28
28
|
# >>>
|
29
29
|
# Characters from the following tables of [StringPrep] are prohibited:
|
@@ -47,7 +47,7 @@ module Net
|
|
47
47
|
|
48
48
|
module_function
|
49
49
|
|
50
|
-
# From RFC-4505[https://
|
50
|
+
# From RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3, The "trace"
|
51
51
|
# Profile of "Stringprep":
|
52
52
|
# >>>
|
53
53
|
# The character repertoire of this profile is Unicode 3.2 [Unicode].
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Net
|
4
|
+
class IMAP < Protocol
|
5
|
+
|
6
|
+
# Net::IMAP::VanishedData represents the contents of a +VANISHED+ response,
|
7
|
+
# which is described by the
|
8
|
+
# {QRESYNC}[https://www.rfc-editor.org/rfc/rfc7162.html] extension.
|
9
|
+
# [{RFC7162 §3.2.10}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.2.10]].
|
10
|
+
#
|
11
|
+
# +VANISHED+ responses replace +EXPUNGE+ responses when either the
|
12
|
+
# {QRESYNC}[https://www.rfc-editor.org/rfc/rfc7162.html] or the
|
13
|
+
# {UIDONLY}[https://www.rfc-editor.org/rfc/rfc9586.html] extension has been
|
14
|
+
# enabled.
|
15
|
+
class VanishedData < Data.define(:uids, :earlier)
|
16
|
+
|
17
|
+
# Returns a new VanishedData object.
|
18
|
+
#
|
19
|
+
# * +uids+ will be converted by SequenceSet.[].
|
20
|
+
# * +earlier+ will be converted to +true+ or +false+
|
21
|
+
def initialize(uids:, earlier:)
|
22
|
+
uids = SequenceSet[uids]
|
23
|
+
earlier = !!earlier
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# :attr_reader: uids
|
29
|
+
#
|
30
|
+
# SequenceSet of UIDs that have been permanently removed from the mailbox.
|
31
|
+
|
32
|
+
##
|
33
|
+
# :attr_reader: earlier
|
34
|
+
#
|
35
|
+
# +true+ when the response was caused by Net::IMAP#uid_fetch with
|
36
|
+
# <tt>vanished: true</tt> or Net::IMAP#select/Net::IMAP#examine with
|
37
|
+
# <tt>qresync: true</tt>.
|
38
|
+
#
|
39
|
+
# +false+ when the response is used to announce message removals within an
|
40
|
+
# already selected mailbox.
|
41
|
+
|
42
|
+
# rdoc doesn't handle attr aliases nicely. :(
|
43
|
+
alias earlier? earlier # :nodoc:
|
44
|
+
##
|
45
|
+
# :attr_reader: earlier?
|
46
|
+
#
|
47
|
+
# Alias for #earlier.
|
48
|
+
|
49
|
+
# Returns an Array of all of the UIDs in #uids.
|
50
|
+
#
|
51
|
+
# See SequenceSet#numbers.
|
52
|
+
def to_a; uids.numbers end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|