net-imap 0.4.12 → 0.4.13
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/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>
|