diff --git a/protocol.go b/protocol.go index a09f82d..6cd38e6 100644 --- a/protocol.go +++ b/protocol.go @@ -229,8 +229,10 @@ func (proto *Protocol) Command(command *Command) (reply *Reply) { return ReplyBye() case "RSET" == command.verb: proto.logf("Got RSET command, switching to MAIL state") + helo := proto.Message.Helo proto.State = MAIL proto.Message = &data.SMTPMessage{} + proto.Message.Helo = helo return ReplyOk() case "NOOP" == command.verb: proto.logf("Got NOOP verb, staying in %s state", StateMap[proto.State]) @@ -410,6 +412,7 @@ func (proto *Protocol) Command(command *Command) (reply *Reply) { // HELO creates a reply to a HELO command func (proto *Protocol) HELO(args string) (reply *Reply) { proto.logf("Got HELO command, switching to MAIL state") + proto.resetState() proto.State = MAIL proto.Message.Helo = args return ReplyOk("Hello " + args) @@ -418,6 +421,7 @@ func (proto *Protocol) HELO(args string) (reply *Reply) { // EHLO creates a reply to a EHLO command func (proto *Protocol) EHLO(args string) (reply *Reply) { proto.logf("Got EHLO command, switching to MAIL state") + proto.resetState() proto.State = MAIL proto.Message.Helo = args replyArgs := []string{"Hello " + args, "PIPELINING"} diff --git a/protocol_test.go b/protocol_test.go index 45f0125..c6ecf61 100644 --- a/protocol_test.go +++ b/protocol_test.go @@ -296,10 +296,10 @@ func TestEHLO(t *testing.T) { So(proto.State, ShouldEqual, MAIL) So(proto.Message.Helo, ShouldEqual, "localhost") }) - Convey("HELO should work in MAIL state", t, func() { + Convey("EHLO should work in MAIL state", t, func() { proto := NewProtocol() proto.Start() - proto.Command(ParseCommand("HELO localhost")) + proto.Command(ParseCommand("EHLO localhost")) So(proto.State, ShouldEqual, MAIL) So(proto.Message.Helo, ShouldEqual, "localhost") reply := proto.Command(ParseCommand("EHLO localhost")) @@ -309,19 +309,43 @@ func TestEHLO(t *testing.T) { So(proto.State, ShouldEqual, MAIL) So(proto.Message.Helo, ShouldEqual, "localhost") }) - Convey("HELO should work in RCPT state", t, func() { + Convey("EHLO should work in RCPT state", t, func() { proto := NewProtocol() proto.Start() - proto.Command(ParseCommand("HELO localhost")) + proto.Command(ParseCommand("EHLO localhost")) proto.Command(ParseCommand("MAIL From:")) So(proto.State, ShouldEqual, RCPT) So(proto.Message.Helo, ShouldEqual, "localhost") - reply := proto.Command(ParseCommand("EHLO localhost")) + So(proto.Message.From, ShouldEqual, "test") + So(proto.Message.To, ShouldBeZeroValue) + reply := proto.Command(ParseCommand("EHLO localhost2")) So(reply, ShouldNotBeNil) So(reply.Status, ShouldEqual, 250) - So(reply.Lines(), ShouldResemble, []string{"250-Hello localhost\r\n", "250 PIPELINING\r\n"}) + So(reply.Lines(), ShouldResemble, []string{"250-Hello localhost2\r\n", "250 PIPELINING\r\n"}) So(proto.State, ShouldEqual, MAIL) + So(proto.Message.Helo, ShouldEqual, "localhost2") + So(proto.Message.From, ShouldBeZeroValue) + So(proto.Message.To, ShouldBeZeroValue) + }) + Convey("EHLO should work in RCPT state with recipients", t, func() { + proto := NewProtocol() + proto.Start() + proto.Command(ParseCommand("EHLO localhost")) + proto.Command(ParseCommand("MAIL From:")) + proto.Command(ParseCommand("RCPT To:")) + proto.Command(ParseCommand("RCPT To:")) + So(proto.State, ShouldEqual, RCPT) So(proto.Message.Helo, ShouldEqual, "localhost") + So(proto.Message.From, ShouldEqual, "test") + So(proto.Message.To, ShouldResemble, []string{"rcpt1", "rcpt2"}) + reply := proto.Command(ParseCommand("EHLO localhost2")) + So(reply, ShouldNotBeNil) + So(reply.Status, ShouldEqual, 250) + So(reply.Lines(), ShouldResemble, []string{"250-Hello localhost2\r\n", "250 PIPELINING\r\n"}) + So(proto.State, ShouldEqual, MAIL) + So(proto.Message.Helo, ShouldEqual, "localhost2") + So(proto.Message.From, ShouldBeZeroValue) + So(proto.Message.To, ShouldBeZeroValue) }) } @@ -370,12 +394,36 @@ func TestHELO(t *testing.T) { proto.Command(ParseCommand("MAIL From:")) So(proto.State, ShouldEqual, RCPT) So(proto.Message.Helo, ShouldEqual, "localhost") - reply := proto.Command(ParseCommand("HELO localhost")) + So(proto.Message.From, ShouldEqual, "test") + So(proto.Message.To, ShouldBeZeroValue) + reply := proto.Command(ParseCommand("HELO localhost2")) So(reply, ShouldNotBeNil) So(reply.Status, ShouldEqual, 250) - So(reply.Lines(), ShouldResemble, []string{"250 Hello localhost\r\n"}) + So(reply.Lines(), ShouldResemble, []string{"250 Hello localhost2\r\n"}) So(proto.State, ShouldEqual, MAIL) + So(proto.Message.Helo, ShouldEqual, "localhost2") + So(proto.Message.From, ShouldBeZeroValue) + So(proto.Message.To, ShouldBeZeroValue) + }) + Convey("HELO should work in RCPT state with recipients", t, func() { + proto := NewProtocol() + proto.Start() + proto.Command(ParseCommand("HELO localhost")) + proto.Command(ParseCommand("MAIL From:")) + proto.Command(ParseCommand("RCPT To:")) + proto.Command(ParseCommand("RCPT To:")) + So(proto.State, ShouldEqual, RCPT) So(proto.Message.Helo, ShouldEqual, "localhost") + So(proto.Message.From, ShouldEqual, "test") + So(proto.Message.To, ShouldResemble, []string{"rcpt1", "rcpt2"}) + reply := proto.Command(ParseCommand("HELO localhost2")) + So(reply, ShouldNotBeNil) + So(reply.Status, ShouldEqual, 250) + So(reply.Lines(), ShouldResemble, []string{"250 Hello localhost2\r\n"}) + So(proto.State, ShouldEqual, MAIL) + So(proto.Message.Helo, ShouldEqual, "localhost2") + So(proto.Message.From, ShouldBeZeroValue) + So(proto.Message.To, ShouldBeZeroValue) }) } @@ -485,6 +533,7 @@ func TestRSET(t *testing.T) { So(reply.Status, ShouldEqual, 250) So(reply.Lines(), ShouldResemble, []string{"250 Ok\r\n"}) So(proto.State, ShouldEqual, MAIL) + So(proto.Message.Helo, ShouldEqual, "localhost") So(proto.Message.From, ShouldEqual, "") So(len(proto.Message.To), ShouldEqual, 0) })