net-imap 0.4.19 → 0.4.24
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 -1
- data/lib/net/imap/command_data.rb +182 -21
- data/lib/net/imap/config/attr_type_coercion.rb +23 -22
- data/lib/net/imap/config.rb +101 -20
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/response_data.rb +22 -2
- data/lib/net/imap/response_reader.rb +82 -0
- data/lib/net/imap/sasl/scram_authenticator.rb +74 -0
- data/lib/net/imap/sequence_set.rb +70 -63
- data/lib/net/imap.rb +215 -69
- metadata +4 -3
data/lib/net/imap.rb
CHANGED
|
@@ -43,10 +43,16 @@ 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
|
+
#
|
|
50
56
|
# === Sequence numbers and UIDs
|
|
51
57
|
#
|
|
52
58
|
# Messages have two sorts of identifiers: message sequence
|
|
@@ -199,6 +205,42 @@ module Net
|
|
|
199
205
|
#
|
|
200
206
|
# This script invokes the FETCH command and the SEARCH command concurrently.
|
|
201
207
|
#
|
|
208
|
+
# When running multiple commands, care must be taken to avoid ambiguity. For
|
|
209
|
+
# example, SEARCH responses are ambiguous about which command they are
|
|
210
|
+
# responding to, so search commands should not run simultaneously, unless the
|
|
211
|
+
# server supports +ESEARCH+ {[RFC4731]}[https://rfc-editor.org/rfc/rfc4731] or
|
|
212
|
+
# IMAP4rev2[https://www.rfc-editor.org/rfc/rfc9051]. See {RFC9051
|
|
213
|
+
# §5.5}[https://www.rfc-editor.org/rfc/rfc9051.html#section-5.5] for
|
|
214
|
+
# other examples of command sequences which should not be pipelined.
|
|
215
|
+
#
|
|
216
|
+
# == Unbounded memory use
|
|
217
|
+
#
|
|
218
|
+
# Net::IMAP reads server responses in a separate receiver thread per client.
|
|
219
|
+
# Unhandled response data is saved to #responses, and response_handlers run
|
|
220
|
+
# inside the receiver thread. See the list of methods for {handling server
|
|
221
|
+
# responses}[rdoc-ref:Net::IMAP@Handling+server+responses], below.
|
|
222
|
+
#
|
|
223
|
+
# Because the receiver thread continuously reads and saves new responses, some
|
|
224
|
+
# scenarios must be careful to avoid unbounded memory use:
|
|
225
|
+
#
|
|
226
|
+
# * Commands such as #list or #fetch can have an enormous number of responses.
|
|
227
|
+
# * Commands such as #fetch can result in an enormous size per response.
|
|
228
|
+
# * Long-lived connections will gradually accumulate unsolicited server
|
|
229
|
+
# responses, especially +EXISTS+, +FETCH+, and +EXPUNGE+ responses.
|
|
230
|
+
# * A buggy or untrusted server could send inappropriate responses, which
|
|
231
|
+
# could be very numerous, very large, and very rapid.
|
|
232
|
+
#
|
|
233
|
+
# Use paginated or limited versions of commands whenever possible.
|
|
234
|
+
#
|
|
235
|
+
# Use Config#max_response_size to impose a limit on incoming server responses
|
|
236
|
+
# as they are being read. <em>This is especially important for untrusted
|
|
237
|
+
# servers.</em>
|
|
238
|
+
#
|
|
239
|
+
# Use #add_response_handler to handle responses after each one is received.
|
|
240
|
+
# Use the +response_handlers+ argument to ::new to assign response handlers
|
|
241
|
+
# before the receiver thread is started. Use #extract_responses,
|
|
242
|
+
# #clear_responses, or #responses (with a block) to prune responses.
|
|
243
|
+
#
|
|
202
244
|
# == Errors
|
|
203
245
|
#
|
|
204
246
|
# An \IMAP server can send three different types of responses to indicate
|
|
@@ -260,8 +302,9 @@ module Net
|
|
|
260
302
|
#
|
|
261
303
|
# - Net::IMAP.new: Creates a new \IMAP client which connects immediately and
|
|
262
304
|
# waits for a successful server greeting before the method returns.
|
|
305
|
+
# - #connection_state: Returns the connection state.
|
|
263
306
|
# - #starttls: Asks the server to upgrade a clear-text connection to use TLS.
|
|
264
|
-
# - #logout: Tells the server to end the session.
|
|
307
|
+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
|
265
308
|
# - #disconnect: Disconnects the connection (without sending #logout first).
|
|
266
309
|
# - #disconnected?: True if the connection has been closed.
|
|
267
310
|
#
|
|
@@ -317,37 +360,36 @@ module Net
|
|
|
317
360
|
# <em>In general, #capable? should be used rather than explicitly sending a
|
|
318
361
|
# +CAPABILITY+ command to the server.</em>
|
|
319
362
|
# - #noop: Allows the server to send unsolicited untagged #responses.
|
|
320
|
-
# - #logout: Tells the server to end the session. Enters the
|
|
363
|
+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
|
321
364
|
#
|
|
322
365
|
# ==== Not Authenticated state
|
|
323
366
|
#
|
|
324
367
|
# In addition to the commands for any state, the following commands are valid
|
|
325
|
-
# in the
|
|
368
|
+
# in the +not_authenticated+ state:
|
|
326
369
|
#
|
|
327
370
|
# - #starttls: Upgrades a clear-text connection to use TLS.
|
|
328
371
|
#
|
|
329
372
|
# <em>Requires the +STARTTLS+ capability.</em>
|
|
330
373
|
# - #authenticate: Identifies the client to the server using the given
|
|
331
374
|
# {SASL mechanism}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
|
|
332
|
-
# and credentials. Enters the
|
|
375
|
+
# and credentials. Enters the +authenticated+ state.
|
|
333
376
|
#
|
|
334
377
|
# <em>The server should list <tt>"AUTH=#{mechanism}"</tt> capabilities for
|
|
335
378
|
# supported mechanisms.</em>
|
|
336
379
|
# - #login: Identifies the client to the server using a plain text password.
|
|
337
|
-
# Using #authenticate is
|
|
338
|
-
# state.
|
|
380
|
+
# Using #authenticate is preferred. Enters the +authenticated+ state.
|
|
339
381
|
#
|
|
340
382
|
# <em>The +LOGINDISABLED+ capability</em> <b>must NOT</b> <em>be listed.</em>
|
|
341
383
|
#
|
|
342
384
|
# ==== Authenticated state
|
|
343
385
|
#
|
|
344
386
|
# In addition to the commands for any state, the following commands are valid
|
|
345
|
-
# in the
|
|
387
|
+
# in the +authenticated+ state:
|
|
346
388
|
#
|
|
347
389
|
# - #enable: Enables backwards incompatible server extensions.
|
|
348
390
|
# <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
|
|
391
|
+
# - #select: Open a mailbox and enter the +selected+ state.
|
|
392
|
+
# - #examine: Open a mailbox read-only, and enter the +selected+ state.
|
|
351
393
|
# - #create: Creates a new mailbox.
|
|
352
394
|
# - #delete: Permanently remove a mailbox.
|
|
353
395
|
# - #rename: Change the name of a mailbox.
|
|
@@ -369,12 +411,12 @@ module Net
|
|
|
369
411
|
#
|
|
370
412
|
# ==== Selected state
|
|
371
413
|
#
|
|
372
|
-
# In addition to the commands for any state and the
|
|
373
|
-
# commands, the following commands are valid in the
|
|
414
|
+
# In addition to the commands for any state and the +authenticated+
|
|
415
|
+
# commands, the following commands are valid in the +selected+ state:
|
|
374
416
|
#
|
|
375
|
-
# - #close: Closes the mailbox and returns to the
|
|
417
|
+
# - #close: Closes the mailbox and returns to the +authenticated+ state,
|
|
376
418
|
# expunging deleted messages, unless the mailbox was opened as read-only.
|
|
377
|
-
# - #unselect: Closes the mailbox and returns to the
|
|
419
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
|
378
420
|
# without expunging any messages.
|
|
379
421
|
# <em>Requires the +UNSELECT+ or +IMAP4rev2+ capability.</em>
|
|
380
422
|
# - #expunge: Permanently removes messages which have the Deleted flag set.
|
|
@@ -395,7 +437,7 @@ module Net
|
|
|
395
437
|
#
|
|
396
438
|
# ==== Logout state
|
|
397
439
|
#
|
|
398
|
-
# No \IMAP commands are valid in the
|
|
440
|
+
# No \IMAP commands are valid in the +logout+ state. If the socket is still
|
|
399
441
|
# open, Net::IMAP will close it after receiving server confirmation.
|
|
400
442
|
# Exceptions will be raised by \IMAP commands that have already started and
|
|
401
443
|
# are waiting for a response, as well as any that are called after logout.
|
|
@@ -418,6 +460,9 @@ module Net
|
|
|
418
460
|
# +LITERAL-+, and +SPECIAL-USE+.</em>
|
|
419
461
|
#
|
|
420
462
|
# ==== RFC2087: +QUOTA+
|
|
463
|
+
# +NOTE:+ Only the +STORAGE+ quota resource type is currently supported.
|
|
464
|
+
# - Obsoleted by <tt>QUOTA=RES-*</tt> [RFC9208[https://www.rfc-editor.org/rfc/rfc9208]],
|
|
465
|
+
# although the commands are backward compatible.
|
|
421
466
|
# - #getquota: returns the resource usage and limits for a quota root
|
|
422
467
|
# - #getquotaroot: returns the list of quota roots for a mailbox, as well as
|
|
423
468
|
# their resource usage and limits.
|
|
@@ -449,7 +494,7 @@ module Net
|
|
|
449
494
|
# ==== RFC3691: +UNSELECT+
|
|
450
495
|
# Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
|
|
451
496
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
|
452
|
-
# - #unselect: Closes the mailbox and returns to the
|
|
497
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
|
453
498
|
# without expunging any messages.
|
|
454
499
|
#
|
|
455
500
|
# ==== RFC4314: +ACL+
|
|
@@ -530,6 +575,16 @@ module Net
|
|
|
530
575
|
# See FetchData#emailid and FetchData#emailid.
|
|
531
576
|
# - Updates #status with support for the +MAILBOXID+ status attribute.
|
|
532
577
|
#
|
|
578
|
+
# ==== RFC9208: <tt>QUOTA=RES-*</tt>
|
|
579
|
+
# +NOTE:+ Only the +STORAGE+ quota resource type is currently supported.
|
|
580
|
+
# - Obsoletes the +QUOTA+ [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]]
|
|
581
|
+
# extension and provides strict semantics for different resource types.
|
|
582
|
+
# - #getquota: returns the resource usage and limits for a quota root
|
|
583
|
+
# - #getquotaroot: returns the list of quota roots for a mailbox, as well as
|
|
584
|
+
# their resource usage and limits.
|
|
585
|
+
# - #setquota: sets the resource limits for a given quota root.
|
|
586
|
+
# - Updates #status with <tt>"DELETED"</tt> and +DELETED-STORAGE+ attributes.
|
|
587
|
+
#
|
|
533
588
|
# == References
|
|
534
589
|
#
|
|
535
590
|
# [{IMAP4rev1}[https://www.rfc-editor.org/rfc/rfc3501.html]]::
|
|
@@ -639,14 +694,13 @@ module Net
|
|
|
639
694
|
#
|
|
640
695
|
# === \IMAP Extensions
|
|
641
696
|
#
|
|
642
|
-
# [QUOTA[https://
|
|
643
|
-
#
|
|
644
|
-
#
|
|
697
|
+
# [QUOTA[https://www.rfc-editor.org/rfc/rfc2087]]::
|
|
698
|
+
# Myers, J., "IMAP4 QUOTA extension", RFC 2087, DOI 10.17487/RFC2087,
|
|
699
|
+
# January 1997, <https://www.rfc-editor.org/info/rfc2087>.
|
|
645
700
|
#
|
|
646
|
-
#
|
|
647
|
-
#
|
|
648
|
-
#
|
|
649
|
-
# [IDLE[https://tools.ietf.org/html/rfc2177]]::
|
|
701
|
+
# *NOTE*: _obsoleted_ by RFC9208[https://www.rfc-editor.org/rfc/rfc9208]
|
|
702
|
+
# (March 2022).
|
|
703
|
+
# [IDLE[https://www.rfc-editor.org/rfc/rfc2177]]::
|
|
650
704
|
# Leiba, B., "IMAP4 IDLE command", RFC 2177, DOI 10.17487/RFC2177,
|
|
651
705
|
# June 1997, <https://www.rfc-editor.org/info/rfc2177>.
|
|
652
706
|
# [NAMESPACE[https://tools.ietf.org/html/rfc2342]]::
|
|
@@ -697,9 +751,15 @@ module Net
|
|
|
697
751
|
# Gondwana, B., Ed., "IMAP Extension for Object Identifiers",
|
|
698
752
|
# RFC 8474, DOI 10.17487/RFC8474, September 2018,
|
|
699
753
|
# <https://www.rfc-editor.org/info/rfc8474>.
|
|
754
|
+
# [{QUOTA=RES-*}[https://www.rfc-editor.org/rfc/rfc9208]]::
|
|
755
|
+
# Melnikov, A., "IMAP QUOTA Extension", RFC 9208, DOI 10.17487/RFC9208,
|
|
756
|
+
# March 2022, <https://www.rfc-editor.org/info/rfc9208>.
|
|
757
|
+
#
|
|
758
|
+
# Obsoletes RFC2087[https://www.rfc-editor.org/rfc/rfc2087].
|
|
700
759
|
#
|
|
701
760
|
# === IANA registries
|
|
702
761
|
# * {IMAP Capabilities}[http://www.iana.org/assignments/imap4-capabilities]
|
|
762
|
+
# * {IMAP Quota Resource Types}[http://www.iana.org/assignments/imap4-capabilities#imap-capabilities-2]
|
|
703
763
|
# * {IMAP Response Codes}[https://www.iana.org/assignments/imap-response-codes/imap-response-codes.xhtml]
|
|
704
764
|
# * {IMAP Mailbox Name Attributes}[https://www.iana.org/assignments/imap-mailbox-name-attributes/imap-mailbox-name-attributes.xhtml]
|
|
705
765
|
# * {IMAP and JMAP Keywords}[https://www.iana.org/assignments/imap-jmap-keywords/imap-jmap-keywords.xhtml]
|
|
@@ -719,7 +779,7 @@ module Net
|
|
|
719
779
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
|
720
780
|
#
|
|
721
781
|
class IMAP < Protocol
|
|
722
|
-
VERSION = "0.4.
|
|
782
|
+
VERSION = "0.4.24"
|
|
723
783
|
|
|
724
784
|
# Aliases for supported capabilities, to be used with the #enable command.
|
|
725
785
|
ENABLE_ALIASES = {
|
|
@@ -727,6 +787,7 @@ module Net
|
|
|
727
787
|
"UTF8=ONLY" => "UTF8=ACCEPT",
|
|
728
788
|
}.freeze
|
|
729
789
|
|
|
790
|
+
autoload :ResponseReader, File.expand_path("imap/response_reader", __dir__)
|
|
730
791
|
autoload :SASL, File.expand_path("imap/sasl", __dir__)
|
|
731
792
|
autoload :SASLAdapter, File.expand_path("imap/sasl_adapter", __dir__)
|
|
732
793
|
autoload :StringPrep, File.expand_path("imap/stringprep", __dir__)
|
|
@@ -741,9 +802,11 @@ module Net
|
|
|
741
802
|
def self.config; Config.global end
|
|
742
803
|
|
|
743
804
|
# Returns the global debug mode.
|
|
805
|
+
# Delegates to {Net::IMAP.config.debug}[rdoc-ref:Config#debug].
|
|
744
806
|
def self.debug; config.debug end
|
|
745
807
|
|
|
746
808
|
# Sets the global debug mode.
|
|
809
|
+
# Delegates to {Net::IMAP.config.debug=}[rdoc-ref:Config#debug=].
|
|
747
810
|
def self.debug=(val)
|
|
748
811
|
config.debug = val
|
|
749
812
|
end
|
|
@@ -764,7 +827,7 @@ module Net
|
|
|
764
827
|
alias default_ssl_port default_tls_port
|
|
765
828
|
end
|
|
766
829
|
|
|
767
|
-
# Returns the initial greeting the server, an UntaggedResponse.
|
|
830
|
+
# Returns the initial greeting sent by the server, an UntaggedResponse.
|
|
768
831
|
attr_reader :greeting
|
|
769
832
|
|
|
770
833
|
# The client configuration. See Net::IMAP::Config.
|
|
@@ -773,13 +836,28 @@ module Net
|
|
|
773
836
|
# Net::IMAP.config.
|
|
774
837
|
attr_reader :config
|
|
775
838
|
|
|
776
|
-
|
|
777
|
-
#
|
|
778
|
-
#
|
|
779
|
-
|
|
839
|
+
##
|
|
840
|
+
# :attr_reader: open_timeout
|
|
841
|
+
# Seconds to wait until a connection is opened. Also used by #starttls.
|
|
842
|
+
# Delegates to {config.open_timeout}[rdoc-ref:Config#open_timeout].
|
|
780
843
|
|
|
844
|
+
##
|
|
845
|
+
# :attr_reader: idle_response_timeout
|
|
781
846
|
# Seconds to wait until an IDLE response is received.
|
|
782
|
-
|
|
847
|
+
# Delegates to {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout].
|
|
848
|
+
|
|
849
|
+
##
|
|
850
|
+
# :attr_accessor: max_response_size
|
|
851
|
+
#
|
|
852
|
+
# The maximum allowed server response size, in bytes.
|
|
853
|
+
# Delegates to {config.max_response_size}[rdoc-ref:Config#max_response_size].
|
|
854
|
+
|
|
855
|
+
# :stopdoc:
|
|
856
|
+
def open_timeout; config.open_timeout end
|
|
857
|
+
def idle_response_timeout; config.idle_response_timeout end
|
|
858
|
+
def max_response_size; config.max_response_size end
|
|
859
|
+
def max_response_size=(val) config.max_response_size = val end
|
|
860
|
+
# :startdoc:
|
|
783
861
|
|
|
784
862
|
# The hostname this client connected to
|
|
785
863
|
attr_reader :host
|
|
@@ -835,6 +913,12 @@ module Net
|
|
|
835
913
|
#
|
|
836
914
|
# See DeprecatedClientOptions.new for deprecated SSL arguments.
|
|
837
915
|
#
|
|
916
|
+
# [response_handlers]
|
|
917
|
+
# A list of response handlers to be added before the receiver thread is
|
|
918
|
+
# started. This ensures every server response is handled, including the
|
|
919
|
+
# #greeting. Note that the greeting is handled in the current thread, but
|
|
920
|
+
# all other responses are handled in the receiver thread.
|
|
921
|
+
#
|
|
838
922
|
# [config]
|
|
839
923
|
# A Net::IMAP::Config object to use as the basis for #config. By default,
|
|
840
924
|
# the global Net::IMAP.config is used.
|
|
@@ -906,7 +990,7 @@ module Net
|
|
|
906
990
|
# [Net::IMAP::ByeResponseError]
|
|
907
991
|
# Connected to the host successfully, but it immediately said goodbye.
|
|
908
992
|
#
|
|
909
|
-
def initialize(host, port: nil, ssl:
|
|
993
|
+
def initialize(host, port: nil, ssl: nil, response_handlers: nil,
|
|
910
994
|
config: Config.global, **config_options)
|
|
911
995
|
super()
|
|
912
996
|
# Config options
|
|
@@ -929,6 +1013,7 @@ module Net
|
|
|
929
1013
|
@receiver_thread = nil
|
|
930
1014
|
@receiver_thread_exception = nil
|
|
931
1015
|
@receiver_thread_terminating = false
|
|
1016
|
+
response_handlers&.each do add_response_handler(_1) end
|
|
932
1017
|
|
|
933
1018
|
# Client Protocol Sender (including state for currently running commands)
|
|
934
1019
|
@tag_prefix = "RUBY"
|
|
@@ -944,6 +1029,7 @@ module Net
|
|
|
944
1029
|
# Connection
|
|
945
1030
|
@tls_verified = false
|
|
946
1031
|
@sock = tcp_socket(@host, @port)
|
|
1032
|
+
@reader = ResponseReader.new(self, @sock)
|
|
947
1033
|
start_tls_session if ssl_ctx
|
|
948
1034
|
start_imap_connection
|
|
949
1035
|
|
|
@@ -1204,6 +1290,10 @@ module Net
|
|
|
1204
1290
|
# both successful. Any error indicates that the connection has not been
|
|
1205
1291
|
# secured.
|
|
1206
1292
|
#
|
|
1293
|
+
# After the server agrees to start a TLS connection, this method waits up to
|
|
1294
|
+
# {config.open_timeout}[rdoc-ref:Config#open_timeout] before raising
|
|
1295
|
+
# +Net::OpenTimeout+.
|
|
1296
|
+
#
|
|
1207
1297
|
# *Note:*
|
|
1208
1298
|
# >>>
|
|
1209
1299
|
# Any #response_handlers added before STARTTLS should be aware that the
|
|
@@ -1222,9 +1312,11 @@ module Net
|
|
|
1222
1312
|
#
|
|
1223
1313
|
def starttls(**options)
|
|
1224
1314
|
@ssl_ctx_params, @ssl_ctx = build_ssl_ctx(options)
|
|
1315
|
+
handled = false
|
|
1225
1316
|
error = nil
|
|
1226
1317
|
ok = send_command("STARTTLS") do |resp|
|
|
1227
1318
|
if resp.kind_of?(TaggedResponse) && resp.name == "OK"
|
|
1319
|
+
handled = true
|
|
1228
1320
|
clear_cached_capabilities
|
|
1229
1321
|
clear_responses
|
|
1230
1322
|
start_tls_session
|
|
@@ -1236,6 +1328,13 @@ module Net
|
|
|
1236
1328
|
disconnect
|
|
1237
1329
|
raise error
|
|
1238
1330
|
end
|
|
1331
|
+
unless handled
|
|
1332
|
+
disconnect
|
|
1333
|
+
raise InvalidResponseError,
|
|
1334
|
+
"STARTTLS handler was bypassed, although server responded %p" % [
|
|
1335
|
+
ok.raw_data.chomp
|
|
1336
|
+
]
|
|
1337
|
+
end
|
|
1239
1338
|
ok
|
|
1240
1339
|
end
|
|
1241
1340
|
|
|
@@ -1670,12 +1769,18 @@ module Net
|
|
|
1670
1769
|
# to both admin and user. If this mailbox exists, it returns an array
|
|
1671
1770
|
# containing objects of type MailboxQuotaRoot and MailboxQuota.
|
|
1672
1771
|
#
|
|
1772
|
+
# *NOTE:* Currently, Net::IMAP only supports +QUOTA+ responses with a single
|
|
1773
|
+
# resource type. This is usually +STORAGE+, but you may need to verify this
|
|
1774
|
+
# with UntaggedResponse#raw_data.
|
|
1775
|
+
#
|
|
1673
1776
|
# Related: #getquota, #setquota, MailboxQuotaRoot, MailboxQuota
|
|
1674
1777
|
#
|
|
1675
1778
|
# ===== Capabilities
|
|
1676
1779
|
#
|
|
1677
|
-
#
|
|
1678
|
-
#
|
|
1780
|
+
# Requires +QUOTA+ [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]]
|
|
1781
|
+
# capability, or a capability prefixed with <tt>QUOTA=RES-*</tt>
|
|
1782
|
+
# {[RFC9208]}[https://www.rfc-editor.org/rfc/rfc9208] for each supported
|
|
1783
|
+
# resource type.
|
|
1679
1784
|
def getquotaroot(mailbox)
|
|
1680
1785
|
synchronize do
|
|
1681
1786
|
send_command("GETQUOTAROOT", mailbox)
|
|
@@ -1687,41 +1792,59 @@ module Net
|
|
|
1687
1792
|
end
|
|
1688
1793
|
|
|
1689
1794
|
# Sends a {GETQUOTA command [RFC2087 §4.2]}[https://www.rfc-editor.org/rfc/rfc2087#section-4.2]
|
|
1690
|
-
#
|
|
1691
|
-
# containing a MailboxQuota object is returned.
|
|
1692
|
-
#
|
|
1795
|
+
# for the +quota_root+. If this quota root exists, then an array
|
|
1796
|
+
# containing a MailboxQuota object is returned.
|
|
1797
|
+
#
|
|
1798
|
+
# The names of quota roots that are applicable to a particular mailbox can
|
|
1799
|
+
# be discovered with #getquotaroot.
|
|
1800
|
+
#
|
|
1801
|
+
# *NOTE:* Currently, Net::IMAP only supports +QUOTA+ responses with a single
|
|
1802
|
+
# resource type. This is usually +STORAGE+, but you may need to verify this
|
|
1803
|
+
# with UntaggedResponse#raw_data.
|
|
1693
1804
|
#
|
|
1694
1805
|
# Related: #getquotaroot, #setquota, MailboxQuota
|
|
1695
1806
|
#
|
|
1696
1807
|
# ===== Capabilities
|
|
1697
1808
|
#
|
|
1698
|
-
#
|
|
1699
|
-
#
|
|
1700
|
-
|
|
1809
|
+
# Requires +QUOTA+ [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]]
|
|
1810
|
+
# capability, or a capability prefixed with <tt>QUOTA=RES-*</tt>
|
|
1811
|
+
# {[RFC9208]}[https://www.rfc-editor.org/rfc/rfc9208] for each supported
|
|
1812
|
+
# resource type.
|
|
1813
|
+
def getquota(quota_root)
|
|
1701
1814
|
synchronize do
|
|
1702
|
-
send_command("GETQUOTA",
|
|
1815
|
+
send_command("GETQUOTA", quota_root)
|
|
1703
1816
|
clear_responses("QUOTA")
|
|
1704
1817
|
end
|
|
1705
1818
|
end
|
|
1706
1819
|
|
|
1707
1820
|
# Sends a {SETQUOTA command [RFC2087 §4.1]}[https://www.rfc-editor.org/rfc/rfc2087#section-4.1]
|
|
1708
|
-
# along with the specified +
|
|
1709
|
-
# +
|
|
1710
|
-
#
|
|
1821
|
+
# along with the specified +quota_root+ and +storage_limit+. If
|
|
1822
|
+
# +storage_limit+ is +nil+, resource limits are unset for that quota root.
|
|
1823
|
+
# If +storage_limit+ is a number, it sets the +STORAGE+ resource limit.
|
|
1824
|
+
#
|
|
1825
|
+
# imap.setquota "#user/alice", 100
|
|
1826
|
+
# imap.getquota "#user/alice"
|
|
1827
|
+
# # => [#<struct Net::IMAP::MailboxQuota mailbox="#user/alice" usage=54 quota=100>]
|
|
1828
|
+
#
|
|
1829
|
+
# Typically one needs to be logged in as a server admin for this to work.
|
|
1830
|
+
#
|
|
1831
|
+
# *NOTE:* Currently, Net::IMAP only supports setting +STORAGE+ quota limits.
|
|
1711
1832
|
#
|
|
1712
1833
|
# Related: #getquota, #getquotaroot
|
|
1713
1834
|
#
|
|
1714
1835
|
# ===== Capabilities
|
|
1715
1836
|
#
|
|
1716
|
-
#
|
|
1717
|
-
#
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1837
|
+
# Requires +QUOTA+ [RFC2087[https://www.rfc-editor.org/rfc/rfc2087]]
|
|
1838
|
+
# capability, or both +QUOTASET+ and a capability prefixed with
|
|
1839
|
+
# <tt>QUOTA=RES-*</tt> {[RFC9208]}[https://www.rfc-editor.org/rfc/rfc9208]
|
|
1840
|
+
# for each supported resource type.
|
|
1841
|
+
def setquota(quota_root, storage_limit)
|
|
1842
|
+
if storage_limit.nil?
|
|
1843
|
+
list = []
|
|
1721
1844
|
else
|
|
1722
|
-
|
|
1845
|
+
list = ["STORAGE", Integer(storage_limit)]
|
|
1723
1846
|
end
|
|
1724
|
-
send_command("SETQUOTA",
|
|
1847
|
+
send_command("SETQUOTA", quota_root, list)
|
|
1725
1848
|
end
|
|
1726
1849
|
|
|
1727
1850
|
# Sends a {SETACL command [RFC4314 §3.1]}[https://www.rfc-editor.org/rfc/rfc4314#section-3.1]
|
|
@@ -1828,7 +1951,10 @@ module Net
|
|
|
1828
1951
|
# <tt>STATUS=SIZE</tt>
|
|
1829
1952
|
# {[RFC8483]}[https://www.rfc-editor.org/rfc/rfc8483.html].
|
|
1830
1953
|
#
|
|
1831
|
-
# +DELETED+
|
|
1954
|
+
# +DELETED+ must be supported when the server's capabilities includes
|
|
1955
|
+
# +IMAP4rev2+.
|
|
1956
|
+
# or <tt>QUOTA=RES-MESSAGES</tt>
|
|
1957
|
+
# {[RFC9208]}[https://www.rfc-editor.org/rfc/rfc9208.html].
|
|
1832
1958
|
#
|
|
1833
1959
|
# +HIGHESTMODSEQ+ requires the server's capabilities to include +CONDSTORE+
|
|
1834
1960
|
# {[RFC7162]}[https://www.rfc-editor.org/rfc/rfc7162.html].
|
|
@@ -1977,6 +2103,14 @@ module Net
|
|
|
1977
2103
|
#
|
|
1978
2104
|
# ===== Search criteria
|
|
1979
2105
|
#
|
|
2106
|
+
# >>>
|
|
2107
|
+
# When +criteria+ is an Array, elements in the array will be validated and
|
|
2108
|
+
# formatted. When +criteria+ is a String, it will be sent <em>with
|
|
2109
|
+
# minimal validation and no encoding or formatting</em>.
|
|
2110
|
+
#
|
|
2111
|
+
# <em>*WARNING:* Although CRLF is prohibited, this is vulnerable to other
|
|
2112
|
+
# types of attribute injection attack if unvetted user input is used.</em>
|
|
2113
|
+
#
|
|
1980
2114
|
# For a full list of search criteria,
|
|
1981
2115
|
# see [{IMAP4rev1 §6.4.4}[https://www.rfc-editor.org/rfc/rfc3501.html#section-6.4.4]],
|
|
1982
2116
|
# or [{IMAP4rev2 §6.4.4}[https://www.rfc-editor.org/rfc/rfc9051.html#section-6.4.4]],
|
|
@@ -2064,6 +2198,13 @@ module Net
|
|
|
2064
2198
|
#
|
|
2065
2199
|
# +attr+ is a list of attributes to fetch; see the documentation
|
|
2066
2200
|
# for FetchData for a list of valid attributes.
|
|
2201
|
+
# >>>
|
|
2202
|
+
# When +attr+ is a String, it will be sent <em>with minimal validation and
|
|
2203
|
+
# no encoding or formatting</em>. When +attr+ is an Array, each String in
|
|
2204
|
+
# +attr+ will be sent this way.
|
|
2205
|
+
#
|
|
2206
|
+
# <em>*WARNING:* Although CRLF is prohibited, this is vulnerable to other
|
|
2207
|
+
# types of attribute injection attack if unvetted user input is used.</em>
|
|
2067
2208
|
#
|
|
2068
2209
|
# +changedsince+ is an optional integer mod-sequence. It limits results to
|
|
2069
2210
|
# messages with a mod-sequence greater than +changedsince+.
|
|
@@ -2619,7 +2760,7 @@ module Net
|
|
|
2619
2760
|
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1)
|
|
2620
2761
|
when :frozen_dup
|
|
2621
2762
|
synchronize {
|
|
2622
|
-
responses = @responses.transform_values
|
|
2763
|
+
responses = @responses.transform_values { _1.dup.freeze }
|
|
2623
2764
|
responses.default_proc = nil
|
|
2624
2765
|
responses.default = [].freeze
|
|
2625
2766
|
return responses.freeze
|
|
@@ -2706,6 +2847,10 @@ module Net
|
|
|
2706
2847
|
# end
|
|
2707
2848
|
# }
|
|
2708
2849
|
#
|
|
2850
|
+
# Response handlers can also be added when the client is created before the
|
|
2851
|
+
# receiver thread is started, by the +response_handlers+ argument to ::new.
|
|
2852
|
+
# This ensures every server response is handled, including the #greeting.
|
|
2853
|
+
#
|
|
2709
2854
|
# Related: #remove_response_handler, #response_handlers
|
|
2710
2855
|
def add_response_handler(handler = nil, &block)
|
|
2711
2856
|
raise ArgumentError, "two Procs are passed" if handler && block
|
|
@@ -2732,6 +2877,7 @@ module Net
|
|
|
2732
2877
|
def start_imap_connection
|
|
2733
2878
|
@greeting = get_server_greeting
|
|
2734
2879
|
@capabilities = capabilities_from_resp_code @greeting
|
|
2880
|
+
@response_handlers.each do |handler| handler.call(@greeting) end
|
|
2735
2881
|
@receiver_thread = start_receiver_thread
|
|
2736
2882
|
rescue Exception
|
|
2737
2883
|
@sock.close
|
|
@@ -2860,23 +3006,10 @@ module Net
|
|
|
2860
3006
|
end
|
|
2861
3007
|
|
|
2862
3008
|
def get_response
|
|
2863
|
-
buff =
|
|
2864
|
-
while true
|
|
2865
|
-
s = @sock.gets(CRLF)
|
|
2866
|
-
break unless s
|
|
2867
|
-
buff.concat(s)
|
|
2868
|
-
if /\{(\d+)\}\r\n/n =~ s
|
|
2869
|
-
s = @sock.read($1.to_i)
|
|
2870
|
-
buff.concat(s)
|
|
2871
|
-
else
|
|
2872
|
-
break
|
|
2873
|
-
end
|
|
2874
|
-
end
|
|
3009
|
+
buff = @reader.read_response_buffer
|
|
2875
3010
|
return nil if buff.length == 0
|
|
2876
|
-
if config.debug?
|
|
2877
|
-
|
|
2878
|
-
end
|
|
2879
|
-
return @parser.parse(buff)
|
|
3011
|
+
$stderr.print(buff.gsub(/^/n, "S: ")) if config.debug?
|
|
3012
|
+
@parser.parse(buff)
|
|
2880
3013
|
end
|
|
2881
3014
|
|
|
2882
3015
|
#############################
|
|
@@ -2928,6 +3061,7 @@ module Net
|
|
|
2928
3061
|
put_string(" ")
|
|
2929
3062
|
send_data(i, tag)
|
|
2930
3063
|
end
|
|
3064
|
+
guard_against_tagged_response_skipping_handler!(tag)
|
|
2931
3065
|
put_string(CRLF)
|
|
2932
3066
|
if cmd == "LOGOUT"
|
|
2933
3067
|
@logout_command_tag = tag
|
|
@@ -2943,6 +3077,17 @@ module Net
|
|
|
2943
3077
|
end
|
|
2944
3078
|
end
|
|
2945
3079
|
end
|
|
3080
|
+
rescue InvalidResponseError
|
|
3081
|
+
disconnect
|
|
3082
|
+
raise
|
|
3083
|
+
end
|
|
3084
|
+
|
|
3085
|
+
def guard_against_tagged_response_skipping_handler!(tag)
|
|
3086
|
+
return unless (resp = @tagged_responses[tag])&.name&.upcase == "OK"
|
|
3087
|
+
raise(InvalidResponseError,
|
|
3088
|
+
"Server sent tagged 'OK' before command was finished: %p. " \
|
|
3089
|
+
"This could indicate a malicious server or client-side " \
|
|
3090
|
+
"command injection. Disconnecting." % [resp.raw_data.chomp])
|
|
2946
3091
|
end
|
|
2947
3092
|
|
|
2948
3093
|
def generate_tag
|
|
@@ -3007,7 +3152,7 @@ module Net
|
|
|
3007
3152
|
end
|
|
3008
3153
|
|
|
3009
3154
|
def store_internal(cmd, set, attr, flags, unchangedsince: nil)
|
|
3010
|
-
attr =
|
|
3155
|
+
attr = Atom.new(attr) if attr.instance_of?(String)
|
|
3011
3156
|
args = [MessageSet.new(set)]
|
|
3012
3157
|
args << ["UNCHANGEDSINCE", Integer(unchangedsince)] if unchangedsince
|
|
3013
3158
|
args << attr << flags
|
|
@@ -3077,6 +3222,7 @@ module Net
|
|
|
3077
3222
|
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
|
|
3078
3223
|
raise "cannot start TLS without SSLContext" unless ssl_ctx
|
|
3079
3224
|
@sock = SSLSocket.new(@sock, ssl_ctx)
|
|
3225
|
+
@reader = ResponseReader.new(self, @sock)
|
|
3080
3226
|
@sock.sync_close = true
|
|
3081
3227
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
|
3082
3228
|
ssl_socket_connect(@sock, open_timeout)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: net-imap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.24
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shugo Maeda
|
|
8
8
|
- nicholas a. evans
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: net-protocol
|
|
@@ -68,6 +68,7 @@ files:
|
|
|
68
68
|
- lib/net/imap/response_data.rb
|
|
69
69
|
- lib/net/imap/response_parser.rb
|
|
70
70
|
- lib/net/imap/response_parser/parser_utils.rb
|
|
71
|
+
- lib/net/imap/response_reader.rb
|
|
71
72
|
- lib/net/imap/sasl.rb
|
|
72
73
|
- lib/net/imap/sasl/anonymous_authenticator.rb
|
|
73
74
|
- lib/net/imap/sasl/authentication_exchange.rb
|
|
@@ -124,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
124
125
|
- !ruby/object:Gem::Version
|
|
125
126
|
version: '0'
|
|
126
127
|
requirements: []
|
|
127
|
-
rubygems_version:
|
|
128
|
+
rubygems_version: 4.0.6
|
|
128
129
|
specification_version: 4
|
|
129
130
|
summary: Ruby client api for Internet Message Access Protocol
|
|
130
131
|
test_files: []
|