summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/net/protocol.rb3
-rw-r--r--lib/net/smtp.rb60
2 files changed, 56 insertions, 7 deletions
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index d8e358b95f..81e8e987eb 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -15,7 +15,7 @@ require 'socket'
module Net
- Version = '1.1.15'
+ Version = '1.1.16'
=begin
@@ -346,6 +346,7 @@ Object
SyntaxErrorCode = ErrorCode.mkchild( ProtoSyntaxError )
FatalErrorCode = ErrorCode.mkchild( ProtoFatalError )
ServerErrorCode = ErrorCode.mkchild( ProtoServerError )
+ AuthErrorCode = ErrorCode.mkchild( ProtoAuthError )
RetriableCode = ReplyCode.mkchild( ProtoRetriableError )
UnknownCode = ReplyCode.mkchild( ProtoUnknownError )
diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb
index 271441279a..fe3dd9e1b2 100644
--- a/lib/net/smtp.rb
+++ b/lib/net/smtp.rb
@@ -11,6 +11,7 @@ You can freely distribute/modify this library.
require 'net/protocol'
+require 'md5'
module Net
@@ -32,10 +33,13 @@ Net::Protocol
=== Methods
-: start( helo_domain = ENV['HOSTNAME'] )
+: start( helo_domain = ENV['HOSTNAME'] || ENV['HOST'], account = nil, password = nil, authtype = nil )
This method opens TCP connection and start SMTP.
If protocol had been started, do nothing and return false.
+ If account and password are given, is trying to get authentication
+ by using AUTH command. "authtype" is :plain (symbol) or :cram_md5.
+
: sendmail( mailsrc, from_addr, to_addrs )
This method sends 'mailsrc' as mail. SMTPSession read strings
from 'mailsrc' by calling 'each' iterator, and convert them
@@ -102,12 +106,15 @@ Net::Protocol
@command.data
end
- def do_start( helodom = ENV['HOSTNAME'] )
+ def do_start( helodom = nil,
+ user = nil, secret = nil, authtype = nil )
unless helodom then
- raise ArgumentError, "cannot get hostname"
+ helodom = ENV['HOSTNAME'] || ENV['HOST']
+ unless helodom then
+ raise ArgumentError, "cannot get hostname"
+ end
end
- @esmtp = false
begin
if @esmtp then
@command.ehlo helodom
@@ -122,6 +129,15 @@ Net::Protocol
raise
end
end
+
+ if user and secret then
+ begin
+ mid = 'auth_' + (authtype || 'cram_md5').to_s
+ @command.send mid, user, secret
+ rescue NameError
+ raise ArgumentError, "wrong auth type #{authtype.to_s}"
+ end
+ end
end
end
@@ -154,6 +170,35 @@ Net::Protocol
end
+ # "PLAIN" authentication [RFC2554]
+ def auth_plain( user, secret )
+ critical {
+ 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 = MD5.new( secret ).digest 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 = MD5.new( isecret + challenge ).digest
+ tmp = MD5.new( osecret + tmp ).hexdigest
+
+ getok [user + ' ' + tmp].pack('m').chomp
+ }
+ end
+
+
def mailfrom( fromaddr )
critical {
getok sprintf( 'MAIL FROM:<%s>', fromaddr )
@@ -198,7 +243,6 @@ Net::Protocol
arr = read_reply
stat = arr[0][0,3]
- klass = UnknownCode
klass = case stat[0]
when ?2 then SuccessCode
when ?3 then ContinueCode
@@ -206,9 +250,11 @@ Net::Protocol
when ?5 then
case stat[1]
when ?0 then SyntaxErrorCode
+ when ?3 then AuthErrorCode
when ?5 then FatalErrorCode
end
end
+ klass ||= UnknownCode
Response.new( klass, stat, arr.join('') )
end
@@ -217,7 +263,9 @@ Net::Protocol
def read_reply
arr = []
- while (str = @socket.readline)[3] == ?- do # ex: "210-..."
+ while true do
+ str = @socket.readline
+ break unless str[3] == ?- # ex: "210-..."
arr.push str
end
arr.push str