net-imap 0.4.14 → 0.4.21
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/lib/net/imap/command_data.rb +2 -2
- data/lib/net/imap/config/attr_type_coercion.rb +25 -21
- data/lib/net/imap/config.rb +228 -43
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/response_data.rb +3 -54
- data/lib/net/imap/response_parser.rb +30 -14
- data/lib/net/imap/response_reader.rb +75 -0
- data/lib/net/imap/sequence_set.rb +274 -123
- data/lib/net/imap/uidplus_data.rb +326 -0
- data/lib/net/imap.rb +220 -59
- metadata +5 -6
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
|
#
|
@@ -288,6 +331,8 @@ module Net
|
|
288
331
|
# pre-authenticated connection.
|
289
332
|
# - #responses: Yields unhandled UntaggedResponse#data and <em>non-+nil+</em>
|
290
333
|
# ResponseCode#data.
|
334
|
+
# - #extract_responses: Removes and returns the responses for which the block
|
335
|
+
# returns a true value.
|
291
336
|
# - #clear_responses: Deletes unhandled data from #responses and returns it.
|
292
337
|
# - #add_response_handler: Add a block to be called inside the receiver thread
|
293
338
|
# with every server response.
|
@@ -315,37 +360,36 @@ module Net
|
|
315
360
|
# <em>In general, #capable? should be used rather than explicitly sending a
|
316
361
|
# +CAPABILITY+ command to the server.</em>
|
317
362
|
# - #noop: Allows the server to send unsolicited untagged #responses.
|
318
|
-
# - #logout: Tells the server to end the session. Enters the
|
363
|
+
# - #logout: Tells the server to end the session. Enters the +logout+ state.
|
319
364
|
#
|
320
365
|
# ==== Not Authenticated state
|
321
366
|
#
|
322
367
|
# In addition to the commands for any state, the following commands are valid
|
323
|
-
# in the
|
368
|
+
# in the +not_authenticated+ state:
|
324
369
|
#
|
325
370
|
# - #starttls: Upgrades a clear-text connection to use TLS.
|
326
371
|
#
|
327
372
|
# <em>Requires the +STARTTLS+ capability.</em>
|
328
373
|
# - #authenticate: Identifies the client to the server using the given
|
329
374
|
# {SASL mechanism}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
|
330
|
-
# and credentials. Enters the
|
375
|
+
# and credentials. Enters the +authenticated+ state.
|
331
376
|
#
|
332
377
|
# <em>The server should list <tt>"AUTH=#{mechanism}"</tt> capabilities for
|
333
378
|
# supported mechanisms.</em>
|
334
379
|
# - #login: Identifies the client to the server using a plain text password.
|
335
|
-
# Using #authenticate is
|
336
|
-
# state.
|
380
|
+
# Using #authenticate is preferred. Enters the +authenticated+ state.
|
337
381
|
#
|
338
382
|
# <em>The +LOGINDISABLED+ capability</em> <b>must NOT</b> <em>be listed.</em>
|
339
383
|
#
|
340
384
|
# ==== Authenticated state
|
341
385
|
#
|
342
386
|
# In addition to the commands for any state, the following commands are valid
|
343
|
-
# in the
|
387
|
+
# in the +authenticated+ state:
|
344
388
|
#
|
345
389
|
# - #enable: Enables backwards incompatible server extensions.
|
346
390
|
# <em>Requires the +ENABLE+ or +IMAP4rev2+ capability.</em>
|
347
|
-
# - #select: Open a mailbox and enter the
|
348
|
-
# - #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.
|
349
393
|
# - #create: Creates a new mailbox.
|
350
394
|
# - #delete: Permanently remove a mailbox.
|
351
395
|
# - #rename: Change the name of a mailbox.
|
@@ -367,12 +411,12 @@ module Net
|
|
367
411
|
#
|
368
412
|
# ==== Selected state
|
369
413
|
#
|
370
|
-
# In addition to the commands for any state and the
|
371
|
-
# 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:
|
372
416
|
#
|
373
|
-
# - #close: Closes the mailbox and returns to the
|
417
|
+
# - #close: Closes the mailbox and returns to the +authenticated+ state,
|
374
418
|
# expunging deleted messages, unless the mailbox was opened as read-only.
|
375
|
-
# - #unselect: Closes the mailbox and returns to the
|
419
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
376
420
|
# without expunging any messages.
|
377
421
|
# <em>Requires the +UNSELECT+ or +IMAP4rev2+ capability.</em>
|
378
422
|
# - #expunge: Permanently removes messages which have the Deleted flag set.
|
@@ -393,7 +437,7 @@ module Net
|
|
393
437
|
#
|
394
438
|
# ==== Logout state
|
395
439
|
#
|
396
|
-
# No \IMAP commands are valid in the
|
440
|
+
# No \IMAP commands are valid in the +logout+ state. If the socket is still
|
397
441
|
# open, Net::IMAP will close it after receiving server confirmation.
|
398
442
|
# Exceptions will be raised by \IMAP commands that have already started and
|
399
443
|
# are waiting for a response, as well as any that are called after logout.
|
@@ -447,7 +491,7 @@ module Net
|
|
447
491
|
# ==== RFC3691: +UNSELECT+
|
448
492
|
# Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
|
449
493
|
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
|
450
|
-
# - #unselect: Closes the mailbox and returns to the
|
494
|
+
# - #unselect: Closes the mailbox and returns to the +authenticated+ state,
|
451
495
|
# without expunging any messages.
|
452
496
|
#
|
453
497
|
# ==== RFC4314: +ACL+
|
@@ -717,7 +761,7 @@ module Net
|
|
717
761
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
718
762
|
#
|
719
763
|
class IMAP < Protocol
|
720
|
-
VERSION = "0.4.
|
764
|
+
VERSION = "0.4.21"
|
721
765
|
|
722
766
|
# Aliases for supported capabilities, to be used with the #enable command.
|
723
767
|
ENABLE_ALIASES = {
|
@@ -725,6 +769,7 @@ module Net
|
|
725
769
|
"UTF8=ONLY" => "UTF8=ACCEPT",
|
726
770
|
}.freeze
|
727
771
|
|
772
|
+
autoload :ResponseReader, File.expand_path("imap/response_reader", __dir__)
|
728
773
|
autoload :SASL, File.expand_path("imap/sasl", __dir__)
|
729
774
|
autoload :SASLAdapter, File.expand_path("imap/sasl_adapter", __dir__)
|
730
775
|
autoload :StringPrep, File.expand_path("imap/stringprep", __dir__)
|
@@ -739,9 +784,11 @@ module Net
|
|
739
784
|
def self.config; Config.global end
|
740
785
|
|
741
786
|
# Returns the global debug mode.
|
787
|
+
# Delegates to {Net::IMAP.config.debug}[rdoc-ref:Config#debug].
|
742
788
|
def self.debug; config.debug end
|
743
789
|
|
744
790
|
# Sets the global debug mode.
|
791
|
+
# Delegates to {Net::IMAP.config.debug=}[rdoc-ref:Config#debug=].
|
745
792
|
def self.debug=(val)
|
746
793
|
config.debug = val
|
747
794
|
end
|
@@ -762,7 +809,7 @@ module Net
|
|
762
809
|
alias default_ssl_port default_tls_port
|
763
810
|
end
|
764
811
|
|
765
|
-
# Returns the initial greeting the server, an UntaggedResponse.
|
812
|
+
# Returns the initial greeting sent by the server, an UntaggedResponse.
|
766
813
|
attr_reader :greeting
|
767
814
|
|
768
815
|
# The client configuration. See Net::IMAP::Config.
|
@@ -771,13 +818,28 @@ module Net
|
|
771
818
|
# Net::IMAP.config.
|
772
819
|
attr_reader :config
|
773
820
|
|
774
|
-
|
775
|
-
#
|
776
|
-
#
|
777
|
-
|
821
|
+
##
|
822
|
+
# :attr_reader: open_timeout
|
823
|
+
# Seconds to wait until a connection is opened. Also used by #starttls.
|
824
|
+
# Delegates to {config.open_timeout}[rdoc-ref:Config#open_timeout].
|
778
825
|
|
826
|
+
##
|
827
|
+
# :attr_reader: idle_response_timeout
|
779
828
|
# Seconds to wait until an IDLE response is received.
|
780
|
-
|
829
|
+
# Delegates to {config.idle_response_timeout}[rdoc-ref:Config#idle_response_timeout].
|
830
|
+
|
831
|
+
##
|
832
|
+
# :attr_accessor: max_response_size
|
833
|
+
#
|
834
|
+
# The maximum allowed server response size, in bytes.
|
835
|
+
# Delegates to {config.max_response_size}[rdoc-ref:Config#max_response_size].
|
836
|
+
|
837
|
+
# :stopdoc:
|
838
|
+
def open_timeout; config.open_timeout end
|
839
|
+
def idle_response_timeout; config.idle_response_timeout end
|
840
|
+
def max_response_size; config.max_response_size end
|
841
|
+
def max_response_size=(val) config.max_response_size = val end
|
842
|
+
# :startdoc:
|
781
843
|
|
782
844
|
# The hostname this client connected to
|
783
845
|
attr_reader :host
|
@@ -833,6 +895,12 @@ module Net
|
|
833
895
|
#
|
834
896
|
# See DeprecatedClientOptions.new for deprecated SSL arguments.
|
835
897
|
#
|
898
|
+
# [response_handlers]
|
899
|
+
# A list of response handlers to be added before the receiver thread is
|
900
|
+
# started. This ensures every server response is handled, including the
|
901
|
+
# #greeting. Note that the greeting is handled in the current thread, but
|
902
|
+
# all other responses are handled in the receiver thread.
|
903
|
+
#
|
836
904
|
# [config]
|
837
905
|
# A Net::IMAP::Config object to use as the basis for #config. By default,
|
838
906
|
# the global Net::IMAP.config is used.
|
@@ -904,7 +972,7 @@ module Net
|
|
904
972
|
# [Net::IMAP::ByeResponseError]
|
905
973
|
# Connected to the host successfully, but it immediately said goodbye.
|
906
974
|
#
|
907
|
-
def initialize(host, port: nil, ssl:
|
975
|
+
def initialize(host, port: nil, ssl: nil, response_handlers: nil,
|
908
976
|
config: Config.global, **config_options)
|
909
977
|
super()
|
910
978
|
# Config options
|
@@ -927,6 +995,7 @@ module Net
|
|
927
995
|
@receiver_thread = nil
|
928
996
|
@receiver_thread_exception = nil
|
929
997
|
@receiver_thread_terminating = false
|
998
|
+
response_handlers&.each do add_response_handler(_1) end
|
930
999
|
|
931
1000
|
# Client Protocol Sender (including state for currently running commands)
|
932
1001
|
@tag_prefix = "RUBY"
|
@@ -942,6 +1011,7 @@ module Net
|
|
942
1011
|
# Connection
|
943
1012
|
@tls_verified = false
|
944
1013
|
@sock = tcp_socket(@host, @port)
|
1014
|
+
@reader = ResponseReader.new(self, @sock)
|
945
1015
|
start_tls_session if ssl_ctx
|
946
1016
|
start_imap_connection
|
947
1017
|
|
@@ -1202,6 +1272,10 @@ module Net
|
|
1202
1272
|
# both successful. Any error indicates that the connection has not been
|
1203
1273
|
# secured.
|
1204
1274
|
#
|
1275
|
+
# After the server agrees to start a TLS connection, this method waits up to
|
1276
|
+
# {config.open_timeout}[rdoc-ref:Config#open_timeout] before raising
|
1277
|
+
# +Net::OpenTimeout+.
|
1278
|
+
#
|
1205
1279
|
# *Note:*
|
1206
1280
|
# >>>
|
1207
1281
|
# Any #response_handlers added before STARTTLS should be aware that the
|
@@ -1220,13 +1294,21 @@ module Net
|
|
1220
1294
|
#
|
1221
1295
|
def starttls(**options)
|
1222
1296
|
@ssl_ctx_params, @ssl_ctx = build_ssl_ctx(options)
|
1223
|
-
|
1297
|
+
error = nil
|
1298
|
+
ok = send_command("STARTTLS") do |resp|
|
1224
1299
|
if resp.kind_of?(TaggedResponse) && resp.name == "OK"
|
1225
1300
|
clear_cached_capabilities
|
1226
1301
|
clear_responses
|
1227
1302
|
start_tls_session
|
1228
1303
|
end
|
1304
|
+
rescue Exception => error
|
1305
|
+
raise # note that the error backtrace is in the receiver_thread
|
1229
1306
|
end
|
1307
|
+
if error
|
1308
|
+
disconnect
|
1309
|
+
raise error
|
1310
|
+
end
|
1311
|
+
ok
|
1230
1312
|
end
|
1231
1313
|
|
1232
1314
|
# :call-seq:
|
@@ -2494,41 +2576,98 @@ module Net
|
|
2494
2576
|
end
|
2495
2577
|
end
|
2496
2578
|
|
2579
|
+
RESPONSES_DEPRECATION_MSG =
|
2580
|
+
"Pass a type or block to #responses, " \
|
2581
|
+
"set config.responses_without_block to :frozen_dup " \
|
2582
|
+
"or :silence_deprecation_warning, " \
|
2583
|
+
"or use #extract_responses or #clear_responses."
|
2584
|
+
private_constant :RESPONSES_DEPRECATION_MSG
|
2585
|
+
|
2497
2586
|
# :call-seq:
|
2587
|
+
# responses -> hash of {String => Array} (see config.responses_without_block)
|
2588
|
+
# responses(type) -> frozen array
|
2498
2589
|
# responses {|hash| ...} -> block result
|
2499
2590
|
# responses(type) {|array| ...} -> block result
|
2500
2591
|
#
|
2501
|
-
# Yields
|
2592
|
+
# Yields or returns unhandled server responses. Unhandled responses are
|
2593
|
+
# stored in a hash, with arrays of UntaggedResponse#data keyed by
|
2594
|
+
# UntaggedResponse#name and <em>non-+nil+</em> untagged ResponseCode#data
|
2595
|
+
# keyed by ResponseCode#name.
|
2596
|
+
#
|
2597
|
+
# When a block is given, yields unhandled responses and returns the block's
|
2598
|
+
# result. Without a block, returns the unhandled responses.
|
2599
|
+
#
|
2600
|
+
# [With +type+]
|
2601
|
+
# Yield or return only the array of responses for that +type+.
|
2602
|
+
# When no block is given, the returned array is a frozen copy.
|
2603
|
+
# [Without +type+]
|
2604
|
+
# Yield or return the entire responses hash.
|
2605
|
+
#
|
2606
|
+
# When no block is given, the behavior is determined by
|
2607
|
+
# Config#responses_without_block:
|
2608
|
+
# >>>
|
2609
|
+
# [+:silence_deprecation_warning+ <em>(original behavior)</em>]
|
2610
|
+
# Returns the mutable responses hash (without any warnings).
|
2611
|
+
# <em>This is not thread-safe.</em>
|
2612
|
+
#
|
2613
|
+
# [+:warn+ <em>(default since +v0.5+)</em>]
|
2614
|
+
# Prints a warning and returns the mutable responses hash.
|
2615
|
+
# <em>This is not thread-safe.</em>
|
2502
2616
|
#
|
2503
|
-
#
|
2504
|
-
#
|
2505
|
-
#
|
2506
|
-
#
|
2507
|
-
#
|
2617
|
+
# [+:frozen_dup+ <em>(planned default for +v0.6+)</em>]
|
2618
|
+
# Returns a frozen copy of the unhandled responses hash, with frozen
|
2619
|
+
# array values.
|
2620
|
+
#
|
2621
|
+
# [+:raise+]
|
2622
|
+
# Raise an +ArgumentError+ with the deprecation warning.
|
2508
2623
|
#
|
2509
2624
|
# For example:
|
2510
2625
|
#
|
2511
2626
|
# imap.select("inbox")
|
2512
|
-
# p imap.responses("EXISTS"
|
2627
|
+
# p imap.responses("EXISTS").last
|
2513
2628
|
# #=> 2
|
2629
|
+
# p imap.responses("UIDNEXT", &:last)
|
2630
|
+
# #=> 123456
|
2514
2631
|
# p imap.responses("UIDVALIDITY", &:last)
|
2515
2632
|
# #=> 968263756
|
2633
|
+
# p imap.responses {|responses|
|
2634
|
+
# {
|
2635
|
+
# exists: responses.delete("EXISTS").last,
|
2636
|
+
# uidnext: responses.delete("UIDNEXT").last,
|
2637
|
+
# uidvalidity: responses.delete("UIDVALIDITY").last,
|
2638
|
+
# }
|
2639
|
+
# }
|
2640
|
+
# #=> {:exists=>2, :uidnext=>123456, :uidvalidity=>968263756}
|
2641
|
+
# # "EXISTS", "UIDNEXT", and "UIDVALIDITY" have been removed:
|
2642
|
+
# p imap.responses(&:keys)
|
2643
|
+
# #=> ["FLAGS", "OK", "PERMANENTFLAGS", "RECENT", "HIGHESTMODSEQ"]
|
2644
|
+
#
|
2645
|
+
# Related: #extract_responses, #clear_responses, #response_handlers, #greeting
|
2516
2646
|
#
|
2647
|
+
# ===== Thread safety
|
2517
2648
|
# >>>
|
2518
2649
|
# *Note:* Access to the responses hash is synchronized for thread-safety.
|
2519
2650
|
# The receiver thread and response_handlers cannot process new responses
|
2520
2651
|
# until the block completes. Accessing either the response hash or its
|
2521
|
-
# response type arrays outside of the block is unsafe.
|
2652
|
+
# response type arrays outside of the block is unsafe. They can be safely
|
2653
|
+
# updated inside the block. Consider using #clear_responses or
|
2654
|
+
# #extract_responses instead.
|
2522
2655
|
#
|
2523
|
-
#
|
2524
|
-
#
|
2525
|
-
#
|
2656
|
+
# Net::IMAP will add and remove responses from the responses hash and its
|
2657
|
+
# array values, in the calling threads for commands and in the receiver
|
2658
|
+
# thread, but will not modify any responses after adding them to the
|
2659
|
+
# responses hash.
|
2660
|
+
#
|
2661
|
+
# ===== Clearing responses
|
2526
2662
|
#
|
2527
2663
|
# Previously unhandled responses are automatically cleared before entering a
|
2528
2664
|
# mailbox with #select or #examine. Long-lived connections can receive many
|
2529
2665
|
# unhandled server responses, which must be pruned or they will continually
|
2530
2666
|
# consume more memory. Update or clear the responses hash or arrays inside
|
2531
|
-
# the block, or
|
2667
|
+
# the block, or remove responses with #extract_responses, #clear_responses,
|
2668
|
+
# or #add_response_handler.
|
2669
|
+
#
|
2670
|
+
# ===== Missing responses
|
2532
2671
|
#
|
2533
2672
|
# Only non-+nil+ data is stored. Many important response codes have no data
|
2534
2673
|
# of their own, but are used as "tags" on the ResponseText object they are
|
@@ -2539,19 +2678,24 @@ module Net
|
|
2539
2678
|
# ResponseCode#data on tagged responses. Although some command methods do
|
2540
2679
|
# return the TaggedResponse directly, #add_response_handler must be used to
|
2541
2680
|
# handle all response codes.
|
2542
|
-
#
|
2543
|
-
# Related: #clear_responses, #response_handlers, #greeting
|
2544
2681
|
def responses(type = nil)
|
2545
2682
|
if block_given?
|
2546
2683
|
synchronize { yield(type ? @responses[type.to_s.upcase] : @responses) }
|
2547
2684
|
elsif type
|
2548
|
-
|
2685
|
+
synchronize { @responses[type.to_s.upcase].dup.freeze }
|
2549
2686
|
else
|
2550
2687
|
case config.responses_without_block
|
2551
2688
|
when :raise
|
2552
|
-
raise ArgumentError,
|
2689
|
+
raise ArgumentError, RESPONSES_DEPRECATION_MSG
|
2553
2690
|
when :warn
|
2554
|
-
warn(
|
2691
|
+
warn(RESPONSES_DEPRECATION_MSG, uplevel: 1)
|
2692
|
+
when :frozen_dup
|
2693
|
+
synchronize {
|
2694
|
+
responses = @responses.transform_values(&:freeze)
|
2695
|
+
responses.default_proc = nil
|
2696
|
+
responses.default = [].freeze
|
2697
|
+
return responses.freeze
|
2698
|
+
}
|
2555
2699
|
end
|
2556
2700
|
@responses
|
2557
2701
|
end
|
@@ -2567,7 +2711,7 @@ module Net
|
|
2567
2711
|
# Clearing responses is synchronized with other threads. The lock is
|
2568
2712
|
# released before returning.
|
2569
2713
|
#
|
2570
|
-
# Related: #responses, #response_handlers
|
2714
|
+
# Related: #extract_responses, #responses, #response_handlers
|
2571
2715
|
def clear_responses(type = nil)
|
2572
2716
|
synchronize {
|
2573
2717
|
if type
|
@@ -2581,6 +2725,30 @@ module Net
|
|
2581
2725
|
.freeze
|
2582
2726
|
end
|
2583
2727
|
|
2728
|
+
# :call-seq:
|
2729
|
+
# extract_responses(type) {|response| ... } -> array
|
2730
|
+
#
|
2731
|
+
# Yields all of the unhandled #responses for a single response +type+.
|
2732
|
+
# Removes and returns the responses for which the block returns a true
|
2733
|
+
# value.
|
2734
|
+
#
|
2735
|
+
# Extracting responses is synchronized with other threads. The lock is
|
2736
|
+
# released before returning.
|
2737
|
+
#
|
2738
|
+
# Related: #responses, #clear_responses
|
2739
|
+
def extract_responses(type)
|
2740
|
+
type = String.try_convert(type) or
|
2741
|
+
raise ArgumentError, "type must be a string"
|
2742
|
+
raise ArgumentError, "must provide a block" unless block_given?
|
2743
|
+
extracted = []
|
2744
|
+
responses(type) do |all|
|
2745
|
+
all.reject! do |response|
|
2746
|
+
extracted << response if yield response
|
2747
|
+
end
|
2748
|
+
end
|
2749
|
+
extracted
|
2750
|
+
end
|
2751
|
+
|
2584
2752
|
# Returns all response handlers, including those that are added internally
|
2585
2753
|
# by commands. Each response handler will be called with every new
|
2586
2754
|
# UntaggedResponse, TaggedResponse, and ContinuationRequest.
|
@@ -2610,6 +2778,10 @@ module Net
|
|
2610
2778
|
# end
|
2611
2779
|
# }
|
2612
2780
|
#
|
2781
|
+
# Response handlers can also be added when the client is created before the
|
2782
|
+
# receiver thread is started, by the +response_handlers+ argument to ::new.
|
2783
|
+
# This ensures every server response is handled, including the #greeting.
|
2784
|
+
#
|
2613
2785
|
# Related: #remove_response_handler, #response_handlers
|
2614
2786
|
def add_response_handler(handler = nil, &block)
|
2615
2787
|
raise ArgumentError, "two Procs are passed" if handler && block
|
@@ -2636,6 +2808,7 @@ module Net
|
|
2636
2808
|
def start_imap_connection
|
2637
2809
|
@greeting = get_server_greeting
|
2638
2810
|
@capabilities = capabilities_from_resp_code @greeting
|
2811
|
+
@response_handlers.each do |handler| handler.call(@greeting) end
|
2639
2812
|
@receiver_thread = start_receiver_thread
|
2640
2813
|
rescue Exception
|
2641
2814
|
@sock.close
|
@@ -2764,23 +2937,10 @@ module Net
|
|
2764
2937
|
end
|
2765
2938
|
|
2766
2939
|
def get_response
|
2767
|
-
buff =
|
2768
|
-
while true
|
2769
|
-
s = @sock.gets(CRLF)
|
2770
|
-
break unless s
|
2771
|
-
buff.concat(s)
|
2772
|
-
if /\{(\d+)\}\r\n/n =~ s
|
2773
|
-
s = @sock.read($1.to_i)
|
2774
|
-
buff.concat(s)
|
2775
|
-
else
|
2776
|
-
break
|
2777
|
-
end
|
2778
|
-
end
|
2940
|
+
buff = @reader.read_response_buffer
|
2779
2941
|
return nil if buff.length == 0
|
2780
|
-
if config.debug?
|
2781
|
-
|
2782
|
-
end
|
2783
|
-
return @parser.parse(buff)
|
2942
|
+
$stderr.print(buff.gsub(/^/n, "S: ")) if config.debug?
|
2943
|
+
@parser.parse(buff)
|
2784
2944
|
end
|
2785
2945
|
|
2786
2946
|
#############################
|
@@ -2981,6 +3141,7 @@ module Net
|
|
2981
3141
|
raise "already using SSL" if @sock.kind_of?(OpenSSL::SSL::SSLSocket)
|
2982
3142
|
raise "cannot start TLS without SSLContext" unless ssl_ctx
|
2983
3143
|
@sock = SSLSocket.new(@sock, ssl_ctx)
|
3144
|
+
@reader = ResponseReader.new(self, @sock)
|
2984
3145
|
@sock.sync_close = true
|
2985
3146
|
@sock.hostname = @host if @sock.respond_to? :hostname=
|
2986
3147
|
ssl_socket_connect(@sock, open_timeout)
|
metadata
CHANGED
@@ -1,15 +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.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
- nicholas a. evans
|
9
|
-
autorequire:
|
10
9
|
bindir: exe
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: net-protocol
|
@@ -69,6 +68,7 @@ files:
|
|
69
68
|
- lib/net/imap/response_data.rb
|
70
69
|
- lib/net/imap/response_parser.rb
|
71
70
|
- lib/net/imap/response_parser/parser_utils.rb
|
71
|
+
- lib/net/imap/response_reader.rb
|
72
72
|
- lib/net/imap/sasl.rb
|
73
73
|
- lib/net/imap/sasl/anonymous_authenticator.rb
|
74
74
|
- lib/net/imap/sasl/authentication_exchange.rb
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- lib/net/imap/stringprep/saslprep_tables.rb
|
96
96
|
- lib/net/imap/stringprep/tables.rb
|
97
97
|
- lib/net/imap/stringprep/trace.rb
|
98
|
+
- lib/net/imap/uidplus_data.rb
|
98
99
|
- net-imap.gemspec
|
99
100
|
- rakelib/benchmarks.rake
|
100
101
|
- rakelib/rdoc.rake
|
@@ -110,7 +111,6 @@ metadata:
|
|
110
111
|
homepage_uri: https://github.com/ruby/net-imap
|
111
112
|
source_code_uri: https://github.com/ruby/net-imap
|
112
113
|
changelog_uri: https://github.com/ruby/net-imap/releases
|
113
|
-
post_install_message:
|
114
114
|
rdoc_options: []
|
115
115
|
require_paths:
|
116
116
|
- lib
|
@@ -125,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
127
|
requirements: []
|
128
|
-
rubygems_version: 3.
|
129
|
-
signing_key:
|
128
|
+
rubygems_version: 3.6.7
|
130
129
|
specification_version: 4
|
131
130
|
summary: Ruby client api for Internet Message Access Protocol
|
132
131
|
test_files: []
|