]>
src.bluestatic.org Git - mailpopbox.git/blob - smtp/conn.go
14 stateNew state
= iota // Before EHLO.
21 type connection
struct {
31 mailFrom
*mail
.Address
35 func AcceptConnection(netConn net
.Conn
, server Server
) error
{
38 tp
: textproto
.NewConn(netConn
),
39 remoteAddr
: netConn
.RemoteAddr(),
45 conn
.writeReply(220, fmt
.Sprintf("%s ESMTP [%s] (mailpopbox)", server
.Name(), netConn
.LocalAddr()))
48 conn
.line
, err
= conn
.tp
.ReadLine()
50 conn
.writeReply(500, "line too long")
55 if _
, err
= fmt
.Sscanf(conn
.line
, "%s", &cmd
); err
!= nil {
56 conn
.reply(ReplyBadSyntax
)
60 switch strings
.ToUpper(cmd
) {
62 conn
.writeReply(221, "Goodbye")
78 conn
.writeReply(252, "I'll do my best")
80 conn
.writeReply(550, "access denied")
84 conn
.writeReply(250, "https://tools.ietf.org/html/rfc5321")
86 conn
.writeReply(500, "unrecognized command")
93 func (conn
*connection
) reply(reply ReplyLine
) {
94 conn
.writeReply(reply
.Code
, reply
.Message
)
97 func (conn
*connection
) writeReply(code
int, msg
string) {
99 conn
.tp
.PrintfLine("%d %s", code
, msg
)
101 conn
.tp
.PrintfLine("%d", code
)
105 // parsePath parses out either a forward-, reverse-, or return-path from the
106 // current connection line. Returns a (valid-path, ReplyOK) if it was
107 // successfully parsed.
108 func (conn
*connection
) parsePath(command
string) (string, ReplyLine
) {
109 if len(conn
.line
) < len(command
) {
110 return "", ReplyBadSyntax
112 if strings
.ToUpper(command
) != strings
.ToUpper(conn
.line
[:len(command
)]) {
113 return "", ReplyLine
{500, "unrecognized command"}
115 return conn
.line
[len(command
):], ReplyOK
118 func (conn
*connection
) doEHLO() {
122 _
, err
:= fmt
.Sscanf(conn
.line
, "%s %s", &cmd
, &conn
.ehlo
)
124 conn
.reply(ReplyBadSyntax
)
129 conn
.writeReply(250, fmt
.Sprintf("Hello %s [%s]", conn
.ehlo
, conn
.remoteAddr
))
131 conn
.tp
.PrintfLine("250-Hello %s [%s]", conn
.ehlo
, conn
.remoteAddr
)
132 if conn
.server
.TLSConfig() != nil {
133 conn
.tp
.PrintfLine("250-STARTTLS")
135 conn
.tp
.PrintfLine("250 SIZE %d", 40960000)
138 conn
.state
= stateInitial
141 func (conn
*connection
) doMAIL() {
142 if conn
.state
!= stateInitial
{
143 conn
.reply(ReplyBadSequence
)
147 mailFrom
, reply
:= conn
.parsePath("MAIL FROM:")
148 if reply
!= ReplyOK
{
154 conn
.mailFrom
, err
= mail
.ParseAddress(mailFrom
)
156 conn
.reply(ReplyBadSyntax
)
160 conn
.state
= stateMail
164 func (conn
*connection
) doRCPT() {
165 if conn
.state
!= stateMail
&& conn
.state
!= stateRecipient
{
166 conn
.reply(ReplyBadSequence
)
170 rcptTo
, reply
:= conn
.parsePath("RCPT TO:")
171 if reply
!= ReplyOK
{
176 address
, err
:= mail
.ParseAddress(rcptTo
)
178 conn
.reply(ReplyBadSyntax
)
181 if reply
:= conn
.server
.VerifyAddress(*address
); reply
!= ReplyOK
{
186 conn
.rcptTo
= append(conn
.rcptTo
, *address
)
188 conn
.state
= stateRecipient
192 func (conn
*connection
) doDATA() {
193 if conn
.state
!= stateRecipient
{
194 conn
.reply(ReplyBadSequence
)
198 conn
.writeReply(354, "Start mail input; end with <CRLF>.<CRLF>")
200 data
, err
:= conn
.tp
.ReadDotBytes()
203 conn
.writeReply(552, "transaction failed")
208 RemoteAddr
: conn
.remoteAddr
,
210 MailFrom
: *conn
.mailFrom
,
215 if reply
:= conn
.server
.OnMessageDelivered(env
); reply
!= nil {
220 conn
.state
= stateInitial
224 func (conn
*connection
) doRSET() {
225 conn
.state
= stateInitial
230 func (conn
*connection
) resetBuffers() {
232 conn
.rcptTo
= make([]mail
.Address
, 0)