@@ -720,6 +720,107 @@ class << self
720
720
alias default_imap_port default_port
721
721
alias default_imaps_port default_tls_port
722
722
alias default_ssl_port default_tls_port
723
+
724
+ # The default value for the +tls+ option of ::new, when +port+ is
725
+ # unspecified or non-standard.
726
+ #
727
+ # *Note*: A future release of Net::IMAP will set the default to +true+, as
728
+ # per RFC7525[https://tools.ietf.org/html/rfc7525],
729
+ # RFC7817[https://tools.ietf.org/html/rfc7817], and
730
+ # RFC8314[https://tools.ietf.org/html/rfc8314].
731
+ #
732
+ # Set to +true+ for the secure default without warnings. Set to
733
+ # +false+ to globally silence warnings and use insecure defaults.
734
+ attr_accessor :default_tls
735
+ alias default_ssl default_tls
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
+ # [tls]
746
+ # When +true+, the connection will use TLS with the default params set by
747
+ # {OpenSSL::SSL::SSLContext#set_params}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-set_params].
748
+ # Assign a hash to override TLS params—the keys are assignment methods on
749
+ # SSLContext[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html].
750
+ #
751
+ # When <tt>port: 993</tt>, +tls+ defaults to +true+.
752
+ # When <tt>port: 143</tt>, +tls+ defaults to +false+.
753
+ # When port is unspecified or non-standard, +tls+ defaults to
754
+ # ::default_tls. When ::default_tls is also +nil+, a warning is printed
755
+ # and the connection does _not_ use TLS.
756
+ #
757
+ # When +nil+ or unassigned a default value is assigned: the default is
758
+ # +true+ if <tt>port: 993</tt>, +false+ if <tt>port: 143</tt>, and
759
+ # ::default_tls when +port+ is unspecified or non-standard. When
760
+ # ::default_tls is +nil+, a back
761
+ #
762
+ # [open_timeout]
763
+ # Seconds to wait until a connection is opened
764
+ # [idle_response_timeout]
765
+ # Seconds to wait until an IDLE response is received
766
+ #
767
+ # The most common errors are:
768
+ #
769
+ # Errno::ECONNREFUSED:: Connection refused by +host+ or an intervening
770
+ # firewall.
771
+ # Errno::ETIMEDOUT:: Connection timed out (possibly due to packets
772
+ # being dropped by an intervening firewall).
773
+ # Errno::ENETUNREACH:: There is no route to that network.
774
+ # SocketError:: Hostname not known or other socket error.
775
+ # Net::IMAP::ByeResponseError:: Connected to the host successfully, but
776
+ # it immediately said goodbye.
777
+ def initialize ( host ,
778
+ port : nil ,
779
+ tls : nil ,
780
+ open_timeout : 30 ,
781
+ idle_response_timeout : 5 )
782
+ # Basic configuration
783
+ @host = host
784
+ @tls , @port = default_tls_and_port ( tls , port )
785
+ @open_timeout = Integer ( open_timeout )
786
+ @idle_response_timeout = Integer ( idle_response_timeout )
787
+
788
+ # Basic Client state
789
+ super ( ) # Mutex and condition vars (MonitorMixin#initialize)
790
+ @greeting = nil
791
+ @capabilities = nil
792
+ @utf8_strings = false # TODO: use @enabled instead
793
+ @debug_output_bol = true
794
+
795
+ # Client Protocol Reciever
796
+ @parser = ResponseParser . new
797
+ @receiver_thread = nil
798
+ @receiver_thread_terminating = false
799
+ @exception = nil
800
+
801
+ # Client Protocol Sender
802
+ @tag_prefix = "RUBY"
803
+ @tagno = 0
804
+
805
+ # Response handlers
806
+ @continuation_request_arrival = new_cond
807
+ @continuation_request_exception = nil
808
+ @tagged_response_arrival = new_cond
809
+ @tagged_responses = { }
810
+ @response_handlers = [ ]
811
+ @responses = Hash . new { |h , k | h [ k ] = [ ] }
812
+
813
+ # Command execution state
814
+ @logout_command_tag = nil
815
+ @continued_command_tag = nil
816
+ @idle_done_cond = nil
817
+
818
+ # DEPRECATED
819
+ @client_thread = Thread . current
820
+
821
+ # create the connection
822
+ @sock = nil
823
+ start_connection
723
824
end
724
825
725
826
def client_thread # :nodoc:
@@ -795,7 +896,7 @@ def capabilities
795
896
# servers will drop all <tt>AUTH=</tt> mechanisms from #capabilities after
796
897
# the connection has authenticated.
797
898
#
798
- # imap = Net::IMAP.new(hostname, ssl : false)
899
+ # imap = Net::IMAP.new(hostname, tls : false)
799
900
# imap.capabilities # => ["IMAP4REV1", "LOGINDISABLED"]
800
901
# imap.auth_mechanisms # => []
801
902
#
@@ -970,15 +1071,9 @@ def logout
970
1071
# Server capabilities may change after #starttls, #login, and #authenticate.
971
1072
# Cached #capabilities will be cleared when this method completes.
972
1073
#
973
- def starttls ( options = { } , verify = true )
1074
+ def starttls ( ** options )
974
1075
send_command ( "STARTTLS" ) do |resp |
975
1076
if resp . kind_of? ( TaggedResponse ) && resp . name == "OK"
976
- begin
977
- # for backward compatibility
978
- certs = options . to_str
979
- options = create_ssl_params ( certs , verify )
980
- rescue NoMethodError
981
- end
982
1077
clear_cached_capabilities
983
1078
clear_responses
984
1079
start_tls_session ( options )
@@ -2213,99 +2308,62 @@ def remove_response_handler(handler)
2213
2308
2214
2309
@@debug = false
2215
2310
2216
- # :call-seq:
2217
- # Net::IMAP.new(host, options = {})
2218
- #
2219
- # Creates a new Net::IMAP object and connects it to the specified
2220
- # +host+.
2221
- #
2222
- # +options+ is an option hash, each key of which is a symbol.
2223
- #
2224
- # The available options are:
2225
- #
2226
- # port:: Port number (default value is 143 for imap, or 993 for imaps)
2227
- # ssl:: If +options[:ssl]+ is true, then an attempt will be made
2228
- # to use SSL (now TLS) to connect to the server.
2229
- # If +options[:ssl]+ is a hash, it's passed to
2230
- # OpenSSL::SSL::SSLContext#set_params as parameters.
2231
- # open_timeout:: Seconds to wait until a connection is opened
2232
- # idle_response_timeout:: Seconds to wait until an IDLE response is received
2233
- #
2234
- # The most common errors are:
2235
- #
2236
- # Errno::ECONNREFUSED:: Connection refused by +host+ or an intervening
2237
- # firewall.
2238
- # Errno::ETIMEDOUT:: Connection timed out (possibly due to packets
2239
- # being dropped by an intervening firewall).
2240
- # Errno::ENETUNREACH:: There is no route to that network.
2241
- # SocketError:: Hostname not known or other socket error.
2242
- # Net::IMAP::ByeResponseError:: The connected to the host was successful, but
2243
- # it immediately said goodbye.
2244
- def initialize ( host , port_or_options = { } ,
2245
- usessl = false , certs = nil , verify = true )
2246
- super ( )
2247
- @host = host
2248
- begin
2249
- options = port_or_options . to_hash
2250
- rescue NoMethodError
2251
- # for backward compatibility
2252
- options = { }
2253
- options [ :port ] = port_or_options
2254
- if usessl
2255
- options [ :ssl ] = create_ssl_params ( certs , verify )
2311
+ def default_tls_and_port ( tls , port )
2312
+ if tls . nil? && port
2313
+ tls = true if port == SSL_PORT || /\A imaps\z /i === port
2314
+ tls = false if port == PORT
2315
+ elsif port . nil? && !tls . nil?
2316
+ port = tls ? SSL_PORT : PORT
2317
+ end
2318
+ if tls . nil? && port . nil?
2319
+ tls = self . class . default_tls . dup . freeze
2320
+ port = tls ? SSL_PORT : PORT
2321
+ if tls . nil?
2322
+ warn "A future version of Net::IMAP.default_tls " \
2323
+ "will default to 'true', for secure connections by default. " \
2324
+ "Use 'Net::IMAP.new(host, tls: false)' or set " \
2325
+ "Net::IMAP.default_tls = false' to silence this warning."
2256
2326
end
2257
2327
end
2258
- @port = options [ :port ] || ( options [ :ssl ] ? SSL_PORT : PORT )
2259
- @tag_prefix = "RUBY"
2260
- @tagno = 0
2261
- @utf8_strings = false
2262
- @open_timeout = options [ :open_timeout ] || 30
2263
- @idle_response_timeout = options [ :idle_response_timeout ] || 5
2264
- @parser = ResponseParser . new
2328
+ tls &&= tls . respond_to? ( :to_hash ) ? tls . to_hash : { }
2329
+ [ tls , port ]
2330
+ end
2331
+
2332
+ def start_connection
2265
2333
@sock = tcp_socket ( @host , @port )
2266
2334
begin
2267
- if options [ :ssl ]
2268
- start_tls_session ( options [ :ssl ] )
2269
- @usessl = true
2270
- else
2271
- @usessl = false
2272
- end
2273
- @responses = Hash . new { |h , k | h [ k ] = [ ] }
2274
- @tagged_responses = { }
2275
- @response_handlers = [ ]
2276
- @tagged_response_arrival = new_cond
2277
- @continued_command_tag = nil
2278
- @continuation_request_arrival = new_cond
2279
- @continuation_request_exception = nil
2280
- @idle_done_cond = nil
2281
- @logout_command_tag = nil
2282
- @debug_output_bol = true
2283
- @exception = nil
2284
-
2335
+ start_tls_session ( @tls ) if @tls
2285
2336
@greeting = get_response
2286
- if @greeting . nil?
2287
- raise Error , "connection closed"
2288
- end
2289
- record_untagged_response_code @greeting
2290
- @capabilities = capabilities_from_resp_code @greeting
2291
- if @greeting . name == "BYE"
2292
- raise ByeResponseError , @greeting
2293
- end
2294
-
2295
- @client_thread = Thread . current
2296
- @receiver_thread = Thread . start {
2297
- begin
2298
- receive_responses
2299
- rescue Exception
2300
- end
2301
- }
2302
- @receiver_thread_terminating = false
2337
+ handle_server_greeting
2338
+ @receiver_thread = start_receiver_thread
2303
2339
rescue Exception
2304
2340
@sock . close
2305
2341
raise
2306
2342
end
2307
2343
end
2308
2344
2345
+ def handle_server_greeting
2346
+ if @greeting . nil?
2347
+ raise Error , "connection closed"
2348
+ end
2349
+ record_untagged_response_code ( @greeting )
2350
+ @capabilities = capabilities_from_resp_code @greeting
2351
+ if @greeting . name == "BYE"
2352
+ raise ByeResponseError , @greeting
2353
+ end
2354
+ end
2355
+
2356
+ def start_receiver_thread
2357
+ Thread . start do
2358
+ receive_responses
2359
+ rescue Exception
2360
+ # don't exit the thread with an exception
2361
+ end
2362
+ rescue Exception
2363
+ @sock . close
2364
+ raise
2365
+ end
2366
+
2309
2367
def tcp_socket ( host , port )
2310
2368
s = Socket . tcp ( host , port , :connect_timeout => @open_timeout )
2311
2369
s . setsockopt ( :SOL_SOCKET , :SO_KEEPALIVE , true )
@@ -2592,34 +2650,12 @@ def normalize_searching_criteria(keys)
2592
2650
end
2593
2651
end
2594
2652
2595
- def create_ssl_params ( certs = nil , verify = true )
2596
- params = { }
2597
- if certs
2598
- if File . file? ( certs )
2599
- params [ :ca_file ] = certs
2600
- elsif File . directory? ( certs )
2601
- params [ :ca_path ] = certs
2602
- end
2603
- end
2604
- if verify
2605
- params [ :verify_mode ] = VERIFY_PEER
2606
- else
2607
- params [ :verify_mode ] = VERIFY_NONE
2608
- end
2609
- return params
2610
- end
2611
-
2612
2653
def start_tls_session ( params = { } )
2613
2654
unless defined? ( OpenSSL ::SSL )
2614
- raise "SSL extension not installed"
2655
+ raise "OpenSSL extension not installed"
2615
2656
end
2616
2657
if @sock . kind_of? ( OpenSSL ::SSL ::SSLSocket )
2617
- raise RuntimeError , "already using SSL"
2618
- end
2619
- begin
2620
- params = params . to_hash
2621
- rescue NoMethodError
2622
- params = { }
2658
+ raise RuntimeError , "already using TLS"
2623
2659
end
2624
2660
context = SSLContext . new
2625
2661
context . set_params ( params )
@@ -2655,3 +2691,6 @@ def self.saslprep(string, **opts)
2655
2691
require_relative "imap/response_data"
2656
2692
require_relative "imap/response_parser"
2657
2693
require_relative "imap/authenticators"
2694
+
2695
+ require_relative "imap/deprecated_client_options"
2696
+ Net ::IMAP . prepend Net ::IMAP ::DeprecatedClientOptions
0 commit comments