From f3d9a0cc213f8b09155f063e057afb576178557e Mon Sep 17 00:00:00 2001 From: aamine Date: Sun, 30 Dec 2001 19:18:45 +0000 Subject: aamine * lib/net/protocol.rb: Protocol#start returns the return value of block. * lib/net/protocol.rb: set timeout limit by default. * lib/net/protocol.rb: new methods WriteAdapter#write, puts, print, printf. * lib/net/http.rb: rename HTTP#get2 to request_get, post2 to request_post ... * lib/net/smtp.rb: should not resolve HELO domain automatically. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1951 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/net/smtp.rb | 196 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 98 insertions(+), 98 deletions(-) (limited to 'lib/net/smtp.rb') diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb index b7b0f6bccc..363fc39088 100644 --- a/lib/net/smtp.rb +++ b/lib/net/smtp.rb @@ -92,17 +92,17 @@ like File and Array. } } -=== Giving "Hello" Domain +=== HELO domain -If your machine does not have canonical host name, maybe you -must designate the third argument of SMTP.start. +In almost all situation, you must designate the third argument +of SMTP.start/SMTP#start. It is the domain name which you are on +(the host to send mail from). It is called "HELO domain". +SMTP server will judge if he/she should send or reject +the SMTP session by inspecting HELO domain. Net::SMTP.start( 'your.smtp.server', 25, 'mail.from.domain' ) {|smtp| -This argument gives MAILFROM domain, the domain name that -you send mail from. SMTP server might judge if he (or she?) -send or reject SMTP session by this data. == class Net::SMTP @@ -111,8 +111,8 @@ send or reject SMTP session by this data. : new( address, port = 25 ) creates a new Net::SMTP object. -: start( address, port = 25, helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) -: start( address, port = 25, helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) {|smtp| .... } +: start( address, port = 25, helo_domain = 'localhost.localdomain', account = nil, password = nil, authtype = nil ) +: start( address, port = 25, helo_domain = 'localhost.localdomain', account = nil, password = nil, authtype = nil ) {|smtp| .... } is equal to Net::SMTP.new(address,port).start(helo_domain,account,password,authtype) @@ -179,8 +179,9 @@ send or reject SMTP session by this data. : ready( from_addr, *to_addrs ) {|adapter| .... } This method stands by the SMTP object for sending mail and - give adapter object to the block. ADAPTER accepts only "write" - method. + gives adapter object to the block. ADAPTER has these 5 methods: + + puts print printf write << FROM_ADDR must be a String, representing source mail address. TO_ADDRS must be Strings or an Array of Strings, representing @@ -188,11 +189,13 @@ send or reject SMTP session by this data. # example Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp| - smtp.ready( 'from@mail.addr', 'dest@mail.addr' ) do |adapter| - adapter.write str1 - adapter.write str2 - adapter.write str3 - end + smtp.ready( 'from@mail.addr', 'dest@mail.addr' ) {|f| + f.puts 'From: aamine@loveruby.net' + f.puts 'To: someone@somedomain.org' + f.puts 'Subject: test mail' + f.puts + f.puts 'This is test mail.' + } } == Exceptions @@ -215,13 +218,11 @@ require 'digest/md5' module Net - class SMTP < Protocol protocol_param :port, '25' protocol_param :command_type, '::Net::SMTPCommand' - def initialize( addr, port = nil ) super @esmtp = true @@ -229,49 +230,23 @@ module Net attr :esmtp - def send_mail( mailsrc, from_addr, *to_addrs ) - do_ready from_addr, to_addrs.flatten - @command.write_mail mailsrc, nil - end - - alias sendmail send_mail - - def ready( from_addr, *to_addrs, &block ) - do_ready from_addr, to_addrs.flatten - @command.write_mail nil, block - end - - private - - def do_ready( from_addr, to_addrs ) - if to_addrs.empty? then - raise ArgumentError, 'mail destination does not given' - end - @command.mailfrom from_addr - @command.rcpt to_addrs - @command.data - end - - def do_start( helodom = nil, + def do_start( helo = 'localhost.localdomain', user = nil, secret = nil, authtype = nil ) - helodom ||= ::Socket.gethostname - unless helodom then - raise ArgumentError, - "cannot get localhost name; try 'smtp.start(local_host_name)'" - end + conn_socket + conn_command begin if @esmtp then - @command.ehlo helodom + command().ehlo helo else - @command.helo helodom + command().helo helo end rescue ProtocolError if @esmtp then @esmtp = false - @command.error_ok + command().error_ok retry else raise @@ -283,110 +258,133 @@ module Net raise ArgumentError, 'both of account and password are required' mid = 'auth_' + (authtype || 'cram_md5').to_s - @command.respond_to? mid or + command().respond_to? mid or raise ArgumentError, "wrong auth type #{authtype.to_s}" - @command.__send__ mid, user, secret + command().__send__ mid, user, secret end end - end + def do_finish + disconn_command + disconn_socket + end - SMTPSession = SMTP + # + # SMTP operations + # + + public + + def send_mail( mailsrc, from_addr, *to_addrs ) + do_ready from_addr, to_addrs.flatten + command().write_mail mailsrc, nil + end + + alias sendmail send_mail + + def ready( from_addr, *to_addrs, &block ) + do_ready from_addr, to_addrs.flatten + command().write_mail nil, block + end + + private + + def do_ready( from_addr, to_addrs ) + if to_addrs.empty? then + raise ArgumentError, 'mail destination does not given' + end + command().mailfrom from_addr + command().rcpt to_addrs + command().data + end + + end class SMTPCommand < Command def initialize( sock ) super - critical { - check_reply SuccessCode + atomic { + check_reply SuccessCode } end - - def helo( fromdom ) - critical { - getok sprintf( 'HELO %s', fromdom ) + def helo( domain ) + atomic { + getok sprintf('HELO %s', domain) } end - - def ehlo( fromdom ) - critical { - getok sprintf( 'EHLO %s', fromdom ) + def ehlo( domain ) + atomic { + getok sprintf('EHLO %s', domain) } end - # "PLAIN" authentication [RFC2554] def auth_plain( user, secret ) - critical { - getok sprintf( 'AUTH PLAIN %s', - ["\0#{user}\0#{secret}"].pack('m').chomp ) + atomic { + getok sprintf('AUTH PLAIN %s', + ["\0#{user}\0#{secret}"].pack('m').chomp) } end # "CRAM-MD5" authentication [RFC2195] def auth_cram_md5( user, secret ) - critical { - rep = getok( 'AUTH CRAM-MD5', ContinueCode ) - challenge = rep.msg.split(' ')[1].unpack('m')[0] - secret = Digest::MD5.digest( secret ) if secret.size > 64 - - isecret = secret + "\0" * (64 - secret.size) - osecret = isecret.dup - 0.upto( 63 ) do |i| - isecret[i] ^= 0x36 - osecret[i] ^= 0x5c - end - tmp = Digest::MD5.digest( isecret + challenge ) - tmp = Digest::MD5.hexdigest( osecret + tmp ) - - getok [user + ' ' + tmp].pack('m').chomp + atomic { + rep = getok( 'AUTH CRAM-MD5', ContinueCode ) + challenge = rep.msg.split(' ')[1].unpack('m')[0] + secret = Digest::MD5.digest(secret) if secret.size > 64 + + isecret = secret + "\0" * (64 - secret.size) + osecret = isecret.dup + 0.upto( 63 ) do |i| + isecret[i] ^= 0x36 + osecret[i] ^= 0x5c + end + tmp = Digest::MD5.digest( isecret + challenge ) + tmp = Digest::MD5.hexdigest( osecret + tmp ) + + getok [user + ' ' + tmp].pack('m').chomp } end - def mailfrom( fromaddr ) - critical { - getok sprintf( 'MAIL FROM:<%s>', fromaddr ) + atomic { + getok sprintf('MAIL FROM:<%s>', fromaddr) } end - def rcpt( toaddrs ) toaddrs.each do |i| - critical { - getok sprintf( 'RCPT TO:<%s>', i ) + atomic { + getok sprintf('RCPT TO:<%s>', i) } end end - def data - return unless begin_critical + return unless begin_atomic getok 'DATA', ContinueCode end def write_mail( mailsrc, block ) - @socket.write_pendstr mailsrc, block + @socket.write_pendstr mailsrc, &block check_reply SuccessCode - end_critical + end_atomic end - def quit - critical { - getok 'QUIT' + atomic { + getok 'QUIT' } end - private - def get_reply arr = read_reply stat = arr[0][0,3] @@ -407,7 +405,6 @@ module Net Response.new( klass, stat, arr.join('') ) end - def read_reply arr = [] while true do @@ -424,6 +421,9 @@ module Net # for backward compatibility + + SMTPSession = SMTP + module NetPrivate SMTPCommand = ::Net::SMTPCommand end -- cgit v1.2.3