"net"
"net/mail"
"net/textproto"
+ "strings"
)
type state int
continue
}
- switch cmd {
+ switch strings.ToUpper(cmd) {
case "QUIT":
conn.writeReply(221, "Goodbye")
conn.tp.Close()
}
}
+// parsePath parses out either a forward-, reverse-, or return-path from the
+// current connection line. Returns a (valid-path, ReplyOK) if it was
+// successfully parsed.
+func (conn *connection) parsePath(command string) (string, ReplyLine) {
+ if len(conn.line) < len(command) {
+ return "", ReplyBadSyntax
+ }
+ if strings.ToUpper(command) != strings.ToUpper(conn.line[:len(command)]) {
+ return "", ReplyLine{500, "unrecognized command"}
+ }
+ return conn.line[len(command):], ReplyOK
+}
+
func (conn *connection) doEHLO() {
conn.resetBuffers()
return
}
- var mailFrom string
- _, err := fmt.Sscanf(conn.line, "MAIL FROM:%s", &mailFrom)
- if err != nil {
- conn.reply(ReplyBadSyntax)
+ mailFrom, reply := conn.parsePath("MAIL FROM:")
+ if reply != ReplyOK {
+ conn.reply(reply)
return
}
+ var err error
conn.mailFrom, err = mail.ParseAddress(mailFrom)
if err != nil {
conn.reply(ReplyBadSyntax)
return
}
- var rcptTo string
- _, err := fmt.Sscanf(conn.line, "RCPT TO:%s", &rcptTo)
- if err != nil {
- conn.reply(ReplyBadSyntax)
+ rcptTo, reply := conn.parsePath("RCPT TO:")
+ if reply != ReplyOK {
+ conn.reply(reply)
return
}
{"QUIT", 221, nil},
})
}
+
+func TestCaseSensitivty(t *testing.T) {
+ s := &testServer{}
+ l := runServer(t, s)
+ defer l.Close()
+
+ conn := createClient(t, l.Addr())
+ readCodeLine(t, conn, 220)
+
+ runTableTest(t, conn, []requestResponse{
+ {"nOoP", 250, nil},
+ {"ehLO test.TEST", 0, func(t testing.TB, conn *textproto.Conn) { conn.ReadResponse(250) }},
+ {"mail FROM:<sender@example.com>", 250, nil},
+ {"RcPT tO:<receive@mail.com>", 250, nil},
+ {"DATa", 0, func(t testing.TB, conn *textproto.Conn) {
+ readCodeLine(t, conn, 354)
+
+ ok(t, conn.PrintfLine("."))
+ readCodeLine(t, conn, 250)
+ }},
+ {"MAIL FR:", 501, nil},
+ {"QUiT", 221, nil},
+ })
+}