Add DATA/RCPT commands

This commit is contained in:
Ian Kent 2014-04-19 12:44:05 +01:00
parent fc2097fc33
commit b5f41ce7b9

View file

@ -14,6 +14,7 @@ type Session struct {
line string line string
conf *mailhog.Config conf *mailhog.Config
state int state int
message *Message
} }
const ( const (
@ -21,19 +22,20 @@ const (
MAIL MAIL
RCPT RCPT
DATA DATA
DONE
) )
type Message struct { type Message struct {
From string From string
To string To []string
Data []byte Data string
Helo string Helo string
} }
func StartSession(conn *net.TCPConn, conf *mailhog.Config) { func StartSession(conn *net.TCPConn, conf *mailhog.Config) {
conv := &Session{conn, "", conf, ESTABLISH} conv := &Session{conn, "", conf, ESTABLISH, &Message{}}
conv.log("Starting session") conv.log("Starting session")
conv.Write("220", "Go-MailHog") conv.Write("220", conv.conf.Hostname + " ESMTP Go-MailHog")
conv.Read() conv.Read()
} }
@ -72,7 +74,15 @@ func (c *Session) Parse() {
} else { } else {
c.line = "" c.line = ""
} }
c.Process(strings.Trim(parts[0], "\r\n")) if c.state == DATA {
c.message.Data += parts[0] + "\n"
if(strings.HasSuffix(c.message.Data, "\r\n.\r\n")) {
c.state = DONE
c.Write("250", "Ok: queued as nnnnnnnn")
}
} else {
c.Process(strings.Trim(parts[0], "\r\n"))
}
} }
c.Read() c.Read()
@ -94,38 +104,70 @@ func (c *Session) Process(line string) {
words := strings.Split(line, " ") words := strings.Split(line, " ")
command := words[0] command := words[0]
c.log("In state %d, got command '%s'", c.state, command) args := strings.Join(words[1:len(words)], " ")
c.log("In state %d, got command '%s', args '%s'", c.state, command, args)
switch { switch {
case command == "RSET": case command == "RSET":
c.log("Got RSET command, switching to ESTABLISH state") c.log("Got RSET command, switching to ESTABLISH state")
c.state = ESTABLISH c.state = ESTABLISH
c.Write("250", "OK") c.message = &Message{}
c.Write("250", "Ok")
case command == "NOOP": case command == "NOOP":
c.log("Got NOOP command") c.log("Got NOOP command")
c.Write("250", "OK") c.Write("250", "Ok")
case command == "QUIT": case command == "QUIT":
c.log("Got QUIT command") c.log("Got QUIT command")
c.Write("221", "OK") c.Write("221", "Bye")
case c.state == ESTABLISH: case c.state == ESTABLISH:
switch command { switch command {
case "HELO": case "HELO":
c.log("Got HELO command, switching to MAIL state") c.log("Got HELO command, switching to MAIL state")
c.state = MAIL c.state = MAIL
c.Write("250", "HELO " + c.conf.Hostname) c.message.Helo = args
c.Write("250", "Hello " + args)
case "EHLO": case "EHLO":
c.log("Got EHLO command, switching to MAIL state") c.log("Got EHLO command, switching to MAIL state")
c.state = MAIL c.state = MAIL
c.Write("250", "EHLO " + c.conf.Hostname) c.message.Helo = args
c.Write("250", "Hello " + args)
default: default:
c.log("Got unknown command for ESTABLISH state: '%s'", command) c.log("Got unknown command for ESTABLISH state: '%s'", command)
} }
case c.state == MAIL: case c.state == MAIL:
switch command { switch command {
case "MAIL": case "MAIL":
c.log("Got MAIL command") c.log("Got MAIL command, switching to RCPT state")
// TODO parse args
c.message.From = args
c.state = RCPT
c.Write("250", "Ok")
default: default:
c.log("Got unknown command for MAIL state: '%s'", command) c.log("Got unknown command for MAIL state: '%s'", command)
} }
case c.state == RCPT:
switch command {
case "RCPT":
c.log("Got RCPT command")
c.message.To = append(c.message.To, args)
c.Write("250", "Ok")
case "DATA":
c.log("Got DATA command, switching to DATA state")
c.state = DATA
c.Write("354", "End data with <CR><LF>.<CR><LF>")
default:
c.log("Got unknown command for RCPT state: '%s'", command)
}
case c.state == DONE:
switch command {
case "MAIL":
c.log("Got MAIL command")
// TODO parse args
c.message.From = args
c.state = RCPT
c.Write("250", "Ok")
default:
c.log("Got unknown command for DONE state: '%s'", command)
}
} }
} }