net-imap 0.4.12 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +8 -1
  3. data/README.md +10 -4
  4. data/docs/styles.css +75 -14
  5. data/lib/net/imap/authenticators.rb +2 -2
  6. data/lib/net/imap/command_data.rb +61 -48
  7. data/lib/net/imap/config/attr_accessors.rb +75 -0
  8. data/lib/net/imap/config/attr_inheritance.rb +90 -0
  9. data/lib/net/imap/config/attr_type_coercion.rb +61 -0
  10. data/lib/net/imap/config.rb +470 -0
  11. data/lib/net/imap/data_encoding.rb +3 -3
  12. data/lib/net/imap/data_lite.rb +226 -0
  13. data/lib/net/imap/deprecated_client_options.rb +8 -5
  14. data/lib/net/imap/errors.rb +6 -0
  15. data/lib/net/imap/esearch_result.rb +180 -0
  16. data/lib/net/imap/fetch_data.rb +126 -47
  17. data/lib/net/imap/response_data.rb +124 -237
  18. data/lib/net/imap/response_parser/parser_utils.rb +11 -6
  19. data/lib/net/imap/response_parser.rb +187 -34
  20. data/lib/net/imap/sasl/anonymous_authenticator.rb +3 -3
  21. data/lib/net/imap/sasl/authentication_exchange.rb +52 -20
  22. data/lib/net/imap/sasl/authenticators.rb +8 -4
  23. data/lib/net/imap/sasl/client_adapter.rb +77 -26
  24. data/lib/net/imap/sasl/cram_md5_authenticator.rb +4 -4
  25. data/lib/net/imap/sasl/digest_md5_authenticator.rb +218 -56
  26. data/lib/net/imap/sasl/external_authenticator.rb +2 -2
  27. data/lib/net/imap/sasl/gs2_header.rb +7 -7
  28. data/lib/net/imap/sasl/login_authenticator.rb +4 -3
  29. data/lib/net/imap/sasl/oauthbearer_authenticator.rb +6 -6
  30. data/lib/net/imap/sasl/plain_authenticator.rb +7 -7
  31. data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
  32. data/lib/net/imap/sasl/scram_authenticator.rb +8 -8
  33. data/lib/net/imap/sasl.rb +7 -4
  34. data/lib/net/imap/sasl_adapter.rb +0 -1
  35. data/lib/net/imap/search_result.rb +2 -2
  36. data/lib/net/imap/sequence_set.rb +221 -82
  37. data/lib/net/imap/stringprep/nameprep.rb +1 -1
  38. data/lib/net/imap/stringprep/trace.rb +4 -4
  39. data/lib/net/imap/uidplus_data.rb +244 -0
  40. data/lib/net/imap/vanished_data.rb +56 -0
  41. data/lib/net/imap.rb +1010 -320
  42. data/net-imap.gemspec +3 -3
  43. data/rakelib/rfcs.rake +2 -0
  44. data/rakelib/string_prep_tables_generator.rb +2 -0
  45. metadata +12 -10
  46. data/.github/dependabot.yml +0 -6
  47. data/.github/workflows/pages.yml +0 -46
  48. data/.github/workflows/push_gem.yml +0 -48
  49. data/.github/workflows/test.yml +0 -31
  50. data/.gitignore +0 -12
  51. data/.mailmap +0 -13
@@ -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