MailHog/mailhog/smtp/server/session.go

112 lines
2.8 KiB
Go
Raw Normal View History

2014-11-22 19:15:50 +00:00
package server
// http://www.rfc-editor.org/rfc/rfc5321.txt
import (
"io"
"log"
"strings"
"github.com/ian-kent/Go-MailHog/mailhog/config"
"github.com/ian-kent/Go-MailHog/mailhog/data"
2014-11-22 19:15:50 +00:00
"github.com/ian-kent/Go-MailHog/mailhog/smtp/protocol"
)
// Session represents a SMTP session using net.TCPConn
type Session struct {
conn io.ReadWriteCloser
proto *protocol.Protocol
conf *config.Config
remoteAddress string
isTLS bool
line string
}
// Accept starts a new SMTP session using io.ReadWriteCloser
func Accept(remoteAddress string, conn io.ReadWriteCloser, conf *config.Config) {
2014-11-22 19:15:50 +00:00
proto := protocol.NewProtocol()
2014-11-23 00:42:15 +00:00
proto.Hostname = conf.Hostname
session := &Session{conn, proto, conf, remoteAddress, false, ""}
proto.LogHandler = session.logf
proto.MessageReceivedHandler = session.acceptMessage
2014-11-22 19:20:47 +00:00
proto.ValidateSenderHandler = session.validateSender
proto.ValidateRecipientHandler = session.validateRecipient
proto.ValidateAuthenticationHandler = session.validateAuthentication
session.logf("Starting session")
2014-11-23 00:42:15 +00:00
session.Write(proto.Start())
for session.Read() == true {
}
session.logf("Session ended")
}
func (c *Session) validateAuthentication(mechanism string, args ...string) (errorReply *protocol.Reply, ok bool) {
return nil, true
}
2014-11-22 19:20:47 +00:00
func (c *Session) validateRecipient(to string) bool {
return true
}
func (c *Session) validateSender(from string) bool {
return true
}
func (c *Session) acceptMessage(msg *data.Message) (id string, err error) {
c.logf("Storing message %s", msg.ID)
id, err = c.conf.Storage.Store(msg)
2014-11-22 18:45:14 +00:00
c.conf.MessageChan <- msg
return
}
func (c *Session) logf(message string, args ...interface{}) {
message = strings.Join([]string{"[SMTP %s]", message}, " ")
args = append([]interface{}{c.remoteAddress}, args...)
log.Printf(message, args...)
}
// Read reads from the underlying net.TCPConn
func (c *Session) Read() bool {
buf := make([]byte, 1024)
n, err := io.Reader(c.conn).Read(buf)
if n == 0 {
c.logf("Connection closed by remote host\n")
return false
}
if err != nil {
c.logf("Error reading from socket: %s\n", err)
return false
}
text := string(buf[0:n])
logText := strings.Replace(text, "\n", "\\n", -1)
logText = strings.Replace(logText, "\r", "\\r", -1)
c.logf("Received %d bytes: '%s'\n", n, logText)
c.line += text
line, reply := c.proto.Parse(c.line)
c.line = line
if reply != nil {
c.Write(reply)
2014-11-22 19:15:50 +00:00
if reply.Status == 221 {
io.Closer(c.conn).Close()
}
}
return true
}
// Write writes a reply to the underlying net.TCPConn
2014-11-22 19:15:50 +00:00
func (c *Session) Write(reply *protocol.Reply) {
lines := reply.Lines()
for _, l := range lines {
logText := strings.Replace(l, "\n", "\\n", -1)
logText = strings.Replace(logText, "\r", "\\r", -1)
c.logf("Sent %d bytes: '%s'", len(l), logText)
io.Writer(c.conn).Write([]byte(l))
}
}