net-imap 0.5.4 → 0.5.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a871e99f51067e3a509aa5a74fe2c49f4d79496bcec2f21ac50c3c5793d2cdbf
4
- data.tar.gz: 302c03e65954f9a118d877f97ea2296f34a7f50c8b1299e3e4f8b589cb620880
3
+ metadata.gz: c9b92943c4c4d17210f7374b4f5577f95471038a987540a8cdad2088e6bec25d
4
+ data.tar.gz: 6a28ce5ca7778cbfa3de48c3451be4d17fe6298a01e2a946725caf022a34dd8c
5
5
  SHA512:
6
- metadata.gz: 85d97c9729220265da03588f175fea22bcdd27d40cd06910ad35bc01ed64bd0c27b2769790464712572166761f3e82fc4eb6330fef64f45cceb0b3e1007f7126
7
- data.tar.gz: aa18d53b81e57ddfbdde2b8295ca7324f965fa744846fdd756ec4ca1c30e6e72092b106ff454d100f70d1078ee239f2b3e643bd4650606a2fc3b4ab5a2d0cc1f
6
+ metadata.gz: 5a575e282b7cd6828d56360003b1de29e8ca0e3d55ce733c8de250f781413dc8e9e6a90549c14b9ed21bb46e0cdc88f3e75d92aeaed769d594f93056359ee40d
7
+ data.tar.gz: 87d57464c32eab235e241c74efea7953b9798b9c40a14f66170e751560943f728aabe852d38c746283cdcb4c03914ee375021c49fec67f653113d3330a6732d2
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # Net::IMAP
2
2
 
3
3
  Net::IMAP implements Internet Message Access Protocol (IMAP) client
