net-imap 0.5.1 → 0.5.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/Gemfile +1 -0
- data/README.md +10 -4
- data/docs/styles.css +75 -14
- data/lib/net/imap/command_data.rb +48 -46
- data/lib/net/imap/config/attr_type_coercion.rb +20 -23
- data/lib/net/imap/config.rb +173 -21
- data/lib/net/imap/connection_state.rb +48 -0
- data/lib/net/imap/data_lite.rb +226 -0
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/esearch_result.rb +180 -0
- data/lib/net/imap/fetch_data.rb +126 -47
- data/lib/net/imap/response_data.rb +118 -144
- data/lib/net/imap/response_parser/parser_utils.rb +5 -0
- data/lib/net/imap/response_parser.rb +178 -17
- data/lib/net/imap/response_reader.rb +73 -0
- data/lib/net/imap/sasl/anonymous_authenticator.rb +3 -3
- data/lib/net/imap/sasl/cram_md5_authenticator.rb +3 -3
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +8 -8
- data/lib/net/imap/sasl/external_authenticator.rb +2 -2
- data/lib/net/imap/sasl/gs2_header.rb +7 -7
- data/lib/net/imap/sasl/login_authenticator.rb +2 -2
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +6 -6
- data/lib/net/imap/sasl/plain_authenticator.rb +7 -7
- data/lib/net/imap/sasl/scram_authenticator.rb +8 -8
- data/lib/net/imap/sasl.rb +1 -1
- data/lib/net/imap/search_result.rb +2 -2
- data/lib/net/imap/sequence_set.rb +267 -118
- data/lib/net/imap/stringprep/nameprep.rb +1 -1
- data/lib/net/imap/stringprep/trace.rb +4 -4
- data/lib/net/imap/uidplus_data.rb +244 -0
- data/lib/net/imap/vanished_data.rb +56 -0
- data/lib/net/imap.rb +911 -365
- data/rakelib/rfcs.rake +2 -0
- metadata +9 -6
data/lib/net/imap.rb
CHANGED
|
@@ -25,8 +25,8 @@ module Net
|
|
|
25
25
|
|
|
26
26
|
# Net::IMAP implements Internet Message Access Protocol (\IMAP) client
|
|
27
27
|
# functionality. The protocol is described
|
|
28
|
-
# in {IMAP4rev1 [RFC3501]}[https://
|
|
29
|
-
# and {IMAP4rev2 [RFC9051]}[https://
|
|
28
|
+
# in {IMAP4rev1 [RFC3501]}[https://www.rfc-editor.org/rfc/rfc3501]
|
|
29
|
+
# and {IMAP4rev2 [RFC9051]}[https://www.rfc-editor.org/rfc/rfc9051].
|
|
30
30
|
#
|
|
31
31
|
# == \IMAP Overview
|
|
32
32
|
#
|
|
@@ -43,10 +43,18 @@ module Net
|
|
|
43
43
|
# To work on the messages within a mailbox, the client must
|
|
44
44
|
# first select that mailbox, using either #select or #examine
|
|
45
45
|
# (for read-only access). Once the client has successfully
|
|
46
|
-
# selected a mailbox, they enter the
|
|
46
|
+
# selected a mailbox, they enter the +selected+ state, and that
|
|
47
47
|
# mailbox becomes the _current_ mailbox, on which mail-item
|
|
48
48
|
# related commands implicitly operate.
|
|
49
49
|
#
|
|
50
|
+
# === Connection state
|
|
51
|
+
#
|
|
52
|
+
# Once an IMAP connection is established, the connection is in one of four
|
|
53
|
+
# states: <tt>not authenticated</tt>, +authenticated+, +selected+, and
|
|
54
|
+
# +logout+. Most commands are valid only in certain states.
|
|
55
|
+
#
|
|
56
|
+
# See #connection_state.
|
|
57
|
+
#
|
|
50
58
|
# === Sequence numbers and UIDs
|
|
51
59
|
#
|
|
52
60
|
# Messages have two sorts of identifiers: message sequence
|
|
@@ -199,6 +207,42 @@ module Net
|
|
|
199
207
|
#
|
|
200
208
|
# This script invokes the FETCH command and the SEARCH command concurrently.
|
|
201
209
|
#
|
|
210
|
+
# When running multiple commands, care must be taken to avoid ambiguity. For
|
|
211
|
+
# example, SEARCH responses are ambiguous about which command they are
|
|
212
|
+
# responding to, so search commands should not run simultaneously, unless the
|
|
213
|
+
# server supports +ESEARCH+ {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731] or
|
|
214
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]. See {RFC9051
|
|
215
|
+
# §5.5}[https://www.rfc-editor.org/rfc/rfc9051.html#section-5.5] for
|
|
216
|
+
# other examples of command sequences which should not be pipelined.
|
|
217
|
+
#
|
|
218
|
+
# == Unbounded memory use
|
|
219
|
+
#
|
|
220
|
+
# Net::IMAP reads server responses in a separate receiver thread per client.
|
|
221
|
+
# Unhandled response data is saved to #responses, and response_handlers run
|
|
222
|
+
# inside the receiver thread. See the list of methods for {handling server
|
|
223
|
+
# responses}[rdoc-ref:Net::IMAP@Handling+server+responses], below.
|
|
224
|
+
#
|
|
225
|
+
# Because the receiver thread continuously reads and saves new responses, some
|
|
226
|
+
# scenarios must be careful to avoid unbounded memory use:
|
|
227
|
+
#
|
|
228
|
+
# * Commands such as #list or #fetch can have an enormous number of responses.
|
|
229
|
+
# * Commands such as #fetch can result in an enormous size per response.
|
|
230
|
+
# * Long-lived connections will gradually accumulate unsolicited server
|
|
231
|
+
# responses, especially +EXISTS+, +FETCH+, and +EXPUNGE+ responses.
|
|
232
|
+
# * A buggy or untrusted server could send inappropriate responses, which
|
|
233
|
+
# could be very numerous, very large, and very rapid.
|
|
234
|
+
#
|
|
235
|
+
# Use paginated or limited versions of commands whenever possible.
|
|
236
|
+
#
|
|
237
|
+
# Use Config#max_response_size to impose a limit on incoming server responses
|
|
238
|
+
# as they are being read. <em>This is especially important for untrusted
|
|
239
|
+
# servers.</em>
|
|
240
|
+
#
|
|
241
|
+
# Use #add_response_handler to handle responses after each one is received.
|
|
242
|
+
# Use the +response_handlers+ argument to ::new to assign response handlers
|
|
243
|
+
# before the receiver thread is started. Use #extract_responses,
|
|
244
|
+
# #clear_responses, or #responses (with a block) to prune responses.
|
|
245
|
+
#
|
|
202
246
|
# == Errors
|
|
203
247
|
#
|
|
204
248
|
# An \IMAP server can send three different types of responses to indicate
|
|
@@ -260,8 +304,9 @@ module Net
|
|
|
260
304
|
#
|
|
261
305
|
# - Net::IMAP.new: Creates a new \IMAP client which connects immediately and
|
|
262
306
|
# waits for a successful server greeting before the method returns.
|
|
307
|
+
# - #connection_state: Returns the connection state.
|
|
263
308
|
# - #starttls: Asks the server to upgrade a clear-text connection to use TLS.
|
|
264
|
-
# - #logout: Tells the server to end the session.
|
|
309
|
+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
|
265
310
|
# - #disconnect: Disconnects the connection (without sending #logout first).
|
|
266
311
|
# - #disconnected?: True if the connection has been closed.
|
|
267
312
|
#
|
|
@@ -299,15 +344,15 @@ module Net
|
|
|
299
344
|
# === Core \IMAP commands
|
|
300
345
|
#
|
|
301
346
|
# The following commands are defined either by
|
|
302
|
-
# the [IMAP4rev1[https://
|
|
347
|
+
# the [IMAP4rev1[https://www.rfc-editor.org/rfc/rfc3501]] base specification, or
|
|
303
348
|
# by one of the following extensions:
|
|
304
|
-
# [IDLE[https://
|
|
305
|
-
# [NAMESPACE[https://
|
|
306
|
-
# [UNSELECT[https://
|
|
307
|
-
# [ENABLE[https://
|
|
308
|
-
# [MOVE[https://
|
|
349
|
+
# [IDLE[https://www.rfc-editor.org/rfc/rfc2177]],
|
|
350
|
+
# [NAMESPACE[https://www.rfc-editor.org/rfc/rfc2342]],
|
|
351
|
+
# [UNSELECT[https://www.rfc-editor.org/rfc/rfc3691]],
|
|
352
|
+
# [ENABLE[https://www.rfc-editor.org/rfc/rfc5161]],
|
|
353
|
+
# [MOVE[https://www.rfc-editor.org/rfc/rfc6851]].
|
|
309
354
|
# These extensions are widely supported by modern IMAP4rev1 servers and have
|
|
310
|
-
# all been integrated into [IMAP4rev2[https://
|
|
355
|
+
# all been integrated into [IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]].
|
|
311
356
|
# <em>*NOTE:* Net::IMAP doesn't support IMAP4rev2 yet.</em>
|
|
312
357
|
#
|
|
313
358
|
# ==== Any state
|
|
@@ -317,37 +362,36 @@ module Net
|
|
|
317
362
|
# <em>In general, #capable? should be used rather than explicitly sending a
|
|
318
363
|
# +CAPABILITY+ command to the server.</em>
|
|
319
364
|
# - #noop: Allows the server to send unsolicited untagged #responses.
|
|
320
|
-
# - #logout: Tells the server to end the session. Enters the
|
|
365
|
+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
|
321
366
|
#
|
|
322
367
|
# ==== Not Authenticated state
|
|
323
368
|
#
|
|
324
369
|
# In addition to the commands for any state, the following commands are valid
|
|
325
|
-
# in the
|
|
370
|
+
# in the +not_authenticated+ state:
|
|
326
371
|
#
|
|
327
372
|
# - #starttls: Upgrades a clear-text connection to use TLS.
|
|
328
373
|
#
|
|
329
374
|
# <em>Requires the +STARTTLS+ capability.</em>
|
|
330
375
|
# - #authenticate: Identifies the client to the server using the given
|
|
331
376
|
# {SASL mechanism}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
|
|
332
|
-
# and credentials. Enters the
|
|
377
|
+
# and credentials. Enters the +authenticated+ state.
|
|
333
378
|
#
|
|
334
379
|
# <em>The server should list <tt>"AUTH=#{mechanism}"</tt> capabilities for
|
|
335
380
|
# supported mechanisms.</em>
|
|
336
381
|
# - #login: Identifies the client to the server using a plain text password.
|
|
337
|
-
# Using #authenticate is
|
|
338
|
-
# state.
|
|
382
|
+
# Using #authenticate is preferred. Enters the +authenticated+ state.
|
|
339
383
|
#
|
|
340
384
|
# <em>The +LOGINDISABLED+ capability</em> <b>must NOT</b> <em>be listed.</em>
|
|
341
385
|
#
|
|
342
386
|
# ==== Authenticated state
|
|
343
387
|
#
|
|
344
388
|
# In addition to the commands for any state, the following commands are valid
|
|
345
|
-
# in the
|
|
389
|
+
# in the +authenticated+ state:
|
|
346
390
|
#
|
|
347
391
|
# - #enable: Enables backwards incompatible server extensions.
|
|
348
392
|
# <em>Requires the +ENABLE+ or +IMAP4rev2+ capability.</em>
|
|
349
|
-
# - #select: Open a mailbox and enter the
|
|
350
|
-
# - #examine: Open a mailbox read-only, and enter the
|
|
393
|
+
# - #select: Open a mailbox and enter the +selected+ state.
|
|
394
|
+
# - #examine: Open a mailbox read-only, and enter the +selected+ state.
|
|
351
395
|
# - #create: Creates a new mailbox.
|
|
352
396
|
# - #delete: Permanently remove a mailbox.
|
|
353
397
|
# - #rename: Change the name of a mailbox.
|
|
@@ -369,12 +413,12 @@ module Net
|
|
|
369
413
|
#
|
|
370
414
|
# ==== Selected state
|
|
371
415
|
#
|
|
372
|
-
# In addition to the commands for any state and the
|
|
373
|
-
# commands, the following commands are valid in the
|
|
416
|
+
# In addition to the commands for any state and the +authenticated+
|
|
417
|
+
# commands, the following commands are valid in the +selected+ state:
|
|
374
418
|
#
|
|
375
|
-
# - #close: Closes the mailbox and returns to the
|
|
419
|
+
# - #close: Closes the mailbox and returns to the +authenticated+ state,
|
|
376
420
|
# expunging deleted messages, unless the mailbox was opened as read-only.
|
|
377
|
-
# - #unselect: Closes the mailbox and returns to the
|
|
421
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
|
378
422
|
# without expunging any messages.
|
|
379
423
|
# <em>Requires the +UNSELECT+ or +IMAP4rev2+ capability.</em>
|
|
380
424
|
# - #expunge: Permanently removes messages which have the Deleted flag set.
|
|
@@ -395,7 +439,7 @@ module Net
|
|
|
395
439
|
#
|
|
396
440
|
# ==== Logout state
|
|
397
441
|
#
|
|
398
|
-
# No \IMAP commands are valid in the
|
|
442
|
+
# No \IMAP commands are valid in the +logout+ state. If the socket is still
|
|
399
443
|
# open, Net::IMAP will close it after receiving server confirmation.
|
|
400
444
|
# Exceptions will be raised by \IMAP commands that have already started and
|
|
401
445
|
# are waiting for a response, as well as any that are called after logout.
|
|
@@ -404,7 +448,7 @@ module Net
|
|
|
404
448
|
#
|
|
405
449
|
# ==== RFC9051: +IMAP4rev2+
|
|
406
450
|
#
|
|
407
|
-
# Although IMAP4rev2[https://
|
|
451
|
+
# Although IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] is not supported
|
|
408
452
|
# yet, Net::IMAP supports several extensions that have been folded into it:
|
|
409
453
|
# +ENABLE+, +IDLE+, +MOVE+, +NAMESPACE+, +SASL-IR+, +UIDPLUS+, +UNSELECT+,
|
|
410
454
|
# <tt>STATUS=SIZE</tt>, and the fetch side of +BINARY+.
|
|
@@ -414,7 +458,7 @@ module Net
|
|
|
414
458
|
# >>>
|
|
415
459
|
# <em>The following are folded into +IMAP4rev2+ but are currently
|
|
416
460
|
# unsupported or incompletely supported by</em> Net::IMAP<em>: RFC4466
|
|
417
|
-
# extensions, +
|
|
461
|
+
# extensions, +SEARCHRES+, +LIST-EXTENDED+, +LIST-STATUS+,
|
|
418
462
|
# +LITERAL-+, and +SPECIAL-USE+.</em>
|
|
419
463
|
#
|
|
420
464
|
# ==== RFC2087: +QUOTA+
|
|
@@ -424,13 +468,13 @@ module Net
|
|
|
424
468
|
# - #setquota: sets the resource limits for a given quota root.
|
|
425
469
|
#
|
|
426
470
|
# ==== RFC2177: +IDLE+
|
|
427
|
-
# Folded into IMAP4rev2[https://
|
|
471
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
428
472
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
429
473
|
# - #idle: Allows the server to send updates to the client, without the client
|
|
430
474
|
# needing to poll using #noop.
|
|
431
475
|
#
|
|
432
476
|
# ==== RFC2342: +NAMESPACE+
|
|
433
|
-
# Folded into IMAP4rev2[https://
|
|
477
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
434
478
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
435
479
|
# - #namespace: Returns mailbox namespaces, with path prefixes and delimiters.
|
|
436
480
|
#
|
|
@@ -439,7 +483,7 @@ module Net
|
|
|
439
483
|
#
|
|
440
484
|
# ==== RFC3516: +BINARY+
|
|
441
485
|
# The fetch side of +BINARY+ has been folded into
|
|
442
|
-
# IMAP4rev2[https://
|
|
486
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
|
|
443
487
|
# - Updates #fetch and #uid_fetch with the +BINARY+, +BINARY.PEEK+, and
|
|
444
488
|
# +BINARY.SIZE+ items. See FetchData#binary and FetchData#binary_size.
|
|
445
489
|
#
|
|
@@ -447,9 +491,9 @@ module Net
|
|
|
447
491
|
# *NOTE:* The binary extension the #append command is _not_ supported yet.
|
|
448
492
|
#
|
|
449
493
|
# ==== RFC3691: +UNSELECT+
|
|
450
|
-
# Folded into IMAP4rev2[https://
|
|
494
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
451
495
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
452
|
-
# - #unselect: Closes the mailbox and returns to the
|
|
496
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
|
453
497
|
# without expunging any messages.
|
|
454
498
|
#
|
|
455
499
|
# ==== RFC4314: +ACL+
|
|
@@ -459,19 +503,23 @@ module Net
|
|
|
459
503
|
# *NOTE:* +DELETEACL+, +LISTRIGHTS+, and +MYRIGHTS+ are not supported yet.
|
|
460
504
|
#
|
|
461
505
|
# ==== RFC4315: +UIDPLUS+
|
|
462
|
-
# Folded into IMAP4rev2[https://
|
|
506
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
463
507
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
464
508
|
# - #uid_expunge: Restricts #expunge to only remove the specified UIDs.
|
|
465
509
|
# - Updates #select, #examine with the +UIDNOTSTICKY+ ResponseCode
|
|
466
510
|
# - Updates #append with the +APPENDUID+ ResponseCode
|
|
467
511
|
# - Updates #copy, #move with the +COPYUID+ ResponseCode
|
|
468
512
|
#
|
|
513
|
+
# ==== RFC4731: +ESEARCH+
|
|
514
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
|
|
515
|
+
# - Updates #search, #uid_search with +return+ options and ESearchResult.
|
|
516
|
+
#
|
|
469
517
|
# ==== RFC4959: +SASL-IR+
|
|
470
|
-
# Folded into IMAP4rev2[https://
|
|
518
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051].
|
|
471
519
|
# - Updates #authenticate with the option to send an initial response.
|
|
472
520
|
#
|
|
473
521
|
# ==== RFC5161: +ENABLE+
|
|
474
|
-
# Folded into IMAP4rev2[https://
|
|
522
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
475
523
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
476
524
|
# - #enable: Enables backwards incompatible server extensions.
|
|
477
525
|
#
|
|
@@ -495,7 +543,7 @@ module Net
|
|
|
495
543
|
# +X-GM-THRID+, but Gmail does not support it (as of 2023-11-10).
|
|
496
544
|
#
|
|
497
545
|
# ==== RFC6851: +MOVE+
|
|
498
|
-
# Folded into IMAP4rev2[https://
|
|
546
|
+
# Folded into IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051] and also included
|
|
499
547
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
500
548
|
# - #move, #uid_move: Moves the specified messages to the end of the
|
|
501
549
|
# specified destination mailbox, expunging them from the current mailbox.
|
|
@@ -530,6 +578,17 @@ module Net
|
|
|
530
578
|
# See FetchData#emailid and FetchData#emailid.
|
|
531
579
|
# - Updates #status with support for the +MAILBOXID+ status attribute.
|
|
532
580
|
#
|
|
581
|
+
# ==== RFC9394: +PARTIAL+
|
|
582
|
+
# - Updates #search, #uid_search with the +PARTIAL+ return option which adds
|
|
583
|
+
# ESearchResult#partial return data.
|
|
584
|
+
# - Updates #uid_fetch with the +partial+ modifier.
|
|
585
|
+
#
|
|
586
|
+
# ==== RFC9586: +UIDONLY+
|
|
587
|
+
# - Updates #enable with +UIDONLY+ parameter.
|
|
588
|
+
# - Updates #uid_fetch and #uid_store to return +UIDFETCH+ response.
|
|
589
|
+
# - Updates #expunge and #uid_expunge to return +VANISHED+ response.
|
|
590
|
+
# - Prohibits use of message sequence numbers in responses or requests.
|
|
591
|
+
#
|
|
533
592
|
# == References
|
|
534
593
|
#
|
|
535
594
|
# [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501.html]]::
|
|
@@ -560,57 +619,57 @@ module Net
|
|
|
560
619
|
# Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC 2180, DOI
|
|
561
620
|
# 10.17487/RFC2180, July 1997, <https://www.rfc-editor.org/info/rfc2180>.
|
|
562
621
|
#
|
|
563
|
-
# [UTF7[https://
|
|
622
|
+
# [UTF7[https://www.rfc-editor.org/rfc/rfc2152]]::
|
|
564
623
|
# Goldsmith, D. and M. Davis, "UTF-7 A Mail-Safe Transformation Format of
|
|
565
624
|
# Unicode", RFC 2152, DOI 10.17487/RFC2152, May 1997,
|
|
566
625
|
# <https://www.rfc-editor.org/info/rfc2152>.
|
|
567
626
|
#
|
|
568
627
|
# === Message envelope and body structure
|
|
569
628
|
#
|
|
570
|
-
# [RFC5322[https://
|
|
629
|
+
# [RFC5322[https://www.rfc-editor.org/rfc/rfc5322]]::
|
|
571
630
|
# Resnick, P., Ed., "Internet Message Format",
|
|
572
631
|
# RFC 5322, DOI 10.17487/RFC5322, October 2008,
|
|
573
632
|
# <https://www.rfc-editor.org/info/rfc5322>.
|
|
574
633
|
#
|
|
575
634
|
# <em>Note: obsoletes</em>
|
|
576
|
-
# RFC-2822[https://
|
|
577
|
-
# RFC-822[https://
|
|
635
|
+
# RFC-2822[https://www.rfc-editor.org/rfc/rfc2822]<em> (April 2001) and</em>
|
|
636
|
+
# RFC-822[https://www.rfc-editor.org/rfc/rfc822]<em> (August 1982).</em>
|
|
578
637
|
#
|
|
579
|
-
# [CHARSET[https://
|
|
638
|
+
# [CHARSET[https://www.rfc-editor.org/rfc/rfc2978]]::
|
|
580
639
|
# Freed, N. and J. Postel, "IANA Charset Registration Procedures", BCP 19,
|
|
581
640
|
# RFC 2978, DOI 10.17487/RFC2978, October 2000,
|
|
582
641
|
# <https://www.rfc-editor.org/info/rfc2978>.
|
|
583
642
|
#
|
|
584
|
-
# [DISPOSITION[https://
|
|
643
|
+
# [DISPOSITION[https://www.rfc-editor.org/rfc/rfc2183]]::
|
|
585
644
|
# Troost, R., Dorner, S., and K. Moore, Ed., "Communicating Presentation
|
|
586
645
|
# Information in Internet Messages: The Content-Disposition Header
|
|
587
646
|
# Field", RFC 2183, DOI 10.17487/RFC2183, August 1997,
|
|
588
647
|
# <https://www.rfc-editor.org/info/rfc2183>.
|
|
589
648
|
#
|
|
590
|
-
# [MIME-IMB[https://
|
|
649
|
+
# [MIME-IMB[https://www.rfc-editor.org/rfc/rfc2045]]::
|
|
591
650
|
# Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions
|
|
592
651
|
# (MIME) Part One: Format of Internet Message Bodies",
|
|
593
652
|
# RFC 2045, DOI 10.17487/RFC2045, November 1996,
|
|
594
653
|
# <https://www.rfc-editor.org/info/rfc2045>.
|
|
595
654
|
#
|
|
596
|
-
# [MIME-IMT[https://
|
|
655
|
+
# [MIME-IMT[https://www.rfc-editor.org/rfc/rfc2046]]::
|
|
597
656
|
# Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions
|
|
598
657
|
# (MIME) Part Two: Media Types", RFC 2046, DOI 10.17487/RFC2046,
|
|
599
658
|
# November 1996, <https://www.rfc-editor.org/info/rfc2046>.
|
|
600
659
|
#
|
|
601
|
-
# [MIME-HDRS[https://
|
|
660
|
+
# [MIME-HDRS[https://www.rfc-editor.org/rfc/rfc2047]]::
|
|
602
661
|
# Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Three:
|
|
603
662
|
# Message Header Extensions for Non-ASCII Text",
|
|
604
663
|
# RFC 2047, DOI 10.17487/RFC2047, November 1996,
|
|
605
664
|
# <https://www.rfc-editor.org/info/rfc2047>.
|
|
606
665
|
#
|
|
607
|
-
# [RFC2231[https://
|
|
666
|
+
# [RFC2231[https://www.rfc-editor.org/rfc/rfc2231]]::
|
|
608
667
|
# Freed, N. and K. Moore, "MIME Parameter Value and Encoded Word
|
|
609
668
|
# Extensions: Character Sets, Languages, and Continuations",
|
|
610
669
|
# RFC 2231, DOI 10.17487/RFC2231, November 1997,
|
|
611
670
|
# <https://www.rfc-editor.org/info/rfc2231>.
|
|
612
671
|
#
|
|
613
|
-
# [I18n-HDRS[https://
|
|
672
|
+
# [I18n-HDRS[https://www.rfc-editor.org/rfc/rfc6532]]::
|
|
614
673
|
# Yang, A., Steele, S., and N. Freed, "Internationalized Email Headers",
|
|
615
674
|
# RFC 6532, DOI 10.17487/RFC6532, February 2012,
|
|
616
675
|
# <https://www.rfc-editor.org/info/rfc6532>.
|
|
@@ -626,12 +685,12 @@ module Net
|
|
|
626
685
|
# RFC 2557, DOI 10.17487/RFC2557, March 1999,
|
|
627
686
|
# <https://www.rfc-editor.org/info/rfc2557>.
|
|
628
687
|
#
|
|
629
|
-
# [MD5[https://
|
|
688
|
+
# [MD5[https://www.rfc-editor.org/rfc/rfc1864]]::
|
|
630
689
|
# Myers, J. and M. Rose, "The Content-MD5 Header Field",
|
|
631
690
|
# RFC 1864, DOI 10.17487/RFC1864, October 1995,
|
|
632
691
|
# <https://www.rfc-editor.org/info/rfc1864>.
|
|
633
692
|
#
|
|
634
|
-
# [RFC3503[https://
|
|
693
|
+
# [RFC3503[https://www.rfc-editor.org/rfc/rfc3503]]::
|
|
635
694
|
# Melnikov, A., "Message Disposition Notification (MDN)
|
|
636
695
|
# profile for Internet Message Access Protocol (IMAP)",
|
|
637
696
|
# RFC 3503, DOI 10.17487/RFC3503, March 2003,
|
|
@@ -639,27 +698,27 @@ module Net
|
|
|
639
698
|
#
|
|
640
699
|
# === \IMAP Extensions
|
|
641
700
|
#
|
|
642
|
-
# [QUOTA[https://
|
|
701
|
+
# [QUOTA[https://www.rfc-editor.org/rfc/rfc9208]]::
|
|
643
702
|
# Melnikov, A., "IMAP QUOTA Extension", RFC 9208, DOI 10.17487/RFC9208,
|
|
644
703
|
# March 2022, <https://www.rfc-editor.org/info/rfc9208>.
|
|
645
704
|
#
|
|
646
705
|
# <em>Note: obsoletes</em>
|
|
647
|
-
# RFC-2087[https://
|
|
706
|
+
# RFC-2087[https://www.rfc-editor.org/rfc/rfc2087]<em> (January 1997)</em>.
|
|
648
707
|
# <em>Net::IMAP does not fully support the RFC9208 updates yet.</em>
|
|
649
|
-
# [IDLE[https://
|
|
708
|
+
# [IDLE[https://www.rfc-editor.org/rfc/rfc2177]]::
|
|
650
709
|
# Leiba, B., "IMAP4 IDLE command", RFC 2177, DOI 10.17487/RFC2177,
|
|
651
710
|
# June 1997, <https://www.rfc-editor.org/info/rfc2177>.
|
|
652
|
-
# [NAMESPACE[https://
|
|
711
|
+
# [NAMESPACE[https://www.rfc-editor.org/rfc/rfc2342]]::
|
|
653
712
|
# Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342,
|
|
654
713
|
# DOI 10.17487/RFC2342, May 1998, <https://www.rfc-editor.org/info/rfc2342>.
|
|
655
|
-
# [ID[https://
|
|
714
|
+
# [ID[https://www.rfc-editor.org/rfc/rfc2971]]::
|
|
656
715
|
# Showalter, T., "IMAP4 ID extension", RFC 2971, DOI 10.17487/RFC2971,
|
|
657
716
|
# October 2000, <https://www.rfc-editor.org/info/rfc2971>.
|
|
658
|
-
# [BINARY[https://
|
|
717
|
+
# [BINARY[https://www.rfc-editor.org/rfc/rfc3516]]::
|
|
659
718
|
# Nerenberg, L., "IMAP4 Binary Content Extension", RFC 3516,
|
|
660
719
|
# DOI 10.17487/RFC3516, April 2003,
|
|
661
720
|
# <https://www.rfc-editor.org/info/rfc3516>.
|
|
662
|
-
# [ACL[https://
|
|
721
|
+
# [ACL[https://www.rfc-editor.org/rfc/rfc4314]]::
|
|
663
722
|
# Melnikov, A., "IMAP4 Access Control List (ACL) Extension", RFC 4314,
|
|
664
723
|
# DOI 10.17487/RFC4314, December 2005,
|
|
665
724
|
# <https://www.rfc-editor.org/info/rfc4314>.
|
|
@@ -667,36 +726,46 @@ module Net
|
|
|
667
726
|
# Crispin, M., "Internet Message Access Protocol (\IMAP) - UIDPLUS
|
|
668
727
|
# extension", RFC 4315, DOI 10.17487/RFC4315, December 2005,
|
|
669
728
|
# <https://www.rfc-editor.org/info/rfc4315>.
|
|
670
|
-
# [SORT[https://
|
|
729
|
+
# [SORT[https://www.rfc-editor.org/rfc/rfc5256]]::
|
|
671
730
|
# Crispin, M. and K. Murchison, "Internet Message Access Protocol - SORT and
|
|
672
731
|
# THREAD Extensions", RFC 5256, DOI 10.17487/RFC5256, June 2008,
|
|
673
732
|
# <https://www.rfc-editor.org/info/rfc5256>.
|
|
674
|
-
# [THREAD[https://
|
|
733
|
+
# [THREAD[https://www.rfc-editor.org/rfc/rfc5256]]::
|
|
675
734
|
# Crispin, M. and K. Murchison, "Internet Message Access Protocol - SORT and
|
|
676
735
|
# THREAD Extensions", RFC 5256, DOI 10.17487/RFC5256, June 2008,
|
|
677
736
|
# <https://www.rfc-editor.org/info/rfc5256>.
|
|
678
737
|
# [RFC5530[https://www.rfc-editor.org/rfc/rfc5530.html]]::
|
|
679
738
|
# Gulbrandsen, A., "IMAP Response Codes", RFC 5530, DOI 10.17487/RFC5530,
|
|
680
739
|
# May 2009, <https://www.rfc-editor.org/info/rfc5530>.
|
|
681
|
-
# [MOVE[https://
|
|
740
|
+
# [MOVE[https://www.rfc-editor.org/rfc/rfc6851]]::
|
|
682
741
|
# Gulbrandsen, A. and N. Freed, Ed., "Internet Message Access Protocol
|
|
683
742
|
# (\IMAP) - MOVE Extension", RFC 6851, DOI 10.17487/RFC6851, January 2013,
|
|
684
743
|
# <https://www.rfc-editor.org/info/rfc6851>.
|
|
685
|
-
# [UTF8=ACCEPT[https://
|
|
686
|
-
# [UTF8=ONLY[https://
|
|
744
|
+
# [UTF8=ACCEPT[https://www.rfc-editor.org/rfc/rfc6855]]::
|
|
745
|
+
# [UTF8=ONLY[https://www.rfc-editor.org/rfc/rfc6855]]::
|
|
687
746
|
# Resnick, P., Ed., Newman, C., Ed., and S. Shen, Ed.,
|
|
688
747
|
# "IMAP Support for UTF-8", RFC 6855, DOI 10.17487/RFC6855, March 2013,
|
|
689
748
|
# <https://www.rfc-editor.org/info/rfc6855>.
|
|
690
|
-
# [CONDSTORE[https://
|
|
691
|
-
# [QRESYNC[https://
|
|
749
|
+
# [CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162]]::
|
|
750
|
+
# [QRESYNC[https://www.rfc-editor.org/rfc/rfc7162]]::
|
|
692
751
|
# Melnikov, A. and D. Cridland, "IMAP Extensions: Quick Flag Changes
|
|
693
752
|
# Resynchronization (CONDSTORE) and Quick Mailbox Resynchronization
|
|
694
753
|
# (QRESYNC)", RFC 7162, DOI 10.17487/RFC7162, May 2014,
|
|
695
754
|
# <https://www.rfc-editor.org/info/rfc7162>.
|
|
696
|
-
# [OBJECTID[https://
|
|
755
|
+
# [OBJECTID[https://www.rfc-editor.org/rfc/rfc8474]]::
|
|
697
756
|
# Gondwana, B., Ed., "IMAP Extension for Object Identifiers",
|
|
698
757
|
# RFC 8474, DOI 10.17487/RFC8474, September 2018,
|
|
699
758
|
# <https://www.rfc-editor.org/info/rfc8474>.
|
|
759
|
+
# [PARTIAL[https://www.rfc-editor.org/info/rfc9394]]::
|
|
760
|
+
# Melnikov, A., Achuthan, A., Nagulakonda, V., and L. Alves,
|
|
761
|
+
# "IMAP PARTIAL Extension for Paged SEARCH and FETCH", RFC 9394,
|
|
762
|
+
# DOI 10.17487/RFC9394, June 2023,
|
|
763
|
+
# <https://www.rfc-editor.org/info/rfc9394>.
|
|
764
|
+
# [UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.pdf]]::
|
|
765
|
+
# Melnikov, A., Achuthan, A., Nagulakonda, V., Singh, A., and L. Alves,
|
|
766
|
+
# "\IMAP Extension for Using and Returning Unique Identifiers (UIDs) Only",
|
|
767
|
+
# RFC 9586, DOI 10.17487/RFC9586, May 2024,
|
|
768
|
+
# <https://www.rfc-editor.org/info/rfc9586>.
|
|
700
769
|
#
|
|
701
770
|
# === IANA registries
|
|
702
771
|
# * {IMAP Capabilities}[http://www.iana.org/assignments/imap4-capabilities]
|
|
@@ -710,7 +779,7 @@ module Net
|
|
|
710
779
|
# * {GSSAPI/Kerberos/SASL Service Names}[https://www.iana.org/assignments/gssapi-service-names/gssapi-service-names.xhtml]:
|
|
711
780
|
# +imap+
|
|
712
781
|
# * {Character sets}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
|
|
713
|
-
#
|
|
782
|
+
# ==== For currently unsupported features:
|
|
714
783
|
# * {IMAP Quota Resource Types}[http://www.iana.org/assignments/imap4-capabilities#imap-capabilities-2]
|
|
715
784
|
# * {LIST-EXTENDED options and responses}[https://www.iana.org/assignments/imap-list-extended/imap-list-extended.xhtml]
|
|
716
785
|
# * {IMAP METADATA Server Entry and Mailbox Entry Registries}[https://www.iana.org/assignments/imap-metadata/imap-metadata.xhtml]
|
|
@@ -719,7 +788,7 @@ module Net
|
|
|
719
788
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
|
720
789
|
#
|
|
721
790
|
class IMAP < Protocol
|
|
722
|
-
VERSION = "0.5.
|
|
791
|
+
VERSION = "0.5.7"
|
|
723
792
|
|
|
724
793
|
# Aliases for supported capabilities, to be used with the #enable command.
|
|
725
794
|
ENABLE_ALIASES = {
|
|
@@ -727,9 +796,12 @@ module Net
|
|
|
727
796
|
"UTF8=ONLY" => "UTF8=ACCEPT",
|
|
728
797
|
}.freeze
|
|
729
798
|
|
|
730
|
-
|
|
731
|
-
autoload :
|
|
732
|
-
autoload :
|
|
799
|
+
dir = File.expand_path("imap", __dir__)
|
|
800
|
+
autoload :ConnectionState, "#{dir}/connection_state"
|
|
801
|
+
autoload :ResponseReader, "#{dir}/response_reader"
|
|
802
|
+
autoload :SASL, "#{dir}/sasl"
|
|
803
|
+
autoload :SASLAdapter, "#{dir}/sasl_adapter"
|
|
804
|
+
autoload :StringPrep, "#{dir}/stringprep"
|
|
733
805
|
|
|
734
806
|
include MonitorMixin
|
|
735
807
|
if defined?(OpenSSL::SSL)
|
|
@@ -741,9 +813,11 @@ module Net
|
|
|
741
813
|
def self.config; Config.global end
|
|
742
814
|
|
|
743
815
|
# Returns the global debug mode.
|
|
816
|
+
# Delegates to {Net::IMAP.config.debug}[rdoc-ref:Config#debug].
|
|
744
817
|
def self.debug; config.debug end
|
|
745
818
|
|
|
746
819
|
# Sets the global debug mode.
|
|
820
|
+
# Delegates to {Net::IMAP.config.debug=}[rdoc-ref:Config#debug=].
|
|
747
821
|
def self.debug=(val)
|
|
748
822
|
config.debug = val
|
|
749
823
|
end
|
|
@@ -764,7 +838,7 @@ module Net
|
|
|
764
838
|
alias default_ssl_port default_tls_port
|
|
765
839
|
end
|
|
766
840
|
|
|
767
|
-
# Returns the initial greeting the server, an UntaggedResponse.
|
|
841
|
+
# Returns the initial greeting sent by the server, an UntaggedResponse.
|
|
768
842
|
attr_reader :greeting
|
|
769
843
|
|
|
770
844
|
# The client configuration. See Net::IMAP::Config.
|
|
@@ -773,13 +847,28 @@ module Net
|
|
|
773
847
|
# Net::IMAP.config.
|
|
774
848
|
attr_reader :config
|
|
775
849
|
|
|
776
|
-
|
|
777
|
-
#
|
|
778
|
-
#
|
|
779
|
-
|
|
850
|
+
##
|
|
851
|
+
# :attr_reader: open_timeout
|
|
852
|
+
# Seconds to wait until a connection is opened. Also used by #starttls.
|
|
853
|
+
# Delegates to {config.open_timeout}[rdoc-ref:Config#open_timeout].
|
|
780
854
|
|
|
855
|
+
##
|
|
856
|
+
# :attr_reader: idle_response_timeout
|
|
781
857
|
# Seconds to wait until an IDLE response is received.
|
|
782
|
-
|
|
858
|
+
# Delegates to {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout].
|
|
859
|
+
|
|
860
|
+
##
|
|
861
|
+
# :attr_accessor: max_response_size
|
|
862
|
+
#
|
|
863
|
+
# The maximum allowed server response size, in bytes.
|
|
864
|
+
# Delegates to {config.max_response_size}[rdoc-ref:Config#max_response_size].
|
|
865
|
+
|
|
866
|
+
# :stopdoc:
|
|
867
|
+
def open_timeout; config.open_timeout end
|
|
868
|
+
def idle_response_timeout; config.idle_response_timeout end
|
|
869
|
+
def max_response_size; config.max_response_size end
|
|
870
|
+
def max_response_size=(val) config.max_response_size = val end
|
|
871
|
+
# :startdoc:
|
|
783
872
|
|
|
784
873
|
# The hostname this client connected to
|
|
785
874
|
attr_reader :host
|
|
@@ -802,6 +891,67 @@ module Net
|
|
|
802
891
|
# Returns +false+ for a plaintext connection.
|
|
803
892
|
attr_reader :ssl_ctx_params
|
|
804
893
|
|
|
894
|
+
# Returns the current connection state.
|
|
895
|
+
#
|
|
896
|
+
# Once an IMAP connection is established, the connection is in one of four
|
|
897
|
+
# states: +not_authenticated+, +authenticated+, +selected+, and +logout+.
|
|
898
|
+
# Most commands are valid only in certain states.
|
|
899
|
+
#
|
|
900
|
+
# The connection state object responds to +to_sym+ and +name+ with the name
|
|
901
|
+
# of the current connection state, as a Symbol or String. Future versions
|
|
902
|
+
# of +net-imap+ may store additional information on the state object.
|
|
903
|
+
#
|
|
904
|
+
# From {RFC9051}[https://www.rfc-editor.org/rfc/rfc9051#section-3]:
|
|
905
|
+
# +----------------------+
|
|
906
|
+
# |connection established|
|
|
907
|
+
# +----------------------+
|
|
908
|
+
# ||
|
|
909
|
+
# \/
|
|
910
|
+
# +--------------------------------------+
|
|
911
|
+
# | server greeting |
|
|
912
|
+
# +--------------------------------------+
|
|
913
|
+
# || (1) || (2) || (3)
|
|
914
|
+
# \/ || ||
|
|
915
|
+
# +-----------------+ || ||
|
|
916
|
+
# |Not Authenticated| || ||
|
|
917
|
+
# +-----------------+ || ||
|
|
918
|
+
# || (7) || (4) || ||
|
|
919
|
+
# || \/ \/ ||
|
|
920
|
+
# || +----------------+ ||
|
|
921
|
+
# || | Authenticated |<=++ ||
|
|
922
|
+
# || +----------------+ || ||
|
|
923
|
+
# || || (7) || (5) || (6) ||
|
|
924
|
+
# || || \/ || ||
|
|
925
|
+
# || || +--------+ || ||
|
|
926
|
+
# || || |Selected|==++ ||
|
|
927
|
+
# || || +--------+ ||
|
|
928
|
+
# || || || (7) ||
|
|
929
|
+
# \/ \/ \/ \/
|
|
930
|
+
# +--------------------------------------+
|
|
931
|
+
# | Logout |
|
|
932
|
+
# +--------------------------------------+
|
|
933
|
+
# ||
|
|
934
|
+
# \/
|
|
935
|
+
# +-------------------------------+
|
|
936
|
+
# |both sides close the connection|
|
|
937
|
+
# +-------------------------------+
|
|
938
|
+
#
|
|
939
|
+
# >>>
|
|
940
|
+
# Legend for the above diagram:
|
|
941
|
+
#
|
|
942
|
+
# 1. connection without pre-authentication (+OK+ #greeting)
|
|
943
|
+
# 2. pre-authenticated connection (+PREAUTH+ #greeting)
|
|
944
|
+
# 3. rejected connection (+BYE+ #greeting)
|
|
945
|
+
# 4. successful #login or #authenticate command
|
|
946
|
+
# 5. successful #select or #examine command
|
|
947
|
+
# 6. #close or #unselect command, unsolicited +CLOSED+ response code, or
|
|
948
|
+
# failed #select or #examine command
|
|
949
|
+
# 7. #logout command, server shutdown, or connection closed
|
|
950
|
+
#
|
|
951
|
+
# Before the server greeting, the state is +not_authenticated+.
|
|
952
|
+
# After the connection closes, the state remains +logout+.
|
|
953
|
+
attr_reader :connection_state
|
|
954
|
+
|
|
805
955
|
# Creates a new Net::IMAP object and connects it to the specified
|
|
806
956
|
# +host+.
|
|
807
957
|
#
|
|
@@ -835,6 +985,12 @@ module Net
|
|
|
835
985
|
#
|
|
836
986
|
# See DeprecatedClientOptions.new for deprecated SSL arguments.
|
|
837
987
|
#
|
|
988
|
+
# [response_handlers]
|
|
989
|
+
# A list of response handlers to be added before the receiver thread is
|
|
990
|
+
# started. This ensures every server response is handled, including the
|
|
991
|
+
# #greeting. Note that the greeting is handled in the current thread, but
|
|
992
|
+
# all other responses are handled in the receiver thread.
|
|
993
|
+
#
|
|
838
994
|
# [config]
|
|
839
995
|
# A Net::IMAP::Config object to use as the basis for #config. By default,
|
|
840
996
|
# the global Net::IMAP.config is used.
|
|
@@ -906,7 +1062,7 @@ module Net
|
|
|
906
1062
|
# [Net::IMAP::ByeResponseError]
|
|
907
1063
|
# Connected to the host successfully, but it immediately said goodbye.
|
|
908
1064
|
#
|
|
909
|
-
def initialize(host, port: nil, ssl:
|
|
1065
|
+
def initialize(host, port: nil, ssl: nil, response_handlers: nil,
|
|
910
1066
|
config: Config.global, **config_options)
|
|
911
1067
|
super()
|
|
912
1068
|
# Config options
|
|
@@ -921,6 +1077,8 @@ module Net
|
|
|
921
1077
|
@exception = nil
|
|
922
1078
|
@greeting = nil
|
|
923
1079
|
@capabilities = nil
|
|
1080
|
+
@tls_verified = false
|
|
1081
|
+
@connection_state = ConnectionState::NotAuthenticated.new
|
|
924
1082
|
|
|
925
1083
|
# Client Protocol Receiver
|
|
926
1084
|
@parser = ResponseParser.new(config: @config)
|
|
@@ -929,6 +1087,7 @@ module Net
|
|
|
929
1087
|
@receiver_thread = nil
|
|
930
1088
|
@receiver_thread_exception = nil
|
|
931
1089
|
@receiver_thread_terminating = false
|
|
1090
|
+
response_handlers&.each do add_response_handler(_1) end
|
|
932
1091
|
|
|
933
1092
|
# Client Protocol Sender (including state for currently running commands)
|
|
934
1093
|
@tag_prefix = "RUBY"
|
|
@@ -942,8 +1101,8 @@ module Net
|
|
|
942
1101
|
@logout_command_tag = nil
|
|
943
1102
|
|
|
944
1103
|
# Connection
|
|
945
|
-
@tls_verified = false
|
|
946
1104
|
@sock = tcp_socket(@host, @port)
|
|
1105
|
+
@reader = ResponseReader.new(self, @sock)
|
|
947
1106
|
start_tls_session if ssl_ctx
|
|
948
1107
|
start_imap_connection
|
|
949
1108
|
end
|
|
@@ -958,6 +1117,7 @@ module Net
|
|
|
958
1117
|
# Related: #logout, #logout!
|
|
959
1118
|
def disconnect
|
|
960
1119
|
return if disconnected?
|
|
1120
|
+
state_logout!
|
|
961
1121
|
begin
|
|
962
1122
|
begin
|
|
963
1123
|
# try to call SSL::SSLSocket#io.
|
|
@@ -1121,12 +1281,12 @@ module Net
|
|
|
1121
1281
|
# )
|
|
1122
1282
|
# end
|
|
1123
1283
|
#
|
|
1124
|
-
# See [ID[https://
|
|
1284
|
+
# See [ID[https://www.rfc-editor.org/rfc/rfc2971]] for field definitions.
|
|
1125
1285
|
#
|
|
1126
|
-
#
|
|
1286
|
+
# ==== Capabilities
|
|
1127
1287
|
#
|
|
1128
1288
|
# The server's capabilities must include +ID+
|
|
1129
|
-
# [RFC2971[https://
|
|
1289
|
+
# [RFC2971[https://www.rfc-editor.org/rfc/rfc2971]].
|
|
1130
1290
|
def id(client_id=nil)
|
|
1131
1291
|
synchronize do
|
|
1132
1292
|
send_command("ID", ClientID.new(client_id))
|
|
@@ -1196,6 +1356,10 @@ module Net
|
|
|
1196
1356
|
# both successful. Any error indicates that the connection has not been
|
|
1197
1357
|
# secured.
|
|
1198
1358
|
#
|
|
1359
|
+
# After the server agrees to start a TLS connection, this method waits up to
|
|
1360
|
+
# {config.open_timeout}[rdoc-ref:Config#open_timeout] before raising
|
|
1361
|
+
# +Net::OpenTimeout+.
|
|
1362
|
+
#
|
|
1199
1363
|
# *Note:*
|
|
1200
1364
|
# >>>
|
|
1201
1365
|
# Any #response_handlers added before STARTTLS should be aware that the
|
|
@@ -1205,7 +1369,7 @@ module Net
|
|
|
1205
1369
|
#
|
|
1206
1370
|
# Related: Net::IMAP.new, #login, #authenticate
|
|
1207
1371
|
#
|
|
1208
|
-
#
|
|
1372
|
+
# ==== Capability
|
|
1209
1373
|
# Clients should not call #starttls unless the server advertises the
|
|
1210
1374
|
# +STARTTLS+ capability.
|
|
1211
1375
|
#
|
|
@@ -1214,13 +1378,21 @@ module Net
|
|
|
1214
1378
|
#
|
|
1215
1379
|
def starttls(**options)
|
|
1216
1380
|
@ssl_ctx_params, @ssl_ctx = build_ssl_ctx(options)
|
|
1217
|
-
|
|
1381
|
+
error = nil
|
|
1382
|
+
ok = send_command("STARTTLS") do |resp|
|
|
1218
1383
|
if resp.kind_of?(TaggedResponse) && resp.name == "OK"
|
|
1219
1384
|
clear_cached_capabilities
|
|
1220
1385
|
clear_responses
|
|
1221
1386
|
start_tls_session
|
|
1222
1387
|
end
|
|
1388
|
+
rescue Exception => error
|
|
1389
|
+
raise # note that the error backtrace is in the receiver_thread
|
|
1223
1390
|
end
|
|
1391
|
+
if error
|
|
1392
|
+
disconnect
|
|
1393
|
+
raise error
|
|
1394
|
+
end
|
|
1395
|
+
ok
|
|
1224
1396
|
end
|
|
1225
1397
|
|
|
1226
1398
|
# :call-seq:
|
|
@@ -1335,7 +1507,7 @@ module Net
|
|
|
1335
1507
|
# capabilities, they will be cached.
|
|
1336
1508
|
def authenticate(*args, sasl_ir: config.sasl_ir, **props, &callback)
|
|
1337
1509
|
sasl_adapter.authenticate(*args, sasl_ir: sasl_ir, **props, &callback)
|
|
1338
|
-
.tap
|
|
1510
|
+
.tap do state_authenticated! _1 end
|
|
1339
1511
|
end
|
|
1340
1512
|
|
|
1341
1513
|
# Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
|
|
@@ -1352,7 +1524,7 @@ module Net
|
|
|
1352
1524
|
#
|
|
1353
1525
|
# Related: #authenticate, #starttls
|
|
1354
1526
|
#
|
|
1355
|
-
#
|
|
1527
|
+
# ==== Capabilities
|
|
1356
1528
|
#
|
|
1357
1529
|
# An IMAP client MUST NOT call #login when the server advertises the
|
|
1358
1530
|
# +LOGINDISABLED+ capability. By default, Net::IMAP will raise a
|
|
@@ -1369,7 +1541,7 @@ module Net
|
|
|
1369
1541
|
raise LoginDisabledError
|
|
1370
1542
|
end
|
|
1371
1543
|
send_command("LOGIN", user, password)
|
|
1372
|
-
.tap
|
|
1544
|
+
.tap do state_authenticated! _1 end
|
|
1373
1545
|
end
|
|
1374
1546
|
|
|
1375
1547
|
# Sends a {SELECT command [IMAP4rev1 §6.3.1]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.3.1]
|
|
@@ -1393,7 +1565,7 @@ module Net
|
|
|
1393
1565
|
#
|
|
1394
1566
|
# Related: #examine
|
|
1395
1567
|
#
|
|
1396
|
-
#
|
|
1568
|
+
# ==== Capabilities
|
|
1397
1569
|
#
|
|
1398
1570
|
# If [UIDPLUS[https://www.rfc-editor.org/rfc/rfc4315.html]] is supported,
|
|
1399
1571
|
# the server may return an untagged "NO" response with a "UIDNOTSTICKY"
|
|
@@ -1409,8 +1581,10 @@ module Net
|
|
|
1409
1581
|
args = ["SELECT", mailbox]
|
|
1410
1582
|
args << ["CONDSTORE"] if condstore
|
|
1411
1583
|
synchronize do
|
|
1584
|
+
state_unselected! # implicitly closes current mailbox
|
|
1412
1585
|
@responses.clear
|
|
1413
1586
|
send_command(*args)
|
|
1587
|
+
.tap do state_selected! end
|
|
1414
1588
|
end
|
|
1415
1589
|
end
|
|
1416
1590
|
|
|
@@ -1427,8 +1601,10 @@ module Net
|
|
|
1427
1601
|
args = ["EXAMINE", mailbox]
|
|
1428
1602
|
args << ["CONDSTORE"] if condstore
|
|
1429
1603
|
synchronize do
|
|
1604
|
+
state_unselected! # implicitly closes current mailbox
|
|
1430
1605
|
@responses.clear
|
|
1431
1606
|
send_command(*args)
|
|
1607
|
+
.tap do state_selected! end
|
|
1432
1608
|
end
|
|
1433
1609
|
end
|
|
1434
1610
|
|
|
@@ -1511,7 +1687,7 @@ module Net
|
|
|
1511
1687
|
#
|
|
1512
1688
|
# Related: #lsub, MailboxList
|
|
1513
1689
|
#
|
|
1514
|
-
#
|
|
1690
|
+
# ==== For example:
|
|
1515
1691
|
#
|
|
1516
1692
|
# imap.create("foo/bar")
|
|
1517
1693
|
# imap.create("foo/baz")
|
|
@@ -1549,7 +1725,7 @@ module Net
|
|
|
1549
1725
|
# servers, then folder creation (and listing, moving, etc) can lead to
|
|
1550
1726
|
# errors.
|
|
1551
1727
|
#
|
|
1552
|
-
# From RFC2342[https://
|
|
1728
|
+
# From RFC2342[https://www.rfc-editor.org/rfc/rfc2342]:
|
|
1553
1729
|
# >>>
|
|
1554
1730
|
# <em>Although typically a server will support only a single Personal
|
|
1555
1731
|
# Namespace, and a single Other User's Namespace, circumstances exist
|
|
@@ -1562,7 +1738,7 @@ module Net
|
|
|
1562
1738
|
#
|
|
1563
1739
|
# Related: #list, Namespaces, Namespace
|
|
1564
1740
|
#
|
|
1565
|
-
#
|
|
1741
|
+
# ==== For example:
|
|
1566
1742
|
#
|
|
1567
1743
|
# if capable?("NAMESPACE")
|
|
1568
1744
|
# namespaces = imap.namespace
|
|
@@ -1576,10 +1752,10 @@ module Net
|
|
|
1576
1752
|
# end
|
|
1577
1753
|
# end
|
|
1578
1754
|
#
|
|
1579
|
-
#
|
|
1755
|
+
# ==== Capabilities
|
|
1580
1756
|
#
|
|
1581
|
-
# The server's capabilities must include +NAMESPACE+
|
|
1582
|
-
# [RFC2342[https://
|
|
1757
|
+
# The server's capabilities must include either +IMAP4rev2+ or +NAMESPACE+
|
|
1758
|
+
# [RFC2342[https://www.rfc-editor.org/rfc/rfc2342]].
|
|
1583
1759
|
def namespace
|
|
1584
1760
|
synchronize do
|
|
1585
1761
|
send_command("NAMESPACE")
|
|
@@ -1615,7 +1791,7 @@ module Net
|
|
|
1615
1791
|
#
|
|
1616
1792
|
# Related: #list, MailboxList
|
|
1617
1793
|
#
|
|
1618
|
-
#
|
|
1794
|
+
# ==== Capabilities
|
|
1619
1795
|
#
|
|
1620
1796
|
# The server's capabilities must include +XLIST+,
|
|
1621
1797
|
# a deprecated Gmail extension (replaced by +SPECIAL-USE+).
|
|
@@ -1638,10 +1814,10 @@ module Net
|
|
|
1638
1814
|
#
|
|
1639
1815
|
# Related: #getquota, #setquota, MailboxQuotaRoot, MailboxQuota
|
|
1640
1816
|
#
|
|
1641
|
-
#
|
|
1817
|
+
# ==== Capabilities
|
|
1642
1818
|
#
|
|
1643
1819
|
# The server's capabilities must include +QUOTA+
|
|
1644
|
-
# [RFC2087[https://
|
|
1820
|
+
# [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
|
|
1645
1821
|
def getquotaroot(mailbox)
|
|
1646
1822
|
synchronize do
|
|
1647
1823
|
send_command("GETQUOTAROOT", mailbox)
|
|
@@ -1659,10 +1835,10 @@ module Net
|
|
|
1659
1835
|
#
|
|
1660
1836
|
# Related: #getquotaroot, #setquota, MailboxQuota
|
|
1661
1837
|
#
|
|
1662
|
-
#
|
|
1838
|
+
# ==== Capabilities
|
|
1663
1839
|
#
|
|
1664
1840
|
# The server's capabilities must include +QUOTA+
|
|
1665
|
-
# [RFC2087[https://
|
|
1841
|
+
# [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
|
|
1666
1842
|
def getquota(mailbox)
|
|
1667
1843
|
synchronize do
|
|
1668
1844
|
send_command("GETQUOTA", mailbox)
|
|
@@ -1677,10 +1853,10 @@ module Net
|
|
|
1677
1853
|
#
|
|
1678
1854
|
# Related: #getquota, #getquotaroot
|
|
1679
1855
|
#
|
|
1680
|
-
#
|
|
1856
|
+
# ==== Capabilities
|
|
1681
1857
|
#
|
|
1682
1858
|
# The server's capabilities must include +QUOTA+
|
|
1683
|
-
# [RFC2087[https://
|
|
1859
|
+
# [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]].
|
|
1684
1860
|
def setquota(mailbox, quota)
|
|
1685
1861
|
if quota.nil?
|
|
1686
1862
|
data = '()'
|
|
@@ -1697,10 +1873,10 @@ module Net
|
|
|
1697
1873
|
#
|
|
1698
1874
|
# Related: #getacl
|
|
1699
1875
|
#
|
|
1700
|
-
#
|
|
1876
|
+
# ==== Capabilities
|
|
1701
1877
|
#
|
|
1702
1878
|
# The server's capabilities must include +ACL+
|
|
1703
|
-
# [RFC4314[https://
|
|
1879
|
+
# [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
|
|
1704
1880
|
def setacl(mailbox, user, rights)
|
|
1705
1881
|
if rights.nil?
|
|
1706
1882
|
send_command("SETACL", mailbox, user, "")
|
|
@@ -1715,10 +1891,10 @@ module Net
|
|
|
1715
1891
|
#
|
|
1716
1892
|
# Related: #setacl, MailboxACLItem
|
|
1717
1893
|
#
|
|
1718
|
-
#
|
|
1894
|
+
# ==== Capabilities
|
|
1719
1895
|
#
|
|
1720
1896
|
# The server's capabilities must include +ACL+
|
|
1721
|
-
# [RFC4314[https://
|
|
1897
|
+
# [RFC4314[https://www.rfc-editor.org/rfc/rfc4314]].
|
|
1722
1898
|
def getacl(mailbox)
|
|
1723
1899
|
synchronize do
|
|
1724
1900
|
send_command("GETACL", mailbox)
|
|
@@ -1752,7 +1928,7 @@ module Net
|
|
|
1752
1928
|
# for +mailbox+ cannot be returned; for instance, because it
|
|
1753
1929
|
# does not exist.
|
|
1754
1930
|
#
|
|
1755
|
-
#
|
|
1931
|
+
# ==== Supported attributes
|
|
1756
1932
|
#
|
|
1757
1933
|
# +MESSAGES+:: The number of messages in the mailbox.
|
|
1758
1934
|
#
|
|
@@ -1783,12 +1959,12 @@ module Net
|
|
|
1783
1959
|
# Unsupported attributes may be requested. The attribute value will be
|
|
1784
1960
|
# either an Integer or an ExtensionData object.
|
|
1785
1961
|
#
|
|
1786
|
-
#
|
|
1962
|
+
# ==== For example:
|
|
1787
1963
|
#
|
|
1788
1964
|
# p imap.status("inbox", ["MESSAGES", "RECENT"])
|
|
1789
1965
|
# #=> {"RECENT"=>0, "MESSAGES"=>44}
|
|
1790
1966
|
#
|
|
1791
|
-
#
|
|
1967
|
+
# ==== Capabilities
|
|
1792
1968
|
#
|
|
1793
1969
|
# +SIZE+ requires the server's capabilities to include either +IMAP4rev2+ or
|
|
1794
1970
|
# <tt>STATUS=SIZE</tt>
|
|
@@ -1828,7 +2004,7 @@ module Net
|
|
|
1828
2004
|
# not exist (it is not created automatically), or if the flags,
|
|
1829
2005
|
# date_time, or message arguments contain errors.
|
|
1830
2006
|
#
|
|
1831
|
-
#
|
|
2007
|
+
# ==== Capabilities
|
|
1832
2008
|
#
|
|
1833
2009
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
1834
2010
|
# supported and the destination supports persistent UIDs, the server's
|
|
@@ -1867,6 +2043,7 @@ module Net
|
|
|
1867
2043
|
# Related: #unselect
|
|
1868
2044
|
def close
|
|
1869
2045
|
send_command("CLOSE")
|
|
2046
|
+
.tap do state_authenticated! end
|
|
1870
2047
|
end
|
|
1871
2048
|
|
|
1872
2049
|
# Sends an {UNSELECT command [RFC3691 §2]}[https://www.rfc-editor.org/rfc/rfc3691#section-3]
|
|
@@ -1877,118 +2054,278 @@ module Net
|
|
|
1877
2054
|
#
|
|
1878
2055
|
# Related: #close
|
|
1879
2056
|
#
|
|
1880
|
-
#
|
|
2057
|
+
# ==== Capabilities
|
|
1881
2058
|
#
|
|
1882
|
-
# The server's capabilities must include +UNSELECT+
|
|
1883
|
-
# [RFC3691[https://
|
|
2059
|
+
# The server's capabilities must include either +IMAP4rev2+ or +UNSELECT+
|
|
2060
|
+
# [RFC3691[https://www.rfc-editor.org/rfc/rfc3691]].
|
|
1884
2061
|
def unselect
|
|
1885
2062
|
send_command("UNSELECT")
|
|
2063
|
+
.tap do state_authenticated! end
|
|
1886
2064
|
end
|
|
1887
2065
|
|
|
2066
|
+
# call-seq:
|
|
2067
|
+
# expunge -> array of message sequence numbers
|
|
2068
|
+
# expunge -> VanishedData of UIDs
|
|
2069
|
+
#
|
|
1888
2070
|
# Sends an {EXPUNGE command [IMAP4rev1 §6.4.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.3]
|
|
1889
|
-
#
|
|
1890
|
-
# selected mailbox
|
|
2071
|
+
# to permanently remove all messages with the +\Deleted+ flag from the
|
|
2072
|
+
# currently selected mailbox.
|
|
2073
|
+
#
|
|
2074
|
+
# Returns either an array of expunged message <em>sequence numbers</em> or
|
|
2075
|
+
# (when the appropriate capability is enabled) VanishedData of expunged
|
|
2076
|
+
# UIDs. Previously unhandled +EXPUNGE+ or +VANISHED+ responses are merged
|
|
2077
|
+
# with the direct response to this command. <tt>VANISHED (EARLIER)</tt>
|
|
2078
|
+
# responses will _not_ be merged.
|
|
2079
|
+
#
|
|
2080
|
+
# When no messages have been expunged, an empty array is returned,
|
|
2081
|
+
# regardless of which extensions are enabled. In a future release, an empty
|
|
2082
|
+
# VanishedData may be returned, based on the currently enabled extensions.
|
|
1891
2083
|
#
|
|
1892
2084
|
# Related: #uid_expunge
|
|
2085
|
+
#
|
|
2086
|
+
# ==== Capabilities
|
|
2087
|
+
#
|
|
2088
|
+
# When either QRESYNC[https://www.rfc-editor.org/rfc/rfc7162] or
|
|
2089
|
+
# UIDONLY[https://www.rfc-editor.org/rfc/rfc9586] are enabled, #expunge
|
|
2090
|
+
# returns VanishedData, which contains UIDs---<em>not message sequence
|
|
2091
|
+
# numbers</em>.
|
|
1893
2092
|
def expunge
|
|
1894
|
-
|
|
1895
|
-
send_command("EXPUNGE")
|
|
1896
|
-
clear_responses("EXPUNGE")
|
|
1897
|
-
end
|
|
2093
|
+
expunge_internal("EXPUNGE")
|
|
1898
2094
|
end
|
|
1899
2095
|
|
|
2096
|
+
# call-seq:
|
|
2097
|
+
# uid_expunge{uid_set) -> array of message sequence numbers
|
|
2098
|
+
# uid_expunge{uid_set) -> VanishedData of UIDs
|
|
2099
|
+
#
|
|
1900
2100
|
# Sends a {UID EXPUNGE command [RFC4315 §2.1]}[https://www.rfc-editor.org/rfc/rfc4315#section-2.1]
|
|
1901
2101
|
# {[IMAP4rev2 §6.4.9]}[https://www.rfc-editor.org/rfc/rfc9051#section-6.4.9]
|
|
1902
2102
|
# to permanently remove all messages that have both the <tt>\\Deleted</tt>
|
|
1903
2103
|
# flag set and a UID that is included in +uid_set+.
|
|
1904
2104
|
#
|
|
2105
|
+
# Returns the same result type as #expunge.
|
|
2106
|
+
#
|
|
1905
2107
|
# By using #uid_expunge instead of #expunge when resynchronizing with
|
|
1906
2108
|
# the server, the client can ensure that it does not inadvertantly
|
|
1907
2109
|
# remove any messages that have been marked as <tt>\\Deleted</tt> by other
|
|
1908
2110
|
# clients between the time that the client was last connected and
|
|
1909
2111
|
# the time the client resynchronizes.
|
|
1910
2112
|
#
|
|
1911
|
-
# *Note:*
|
|
1912
|
-
# >>>
|
|
1913
|
-
# Although the command takes a set of UIDs for its argument, the
|
|
1914
|
-
# server still returns regular EXPUNGE responses, which contain
|
|
1915
|
-
# a <em>sequence number</em>. These will be deleted from
|
|
1916
|
-
# #responses and this method returns them as an array of
|
|
1917
|
-
# <em>sequence number</em> integers.
|
|
1918
|
-
#
|
|
1919
2113
|
# Related: #expunge
|
|
1920
2114
|
#
|
|
1921
|
-
#
|
|
2115
|
+
# ==== Capabilities
|
|
1922
2116
|
#
|
|
1923
|
-
# The server's capabilities must include +UIDPLUS+
|
|
2117
|
+
# The server's capabilities must include either +IMAP4rev2+ or +UIDPLUS+
|
|
1924
2118
|
# [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]].
|
|
2119
|
+
#
|
|
2120
|
+
# Otherwise, #uid_expunge is updated by extensions in the same way as
|
|
2121
|
+
# #expunge.
|
|
1925
2122
|
def uid_expunge(uid_set)
|
|
1926
|
-
|
|
1927
|
-
send_command("UID EXPUNGE", SequenceSet.new(uid_set))
|
|
1928
|
-
clear_responses("EXPUNGE")
|
|
1929
|
-
end
|
|
2123
|
+
expunge_internal("UID EXPUNGE", SequenceSet.new(uid_set))
|
|
1930
2124
|
end
|
|
1931
2125
|
|
|
1932
2126
|
# :call-seq:
|
|
1933
2127
|
# search(criteria, charset = nil) -> result
|
|
2128
|
+
# search(criteria, charset: nil, return: nil) -> result
|
|
1934
2129
|
#
|
|
1935
2130
|
# Sends a {SEARCH command [IMAP4rev1 §6.4.4]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.4]
|
|
1936
2131
|
# to search the mailbox for messages that match the given search +criteria+,
|
|
1937
|
-
# and returns a SearchResult. SearchResult
|
|
1938
|
-
# backward compatibility) but adds
|
|
1939
|
-
# capability has been enabled.
|
|
2132
|
+
# and returns either a SearchResult or an ESearchResult. SearchResult
|
|
2133
|
+
# inherits from Array (for backward compatibility) but adds
|
|
2134
|
+
# SearchResult#modseq when the +CONDSTORE+ capability has been enabled.
|
|
2135
|
+
# ESearchResult also implements {#to_a}[rdoc-ref:ESearchResult#to_a], for
|
|
2136
|
+
# compatibility with SearchResult.
|
|
1940
2137
|
#
|
|
1941
2138
|
# +criteria+ is one or more search keys and their arguments, which may be
|
|
1942
2139
|
# provided as an array or a string.
|
|
1943
|
-
# See {"
|
|
1944
|
-
#
|
|
1945
|
-
#
|
|
1946
|
-
#
|
|
1947
|
-
#
|
|
1948
|
-
#
|
|
1949
|
-
#
|
|
1950
|
-
#
|
|
1951
|
-
#
|
|
1952
|
-
#
|
|
1953
|
-
#
|
|
1954
|
-
# +Array+ of these same types.
|
|
1955
|
-
# * Any +String+ is sent verbatim when it is a valid \IMAP atom,
|
|
1956
|
-
# and encoded as an \IMAP quoted or literal string otherwise.
|
|
1957
|
-
# * Any other nested +Array+ is encoded as a parenthesized list, to group
|
|
1958
|
-
# multiple search keys (e.g., for use with +OR+ and +NOT+).
|
|
1959
|
-
# * Any other +Integer+ (besides <tt>-1</tt>) will be sent as +#to_s+.
|
|
1960
|
-
# * +Date+ objects will be encoded as an \IMAP date (see ::encode_date).
|
|
1961
|
-
#
|
|
1962
|
-
# * When +criteria+ is a string, it will be sent directly to the server
|
|
1963
|
-
# <em>without any validation or encoding</em>. *WARNING:* This is
|
|
1964
|
-
# vulnerable to injection attacks when external inputs are used.
|
|
2140
|
+
# See {"Argument translation"}[rdoc-ref:#search@Argument+translation]
|
|
2141
|
+
# and {"Search criteria"}[rdoc-ref:#search@Search+criteria], below.
|
|
2142
|
+
#
|
|
2143
|
+
# +return+ options control what kind of information is returned about
|
|
2144
|
+
# messages matching the search +criteria+. Specifying +return+ should force
|
|
2145
|
+
# the server to return an ESearchResult instead of a SearchResult, but some
|
|
2146
|
+
# servers disobey this requirement. <em>Requires an extended search
|
|
2147
|
+
# capability, such as +ESEARCH+ or +IMAP4rev2+.</em>
|
|
2148
|
+
# See {"Argument translation"}[rdoc-ref:#search@Argument+translation] and
|
|
2149
|
+
# {"Supported return options"}[rdoc-ref:#search@Supported+return+options],
|
|
2150
|
+
# below.
|
|
1965
2151
|
#
|
|
1966
2152
|
# +charset+ is the name of the {registered character
|
|
1967
2153
|
# set}[https://www.iana.org/assignments/character-sets/character-sets.xhtml]
|
|
1968
2154
|
# used by strings in the search +criteria+. When +charset+ isn't specified,
|
|
1969
2155
|
# either <tt>"US-ASCII"</tt> or <tt>"UTF-8"</tt> is assumed, depending on
|
|
1970
|
-
# the server's capabilities.
|
|
1971
|
-
#
|
|
2156
|
+
# the server's capabilities.
|
|
2157
|
+
#
|
|
2158
|
+
# _NOTE:_ Return options and charset may be sent as part of +criteria+. Do
|
|
2159
|
+
# not use the +return+ or +charset+ arguments when either return options or
|
|
2160
|
+
# charset are embedded in +criteria+.
|
|
1972
2161
|
#
|
|
1973
2162
|
# Related: #uid_search
|
|
1974
2163
|
#
|
|
1975
|
-
#
|
|
2164
|
+
# ==== For example:
|
|
1976
2165
|
#
|
|
1977
|
-
#
|
|
2166
|
+
# imap.search(["SUBJECT", "hello", "NOT", "SEEN"])
|
|
1978
2167
|
# #=> [1, 6, 7, 8]
|
|
1979
2168
|
#
|
|
1980
|
-
# The following
|
|
1981
|
-
#
|
|
1982
|
-
#
|
|
1983
|
-
#
|
|
1984
|
-
#
|
|
1985
|
-
#
|
|
1986
|
-
#
|
|
1987
|
-
#
|
|
1988
|
-
#
|
|
1989
|
-
#
|
|
1990
|
-
#
|
|
1991
|
-
#
|
|
2169
|
+
# The following assumes the server supports +ESEARCH+ and +CONDSTORE+:
|
|
2170
|
+
#
|
|
2171
|
+
# result = imap.uid_search(["UID", 12345.., "MODSEQ", 620_162_338],
|
|
2172
|
+
# return: %w(all count min max))
|
|
2173
|
+
# # => #<data Net::IMAP::ESearchResult tag="RUBY0123", uid=true,
|
|
2174
|
+
# # data=[["ALL", Net::IMAP::SequenceSet["12346:12349,22222:22230"]],
|
|
2175
|
+
# # ["COUNT", 13], ["MIN", 12346], ["MAX", 22230],
|
|
2176
|
+
# # ["MODSEQ", 917162488]]>
|
|
2177
|
+
# result.to_a # => [12346, 12347, 12348, 12349, 22222, 22223, 22224,
|
|
2178
|
+
# # 22225, 22226, 22227, 22228, 22229, 22230]
|
|
2179
|
+
# result.uid? # => true
|
|
2180
|
+
# result.count # => 13
|
|
2181
|
+
# result.min # => 12346
|
|
2182
|
+
# result.max # => 22230
|
|
2183
|
+
# result.modseq # => 917162488
|
|
2184
|
+
#
|
|
2185
|
+
# Using +return+ options to limit the result to only min, max, and count:
|
|
2186
|
+
#
|
|
2187
|
+
# result = imap.uid_search(["UID", 12345..,], return: %w(count min max))
|
|
2188
|
+
# # => #<data Net::IMAP::ESearchResult tag="RUBY0124", uid=true,
|
|
2189
|
+
# # data=[["COUNT", 13], ["MIN", 12346], ["MAX", 22230]]>
|
|
2190
|
+
# result.to_a # => []
|
|
2191
|
+
# result.count # => 13
|
|
2192
|
+
# result.min # => 12346
|
|
2193
|
+
# result.max # => 22230
|
|
2194
|
+
#
|
|
2195
|
+
# Return options and charset may be sent as keyword args or embedded in the
|
|
2196
|
+
# +criteria+ arg, but they must be in the correct order: <tt>"RETURN (...)
|
|
2197
|
+
# CHARSET ... criteria..."</tt>. The following searches
|
|
2198
|
+
# send the exact same command to the server:
|
|
2199
|
+
#
|
|
2200
|
+
# # Return options and charset as keyword arguments (preferred)
|
|
2201
|
+
# imap.search(%w(OR UNSEEN FLAGGED), return: %w(MIN MAX), charset: "UTF-8")
|
|
2202
|
+
# # Embedding return and charset in the criteria array
|
|
2203
|
+
# imap.search(["RETURN", %w(MIN MAX), "CHARSET", "UTF-8", *%w(OR UNSEEN FLAGGED)])
|
|
2204
|
+
# # Embedding return and charset in the criteria string
|
|
2205
|
+
# imap.search("RETURN (MIN MAX) CHARSET UTF-8 OR UNSEEN FLAGGED")
|
|
2206
|
+
#
|
|
2207
|
+
# Sending charset as the second positional argument is supported for
|
|
2208
|
+
# backward compatibility. Future versions may print a deprecation warning:
|
|
2209
|
+
# imap.search(%w(OR UNSEEN FLAGGED), "UTF-8", return: %w(MIN MAX))
|
|
2210
|
+
#
|
|
2211
|
+
# ==== Argument translation
|
|
2212
|
+
#
|
|
2213
|
+
# [+return+ options]
|
|
2214
|
+
# Must be an Array. Return option names may be either strings or symbols.
|
|
2215
|
+
# +Range+ elements which begin and end with negative integers are encoded
|
|
2216
|
+
# for use with +PARTIAL+--any other ranges are converted to SequenceSet.
|
|
2217
|
+
# Unlike +criteria+, other return option arguments are not automatically
|
|
2218
|
+
# converted to SequenceSet.
|
|
2219
|
+
#
|
|
2220
|
+
# [When +criteria+ is an Array]
|
|
2221
|
+
# When the array begins with <tt>"RETURN"</tt> (case insensitive), the
|
|
2222
|
+
# second array element is translated like the +return+ parameter (as
|
|
2223
|
+
# described above).
|
|
2224
|
+
#
|
|
2225
|
+
# Every other member is a +SEARCH+ command argument:
|
|
2226
|
+
# [SequenceSet]
|
|
2227
|
+
# Encoded as an \IMAP +sequence-set+ with SequenceSet#valid_string.
|
|
2228
|
+
# [Set, Range, <tt>-1</tt>, +:*+, responds to +#to_sequence_set+]
|
|
2229
|
+
# Converted to SequenceSet for validation and encoding.
|
|
2230
|
+
# [nested sequence-set +Array+]
|
|
2231
|
+
# When every element in a nested array is one of the above types, a
|
|
2232
|
+
# positive +Integer+, a sequence-set formatted +String+, or a deeply
|
|
2233
|
+
# nested +Array+ of these same types, the array will be converted to
|
|
2234
|
+
# SequenceSet for validation and encoding.
|
|
2235
|
+
# [Any other nested +Array+]
|
|
2236
|
+
# Otherwise, a nested array is encoded as a parenthesized list, to
|
|
2237
|
+
# combine multiple search keys (e.g., for use with +OR+ and +NOT+).
|
|
2238
|
+
# [+String+]
|
|
2239
|
+
# Sent verbatim when it is a valid \IMAP +atom+, and encoded as an \IMAP
|
|
2240
|
+
# +quoted+ or +literal+ string otherwise. Every standard search key
|
|
2241
|
+
# name is a valid \IMAP +atom+ and every standard search key string
|
|
2242
|
+
# argument is an +astring+ which may be encoded as +atom+, +quoted+, or
|
|
2243
|
+
# +literal+.
|
|
2244
|
+
#
|
|
2245
|
+
# *Note:* <tt>*</tt> is not a valid \IMAP +atom+ character. Any string
|
|
2246
|
+
# containing <tt>*</tt> will be encoded as a +quoted+ string, _not_ a
|
|
2247
|
+
# +sequence-set+.
|
|
2248
|
+
# [+Integer+ (except for <tt>-1</tt>)]
|
|
2249
|
+
# Encoded using +#to_s+.
|
|
2250
|
+
# [+Date+]
|
|
2251
|
+
# Encoded as an \IMAP date (see ::encode_date).
|
|
2252
|
+
#
|
|
2253
|
+
# [When +criteria+ is a String]
|
|
2254
|
+
# +criteria+ will be sent directly to the server <em>without any
|
|
2255
|
+
# validation or encoding</em>.
|
|
2256
|
+
#
|
|
2257
|
+
# <em>*WARNING:* This is vulnerable to injection attacks when external
|
|
2258
|
+
# inputs are used.</em>
|
|
2259
|
+
#
|
|
2260
|
+
# ==== Supported return options
|
|
2261
|
+
#
|
|
2262
|
+
# For full definitions of the standard return options and return data, see
|
|
2263
|
+
# the relevant RFCs.
|
|
2264
|
+
#
|
|
2265
|
+
# [+ALL+]
|
|
2266
|
+
# Returns ESearchResult#all with a SequenceSet of all matching sequence
|
|
2267
|
+
# numbers or UIDs. This is the default, when return options are empty.
|
|
2268
|
+
#
|
|
2269
|
+
# For compatibility with SearchResult, ESearchResult#to_a returns an
|
|
2270
|
+
# Array of message sequence numbers or UIDs.
|
|
2271
|
+
#
|
|
2272
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2273
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2274
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2275
|
+
#
|
|
2276
|
+
# [+COUNT+]
|
|
2277
|
+
# Returns ESearchResult#count with the number of matching messages.
|
|
2278
|
+
#
|
|
2279
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2280
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2281
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2282
|
+
#
|
|
2283
|
+
# [+MAX+]
|
|
2284
|
+
# Returns ESearchResult#max with the highest matching sequence number or
|
|
2285
|
+
# UID.
|
|
2286
|
+
#
|
|
2287
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2288
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2289
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2290
|
+
#
|
|
2291
|
+
# [+MIN+]
|
|
2292
|
+
# Returns ESearchResult#min with the lowest matching sequence number or
|
|
2293
|
+
# UID.
|
|
2294
|
+
#
|
|
2295
|
+
# <em>Requires either the +ESEARCH+ or +IMAP4rev2+ capabability.</em>
|
|
2296
|
+
# {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731]
|
|
2297
|
+
# {[RFC9051]}[https://rfc-editor.org/rfc/rfc9051]
|
|
2298
|
+
#
|
|
2299
|
+
# [+PARTIAL+ _range_]
|
|
2300
|
+
# Returns ESearchResult#partial with a SequenceSet of a subset of
|
|
2301
|
+
# matching sequence numbers or UIDs, as selected by _range_. As with
|
|
2302
|
+
# sequence numbers, the first result is +1+: <tt>1..500</tt> selects the
|
|
2303
|
+
# first 500 search results (in mailbox order), <tt>501..1000</tt> the
|
|
2304
|
+
# second 500, and so on. _range_ may also be negative: <tt>-500..-1</tt>
|
|
2305
|
+
# selects the last 500 search results.
|
|
2306
|
+
#
|
|
2307
|
+
# <em>Requires either the <tt>CONTEXT=SEARCH</tt> or +PARTIAL+ capabability.</em>
|
|
2308
|
+
# {[RFC5267]}[https://rfc-editor.org/rfc/rfc5267]
|
|
2309
|
+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
|
|
2310
|
+
#
|
|
2311
|
+
# ===== +MODSEQ+ return data
|
|
2312
|
+
#
|
|
2313
|
+
# ESearchResult#modseq return data does not have a corresponding return
|
|
2314
|
+
# option. Instead, it is returned if the +MODSEQ+ search key is used or
|
|
2315
|
+
# when the +CONDSTORE+ extension is enabled for the selected mailbox.
|
|
2316
|
+
# See [{RFC4731 §3.2}[https://www.rfc-editor.org/rfc/rfc4731#section-3.2]]
|
|
2317
|
+
# or [{RFC7162 §2.1.5}[https://www.rfc-editor.org/rfc/rfc7162#section-3.1.5]].
|
|
2318
|
+
#
|
|
2319
|
+
# ===== +RFC4466+ compatible extensions
|
|
2320
|
+
#
|
|
2321
|
+
# {RFC4466 §2.6}[https://www.rfc-editor.org/rfc/rfc4466.html#section-2.6]
|
|
2322
|
+
# defines standard syntax for search extensions. Net::IMAP allows sending
|
|
2323
|
+
# unsupported search return options and will parse unsupported search
|
|
2324
|
+
# extensions' return values into ExtensionData. Please note that this is an
|
|
2325
|
+
# intentionally _unstable_ API. Future releases may return different
|
|
2326
|
+
# (incompatible) objects, <em>without deprecation or warning</em>.
|
|
2327
|
+
#
|
|
2328
|
+
# ==== Search keys
|
|
1992
2329
|
#
|
|
1993
2330
|
# For full definitions of the standard search +criteria+,
|
|
1994
2331
|
# see [{IMAP4rev1 §6.4.4}[https://www.rfc-editor.org/rfc/rfc3501.html#section-6.4.4]],
|
|
@@ -2003,23 +2340,21 @@ module Net
|
|
|
2003
2340
|
# arguments. The number and type of arguments is specific to each search
|
|
2004
2341
|
# key.
|
|
2005
2342
|
#
|
|
2006
|
-
#
|
|
2007
|
-
# Matches every message in the mailbox.
|
|
2343
|
+
# ===== Search keys that match all messages
|
|
2008
2344
|
#
|
|
2009
|
-
#
|
|
2010
|
-
#
|
|
2011
|
-
# messages which match all contained search keys. Useful for +OR+, +NOT+,
|
|
2012
|
-
# and other search keys with _search-key_ arguments.
|
|
2345
|
+
# [+ALL+]
|
|
2346
|
+
# The default initial key. Matches every message in the mailbox.
|
|
2013
2347
|
#
|
|
2014
|
-
#
|
|
2348
|
+
# [+SAVEDATESUPPORTED+]
|
|
2349
|
+
# Matches every message in the mailbox when the mailbox supports the save
|
|
2350
|
+
# date attribute. Otherwise, it matches no messages.
|
|
2015
2351
|
#
|
|
2016
|
-
# +
|
|
2017
|
-
#
|
|
2352
|
+
# <em>Requires +SAVEDATE+ capability</em>.
|
|
2353
|
+
# {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
|
|
2018
2354
|
#
|
|
2019
|
-
#
|
|
2020
|
-
# Matches messages which do not match _search-key_.
|
|
2355
|
+
# ===== Sequence set search keys
|
|
2021
2356
|
#
|
|
2022
|
-
# _sequence-set_
|
|
2357
|
+
# [_sequence-set_]
|
|
2023
2358
|
# Matches messages with message sequence numbers in _sequence-set_.
|
|
2024
2359
|
#
|
|
2025
2360
|
# _Note:_ this search key has no label.
|
|
@@ -2027,121 +2362,139 @@ module Net
|
|
|
2027
2362
|
# <em>+UIDONLY+ must *not* be enabled.</em>
|
|
2028
2363
|
# {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.html]
|
|
2029
2364
|
#
|
|
2030
|
-
# +UID+ _sequence-set_
|
|
2365
|
+
# [+UID+ _sequence-set_]
|
|
2031
2366
|
# Matches messages with a UID in _sequence-set_.
|
|
2032
2367
|
#
|
|
2033
|
-
#
|
|
2034
|
-
#
|
|
2368
|
+
# ===== Compound search keys
|
|
2369
|
+
#
|
|
2370
|
+
# [(_search-key_ _search-key_...)]
|
|
2371
|
+
# Combines one or more _search-key_ arguments to match
|
|
2372
|
+
# messages which match all contained search keys. Useful for +OR+, +NOT+,
|
|
2373
|
+
# and other search keys with _search-key_ arguments.
|
|
2374
|
+
#
|
|
2375
|
+
# _Note:_ this search key has no label.
|
|
2376
|
+
#
|
|
2377
|
+
# [+OR+ _search-key_ _search-key_]
|
|
2378
|
+
# Matches messages which match either _search-key_ argument.
|
|
2379
|
+
#
|
|
2380
|
+
# [+NOT+ _search-key_]
|
|
2381
|
+
# Matches messages which do not match _search-key_.
|
|
2382
|
+
#
|
|
2383
|
+
# [+FUZZY+ _search-key_]
|
|
2384
|
+
# Uses fuzzy matching for the specified search key.
|
|
2385
|
+
#
|
|
2386
|
+
# <em>Requires <tt>SEARCH=FUZZY</tt> capability.</em>
|
|
2387
|
+
# {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
|
|
2388
|
+
#
|
|
2389
|
+
# ===== Flags search keys
|
|
2390
|
+
#
|
|
2391
|
+
# [+ANSWERED+, +UNANSWERED+]
|
|
2035
2392
|
# Matches messages with or without the <tt>\\Answered</tt> flag.
|
|
2036
|
-
# +DELETED
|
|
2037
|
-
# +UNDELETED+::
|
|
2393
|
+
# [+DELETED+, +UNDELETED+]
|
|
2038
2394
|
# Matches messages with or without the <tt>\\Deleted</tt> flag.
|
|
2039
|
-
# +DRAFT
|
|
2040
|
-
# +UNDRAFT+::
|
|
2395
|
+
# [+DRAFT+, +UNDRAFT+]
|
|
2041
2396
|
# Matches messages with or without the <tt>\\Draft</tt> flag.
|
|
2042
|
-
# +FLAGGED
|
|
2043
|
-
# +UNFLAGGED+::
|
|
2397
|
+
# [+FLAGGED+, +UNFLAGGED+]
|
|
2044
2398
|
# Matches messages with or without the <tt>\\Flagged</tt> flag.
|
|
2045
|
-
# +SEEN
|
|
2046
|
-
# +UNSEEN+::
|
|
2399
|
+
# [+SEEN+, +UNSEEN+]
|
|
2047
2400
|
# Matches messages with or without the <tt>\\Seen</tt> flag.
|
|
2048
|
-
#
|
|
2049
|
-
# +KEYWORD+ _keyword_::
|
|
2050
|
-
# +UNKEYWORD+ _keyword_::
|
|
2401
|
+
# [+KEYWORD+ _keyword_, +UNKEYWORD+ _keyword_]
|
|
2051
2402
|
# Matches messages with or without the specified _keyword_.
|
|
2052
2403
|
#
|
|
2053
|
-
# +
|
|
2054
|
-
# Matches
|
|
2055
|
-
#
|
|
2056
|
-
#
|
|
2057
|
-
# +
|
|
2058
|
-
#
|
|
2059
|
-
#
|
|
2060
|
-
#
|
|
2061
|
-
#
|
|
2062
|
-
#
|
|
2063
|
-
#
|
|
2064
|
-
# +
|
|
2404
|
+
# [+RECENT+, +UNRECENT+]
|
|
2405
|
+
# Matches messages with or without the <tt>\\Recent</tt> flag.
|
|
2406
|
+
#
|
|
2407
|
+
# *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
|
|
2408
|
+
# [+NEW+]
|
|
2409
|
+
# Equivalent to <tt>(RECENT UNSEEN)</tt>.
|
|
2410
|
+
#
|
|
2411
|
+
# *NOTE:* The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+.
|
|
2412
|
+
#
|
|
2413
|
+
# ===== Header field substring search keys
|
|
2414
|
+
#
|
|
2415
|
+
# [+BCC+ _substring_]
|
|
2416
|
+
# Matches when _substring_ is in the envelope's +BCC+ field.
|
|
2417
|
+
# [+CC+ _substring_]
|
|
2418
|
+
# Matches when _substring_ is in the envelope's +CC+ field.
|
|
2419
|
+
# [+FROM+ _substring_]
|
|
2420
|
+
# Matches when _substring_ is in the envelope's +FROM+ field.
|
|
2421
|
+
# [+SUBJECT+ _substring_]
|
|
2422
|
+
# Matches when _substring_ is in the envelope's +SUBJECT+ field.
|
|
2423
|
+
# [+TO+ _substring_]
|
|
2424
|
+
# Matches when _substring_ is in the envelope's +TO+ field.
|
|
2425
|
+
#
|
|
2426
|
+
# [+HEADER+ _field_ _substring_]
|
|
2065
2427
|
# Matches when _substring_ is in the specified header _field_.
|
|
2066
2428
|
#
|
|
2067
|
-
#
|
|
2429
|
+
# ===== Body text search keys
|
|
2430
|
+
# [+BODY+ _string_]
|
|
2068
2431
|
# Matches when _string_ is in the body of the message.
|
|
2069
2432
|
# Does not match on header fields.
|
|
2070
2433
|
#
|
|
2071
2434
|
# The server _may_ use flexible matching, rather than simple substring
|
|
2072
2435
|
# matches. For example, this may use stemming or match only full words.
|
|
2073
2436
|
#
|
|
2074
|
-
# +TEXT+ _string_
|
|
2437
|
+
# [+TEXT+ _string_]
|
|
2075
2438
|
# Matches when _string_ is in the header or body of the message.
|
|
2076
2439
|
#
|
|
2077
2440
|
# The server _may_ use flexible matching, rather than simple substring
|
|
2078
2441
|
# matches. For example, this may use stemming or match only full words.
|
|
2079
2442
|
#
|
|
2080
|
-
#
|
|
2081
|
-
# +ON+ _date_::
|
|
2082
|
-
# +SINCE+ _date_::
|
|
2083
|
-
# Matches when the +INTERNALDATE+ is earlier than, on, or later than
|
|
2084
|
-
# _date_.
|
|
2443
|
+
# ===== Date/Time search keys
|
|
2085
2444
|
#
|
|
2086
|
-
# +SENTBEFORE+ _date_
|
|
2087
|
-
# +SENTON+ _date_
|
|
2088
|
-
# +SENTSINCE+ _date_
|
|
2445
|
+
# [+SENTBEFORE+ _date_]
|
|
2446
|
+
# [+SENTON+ _date_]
|
|
2447
|
+
# [+SENTSINCE+ _date_]
|
|
2089
2448
|
# Matches when the +Date+ header is earlier than, on, or later than _date_.
|
|
2090
2449
|
#
|
|
2091
|
-
# +
|
|
2092
|
-
# +
|
|
2093
|
-
#
|
|
2094
|
-
#
|
|
2095
|
-
#
|
|
2096
|
-
#
|
|
2097
|
-
# The <tt>\\Recent</tt> flag has been removed from +IMAP4rev2+. So these
|
|
2098
|
-
# search keys require the +IMAP4rev1+ capability.
|
|
2450
|
+
# [+BEFORE+ _date_]
|
|
2451
|
+
# [+ON+ _date_]
|
|
2452
|
+
# [+SINCE+ _date_]
|
|
2453
|
+
# Matches when the +INTERNALDATE+ is earlier than, on, or later than
|
|
2454
|
+
# _date_.
|
|
2099
2455
|
#
|
|
2100
|
-
# +
|
|
2101
|
-
# +
|
|
2102
|
-
# Matches
|
|
2456
|
+
# [+OLDER+ _interval_]
|
|
2457
|
+
# [+YOUNGER+ _interval_]
|
|
2458
|
+
# Matches when the +INTERNALDATE+ is more/less than _interval_ seconds ago.
|
|
2103
2459
|
#
|
|
2104
|
-
# +
|
|
2105
|
-
#
|
|
2460
|
+
# <em>Requires +WITHIN+ capability</em>.
|
|
2461
|
+
# {[RFC5032]}[https://www.rfc-editor.org/rfc/rfc5032.html]
|
|
2106
2462
|
#
|
|
2107
|
-
#
|
|
2463
|
+
# [+SAVEDBEFORE+ _date_]
|
|
2464
|
+
# [+SAVEDON+ _date_]
|
|
2465
|
+
# [+SAVEDSINCE+ _date_]
|
|
2466
|
+
# Matches when the save date is earlier than, on, or later than _date_.
|
|
2108
2467
|
#
|
|
2109
|
-
#
|
|
2468
|
+
# <em>Requires +SAVEDATE+ capability.</em>
|
|
2469
|
+
# {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
|
|
2110
2470
|
#
|
|
2111
|
-
#
|
|
2112
|
-
# +YOUNGER+ _interval_::
|
|
2113
|
-
# Matches when +INTERNALDATE+ is more/less than _interval_ seconds ago.
|
|
2471
|
+
# ===== Other message attribute search keys
|
|
2114
2472
|
#
|
|
2115
|
-
#
|
|
2116
|
-
#
|
|
2473
|
+
# [+SMALLER+ _bytes_]
|
|
2474
|
+
# [+LARGER+ _bytes_]
|
|
2475
|
+
# Matches when +RFC822.SIZE+ is smaller or larger than _bytes_.
|
|
2117
2476
|
#
|
|
2118
|
-
# +ANNOTATION+ _entry_ _attr_ _value_
|
|
2477
|
+
# [+ANNOTATION+ _entry_ _attr_ _value_]
|
|
2119
2478
|
# Matches messages that have annotations with entries matching _entry_,
|
|
2120
2479
|
# attributes matching _attr_, and _value_ in the attribute's values.
|
|
2121
2480
|
#
|
|
2122
|
-
# <em>Requires
|
|
2481
|
+
# <em>Requires +ANNOTATE-EXPERIMENT-1+ capability</em>.
|
|
2123
2482
|
# {[RFC5257]}[https://www.rfc-editor.org/rfc/rfc5257.html].
|
|
2124
2483
|
#
|
|
2125
|
-
# +FILTER+ _filter_
|
|
2484
|
+
# [+FILTER+ _filter_]
|
|
2126
2485
|
# References a _filter_ that is stored on the server and matches all
|
|
2127
2486
|
# messages which would be matched by that filter's search criteria.
|
|
2128
2487
|
#
|
|
2129
|
-
# <em>Requires
|
|
2488
|
+
# <em>Requires +FILTERS+ capability</em>.
|
|
2130
2489
|
# {[RFC5466]}[https://www.rfc-editor.org/rfc/rfc5466.html#section-3.1]
|
|
2131
2490
|
#
|
|
2132
|
-
# +
|
|
2133
|
-
# Uses fuzzy matching for the specified search key.
|
|
2134
|
-
#
|
|
2135
|
-
# <em>Requires the <tt>SEARCH=FUZZY</tt> capability.</em>
|
|
2136
|
-
# {[RFC6203]}[https://www.rfc-editor.org/rfc/rfc6203.html#section-6].
|
|
2137
|
-
#
|
|
2138
|
-
# +MODSEQ+ _modseq_::
|
|
2491
|
+
# [+MODSEQ+ _modseq_]
|
|
2139
2492
|
# Matches when +MODSEQ+ is greater than or equal to _modseq_.
|
|
2140
2493
|
#
|
|
2141
|
-
# <em>Requires
|
|
2494
|
+
# <em>Requires +CONDSTORE+ capability</em>.
|
|
2142
2495
|
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
|
|
2143
2496
|
#
|
|
2144
|
-
# +MODSEQ+ _entry_ _entry-type_ _modseq_
|
|
2497
|
+
# [+MODSEQ+ _entry_ _entry-type_ _modseq_]
|
|
2145
2498
|
# Matches when a specific metadata _entry_ has been updated since
|
|
2146
2499
|
# _modseq_.
|
|
2147
2500
|
#
|
|
@@ -2150,33 +2503,25 @@ module Net
|
|
|
2150
2503
|
# <tt>\\</tt> prefix. _entry-type_ can be one of <tt>"shared"</tt>,
|
|
2151
2504
|
# <tt>"priv"</tt> (private), or <tt>"all"</tt>.
|
|
2152
2505
|
#
|
|
2153
|
-
# <em>Requires
|
|
2506
|
+
# <em>Requires +CONDSTORE+ capability</em>.
|
|
2154
2507
|
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html#section-3.1.5].
|
|
2155
2508
|
#
|
|
2156
|
-
# +EMAILID+ _objectid_
|
|
2157
|
-
# +THREADID+ _objectid_
|
|
2509
|
+
# [+EMAILID+ _objectid_]
|
|
2510
|
+
# [+THREADID+ _objectid_]
|
|
2158
2511
|
# Matches when +EMAILID+/+THREADID+ is equal to _objectid_
|
|
2159
2512
|
# (substring matches are not supported).
|
|
2160
2513
|
#
|
|
2161
|
-
# <em>Requires
|
|
2514
|
+
# <em>Requires +OBJECTID+ capability</em>.
|
|
2162
2515
|
# {[RFC8474]}[https://www.rfc-editor.org/rfc/rfc8474.html#section-6]
|
|
2163
2516
|
#
|
|
2164
|
-
#
|
|
2165
|
-
# Matches every message in the mailbox when the mailbox supports the save
|
|
2166
|
-
# date attribute. Otherwise, it matches no messages.
|
|
2167
|
-
#
|
|
2168
|
-
# <em>Requires the +SAVEDATE+ capability</em>.
|
|
2169
|
-
# {[RFC8514]}[https://www.rfc-editor.org/rfc/rfc8514.html#section-4.3]
|
|
2170
|
-
#
|
|
2171
|
-
# +SAVEDBEFORE+ _date_::
|
|
2172
|
-
# +SAVEDON+ _date_::
|
|
2173
|
-
# +SAVEDSINCE+ _date_::
|
|
2174
|
-
# Matches when the save date is earlier than, on, or later than _date_.
|
|
2517
|
+
# ==== Capabilities
|
|
2175
2518
|
#
|
|
2176
|
-
#
|
|
2177
|
-
#
|
|
2519
|
+
# Return options should only be specified when the server supports
|
|
2520
|
+
# +IMAP4rev2+ or an extension that allows them, such as +ESEARCH+
|
|
2521
|
+
# [RFC4731[https://rfc-editor.org/rfc/rfc4731#section-3.1]].
|
|
2178
2522
|
#
|
|
2179
|
-
#
|
|
2523
|
+
# When +IMAP4rev2+ is enabled, or when the server supports +IMAP4rev2+ but
|
|
2524
|
+
# not +IMAP4rev1+, ESearchResult is always returned instead of SearchResult.
|
|
2180
2525
|
#
|
|
2181
2526
|
# If CONDSTORE[https://www.rfc-editor.org/rfc/rfc7162.html] is supported
|
|
2182
2527
|
# and enabled for the selected mailbox, a non-empty SearchResult will
|
|
@@ -2185,12 +2530,16 @@ module Net
|
|
|
2185
2530
|
# result = imap.search(["SUBJECT", "hi there", "not", "new"])
|
|
2186
2531
|
# #=> Net::IMAP::SearchResult[1, 6, 7, 8, modseq: 5594]
|
|
2187
2532
|
# result.modseq # => 5594
|
|
2533
|
+
#
|
|
2534
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2535
|
+
# the +SEARCH+ command is prohibited. Use #uid_search instead.
|
|
2188
2536
|
def search(...)
|
|
2189
2537
|
search_internal("SEARCH", ...)
|
|
2190
2538
|
end
|
|
2191
2539
|
|
|
2192
2540
|
# :call-seq:
|
|
2193
2541
|
# uid_search(criteria, charset = nil) -> result
|
|
2542
|
+
# uid_search(criteria, charset: nil, return: nil) -> result
|
|
2194
2543
|
#
|
|
2195
2544
|
# Sends a {UID SEARCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
|
|
2196
2545
|
# to search the mailbox for messages that match the given searching
|
|
@@ -2201,6 +2550,16 @@ module Net
|
|
|
2201
2550
|
# capability has been enabled.
|
|
2202
2551
|
#
|
|
2203
2552
|
# See #search for documentation of parameters.
|
|
2553
|
+
#
|
|
2554
|
+
# ==== Capabilities
|
|
2555
|
+
#
|
|
2556
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2557
|
+
# #uid_search must be used instead of #search, and the <tt><message
|
|
2558
|
+
# set></tt> search criterion is prohibited. Use +ALL+ or <tt>UID
|
|
2559
|
+
# sequence-set</tt> instead.
|
|
2560
|
+
#
|
|
2561
|
+
# Otherwise, #uid_search is updated by extensions in the same way as
|
|
2562
|
+
# #search.
|
|
2204
2563
|
def uid_search(...)
|
|
2205
2564
|
search_internal("UID SEARCH", ...)
|
|
2206
2565
|
end
|
|
@@ -2211,26 +2570,21 @@ module Net
|
|
|
2211
2570
|
# Sends a {FETCH command [IMAP4rev1 §6.4.5]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.5]
|
|
2212
2571
|
# to retrieve data associated with a message in the mailbox.
|
|
2213
2572
|
#
|
|
2214
|
-
#
|
|
2215
|
-
#
|
|
2216
|
-
#
|
|
2217
|
-
# being interpreted as '100:*'. Beware that the +exclude_end?+
|
|
2218
|
-
# property of a Range object is ignored, and the contents of a
|
|
2219
|
-
# range are independent of the order of the range endpoints as per
|
|
2220
|
-
# the protocol specification, so 1...5, 5..1 and 5...1 are all
|
|
2221
|
-
# equivalent to 1..5.
|
|
2573
|
+
# +set+ is the message sequence numbers to fetch, and may be any valid input
|
|
2574
|
+
# to {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
|
|
2575
|
+
# (For UIDs, use #uid_fetch instead.)
|
|
2222
2576
|
#
|
|
2223
|
-
# +attr+ is a list of attributes to fetch; see
|
|
2224
|
-
#
|
|
2577
|
+
# +attr+ is a list of attributes to fetch; see FetchStruct documentation for
|
|
2578
|
+
# a list of supported attributes.
|
|
2225
2579
|
#
|
|
2226
2580
|
# +changedsince+ is an optional integer mod-sequence. It limits results to
|
|
2227
2581
|
# messages with a mod-sequence greater than +changedsince+.
|
|
2228
2582
|
#
|
|
2229
2583
|
# The return value is an array of FetchData.
|
|
2230
2584
|
#
|
|
2231
|
-
# Related: #
|
|
2585
|
+
# Related: #uid_fetch, FetchData
|
|
2232
2586
|
#
|
|
2233
|
-
#
|
|
2587
|
+
# ==== For example:
|
|
2234
2588
|
#
|
|
2235
2589
|
# p imap.fetch(6..8, "UID")
|
|
2236
2590
|
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
|
|
@@ -2248,39 +2602,82 @@ module Net
|
|
|
2248
2602
|
# p data.attr["UID"]
|
|
2249
2603
|
# #=> 98
|
|
2250
2604
|
#
|
|
2251
|
-
#
|
|
2605
|
+
# ==== Capabilities
|
|
2252
2606
|
#
|
|
2253
|
-
# Many extensions define new message +attr+ names. See
|
|
2254
|
-
# of supported extension fields.
|
|
2607
|
+
# Many extensions define new message +attr+ names. See FetchStruct for a
|
|
2608
|
+
# list of supported extension fields.
|
|
2255
2609
|
#
|
|
2256
2610
|
# The server's capabilities must include +CONDSTORE+
|
|
2257
|
-
# {[RFC7162]}[https://
|
|
2611
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
|
|
2258
2612
|
# +changedsince+ argument. Using +changedsince+ implicitly enables the
|
|
2259
2613
|
# +CONDSTORE+ extension.
|
|
2260
|
-
|
|
2261
|
-
|
|
2614
|
+
#
|
|
2615
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2616
|
+
# +FETCH+ command is prohibited. Use #uid_fetch instead.
|
|
2617
|
+
def fetch(...)
|
|
2618
|
+
fetch_internal("FETCH", ...)
|
|
2262
2619
|
end
|
|
2263
2620
|
|
|
2264
2621
|
# :call-seq:
|
|
2265
|
-
# uid_fetch(set, attr, changedsince: nil) -> array of FetchData
|
|
2622
|
+
# uid_fetch(set, attr, changedsince: nil, partial: nil) -> array of FetchData (or UIDFetchData)
|
|
2266
2623
|
#
|
|
2267
2624
|
# Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
|
|
2268
2625
|
# to retrieve data associated with a message in the mailbox.
|
|
2269
2626
|
#
|
|
2270
|
-
#
|
|
2271
|
-
#
|
|
2627
|
+
# +set+ is the message UIDs to fetch, and may be any valid input to
|
|
2628
|
+
# {SequenceSet[...]}[rdoc-ref:SequenceSet@Creating+sequence+sets].
|
|
2629
|
+
# (For message sequence numbers, use #fetch instead.)
|
|
2272
2630
|
#
|
|
2631
|
+
# +attr+ behaves the same as with #fetch.
|
|
2273
2632
|
# >>>
|
|
2274
2633
|
# *Note:* Servers _MUST_ implicitly include the +UID+ message data item as
|
|
2275
2634
|
# part of any +FETCH+ response caused by a +UID+ command, regardless of
|
|
2276
2635
|
# whether a +UID+ was specified as a message data item to the +FETCH+.
|
|
2277
2636
|
#
|
|
2637
|
+
# +changedsince+ (optional) behaves the same as with #fetch.
|
|
2638
|
+
#
|
|
2639
|
+
# +partial+ is an optional range to limit the number of results returned.
|
|
2640
|
+
# It's useful when +set+ contains an unknown number of messages.
|
|
2641
|
+
# <tt>1..500</tt> returns the first 500 messages in +set+ (in mailbox
|
|
2642
|
+
# order), <tt>501..1000</tt> the second 500, and so on. +partial+ may also
|
|
2643
|
+
# be negative: <tt>-500..-1</tt> selects the last 500 messages in +set+.
|
|
2644
|
+
# <em>Requires the +PARTIAL+ capabability.</em>
|
|
2645
|
+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
|
|
2646
|
+
#
|
|
2647
|
+
# For example:
|
|
2648
|
+
#
|
|
2649
|
+
# # Without partial, the size of the results may be unknown beforehand:
|
|
2650
|
+
# results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS))
|
|
2651
|
+
# # ... maybe wait for a long time ... and allocate a lot of memory ...
|
|
2652
|
+
# results.size # => 0..2**32-1
|
|
2653
|
+
# process results # may also take a long time and use a lot of memory...
|
|
2654
|
+
#
|
|
2655
|
+
# # Using partial, the results may be paginated:
|
|
2656
|
+
# loop do
|
|
2657
|
+
# results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS),
|
|
2658
|
+
# partial: 1..500)
|
|
2659
|
+
# # fetch should return quickly and allocate little memory
|
|
2660
|
+
# results.size # => 0..500
|
|
2661
|
+
# break if results.empty?
|
|
2662
|
+
# next_uid_to_fetch = results.last.uid + 1
|
|
2663
|
+
# process results
|
|
2664
|
+
# end
|
|
2665
|
+
#
|
|
2278
2666
|
# Related: #fetch, FetchData
|
|
2279
2667
|
#
|
|
2280
|
-
#
|
|
2281
|
-
#
|
|
2282
|
-
|
|
2283
|
-
|
|
2668
|
+
# ==== Capabilities
|
|
2669
|
+
#
|
|
2670
|
+
# The server's capabilities must include +PARTIAL+
|
|
2671
|
+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394] in order to use the
|
|
2672
|
+
# +partial+ argument.
|
|
2673
|
+
#
|
|
2674
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2675
|
+
# #uid_fetch must be used instead of #fetch, and UIDFetchData will be
|
|
2676
|
+
# returned instead of FetchData.
|
|
2677
|
+
#
|
|
2678
|
+
# Otherwise, #uid_fetch is updated by extensions in the same way as #fetch.
|
|
2679
|
+
def uid_fetch(...)
|
|
2680
|
+
fetch_internal("UID FETCH", ...)
|
|
2284
2681
|
end
|
|
2285
2682
|
|
|
2286
2683
|
# :call-seq:
|
|
@@ -2311,27 +2708,30 @@ module Net
|
|
|
2311
2708
|
#
|
|
2312
2709
|
# Related: #uid_store
|
|
2313
2710
|
#
|
|
2314
|
-
#
|
|
2711
|
+
# ==== For example:
|
|
2315
2712
|
#
|
|
2316
2713
|
# p imap.store(6..8, "+FLAGS", [:Deleted])
|
|
2317
2714
|
# #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>,
|
|
2318
2715
|
# #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>,
|
|
2319
2716
|
# #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
|
|
2320
2717
|
#
|
|
2321
|
-
#
|
|
2718
|
+
# ==== Capabilities
|
|
2322
2719
|
#
|
|
2323
2720
|
# Extensions may define new data items to be used with #store.
|
|
2324
2721
|
#
|
|
2325
2722
|
# The server's capabilities must include +CONDSTORE+
|
|
2326
|
-
# {[RFC7162]}[https://
|
|
2723
|
+
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162] in order to use the
|
|
2327
2724
|
# +unchangedsince+ argument. Using +unchangedsince+ implicitly enables the
|
|
2328
2725
|
# +CONDSTORE+ extension.
|
|
2726
|
+
#
|
|
2727
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2728
|
+
# +STORE+ command is prohibited. Use #uid_store instead.
|
|
2329
2729
|
def store(set, attr, flags, unchangedsince: nil)
|
|
2330
2730
|
store_internal("STORE", set, attr, flags, unchangedsince: unchangedsince)
|
|
2331
2731
|
end
|
|
2332
2732
|
|
|
2333
2733
|
# :call-seq:
|
|
2334
|
-
# uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData
|
|
2734
|
+
# uid_store(set, attr, value, unchangedsince: nil) -> array of FetchData (or UIDFetchData)
|
|
2335
2735
|
#
|
|
2336
2736
|
# Sends a {UID STORE command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
|
|
2337
2737
|
# to alter data associated with messages in the mailbox, in particular their
|
|
@@ -2342,8 +2742,13 @@ module Net
|
|
|
2342
2742
|
#
|
|
2343
2743
|
# Related: #store
|
|
2344
2744
|
#
|
|
2345
|
-
#
|
|
2346
|
-
#
|
|
2745
|
+
# ==== Capabilities
|
|
2746
|
+
#
|
|
2747
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2748
|
+
# #uid_store must be used instead of #store, and UIDFetchData will be
|
|
2749
|
+
# returned instead of FetchData.
|
|
2750
|
+
#
|
|
2751
|
+
# Otherwise, #uid_store is updated by extensions in the same way as #store.
|
|
2347
2752
|
def uid_store(set, attr, flags, unchangedsince: nil)
|
|
2348
2753
|
store_internal("UID STORE", set, attr, flags, unchangedsince: unchangedsince)
|
|
2349
2754
|
end
|
|
@@ -2355,13 +2760,16 @@ module Net
|
|
|
2355
2760
|
#
|
|
2356
2761
|
# Related: #uid_copy
|
|
2357
2762
|
#
|
|
2358
|
-
#
|
|
2763
|
+
# ==== Capabilities
|
|
2359
2764
|
#
|
|
2360
2765
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2361
2766
|
# supported, the server's response should include a +COPYUID+ response code
|
|
2362
2767
|
# with UIDPlusData. This will report the UIDVALIDITY of the destination
|
|
2363
2768
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2364
2769
|
# the moved messages.
|
|
2770
|
+
#
|
|
2771
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2772
|
+
# +COPY+ command is prohibited. Use #uid_copy instead.
|
|
2365
2773
|
def copy(set, mailbox)
|
|
2366
2774
|
copy_internal("COPY", set, mailbox)
|
|
2367
2775
|
end
|
|
@@ -2372,9 +2780,12 @@ module Net
|
|
|
2372
2780
|
#
|
|
2373
2781
|
# Similar to #copy, but +set+ contains unique identifiers.
|
|
2374
2782
|
#
|
|
2375
|
-
#
|
|
2783
|
+
# ==== Capabilities
|
|
2376
2784
|
#
|
|
2377
|
-
#
|
|
2785
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] in enabled,
|
|
2786
|
+
# #uid_copy must be used instead of #copy.
|
|
2787
|
+
#
|
|
2788
|
+
# Otherwise, #uid_copy is updated by extensions in the same way as #copy.
|
|
2378
2789
|
def uid_copy(set, mailbox)
|
|
2379
2790
|
copy_internal("UID COPY", set, mailbox)
|
|
2380
2791
|
end
|
|
@@ -2387,10 +2798,10 @@ module Net
|
|
|
2387
2798
|
#
|
|
2388
2799
|
# Related: #uid_move
|
|
2389
2800
|
#
|
|
2390
|
-
#
|
|
2801
|
+
# ==== Capabilities
|
|
2391
2802
|
#
|
|
2392
|
-
# The server's capabilities must include +MOVE+
|
|
2393
|
-
# [RFC6851[https://
|
|
2803
|
+
# The server's capabilities must include either +IMAP4rev2+ or +MOVE+
|
|
2804
|
+
# [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
|
|
2394
2805
|
#
|
|
2395
2806
|
# If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is
|
|
2396
2807
|
# supported, the server's response should include a +COPYUID+ response code
|
|
@@ -2398,6 +2809,8 @@ module Net
|
|
|
2398
2809
|
# mailbox, the UID set of the source messages, and the assigned UID set of
|
|
2399
2810
|
# the moved messages.
|
|
2400
2811
|
#
|
|
2812
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled, the
|
|
2813
|
+
# +MOVE+ command is prohibited. Use #uid_move instead.
|
|
2401
2814
|
def move(set, mailbox)
|
|
2402
2815
|
copy_internal("MOVE", set, mailbox)
|
|
2403
2816
|
end
|
|
@@ -2411,11 +2824,15 @@ module Net
|
|
|
2411
2824
|
#
|
|
2412
2825
|
# Related: #move
|
|
2413
2826
|
#
|
|
2414
|
-
#
|
|
2827
|
+
# ==== Capabilities
|
|
2415
2828
|
#
|
|
2416
|
-
#
|
|
2417
|
-
# [RFC6851[https://
|
|
2418
|
-
#
|
|
2829
|
+
# The server's capabilities must include either +IMAP4rev2+ or +MOVE+
|
|
2830
|
+
# [RFC6851[https://www.rfc-editor.org/rfc/rfc6851]].
|
|
2831
|
+
#
|
|
2832
|
+
# When UIDONLY[https://www.rfc-editor.org/rfc/rfc9586.html] is enabled,
|
|
2833
|
+
# #uid_move must be used instead of #move.
|
|
2834
|
+
#
|
|
2835
|
+
# Otherwise, #uid_move is updated by extensions in the same way as #move.
|
|
2419
2836
|
def uid_move(set, mailbox)
|
|
2420
2837
|
copy_internal("UID MOVE", set, mailbox)
|
|
2421
2838
|
end
|
|
@@ -2431,17 +2848,17 @@ module Net
|
|
|
2431
2848
|
#
|
|
2432
2849
|
# Related: #uid_sort, #search, #uid_search, #thread, #uid_thread
|
|
2433
2850
|
#
|
|
2434
|
-
#
|
|
2851
|
+
# ==== For example:
|
|
2435
2852
|
#
|
|
2436
2853
|
# p imap.sort(["FROM"], ["ALL"], "US-ASCII")
|
|
2437
2854
|
# #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
|
|
2438
2855
|
# p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
|
|
2439
2856
|
# #=> [6, 7, 8, 1]
|
|
2440
2857
|
#
|
|
2441
|
-
#
|
|
2858
|
+
# ==== Capabilities
|
|
2442
2859
|
#
|
|
2443
2860
|
# The server's capabilities must include +SORT+
|
|
2444
|
-
# [RFC5256[https://
|
|
2861
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2445
2862
|
def sort(sort_keys, search_keys, charset)
|
|
2446
2863
|
return sort_internal("SORT", sort_keys, search_keys, charset)
|
|
2447
2864
|
end
|
|
@@ -2453,10 +2870,10 @@ module Net
|
|
|
2453
2870
|
#
|
|
2454
2871
|
# Related: #sort, #search, #uid_search, #thread, #uid_thread
|
|
2455
2872
|
#
|
|
2456
|
-
#
|
|
2873
|
+
# ==== Capabilities
|
|
2457
2874
|
#
|
|
2458
2875
|
# The server's capabilities must include +SORT+
|
|
2459
|
-
# [RFC5256[https://
|
|
2876
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2460
2877
|
def uid_sort(sort_keys, search_keys, charset)
|
|
2461
2878
|
return sort_internal("UID SORT", sort_keys, search_keys, charset)
|
|
2462
2879
|
end
|
|
@@ -2478,10 +2895,10 @@ module Net
|
|
|
2478
2895
|
#
|
|
2479
2896
|
# Related: #uid_thread, #search, #uid_search, #sort, #uid_sort
|
|
2480
2897
|
#
|
|
2481
|
-
#
|
|
2898
|
+
# ==== Capabilities
|
|
2482
2899
|
#
|
|
2483
2900
|
# The server's capabilities must include +THREAD+
|
|
2484
|
-
# [RFC5256[https://
|
|
2901
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2485
2902
|
def thread(algorithm, search_keys, charset)
|
|
2486
2903
|
return thread_internal("THREAD", algorithm, search_keys, charset)
|
|
2487
2904
|
end
|
|
@@ -2492,10 +2909,10 @@ module Net
|
|
|
2492
2909
|
#
|
|
2493
2910
|
# Related: #thread, #search, #uid_search, #sort, #uid_sort
|
|
2494
2911
|
#
|
|
2495
|
-
#
|
|
2912
|
+
# ==== Capabilities
|
|
2496
2913
|
#
|
|
2497
2914
|
# The server's capabilities must include +THREAD+
|
|
2498
|
-
# [RFC5256[https://
|
|
2915
|
+
# [RFC5256[https://www.rfc-editor.org/rfc/rfc5256]].
|
|
2499
2916
|
def uid_thread(algorithm, search_keys, charset)
|
|
2500
2917
|
return thread_internal("UID THREAD", algorithm, search_keys, charset)
|
|
2501
2918
|
end
|
|
@@ -2511,11 +2928,11 @@ module Net
|
|
|
2511
2928
|
#
|
|
2512
2929
|
# Related: #capable?, #capabilities, #capability
|
|
2513
2930
|
#
|
|
2514
|
-
#
|
|
2931
|
+
# ==== Capabilities
|
|
2515
2932
|
#
|
|
2516
2933
|
# The server's capabilities must include
|
|
2517
|
-
# +ENABLE+ [RFC5161[https://
|
|
2518
|
-
# or +IMAP4REV2+ [RFC9051[https://
|
|
2934
|
+
# +ENABLE+ [RFC5161[https://www.rfc-editor.org/rfc/rfc5161]]
|
|
2935
|
+
# or +IMAP4REV2+ [RFC9051[https://www.rfc-editor.org/rfc/rfc9051]].
|
|
2519
2936
|
#
|
|
2520
2937
|
# Additionally, the server capabilities must include a capability matching
|
|
2521
2938
|
# each enabled extension (usually the same name as the enabled extension).
|
|
@@ -2534,7 +2951,7 @@ module Net
|
|
|
2534
2951
|
# <tt>"UTF8=ACCEPT"</tt> or <tt>"IMAP4rev2"</tt>, depending on server
|
|
2535
2952
|
# capabilities.
|
|
2536
2953
|
#
|
|
2537
|
-
# [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://
|
|
2954
|
+
# [<tt>"UTF8=ACCEPT"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
|
|
2538
2955
|
#
|
|
2539
2956
|
# The server's capabilities must include <tt>UTF8=ACCEPT</tt> _or_
|
|
2540
2957
|
# <tt>UTF8=ONLY</tt>.
|
|
@@ -2553,13 +2970,23 @@ module Net
|
|
|
2553
2970
|
# encoding, even if they generally contain UTF-8 data, if they are
|
|
2554
2971
|
# text at all.
|
|
2555
2972
|
#
|
|
2556
|
-
# [<tt>"UTF8=ONLY"</tt> [RFC6855[https://
|
|
2973
|
+
# [<tt>"UTF8=ONLY"</tt> [RFC6855[https://www.rfc-editor.org/rfc/rfc6855]]]
|
|
2557
2974
|
#
|
|
2558
2975
|
# A server that reports the <tt>UTF8=ONLY</tt> capability _requires_ that
|
|
2559
2976
|
# the client <tt>enable("UTF8=ACCEPT")</tt> before any mailboxes may be
|
|
2560
2977
|
# selected. For convenience, <tt>enable("UTF8=ONLY")</tt> is aliased to
|
|
2561
2978
|
# <tt>enable("UTF8=ACCEPT")</tt>.
|
|
2562
2979
|
#
|
|
2980
|
+
# [+UIDONLY+ {[RFC9586]}[https://www.rfc-editor.org/rfc/rfc9586.pdf]]
|
|
2981
|
+
#
|
|
2982
|
+
# When UIDONLY is enabled, the #fetch, #store, #search, #copy, and #move
|
|
2983
|
+
# commands are prohibited and result in a tagged BAD response. Clients
|
|
2984
|
+
# should instead use uid_fetch, uid_store, uid_search, uid_copy, or
|
|
2985
|
+
# uid_move, respectively. All +FETCH+ responses that would be returned are
|
|
2986
|
+
# replaced by +UIDFETCH+ responses. All +EXPUNGED+ responses that would be
|
|
2987
|
+
# returned are replaced by +VANISHED+ responses. The "<sequence set>"
|
|
2988
|
+
# uid_search criterion is prohibited.
|
|
2989
|
+
#
|
|
2563
2990
|
# ===== Unsupported capabilities
|
|
2564
2991
|
#
|
|
2565
2992
|
# *Note:* Some extensions that use ENABLE permit the server to send syntax
|
|
@@ -2613,10 +3040,10 @@ module Net
|
|
|
2613
3040
|
#
|
|
2614
3041
|
# Related: #idle_done, #noop, #check
|
|
2615
3042
|
#
|
|
2616
|
-
#
|
|
3043
|
+
# ==== Capabilities
|
|
2617
3044
|
#
|
|
2618
|
-
# The server's capabilities must include +IDLE+
|
|
2619
|
-
# [RFC2177[https://
|
|
3045
|
+
# The server's capabilities must include either +IMAP4rev2+ or +IDLE+
|
|
3046
|
+
# [RFC2177[https://www.rfc-editor.org/rfc/rfc2177]].
|
|
2620
3047
|
def idle(timeout = nil, &response_handler)
|
|
2621
3048
|
raise LocalJumpError, "no block given" unless response_handler
|
|
2622
3049
|
|
|
@@ -2730,7 +3157,7 @@ module Net
|
|
|
2730
3157
|
#
|
|
2731
3158
|
# Related: #extract_responses, #clear_responses, #response_handlers, #greeting
|
|
2732
3159
|
#
|
|
2733
|
-
#
|
|
3160
|
+
# ==== Thread safety
|
|
2734
3161
|
# >>>
|
|
2735
3162
|
# *Note:* Access to the responses hash is synchronized for thread-safety.
|
|
2736
3163
|
# The receiver thread and response_handlers cannot process new responses
|
|
@@ -2744,7 +3171,7 @@ module Net
|
|
|
2744
3171
|
# thread, but will not modify any responses after adding them to the
|
|
2745
3172
|
# responses hash.
|
|
2746
3173
|
#
|
|
2747
|
-
#
|
|
3174
|
+
# ==== Clearing responses
|
|
2748
3175
|
#
|
|
2749
3176
|
# Previously unhandled responses are automatically cleared before entering a
|
|
2750
3177
|
# mailbox with #select or #examine. Long-lived connections can receive many
|
|
@@ -2753,7 +3180,7 @@ module Net
|
|
|
2753
3180
|
# the block, or remove responses with #extract_responses, #clear_responses,
|
|
2754
3181
|
# or #add_response_handler.
|
|
2755
3182
|
#
|
|
2756
|
-
#
|
|
3183
|
+
# ==== Missing responses
|
|
2757
3184
|
#
|
|
2758
3185
|
# Only non-+nil+ data is stored. Many important response codes have no data
|
|
2759
3186
|
# of their own, but are used as "tags" on the ResponseText object they are
|
|
@@ -2864,6 +3291,10 @@ module Net
|
|
|
2864
3291
|
# end
|
|
2865
3292
|
# }
|
|
2866
3293
|
#
|
|
3294
|
+
# Response handlers can also be added when the client is created before the
|
|
3295
|
+
# receiver thread is started, by the +response_handlers+ argument to ::new.
|
|
3296
|
+
# This ensures every server response is handled, including the #greeting.
|
|
3297
|
+
#
|
|
2867
3298
|
# Related: #remove_response_handler, #response_handlers
|
|
2868
3299
|
def add_response_handler(handler = nil, &block)
|
|
2869
3300
|
raise ArgumentError, "two Procs are passed" if handler && block
|
|
@@ -2890,8 +3321,10 @@ module Net
|
|
|
2890
3321
|
def start_imap_connection
|
|
2891
3322
|
@greeting = get_server_greeting
|
|
2892
3323
|
@capabilities = capabilities_from_resp_code @greeting
|
|
3324
|
+
@response_handlers.each do |handler| handler.call(@greeting) end
|
|
2893
3325
|
@receiver_thread = start_receiver_thread
|
|
2894
3326
|
rescue Exception
|
|
3327
|
+
state_logout!
|
|
2895
3328
|
@sock.close
|
|
2896
3329
|
raise
|
|
2897
3330
|
end
|
|
@@ -2900,7 +3333,10 @@ module Net
|
|
|
2900
3333
|
greeting = get_response
|
|
2901
3334
|
raise Error, "No server greeting - connection closed" unless greeting
|
|
2902
3335
|
record_untagged_response_code greeting
|
|
2903
|
-
|
|
3336
|
+
case greeting.name
|
|
3337
|
+
when "PREAUTH" then state_authenticated!
|
|
3338
|
+
when "BYE" then state_logout!; raise ByeResponseError, greeting
|
|
3339
|
+
end
|
|
2904
3340
|
greeting
|
|
2905
3341
|
end
|
|
2906
3342
|
|
|
@@ -2910,6 +3346,8 @@ module Net
|
|
|
2910
3346
|
rescue Exception => ex
|
|
2911
3347
|
@receiver_thread_exception = ex
|
|
2912
3348
|
# don't exit the thread with an exception
|
|
3349
|
+
ensure
|
|
3350
|
+
state_logout!
|
|
2913
3351
|
end
|
|
2914
3352
|
end
|
|
2915
3353
|
|
|
@@ -2932,6 +3370,7 @@ module Net
|
|
|
2932
3370
|
resp = get_response
|
|
2933
3371
|
rescue Exception => e
|
|
2934
3372
|
synchronize do
|
|
3373
|
+
state_logout!
|
|
2935
3374
|
@sock.close
|
|
2936
3375
|
@exception = e
|
|
2937
3376
|
end
|
|
@@ -2951,6 +3390,7 @@ module Net
|
|
|
2951
3390
|
@tagged_response_arrival.broadcast
|
|
2952
3391
|
case resp.tag
|
|
2953
3392
|
when @logout_command_tag
|
|
3393
|
+
state_logout!
|
|
2954
3394
|
return
|
|
2955
3395
|
when @continued_command_tag
|
|
2956
3396
|
@continuation_request_exception =
|
|
@@ -2960,6 +3400,7 @@ module Net
|
|
|
2960
3400
|
when UntaggedResponse
|
|
2961
3401
|
record_untagged_response(resp)
|
|
2962
3402
|
if resp.name == "BYE" && @logout_command_tag.nil?
|
|
3403
|
+
state_logout!
|
|
2963
3404
|
@sock.close
|
|
2964
3405
|
@exception = ByeResponseError.new(resp)
|
|
2965
3406
|
connection_closed = true
|
|
@@ -2967,6 +3408,7 @@ module Net
|
|
|
2967
3408
|
when ContinuationRequest
|
|
2968
3409
|
@continuation_request_arrival.signal
|
|
2969
3410
|
end
|
|
3411
|
+
state_unselected! if resp in {data: {code: {name: "CLOSED"}}}
|
|
2970
3412
|
@response_handlers.each do |handler|
|
|
2971
3413
|
handler.call(resp)
|
|
2972
3414
|
end
|
|
@@ -3018,23 +3460,10 @@ module Net
|
|
|
3018
3460
|
end
|
|
3019
3461
|
|
|
3020
3462
|
def get_response
|
|
3021
|
-
buff =
|
|
3022
|
-
while true
|
|
3023
|
-
s = @sock.gets(CRLF)
|
|
3024
|
-
break unless s
|
|
3025
|
-
buff.concat(s)
|
|
3026
|
-
if /\{(\d+)\}\r\n/n =~ s
|
|
3027
|
-
s = @sock.read($1.to_i)
|
|
3028
|
-
buff.concat(s)
|
|
3029
|
-
else
|
|
3030
|
-
break
|
|
3031
|
-
end
|
|
3032
|
-
end
|
|
3463
|
+
buff = @reader.read_response_buffer
|
|
3033
3464
|
return nil if buff.length == 0
|
|
3034
|
-
if config.debug?
|
|
3035
|
-
|
|
3036
|
-
end
|
|
3037
|
-
return @parser.parse(buff)
|
|
3465
|
+
$stderr.print(buff.gsub(/^/n, "S: ")) if config.debug?
|
|
3466
|
+
@parser.parse(buff)
|
|
3038
3467
|
end
|
|
3039
3468
|
|
|
3040
3469
|
#############################
|
|
@@ -3131,16 +3560,107 @@ module Net
|
|
|
3131
3560
|
end
|
|
3132
3561
|
end
|
|
3133
3562
|
|
|
3134
|
-
def
|
|
3135
|
-
|
|
3136
|
-
|
|
3563
|
+
def expunge_internal(...)
|
|
3564
|
+
synchronize do
|
|
3565
|
+
send_command(...)
|
|
3566
|
+
expunged_array = clear_responses("EXPUNGE")
|
|
3567
|
+
vanished_array = extract_responses("VANISHED") { !_1.earlier? }
|
|
3568
|
+
if vanished_array.empty?
|
|
3569
|
+
expunged_array
|
|
3570
|
+
elsif vanished_array.length == 1
|
|
3571
|
+
vanished_array.first
|
|
3572
|
+
else
|
|
3573
|
+
merged_uids = SequenceSet[*vanished_array.map(&:uids)]
|
|
3574
|
+
VanishedData[uids: merged_uids, earlier: false]
|
|
3575
|
+
end
|
|
3576
|
+
end
|
|
3577
|
+
end
|
|
3578
|
+
|
|
3579
|
+
RETURN_WHOLE = /\ARETURN\z/i
|
|
3580
|
+
RETURN_START = /\ARETURN\b/i
|
|
3581
|
+
private_constant :RETURN_WHOLE, :RETURN_START
|
|
3582
|
+
|
|
3583
|
+
def search_args(keys, charset_arg = nil, return: nil, charset: nil)
|
|
3584
|
+
{return:} => {return: return_kw}
|
|
3585
|
+
case [return_kw, keys]
|
|
3586
|
+
in [nil, Array[RETURN_WHOLE, return_opts, *keys]]
|
|
3587
|
+
return_opts = convert_return_opts(return_opts)
|
|
3588
|
+
esearch = true
|
|
3589
|
+
in [nil => return_opts, RETURN_START]
|
|
3590
|
+
esearch = true
|
|
3591
|
+
in [nil => return_opts, keys]
|
|
3592
|
+
esearch = false
|
|
3593
|
+
in [_, Array[RETURN_WHOLE, _, *] | RETURN_START]
|
|
3594
|
+
raise ArgumentError, "conflicting return options"
|
|
3595
|
+
in [_, Array[RETURN_WHOLE, _, *]] # workaround for https://bugs.ruby-lang.org/issues/20956
|
|
3596
|
+
raise ArgumentError, "conflicting return options"
|
|
3597
|
+
in [_, RETURN_START] # workaround for https://bugs.ruby-lang.org/issues/20956
|
|
3598
|
+
raise ArgumentError, "conflicting return options"
|
|
3599
|
+
in [return_opts, keys]
|
|
3600
|
+
return_opts = convert_return_opts(return_opts)
|
|
3601
|
+
esearch = true
|
|
3602
|
+
end
|
|
3603
|
+
if charset && charset_arg
|
|
3604
|
+
raise ArgumentError, "multiple charset arguments"
|
|
3605
|
+
end
|
|
3606
|
+
charset ||= charset_arg
|
|
3607
|
+
# NOTE: not handling combined RETURN and CHARSET for raw strings
|
|
3608
|
+
if charset && keys in /\ACHARSET\b/i | Array[/\ACHARSET\z/i, *]
|
|
3609
|
+
raise ArgumentError, "multiple charset arguments"
|
|
3610
|
+
end
|
|
3611
|
+
args = normalize_searching_criteria(keys)
|
|
3612
|
+
args.prepend("CHARSET", charset) if charset
|
|
3613
|
+
args.prepend("RETURN", return_opts) if return_opts
|
|
3614
|
+
return args, esearch
|
|
3615
|
+
end
|
|
3616
|
+
|
|
3617
|
+
def convert_return_opts(unconverted)
|
|
3618
|
+
return_opts = Array.try_convert(unconverted) or
|
|
3619
|
+
raise TypeError, "expected return options to be Array, got %s" % [
|
|
3620
|
+
unconverted.class
|
|
3621
|
+
]
|
|
3622
|
+
return_opts.map {|opt|
|
|
3623
|
+
case opt
|
|
3624
|
+
when Symbol then opt.to_s
|
|
3625
|
+
when PartialRange::Negative then PartialRange[opt]
|
|
3626
|
+
when Range then SequenceSet[opt]
|
|
3627
|
+
else opt
|
|
3628
|
+
end
|
|
3629
|
+
}
|
|
3630
|
+
end
|
|
3631
|
+
|
|
3632
|
+
def search_internal(cmd, ...)
|
|
3633
|
+
args, esearch = search_args(...)
|
|
3137
3634
|
synchronize do
|
|
3138
|
-
send_command(cmd, *args)
|
|
3139
|
-
|
|
3635
|
+
tagged = send_command(cmd, *args)
|
|
3636
|
+
tag = tagged.tag
|
|
3637
|
+
# Only the last ESEARCH or SEARCH is used. Excess results are ignored.
|
|
3638
|
+
esearch_result = extract_responses("ESEARCH") {|response|
|
|
3639
|
+
response in ESearchResult(tag: ^tag)
|
|
3640
|
+
}.last
|
|
3641
|
+
search_result = clear_responses("SEARCH").last
|
|
3642
|
+
if esearch_result
|
|
3643
|
+
# silently ignore SEARCH results, if any
|
|
3644
|
+
esearch_result
|
|
3645
|
+
elsif search_result
|
|
3646
|
+
# warn EXPECTED_ESEARCH_RESULT if esearch
|
|
3647
|
+
search_result
|
|
3648
|
+
elsif esearch
|
|
3649
|
+
# warn NO_SEARCH_RESPONSE
|
|
3650
|
+
ESearchResult[tag:, uid: cmd.start_with?("UID ")]
|
|
3651
|
+
else
|
|
3652
|
+
# warn NO_SEARCH_RESPONSE
|
|
3653
|
+
SearchResult[]
|
|
3654
|
+
end
|
|
3140
3655
|
end
|
|
3141
3656
|
end
|
|
3142
3657
|
|
|
3143
|
-
def fetch_internal(cmd, set, attr, mod = nil, changedsince: nil)
|
|
3658
|
+
def fetch_internal(cmd, set, attr, mod = nil, partial: nil, changedsince: nil)
|
|
3659
|
+
set = SequenceSet[set]
|
|
3660
|
+
if partial
|
|
3661
|
+
mod ||= []
|
|
3662
|
+
mod << "PARTIAL" << PartialRange[partial]
|
|
3663
|
+
end
|
|
3144
3664
|
if changedsince
|
|
3145
3665
|
mod ||= []
|
|
3146
3666
|
mod << "CHANGEDSINCE" << Integer(changedsince)
|
|
@@ -3154,15 +3674,9 @@ module Net
|
|
|
3154
3674
|
}
|
|
3155
3675
|
end
|
|
3156
3676
|
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
send_command(cmd, SequenceSet.new(set), attr, mod)
|
|
3161
|
-
else
|
|
3162
|
-
send_command(cmd, SequenceSet.new(set), attr)
|
|
3163
|
-
end
|
|
3164
|
-
clear_responses("FETCH")
|
|
3165
|
-
end
|
|
3677
|
+
args = [cmd, set, attr]
|
|
3678
|
+
args << mod if mod
|
|
3679
|
+
send_command_returning_fetch_results(*args)
|
|
3166
3680
|
end
|
|
3167
3681
|
|
|
3168
3682
|
def store_internal(cmd, set, attr, flags, unchangedsince: nil)
|
|
@@ -3170,10 +3684,17 @@ module Net
|
|
|
3170
3684
|
args = [SequenceSet.new(set)]
|
|
3171
3685
|
args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
|
|
3172
3686
|
args << attr << flags
|
|
3687
|
+
send_command_returning_fetch_results(cmd, *args)
|
|
3688
|
+
end
|
|
3689
|
+
|
|
3690
|
+
def send_command_returning_fetch_results(...)
|
|
3173
3691
|
synchronize do
|
|
3174
3692
|
clear_responses("FETCH")
|
|
3175
|
-
|
|
3176
|
-
|
|
3693
|
+
clear_responses("UIDFETCH")
|
|
3694
|
+
send_command(...)
|
|
3695
|
+
fetches = clear_responses("FETCH")
|
|
3696
|
+
uidfetches = clear_responses("UIDFETCH")
|
|
3697
|
+
uidfetches.any? ? uidfetches : fetches
|
|
3177
3698
|
end
|
|
3178
3699
|
end
|
|
3179
3700
|
|
|
@@ -3198,7 +3719,7 @@ module Net
|
|
|
3198
3719
|
end
|
|
3199
3720
|
|
|
3200
3721
|
def normalize_searching_criteria(criteria)
|
|
3201
|
-
return RawData.new(criteria) if criteria.is_a?(String)
|
|
3722
|
+
return [RawData.new(criteria)] if criteria.is_a?(String)
|
|
3202
3723
|
criteria.map {|i|
|
|
3203
3724
|
if coerce_search_arg_to_seqset?(i)
|
|
3204
3725
|
SequenceSet[i]
|
|
@@ -3246,6 +3767,7 @@ module Net
|
|
|
3246
3767
|
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
|
|
3247
3768
|
raise "cannot start TLS without SSLContext" unless ssl_ctx
|
|
3248
3769
|
@sock = SSLSocket.new(@sock, ssl_ctx)
|
|
3770
|
+
@reader = ResponseReader.new(self, @sock)
|
|
3249
3771
|
@sock.sync_close = true
|
|
3250
3772
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
|
3251
3773
|
ssl_socket_connect(@sock, open_timeout)
|
|
@@ -3255,6 +3777,29 @@ module Net
|
|
|
3255
3777
|
end
|
|
3256
3778
|
end
|
|
3257
3779
|
|
|
3780
|
+
def state_authenticated!(resp = nil)
|
|
3781
|
+
synchronize do
|
|
3782
|
+
@capabilities = capabilities_from_resp_code resp if resp
|
|
3783
|
+
@connection_state = ConnectionState::Authenticated.new
|
|
3784
|
+
end
|
|
3785
|
+
end
|
|
3786
|
+
|
|
3787
|
+
def state_selected!
|
|
3788
|
+
synchronize do
|
|
3789
|
+
@connection_state = ConnectionState::Selected.new
|
|
3790
|
+
end
|
|
3791
|
+
end
|
|
3792
|
+
|
|
3793
|
+
def state_unselected!
|
|
3794
|
+
state_authenticated! if connection_state.to_sym == :selected
|
|
3795
|
+
end
|
|
3796
|
+
|
|
3797
|
+
def state_logout!
|
|
3798
|
+
synchronize do
|
|
3799
|
+
@connection_state = ConnectionState::Logout.new
|
|
3800
|
+
end
|
|
3801
|
+
end
|
|
3802
|
+
|
|
3258
3803
|
def sasl_adapter
|
|
3259
3804
|
SASLAdapter.new(self, &method(:send_command_with_continuations))
|
|
3260
3805
|
end
|
|
@@ -3276,6 +3821,7 @@ require_relative "imap/errors"
|
|
|
3276
3821
|
require_relative "imap/config"
|
|
3277
3822
|
require_relative "imap/command_data"
|
|
3278
3823
|
require_relative "imap/data_encoding"
|
|
3824
|
+
require_relative "imap/data_lite"
|
|
3279
3825
|
require_relative "imap/flags"
|
|
3280
3826
|
require_relative "imap/response_data"
|
|
3281
3827
|
require_relative "imap/response_parser"
|