net-imap 0.4.12 → 0.4.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/net/imap/config/attr_accessors.rb +70 -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 +162 -0
- data/lib/net/imap/deprecated_client_options.rb +2 -2
- data/lib/net/imap/response_parser/parser_utils.rb +6 -6
- data/lib/net/imap/response_parser.rb +4 -1
- data/lib/net/imap.rb +84 -34
- data/net-imap.gemspec +2 -2
- metadata +10 -9
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a7254a9f8865dfd12d8887a0ce62f58d764f43acb3eea019fadd13ff3f6983c
|
4
|
+
data.tar.gz: 8a3ae5456b5a7d78f72d862e6dcf8f8df86ec6a3d32956314c1eadc36bf5def0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41ee8dd354e77a06f4875ad559efb6dbae6f60c39ad714d0de46efe8a49e125194b48e02cce4d1425c73122c57ec300dcd4e7707409bcf964318146b3b9e6168
|
7
|
+
data.tar.gz: 215057347ecca04a9816df24b5250f124b2b655615507ef84e6b2a12567b23810da9f394f74801cd046c18e7d01072a567b95eb241bb7db7896982e9d24e414f
|
@@ -0,0 +1,70 @@
|
|
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_dup(other)
|
63
|
+
super
|
64
|
+
@data = other.data.dup
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
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,162 @@
|
|
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
|
+
#
|
58
|
+
# == Thread Safety
|
59
|
+
#
|
60
|
+
# *NOTE:* Updates to config objects are not synchronized for thread-safety.
|
61
|
+
#
|
62
|
+
class Config
|
63
|
+
# The default config, which is hardcoded and frozen.
|
64
|
+
def self.default; @default end
|
65
|
+
|
66
|
+
# The global config object. Also available from Net::IMAP.config.
|
67
|
+
def self.global; @global end
|
68
|
+
|
69
|
+
def self.[](config) # :nodoc: unfinished API
|
70
|
+
if config.is_a?(Config) || config.nil? && global.nil?
|
71
|
+
config
|
72
|
+
else
|
73
|
+
raise TypeError, "no implicit conversion of %s to %s" % [
|
74
|
+
config.class, Config
|
75
|
+
]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
include AttrAccessors
|
80
|
+
include AttrInheritance
|
81
|
+
include AttrTypeCoercion
|
82
|
+
|
83
|
+
# The debug mode (boolean)
|
84
|
+
#
|
85
|
+
# The default value is +false+.
|
86
|
+
attr_accessor :debug, type: :boolean
|
87
|
+
|
88
|
+
# method: debug?
|
89
|
+
# :call-seq: debug? -> boolean
|
90
|
+
#
|
91
|
+
# Alias for #debug
|
92
|
+
|
93
|
+
# Seconds to wait until a connection is opened.
|
94
|
+
#
|
95
|
+
# If the IMAP object cannot open a connection within this time,
|
96
|
+
# it raises a Net::OpenTimeout exception.
|
97
|
+
#
|
98
|
+
# See Net::IMAP.new.
|
99
|
+
#
|
100
|
+
# The default value is +30+ seconds.
|
101
|
+
attr_accessor :open_timeout, type: Integer
|
102
|
+
|
103
|
+
# Seconds to wait until an IDLE response is received, after
|
104
|
+
# the client asks to leave the IDLE state.
|
105
|
+
#
|
106
|
+
# See Net::IMAP#idle and Net::IMAP#idle_done.
|
107
|
+
#
|
108
|
+
# The default value is +5+ seconds.
|
109
|
+
attr_accessor :idle_response_timeout, type: Integer
|
110
|
+
|
111
|
+
# :markup: markdown
|
112
|
+
#
|
113
|
+
# Whether to use the +SASL-IR+ extension when the server and \SASL
|
114
|
+
# mechanism both support it.
|
115
|
+
#
|
116
|
+
# See Net::IMAP#authenticate.
|
117
|
+
#
|
118
|
+
# | Starting with version | The default value is |
|
119
|
+
# |-----------------------|------------------------------------------|
|
120
|
+
# | _original_ | +false+ <em>(extension unsupported)</em> |
|
121
|
+
# | v0.4 | +true+ <em>(support added)</em> |
|
122
|
+
attr_accessor :sasl_ir, type: :boolean
|
123
|
+
|
124
|
+
# :markup: markdown
|
125
|
+
#
|
126
|
+
# Controls the behavior of Net::IMAP#responses when called without a
|
127
|
+
# block. Valid options are `:warn`, `:raise`, or
|
128
|
+
# `:silence_deprecation_warning`.
|
129
|
+
#
|
130
|
+
# | Starting with version | The default value is |
|
131
|
+
# |-------------------------|--------------------------------|
|
132
|
+
# | v0.4.13 | +:silence_deprecation_warning+ |
|
133
|
+
# | v0.5 <em>(planned)</em> | +:warn+ |
|
134
|
+
# | _eventually_ | +:raise+ |
|
135
|
+
attr_accessor :responses_without_block, type: [
|
136
|
+
:silence_deprecation_warning, :warn, :raise,
|
137
|
+
]
|
138
|
+
|
139
|
+
# Creates a new config object and initialize its attribute with +attrs+.
|
140
|
+
#
|
141
|
+
# If +parent+ is not given, the global config is used by default.
|
142
|
+
#
|
143
|
+
# If a block is given, the new config object is yielded to it.
|
144
|
+
def initialize(parent = Config.global, **attrs)
|
145
|
+
super(parent)
|
146
|
+
attrs.each do send(:"#{_1}=", _2) end
|
147
|
+
yield self if block_given?
|
148
|
+
end
|
149
|
+
|
150
|
+
@default = new(
|
151
|
+
debug: false,
|
152
|
+
open_timeout: 30,
|
153
|
+
idle_response_timeout: 5,
|
154
|
+
sasl_ir: true,
|
155
|
+
responses_without_block: :silence_deprecation_warning,
|
156
|
+
).freeze
|
157
|
+
|
158
|
+
@global = default.new
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -16,8 +16,8 @@ module Net
|
|
16
16
|
#
|
17
17
|
# ==== Obsolete arguments
|
18
18
|
#
|
19
|
-
#
|
20
|
-
# deprecated by a future release.
|
19
|
+
# Use of obsolete arguments does not print a warning. Obsolete arguments
|
20
|
+
# will be deprecated by a future release.
|
21
21
|
#
|
22
22
|
# If a second positional argument is given and it is a hash (or is
|
23
23
|
# convertible via +#to_hash+), it is converted to keyword arguments.
|
@@ -154,7 +154,7 @@ module Net
|
|
154
154
|
end
|
155
155
|
|
156
156
|
# To be used conditionally:
|
157
|
-
# assert_no_lookahead if
|
157
|
+
# assert_no_lookahead if config.debug?
|
158
158
|
def assert_no_lookahead
|
159
159
|
@token.nil? or
|
160
160
|
parse_error("assertion failed: expected @token.nil?, actual %s: %p",
|
@@ -181,23 +181,23 @@ module Net
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def peek_str?(str)
|
184
|
-
assert_no_lookahead if
|
184
|
+
assert_no_lookahead if config.debug?
|
185
185
|
@str[@pos, str.length] == str
|
186
186
|
end
|
187
187
|
|
188
188
|
def peek_re(re)
|
189
|
-
assert_no_lookahead if
|
189
|
+
assert_no_lookahead if config.debug?
|
190
190
|
re.match(@str, @pos)
|
191
191
|
end
|
192
192
|
|
193
193
|
def accept_re(re)
|
194
|
-
assert_no_lookahead if
|
194
|
+
assert_no_lookahead if config.debug?
|
195
195
|
re.match(@str, @pos) and @pos = $~.end(0)
|
196
196
|
$~
|
197
197
|
end
|
198
198
|
|
199
199
|
def match_re(re, name)
|
200
|
-
assert_no_lookahead if
|
200
|
+
assert_no_lookahead if config.debug?
|
201
201
|
if re.match(@str, @pos)
|
202
202
|
@pos = $~.end(0)
|
203
203
|
$~
|
@@ -212,7 +212,7 @@ module Net
|
|
212
212
|
|
213
213
|
def parse_error(fmt, *args)
|
214
214
|
msg = format(fmt, *args)
|
215
|
-
if
|
215
|
+
if config.debug?
|
216
216
|
local_path = File.dirname(__dir__)
|
217
217
|
tok = @token ? "%s: %p" % [@token.symbol, @token.value] : "nil"
|
218
218
|
warn "%s %s: %s" % [self.class, __method__, msg]
|
@@ -11,12 +11,15 @@ module Net
|
|
11
11
|
include ParserUtils
|
12
12
|
extend ParserUtils::Generator
|
13
13
|
|
14
|
+
attr_reader :config
|
15
|
+
|
14
16
|
# :call-seq: Net::IMAP::ResponseParser.new -> Net::IMAP::ResponseParser
|
15
|
-
def initialize
|
17
|
+
def initialize(config: Config.global)
|
16
18
|
@str = nil
|
17
19
|
@pos = nil
|
18
20
|
@lex_state = nil
|
19
21
|
@token = nil
|
22
|
+
@config = Config[config]
|
20
23
|
end
|
21
24
|
|
22
25
|
# :call-seq:
|
data/lib/net/imap.rb
CHANGED
@@ -717,7 +717,7 @@ module Net
|
|
717
717
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
718
718
|
#
|
719
719
|
class IMAP < Protocol
|
720
|
-
VERSION = "0.4.
|
720
|
+
VERSION = "0.4.13"
|
721
721
|
|
722
722
|
# Aliases for supported capabilities, to be used with the #enable command.
|
723
723
|
ENABLE_ALIASES = {
|
@@ -735,14 +735,15 @@ module Net
|
|
735
735
|
include SSL
|
736
736
|
end
|
737
737
|
|
738
|
-
# Returns the
|
739
|
-
def self.
|
740
|
-
|
741
|
-
|
738
|
+
# Returns the global Config object
|
739
|
+
def self.config; Config.global end
|
740
|
+
|
741
|
+
# Returns the global debug mode.
|
742
|
+
def self.debug; config.debug end
|
742
743
|
|
743
|
-
# Sets the debug mode.
|
744
|
+
# Sets the global debug mode.
|
744
745
|
def self.debug=(val)
|
745
|
-
|
746
|
+
config.debug = val
|
746
747
|
end
|
747
748
|
|
748
749
|
# The default port for IMAP connections, port 143
|
@@ -764,13 +765,19 @@ module Net
|
|
764
765
|
# Returns the initial greeting the server, an UntaggedResponse.
|
765
766
|
attr_reader :greeting
|
766
767
|
|
768
|
+
# The client configuration. See Net::IMAP::Config.
|
769
|
+
#
|
770
|
+
# By default, the client's local configuration inherits from the global
|
771
|
+
# Net::IMAP.config.
|
772
|
+
attr_reader :config
|
773
|
+
|
767
774
|
# Seconds to wait until a connection is opened.
|
768
775
|
# If the IMAP object cannot open a connection within this time,
|
769
776
|
# it raises a Net::OpenTimeout exception. The default value is 30 seconds.
|
770
|
-
|
777
|
+
def open_timeout; config.open_timeout end
|
771
778
|
|
772
779
|
# Seconds to wait until an IDLE response is received.
|
773
|
-
|
780
|
+
def idle_response_timeout; config.idle_response_timeout end
|
774
781
|
|
775
782
|
# The hostname this client connected to
|
776
783
|
attr_reader :host
|
@@ -809,14 +816,40 @@ module Net
|
|
809
816
|
# If +ssl+ is a hash, it's passed to
|
810
817
|
# {OpenSSL::SSL::SSLContext#set_params}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-set_params];
|
811
818
|
# the keys are names of attribute assignment methods on
|
812
|
-
# SSLContext[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html].
|
819
|
+
# SSLContext[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html]. For example:
|
820
|
+
#
|
821
|
+
# [{ca_file}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#attribute-i-ca_file]]
|
822
|
+
# The path to a file containing a PEM-format CA certificate.
|
823
|
+
# [{ca_path}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#attribute-i-ca_path]]
|
824
|
+
# The path to a directory containing CA certificates in PEM format.
|
825
|
+
# [{min_version}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D]]
|
826
|
+
# Sets the lower bound on the supported SSL/TLS protocol version. Set to
|
827
|
+
# an +OpenSSL+ constant such as +OpenSSL::SSL::TLS1_2_VERSION+,
|
828
|
+
# [{verify_mode}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#attribute-i-verify_mode]]
|
829
|
+
# SSL session verification mode. Valid modes include
|
830
|
+
# +OpenSSL::SSL::VERIFY_PEER+ and +OpenSSL::SSL::VERIFY_NONE+.
|
831
|
+
#
|
832
|
+
# See {OpenSSL::SSL::SSLContext}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html] for other valid SSL context params.
|
833
|
+
#
|
834
|
+
# See DeprecatedClientOptions.new for deprecated SSL arguments.
|
813
835
|
#
|
814
|
-
# [
|
815
|
-
#
|
816
|
-
#
|
817
|
-
# Seconds to wait until an IDLE response is received
|
836
|
+
# [config]
|
837
|
+
# A Net::IMAP::Config object to use as the basis for #config. By default,
|
838
|
+
# the global Net::IMAP.config is used.
|
818
839
|
#
|
819
|
-
#
|
840
|
+
# >>>
|
841
|
+
# *NOTE:* +config+ does not set #config directly---it sets the _parent_
|
842
|
+
# config for inheritance. Every client creates its own unique #config.
|
843
|
+
#
|
844
|
+
# All other keyword arguments are forwarded to Net::IMAP::Config.new, to
|
845
|
+
# initialize the client's #config. For example:
|
846
|
+
#
|
847
|
+
# [{open_timeout}[rdoc-ref:Config#open_timeout]]
|
848
|
+
# Seconds to wait until a connection is opened
|
849
|
+
# [{idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]]
|
850
|
+
# Seconds to wait until an IDLE response is received
|
851
|
+
#
|
852
|
+
# See Net::IMAP::Config for other valid options.
|
820
853
|
#
|
821
854
|
# ==== Examples
|
822
855
|
#
|
@@ -872,13 +905,12 @@ module Net
|
|
872
905
|
# Connected to the host successfully, but it immediately said goodbye.
|
873
906
|
#
|
874
907
|
def initialize(host, port: nil, ssl: nil,
|
875
|
-
|
908
|
+
config: Config.global, **config_options)
|
876
909
|
super()
|
877
910
|
# Config options
|
878
911
|
@host = host
|
912
|
+
@config = Config.new(config, **config_options)
|
879
913
|
@port = port || (ssl ? SSL_PORT : PORT)
|
880
|
-
@open_timeout = Integer(open_timeout)
|
881
|
-
@idle_response_timeout = Integer(idle_response_timeout)
|
882
914
|
@ssl_ctx_params, @ssl_ctx = build_ssl_ctx(ssl)
|
883
915
|
|
884
916
|
# Basic Client State
|
@@ -889,7 +921,7 @@ module Net
|
|
889
921
|
@capabilities = nil
|
890
922
|
|
891
923
|
# Client Protocol Receiver
|
892
|
-
@parser = ResponseParser.new
|
924
|
+
@parser = ResponseParser.new(config: @config)
|
893
925
|
@responses = Hash.new {|h, k| h[k] = [] }
|
894
926
|
@response_handlers = []
|
895
927
|
@receiver_thread = nil
|
@@ -1198,7 +1230,7 @@ module Net
|
|
1198
1230
|
end
|
1199
1231
|
|
1200
1232
|
# :call-seq:
|
1201
|
-
# authenticate(mechanism, *, sasl_ir:
|
1233
|
+
# authenticate(mechanism, *, sasl_ir: config.sasl_ir, registry: Net::IMAP::SASL.authenticators, **, &) -> ok_resp
|
1202
1234
|
#
|
1203
1235
|
# Sends an {AUTHENTICATE command [IMAP4rev1 §6.2.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.2]
|
1204
1236
|
# to authenticate the client. If successful, the connection enters the
|
@@ -1207,7 +1239,8 @@ module Net
|
|
1207
1239
|
# +mechanism+ is the name of the \SASL authentication mechanism to be used.
|
1208
1240
|
#
|
1209
1241
|
# +sasl_ir+ allows or disallows sending an "initial response" (see the
|
1210
|
-
# +SASL-IR+ capability, below).
|
1242
|
+
# +SASL-IR+ capability, below). Defaults to the #config value for
|
1243
|
+
# {sasl_ir}[rdoc-ref:Config#sasl_ir], which defaults to +true+.
|
1211
1244
|
#
|
1212
1245
|
# All other arguments are forwarded to the registered SASL authenticator for
|
1213
1246
|
# the requested mechanism. <em>The documentation for each individual
|
@@ -1303,7 +1336,9 @@ module Net
|
|
1303
1336
|
# Previously cached #capabilities will be cleared when this method
|
1304
1337
|
# completes. If the TaggedResponse to #authenticate includes updated
|
1305
1338
|
# capabilities, they will be cached.
|
1306
|
-
def authenticate(mechanism, *creds,
|
1339
|
+
def authenticate(mechanism, *creds,
|
1340
|
+
sasl_ir: config.sasl_ir,
|
1341
|
+
**props, &callback)
|
1307
1342
|
mechanism = mechanism.to_s.tr("_", "-").upcase
|
1308
1343
|
authenticator = SASL.authenticator(mechanism, *creds, **props, &callback)
|
1309
1344
|
cmdargs = ["AUTHENTICATE", mechanism]
|
@@ -2397,11 +2432,17 @@ module Net
|
|
2397
2432
|
# checks the connection for each 60 seconds.
|
2398
2433
|
#
|
2399
2434
|
# loop do
|
2400
|
-
# imap.idle(60) do |
|
2401
|
-
#
|
2435
|
+
# imap.idle(60) do |response|
|
2436
|
+
# do_something_with(response)
|
2437
|
+
# imap.idle_done if some_condition?(response)
|
2402
2438
|
# end
|
2403
2439
|
# end
|
2404
2440
|
#
|
2441
|
+
# Returns the server's response to indicate the IDLE state has ended.
|
2442
|
+
# Returns +nil+ if the server does not respond to #idle_done within
|
2443
|
+
# {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]
|
2444
|
+
# seconds.
|
2445
|
+
#
|
2405
2446
|
# Related: #idle_done, #noop, #check
|
2406
2447
|
#
|
2407
2448
|
# ===== Capabilities
|
@@ -2429,7 +2470,7 @@ module Net
|
|
2429
2470
|
unless @receiver_thread_terminating
|
2430
2471
|
remove_response_handler(response_handler)
|
2431
2472
|
put_string("DONE#{CRLF}")
|
2432
|
-
response = get_tagged_response(tag, "IDLE",
|
2473
|
+
response = get_tagged_response(tag, "IDLE", idle_response_timeout)
|
2433
2474
|
end
|
2434
2475
|
end
|
2435
2476
|
end
|
@@ -2437,7 +2478,11 @@ module Net
|
|
2437
2478
|
return response
|
2438
2479
|
end
|
2439
2480
|
|
2440
|
-
# Leaves IDLE.
|
2481
|
+
# Leaves IDLE, allowing #idle to return.
|
2482
|
+
#
|
2483
|
+
# If the server does not respond within
|
2484
|
+
# {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout]
|
2485
|
+
# seconds, #idle will return +nil+.
|
2441
2486
|
#
|
2442
2487
|
# Related: #idle
|
2443
2488
|
def idle_done
|
@@ -2477,6 +2522,7 @@ module Net
|
|
2477
2522
|
#
|
2478
2523
|
# Calling without a block is unsafe and deprecated. Future releases will
|
2479
2524
|
# raise ArgumentError unless a block is given.
|
2525
|
+
# See Config#responses_without_block.
|
2480
2526
|
#
|
2481
2527
|
# Previously unhandled responses are automatically cleared before entering a
|
2482
2528
|
# mailbox with #select or #examine. Long-lived connections can receive many
|
@@ -2501,7 +2547,12 @@ module Net
|
|
2501
2547
|
elsif type
|
2502
2548
|
raise ArgumentError, "Pass a block or use #clear_responses"
|
2503
2549
|
else
|
2504
|
-
|
2550
|
+
case config.responses_without_block
|
2551
|
+
when :raise
|
2552
|
+
raise ArgumentError, "Pass a block or use #clear_responses"
|
2553
|
+
when :warn
|
2554
|
+
warn("DEPRECATED: pass a block or use #clear_responses", uplevel: 1)
|
2555
|
+
end
|
2505
2556
|
@responses
|
2506
2557
|
end
|
2507
2558
|
end
|
@@ -2582,8 +2633,6 @@ module Net
|
|
2582
2633
|
PORT = 143 # :nodoc:
|
2583
2634
|
SSL_PORT = 993 # :nodoc:
|
2584
2635
|
|
2585
|
-
@@debug = false
|
2586
|
-
|
2587
2636
|
def start_imap_connection
|
2588
2637
|
@greeting = get_server_greeting
|
2589
2638
|
@capabilities = capabilities_from_resp_code @greeting
|
@@ -2611,12 +2660,12 @@ module Net
|
|
2611
2660
|
end
|
2612
2661
|
|
2613
2662
|
def tcp_socket(host, port)
|
2614
|
-
s = Socket.tcp(host, port, :connect_timeout =>
|
2663
|
+
s = Socket.tcp(host, port, :connect_timeout => open_timeout)
|
2615
2664
|
s.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, true)
|
2616
2665
|
s
|
2617
2666
|
rescue Errno::ETIMEDOUT
|
2618
2667
|
raise Net::OpenTimeout, "Timeout to open TCP connection to " +
|
2619
|
-
"#{host}:#{port} (exceeds #{
|
2668
|
+
"#{host}:#{port} (exceeds #{open_timeout} seconds)"
|
2620
2669
|
end
|
2621
2670
|
|
2622
2671
|
def receive_responses
|
@@ -2728,7 +2777,7 @@ module Net
|
|
2728
2777
|
end
|
2729
2778
|
end
|
2730
2779
|
return nil if buff.length == 0
|
2731
|
-
if
|
2780
|
+
if config.debug?
|
2732
2781
|
$stderr.print(buff.gsub(/^/n, "S: "))
|
2733
2782
|
end
|
2734
2783
|
return @parser.parse(buff)
|
@@ -2807,7 +2856,7 @@ module Net
|
|
2807
2856
|
|
2808
2857
|
def put_string(str)
|
2809
2858
|
@sock.print(str)
|
2810
|
-
if
|
2859
|
+
if config.debug?
|
2811
2860
|
if @debug_output_bol
|
2812
2861
|
$stderr.print("C: ")
|
2813
2862
|
end
|
@@ -2934,7 +2983,7 @@ module Net
|
|
2934
2983
|
@sock = SSLSocket.new(@sock, ssl_ctx)
|
2935
2984
|
@sock.sync_close = true
|
2936
2985
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
2937
|
-
ssl_socket_connect(@sock,
|
2986
|
+
ssl_socket_connect(@sock, open_timeout)
|
2938
2987
|
if ssl_ctx.verify_mode != VERIFY_NONE
|
2939
2988
|
@sock.post_connection_check(@host)
|
2940
2989
|
@tls_verified = true
|
@@ -2959,6 +3008,7 @@ module Net
|
|
2959
3008
|
end
|
2960
3009
|
|
2961
3010
|
require_relative "imap/errors"
|
3011
|
+
require_relative "imap/config"
|
2962
3012
|
require_relative "imap/command_data"
|
2963
3013
|
require_relative "imap/data_encoding"
|
2964
3014
|
require_relative "imap/flags"
|
data/net-imap.gemspec
CHANGED
@@ -25,9 +25,9 @@ Gem::Specification.new do |spec|
|
|
25
25
|
|
26
26
|
# Specify which files should be added to the gem when it is released.
|
27
27
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
28
|
-
spec.files = Dir.chdir(
|
28
|
+
spec.files = Dir.chdir(__dir__) do
|
29
29
|
`git ls-files -z 2>/dev/null`.split("\x0")
|
30
|
-
.grep_v(%r{^(\.git
|
30
|
+
.grep_v(%r{^(\.git(ignore)?|\.mailmap|(\.github|bin|test|spec|benchmarks|features|rfcs)/)})
|
31
31
|
end
|
32
32
|
spec.bindir = "exe"
|
33
33
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-imap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
- nicholas a. evans
|
9
|
+
autorequire:
|
9
10
|
bindir: exe
|
10
11
|
cert_chain: []
|
11
|
-
date: 2024-06-
|
12
|
+
date: 2024-06-16 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: net-protocol
|
@@ -46,12 +47,6 @@ executables: []
|
|
46
47
|
extensions: []
|
47
48
|
extra_rdoc_files: []
|
48
49
|
files:
|
49
|
-
- ".github/dependabot.yml"
|
50
|
-
- ".github/workflows/pages.yml"
|
51
|
-
- ".github/workflows/push_gem.yml"
|
52
|
-
- ".github/workflows/test.yml"
|
53
|
-
- ".gitignore"
|
54
|
-
- ".mailmap"
|
55
50
|
- BSDL
|
56
51
|
- COPYING
|
57
52
|
- Gemfile
|
@@ -62,6 +57,10 @@ files:
|
|
62
57
|
- lib/net/imap.rb
|
63
58
|
- lib/net/imap/authenticators.rb
|
64
59
|
- lib/net/imap/command_data.rb
|
60
|
+
- lib/net/imap/config.rb
|
61
|
+
- lib/net/imap/config/attr_accessors.rb
|
62
|
+
- lib/net/imap/config/attr_inheritance.rb
|
63
|
+
- lib/net/imap/config/attr_type_coercion.rb
|
65
64
|
- lib/net/imap/data_encoding.rb
|
66
65
|
- lib/net/imap/deprecated_client_options.rb
|
67
66
|
- lib/net/imap/errors.rb
|
@@ -111,6 +110,7 @@ metadata:
|
|
111
110
|
homepage_uri: https://github.com/ruby/net-imap
|
112
111
|
source_code_uri: https://github.com/ruby/net-imap
|
113
112
|
changelog_uri: https://github.com/ruby/net-imap/releases
|
113
|
+
post_install_message:
|
114
114
|
rdoc_options: []
|
115
115
|
require_paths:
|
116
116
|
- lib
|
@@ -125,7 +125,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
127
|
requirements: []
|
128
|
-
rubygems_version: 3.
|
128
|
+
rubygems_version: 3.5.9
|
129
|
+
signing_key:
|
129
130
|
specification_version: 4
|
130
131
|
summary: Ruby client api for Internet Message Access Protocol
|
131
132
|
test_files: []
|
data/.github/dependabot.yml
DELETED
data/.github/workflows/pages.yml
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
name: Deploy RDoc site to Pages
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [ 'master' ]
|
6
|
-
workflow_dispatch:
|
7
|
-
|
8
|
-
permissions:
|
9
|
-
contents: read
|
10
|
-
pages: write
|
11
|
-
id-token: write
|
12
|
-
|
13
|
-
concurrency:
|
14
|
-
group: "pages"
|
15
|
-
cancel-in-progress: true
|
16
|
-
|
17
|
-
jobs:
|
18
|
-
build:
|
19
|
-
runs-on: ubuntu-latest
|
20
|
-
steps:
|
21
|
-
- name: Checkout
|
22
|
-
uses: actions/checkout@v4
|
23
|
-
- name: Setup Ruby
|
24
|
-
uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
|
25
|
-
with:
|
26
|
-
ruby-version: '3.2'
|
27
|
-
bundler-cache: true
|
28
|
-
- name: Setup Pages
|
29
|
-
id: pages
|
30
|
-
uses: actions/configure-pages@v5
|
31
|
-
- name: Build with RDoc
|
32
|
-
run: bundle exec rake rdoc
|
33
|
-
- name: Upload artifact
|
34
|
-
uses: actions/upload-pages-artifact@v3
|
35
|
-
with: { path: 'doc' }
|
36
|
-
|
37
|
-
deploy:
|
38
|
-
environment:
|
39
|
-
name: github-pages
|
40
|
-
url: ${{ steps.deployment.outputs.page_url }}
|
41
|
-
runs-on: ubuntu-latest
|
42
|
-
needs: build
|
43
|
-
steps:
|
44
|
-
- name: Deploy to GitHub Pages
|
45
|
-
id: deployment
|
46
|
-
uses: actions/deploy-pages@v4
|
@@ -1,48 +0,0 @@
|
|
1
|
-
name: Publish gem to rubygems.org
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
tags:
|
6
|
-
- 'v*'
|
7
|
-
|
8
|
-
permissions:
|
9
|
-
contents: read
|
10
|
-
|
11
|
-
jobs:
|
12
|
-
push:
|
13
|
-
if: github.repository == 'ruby/net-imap'
|
14
|
-
runs-on: ubuntu-latest
|
15
|
-
|
16
|
-
environment:
|
17
|
-
name: rubygems.org
|
18
|
-
url: https://rubygems.org/gems/net-imap
|
19
|
-
|
20
|
-
permissions:
|
21
|
-
contents: write
|
22
|
-
id-token: write
|
23
|
-
|
24
|
-
steps:
|
25
|
-
# Set up
|
26
|
-
- name: Harden Runner
|
27
|
-
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
28
|
-
with:
|
29
|
-
egress-policy: audit
|
30
|
-
|
31
|
-
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
32
|
-
|
33
|
-
- name: Set up Ruby
|
34
|
-
uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
|
35
|
-
with:
|
36
|
-
bundler-cache: true
|
37
|
-
ruby-version: ruby
|
38
|
-
|
39
|
-
# Release
|
40
|
-
- name: Publish to RubyGems
|
41
|
-
uses: rubygems/release-gem@612653d273a73bdae1df8453e090060bb4db5f31 # v1
|
42
|
-
|
43
|
-
- name: Create GitHub release
|
44
|
-
run: |
|
45
|
-
tag_name="$(git describe --tags --abbrev=0)"
|
46
|
-
gh release create "${tag_name}" --verify-tag --draft --generate-notes
|
47
|
-
env:
|
48
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
data/.github/workflows/test.yml
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
name: Run tests
|
2
|
-
|
3
|
-
on: [push, pull_request]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
ruby-versions:
|
7
|
-
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
8
|
-
with:
|
9
|
-
engine: cruby
|
10
|
-
min_version: 2.7
|
11
|
-
|
12
|
-
build:
|
13
|
-
needs: ruby-versions
|
14
|
-
name: build (${{ matrix.ruby }} / ${{ matrix.os }})
|
15
|
-
strategy:
|
16
|
-
matrix:
|
17
|
-
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
18
|
-
os: [ ubuntu-latest, macos-latest ]
|
19
|
-
experimental: [false]
|
20
|
-
runs-on: ${{ matrix.os }}
|
21
|
-
continue-on-error: ${{ matrix.experimental }}
|
22
|
-
steps:
|
23
|
-
- uses: actions/checkout@v4
|
24
|
-
- name: Set up Ruby
|
25
|
-
uses: ruby/setup-ruby@v1
|
26
|
-
with:
|
27
|
-
ruby-version: ${{ matrix.ruby }}
|
28
|
-
bundler-cache: true
|
29
|
-
rubygems: 3.4.22
|
30
|
-
- name: Run test
|
31
|
-
run: bundle exec rake test
|
data/.gitignore
DELETED
data/.mailmap
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
nicholas a. evans <nick@rubinick.dev>
|
2
|
-
nicholas a. evans <nick@rubinick.dev> <nick@410labs.com>
|
3
|
-
nicholas a. evans <nick@rubinick.dev> <nick@ekenosen.net>
|
4
|
-
nicholas a. evans <nick@rubinick.dev> <nicholas.evans@gmail.com>
|
5
|
-
|
6
|
-
Shugo Maeda <shugo@ruby-lang.org>
|
7
|
-
Shugo Maeda <shugo@ruby-lang.org> <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
|
8
|
-
|
9
|
-
Nobuyoshi Nakada <nobu@ruby-lang.org>
|
10
|
-
Nobuyoshi Nakada <nobu@ruby-lang.org> <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
|
11
|
-
|
12
|
-
Hiroshi SHIBATA <hsbt@ruby-lang.org>
|
13
|
-
Hiroshi SHIBATA <hsbt@ruby-lang.org> <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
|