4
- functionality. The protocol is described in [IMAP](https://tools.ietf.org/html/rfc3501).
4
+ functionality. The protocol is described in
5
+ [RFC3501](https://www.rfc-editor.org/rfc/rfc3501),
6
+ [RFC9051](https://www.rfc-editor.org/rfc/rfc9051) and various extensions.
5
7
 
6
8
  ## Installation
7
9
 
data/docs/styles.css CHANGED
@@ -10,18 +10,28 @@ main .method-detail {
10
10
  justify-content: space-between;
11
11
  }
12
12
 
13
- main .method-header, main .method-controls {
13
+ main .method-header,
14
+ main .method-controls,
15
+ .attribute-method-heading {
14
16
  padding: 0.5em;
15
17
  /* border: 1px solid var(--highlight-color); */
16
18
  background: var(--table-header-background-color);
17
19
  line-height: 1.6;
18
20
  }
19
21
 
22
+ .attribute-method-heading .attribute-access-type {
23
+ float: right;
24
+ }
25
+
20
26
  main .method-header {
21
27
  border-right: none;
22
28
  border-radius: 4px 0 0 4px;
23
29
  }
24
30
 
31
+ main .method-heading :any-link {
32
+ text-decoration: none;
33
+ }
34
+
25
35
  main .method-controls {
26
36
  border-left: none;
27
37
  border-radius: 0 4px 4px 0;
@@ -75,7 +75,7 @@ module Net
75
75
  #
76
76
  # client = Net::IMAP.new(hostname, config: :future)
77
77
  # client.config.sasl_ir # => true
78
- # client.config.responses_without_block # => :raise
78
+ # client.config.responses_without_block # => :frozen_dup
79
79
  #
80
80
  # The versioned default configs inherit certain specific config options from
81
81
  # Config.global, for example #debug:
@@ -109,9 +109,11 @@ module Net
109
109
  # [+:future+]
110
110
  # The _planned_ eventual config for some future +x.y+ version.
111
111
  #
112
- # For example, to raise exceptions for all current deprecations:
112
+ # For example, to disable all currently deprecated behavior:
113
113
  # client = Net::IMAP.new(hostname, config: :future)
114
- # client.responses # raises an ArgumentError
114
+ # client.config.response_without_args # => :frozen_dup
115
+ # client.responses.frozen? # => true
116
+ # client.responses.values.all?(&:frozen?) # => true
115
117
  #
116
118
  # == Thread Safety
117
119
  #
@@ -29,7 +29,7 @@ module Net
29
29
  class IMAP
30
30
  data_or_object = RUBY_VERSION >= "3.2.0" ? ::Data : Object
31
31
  class DataLite < data_or_object
32
- def encode_with(coder) coder.map = attributes.transform_keys(&:to_s) end
32
+ def encode_with(coder) coder.map = to_h.transform_keys(&:to_s) end
33
33
  def init_with(coder) initialize(**coder.map.transform_keys(&:to_sym)) end
34
34
  end
35
35
 
@@ -159,28 +159,27 @@ module Net
159
159
 
160
160
  ##
161
161
  def members; self.class.members end
162
- def attributes; Hash[members.map {|m| [m, send(m)] }] end
163
- def to_h(&block) attributes.to_h(&block) end
164
- def hash; [self.class, attributes].hash end
162
+ def to_h(&block) block ? __to_h__.to_h(&block) : __to_h__ end
163
+ def hash; [self.class, __to_h__].hash end
165
164
  def ==(other) self.class == other.class && to_h == other.to_h end
166
165
  def eql?(other) self.class == other.class && hash == other.hash end
167
- def deconstruct; attributes.values end
166
+ def deconstruct; __to_h__.values end
168
167
 
169
168
  def deconstruct_keys(keys)
170
169
  raise TypeError unless keys.is_a?(Array) || keys.nil?
171
- return attributes if keys&.first.nil?
172
- attributes.slice(*keys)
170
+ return __to_h__ if keys&.first.nil?
171
+ __to_h__.slice(*keys)
173
172
  end
174
173
 
175
174
  def with(**kwargs)
176
175
  return self if kwargs.empty?
177
- self.class.new(**attributes.merge(kwargs))
176
+ self.class.new(**__to_h__.merge(kwargs))
178
177
  end
179
178
 
180
179
  def inspect
181
180
  __inspect_guard__(self) do |seen|
182
181
  return "#<data #{self.class}:...>" if seen
183
- attrs = attributes.map {|kv| "%s=%p" % kv }.join(", ")
182
+ attrs = __to_h__.map {|kv| "%s=%p" % kv }.join(", ")
184
183
  display = ["data", self.class.name, attrs].compact.join(" ")
185
184
  "#<#{display}>"
186
185
  end
@@ -190,7 +189,9 @@ module Net
190
189
  private
191
190
 
192
191
  def initialize_copy(source) super.freeze end
193
- def marshal_dump; attributes end
192
+ def marshal_dump; __to_h__ end
193
+
194
+ def __to_h__; Hash[members.map {|m| [m, send(m)] }] end
194
195
 
195
196
  # Yields +true+ if +obj+ has been seen already, +false+ if it hasn't.
196
197
  # Marks +obj+ as seen inside the block, so circuler references don't
@@ -3,9 +3,9 @@
3
3
  module Net
4
4
  class IMAP < Protocol
5
5
 
6
- # Net::IMAP::FetchData represents the contents of a FETCH response.
7
- # Net::IMAP#fetch and Net::IMAP#uid_fetch both return an array of
8
- # FetchData objects.
6
+ # Net::IMAP::FetchStruct is the superclass for FetchData and UIDFetchData.
7
+ # Net::IMAP#fetch, Net::IMAP#uid_fetch, Net::IMAP#store, and
8
+ # Net::IMAP#uid_store all return arrays of FetchStruct objects.
9
9
  #
10
10
  # === Fetch attributes
11
11
  #
@@ -63,8 +63,7 @@ module Net
63
63
  # * <b><tt>"X-GM-MSGID"</tt></b> --- unique message ID. Access via #attr.
64
64
  # * <b><tt>"X-GM-THRID"</tt></b> --- Thread ID. Access via #attr.
65
65
  #
66
- # [Note:]
67
- # >>>
66
+ # [NOTE:]
68
67
  # Additional static fields are defined in other \IMAP extensions, but
69
68
  # Net::IMAP can't parse them yet.
70
69
  #
@@ -87,34 +86,23 @@ module Net
87
86
  # extension]}[https://developers.google.com/gmail/imap/imap-extensions]
88
87
  # * <b><tt>"X-GM-LABELS"</tt></b> --- Gmail labels. Access via #attr.
89
88
  #
90
- # [Note:]
91
- # >>>
89
+ # [NOTE:]
92
90
  # Additional dynamic fields are defined in other \IMAP extensions, but
93
91
  # Net::IMAP can't parse them yet.
94
92
  #
95
93
  # === Implicitly setting <tt>\Seen</tt> and using +PEEK+
96
94
  #
97
- # Unless the mailbox is has been opened as read-only, fetching
95
+ # Unless the mailbox has been opened as read-only, fetching
98
96
  # <tt>BODY[#{section}]</tt> or <tt>BINARY[#{section}]</tt>
99
97
  # will implicitly set the <tt>\Seen</tt> flag. To avoid this, fetch using
100
98
  # <tt>BODY.PEEK[#{section}]</tt> or <tt>BINARY.PEEK[#{section}]</tt>
101
99
  # instead.
102
100
  #
103
- # Note that the data will always be _returned_ without <tt>".PEEK"</tt>, in
104
- # <tt>BODY[#{specifier}]</tt> or <tt>BINARY[#{section}]</tt>.
101
+ # [NOTE:]
102
+ # The data will always be _returned_ without the <tt>".PEEK"</tt> suffix,
103
+ # as <tt>BODY[#{specifier}]</tt> or <tt>BINARY[#{section}]</tt>.
105
104
  #
106
- class FetchData < Struct.new(:seqno, :attr)
107
- ##
108
- # method: seqno
109
- # :call-seq: seqno -> Integer
110
- #
111
- # The message sequence number.
112
- #
113
- # [Note]
114
- # This is never the unique identifier (UID), not even for the
115
- # Net::IMAP#uid_fetch result. The UID is available from #uid, if it was
116
- # returned.
117
-
105
+ class FetchStruct < Struct
118
106
  ##
119
107
  # method: attr
120
108
  # :call-seq: attr -> hash
@@ -123,9 +111,6 @@ module Net
123
111
  # corresponding data item. Standard data items have corresponding
124
112
  # accessor methods. The definitions of each attribute type is documented
125
113
  # on its accessor.
126
- #
127
- # >>>
128
- # *Note:* #seqno is not a message attribute.
129
114
 
130
115
  # :call-seq: attr_upcase -> hash
131
116
  #
@@ -142,7 +127,7 @@ module Net
142
127
  #
143
128
  # This is the same as getting the value for <tt>"BODY"</tt> from #attr.
144
129
  #
145
- # [Note]
130
+ # [NOTE:]
146
131
  # Use #message, #part, #header, #header_fields, #header_fields_not,
147
132
  # #text, or #mime to retrieve <tt>BODY[#{section_spec}]</tt> attributes.
148
133
  def body; attr["BODY"] end
@@ -235,7 +220,7 @@ module Net
235
220
  fields && except and
236
221
  raise ArgumentError, "conflicting 'fields' and 'except' arguments"
237
222
  if fields
238
- text = "HEADER.FIELDS (%s)" % [fields.join(" ").upcase]
223
+ text = "HEADER.FIELDS (%s)" % [fields.join(" ").upcase]
239
224
  attr_upcase[body_section_attr(part_nums, text, offset: offset)]
240
225
  elsif except
241
226
  text = "HEADER.FIELDS.NOT (%s)" % [except.join(" ").upcase]
@@ -308,6 +293,7 @@ module Net
308
293
  # This is the same as getting the value for <tt>"BODYSTRUCTURE"</tt> from
309
294
  # #attr.
310
295
  def bodystructure; attr["BODYSTRUCTURE"] end
296
+
311
297
  alias body_structure bodystructure
312
298
 
313
299
  # :call-seq: envelope -> Envelope or nil
@@ -320,7 +306,7 @@ module Net
320
306
  # #attr.
321
307
  def envelope; attr["ENVELOPE"] end
322
308
 
323
- # :call-seq: flags -> array of Symbols and Strings
309
+ # :call-seq: flags -> array of Symbols and Strings, or nil
324
310
  #
325
311
  # A array of flags that are set for this message. System flags are
326
312
  # symbols that have been capitalized by String#capitalize. Keyword flags
@@ -328,7 +314,7 @@ module Net
328
314
  #
329
315
  # This is the same as getting the value for <tt>"FLAGS"</tt> from #attr.
330
316
  #
331
- # [Note]
317
+ # [NOTE:]
332
318
  # The +FLAGS+ field is dynamic, and can change for a uniquely identified
333
319
  # message.
334
320
  def flags; attr["FLAGS"] end
@@ -336,40 +322,41 @@ module Net
336
322
  # :call-seq: internaldate -> Time or nil
337
323
  #
338
324
  # The internal date and time of the message on the server. This is not
339
- # the date and time in the [RFC5322[https://tools.ietf.org/html/rfc5322]]
325
+ # the date and time in the [RFC5322[https://www.rfc-editor.org/rfc/rfc5322]]
340
326
  # header, but rather a date and time which reflects when the message was
341
327
  # received.
342
328
  #
343
329
  # This is similar to getting the value for <tt>"INTERNALDATE"</tt> from
344
330
  # #attr.
345
331
  #
346
- # [Note]
332
+ # [NOTE:]
347
333
  # <tt>attr["INTERNALDATE"]</tt> returns a string, and this method
348
334
  # returns a Time object.
349
335
  def internaldate
350
336
  attr["INTERNALDATE"]&.then { IMAP.decode_time _1 }
351
337
  end
338
+
352
339
  alias internal_date internaldate
353
340
 
354
- # :call-seq: rfc822 -> String
341
+ # :call-seq: rfc822 -> String or nil
355
342
  #
356
343
  # Semantically equivalent to #message with no arguments.
357
344
  #
358
345
  # This is the same as getting the value for <tt>"RFC822"</tt> from #attr.
359
346
  #
360
- # [Note]
347
+ # [NOTE:]
361
348
  # +IMAP4rev2+ deprecates <tt>RFC822</tt>.
362
349
  def rfc822; attr["RFC822"] end
363
350
 
364
- # :call-seq: rfc822_size -> Integer
351
+ # :call-seq: rfc822_size -> Integer or nil
365
352
  #
366
- # A number expressing the [RFC5322[https://tools.ietf.org/html/rfc5322]]
353
+ # A number expressing the [RFC5322[https://www.rfc-editor.org/rfc/rfc5322]]
367
354
  # size of the message.
368
355
  #
369
356
  # This is the same as getting the value for <tt>"RFC822.SIZE"</tt> from
370
357
  # #attr.
371
358
  #
372
- # [Note]
359
+ # [NOTE:]
373
360
  # \IMAP was originally developed for the older
374
361
  # RFC822[https://www.rfc-editor.org/rfc/rfc822.html] standard, and as a
375
362
  # consequence several fetch items in \IMAP incorporate "RFC822" in their
@@ -379,34 +366,45 @@ module Net
379
366
  # interpreted as a reference to the updated
380
367
  # RFC5322[https://www.rfc-editor.org/rfc/rfc5322.html] standard.
381
368
  def rfc822_size; attr["RFC822.SIZE"] end
382
- alias size rfc822_size
383
369
 
384
- # :call-seq: rfc822_header -> String
370
+ # NOTE: a bug in rdoc 6.7 prevents us from adding a call-seq to
371
+ # rfc822_size _and_ aliasing size => rfc822_size. Is it because this
372
+ # class inherits from Struct?
373
+
374
+ # Alias for: rfc822_size
375
+ def size; rfc822_size end
376
+
377
+
378
+ # :call-seq: rfc822_header -> String or nil
385
379
  #
386
380
  # Semantically equivalent to #header, with no arguments.
387
381
  #
388
382
  # This is the same as getting the value for <tt>"RFC822.HEADER"</tt> from #attr.
389
383
  #
390
- # [Note]
384
+ # [NOTE:]
391
385
  # +IMAP4rev2+ deprecates <tt>RFC822.HEADER</tt>.
392
386
  def rfc822_header; attr["RFC822.HEADER"] end
393
387
 
394
- # :call-seq: rfc822_text -> String
388
+ # :call-seq: rfc822_text -> String or nil
395
389
  #
396
390
  # Semantically equivalent to #text, with no arguments.
397
391
  #
398
392
  # This is the same as getting the value for <tt>"RFC822.TEXT"</tt> from
399
393
  # #attr.
400
394
  #
401
- # [Note]
395
+ # [NOTE:]
402
396
  # +IMAP4rev2+ deprecates <tt>RFC822.TEXT</tt>.
403
397
  def rfc822_text; attr["RFC822.TEXT"] end
404
398
 
405
- # :call-seq: uid -> Integer
399
+ # :call-seq: uid -> Integer or nil
406
400
  #
407
401
  # A number expressing the unique identifier of the message.
408
402
  #
409
403
  # This is the same as getting the value for <tt>"UID"</tt> from #attr.
404
+ #
405
+ # [NOTE:]
406
+ # For UIDFetchData, this returns the uniqueid at the beginning of the
407
+ # +UIDFETCH+ response, _not_ the value from #attr.
410
408
  def uid; attr["UID"] end
411
409
 
412
410
  # :call-seq:
@@ -452,7 +450,7 @@ module Net
452
450
  attr[section_attr("BINARY.SIZE", part_nums)]
453
451
  end
454
452
 
455
- # :call-seq: modseq -> Integer
453
+ # :call-seq: modseq -> Integer or nil
456
454
  #
457
455
  # The modification sequence number associated with this IMAP message.
458
456
  #
@@ -461,7 +459,7 @@ module Net
461
459
  # The server must support the +CONDSTORE+ extension
462
460
  # {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
463
461
  #
464
- # [Note]
462
+ # [NOTE:]
465
463
  # The +MODSEQ+ field is dynamic, and can change for a uniquely
466
464
  # identified message.
467
465
  def modseq; attr["MODSEQ"] end
@@ -508,11 +506,92 @@ module Net
508
506
  spec = Array(part).flatten.map { Integer(_1) }
509
507
  spec << text if text
510
508
  spec = spec.join(".")
511
- if offset then "%s[%s]<%d>" % [attr, spec, Integer(offset)]
512
- else "%s[%s]" % [attr, spec]
513
- end
509
+ if offset then "%s[%s]<%d>" % [attr, spec, Integer(offset)] else "%s[%s]" % [attr, spec] end
514
510
  end
511
+ end
515
512
 
513
+ # Net::IMAP::FetchData represents the contents of a +FETCH+ response.
514
+ # Net::IMAP#fetch, Net::IMAP#uid_fetch, Net::IMAP#store, and
515
+ # Net::IMAP#uid_store all return arrays of FetchData objects, except when
516
+ # the +UIDONLY+ extension is enabled.
517
+ #
518
+ # See FetchStruct documentation for a list of standard message attributes.
519
+ class FetchData < FetchStruct.new(:seqno, :attr)
520
+ ##
521
+ # method: seqno
522
+ # :call-seq: seqno -> Integer
523
+ #
524
+ # The message sequence number.
525
+ #
526
+ # [NOTE:]
527
+ # This is not the same as the unique identifier (UID), not even for the
528
+ # Net::IMAP#uid_fetch result. The UID is available from #uid, if it was
529
+ # returned.
530
+ #
531
+ # [NOTE:]
532
+ # UIDFetchData will raise a NoMethodError.
533
+
534
+ ##
535
+ # method: attr
536
+ # :call-seq: attr -> hash
537
+ #
538
+ # Each key specifies a message attribute, and the value is the
539
+ # corresponding data item. Standard data items have corresponding
540
+ # accessor methods. The definitions of each attribute type is documented
541
+ # on its accessor.
542
+ #
543
+ # See FetchStruct documentation for message attribute accessors.
544
+ #
545
+ # [NOTE:]
546
+ # #seqno is not a message attribute.
547
+ end
548
+
549
+ # Net::IMAP::UIDFetchData represents the contents of a +UIDFETCH+ response,
550
+ # When the +UIDONLY+ extension has been enabled, Net::IMAP#uid_fetch and
551
+ # Net::IMAP#uid_store will both return an array of UIDFetchData objects.
552
+ #
553
+ # UIDFetchData contains the same message attributes as FetchData. However,
554
+ # +UIDFETCH+ responses return the UID at the beginning of the response,
555
+ # replacing FetchData#seqno. UIDFetchData never contains a message sequence
556
+ # number.
557
+ #
558
+ # See FetchStruct documentation for a list of standard message attributes.
559
+ class UIDFetchData < FetchStruct.new(:uid, :attr)
560
+ ##
561
+ # method: uid
562
+ # call-seq: uid -> Integer
563
+ #
564
+ # A number expressing the unique identifier of the message.
565
+ #
566
+ # [NOTE:]
567
+ # Although #attr may _also_ have a redundant +UID+ attribute, #uid
568
+ # returns the uniqueid at the beginning of the +UIDFETCH+ response.
569
+
570
+ ##
571
+ # method: attr
572
+ # call-seq: attr -> hash
573
+ #
574
+ # Each key specifies a message attribute, and the value is the
575
+ # corresponding data item. Standard data items have corresponding
576
+ # accessor methods. The definitions of each attribute type is documented
577
+ # on its accessor.
578
+ #
579
+ # See FetchStruct documentation for message attribute accessors.
580
+ #
581
+ # [NOTE:]
582
+ # #uid is not a message attribute. Although the server may return a
583
+ # +UID+ message attribute, it is not required to. #uid is taken from
584
+ # its corresponding +UIDFETCH+ field.
585
+
586
+ # UIDFetchData will print a warning if <tt>#attr["UID"]</tt> is present
587
+ # but not identical to #uid.
588
+ def initialize(...)
589
+ super
590
+ attr and
591
+ attr_uid = attr["UID"] and
592
+ attr_uid != uid and
593
+ warn "#{self.class} UIDs do not match (#{attr_uid} != #{uid})"
594
+ end
516
595
  end
517
596
  end
518
597
  end