--Boundary-00DKcAGvH0LnkjzG Content-Type: Multipart/Mixed; boundaryoundary-00DKcAGvH0LnkjzG" --Boundary-00DKcAGvH0LnkjzG Content-Type: text/plain; charset s-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline I've reworked the patch to implement a few new methods and not add any extra arguments to existing methods. 3 new class vars: @@usessl @@certs @@verify New methods: Toggle SSL connections for new instances. Sets the above class variables. POP3.enable_ssl( verify, certs ) POP3.disable_ssl 2 equivalent instance methods to enable / disable SSL on a per instance basis: pop.enable_ssl(verify, certs, port) pop.disable_ssl Example usage: Quick 'n dirty all connections are SSL: Net::POP3.enable_ssl Net::POP3.start(server,port,account,password) do |pop| ... end Use SSL on a case by case basis: pop et::POP3.new(server) pop.enable_ssl if use_ssl_on_this_server pop.start(user,password) do |pop| ... end Do people like this better? This way of handling SSL could be applied to SMTP and IMAP as well to get a consistant SSL API across all the mail services. FYI, I'll be on vacation for the next week and away from a computer until I get back. -- Daniel Hobe <daniel / nightrunner.com> http://www.nightrunner.com --Boundary-00DKcAGvH0LnkjzG Content-Type: text/x-diff; charset s-ascii"; name op.patch_v4" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename op.patch_v4" --- /home/hobe/downloads/ruby/ruby/lib/net/pop.rb 2004-04-04 16:37:09.000000000 -0700 +++ pop.rb 2004-04-04 16:56:33.000000000 -0700 @@ -36,12 +36,13 @@ # require 'net/pop' # # pop et::POP3.new('pop.example.com') -# pop.start('YourAccount', 'YourPassword') # (1) +# pop op.enable_ssl(verify, certs) if $use_ssl # (1) +# pop.start('YourAccount', 'YourPassword') # (2) # if pop.mails.empty? # puts 'no mail.' # else # i -# pop.each_mail do |m| # or "pop.mails.each ..." # (2) +# pop.each_mail do |m| # or "pop.mails.each ..." # (3) # File.open("inbox/#{i}", 'w') {|f| # f.write m.pop # } @@ -50,11 +51,12 @@ # end # puts "#{pop.mails.size} mails popped." # end -# pop.finish # (3) +# pop.finish # (4) # -# 1. call Net::POP3#start and start POP session -# 2. access messages by using POP3#each_mail and/or POP3#mails -# 3. close POP session by calling POP3#finish or use the block form of #start. +# 1. optionally enable SSL for this POP connection +# 2. call Net::POP3#start and start POP session +# 3. access messages by using POP3#each_mail and/or POP3#mails +# 4. close POP session by calling POP3#finish or use the block form of #start. # # Shortened Code # @@ -141,10 +143,31 @@ # # # Use APOP authentication if $isapop true # pop et::POP3.APOP($is_apop).new('apop.example.com', 110) -# pop.start(YourAccount', 'YourPassword') {|pop| +# pop.start('YourAccount', 'YourPassword') {|pop| # # Rest code is same. # } +# +# Using SSL +# The net/pop library supports POP3 over SSL. +# To use SSL: +# +# Example 1: +# require 'net/pop' +# +# pop et::POP3.APOP($is_apop) +# pop op.enable_ssl if $use_ssl +# pop.start(server, port, account, password) do |pop| +# ... +# end # +# Example 2: +# require 'net/pop' +# pop et::POP3.new('pop.example.com').enable_ssl +# pop.start(username, password) do |pop| +# ... +# end +# +# # Fetch Only Selected Mail Using `UIDL' POP Command # # If your POP server provides UIDL functionality, @@ -170,6 +193,11 @@ require 'digest/md5' require 'timeout' +begin + require "openssl" +rescue LoadError +end + module Net # Non-authentication POP3 protocol error @@ -196,9 +224,19 @@ # Class Parameters # + @@usessl il + @@verify il + @@certs il + PORT 10 + SSL_PORT 95 # The default port for POP3 connections, port 110 def POP3.default_port - 110 + PORT + end + + # The default port for POP3S connections, port 995 + def POP3.default_ssl_port + SSL_PORT end def POP3.socket_type #:nodoc: obsolete @@ -324,17 +362,43 @@ new(address, port, isapop).start(account, password, &block) end + # Enable SSL for all new instances. + # +verify+ is the type of verification to do on the Server Cert; Defaults + # to OpenSSL::SSL::VERIFY_PEER. + # +certs+ is a file or directory holding CA certs to use to verify the + # server cert; Defaults to nil. + def POP3.enable_ssl( verify penSSL::SSL::VERIFY_PEER, certs il ) + @@usessl rue + @@verify erify + @@certs erts + end + + # Disable SSL for all new instances. + def POP3.disable_ssl + @@usessl il + @@verify il + @@certs il + end + # Creates a new POP3 object. - # +address+ is the hostname or ip address of your POP3 server. - # The optional +port+ is the port to connect to; it defaults to 110. + # +addr+ is the hostname or ip address of your POP3 server. + # The optional +port+ is the port to connect to. # The optional +isapop+ specifies whether this connection is going # to use APOP authentication; it defaults to +false+. # This method does *not* open the TCP connection. def initialize(addr, port il, isapop alse) @address ddr - @port ort || self.class.default_port + @usessl @usessl + if @usessl + @port ort || POP3::SSL_PORT + else + @port ort || POP3::PORT + end @apop sapop - + + @certs @certs + @verify @verify + @command il @socket il @started alse @@ -352,6 +416,32 @@ @apop end + # does this instance use SSL? + def usessl? + @usessl + end + + # Enables SSL for this instance. Must be called before the connection is + # established to have any effect. + # +verify+ is the type of verification to do on the Server Cert; Defaults + # to OpenSSL::SSL::VERIFY_PEER. + # +certs+ is a file or directory holding CA certs to use to verify the + # server cert; Defaults to nil. + # +port+ is port to establish the SSL conection on; Defaults to 995. + def enable_ssl(verify penSSL::SSL::VERIFY_PEER, certs il, + port OP3::SSL_PORT) + @usessl rue + @verify erify + @certs erts + @port ort + end + + def disable_ssl + @usessl il + @verify il + @certs il + end + # Provide human-readable stringification of class state. def inspect "#<#{self.class} #{@address}:#{@port} open @started}>" @@ -424,9 +514,22 @@ end def do_start(account, password) - @socket nternetMessageIO.new(timeout(@open_timeout) { - TCPSocket.open(@address, @port) - }) + s imeout(@open_timeout) { TCPSocket.open(@address, @port) } + if @usessl + unless defined?(OpenSSL) + raise "SSL extension not installed" + end + sslctx penSSL::SSL::SSLContext.new + sslctx.verify_mode verify + sslctx.ca_file certs if @certs && FileTest::file?(@certs) + sslctx.ca_path certs if @certs && FileTest::directory?(@certs) + s penSSL::SSL::SSLSocket.new(s, sslctx) + s.sync_close rue + s.connect + end + + @socket nternetMessageIO.new(s) + logging "POP session started: #{@address}:#{@port} (#{@apop ? 'APOP' : 'POP'})" @socket.read_timeout read_timeout @socket.debug_output debug_output --Boundary-00DKcAGvH0LnkjzG-- --Boundary-00DKcAGvH0LnkjzG--