net-imap 0.4.24 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9419630b908b12c7f89846682dae953e50376d89ebb3b7391b3426bb34480991
4
- data.tar.gz: 4558a77d38a4def28af960c201ca9359fcc828d5a316f76f95cf3c0e575702b6
3
+ metadata.gz: 2c89d97e842bce303df112c3fbc0f048f20a2ff1dbf3b85bb2314ea0d2e207c5
4
+ data.tar.gz: 11d6ec196e1e768f61a17b0ce7f385a11eb03e3e92af8ab327ba9a90699ee940
5
5
  SHA512:
6
- metadata.gz: 5f4baf570c8ed5732493ba801121ae092177fca3ab5f9162ef66f0db2a23e91c09fe740d8ddba52977e65737906a6735a8405bb94e923111970621e79b813141
7
- data.tar.gz: 624e1b8a76630bffa007391b303eab5729b20665d9a5242f58749e0127340ddd1a842eb94ca46da085ccfa91cc093367348586cde705b51fe3eff25882f8f096
6
+ metadata.gz: ca70e20c3c70f4ca57822f70936546adb3129dd7c0771ef2d054b0356ed4f6a994b7453803cc06bd25ebb37dc0ed10f60b5541bc56749dee38a6126264344599
7
+ data.tar.gz: 2921a79dbdab7bd0476d883c18db50150388d587c711270faac99ad4505574a23e6532fe61a4fb48f51c8bddea6641d96f81d9dcbe245b4d4f4542fcc7418566
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- # gem "digest" # not included as a workaround for #576
7
+ gem "digest"
8
8
  gem "strscan"
9
9
  gem "base64"
10
10
 
@@ -13,4 +13,10 @@ gem "rdoc"
13
13
  gem "test-unit"
14
14
  gem "test-unit-ruby-core", git: "https://github.com/ruby/test-unit-ruby-core"
15
15
 
16
- gem "benchmark-driver"
16
+ gem "benchmark-driver", require: false
17
+
18
+ group :test do
19
+ gem "simplecov", require: false
20
+ gem "simplecov-html", require: false
21
+ gem "simplecov-json", require: false
22
+ end
@@ -9,7 +9,7 @@ module Net::IMAP::Authenticators
9
9
  "%s.%s is deprecated. Use %s.%s instead." % [
10
10
  Net::IMAP, __method__, Net::IMAP::SASL, __method__
11
11
  ],
12
- uplevel: 1
12
+ uplevel: 1, category: :deprecated
13
13
  )
14
14
  Net::IMAP::SASL.add_authenticator(...)
15
15
  end
@@ -20,7 +20,7 @@ module Net::IMAP::Authenticators
20
20
  "%s.%s is deprecated. Use %s.%s instead." % [
21
21
  Net::IMAP, __method__, Net::IMAP::SASL, __method__
22
22
  ],
23
- uplevel: 1
23
+ uplevel: 1, category: :deprecated
24
24
  )
25
25
  Net::IMAP::SASL.authenticator(...)
26
26
  end
@@ -25,7 +25,6 @@ module Net
25
25
  end
26
26
  when Time, Date, DateTime
27
27
  when Symbol
28
- Flag.validate(data)
29
28
  else
30
29
  data.validate
31
30
  end
@@ -46,7 +45,7 @@ module Net
46
45
  when Date
47
46
  send_date_data(data)
48
47
  when Symbol
49
- Flag[data].send_data(self, tag)
48
+ send_symbol_data(data)
50
49
  else
51
50
  data.send_data(self, tag)
52
51
  end
