@@ -716,11 +716,104 @@ class << self
716
716
alias default_imap_port default_port
717
717
alias default_imaps_port default_tls_port
718
718
alias default_ssl_port default_tls_port
719
+
720
+ # The default value for the +ssl+ option of ::new, when +port+ is
721
+ # unspecified or non-standard.
722
+ #
723
+ # Defaults to +nil+ for backward compatibility, which prints a warning and
724
+ # does _not_ use TLS.
725
+ #
726
+ # >>>
727
+ # *Note*: A future version of Net::IMAP will default to +true+, as per
728
+ # RFC7525[https://tools.ietf.org/html/rfc7525],
729
+ # RFC7817[https://tools.ietf.org/html/rfc7817],
730
+ # and RFC8314[https://tools.ietf.org/html/rfc8314].
731
+ #
732
+ # Set to +false+ to *globally* use insecure defaults and silence warnings.
733
+ # Send <tt>ssl: false</tt> to ::new to explicitly silence warnings for a
734
+ # single connection.
735
+ attr_accessor :default_ssl
736
+ end
737
+
738
+ # Creates a new Net::IMAP object and connects it to the specified
739
+ # +host+.
740
+ #
741
+ # Accepts the following options:
742
+ #
743
+ # [port]
744
+ # Port number (default value is 143 for imap, or 993 for imaps)
745
+ # [ssl]
746
+ # When +true+, the connection will use TLS using the defaults chosen by
747
+ # {OpenSSL::SSL::SSLContext#set_params}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-set_params].
748
+ # Use a hash to override the defaults---the keys are assignment methods on
749
+ # SSLContext[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html].
750
+ # Defaults to +true+ or +false+ to match +port+, or to ::default_ssl when
751
+ # +port+ is unspecified or non-standard.
752
+ # [open_timeout]
753
+ # Seconds to wait until a connection is opened
754
+ # [idle_response_timeout]
755
+ # Seconds to wait until an IDLE response is received
756
+ #
757
+ # The most common errors are:
758
+ #
759
+ # Errno::ECONNREFUSED:: Connection refused by +host+ or an intervening
760
+ # firewall.
761
+ # Errno::ETIMEDOUT:: Connection timed out (possibly due to packets
762
+ # being dropped by an intervening firewall).
763
+ # Errno::ENETUNREACH:: There is no route to that network.
764
+ # SocketError:: Hostname not known or other socket error.
765
+ # Net::IMAP::ByeResponseError:: Connected to the host successfully, but
766
+ # it immediately said goodbye.
767
+ def initialize ( host ,
768
+ port : nil ,
769
+ ssl : nil ,
770
+ open_timeout : 30 ,
771
+ idle_response_timeout : 5 )
772
+ # Basic configuration
773
+ @host = host
774
+ @ssl , @port = default_ssl_and_port ( ssl , port )
775
+ @open_timeout = Integer ( open_timeout )
776
+ @idle_response_timeout = Integer ( idle_response_timeout )
777
+
778
+ # Basic Client state
779
+ super ( ) # Mutex and condition vars (MonitorMixin#initialize)
780
+ @greeting = nil
781
+ @capabilities = nil
782
+ @utf8_strings = false # TODO: use @enabled instead
783
+ @debug_output_bol = true
784
+
785
+ # Client Protocol Reciever
786
+ @parser = ResponseParser . new
787
+ @receiver_thread = nil
788
+ @receiver_thread_terminating = false
789
+ @exception = nil
790
+
791
+ # Client Protocol Sender
792
+ @tag_prefix = "RUBY"
793
+ @tagno = 0
794
+
795
+ # Response handlers
796
+ @continuation_request_arrival = new_cond
797
+ @continuation_request_exception = nil
798
+ @tagged_response_arrival = new_cond
799
+ @tagged_responses = { }
800
+ @response_handlers = [ ]
801
+ @responses = Hash . new { |h , k | h [ k ] = [ ] }
802
+
803
+ # Command execution state
804
+ @logout_command_tag = nil
805
+ @continued_command_tag = nil
806
+ @idle_done_cond = nil
807
+
808
+ # create the connection
809
+ @sock = nil
810
+ start_connection
719
811
end
720
812
721
813
def client_thread # :nodoc:
722
- warn "Net::IMAP#client_thread is deprecated and will be removed soon."
723
- @client_thread
814
+ warn "Net::IMAP#client_thread is deprecated and always returns the " \
815
+ "caller's current thread."
816
+ Thread . current
724
817
end
725
818
726
819
# Disconnects from the server.
@@ -966,15 +1059,9 @@ def logout
966
1059
# Server capabilities may change after #starttls, #login, and #authenticate.
967
1060
# Cached #capabilities will be cleared when this method completes.
968
1061
#
969
- def starttls ( options = { } , verify = true )
1062
+ def starttls ( options = { } )
970
1063
send_command ( "STARTTLS" ) do |resp |
971
1064
if resp . kind_of? ( TaggedResponse ) && resp . name == "OK"
972
- begin
973
- # for backward compatibility
974
- certs = options . to_str
975
- options = create_ssl_params ( certs , verify )
976
- rescue NoMethodError
977
- end
978
1065
clear_cached_capabilities
979
1066
clear_responses
980
1067
start_tls_session ( options )
@@ -2190,99 +2277,62 @@ def remove_response_handler(handler)
2190
2277
2191
2278
@@debug = false
2192
2279
2193
- # :call-seq:
2194
- # Net::IMAP.new(host, options = {})
2195
- #
2196
- # Creates a new Net::IMAP object and connects it to the specified
2197
- # +host+.
2198
- #
2199
- # +options+ is an option hash, each key of which is a symbol.
2200
- #
2201
- # The available options are:
2202
- #
2203
- # port:: Port number (default value is 143 for imap, or 993 for imaps)
2204
- # ssl:: If +options[:ssl]+ is true, then an attempt will be made
2205
- # to use SSL (now TLS) to connect to the server.
2206
- # If +options[:ssl]+ is a hash, it's passed to
2207
- # OpenSSL::SSL::SSLContext#set_params as parameters.
2208
- # open_timeout:: Seconds to wait until a connection is opened
2209
- # idle_response_timeout:: Seconds to wait until an IDLE response is received
2210
- #
2211
- # The most common errors are:
2212
- #
2213
- # Errno::ECONNREFUSED:: Connection refused by +host+ or an intervening
2214
- # firewall.
2215
- # Errno::ETIMEDOUT:: Connection timed out (possibly due to packets
2216
- # being dropped by an intervening firewall).
2217
- # Errno::ENETUNREACH:: There is no route to that network.
2218
- # SocketError:: Hostname not known or other socket error.
2219
- # Net::IMAP::ByeResponseError:: The connected to the host was successful, but
2220
- # it immediately said goodbye.
2221
- def initialize ( host , port_or_options = { } ,
2222
- usessl = false , certs = nil , verify = true )
2223
- super ( )
2224
- @host = host
2225
- begin
2226
- options = port_or_options . to_hash
2227
- rescue NoMethodError
2228
- # for backward compatibility
2229
- options = { }
2230
- options [ :port ] = port_or_options
2231
- if usessl
2232
- options [ :ssl ] = create_ssl_params ( certs , verify )
2280
+ def default_ssl_and_port ( ssl , port )
2281
+ if ssl . nil? && port
2282
+ ssl = true if port == SSL_PORT || /\A imaps\z /i === port
2283
+ ssl = false if port == PORT
2284
+ elsif port . nil? && !ssl . nil?
2285
+ port = ssl ? SSL_PORT : PORT
2286
+ end
2287
+ if ssl . nil? && port . nil?
2288
+ ssl = self . class . default_ssl . dup . freeze
2289
+ port = ssl ? SSL_PORT : PORT
2290
+ if ssl . nil?
2291
+ warn "A future version of Net::IMAP.default_ssl " \
2292
+ "will default to 'true', for secure connections by default. " \
2293
+ "Use 'Net::IMAP.new(host, ssl: false)' or set " \
2294
+ "Net::IMAP.default_ssl = false' to silence this warning."
2233
2295
end
2234
2296
end
2235
- @port = options [ :port ] || ( options [ :ssl ] ? SSL_PORT : PORT )
2236
- @tag_prefix = "RUBY"
2237
- @tagno = 0
2238
- @utf8_strings = false
2239
- @open_timeout = options [ :open_timeout ] || 30
2240
- @idle_response_timeout = options [ :idle_response_timeout ] || 5
2241
- @parser = ResponseParser . new
2297
+ ssl &&= ssl . respond_to? ( :to_hash ) ? ssl . to_hash : { }
2298
+ [ ssl , port ]
2299
+ end
2300
+
2301
+ def start_connection
2242
2302
@sock = tcp_socket ( @host , @port )
2243
2303
begin
2244
- if options [ :ssl ]
2245
- start_tls_session ( options [ :ssl ] )
2246
- @usessl = true
2247
- else
2248
- @usessl = false
2249
- end
2250
- @responses = Hash . new { |h , k | h [ k ] = [ ] }
2251
- @tagged_responses = { }
2252
- @response_handlers = [ ]
2253
- @tagged_response_arrival = new_cond
2254
- @continued_command_tag = nil
2255
- @continuation_request_arrival = new_cond
2256
- @continuation_request_exception = nil
2257
- @idle_done_cond = nil
2258
- @logout_command_tag = nil
2259
- @debug_output_bol = true
2260
- @exception = nil
2261
-
2304
+ start_tls_session ( @ssl ) if @ssl
2262
2305
@greeting = get_response
2263
- if @greeting . nil?
2264
- raise Error , "connection closed"
2265
- end
2266
- record_untagged_response_code @greeting
2267
- @capabilities = capabilities_from_resp_code @greeting
2268
- if @greeting . name == "BYE"
2269
- raise ByeResponseError , @greeting
2270
- end
2271
-
2272
- @client_thread = Thread . current
2273
- @receiver_thread = Thread . start {
2274
- begin
2275
- receive_responses
2276
- rescue Exception
2277
- end
2278
- }
2279
- @receiver_thread_terminating = false
2306
+ handle_server_greeting
2307
+ @receiver_thread = start_receiver_thread
2280
2308
rescue Exception
2281
2309
@sock . close
2282
2310
raise
2283
2311
end
2284
2312
end
2285
2313
2314
+ def handle_server_greeting
2315
+ if @greeting . nil?
2316
+ raise Error , "connection closed"
2317
+ end
2318
+ record_untagged_response_code ( @greeting )
2319
+ @capabilities = capabilities_from_resp_code @greeting
2320
+ if @greeting . name == "BYE"
2321
+ raise ByeResponseError , @greeting
2322
+ end
2323
+ end
2324
+
2325
+ def start_receiver_thread
2326
+ Thread . start do
2327
+ receive_responses
2328
+ rescue Exception
2329
+ # don't exit the thread with an exception
2330
+ end
2331
+ rescue Exception
2332
+ @sock . close
2333
+ raise
2334
+ end
2335
+
2286
2336
def tcp_socket ( host , port )
2287
2337
s = Socket . tcp ( host , port , :connect_timeout => @open_timeout )
2288
2338
s . setsockopt ( :SOL_SOCKET , :SO_KEEPALIVE , true )
@@ -2569,35 +2619,13 @@ def normalize_searching_criteria(keys)
2569
2619
end
2570
2620
end
2571
2621
2572
- def create_ssl_params ( certs = nil , verify = true )
2573
- params = { }
2574
- if certs
2575
- if File . file? ( certs )
2576
- params [ :ca_file ] = certs
2577
- elsif File . directory? ( certs )
2578
- params [ :ca_path ] = certs
2579
- end
2580
- end
2581
- if verify
2582
- params [ :verify_mode ] = VERIFY_PEER
2583
- else
2584
- params [ :verify_mode ] = VERIFY_NONE
2585
- end
2586
- return params
2587
- end
2588
-
2589
2622
def start_tls_session ( params = { } )
2590
2623
unless defined? ( OpenSSL ::SSL )
2591
2624
raise "SSL extension not installed"
2592
2625
end
2593
2626
if @sock . kind_of? ( OpenSSL ::SSL ::SSLSocket )
2594
2627
raise RuntimeError , "already using SSL"
2595
2628
end
2596
- begin
2597
- params = params . to_hash
2598
- rescue NoMethodError
2599
- params = { }
2600
- end
2601
2629
context = SSLContext . new
2602
2630
context . set_params ( params )
2603
2631
if defined? ( VerifyCallbackProc )
@@ -2632,3 +2660,6 @@ def self.saslprep(string, **opts)
2632
2660
require_relative "imap/response_data"
2633
2661
require_relative "imap/response_parser"
2634
2662
require_relative "imap/authenticators"
2663
+
2664
+ require_relative "imap/deprecated_client_options"
2665
+ Net ::IMAP . prepend Net ::IMAP ::DeprecatedClientOptions
0 commit comments