Skip to content

Loading…

SmtpServer: support multiple messages per one connection #288

Open
wants to merge 4 commits into from

3 participants

@bogdan

In order to do that we need to reset the @state to "after authentication complete" point after receive message data.

Test case included.

@ibc
ibc commented

Hi, this pull request (along with others) has been included in EventMachine-LE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 3, 2012
  1. @bogdan
Commits on Feb 23, 2012
  1. @bogdan
Commits on Mar 1, 2012
  1. @bogdan

    Rename method properly

    bogdan committed
Commits on Jul 31, 2012
  1. @gregolsen
This page is out of date. Refresh to see the latest.
Showing with 99 additions and 13 deletions.
  1. +32 −9 lib/em/protocols/smtpserver.rb
  2. +67 −4 tests/test_smtpserver.rb
View
41 lib/em/protocols/smtpserver.rb
@@ -194,7 +194,8 @@ def receive_line ln
@@parms[:verbose] and $>.puts ">>> #{ln}"
return process_data_line(ln) if @state.include?(:data)
- return process_auth_line(ln) if @state.include?(:auth_incomplete)
+ return process_auth_plain_line(ln) if @state.include?(:auth_plain_incomplete)
+ return process_auth_login_line(ln) if @state.include?(:auth_login_incomplete)
case ln
when EhloRegex
@@ -343,28 +344,50 @@ def process_auth str
elsif str =~ /\APLAIN\s?/i
if $'.length == 0
# we got a partial response, so let the client know to send the rest
- @state << :auth_incomplete
+ @state << :auth_plain_incomplete
send_data("334 \r\n")
else
# we got the initial response, so go ahead & process it
- process_auth_line($')
+ process_auth_plain_line($')
end
- #elsif str =~ /\ALOGIN\s+/i
+ elsif str =~ /\ALOGIN\s?/i
+ if $'.length == 0
+ @state << :auth_login_incomplete
+ send_data("334 \r\n")
+ else
+ process_auth_login_line($')
+ end
+
else
send_data "504 auth mechanism not available\r\n"
end
end
- def process_auth_line(line)
+ def process_auth_login_line(line)
+ @login_auth ||= []
+ @login_auth << line.unpack("m").first
+ if @login_auth.size == 2
+ process_plain_auth(@login_auth.shift, @login_auth.shift)
+ @state.delete :auth_login_incomplete
+ else
+ send_data("334 \r\n")
+ end
+ end
+
+ def process_auth_plain_line(line)
plain = line.unpack("m").first
_,user,psw = plain.split("\000")
- if receive_plain_auth user,psw
+ process_plain_auth user,psw
+ @state.delete :auth_plain_incomplete
+ end
+
+ def process_plain_auth(user, password)
+ if receive_plain_auth(user, password)
send_data "235 authentication ok\r\n"
@state << :auth
else
send_data "535 invalid authentication\r\n"
end
- @state.delete :auth_incomplete
end
#--
@@ -538,10 +561,10 @@ def process_data_line ln
(d ? succeeded : failed).call
end
- @state.delete :data
+ @state -= [:data, :mail_from, :rcpt]
else
# slice off leading . if any
- ln.slice!(0...1) if ln[0] == 46
+ ln.slice!(0...1) if ln.start_with?('.')
@databuffer << ln
if @databuffer.length > @@parms[:chunksize]
receive_data_chunk @databuffer
View
71 tests/test_smtpserver.rb
@@ -1,3 +1,5 @@
+require 'net/smtp'
+require "net/telnet"
require 'em_test_helper'
class TestSmtpServer < Test::Unit::TestCase
@@ -13,34 +15,52 @@ class TestSmtpServer < Test::Unit::TestCase
#
class Mailserver < EM::Protocols::SmtpServer
- attr_reader :my_msg_body, :my_sender, :my_recipients
+ attr_reader :my_msg_body, :my_sender, :my_recipients, :messages_count
+
def initialize *args
super
end
+
def receive_sender sender
@my_sender = sender
#p sender
true
end
+
def receive_recipient rcpt
@my_recipients ||= []
@my_recipients << rcpt
true
end
+
def receive_data_chunk c
@my_msg_body = c.last
end
+
+ def receive_message
+ @messages_count ||= 0
+ @messages_count += 1
+ true
+ end
+
def connection_ended
EM.stop
end
end
- def test_mail
+ def run_server
c = nil
EM.run {
EM.start_server( Localhost, Localport, Mailserver ) {|conn| c = conn}
EM::Timer.new(2) {EM.stop} # prevent hanging the test suite in case of error
+ yield if block_given?
+ }
+ c
+ end
+
+ def test_mail
+ c = run_server do
EM::Protocols::SmtpClient.send :host=>Localhost,
:port=>Localport,
:domain=>"bogus",
@@ -48,10 +68,53 @@ def test_mail
:to=>"you@example.com",
:header=> {"Subject"=>"Email subject line", "Reply-to"=>"me@example.com"},
:body=>"Not much of interest here."
-
- }
+ end
assert_equal( "Not much of interest here.", c.my_msg_body )
assert_equal( "<me@example.com>", c.my_sender )
assert_equal( ["<you@example.com>"], c.my_recipients )
end
+
+
+
+ def test_multiple_messages_per_connection
+ c = run_server do
+ Thread.new do
+ Net::SMTP.start( Localhost, Localport, Localhost ) do |smtp|
+ 2.times do
+ smtp.send_message "This is a test e-mail message.", 'me@fromdomain.com', 'test@todomain.com'
+ end
+ end
+ end
+ end
+
+ assert_equal( 2, c.messages_count )
+ end
+
+ def test_login_authentication
+ Mailserver.parms = {:auth => :required}
+ connection = run_server do
+ Thread.new do
+ pop = Net::Telnet::new("Host" => Localhost,
+ "Port" =>Localport,
+ "Telnetmode" => false,
+ "Prompt" => /^\d{3}\s+/n
+ )
+ pop.cmd(<<-CMD)
+auth login
+#{["aaa"].pack('m').chomp}
+#{["bbb"].pack('m').chomp}
+mail from:a@b.com
+rcpt to:c@d.com
+data
+hello
+.
+quit
+CMD
+ end
+ end
+
+ assert_equal( 1, connection.messages_count )
+ ensure
+ Mailserver.parms = {:auth => nil}
+ end
end
Something went wrong with that request. Please try again.