net-imap 0.5.14 → 0.5.15
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/lib/net/imap/command_data.rb +81 -37
- data/lib/net/imap/response_parser.rb +20 -12
- data/lib/net/imap/response_reader.rb +14 -1
- data/lib/net/imap.rb +30 -15
- 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: '0917528437aff2a931fa3b40d476ffbad713cf46655163dc21a6a7a2333f7a49'
|
|
4
|
+
data.tar.gz: 90b3bf050a4f403408e30eecfaf449069e55bc293297b482e627201821997e0c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c2aaf64941ac0537b7ba6da23ea501dacf438d9eb99581a2ca9906ad150bf5f55a7702141cb573e38306e3eb16000388acb4eb0dbc478727488bc21fa1c61288
|
|
7
|
+
data.tar.gz: 9d6b93b6c963e4e9c226044e1d8f9c4c5e09365ab57beaf1157128f85cc511402927d50033b0ad154b75914cf7191f2ec111dd240c566907203e4263a24f5e49
|
|
@@ -17,14 +17,15 @@ module Net
|
|
|
17
17
|
when nil
|
|
18
18
|
when String
|
|
19
19
|
when Integer
|
|
20
|
-
|
|
20
|
+
# Covers modseq-valzer, which is the largest valid IMAP integer
|
|
21
|
+
if data.negative?
|
|
22
|
+
raise DataFormatError, "Integer argument must be unsigned: #{data}"
|
|
23
|
+
elsif 0xffff_ffff_ffff_ffff < data
|
|
24
|
+
raise DataFormatError, "Integer argument must fit in 64 bits: #{data}"
|
|
25
|
+
end
|
|
21
26
|
when Array
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
else
|
|
25
|
-
data.each do |i|
|
|
26
|
-
validate_data(i)
|
|
27
|
-
end
|
|
27
|
+
data.each do |i|
|
|
28
|
+
validate_data(i)
|
|
28
29
|
end
|
|
29
30
|
when Time, Date, DateTime
|
|
30
31
|
when Symbol
|
|
@@ -85,15 +86,23 @@ module Net
|
|
|
85
86
|
|
|
86
87
|
# `non_sync` is an optional tri-state flag:
|
|
87
88
|
# * `true` -> Force non-synchronizing `LITERAL+`/`LITERAL-` behavior.
|
|
88
|
-
#
|
|
89
|
+
# NOTE: raises DataFormatError when server doesn't support
|
|
90
|
+
# non-synchronizing literal, or literal is too large for LITERAL-.
|
|
89
91
|
# * `false` -> Force normal synchronizing literal behavior.
|
|
90
92
|
# * `nil` -> (default) Currently behaves like `false` (will be dynamic).
|
|
91
93
|
# TODO: Dynamic, based on capabilities and bytesize.
|
|
92
94
|
def send_literal(str, tag = nil, binary: false, non_sync: nil)
|
|
95
|
+
bytesize = str.bytesize
|
|
93
96
|
synchronize do
|
|
97
|
+
if non_sync && !non_sync_literal_allowed?(bytesize)
|
|
98
|
+
# TODO: check in Printer, so we don't need to close the connection.
|
|
99
|
+
@sock.close
|
|
100
|
+
raise DataFormatError, "Connection closed: " \
|
|
101
|
+
"Cannot send non-synchronizing literal without known server support"
|
|
102
|
+
end
|
|
94
103
|
prefix = "~" if binary
|
|
95
104
|
plus = "+" if non_sync
|
|
96
|
-
put_string("#{prefix}{#{
|
|
105
|
+
put_string("#{prefix}{#{bytesize}#{plus}}\r\n")
|
|
97
106
|
if non_sync
|
|
98
107
|
put_string(str)
|
|
99
108
|
return
|
|
@@ -112,8 +121,18 @@ module Net
|
|
|
112
121
|
end
|
|
113
122
|
end
|
|
114
123
|
|
|
124
|
+
def non_sync_literal_allowed?(bytesize)
|
|
125
|
+
return unless capabilities_cached?
|
|
126
|
+
return "+" if capable?("LITERAL+")
|
|
127
|
+
return "-" if capable_literal_minus? && bytesize <= 4096
|
|
128
|
+
false
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def capable_literal_minus? = capable?("LITERAL-") || capable?("IMAP4rev2")
|
|
132
|
+
|
|
133
|
+
# NOTE: +num+ should already be an Integer
|
|
115
134
|
def send_number_data(num)
|
|
116
|
-
put_string(num.to_s)
|
|
135
|
+
put_string(Integer(num).to_s)
|
|
117
136
|
end
|
|
118
137
|
|
|
119
138
|
def send_list_data(list, tag = nil)
|
|
@@ -148,36 +167,38 @@ module Net
|
|
|
148
167
|
end
|
|
149
168
|
end
|
|
150
169
|
|
|
151
|
-
# Represents IMAP +text+ data, which
|
|
152
|
-
#
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
170
|
+
# Represents IMAP +text+ or +quoted+ data, which share the same
|
|
171
|
+
# validations of decoded #data, and differ only in how they are formatted.
|
|
172
|
+
#
|
|
173
|
+
# +data+ may contain any 7-bit ASCII character except +NULL+, +CR+, or +LF+.
|
|
174
|
+
# Any multibyte +UTF-8+ character is also allowed when the connection
|
|
175
|
+
# supports UTF8: either +UTF8=ACCEPT+ or +IMAP4rev2+ have been enabled, or
|
|
176
|
+
# the server supports only +IMAP4rev2+ and not earlier IMAP revisions, or
|
|
177
|
+
# the server advertises +UTF8=ONLY+.
|
|
156
178
|
#
|
|
157
|
-
# NOTE:
|
|
158
|
-
#
|
|
179
|
+
# NOTE: This does not verify whether the connection supports UTF-8, but that
|
|
180
|
+
# may change in future versions.
|
|
159
181
|
#
|
|
160
182
|
# The string's bytes must be valid ASCII or valid UTF-8. The string's
|
|
161
183
|
# reported encoding is ignored, but the string is _not_ transcoded.
|
|
162
|
-
class
|
|
184
|
+
class ValidNonLiteralData < CommandData
|
|
163
185
|
def initialize(data:)
|
|
164
186
|
data = String(data.to_str)
|
|
165
|
-
|
|
166
|
-
-
|
|
167
|
-
elsif data.ascii_only?
|
|
168
|
-
-(data.dup.force_encoding("ASCII"))
|
|
169
|
-
else
|
|
170
|
-
-(data.dup.force_encoding("UTF-8"))
|
|
187
|
+
unless data.encoding in Encoding::ASCII | Encoding::UTF_8
|
|
188
|
+
data = data.dup.force_encoding(data.ascii_only? ? "ASCII" : "UTF-8")
|
|
171
189
|
end
|
|
190
|
+
data = -data
|
|
172
191
|
super
|
|
173
192
|
validate
|
|
174
193
|
end
|
|
175
194
|
|
|
176
195
|
def validate
|
|
177
|
-
if data.
|
|
178
|
-
raise DataFormatError, "
|
|
196
|
+
if !(data.encoding in Encoding::ASCII | Encoding::UTF_8)
|
|
197
|
+
raise DataFormatError, "must use ASCII or UTF-8 encoding"
|
|
179
198
|
elsif !data.valid_encoding?
|
|
180
199
|
raise DataFormatError, "invalid UTF-8 must be literal encoded"
|
|
200
|
+
elsif data.include?("\0")
|
|
201
|
+
raise DataFormatError, "NULL byte must be binary literal encoded"
|
|
181
202
|
elsif /[\r\n]/.match?(data)
|
|
182
203
|
raise DataFormatError, "CR and LF bytes must be literal encoded"
|
|
183
204
|
end
|
|
@@ -185,12 +206,27 @@ module Net
|
|
|
185
206
|
|
|
186
207
|
def ascii_only? = data.ascii_only?
|
|
187
208
|
|
|
188
|
-
def send_data(imap, tag) = imap.__send__(:put_string,
|
|
209
|
+
def send_data(imap, tag = nil) = imap.__send__(:put_string, formatted)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Represents IMAP +text+ data, which covers everything in the IMAP grammar,
|
|
213
|
+
# except for +literal+, +literal8+, and the concluding +CRLF+.
|
|
214
|
+
#
|
|
215
|
+
# NOTE: The current implementation does not verify that the connection
|
|
216
|
+
# supports UTF-8. Future versions may validate this.
|
|
217
|
+
class RawText < ValidNonLiteralData # :nodoc:
|
|
218
|
+
# raw: no formatting necessary
|
|
219
|
+
alias formatted data
|
|
189
220
|
end
|
|
190
221
|
|
|
191
222
|
class RawData < CommandData # :nodoc:
|
|
192
223
|
def initialize(data:)
|
|
193
|
-
|
|
224
|
+
case data
|
|
225
|
+
in String then data = self.class.split(data)
|
|
226
|
+
in Array if data.all? { _1 in RawText | Literal }
|
|
227
|
+
else
|
|
228
|
+
raise TypeError, "expected String or Array[#{RawText} | #{Literal}]"
|
|
229
|
+
end
|
|
194
230
|
super
|
|
195
231
|
validate
|
|
196
232
|
end
|
|
@@ -199,14 +235,16 @@ module Net
|
|
|
199
235
|
|
|
200
236
|
def validate
|
|
201
237
|
return unless data.last in RawText(data: text)
|
|
202
|
-
if text.rindex(
|
|
238
|
+
if text.rindex(/\{\d+\+?\}\z/n)
|
|
203
239
|
raise DataFormatError, "RawData cannot end with literal continuation"
|
|
204
240
|
end
|
|
205
241
|
end
|
|
206
242
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
243
|
+
# Splits an input +string+ into an array of RawText and Literal/Literal8.
|
|
244
|
+
#
|
|
245
|
+
# NOTE: unlike RawData#validate, this does not prevent the final RawText
|
|
246
|
+
# from ending with a literal prefix.
|
|
247
|
+
def self.split(data)
|
|
210
248
|
data = data.b # dups and ensures BINARY encoding
|
|
211
249
|
parts = []
|
|
212
250
|
while data.match(/(~)?\{(0|[1-9]\d*)(\+)?\}\r\n/n)
|
|
@@ -220,7 +258,7 @@ module Net
|
|
|
220
258
|
parts
|
|
221
259
|
end
|
|
222
260
|
|
|
223
|
-
def extract_literal(data, binary:, bytesize:, non_sync:)
|
|
261
|
+
def self.extract_literal(data, binary:, bytesize:, non_sync:)
|
|
224
262
|
if data.bytesize < bytesize
|
|
225
263
|
raise DataFormatError, "Too few bytes in string for literal, " \
|
|
226
264
|
"expected: %s, remaining: %s" % [bytesize, data.bytesize]
|
|
@@ -228,6 +266,7 @@ module Net
|
|
|
228
266
|
literal = data.byteslice(0, bytesize)
|
|
229
267
|
(binary ? Literal8 : Literal).new(data: literal, non_sync:)
|
|
230
268
|
end
|
|
269
|
+
private_class_method :extract_literal
|
|
231
270
|
end
|
|
232
271
|
|
|
233
272
|
class Atom < CommandData # :nodoc:
|
|
@@ -241,6 +280,8 @@ module Net
|
|
|
241
280
|
or raise DataFormatError, "#{self.class} must be ASCII only"
|
|
242
281
|
data.match?(ResponseParser::Patterns::ATOM_SPECIALS) \
|
|
243
282
|
and raise DataFormatError, "#{self.class} must not contain atom-specials"
|
|
283
|
+
data.empty? \
|
|
284
|
+
and raise DataFormatError, "#{self.class} must not be empty"
|
|
244
285
|
end
|
|
245
286
|
|
|
246
287
|
def send_data(imap, tag)
|
|
@@ -254,10 +295,13 @@ module Net
|
|
|
254
295
|
end
|
|
255
296
|
end
|
|
256
297
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
298
|
+
# Represents a IMAP +quoted+ string, which can encode any valid ASCII or
|
|
299
|
+
# UTF-8 string, unless it contains any +CR+, +LF+, or +NULL+ bytes.
|
|
300
|
+
#
|
|
301
|
+
# NOTE: The current implementation does not verify that the connection
|
|
302
|
+
# supports UTF-8. Future versions may validate this.
|
|
303
|
+
class QuotedString < ValidNonLiteralData # :nodoc:
|
|
304
|
+
def formatted = %("#{data.gsub(/["\\]/, "\\\\\\&")}")
|
|
261
305
|
end
|
|
262
306
|
|
|
263
307
|
class Literal < Data.define(:data, :non_sync) # :nodoc:
|
|
@@ -2189,10 +2189,7 @@ module Net
|
|
|
2189
2189
|
if $1
|
|
2190
2190
|
return Token.new(T_SPACE, $+)
|
|
2191
2191
|
elsif $2
|
|
2192
|
-
|
|
2193
|
-
val = @str[@pos, len]
|
|
2194
|
-
@pos += len
|
|
2195
|
-
return Token.new(T_LITERAL8, val)
|
|
2192
|
+
literal_token($+, T_LITERAL8)
|
|
2196
2193
|
elsif $3 && $7
|
|
2197
2194
|
# greedily match ATOM, prefixed with NUMBER, NIL, or PLUS.
|
|
2198
2195
|
return Token.new(T_ATOM, $3)
|
|
@@ -2220,10 +2217,7 @@ module Net
|
|
|
2220
2217
|
elsif $15
|
|
2221
2218
|
return Token.new(T_RBRA, $+)
|
|
2222
2219
|
elsif $16
|
|
2223
|
-
|
|
2224
|
-
val = @str[@pos, len]
|
|
2225
|
-
@pos += len
|
|
2226
|
-
return Token.new(T_LITERAL, val)
|
|
2220
|
+
literal_token($+)
|
|
2227
2221
|
elsif $17
|
|
2228
2222
|
return Token.new(T_PERCENT, $+)
|
|
2229
2223
|
elsif $18
|
|
@@ -2249,10 +2243,7 @@ module Net
|
|
|
2249
2243
|
elsif $4
|
|
2250
2244
|
return Token.new(T_QUOTED, Patterns.unescape_quoted($+))
|
|
2251
2245
|
elsif $5
|
|
2252
|
-
|
|
2253
|
-
val = @str[@pos, len]
|
|
2254
|
-
@pos += len
|
|
2255
|
-
return Token.new(T_LITERAL, val)
|
|
2246
|
+
literal_token($+)
|
|
2256
2247
|
elsif $6
|
|
2257
2248
|
return Token.new(T_LPAR, $+)
|
|
2258
2249
|
elsif $7
|
|
@@ -2267,6 +2258,23 @@ module Net
|
|
|
2267
2258
|
else
|
|
2268
2259
|
parse_error("invalid @lex_state - %s", @lex_state.inspect)
|
|
2269
2260
|
end
|
|
2261
|
+
rescue DataFormatError => error
|
|
2262
|
+
parse_error error.message
|
|
2263
|
+
end
|
|
2264
|
+
|
|
2265
|
+
def literal_token(len, type = T_LITERAL)
|
|
2266
|
+
len = coerce_number64 len.to_i
|
|
2267
|
+
val = @str[@pos, len]
|
|
2268
|
+
@pos += len
|
|
2269
|
+
Token.new(type, val)
|
|
2270
|
+
end
|
|
2271
|
+
|
|
2272
|
+
# copied/adapted from NumValidator in v0.6
|
|
2273
|
+
def coerce_number64(num)
|
|
2274
|
+
int = num.to_i
|
|
2275
|
+
return int if 0 <= int && int <= 0x7fff_ffff_ffff_ffff
|
|
2276
|
+
raise DataFormatError,
|
|
2277
|
+
"number64 must be unsigned 63-bit integer: #{num}"
|
|
2270
2278
|
end
|
|
2271
2279
|
|
|
2272
2280
|
end
|
|
@@ -4,6 +4,8 @@ module Net
|
|
|
4
4
|
class IMAP
|
|
5
5
|
# See https://www.rfc-editor.org/rfc/rfc9051#section-2.2.2
|
|
6
6
|
class ResponseReader # :nodoc:
|
|
7
|
+
include NumValidator
|
|
8
|
+
|
|
7
9
|
attr_reader :client
|
|
8
10
|
|
|
9
11
|
def initialize(client, sock)
|
|
@@ -35,7 +37,10 @@ module Net
|
|
|
35
37
|
def line_done? = buff.end_with?(CRLF)
|
|
36
38
|
|
|
37
39
|
def get_literal_size(buff)
|
|
38
|
-
buff.end_with?("}\r\n") && buff.rindex(/\{(\d+)\}\r\n\z/n) &&
|
|
40
|
+
buff.end_with?("}\r\n") && buff.rindex(/\{(\d+)\}\r\n\z/n) &&
|
|
41
|
+
coerce_number64($1)
|
|
42
|
+
rescue DataFormatError
|
|
43
|
+
raise DataFormatError, format("invalid response literal size (%s)", $1)
|
|
39
44
|
end
|
|
40
45
|
|
|
41
46
|
def read_line
|
|
@@ -74,6 +79,14 @@ module Net
|
|
|
74
79
|
)
|
|
75
80
|
end
|
|
76
81
|
|
|
82
|
+
# copied/adapted from NumValidator in v0.6
|
|
83
|
+
def coerce_number64(num)
|
|
84
|
+
int = num.to_i
|
|
85
|
+
return int if 0 <= int && int <= 0x7fff_ffff_ffff_ffff
|
|
86
|
+
raise DataFormatError,
|
|
87
|
+
"number64 must be unsigned 63-bit integer: #{num}"
|
|
88
|
+
end
|
|
89
|
+
|
|
77
90
|
end
|
|
78
91
|
end
|
|
79
92
|
end
|
data/lib/net/imap.rb
CHANGED
|
@@ -806,7 +806,7 @@ module Net
|
|
|
806
806
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
|
807
807
|
#
|
|
808
808
|
class IMAP < Protocol
|
|
809
|
-
VERSION = "0.5.
|
|
809
|
+
VERSION = "0.5.15"
|
|
810
810
|
|
|
811
811
|
# Aliases for supported capabilities, to be used with the #enable command.
|
|
812
812
|
ENABLE_ALIASES = {
|
|
@@ -1149,22 +1149,24 @@ module Net
|
|
|
1149
1149
|
|
|
1150
1150
|
# Disconnects from the server.
|
|
1151
1151
|
#
|
|
1152
|
-
# Waits for receiver thread to close before returning
|
|
1153
|
-
#
|
|
1152
|
+
# Waits for receiver thread to close before returning, except when called
|
|
1153
|
+
# from inside the connection mutex such as from a response handler. Slow or
|
|
1154
|
+
# stuck response handlers can cause #disconnect to hang until they complete.
|
|
1154
1155
|
#
|
|
1155
1156
|
# Related: #logout, #logout!
|
|
1156
1157
|
def disconnect
|
|
1157
1158
|
in_logout_state = try_state_logout?
|
|
1158
1159
|
return if disconnected?
|
|
1160
|
+
in_receiver_thread = Thread.current == @receiver_thread
|
|
1159
1161
|
begin
|
|
1160
1162
|
@sock.to_io.shutdown
|
|
1161
1163
|
rescue Errno::ENOTCONN
|
|
1162
1164
|
# ignore `Errno::ENOTCONN: Socket is not connected' on some platforms.
|
|
1163
1165
|
rescue Exception => e
|
|
1164
|
-
@receiver_thread.raise(e)
|
|
1166
|
+
@receiver_thread.raise(e) unless in_receiver_thread
|
|
1165
1167
|
end
|
|
1166
1168
|
@sock.close
|
|
1167
|
-
@receiver_thread.join
|
|
1169
|
+
@receiver_thread.join unless mon_owned? || in_receiver_thread
|
|
1168
1170
|
raise e if e
|
|
1169
1171
|
ensure
|
|
1170
1172
|
# Try again after shutting down the receiver thread. With no reciever
|
|
@@ -2209,6 +2211,7 @@ module Net
|
|
|
2209
2211
|
# provided as an array or a string.
|
|
2210
2212
|
# See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
|
|
2211
2213
|
# and {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
|
|
2214
|
+
# <em>Please note</em> the warning for when +criteria+ is a String.
|
|
2212
2215
|
#
|
|
2213
2216
|
# +return+ options control what kind of information is returned about
|
|
2214
2217
|
# messages matching the search +criteria+. Specifying +return+ should force
|
|
@@ -2619,7 +2622,8 @@ module Net
|
|
|
2619
2622
|
# backward compatibility) but adds SearchResult#modseq when the +CONDSTORE+
|
|
2620
2623
|
# capability has been enabled.
|
|
2621
2624
|
#
|
|
2622
|
-
# See #search for documentation of parameters.
|
|
2625
|
+
# See #search for documentation of parameters. <em>Please note</em> the
|
|
2626
|
+
# warning for when +criteria+ is a String.
|
|
2623
2627
|
#
|
|
2624
2628
|
# ==== Capabilities
|
|
2625
2629
|
#
|
|
@@ -2705,7 +2709,8 @@ module Net
|
|
|
2705
2709
|
# {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
|
|
2706
2710
|
# (For message sequence numbers, use #fetch instead.)
|
|
2707
2711
|
#
|
|
2708
|
-
# +attr+ behaves the same as with #fetch.
|
|
2712
|
+
# +attr+ behaves the same as with #fetch. <em>Please note</em> the #fetch
|
|
2713
|
+
# warning on the +attr+ argument.
|
|
2709
2714
|
# >>>
|
|
2710
2715
|
# *Note:* Servers _MUST_ implicitly include the +UID+ message data item as
|
|
2711
2716
|
# part of any +FETCH+ response caused by a +UID+ command, regardless of
|
|
@@ -2917,8 +2922,10 @@ module Net
|
|
|
2917
2922
|
|
|
2918
2923
|
# Sends a {SORT command [RFC5256 §3]}[https://www.rfc-editor.org/rfc/rfc5256#section-3]
|
|
2919
2924
|
# to search a mailbox for messages that match +search_keys+ and return an
|
|
2920
|
-
# array of message sequence numbers, sorted by +sort_keys+.
|
|
2921
|
-
#
|
|
2925
|
+
# array of message sequence numbers, sorted by +sort_keys+.
|
|
2926
|
+
#
|
|
2927
|
+
# +search_keys+ are interpreted the same as the +criteria+ argument for
|
|
2928
|
+
# #search. <em>Please note</em> the #search warning for String +criteria+.
|
|
2922
2929
|
#
|
|
2923
2930
|
#--
|
|
2924
2931
|
# TODO: describe +sort_keys+
|
|
@@ -2943,8 +2950,10 @@ module Net
|
|
|
2943
2950
|
|
|
2944
2951
|
# Sends a {UID SORT command [RFC5256 §3]}[https://www.rfc-editor.org/rfc/rfc5256#section-3]
|
|
2945
2952
|
# to search a mailbox for messages that match +search_keys+ and return an
|
|
2946
|
-
# array of unique identifiers, sorted by +sort_keys+.
|
|
2947
|
-
#
|
|
2953
|
+
# array of unique identifiers, sorted by +sort_keys+.
|
|
2954
|
+
#
|
|
2955
|
+
# +search_keys+ are interpreted the same as the +criteria+ argument for
|
|
2956
|
+
# #search. <em>Please note</em> the #search warning for String +criteria+.
|
|
2948
2957
|
#
|
|
2949
2958
|
# Related: #sort, #search, #uid_search, #thread, #uid_thread
|
|
2950
2959
|
#
|
|
@@ -2958,8 +2967,10 @@ module Net
|
|
|
2958
2967
|
|
|
2959
2968
|
# Sends a {THREAD command [RFC5256 §3]}[https://www.rfc-editor.org/rfc/rfc5256#section-3]
|
|
2960
2969
|
# to search a mailbox and return message sequence numbers in threaded
|
|
2961
|
-
# format, as a ThreadMember tree.
|
|
2962
|
-
#
|
|
2970
|
+
# format, as a ThreadMember tree.
|
|
2971
|
+
#
|
|
2972
|
+
# +search_keys+ are interpreted the same as the +criteria+ argument for
|
|
2973
|
+
# #search. <em>Please note</em> the #search warning for String +criteria+.
|
|
2963
2974
|
#
|
|
2964
2975
|
# The supported algorithms are:
|
|
2965
2976
|
#
|
|
@@ -2985,6 +2996,9 @@ module Net
|
|
|
2985
2996
|
# Similar to #thread, but returns unique identifiers instead of
|
|
2986
2997
|
# message sequence numbers.
|
|
2987
2998
|
#
|
|
2999
|
+
# +search_keys+ are interpreted the same as the +criteria+ argument for
|
|
3000
|
+
# #search. <em>Please note</em> the #search warning for String +criteria+.
|
|
3001
|
+
#
|
|
2988
3002
|
# Related: #thread, #search, #uid_search, #sort, #uid_sort
|
|
2989
3003
|
#
|
|
2990
3004
|
# ==== Capabilities
|
|
@@ -3094,10 +3108,11 @@ module Net
|
|
|
3094
3108
|
capabilities = capabilities
|
|
3095
3109
|
.flatten
|
|
3096
3110
|
.map {|e| ENABLE_ALIASES[e] || e }
|
|
3111
|
+
.flat_map { _1.is_a?(String) && !_1.empty? ? _1.split(/ /, -1) : [_1] }
|
|
3097
3112
|
.uniq
|
|
3098
|
-
.
|
|
3113
|
+
.map { Atom[_1] }
|
|
3099
3114
|
synchronize do
|
|
3100
|
-
send_command("ENABLE
|
|
3115
|
+
send_command("ENABLE", *capabilities)
|
|
3101
3116
|
result = clear_responses("ENABLED").last || []
|
|
3102
3117
|
@utf8_strings ||= result.include? "UTF8=ACCEPT"
|
|
3103
3118
|
@utf8_strings ||= result.include? "IMAP4REV2"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: net-imap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shugo Maeda
|
|
@@ -130,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
131
|
version: '0'
|
|
132
132
|
requirements: []
|
|
133
|
-
rubygems_version: 4.0.
|
|
133
|
+
rubygems_version: 4.0.10
|
|
134
134
|
specification_version: 4
|
|
135
135
|
summary: Ruby client api for Internet Message Access Protocol
|
|
136
136
|
test_files: []
|