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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 561e6151a9540c8eaa6c12fd16d625061843a053fb0b0c8a2f215eb1a518ef70
|
|
4
|
+
data.tar.gz: 5be61c15097d2e0007822fc6c4825f59795d6078d6cf9b5cbe6ed4dd2bd1d22e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f84a8adf89f177e953fe57e390b027232bc4c7325ecb0049221a88db87fccc76a09281aea87c4f48de05bc547db1248b628b9c271134a466aedba953305001cc
|
|
7
|
+
data.tar.gz: 0b82898fb8581bab9a30c5b3edb96c89d81c4bddf197ade29a25ef166db827983a6c2c25d1eda9989a9f985cfcbec52f4bf484dbc1b57cfde32f432dcd0dfbc3
|
data/Gemfile
CHANGED
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
require "date"
|
|
4
4
|
|
|
5
5
|
require_relative "errors"
|
|
6
|
-
require_relative "data_lite"
|
|
7
|
-
|
|
8
|
-
# :enddoc:
|
|
9
6
|
|
|
10
7
|
module Net
|
|
11
8
|
class IMAP < Protocol
|
|
@@ -28,7 +25,6 @@ module Net
|
|
|
28
25
|
end
|
|
29
26
|
when Time, Date, DateTime
|
|
30
27
|
when Symbol
|
|
31
|
-
Flag.validate(data)
|
|
32
28
|
else
|
|
33
29
|
data.validate
|
|
34
30
|
end
|
|
@@ -49,7 +45,7 @@ module Net
|
|
|
49
45
|
when Date
|
|
50
46
|
send_date_data(data)
|
|
51
47
|
when Symbol
|
|
52
|
-
|
|
48
|
+
send_symbol_data(data)
|
|
53
49
|
else
|
|
54
50
|
data.send_data(self, tag)
|
|
55
51
|
end
|
|
@@ -81,23 +77,9 @@ module Net
|
|
|
81
77
|
put_string('"' + str.gsub(/["\\]/, "\\\\\\&") + '"')
|
|
82
78
|
end
|
|
83
79
|
|
|
84
|
-
def
|
|
85
|
-
|
|
86
|
-
# `non_sync` is an optional tri-state flag:
|
|
87
|
-
# * `true` -> Force non-synchronizing `LITERAL+`/`LITERAL-` behavior.
|
|
88
|
-
# TODO: raise or warn when capabilities don't allow non_sync.
|
|
89
|
-
# * `false` -> Force normal synchronizing literal behavior.
|
|
90
|
-
# * `nil` -> (default) Currently behaves like `false` (will be dynamic).
|
|
91
|
-
# TODO: Dynamic, based on capabilities and bytesize.
|
|
92
|
-
def send_literal(str, tag = nil, binary: false, non_sync: nil)
|
|
80
|
+
def send_literal(str, tag = nil)
|
|
93
81
|
synchronize do
|
|
94
|
-
|
|
95
|
-
plus = "+" if non_sync
|
|
96
|
-
put_string("#{prefix}{#{str.bytesize}#{plus}}\r\n")
|
|
97
|
-
if non_sync
|
|
98
|
-
put_string(str)
|
|
99
|
-
return
|
|
100
|
-
end
|
|
82
|
+
put_string("{" + str.bytesize.to_s + "}" + CRLF)
|
|
101
83
|
@continued_command_tag = tag
|
|
102
84
|
@continuation_request_exception = nil
|
|
103
85
|
begin
|
|
@@ -133,13 +115,11 @@ module Net
|
|
|
133
115
|
def send_date_data(date) put_string Net::IMAP.encode_date(date) end
|
|
134
116
|
def send_time_data(time) put_string Net::IMAP.encode_time(time) end
|
|
135
117
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
data.validate
|
|
140
|
-
data
|
|
141
|
-
end
|
|
118
|
+
def send_symbol_data(symbol)
|
|
119
|
+
put_string("\\" + symbol.to_s)
|
|
120
|
+
end
|
|
142
121
|
|
|
122
|
+
CommandData = Data.define(:data) do # :nodoc:
|
|
143
123
|
def send_data(imap, tag)
|
|
144
124
|
raise NoMethodError, "#{self.class} must implement #{__method__}"
|
|
145
125
|
end
|
|
@@ -148,109 +128,15 @@ module Net
|
|
|
148
128
|
end
|
|
149
129
|
end
|
|
150
130
|
|
|
151
|
-
# Represents IMAP +text+ data, which may contain any 7-bit ASCII character,
|
|
152
|
-
# except for +NULL+, +CR+, or +LF+. +text+ is extended to allow any
|
|
153
|
-
# multibyte +UTF-8+ character when either +UTF8=ACCEPT+ or +IMAP4rev2+ have
|
|
154
|
-
# been enabled, or when the server supports only +IMAP4rev2+ and not earlier
|
|
155
|
-
# IMAP revisions, or when the server advertises +UTF8=ONLY+.
|
|
156
|
-
#
|
|
157
|
-
# NOTE: The current implementation does not validate whether the connection
|
|
158
|
-
# currently supports UTF-8. Future versions may change.
|
|
159
|
-
#
|
|
160
|
-
# The string's bytes must be valid ASCII or valid UTF-8. The string's
|
|
161
|
-
# reported encoding is ignored, but the string is _not_ transcoded.
|
|
162
|
-
class RawText < CommandData # :nodoc:
|
|
163
|
-
def initialize(data:)
|
|
164
|
-
data = String(data.to_str)
|
|
165
|
-
data = if data.encoding in Encoding::ASCII | Encoding::UTF_8
|
|
166
|
-
-data
|
|
167
|
-
elsif data.ascii_only?
|
|
168
|
-
-(data.dup.force_encoding("ASCII"))
|
|
169
|
-
else
|
|
170
|
-
-(data.dup.force_encoding("UTF-8"))
|
|
171
|
-
end
|
|
172
|
-
super
|
|
173
|
-
validate
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def validate
|
|
177
|
-
if data.include?("\0")
|
|
178
|
-
raise DataFormatError, "NULL byte must be binary literal encoded"
|
|
179
|
-
elsif !data.valid_encoding?
|
|
180
|
-
raise DataFormatError, "invalid UTF-8 must be literal encoded"
|
|
181
|
-
elsif /[\r\n]/.match?(data)
|
|
182
|
-
raise DataFormatError, "CR and LF bytes must be literal encoded"
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
def ascii_only? = data.ascii_only?
|
|
187
|
-
|
|
188
|
-
def send_data(imap, tag) = imap.__send__(:put_string, data)
|
|
189
|
-
end
|
|
190
|
-
|
|
191
131
|
class RawData < CommandData # :nodoc:
|
|
192
|
-
def initialize(data:)
|
|
193
|
-
data = split_parts(data)
|
|
194
|
-
super
|
|
195
|
-
validate
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def send_data(imap, tag) = data.each do _1.send_data(imap, tag) end
|
|
199
|
-
|
|
200
|
-
def validate
|
|
201
|
-
return unless data.last in RawText(data: text)
|
|
202
|
-
if text.rindex(/~?\{[1-9]\d*\+?\}\z/n)
|
|
203
|
-
raise DataFormatError, "RawData cannot end with literal continuation"
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
private
|
|
208
|
-
|
|
209
|
-
def split_parts(data)
|
|
210
|
-
data = data.b # dups and ensures BINARY encoding
|
|
211
|
-
parts = []
|
|
212
|
-
while data.match(/(~)?\{(0|[1-9]\d*)(\+)?\}\r\n/n)
|
|
213
|
-
text, binary, bytesize, non_sync, data = $`, !!$1, $2, !!$3, $'
|
|
214
|
-
bytesize = Integer bytesize, 10
|
|
215
|
-
parts << RawText[text] unless text.empty?
|
|
216
|
-
parts << extract_literal(data, binary:, bytesize:, non_sync:)
|
|
217
|
-
data[0, bytesize] = ""
|
|
218
|
-
end
|
|
219
|
-
parts << RawText[data] unless data.empty?
|
|
220
|
-
parts
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def extract_literal(data, binary:, bytesize:, non_sync:)
|
|
224
|
-
if data.bytesize < bytesize
|
|
225
|
-
raise DataFormatError, "Too few bytes in string for literal, " \
|
|
226
|
-
"expected: %s, remaining: %s" % [bytesize, data.bytesize]
|
|
227
|
-
end
|
|
228
|
-
literal = data.byteslice(0, bytesize)
|
|
229
|
-
(binary ? Literal8 : Literal).new(data: literal, non_sync:)
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
class Atom < CommandData # :nodoc:
|
|
234
|
-
def initialize(**)
|
|
235
|
-
super
|
|
236
|
-
validate
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
def validate
|
|
240
|
-
data.to_s.ascii_only? \
|
|
241
|
-
or raise DataFormatError, "#{self.class} must be ASCII only"
|
|
242
|
-
data.match?(ResponseParser::Patterns::ATOM_SPECIALS) \
|
|
243
|
-
and raise DataFormatError, "#{self.class} must not contain atom-specials"
|
|
244
|
-
end
|
|
245
|
-
|
|
246
132
|
def send_data(imap, tag)
|
|
247
|
-
imap.__send__(:put_string, data
|
|
133
|
+
imap.__send__(:put_string, data)
|
|
248
134
|
end
|
|
249
135
|
end
|
|
250
136
|
|
|
251
|
-
class
|
|
137
|
+
class Atom < CommandData # :nodoc:
|
|
252
138
|
def send_data(imap, tag)
|
|
253
|
-
imap.__send__(:put_string,
|
|
139
|
+
imap.__send__(:put_string, data)
|
|
254
140
|
end
|
|
255
141
|
end
|
|
256
142
|
|
|
@@ -260,39 +146,9 @@ module Net
|
|
|
260
146
|
end
|
|
261
147
|
end
|
|
262
148
|
|
|
263
|
-
class Literal <
|
|
264
|
-
def self.validate(...)
|
|
265
|
-
data = new(...)
|
|
266
|
-
data.validate
|
|
267
|
-
data
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def initialize(data:, non_sync: nil)
|
|
271
|
-
data = -String(data.to_str).b or
|
|
272
|
-
raise DataFormatError, "#{self.class} expects string input"
|
|
273
|
-
super
|
|
274
|
-
validate
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
def bytesize; data.bytesize end
|
|
278
|
-
|
|
279
|
-
def validate
|
|
280
|
-
if data.include?("\0")
|
|
281
|
-
raise DataFormatError, "NULL byte not allowed in #{self.class}. " \
|
|
282
|
-
"Use #{Literal8} or a null-safe encoding."
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
def send_data(imap, tag)
|
|
287
|
-
imap.__send__(:send_literal, data, tag, non_sync:)
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
class Literal8 < Literal # :nodoc:
|
|
292
|
-
def validate; nil end # all bytes are okay
|
|
293
|
-
|
|
149
|
+
class Literal < CommandData # :nodoc:
|
|
294
150
|
def send_data(imap, tag)
|
|
295
|
-
imap.__send__(:
|
|
151
|
+
imap.__send__(:send_literal, data, tag)
|
|
296
152
|
end
|
|
297
153
|
end
|
|
298
154
|
|
|
@@ -328,73 +184,6 @@ module Net
|
|
|
328
184
|
end
|
|
329
185
|
end
|
|
330
186
|
|
|
331
|
-
# *DEPRECATED*. Replaced by SequenceSet.
|
|
332
|
-
class MessageSet < CommandData # :nodoc:
|
|
333
|
-
def send_data(imap, tag)
|
|
334
|
-
imap.__send__(:put_string, format_internal(data))
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
def validate
|
|
338
|
-
validate_internal(data)
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
private
|
|
342
|
-
|
|
343
|
-
def initialize(data:)
|
|
344
|
-
super
|
|
345
|
-
warn("DEPRECATED: #{MessageSet} should be replaced with #{SequenceSet}.",
|
|
346
|
-
uplevel: 1, category: :deprecated)
|
|
347
|
-
begin
|
|
348
|
-
# to ensure the input works with SequenceSet, too
|
|
349
|
-
SequenceSet.new(data)
|
|
350
|
-
rescue
|
|
351
|
-
warn "MessageSet input is incompatible with SequenceSet: [%s] %s" % [
|
|
352
|
-
$!.class, $!.message
|
|
353
|
-
]
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
def format_internal(data)
|
|
358
|
-
case data
|
|
359
|
-
when "*"
|
|
360
|
-
return data
|
|
361
|
-
when Integer
|
|
362
|
-
if data == -1
|
|
363
|
-
return "*"
|
|
364
|
-
else
|
|
365
|
-
return data.to_s
|
|
366
|
-
end
|
|
367
|
-
when Range
|
|
368
|
-
return format_internal(data.first) +
|
|
369
|
-
":" + format_internal(data.last)
|
|
370
|
-
when Array
|
|
371
|
-
return data.collect {|i| format_internal(i)}.join(",")
|
|
372
|
-
when ThreadMember
|
|
373
|
-
return data.seqno.to_s +
|
|
374
|
-
":" + data.children.collect {|i| format_internal(i).join(",")}
|
|
375
|
-
end
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
def validate_internal(data)
|
|
379
|
-
case data
|
|
380
|
-
when "*"
|
|
381
|
-
when Integer
|
|
382
|
-
NumValidator.ensure_nz_number(data)
|
|
383
|
-
when Range
|
|
384
|
-
when Array
|
|
385
|
-
data.each do |i|
|
|
386
|
-
validate_internal(i)
|
|
387
|
-
end
|
|
388
|
-
when ThreadMember
|
|
389
|
-
data.children.each do |i|
|
|
390
|
-
validate_internal(i)
|
|
391
|
-
end
|
|
392
|
-
else
|
|
393
|
-
raise DataFormatError, data.inspect
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
end
|
|
397
|
-
|
|
398
187
|
class ClientID < CommandData # :nodoc:
|
|
399
188
|
|
|
400
189
|
def send_data(imap, tag)
|
|
@@ -54,9 +54,22 @@ module Net
|
|
|
54
54
|
# Creates a new config, which inherits from +self+.
|
|
55
55
|
def new(**attrs) self.class.new(self, **attrs) end
|
|
56
56
|
|
|
57
|
+
# :call-seq:
|
|
58
|
+
# inherited?(attr) -> true or false
|
|
59
|
+
# inherited?(*attrs) -> true or false
|
|
60
|
+
# inherited? -> true or false
|
|
61
|
+
#
|
|
57
62
|
# Returns +true+ if +attr+ is inherited from #parent and not overridden
|
|
58
63
|
# by this config.
|
|
59
|
-
|
|
64
|
+
#
|
|
65
|
+
# When multiple +attrs+ are given, returns +true+ if *all* of them are
|
|
66
|
+
# inherited, or +false+ if any of them are overriden. When no +attrs+
|
|
67
|
+
# are given, returns +true+ if *all* attributes are inherited, or
|
|
68
|
+
# +false+ if any attribute is overriden.
|
|
69
|
+
def inherited?(*attrs)
|
|
70
|
+
attrs = data.members if attrs.empty?
|
|
71
|
+
attrs.all? { data[_1] == INHERITED }
|
|
72
|
+
end
|
|
60
73
|
|
|
61
74
|
# :call-seq:
|
|
62
75
|
# reset -> self
|
|
@@ -24,7 +24,7 @@ module Net
|
|
|
24
24
|
VERSIONS = ((0.0r..FUTURE_VERSION) % 0.1r).to_a.freeze
|
|
25
25
|
|
|
26
26
|
# See Config.version_defaults.
|
|
27
|
-
singleton_class.
|
|
27
|
+
singleton_class.attr_accessor :version_defaults
|
|
28
28
|
|
|
29
29
|
@version_defaults = Hash.new {|h, k|
|
|
30
30
|
# NOTE: String responds to both so the order is significant.
|
data/lib/net/imap/config.rb
CHANGED
|
@@ -234,13 +234,26 @@ module Net
|
|
|
234
234
|
# Do not use +SASL-IR+, even when it is supported by the server and the
|
|
235
235
|
# mechanism.
|
|
236
236
|
#
|
|
237
|
+
# [+:when_capabilities_cached+]
|
|
238
|
+
# Use +SASL-IR+ when Net::IMAP#capabilities_cached? is +true+ and it is
|
|
239
|
+
# supported by the server and the mechanism, but do not send a
|
|
240
|
+
# +CAPABILITY+ command to discover the server capabilities.
|
|
241
|
+
#
|
|
242
|
+
# <em>(+:when_capabilities_cached+ option was added by +v0.6.0+)</em>
|
|
243
|
+
#
|
|
237
244
|
# [+true+ <em>(default since +v0.4+)</em>]
|
|
238
245
|
# Use +SASL-IR+ when it is supported by the server and the mechanism.
|
|
239
|
-
attr_accessor :sasl_ir, type:
|
|
246
|
+
attr_accessor :sasl_ir, type: Enum[
|
|
247
|
+
false, :when_capabilities_cached, true
|
|
248
|
+
], defaults: {
|
|
240
249
|
0.0r => false,
|
|
241
250
|
0.4r => true,
|
|
242
251
|
}
|
|
243
252
|
|
|
253
|
+
# :stopdoc:
|
|
254
|
+
alias sasl_ir? sasl_ir
|
|
255
|
+
# :startdoc:
|
|
256
|
+
|
|
244
257
|
# Controls the behavior of Net::IMAP#login when the +LOGINDISABLED+
|
|
245
258
|
# capability is present. When enforced, Net::IMAP will raise a
|
|
246
259
|
# LoginDisabledError when that capability is present.
|
|
@@ -347,39 +360,32 @@ module Net
|
|
|
347
360
|
#
|
|
348
361
|
# Alias for responses_without_block
|
|
349
362
|
|
|
350
|
-
#
|
|
351
|
-
#
|
|
352
|
-
#
|
|
363
|
+
# **NOTE:** <em>+UIDPlusData+ has been removed since +v0.6.0+, and this
|
|
364
|
+
# config option only affects deprecation warnings.
|
|
365
|
+
# This config option will be **removed** in +v0.7.0+.</em>
|
|
353
366
|
#
|
|
354
|
-
#
|
|
355
|
-
#
|
|
356
|
-
#
|
|
357
|
-
# vulnerability. Otherwise, parser_max_deprecated_uidplus_data_size
|
|
358
|
-
# mitigates this vulnerability.
|
|
367
|
+
# ResponseParser always returns CopyUIDData for +COPYUID+ response codes,
|
|
368
|
+
# and AppendUIDData for +APPENDUID+ response codes. Previously, this
|
|
369
|
+
# option determined when UIDPlusData would be returned instead.
|
|
359
370
|
#
|
|
360
|
-
#
|
|
361
|
-
# UIDPlusData. Most applications should be able to upgrade with little
|
|
362
|
-
# or no changes.
|
|
371
|
+
# Parser support for +UIDPLUS+ added in +v0.3.2+.
|
|
363
372
|
#
|
|
364
|
-
#
|
|
373
|
+
# Config option added in +v0.4.19+ and +v0.5.6+.
|
|
365
374
|
#
|
|
366
|
-
# <em>
|
|
375
|
+
# <em>UIDPlusData removed in +v0.6.0+.</em>
|
|
367
376
|
#
|
|
368
|
-
#
|
|
369
|
-
# be ignored.</em>
|
|
370
|
-
#
|
|
371
|
-
# ==== Valid options
|
|
377
|
+
# ==== Options
|
|
372
378
|
#
|
|
373
379
|
# [+true+ <em>(original default)</em>]
|
|
374
|
-
#
|
|
380
|
+
# <em>Since v0.6.0:</em>
|
|
381
|
+
# Prints a deprecation warning when parsing +COPYUID+ or +APPENDUID+.
|
|
375
382
|
#
|
|
376
383
|
# [+:up_to_max_size+ <em>(default since +v0.5.6+)</em>]
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
# ResponseParser uses AppendUIDData or CopyUIDData.
|
|
384
|
+
# <em>Since v0.6.0:</em>
|
|
385
|
+
# Prints a deprecation warning when parsing +COPYUID+ or +APPENDUID+.
|
|
380
386
|
#
|
|
381
|
-
# [+false+ <em>(
|
|
382
|
-
#
|
|
387
|
+
# [+false+ <em>(default since +v0.6.0+)</em>]
|
|
388
|
+
# This is the only supported option <em>(since v0.6.0)</em>.
|
|
383
389
|
attr_accessor :parser_use_deprecated_uidplus_data, type: Enum[
|
|
384
390
|
true, :up_to_max_size, false
|
|
385
391
|
], defaults: {
|
|
@@ -388,22 +394,22 @@ module Net
|
|
|
388
394
|
0.6r => false,
|
|
389
395
|
}
|
|
390
396
|
|
|
391
|
-
#
|
|
392
|
-
#
|
|
393
|
-
#
|
|
397
|
+
# **NOTE:** <em>+UIDPlusData+ has been removed since +v0.6.0+, and this
|
|
398
|
+
# config option is ignored.
|
|
399
|
+
# This config option will be **removed** in +v0.7.0+.</em>
|
|
394
400
|
#
|
|
395
|
-
#
|
|
401
|
+
# ResponseParser always returns CopyUIDData for +COPYUID+ response codes,
|
|
402
|
+
# and AppendUIDData for +APPENDUID+ response codes. Previously, this
|
|
403
|
+
# option determined when UIDPlusData would be returned instead.
|
|
396
404
|
#
|
|
397
|
-
#
|
|
398
|
-
# +v0.3.8+, +v0.4.19+, and +v0.5.6+.</em>
|
|
405
|
+
# Parser support for +UIDPLUS+ added in +v0.3.2+.
|
|
399
406
|
#
|
|
400
|
-
#
|
|
407
|
+
# Support for limiting UIDPlusData to a maximum size was added in
|
|
408
|
+
# +v0.3.8+, +v0.4.19+, and +v0.5.6+.
|
|
401
409
|
#
|
|
402
|
-
#
|
|
410
|
+
# <em>UIDPlusData was removed in +v0.6.0+.</em>
|
|
403
411
|
#
|
|
404
|
-
#
|
|
405
|
-
# memory exhaustion, the versioned default (used by #load_defaults) also
|
|
406
|
-
# applies to versions without the feature.
|
|
412
|
+
# ==== Versioned Defaults
|
|
407
413
|
#
|
|
408
414
|
# * +0.3+ and prior: <tt>10,000</tt>
|
|
409
415
|
# * +0.4+: <tt>1,000</tt>
|
|
@@ -485,8 +491,142 @@ module Net
|
|
|
485
491
|
# Returns all config attributes in a hash.
|
|
486
492
|
def to_h; data.members.to_h { [_1, send(_1)] } end
|
|
487
493
|
|
|
494
|
+
# Returns a string representation of overriden config attributes and the
|
|
495
|
+
# inheritance chain.
|
|
496
|
+
#
|
|
497
|
+
# Attributes overridden by ancestors are also inspected, recursively.
|
|
498
|
+
# Attributes that are inherited from default configs are not shown (see
|
|
499
|
+
# Config@Versioned+defaults and Config@Named+defaults).
|
|
500
|
+
#
|
|
501
|
+
# # (Line breaks have been added to the example output for legibility.)
|
|
502
|
+
#
|
|
503
|
+
# Net::IMAP::Config.new(0.4)
|
|
504
|
+
# .new(open_timeout: 10, enforce_logindisabled: true)
|
|
505
|
+
# .inspect
|
|
506
|
+
# #=> "#<Net::IMAP::Config:0x0000745871125410 open_timeout=10 enforce_logindisabled=true
|
|
507
|
+
# # inherits from Net::IMAP::Config[0.4]
|
|
508
|
+
# # inherits from Net::IMAP::Config.global
|
|
509
|
+
# # inherits from Net::IMAP::Config.default>"
|
|
510
|
+
#
|
|
511
|
+
# Non-default attributes are listed after the ancestor config from which
|
|
512
|
+
# they are inherited.
|
|
513
|
+
#
|
|
514
|
+
# # (Line breaks have been added to the example output for legibility.)
|
|
515
|
+
#
|
|
516
|
+
# config = Net::IMAP::Config.global
|
|
517
|
+
# .new(open_timeout: 10, idle_response_timeout: 2)
|
|
518
|
+
# .new(enforce_logindisabled: :when_capabilities_cached, sasl_ir: false)
|
|
519
|
+
# config.inspect
|
|
520
|
+
# #=> "#<Net::IMAP::Config:0x00007ce2a1e20e40 sasl_ir=false enforce_logindisabled=:when_capabilities_cached
|
|
521
|
+
# # inherits from Net::IMAP::Config:0x00007ce2a1e20f80 open_timeout=10 idle_response_timeout=2
|
|
522
|
+
# # inherits from Net::IMAP::Config.global
|
|
523
|
+
# # inherits from Net::IMAP::Config.default>"
|
|
524
|
+
#
|
|
525
|
+
# Net::IMAP.debug = true
|
|
526
|
+
# config.inspect
|
|
527
|
+
# #=> "#<Net::IMAP::Config:0x00007ce2a1e20e40 sasl_ir=false enforce_logindisabled=:when_capabilities_cached
|
|
528
|
+
# # inherits from Net::IMAP::Config:0x00007ce2a1e20f80 open_timeout=10 idle_response_timeout=2
|
|
529
|
+
# # inherits from Net::IMAP::Config.global debug=true
|
|
530
|
+
# # inherits from Net::IMAP::Config.default>"
|
|
531
|
+
#
|
|
532
|
+
# Use +pp+ (see #pretty_print) to inspect _all_ config attributes,
|
|
533
|
+
# including default values.
|
|
534
|
+
#
|
|
535
|
+
# Use #to_h to inspect all config attributes ignoring inheritance.
|
|
536
|
+
def inspect;
|
|
537
|
+
"#<#{inspect_recursive}>"
|
|
538
|
+
end
|
|
539
|
+
alias to_s inspect
|
|
540
|
+
|
|
541
|
+
# Used by PP[https://docs.ruby-lang.org/en/master/PP.html] to create a
|
|
542
|
+
# string representation of all config attributes and the inheritance
|
|
543
|
+
# chain. Inherited attributes are listed with the ancestor config from
|
|
544
|
+
# which they are inherited.
|
|
545
|
+
#
|
|
546
|
+
# pp Config.new[0.4].new(open_timeout: 10, idle_response_timeout: 10)
|
|
547
|
+
# # #<Net::IMAP::Config:0x0000745871125410
|
|
548
|
+
# # open_timeout=10
|
|
549
|
+
# # idle_response_timeout=10
|
|
550
|
+
# # inherits from Net::IMAP::Config[0.4]
|
|
551
|
+
# # responses_without_block=:silence_deprecation_warning
|
|
552
|
+
# # max_response_size=nil
|
|
553
|
+
# # sasl_ir=true
|
|
554
|
+
# # enforce_logindisabled=false
|
|
555
|
+
# # parser_use_deprecated_uidplus_data=true
|
|
556
|
+
# # parser_max_deprecated_uidplus_data_size=1000
|
|
557
|
+
# # inherits from Net::IMAP::Config.global
|
|
558
|
+
# # inherits from Net::IMAP::Config.default
|
|
559
|
+
# # debug=false>
|
|
560
|
+
#
|
|
561
|
+
# Related: #inspect, #to_h.
|
|
562
|
+
def pretty_print(pp)
|
|
563
|
+
pp.group(2, "#<", ">") do
|
|
564
|
+
pretty_print_recursive(pp)
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
# :stopdoc:
|
|
569
|
+
|
|
488
570
|
protected
|
|
489
571
|
|
|
572
|
+
def named_default?
|
|
573
|
+
equal?(Config.default) ||
|
|
574
|
+
AttrVersionDefaults::VERSIONS.any? { equal? Config[_1] }
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def name
|
|
578
|
+
if equal? Config.default then "#{Config}.default"
|
|
579
|
+
elsif equal? Config.global then "#{Config}.global"
|
|
580
|
+
elsif equal? Config[0.0r] then "#{Config}[:original]"
|
|
581
|
+
elsif equal? Config[:default] then "#{Config}[:default]"
|
|
582
|
+
elsif (v = AttrVersionDefaults::VERSIONS.find { equal? Config[_1] })
|
|
583
|
+
"%s[%0.1f]" % [Config, v]
|
|
584
|
+
else
|
|
585
|
+
Kernel.instance_method(:to_s).bind_call(self).delete("<#>")
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
def inspect_recursive(attrs = AttrAccessors.struct.members)
|
|
590
|
+
strings = [name]
|
|
591
|
+
assigned = assigned_attrs_hash(attrs)
|
|
592
|
+
strings.concat assigned.map { "%s=%p" % _1 }
|
|
593
|
+
if parent
|
|
594
|
+
if parent.equal?(Config.default)
|
|
595
|
+
inherited_overrides = []
|
|
596
|
+
elsif parent
|
|
597
|
+
inherited_overrides = attrs - assigned.keys
|
|
598
|
+
inherited_overrides &= DEFAULT_TO_INHERIT if parent.named_default?
|
|
599
|
+
end
|
|
600
|
+
strings << "inherits from #{parent.inspect_recursive(inherited_overrides)}"
|
|
601
|
+
end
|
|
602
|
+
strings.join " "
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def pretty_print_recursive(pp, attrs = AttrAccessors.struct.members)
|
|
606
|
+
pp.text name
|
|
607
|
+
assigned = assigned_attrs_hash(attrs)
|
|
608
|
+
pp.breakable
|
|
609
|
+
pp.seplist(assigned, ->{pp.breakable}) do |key, val|
|
|
610
|
+
pp.text key.to_s
|
|
611
|
+
pp.text "="
|
|
612
|
+
pp.pp val
|
|
613
|
+
end
|
|
614
|
+
if parent
|
|
615
|
+
pp.breakable if assigned.any?
|
|
616
|
+
pp.nest(2) do
|
|
617
|
+
pp.text "inherits from "
|
|
618
|
+
parent.pretty_print_recursive(pp, attrs - assigned.keys)
|
|
619
|
+
end
|
|
620
|
+
elsif assigned.empty?
|
|
621
|
+
pp.text "(overridden)"
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
def assigned_attrs_hash(attrs)
|
|
626
|
+
own_attrs = attrs.reject { inherited?(_1) }
|
|
627
|
+
own_attrs.to_h { [_1, data[_1]] }
|
|
628
|
+
end
|
|
629
|
+
|
|
490
630
|
def defaults_hash
|
|
491
631
|
to_h.reject {|k,v| DEFAULT_TO_INHERIT.include?(k) }
|
|
492
632
|
end
|