net-imap 0.6.6 → 0.6.7
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/.simplecov +3 -2
- data/Gemfile +2 -2
- data/README.md +50 -24
- data/Rakefile +51 -4
- data/lib/net/imap/command_data.rb +13 -10
- data/lib/net/imap/config/attr_accessors.rb +2 -2
- data/lib/net/imap/config.rb +63 -3
- data/lib/net/imap/esearch_result.rb +2 -2
- data/lib/net/imap/fetch_data.rb +5 -5
- data/lib/net/imap/response_data.rb +79 -79
- data/lib/net/imap/response_parser.rb +2 -1
- data/lib/net/imap/sasl/client_adapter.rb +6 -6
- data/lib/net/imap/search_result.rb +4 -6
- data/lib/net/imap/sequence_set.rb +251 -8
- data/lib/net/imap.rb +194 -45
- data/rakelib/rdoc.rake +24 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5300636497a02d1c8bc10b528bf1d3fe8aad9898ba02ba3ab40f2329f9306baf
|
|
4
|
+
data.tar.gz: 449230117bc3289dc13cb1531d95a2ae530558a21a405d8f4effb958773da88d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b034f4ab8fc449890b3eb29c2049c4af1ed5aac42e8943f0a5eb20d4f9eae910740e0c8d590590f3379121c30ac347ce49f5387dcd4985e2dd551292545bd2de
|
|
7
|
+
data.tar.gz: 996ab44d2c1f4bf6d5d2e3d141b1890d25a38cddf1e0032726257c63346fc7175bcdd05f3ed97cce3a3ce63d8939154c4d9c4b9e931b035a46d9c4fa1a518450
|
data/.simplecov
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
SimpleCov.configure do
|
|
4
|
-
formatter SimpleCov::Formatter::HTMLFormatter
|
|
5
|
-
|
|
6
4
|
enable_coverage :branch
|
|
7
5
|
enable_coverage :method
|
|
8
6
|
enable_coverage :eval
|
|
9
7
|
|
|
8
|
+
# eval branch coverage varies too much between runtime environments
|
|
9
|
+
ignore_branches :eval_generated
|
|
10
|
+
|
|
10
11
|
skip "/test/"
|
|
11
12
|
skip "/rakelib/"
|
|
12
13
|
cover "lib/**/*.rb"
|
data/Gemfile
CHANGED
|
@@ -13,10 +13,10 @@ gem "irb"
|
|
|
13
13
|
gem "rake"
|
|
14
14
|
gem "rdoc", ">= 7.2.0"
|
|
15
15
|
gem "test-unit"
|
|
16
|
-
gem "test-unit-ruby-core"
|
|
16
|
+
gem "test-unit-ruby-core"
|
|
17
17
|
|
|
18
18
|
gem "benchmark", require: false
|
|
19
|
-
gem "
|
|
19
|
+
gem "benchmark_driver", require: false
|
|
20
20
|
gem "vernier", require: false, platform: :mri
|
|
21
21
|
|
|
22
22
|
group :test do
|
data/README.md
CHANGED
|
@@ -26,41 +26,61 @@ Or install it yourself as:
|
|
|
26
26
|
### Connect with TLS to port 993
|
|
27
27
|
|
|
28
28
|
```ruby
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
hostname = "mail.example.com"
|
|
30
|
+
username = "user@example.com"
|
|
31
|
+
password = "correct-horse-battery-staple"
|
|
32
|
+
|
|
33
|
+
imap = Net::IMAP.new(hostname, ssl: true)
|
|
34
|
+
imap.authenticate(:plain, username, password)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
To authenticate with an OAuth2 access token:
|
|
38
|
+
```ruby
|
|
39
|
+
if imap.auth_capable?(:OAUTHBEARER)
|
|
40
|
+
imap.authenticate(:OAUTHBEARER, username, oauth2_token)
|
|
41
|
+
elsif imap.auth_capable?(:XOAUTH2)
|
|
42
|
+
imap.authenticate(:XOAUTH2, username, oauth2_token)
|
|
43
|
+
else
|
|
44
|
+
raise "OAuth2 not supported?"
|
|
38
45
|
end
|
|
39
46
|
```
|
|
40
47
|
|
|
41
|
-
### List sender and subject of
|
|
48
|
+
### List sender and subject of recent messages
|
|
42
49
|
|
|
43
50
|
```ruby
|
|
44
51
|
imap.examine('INBOX')
|
|
45
|
-
imap.
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
search_result = imap.uid_search(["SINCE", Date.today - 7])
|
|
53
|
+
imap.uid_fetch(search_result, "ENVELOPE").each do |fetch_data|
|
|
54
|
+
envelope = fetch_data.envelope
|
|
55
|
+
puts "#{envelope.from.first.name}: \t#{envelope.subject}"
|
|
48
56
|
end
|
|
49
57
|
```
|
|
50
58
|
|
|
51
|
-
### Move
|
|
59
|
+
### Move messages between two dates to another mailbox
|
|
52
60
|
|
|
53
61
|
```ruby
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
source = "Mail/sent-mail"
|
|
63
|
+
destination = "Mail/sent-apr03"
|
|
64
|
+
|
|
65
|
+
# The "BEFORE" and "AFTER" search criteria are not inclusive.
|
|
66
|
+
since = Date.parse("2003-04-01").prev_day
|
|
67
|
+
before = Date.parse("2003-05-01")
|
|
68
|
+
|
|
69
|
+
if imap.list("", destination).empty?
|
|
70
|
+
imap.create(destination)
|
|
57
71
|
end
|
|
58
|
-
imap.
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
imap.select(source)
|
|
73
|
+
search_result = imap.uid_search(["SINCE", since, "BEFORE", before])
|
|
74
|
+
if imap.capable?(:MOVE) || imap.capable?(:IMAP4rev2)
|
|
75
|
+
imap.uid_move(search_result, destination)
|
|
76
|
+
else
|
|
77
|
+
# Atomic MOVE is not supported. Copy, delete, and expunge.
|
|
78
|
+
imap.uid_copy(search_result, destination)
|
|
79
|
+
imap.uid_store(search_result, "+FLAGS", [:Deleted])
|
|
80
|
+
if imap.capable?(:UIDPLUS) || imap.capable?(:IMAP4rev2)
|
|
81
|
+
imap.uid_expunge(search_result)
|
|
61
82
|
else
|
|
62
|
-
|
|
63
|
-
imap.store(message_id, "+FLAGS", [:Deleted])
|
|
83
|
+
# NOTE: This may expunge _other_ deleted messages, too.
|
|
64
84
|
imap.expunge
|
|
65
85
|
end
|
|
66
86
|
end
|
|
@@ -68,9 +88,15 @@ end
|
|
|
68
88
|
|
|
69
89
|
## Development
|
|
70
90
|
|
|
71
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
91
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
92
|
+
`bin/test` to run the tests. You can also run `bin/console` for an interactive
|
|
93
|
+
prompt that will allow you to experiment.
|
|
72
94
|
|
|
73
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
95
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
96
|
+
release a new version, update the version number in `version.rb`, and then run
|
|
97
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
|
98
|
+
git commits and tags, and push the `.gem` file to
|
|
99
|
+
[rubygems.org](https://rubygems.org).
|
|
74
100
|
|
|
75
101
|
## Contributing
|
|
76
102
|
|
data/Rakefile
CHANGED
|
@@ -12,13 +12,60 @@ end
|
|
|
12
12
|
|
|
13
13
|
task :default => :test
|
|
14
14
|
|
|
15
|
-
desc "Output coverage data report, and error when threshholds aren't met"
|
|
16
|
-
task "coverage:report" do
|
|
15
|
+
desc "Output HTML coverage data report, and error when threshholds aren't met"
|
|
16
|
+
task "test:coverage:report" do
|
|
17
17
|
require "simplecov"
|
|
18
|
+
|
|
18
19
|
SimpleCov.collate "coverage/.resultset.json" do
|
|
20
|
+
formatter SimpleCov::Formatter::HTMLFormatter
|
|
21
|
+
|
|
19
22
|
coverage(:line) do
|
|
20
|
-
minimum
|
|
21
|
-
|
|
23
|
+
minimum 95
|
|
24
|
+
|
|
25
|
+
minimum_per_group 98, only: "Config"
|
|
26
|
+
minimum_per_group 97, only: "StringPrep"
|
|
27
|
+
minimum_per_group 97, only: "SASL"
|
|
28
|
+
minimum_per_group 95, only: "Data Types"
|
|
29
|
+
minimum_per_group 94, only: "Parser"
|
|
30
|
+
minimum_per_group 92, only: "Client"
|
|
31
|
+
|
|
32
|
+
minimum_per_file 80
|
|
33
|
+
minimum_per_file 55, only: "lib/net/imap/search_result.rb"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# NOTE: branch coverage varies more widely between ruby versions
|
|
37
|
+
coverage(:branch) do
|
|
38
|
+
minimum 80
|
|
39
|
+
|
|
40
|
+
minimum_per_group 90, only: "Data Types"
|
|
41
|
+
minimum_per_group 85, only: "Config"
|
|
42
|
+
minimum_per_group 80, only: "Client"
|
|
43
|
+
minimum_per_group 80, only: "Parser"
|
|
44
|
+
minimum_per_group 70, only: "SASL"
|
|
45
|
+
minimum_per_group 70, only: "StringPrep"
|
|
46
|
+
|
|
47
|
+
minimum_per_file 60
|
|
48
|
+
minimum_per_file 50, only: "lib/net/imap/sasl/authenticators.rb"
|
|
49
|
+
minimum_per_file 50, only: "lib/net/imap/config/attr_accessors.rb"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
coverage(:method) do
|
|
53
|
+
minimum 88
|
|
54
|
+
|
|
55
|
+
minimum_per_group 100, only: "Config"
|
|
56
|
+
minimum_per_group 90, only: "Data Types"
|
|
57
|
+
minimum_per_group 90, only: "StringPrep"
|
|
58
|
+
minimum_per_group 85, only: "Client"
|
|
59
|
+
minimum_per_group 80, only: "Parser"
|
|
60
|
+
minimum_per_group 80, only: "SASL"
|
|
61
|
+
|
|
62
|
+
minimum_per_file 65
|
|
63
|
+
minimum_per_file 60, only: "lib/net/imap/response_parser/parser_utils.rb"
|
|
64
|
+
minimum_per_file 55, only: "lib/net/imap/sasl/authenticators.rb"
|
|
65
|
+
minimum_per_file 50, only: "lib/net/imap/authenticators.rb"
|
|
66
|
+
minimum_per_file 50, only: "lib/net/imap/sasl/anonymous_authenticator.rb"
|
|
67
|
+
minimum_per_file 35, only: "lib/net/imap/sasl/protocol_adapters.rb"
|
|
68
|
+
minimum_per_file 20, only: "lib/net/imap/response_data.rb"
|
|
22
69
|
end
|
|
23
70
|
end
|
|
24
71
|
end
|
|
@@ -265,23 +265,26 @@ module Net
|
|
|
265
265
|
def self.split(data)
|
|
266
266
|
data = data.b # dups and ensures BINARY encoding
|
|
267
267
|
parts = []
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
text_start = 0
|
|
269
|
+
while data.match(/(~)?\{(0|[1-9]\d*)(\+)?\}\r\n/n, text_start)
|
|
270
|
+
text, binary, bytesize, non_sync, literal_start =
|
|
271
|
+
data.byteslice(text_start...$~.begin(0)), !!$1, $2, !!$3, $~.end(0)
|
|
270
272
|
bytesize = NumValidator.coerce_number64 bytesize
|
|
273
|
+
text_start = literal_start + bytesize
|
|
271
274
|
parts << RawText[text] unless text.empty?
|
|
272
|
-
parts << extract_literal(data,
|
|
273
|
-
data.bytesplice(0, bytesize, "")
|
|
275
|
+
parts << extract_literal(data, literal_start, bytesize, binary:, non_sync:)
|
|
274
276
|
end
|
|
275
|
-
parts << RawText[data]
|
|
277
|
+
parts << RawText[data.byteslice(text_start..)] if text_start < data.bytesize
|
|
276
278
|
parts
|
|
277
279
|
end
|
|
278
280
|
|
|
279
|
-
def self.extract_literal(data,
|
|
280
|
-
|
|
281
|
+
def self.extract_literal(data, offset, bytesize, binary:, non_sync:)
|
|
282
|
+
remaining = data.bytesize - offset
|
|
283
|
+
if remaining < bytesize
|
|
281
284
|
raise DataFormatError, "Too few bytes in string for literal, " \
|
|
282
|
-
"expected: %s, remaining: %s" % [bytesize,
|
|
285
|
+
"expected: %s, remaining: %s" % [bytesize, remaining]
|
|
283
286
|
end
|
|
284
|
-
literal = data.byteslice(
|
|
287
|
+
literal = data.byteslice(offset, bytesize)
|
|
285
288
|
(binary ? Literal8 : Literal).new(data: literal, non_sync:)
|
|
286
289
|
end
|
|
287
290
|
private_class_method :extract_literal
|
|
@@ -459,7 +462,7 @@ module Net
|
|
|
459
462
|
# coerces using +to_s+
|
|
460
463
|
def string(str)
|
|
461
464
|
str = str.to_s
|
|
462
|
-
if str
|
|
465
|
+
if str.b.match?(LITERAL_REGEX)
|
|
463
466
|
Literal.new(str)
|
|
464
467
|
else
|
|
465
468
|
QuotedString.new(str)
|
data/lib/net/imap/config.rb
CHANGED
|
@@ -120,6 +120,66 @@ module Net
|
|
|
120
120
|
#
|
|
121
121
|
# *NOTE:* Updates to config objects are not synchronized for thread-safety.
|
|
122
122
|
#
|
|
123
|
+
# == What's here?
|
|
124
|
+
#
|
|
125
|
+
# === \Config attributes
|
|
126
|
+
#
|
|
127
|
+
# ==== Timeouts and other limits
|
|
128
|
+
#
|
|
129
|
+
# * #open_timeout: seconds to wait for connection to open or start TLS
|
|
130
|
+
# * #idle_response_timeout: seconds to wait for +IDLE+ command to complete
|
|
131
|
+
# * max_response_size: Maximum allowed server response size.
|
|
132
|
+
#
|
|
133
|
+
# ==== Server capabilities
|
|
134
|
+
#
|
|
135
|
+
# * #sasl_ir: Controls +SASL-IR+ behavior for Net::IMAP#authenticate.
|
|
136
|
+
# * #enforce_logindisabled: Controls +LOGINDISABLED+ behavior in
|
|
137
|
+
# Net::IMAP#login.
|
|
138
|
+
# * max_non_synchronizing_literal: maximum bytesize for <tt>LITERAL+</tt> /
|
|
139
|
+
# <tt>LITERAL-</tt> non-synchronizing literals.
|
|
140
|
+
#
|
|
141
|
+
# ==== Inherited defaults
|
|
142
|
+
# {Versioned defaults}[rdoc-ref:Net::IMAP@Versioned+defaults] inherit these
|
|
143
|
+
# from ::global and #load_defaults doesn't update them.
|
|
144
|
+
#
|
|
145
|
+
# * #debug (aliased as #debug?): whether debug mode is enabled
|
|
146
|
+
#
|
|
147
|
+
# ==== Backward compatibility
|
|
148
|
+
# These attributes will be removed by some future release.
|
|
149
|
+
#
|
|
150
|
+
# * #responses_without_block: Controls the behavior of Net::IMAP#responses
|
|
151
|
+
# when called without any arguments (+type+ or +block+).
|
|
152
|
+
# * #parser_use_deprecated_uidplus_data: <em>Ignored since +v0.6.0+.</em>
|
|
153
|
+
# * #parser_max_deprecated_uidplus_data_size: <em>Ignored since +v0.6.0+.</em>
|
|
154
|
+
#
|
|
155
|
+
# === Getting a new or existing config
|
|
156
|
+
# * ::global: The global config, used as the default #parent.
|
|
157
|
+
# * ::default: The hardcoded frozen default config, and parent of ::global.
|
|
158
|
+
# * ::version_defaults: Hard-coded frozen default configurations, indexed
|
|
159
|
+
# by version.
|
|
160
|
+
# * ::[]: Returns a config from ::version_defaults or created by ::new.
|
|
161
|
+
# * ::new: Return a new Config which inherits from a given +parent+.
|
|
162
|
+
# * #new: Return a new Config which inherits from +self+.
|
|
163
|
+
#
|
|
164
|
+
# === Updating multiple attributes
|
|
165
|
+
# * #load_defaults: Sets attributes to a given +version+'s default values.
|
|
166
|
+
# * #update: Assigns multiple attribute values to +self+.
|
|
167
|
+
# * #reset: Resets attributes to inherit from #parent.
|
|
168
|
+
#
|
|
169
|
+
# === Exporting multiple attributes
|
|
170
|
+
# * #to_h: Return a hash with all attributes.
|
|
171
|
+
# * #inspect (aliased as #to_s): Returns a string representation of
|
|
172
|
+
# overriden config attributes and the config inheritance chain.
|
|
173
|
+
# * #pretty_print: Used by PP[https://docs.ruby-lang.org/en/master/PP.html]
|
|
174
|
+
# to create a string representation of all config attributes and the
|
|
175
|
+
# inheritance chain.
|
|
176
|
+
#
|
|
177
|
+
# === Inheritance inspection
|
|
178
|
+
# * #parent: Returns the parent config object.
|
|
179
|
+
# * #inherited?: Returns whether all attributes inherit from #parent.
|
|
180
|
+
# * #inherits_defaults?: Returns whether all attributes inherit from a default config.
|
|
181
|
+
# * #overrides?: Returns whether any attributes override the #parent value.
|
|
182
|
+
#
|
|
123
183
|
class Config
|
|
124
184
|
# Array of attribute names that are _not_ loaded by #load_defaults.
|
|
125
185
|
DEFAULT_TO_INHERIT = %i[debug].freeze
|
|
@@ -196,7 +256,7 @@ module Net
|
|
|
196
256
|
# #load_defaults will not override #debug.
|
|
197
257
|
attr_accessor :debug, type: :boolean, default: false
|
|
198
258
|
|
|
199
|
-
# method: debug?
|
|
259
|
+
# :method: debug?
|
|
200
260
|
# :call-seq: debug? -> boolean
|
|
201
261
|
#
|
|
202
262
|
# Alias for #debug
|
|
@@ -312,7 +372,7 @@ module Net
|
|
|
312
372
|
# * +0.6+: 16 KiB
|
|
313
373
|
attr_accessor :max_non_synchronizing_literal, type: Integer, defaults: {
|
|
314
374
|
0.0r => -1,
|
|
315
|
-
0.6r => 16 <<
|
|
375
|
+
0.6r => 16 << 10, # 16 KiB
|
|
316
376
|
}
|
|
317
377
|
|
|
318
378
|
# The maximum allowed server response size. When +nil+, there is no limit
|
|
@@ -365,7 +425,7 @@ module Net
|
|
|
365
425
|
# Prints a warning and returns the mutable responses hash.
|
|
366
426
|
# <em>This is not thread-safe.</em>
|
|
367
427
|
#
|
|
368
|
-
# [+:frozen_dup+ <em>(
|
|
428
|
+
# [+:frozen_dup+ <em>(default since +v0.6+)</em>]
|
|
369
429
|
# Returns a frozen copy of the unhandled responses hash, with frozen
|
|
370
430
|
# array values.
|
|
371
431
|
#
|
|
@@ -193,11 +193,11 @@ module Net
|
|
|
193
193
|
end
|
|
194
194
|
|
|
195
195
|
##
|
|
196
|
-
# method: range
|
|
196
|
+
# :method: range
|
|
197
197
|
# :call-seq: range -> range
|
|
198
198
|
|
|
199
199
|
##
|
|
200
|
-
# method: results
|
|
200
|
+
# :method: results
|
|
201
201
|
# :call-seq: results -> sequence set or nil
|
|
202
202
|
|
|
203
203
|
# Converts #results to an array of integers.
|
data/lib/net/imap/fetch_data.rb
CHANGED
|
@@ -104,7 +104,7 @@ module Net
|
|
|
104
104
|
#
|
|
105
105
|
class FetchStruct < Struct
|
|
106
106
|
##
|
|
107
|
-
# method: attr
|
|
107
|
+
# :method: attr
|
|
108
108
|
# :call-seq: attr -> hash
|
|
109
109
|
#
|
|
110
110
|
# Each key specifies a message attribute, and the value is the
|
|
@@ -518,7 +518,7 @@ module Net
|
|
|
518
518
|
# See FetchStruct documentation for a list of standard message attributes.
|
|
519
519
|
class FetchData < FetchStruct.new(:seqno, :attr)
|
|
520
520
|
##
|
|
521
|
-
# method: seqno
|
|
521
|
+
# :method: seqno
|
|
522
522
|
# :call-seq: seqno -> Integer
|
|
523
523
|
#
|
|
524
524
|
# The message sequence number.
|
|
@@ -532,7 +532,7 @@ module Net
|
|
|
532
532
|
# UIDFetchData will raise a NoMethodError.
|
|
533
533
|
|
|
534
534
|
##
|
|
535
|
-
# method: attr
|
|
535
|
+
# :method: attr
|
|
536
536
|
# :call-seq: attr -> hash
|
|
537
537
|
#
|
|
538
538
|
# Each key specifies a message attribute, and the value is the
|
|
@@ -558,7 +558,7 @@ module Net
|
|
|
558
558
|
# See FetchStruct documentation for a list of standard message attributes.
|
|
559
559
|
class UIDFetchData < FetchStruct.new(:uid, :attr)
|
|
560
560
|
##
|
|
561
|
-
# method: uid
|
|
561
|
+
# :method: uid
|
|
562
562
|
# call-seq: uid -> Integer
|
|
563
563
|
#
|
|
564
564
|
# A number expressing the unique identifier of the message.
|
|
@@ -568,7 +568,7 @@ module Net
|
|
|
568
568
|
# returns the uniqueid at the beginning of the +UIDFETCH+ response.
|
|
569
569
|
|
|
570
570
|
##
|
|
571
|
-
# method: attr
|
|
571
|
+
# :method: attr
|
|
572
572
|
# call-seq: attr -> hash
|
|
573
573
|
#
|
|
574
574
|
# Each key specifies a message attribute, and the value is the
|