net-imap 0.4.11 → 0.4.14
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/BSDL +22 -0
- data/COPYING +56 -0
- data/LICENSE.txt +3 -22
- 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 +339 -0
- data/lib/net/imap/data_encoding.rb +1 -1
- data/lib/net/imap/deprecated_client_options.rb +3 -3
- data/lib/net/imap/errors.rb +1 -1
- data/lib/net/imap/flags.rb +1 -1
- data/lib/net/imap/response_data.rb +5 -5
- data/lib/net/imap/response_parser/parser_utils.rb +6 -6
- data/lib/net/imap/response_parser.rb +4 -1
- data/lib/net/imap/sasl/external_authenticator.rb +1 -1
- data/lib/net/imap/sasl.rb +1 -1
- data/lib/net/imap/sequence_set.rb +2 -2
- data/lib/net/imap.rb +86 -36
- data/net-imap.gemspec +2 -2
- metadata +9 -9
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/pages.yml +0 -46
- data/.github/workflows/release-gem.yml +0 -38
- data/.github/workflows/test.yml +0 -31
- data/.gitignore +0 -12
- data/.mailmap +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 06be993e038a4432ec954b11701ce86f946c456f9125d2b539e6c21d05e728ab
|
|
4
|
+
data.tar.gz: 7807fb77537a843e9d9a2ad0ad892dc3e75af3a734f2c4c68a1e2cbae4d34ef1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 182edade4a45d1c6f4772332f2f9cd4704827895770764202aa843bfbb754defff11a8037c1955e352642201c57cea850ea51aa8e4fe6c1761b36c78562b1c5b
|
|
7
|
+
data.tar.gz: 2fff884a15a87ae7cb4a5ac422f743b5accd1ea98b34bf994cbb18238577cc259a1a672a04e5dac14864ad61bdafd90c43c160ede8ba369246fd3bb265e5cff2
|
data/BSDL
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions
|
|
5
|
+
are met:
|
|
6
|
+
1. Redistributions of source code must retain the above copyright
|
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
|
10
|
+
documentation and/or other materials provided with the distribution.
|
|
11
|
+
|
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
13
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
14
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
15
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
16
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
17
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
18
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
19
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
20
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
21
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
22
|
+
SUCH DAMAGE.
|
data/COPYING
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
|
|
2
|
+
You can redistribute it and/or modify it under either the terms of the
|
|
3
|
+
2-clause BSDL (see the file BSDL), or the conditions below:
|
|
4
|
+
|
|
5
|
+
1. You may make and give away verbatim copies of the source form of the
|
|
6
|
+
software without restriction, provided that you duplicate all of the
|
|
7
|
+
original copyright notices and associated disclaimers.
|
|
8
|
+
|
|
9
|
+
2. You may modify your copy of the software in any way, provided that
|
|
10
|
+
you do at least ONE of the following:
|
|
11
|
+
|
|
12
|
+
a. place your modifications in the Public Domain or otherwise
|
|
13
|
+
make them Freely Available, such as by posting said
|
|
14
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
|
15
|
+
the author to include your modifications in the software.
|
|
16
|
+
|
|
17
|
+
b. use the modified software only within your corporation or
|
|
18
|
+
organization.
|
|
19
|
+
|
|
20
|
+
c. give non-standard binaries non-standard names, with
|
|
21
|
+
instructions on where to get the original software distribution.
|
|
22
|
+
|
|
23
|
+
d. make other distribution arrangements with the author.
|
|
24
|
+
|
|
25
|
+
3. You may distribute the software in object code or binary form,
|
|
26
|
+
provided that you do at least ONE of the following:
|
|
27
|
+
|
|
28
|
+
a. distribute the binaries and library files of the software,
|
|
29
|
+
together with instructions (in the manual page or equivalent)
|
|
30
|
+
on where to get the original distribution.
|
|
31
|
+
|
|
32
|
+
b. accompany the distribution with the machine-readable source of
|
|
33
|
+
the software.
|
|
34
|
+
|
|
35
|
+
c. give non-standard binaries non-standard names, with
|
|
36
|
+
instructions on where to get the original software distribution.
|
|
37
|
+
|
|
38
|
+
d. make other distribution arrangements with the author.
|
|
39
|
+
|
|
40
|
+
4. You may modify and include the part of the software into any other
|
|
41
|
+
software (possibly commercial). But some files in the distribution
|
|
42
|
+
are not written by the author, so that they are not under these terms.
|
|
43
|
+
|
|
44
|
+
For the list of those files and their copying conditions, see the
|
|
45
|
+
file LEGAL.
|
|
46
|
+
|
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
|
48
|
+
output from the software do not automatically fall under the
|
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
|
51
|
+
software.
|
|
52
|
+
|
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
56
|
+
PURPOSE.
|
data/LICENSE.txt
CHANGED
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
modification, are permitted provided that the following conditions
|
|
5
|
-
are met:
|
|
6
|
-
1. Redistributions of source code must retain the above copyright
|
|
7
|
-
notice, this list of conditions and the following disclaimer.
|
|
8
|
-
2. Redistributions in binary form must reproduce the above copyright
|
|
9
|
-
notice, this list of conditions and the following disclaimer in the
|
|
10
|
-
documentation and/or other materials provided with the distribution.
|
|
11
|
-
|
|
12
|
-
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
13
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
14
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
15
|
-
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
16
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
17
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
18
|
-
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
19
|
-
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
20
|
-
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
21
|
-
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
22
|
-
SUCH DAMAGE.
|
|
1
|
+
All the files in this distribution are covered under either the Ruby license or
|
|
2
|
+
the BSD-2-Clause license (see the file COPYING) except some documentation mentioned
|
|
3
|
+
below.
|
|
23
4
|
|
|
24
5
|
-------------------------------------------------------------------------
|
|
25
6
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
5
|
+
module Net
|
|
6
|
+
class IMAP
|
|
7
|
+
class Config
|
|
8
|
+
# >>>
|
|
9
|
+
# *NOTE:* This module is an internal implementation detail, with no
|
|
10
|
+
# guarantee of backward compatibility.
|
|
11
|
+
#
|
|
12
|
+
# +attr_accessor+ values are stored in a struct rather than ivars, making
|
|
13
|
+
# it simpler to ensure that all config objects share a single object
|
|
14
|
+
# shape. This also simplifies iteration over all defined attributes.
|
|
15
|
+
module AttrAccessors
|
|
16
|
+
module Macros # :nodoc: internal API
|
|
17
|
+
def attr_accessor(name) AttrAccessors.attr_accessor(name) end
|
|
18
|
+
end
|
|
19
|
+
private_constant :Macros
|
|
20
|
+
|
|
21
|
+
def self.included(mod)
|
|
22
|
+
mod.extend Macros
|
|
23
|
+
end
|
|
24
|
+
private_class_method :included
|
|
25
|
+
|
|
26
|
+
extend Forwardable
|
|
27
|
+
|
|
28
|
+
def self.attr_accessor(name) # :nodoc: internal API
|
|
29
|
+
name = name.to_sym
|
|
30
|
+
def_delegators :data, name, :"#{name}="
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.attributes
|
|
34
|
+
instance_methods.grep(/=\z/).map { _1.to_s.delete_suffix("=").to_sym }
|
|
35
|
+
end
|
|
36
|
+
private_class_method :attributes
|
|
37
|
+
|
|
38
|
+
def self.struct # :nodoc: internal API
|
|
39
|
+
unless defined?(self::Struct)
|
|
40
|
+
const_set :Struct, Struct.new(*attributes)
|
|
41
|
+
end
|
|
42
|
+
self::Struct
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def initialize # :notnew:
|
|
46
|
+
super()
|
|
47
|
+
@data = AttrAccessors.struct.new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Freezes the internal attributes struct, in addition to +self+.
|
|
51
|
+
def freeze
|
|
52
|
+
data.freeze
|
|
53
|
+
super
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
protected
|
|
57
|
+
|
|
58
|
+
attr_reader :data # :nodoc: internal API
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def initialize_clone(other)
|
|
63
|
+
super
|
|
64
|
+
@data = other.data.clone
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def initialize_dup(other)
|
|
68
|
+
super
|
|
69
|
+
@data = other.data.dup
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Net
|
|
4
|
+
class IMAP
|
|
5
|
+
class Config
|
|
6
|
+
# >>>
|
|
7
|
+
# *NOTE:* The public methods on this module are part of the stable
|
|
8
|
+
# public API of Net::IMAP::Config. But the module itself is an internal
|
|
9
|
+
# implementation detail, with no guarantee of backward compatibility.
|
|
10
|
+
#
|
|
11
|
+
# +attr_accessor+ methods will delegate to their #parent when the local
|
|
12
|
+
# value does not contain an override. Inheritance forms a singly linked
|
|
13
|
+
# list, so lookup will be <tt>O(n)</tt> on the number of ancestors. In
|
|
14
|
+
# practice, the ancestor chain is not expected to be long. Without
|
|
15
|
+
# customization, it is only three deep:
|
|
16
|
+
# >>>
|
|
17
|
+
# IMAP#config → Config.global → Config.default
|
|
18
|
+
#
|
|
19
|
+
# When creating a client with the +config+ keyword, for example to use
|
|
20
|
+
# the appropriate defaults for an application or a library while still
|
|
21
|
+
# relying on global for configuration of +debug+ or +logger+, most likely
|
|
22
|
+
# the ancestor chain is still only four deep:
|
|
23
|
+
# >>>
|
|
24
|
+
# IMAP#config → alternate defaults → Config.global → Config.default
|
|
25
|
+
module AttrInheritance
|
|
26
|
+
INHERITED = Module.new.freeze
|
|
27
|
+
private_constant :INHERITED
|
|
28
|
+
|
|
29
|
+
module Macros # :nodoc: internal API
|
|
30
|
+
def attr_accessor(name) super; AttrInheritance.attr_accessor(name) end
|
|
31
|
+
end
|
|
32
|
+
private_constant :Macros
|
|
33
|
+
|
|
34
|
+
def self.included(mod)
|
|
35
|
+
mod.extend Macros
|
|
36
|
+
end
|
|
37
|
+
private_class_method :included
|
|
38
|
+
|
|
39
|
+
def self.attr_accessor(name) # :nodoc: internal API
|
|
40
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
41
|
+
def #{name}; (val = super) == INHERITED ? parent&.#{name} : val end
|
|
42
|
+
RUBY
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The parent Config object
|
|
46
|
+
attr_reader :parent
|
|
47
|
+
|
|
48
|
+
def initialize(parent = nil) # :notnew:
|
|
49
|
+
super()
|
|
50
|
+
@parent = Config[parent]
|
|
51
|
+
reset
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Creates a new config, which inherits from +self+.
|
|
55
|
+
def new(**attrs) self.class.new(self, **attrs) end
|
|
56
|
+
|
|
57
|
+
# Returns +true+ if +attr+ is inherited from #parent and not overridden
|
|
58
|
+
# by this config.
|
|
59
|
+
def inherited?(attr) data[attr] == INHERITED end
|
|
60
|
+
|
|
61
|
+
# :call-seq:
|
|
62
|
+
# reset -> self
|
|
63
|
+
# reset(attr) -> attribute value
|
|
64
|
+
#
|
|
65
|
+
# Resets an +attr+ to inherit from the #parent config.
|
|
66
|
+
#
|
|
67
|
+
# When +attr+ is nil or not given, all attributes are reset.
|
|
68
|
+
def reset(attr = nil)
|
|
69
|
+
if attr.nil?
|
|
70
|
+
data.members.each do |attr| data[attr] = INHERITED end
|
|
71
|
+
self
|
|
72
|
+
elsif inherited?(attr)
|
|
73
|
+
nil
|
|
74
|
+
else
|
|
75
|
+
old, data[attr] = data[attr], INHERITED
|
|
76
|
+
old
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def initialize_copy(other)
|
|
83
|
+
super
|
|
84
|
+
@parent ||= other # only default has nil parent
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Net
|
|
4
|
+
class IMAP
|
|
5
|
+
class Config
|
|
6
|
+
# >>>
|
|
7
|
+
# *NOTE:* This module is an internal implementation detail, with no
|
|
8
|
+
# guarantee of backward compatibility.
|
|
9
|
+
#
|
|
10
|
+
# Adds a +type+ keyword parameter to +attr_accessor+, to enforce that
|
|
11
|
+
# config attributes have valid types, for example: boolean, numeric,
|
|
12
|
+
# enumeration, non-nullable, etc.
|
|
13
|
+
module AttrTypeCoercion
|
|
14
|
+
# :stopdoc: internal APIs only
|
|
15
|
+
|
|
16
|
+
module Macros # :nodoc: internal API
|
|
17
|
+
def attr_accessor(attr, type: nil)
|
|
18
|
+
super(attr)
|
|
19
|
+
AttrTypeCoercion.attr_accessor(attr, type: type)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
private_constant :Macros
|
|
23
|
+
|
|
24
|
+
def self.included(mod)
|
|
25
|
+
mod.extend Macros
|
|
26
|
+
end
|
|
27
|
+
private_class_method :included
|
|
28
|
+
|
|
29
|
+
def self.attr_accessor(attr, type: nil)
|
|
30
|
+
return unless type
|
|
31
|
+
if :boolean == type then boolean attr
|
|
32
|
+
elsif Integer == type then integer attr
|
|
33
|
+
elsif Array === type then enum attr, type
|
|
34
|
+
else raise ArgumentError, "unknown type coercion %p" % [type]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.boolean(attr)
|
|
39
|
+
define_method :"#{attr}=" do |val| super !!val end
|
|
40
|
+
define_method :"#{attr}?" do send attr end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.integer(attr)
|
|
44
|
+
define_method :"#{attr}=" do |val| super Integer val end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.enum(attr, enum)
|
|
48
|
+
enum = enum.dup.freeze
|
|
49
|
+
expected = -"one of #{enum.map(&:inspect).join(", ")}"
|
|
50
|
+
define_method :"#{attr}=" do |val|
|
|
51
|
+
unless enum.include?(val)
|
|
52
|
+
raise ArgumentError, "expected %s, got %p" % [expected, val]
|
|
53
|
+
end
|
|
54
|
+
super val
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "config/attr_accessors"
|
|
4
|
+
require_relative "config/attr_inheritance"
|
|
5
|
+
require_relative "config/attr_type_coercion"
|
|
6
|
+
|
|
7
|
+
module Net
|
|
8
|
+
class IMAP
|
|
9
|
+
|
|
10
|
+
# Net::IMAP::Config stores configuration options for Net::IMAP clients.
|
|
11
|
+
# The global configuration can be seen at either Net::IMAP.config or
|
|
12
|
+
# Net::IMAP::Config.global, and the client-specific configuration can be
|
|
13
|
+
# seen at Net::IMAP#config.
|
|
14
|
+
#
|
|
15
|
+
# When creating a new client, all unhandled keyword arguments to
|
|
16
|
+
# Net::IMAP.new are delegated to Config.new. Every client has its own
|
|
17
|
+
# config.
|
|
18
|
+
#
|
|
19
|
+
# debug_client = Net::IMAP.new(hostname, debug: true)
|
|
20
|
+
# quiet_client = Net::IMAP.new(hostname, debug: false)
|
|
21
|
+
# debug_client.config.debug? # => true
|
|
22
|
+
# quiet_client.config.debug? # => false
|
|
23
|
+
#
|
|
24
|
+
# == Inheritance
|
|
25
|
+
#
|
|
26
|
+
# Configs have a parent[rdoc-ref:Config::AttrInheritance#parent] config, and
|
|
27
|
+
# any attributes which have not been set locally will inherit the parent's
|
|
28
|
+
# value. Every client creates its own specific config. By default, client
|
|
29
|
+
# configs inherit from Config.global.
|
|
30
|
+
#
|
|
31
|
+
# plain_client = Net::IMAP.new(hostname)
|
|
32
|
+
# debug_client = Net::IMAP.new(hostname, debug: true)
|
|
33
|
+
# quiet_client = Net::IMAP.new(hostname, debug: false)
|
|
34
|
+
#
|
|
35
|
+
# plain_client.config.inherited?(:debug) # => true
|
|
36
|
+
# debug_client.config.inherited?(:debug) # => false
|
|
37
|
+
# quiet_client.config.inherited?(:debug) # => false
|
|
38
|
+
#
|
|
39
|
+
# plain_client.config.debug? # => false
|
|
40
|
+
# debug_client.config.debug? # => true
|
|
41
|
+
# quiet_client.config.debug? # => false
|
|
42
|
+
#
|
|
43
|
+
# # Net::IMAP.debug is delegated to Net::IMAP::Config.global.debug
|
|
44
|
+
# Net::IMAP.debug = true
|
|
45
|
+
# plain_client.config.debug? # => true
|
|
46
|
+
# debug_client.config.debug? # => true
|
|
47
|
+
# quiet_client.config.debug? # => false
|
|
48
|
+
#
|
|
49
|
+
# Net::IMAP.debug = false
|
|
50
|
+
# plain_client.config.debug = true
|
|
51
|
+
# plain_client.config.inherited?(:debug) # => false
|
|
52
|
+
# plain_client.config.debug? # => true
|
|
53
|
+
# plain_client.config.reset(:debug)
|
|
54
|
+
# plain_client.config.inherited?(:debug) # => true
|
|
55
|
+
# plain_client.config.debug? # => false
|
|
56
|
+
#
|
|
57
|
+
# == Versioned defaults
|
|
58
|
+
#
|
|
59
|
+
# The effective default configuration for a specific +x.y+ version of
|
|
60
|
+
# +net-imap+ can be loaded with the +config+ keyword argument to
|
|
61
|
+
# Net::IMAP.new. Requesting default configurations for previous versions
|
|
62
|
+
# enables extra backward compatibility with those versions:
|
|
63
|
+
#
|
|
64
|
+
# client = Net::IMAP.new(hostname, config: 0.3)
|
|
65
|
+
# client.config.sasl_ir # => false
|
|
66
|
+
# client.config.responses_without_block # => :silence_deprecation_warning
|
|
67
|
+
#
|
|
68
|
+
# client = Net::IMAP.new(hostname, config: 0.4)
|
|
69
|
+
# client.config.sasl_ir # => true
|
|
70
|
+
# client.config.responses_without_block # => :silence_deprecation_warning
|
|
71
|
+
#
|
|
72
|
+
# client = Net::IMAP.new(hostname, config: 0.5)
|
|
73
|
+
# client.config.sasl_ir # => true
|
|
74
|
+
# client.config.responses_without_block # => :warn
|
|
75
|
+
#
|
|
76
|
+
# client = Net::IMAP.new(hostname, config: :future)
|
|
77
|
+
# client.config.sasl_ir # => true
|
|
78
|
+
# client.config.responses_without_block # => :raise
|
|
79
|
+
#
|
|
80
|
+
# The versioned default configs inherit certain specific config options from
|
|
81
|
+
# Config.global, for example #debug:
|
|
82
|
+
#
|
|
83
|
+
# client = Net::IMAP.new(hostname, config: 0.4)
|
|
84
|
+
# Net::IMAP.debug = false
|
|
85
|
+
# client.config.debug? # => false
|
|
86
|
+
#
|
|
87
|
+
# Net::IMAP.debug = true
|
|
88
|
+
# client.config.debug? # => true
|
|
89
|
+
#
|
|
90
|
+
# Use #load_defaults to globally behave like a specific version:
|
|
91
|
+
# client = Net::IMAP.new(hostname)
|
|
92
|
+
# client.config.sasl_ir # => true
|
|
93
|
+
# Net::IMAP.config.load_defaults 0.3
|
|
94
|
+
# client.config.sasl_ir # => false
|
|
95
|
+
#
|
|
96
|
+
# === Named defaults
|
|
97
|
+
# In addition to +x.y+ version numbers, the following aliases are supported:
|
|
98
|
+
#
|
|
99
|
+
# [+:default+]
|
|
100
|
+
# An alias for +:current+.
|
|
101
|
+
#
|
|
102
|
+
# >>>
|
|
103
|
+
# *NOTE*: This is _not_ the same as Config.default. It inherits some
|
|
104
|
+
# attributes from Config.global, for example: #debug.
|
|
105
|
+
# [+:current+]
|
|
106
|
+
# An alias for the current +x.y+ version's defaults.
|
|
107
|
+
# [+:next+]
|
|
108
|
+
# The _planned_ config for the next +x.y+ version.
|
|
109
|
+
# [+:future+]
|
|
110
|
+
# The _planned_ eventual config for some future +x.y+ version.
|
|
111
|
+
#
|
|
112
|
+
# For example, to raise exceptions for all current deprecations:
|
|
113
|
+
# client = Net::IMAP.new(hostname, config: :future)
|
|
114
|
+
# client.responses # raises an ArgumentError
|
|
115
|
+
#
|
|
116
|
+
# == Thread Safety
|
|
117
|
+
#
|
|
118
|
+
# *NOTE:* Updates to config objects are not synchronized for thread-safety.
|
|
119
|
+
#
|
|
120
|
+
class Config
|
|
121
|
+
# Array of attribute names that are _not_ loaded by #load_defaults.
|
|
122
|
+
DEFAULT_TO_INHERIT = %i[debug].freeze
|
|
123
|
+
private_constant :DEFAULT_TO_INHERIT
|
|
124
|
+
|
|
125
|
+
# The default config, which is hardcoded and frozen.
|
|
126
|
+
def self.default; @default end
|
|
127
|
+
|
|
128
|
+
# The global config object. Also available from Net::IMAP.config.
|
|
129
|
+
def self.global; @global if defined?(@global) end
|
|
130
|
+
|
|
131
|
+
# A hash of hard-coded configurations, indexed by version number.
|
|
132
|
+
def self.version_defaults; @version_defaults end
|
|
133
|
+
@version_defaults = {}
|
|
134
|
+
|
|
135
|
+
# :call-seq:
|
|
136
|
+
# Net::IMAP::Config[number] -> versioned config
|
|
137
|
+
# Net::IMAP::Config[symbol] -> named config
|
|
138
|
+
# Net::IMAP::Config[hash] -> new frozen config
|
|
139
|
+
# Net::IMAP::Config[config] -> same config
|
|
140
|
+
#
|
|
141
|
+
# Given a version number, returns the default configuration for the target
|
|
142
|
+
# version. See Config@Versioned+defaults.
|
|
143
|
+
#
|
|
144
|
+
# Given a version name, returns the default configuration for the target
|
|
145
|
+
# version. See Config@Named+defaults.
|
|
146
|
+
#
|
|
147
|
+
# Given a Hash, creates a new _frozen_ config which inherits from
|
|
148
|
+
# Config.global. Use Config.new for an unfrozen config.
|
|
149
|
+
#
|
|
150
|
+
# Given a config, returns that same config.
|
|
151
|
+
def self.[](config)
|
|
152
|
+
if config.is_a?(Config) then config
|
|
153
|
+
elsif config.nil? && global.nil? then nil
|
|
154
|
+
elsif config.respond_to?(:to_hash) then new(global, **config).freeze
|
|
155
|
+
else
|
|
156
|
+
version_defaults.fetch(config) do
|
|
157
|
+
case config
|
|
158
|
+
when Numeric
|
|
159
|
+
raise RangeError, "unknown config version: %p" % [config]
|
|
160
|
+
when Symbol
|
|
161
|
+
raise KeyError, "unknown config name: %p" % [config]
|
|
162
|
+
else
|
|
163
|
+
raise TypeError, "no implicit conversion of %s to %s" % [
|
|
164
|
+
config.class, Config
|
|
165
|
+
]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
include AttrAccessors
|
|
172
|
+
include AttrInheritance
|
|
173
|
+
include AttrTypeCoercion
|
|
174
|
+
|
|
175
|
+
# The debug mode (boolean)
|
|
176
|
+
#
|
|
177
|
+
# The default value is +false+.
|
|
178
|
+
attr_accessor :debug, type: :boolean
|
|
179
|
+
|
|
180
|
+
# method: debug?
|
|
181
|
+
# :call-seq: debug? -> boolean
|
|
182
|
+
#
|
|
183
|
+
# Alias for #debug
|
|
184
|
+
|
|
185
|
+
# Seconds to wait until a connection is opened.
|
|
186
|
+
#
|
|
187
|
+
# If the IMAP object cannot open a connection within this time,
|
|
188
|
+
# it raises a Net::OpenTimeout exception.
|
|
189
|
+
#
|
|
190
|
+
# See Net::IMAP.new.
|
|
191
|
+
#
|
|
192
|
+
# The default value is +30+ seconds.
|
|
193
|
+
attr_accessor :open_timeout, type: Integer
|
|
194
|
+
|
|
195
|
+
# Seconds to wait until an IDLE response is received, after
|
|
196
|
+
# the client asks to leave the IDLE state.
|
|
197
|
+
#
|
|
198
|
+
# See Net::IMAP#idle and Net::IMAP#idle_done.
|
|
199
|
+
#
|
|
200
|
+
# The default value is +5+ seconds.
|
|
201
|
+
attr_accessor :idle_response_timeout, type: Integer
|
|
202
|
+
|
|
203
|
+
# :markup: markdown
|
|
204
|
+
#
|
|
205
|
+
# Whether to use the +SASL-IR+ extension when the server and \SASL
|
|
206
|
+
# mechanism both support it.
|
|
207
|
+
#
|
|
208
|
+
# See Net::IMAP#authenticate.
|
|
209
|
+
#
|
|
210
|
+
# | Starting with version | The default value is |
|
|
211
|
+
# |-----------------------|------------------------------------------|
|
|
212
|
+
# | _original_ | +false+ <em>(extension unsupported)</em> |
|
|
213
|
+
# | v0.4 | +true+ <em>(support added)</em> |
|
|
214
|
+
attr_accessor :sasl_ir, type: :boolean
|
|
215
|
+
|
|
216
|
+
# :markup: markdown
|
|
217
|
+
#
|
|
218
|
+
# Controls the behavior of Net::IMAP#responses when called without a
|
|
219
|
+
# block. Valid options are `:warn`, `:raise`, or
|
|
220
|
+
# `:silence_deprecation_warning`.
|
|
221
|
+
#
|
|
222
|
+
# | Starting with version | The default value is |
|
|
223
|
+
# |-------------------------|--------------------------------|
|
|
224
|
+
# | v0.4.13 | +:silence_deprecation_warning+ |
|
|
225
|
+
# | v0.5 <em>(planned)</em> | +:warn+ |
|
|
226
|
+
# | _eventually_ | +:raise+ |
|
|
227
|
+
attr_accessor :responses_without_block, type: [
|
|
228
|
+
:silence_deprecation_warning, :warn, :raise,
|
|
229
|
+
]
|
|
230
|
+
|
|
231
|
+
# Creates a new config object and initialize its attribute with +attrs+.
|
|
232
|
+
#
|
|
233
|
+
# If +parent+ is not given, the global config is used by default.
|
|
234
|
+
#
|
|
235
|
+
# If a block is given, the new config object is yielded to it.
|
|
236
|
+
def initialize(parent = Config.global, **attrs)
|
|
237
|
+
super(parent)
|
|
238
|
+
update(**attrs)
|
|
239
|
+
yield self if block_given?
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# :call-seq: update(**attrs) -> self
|
|
243
|
+
#
|
|
244
|
+
# Assigns all of the provided +attrs+ to this config, and returns +self+.
|
|
245
|
+
#
|
|
246
|
+
# An ArgumentError is raised unless every key in +attrs+ matches an
|
|
247
|
+
# assignment method on Config.
|
|
248
|
+
#
|
|
249
|
+
# >>>
|
|
250
|
+
# *NOTE:* #update is not atomic. If an exception is raised due to an
|
|
251
|
+
# invalid attribute value, +attrs+ may be partially applied.
|
|
252
|
+
def update(**attrs)
|
|
253
|
+
unless (bad = attrs.keys.reject { respond_to?(:"#{_1}=") }).empty?
|
|
254
|
+
raise ArgumentError, "invalid config options: #{bad.join(", ")}"
|
|
255
|
+
end
|
|
256
|
+
attrs.each do send(:"#{_1}=", _2) end
|
|
257
|
+
self
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# :call-seq:
|
|
261
|
+
# with(**attrs) -> config
|
|
262
|
+
# with(**attrs) {|config| } -> result
|
|
263
|
+
#
|
|
264
|
+
# Without a block, returns a new config which inherits from self. With a
|
|
265
|
+
# block, yields the new config and returns the block's result.
|
|
266
|
+
#
|
|
267
|
+
# If no keyword arguments are given, an ArgumentError will be raised.
|
|
268
|
+
#
|
|
269
|
+
# If +self+ is frozen, the copy will also be frozen.
|
|
270
|
+
def with(**attrs)
|
|
271
|
+
attrs.empty? and
|
|
272
|
+
raise ArgumentError, "expected keyword arguments, none given"
|
|
273
|
+
copy = new(**attrs)
|
|
274
|
+
copy.freeze if frozen?
|
|
275
|
+
block_given? ? yield(copy) : copy
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# :call-seq: load_defaults(version) -> self
|
|
279
|
+
#
|
|
280
|
+
# Resets the current config to behave like the versioned default
|
|
281
|
+
# configuration for +version+. #parent will not be changed.
|
|
282
|
+
#
|
|
283
|
+
# Some config attributes default to inheriting from their #parent (which
|
|
284
|
+
# is usually Config.global) and are left unchanged, for example: #debug.
|
|
285
|
+
#
|
|
286
|
+
# See Config@Versioned+defaults and Config@Named+defaults.
|
|
287
|
+
def load_defaults(version)
|
|
288
|
+
[Numeric, Symbol, String].any? { _1 === version } or
|
|
289
|
+
raise ArgumentError, "expected number or symbol, got %p" % [version]
|
|
290
|
+
update(**Config[version].defaults_hash)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# :call-seq: to_h -> hash
|
|
294
|
+
#
|
|
295
|
+
# Returns all config attributes in a hash.
|
|
296
|
+
def to_h; data.members.to_h { [_1, send(_1)] } end
|
|
297
|
+
|
|
298
|
+
protected
|
|
299
|
+
|
|
300
|
+
def defaults_hash
|
|
301
|
+
to_h.reject {|k,v| DEFAULT_TO_INHERIT.include?(k) }
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
@default = new(
|
|
305
|
+
debug: false,
|
|
306
|
+
open_timeout: 30,
|
|
307
|
+
idle_response_timeout: 5,
|
|
308
|
+
sasl_ir: true,
|
|
309
|
+
responses_without_block: :silence_deprecation_warning,
|
|
310
|
+
).freeze
|
|
311
|
+
|
|
312
|
+
@global = default.new
|
|
313
|
+
|
|
314
|
+
version_defaults[0.4] = Config[default.send(:defaults_hash)]
|
|
315
|
+
|
|
316
|
+
version_defaults[0] = Config[0.4].dup.update(
|
|
317
|
+
sasl_ir: false,
|
|
318
|
+
).freeze
|
|
319
|
+
version_defaults[0.0] = Config[0]
|
|
320
|
+
version_defaults[0.1] = Config[0]
|
|
321
|
+
version_defaults[0.2] = Config[0]
|
|
322
|
+
version_defaults[0.3] = Config[0]
|
|
323
|
+
|
|
324
|
+
version_defaults[0.5] = Config[0.4].dup.update(
|
|
325
|
+
responses_without_block: :warn,
|
|
326
|
+
).freeze
|
|
327
|
+
|
|
328
|
+
version_defaults[:default] = Config[0.4]
|
|
329
|
+
version_defaults[:current] = Config[0.4]
|
|
330
|
+
version_defaults[:next] = Config[0.5]
|
|
331
|
+
|
|
332
|
+
version_defaults[:future] = Config[0.5].dup.update(
|
|
333
|
+
responses_without_block: :raise,
|
|
334
|
+
).freeze
|
|
335
|
+
|
|
336
|
+
version_defaults.freeze
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|