@@ -78,23 +77,9 @@ module Net
78
77
  put_string('"' + str.gsub(/["\\]/, "\\\\\\&") + '"')
79
78
  end
80
79
 
81
- def send_binary_literal(*a, **kw) send_literal(*a, **kw, binary: true) end
82
-
83
- # `non_sync` is an optional tri-state flag:
84
- # * `true` -> Force non-synchronizing `LITERAL+`/`LITERAL-` behavior.
85
- # TODO: raise or warn when capabilities don't allow non_sync.
86
- # * `false` -> Force normal synchronizing literal behavior.
87
- # * `nil` -> (default) Currently behaves like `false` (will be dynamic).
88
- # TODO: Dynamic, based on capabilities and bytesize.
89
- def send_literal(str, tag = nil, binary: false, non_sync: nil)
80
+ def send_literal(str, tag = nil)
90
81
  synchronize do
91
- prefix = "~" if binary
92
- plus = "+" if non_sync
93
- put_string("#{prefix}{#{str.bytesize}#{plus}}\r\n")
94
- if non_sync
95
- put_string(str)
96
- return
97
- end
82
+ put_string("{" + str.bytesize.to_s + "}" + CRLF)
98
83
  @continued_command_tag = tag
99
84
  @continuation_request_exception = nil
100
85
  begin
@@ -130,148 +115,37 @@ module Net
130
115
  def send_date_data(date) put_string Net::IMAP.encode_date(date) end
131
116
  def send_time_data(time) put_string Net::IMAP.encode_time(time) end
132
117
 
133
- # simplistic emulation of CommandData = Data.define(:data)
134
- class CommandData # :nodoc:
135
- class << self
136
- def new(arg = nil, data: arg) super(data: data) end
137
- alias :[] :new
138
- end
139
-
140
- def initialize(data:)
141
- @data = data
142
- freeze
143
- end
144
-
145
- attr_reader :data
146
-
147
- def to_h(&block) block ? to_h.to_h(&block) : { data: data } end
148
- def ==(other) self.class === other && to_h == other.to_h end
149
- def eql?(other) self.class === other && to_h.eql?(other.to_h) end
150
-
151
- # following class definition goes beyond the basic Data.define(:data)
152
- ##
153
-
154
- def self.validate(...)
155
- data = new(...)
156
- data.validate
157
- data
158
- end
159
-
160
- def send_data(imap, tag)
161
- raise NoMethodError, "#{self.class} must implement #{__method__}"
162
- end
163
-
164
- def validate
165
- end
118
+ def send_symbol_data(symbol)
119
+ put_string("\\" + symbol.to_s)
166
120
  end
167
121
 
168
- # Represents IMAP +text+ data, which may contain any 7-bit ASCII character,
169
- # except for +NULL+, +CR+, or +LF+. +text+ is extended to allow any
170
- # multibyte +UTF-8+ character when either +UTF8=ACCEPT+ or +IMAP4rev2+ have
171
- # been enabled, or when the server supports only +IMAP4rev2+ and not earlier
172
- # IMAP revisions, or when the server advertises +UTF8=ONLY+.
173
- #
174
- # NOTE: The current implementation does not validate whether the connection
175
- # currently supports UTF-8. Future versions may change.
176
- #
177
- # The string's bytes must be valid ASCII or valid UTF-8. The string's
178
- # reported encoding is ignored, but the string is _not_ transcoded.
179
- class RawText < CommandData # :nodoc:
180
- def initialize(data:)
181
- data = String(data.to_str)
182
- data = if [Encoding::ASCII, Encoding::UTF_8].include?(data.encoding)
183
- -data
184
- elsif data.ascii_only?
185
- -(data.dup.force_encoding("ASCII"))
186
- else
187
- -(data.dup.force_encoding("UTF-8"))
188
- end
189
- super
190
- validate
191
- end
192
-
193
- def validate
194
- if data.include?("\0")
195
- raise DataFormatError, "NULL byte must be binary literal encoded"
196
- elsif !data.valid_encoding?
197
- raise DataFormatError, "invalid UTF-8 must be literal encoded"
198
- elsif /[\r\n]/.match?(data)
199
- raise DataFormatError, "CR and LF bytes must be literal encoded"
200
- end
201
- end
202
-
203
- def ascii_only?; data.ascii_only? end
204
-
205
- def send_data(imap, tag) imap.__send__(:put_string, data) end
206
- end
207
-
208
- class RawData < CommandData # :nodoc:
209
- def initialize(data:)
210
- data = split_parts(data)
211
- super
212
- validate
122
+ class RawData # :nodoc:
123
+ def send_data(imap, tag)
124
+ imap.__send__(:put_string, @data)
213
125
  end
214
126
 
215
- def send_data(imap, tag) data.each do _1.send_data(imap, tag) end end
216
-
217
127
  def validate
218
- return unless RawText === data.last
219
- text = data.last.data
220
- if text.rindex(/~?\{[1-9]\d*\+?\}\z/n)
221
- raise DataFormatError, "RawData cannot end with literal continuation"
222
- end
223
128
  end
224
129
 
225
130
  private
226
131
 
227
- def split_parts(data)
228
- data = data.b # dups and ensures BINARY encoding
229
- parts = []
230
- while data.match(/(~)?\{(0|[1-9]\d*)(\+)?\}\r\n/n)
231
- text, binary, bytesize, non_sync, data = $`, !!$1, $2, !!$3, $'
232
- bytesize = Integer bytesize, 10
233
- parts << RawText[text] unless text.empty?
234
- parts << extract_literal(data,
235
- binary: binary,
236
- bytesize: bytesize,
237
- non_sync: non_sync)
238
- data[0, bytesize] = ""
239
- end
240
- parts << RawText[data] unless data.empty?
241
- parts
242
- end
243
-
244
- def extract_literal(data, binary:, bytesize:, non_sync:)
245
- if data.bytesize < bytesize
246
- raise DataFormatError, "Too few bytes in string for literal, " \
247
- "expected: %s, remaining: %s" % [bytesize, data.bytesize]
248
- end
249
- literal = data.byteslice(0, bytesize)
250
- (binary ? Literal8 : Literal).new(data: literal, non_sync: non_sync)
132
+ def initialize(data)
133
+ @data = data
251
134
  end
252
135
  end
253
136
 
254
- class Atom < CommandData # :nodoc:
255
- def initialize(**)
256
- super
257
- validate
137
+ class Atom # :nodoc:
138
+ def send_data(imap, tag)
139
+ imap.__send__(:put_string, @data)
258
140
  end
259
141
 
260
142
  def validate
261
- data.to_s.ascii_only? \
262
- or raise DataFormatError, "#{self.class} must be ASCII only"
263
- data.match?(ResponseParser::Patterns::ATOM_SPECIALS) \
264
- and raise DataFormatError, "#{self.class} must not contain atom-specials"
265
143
  end
266
144
 
267
- def send_data(imap, tag)
268
- imap.__send__(:put_string, data.to_s)
269
- end
270
- end
145
+ private
271
146
 
272
- class Flag < Atom # :nodoc:
273
- def send_data(imap, tag)
274
- imap.__send__(:put_string, "\\#{data}")
147
+ def initialize(data)
148
+ @data = data
275
149
  end
276
150
  end
277
151
 
@@ -291,55 +165,21 @@ module Net
291
165
  end
292
166
 
293
167
  class Literal # :nodoc:
294
- class << self
295
- def new(_data = nil, _non_sync = nil, data: _data, non_sync: _non_sync)
296
- super(data: data, non_sync: non_sync)
297
- end
298
- alias :[] :new
299
- end
300
-
301
- attr_reader :data, :non_sync
302
-
303
- def to_h(&block) block ? to_h.to_h(&block) : { data: data, non_sync: non_sync } end
304
- def ==(other) self.class === other && to_h == other.to_h end
305
- def eql?(other) self.class === other && to_h.eql?(other.to_h) end
306
-
307
- def initialize(data:, non_sync: nil)
308
- data = -String(data.to_str).b or
309
- raise DataFormatError, "#{self.class} expects string input"
310
- @data, @non_sync = data, non_sync
311
- validate
312
- freeze
313
- end
314
-
315
- def self.validate(...)
316
- data = new(...)
317
- data.validate
318
- data
168
+ def send_data(imap, tag)
169
+ imap.__send__(:send_literal, @data, tag)
319
170
  end
320
171
 
321
- def bytesize; data.bytesize end
322
-
323
172
  def validate
324
- if data.include?("\0")
325
- raise DataFormatError, "NULL byte not allowed in #{self.class}. " \
326
- "Use #{Literal8} or a null-safe encoding."
327
- end
328
173
  end
329
174
 
330
- def send_data(imap, tag)
331
- imap.__send__(:send_literal, data, tag, non_sync: non_sync)
332
- end
333
- end
334
-
335
- class Literal8 < Literal # :nodoc:
336
- def validate; nil end # all bytes are okay
175
+ private
337
176
 
338
- def send_data(imap, tag)
339
- imap.__send__(:send_binary_literal, data, tag, non_sync: non_sync)
177
+ def initialize(data)
178
+ @data = data
340
179
  end
341
180
  end
342
181
 
182
+ # *DEPRECATED*. Replaced by SequenceSet.
343
183
  class MessageSet # :nodoc:
344
184
  def send_data(imap, tag)
345
185
  imap.__send__(:put_string, format_internal(@data))
@@ -353,6 +193,16 @@ module Net
353
193
 
354
194
  def initialize(data)
355
195
  @data = data
196
+ warn("DEPRECATED: #{MessageSet} should be replaced with #{SequenceSet}.",
197
+ uplevel: 1, category: :deprecated)
198
+ begin
199
+ # to ensure the input works with SequenceSet, too
200
+ SequenceSet.new(data)
201
+ rescue
202
+ warn "MessageSet input is incompatible with SequenceSet: [%s] %s" % [
203
+ $!.class, $!.message
204
+ ]
205
+ end
356
206
  end
357
207
 
358
208
  def format_internal(data)
@@ -18,8 +18,6 @@ module Net
18
18
  super(attr)
19
19
  AttrTypeCoercion.attr_accessor(attr, type: type)
20
20
  end
21
-
22
- module_function def Integer?; NilOrInteger end
23
21
  end
24
22
  private_constant :Macros
25
23
 
@@ -28,33 +26,34 @@ module Net
28
26
  end
29
27
  private_class_method :included
30
28
 
31
- # Used in v0.5.8+ for Ractor sharability.
32
- def self.safe(...) nil.instance_eval(...).freeze end
33
- private_class_method :safe
34
-
35
- Types = Hash.new do |h, type|
36
- type.nil? || Proc === type or raise TypeError, "type not nil or Proc"
37
- safe{type}
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
38
36
  end
39
- Types[:boolean] = Boolean = safe{-> {!!_1}}
40
- Types[Integer] = safe{->{Integer(_1)}}
41
37
 
42
- def self.attr_accessor(attr, type: nil)
43
- type = Types[type] or return
44
- define_method :"#{attr}=" do |val| super type[val] end
45
- define_method :"#{attr}?" do send attr end if type == Boolean
38
+ def self.boolean(attr)
39
+ define_method :"#{attr}=" do |val| super !!val end
40
+ define_method :"#{attr}?" do send attr end
46
41
  end
47
42
 
48
- NilOrInteger = safe{->val { Integer val unless val.nil? }}
43
+ def self.integer(attr)
44
+ define_method :"#{attr}=" do |val| super Integer val end
45
+ end
49
46
 
50
- Enum = ->(*enum) {
51
- enum = safe{enum}
47
+ def self.enum(attr, enum)
48
+ enum = enum.dup.freeze
52
49
  expected = -"one of #{enum.map(&:inspect).join(", ")}"
53
- safe{->val {
54
- return val if enum.include?(val)
55
- raise ArgumentError, "expected %s, got %p" % [expected, val]
56
- }}
57
- }
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
58
57
 
59
58
  end
60
59
  end