MailHog/mailhog/smtp/smtp.go

103 lines
1.9 KiB
Go
Raw Normal View History

2014-04-16 22:59:25 +00:00
package smtp
// http://www.rfc-editor.org/rfc/rfc5321.txt
import (
"log"
"net"
2014-04-18 17:25:36 +00:00
"strings"
2014-04-16 22:59:25 +00:00
)
type Session struct {
conn *net.TCPConn
2014-04-18 17:25:36 +00:00
line string
2014-04-16 22:59:25 +00:00
}
type Message struct {
From string
To string
Data []byte
Helo string
}
2014-04-16 23:11:56 +00:00
func StartSession(conn *net.TCPConn) {
2014-04-18 17:25:36 +00:00
conv := &Session{conn, ""}
log.Printf("Starting session with %s", conn.RemoteAddr())
2014-04-16 22:59:25 +00:00
conv.Begin()
2014-04-16 23:11:56 +00:00
}
2014-04-18 17:25:36 +00:00
func (c Session) log(message string, args ...interface{}) {
message = strings.Join([]string{"[%s]", message}, " ")
args = append([]interface{}{c.conn.RemoteAddr()}, args...)
log.Printf(message, args...)
}
2014-04-16 23:11:56 +00:00
func (c Session) Read() {
2014-04-18 17:25:36 +00:00
buf := make([]byte, 1024)
2014-04-16 23:11:56 +00:00
n, err := c.conn.Read(buf)
2014-04-18 17:25:36 +00:00
2014-04-16 23:11:56 +00:00
if n == 0 {
2014-04-18 17:25:36 +00:00
c.log("Connection closed by remote host\n")
2014-04-16 23:11:56 +00:00
return
}
if err != nil {
2014-04-18 17:25:36 +00:00
c.log("Error reading from socket: %s\n", err)
2014-04-16 23:11:56 +00:00
return
}
2014-04-18 17:25:36 +00:00
2014-04-16 23:11:56 +00:00
text := string(buf)
2014-04-18 17:25:36 +00:00
c.log("Received %d bytes: %s\n", n, text)
c.line += text
c.Parse()
2014-04-16 23:11:56 +00:00
}
2014-04-18 17:25:36 +00:00
func (c Session) Parse() {
for strings.Contains(c.line, "\n") {
parts := strings.SplitN(c.line, "\n", 2)
c.line = parts[1]
c.log("Parsing string: %s", parts[0])
c.Process(strings.Trim(parts[0], "\r\n"))
}
2014-04-16 23:11:56 +00:00
c.Read()
2014-04-16 22:59:25 +00:00
}
2014-04-18 17:25:36 +00:00
func (c Session) Write(code string, text ...string) {
if len(text) == 1 {
c.conn.Write([]byte(code + " " + text[0] + "\n"))
return
}
for i := 0; i < len(text) - 2; i++ {
c.conn.Write([]byte(code + "-" + text[i] + "\n"))
}
c.conn.Write([]byte(code + " " + text[len(text)] + "\n"))
}
func (c Session) Process(line string) {
c.log("Processing line: %s", line)
words := strings.Split(line, " ")
switch words[0] {
case "HELO":
c.log("Got HELO command")
c.Write("250", "HELO " + "my.hostname")
case "EHLO":
c.log("Got EHLO command")
c.Write("250", "HELO " + "my.hostname")
default:
c.log("Got unknown command: '%s'", words[0])
}
}
2014-04-16 22:59:25 +00:00
func (c Session) Begin() {
_, err := c.conn.Write([]byte("220 Go-MailHog\n"))
if err != nil {
2014-04-18 17:25:36 +00:00
c.log("Failed writing to socket: %s\n", err)
2014-04-16 22:59:25 +00:00
return
}
2014-04-16 23:11:56 +00:00
c.Read()
2014-04-16 22:59:25 +00:00
}