You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
2.4 KiB
130 lines
2.4 KiB
// Simple Mail Transfer Daemon
|
|
package smtpd
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"strings"
|
|
|
|
"git.watsonserve.com/maild/base"
|
|
)
|
|
|
|
|
|
// 接口集合
|
|
type SmtpServerConfigure interface {
|
|
GetConfig() *base.ServerConfig
|
|
Auth(username string, password string) string
|
|
TakeOff(email *base.Mail)
|
|
}
|
|
|
|
type smtpd_t struct {
|
|
config SmtpServerConfigure
|
|
dict map[string]func(*smtp_context_t)
|
|
}
|
|
|
|
func task(self *smtpd_t, conn net.Conn) {
|
|
defer conn.Close()
|
|
scanner := bufio.NewScanner(conn)
|
|
ctx := initSmtpContext(conn, self.config)
|
|
ctx.hola()
|
|
|
|
for scanner.Scan() {
|
|
err := scanner.Err()
|
|
if nil != err {
|
|
log.Println("Reading standard input: ", err)
|
|
break
|
|
}
|
|
// 行遍历
|
|
msg := scanner.Text()
|
|
ctx.Msg = msg
|
|
switch ctx.Module {
|
|
case mod_COMMAND:
|
|
err = commandHash(self, ctx)
|
|
if nil != err {
|
|
log.Println("Unknow Cmd: ", err)
|
|
}
|
|
case mod_HEAD:
|
|
dataHead(ctx)
|
|
case mod_BODY:
|
|
dataBody(ctx)
|
|
}
|
|
}
|
|
}
|
|
|
|
func commandHash(this *smtpd_t, ctx *smtp_context_t) error {
|
|
var key string
|
|
// 截取第一个单词
|
|
_, err := fmt.Sscanf(ctx.Msg, "%s", &key)
|
|
if nil != err {
|
|
return err
|
|
}
|
|
// 查找处理方法
|
|
method, exist := this.dict[key]
|
|
if !exist {
|
|
ctx.Send("method " + key + " not valid\r\n")
|
|
return errors.New("method " + key + " not valid")
|
|
}
|
|
// 执行处理
|
|
method(ctx)
|
|
return nil
|
|
}
|
|
|
|
func dataHead(ctx *smtp_context_t) {
|
|
if "" == ctx.Msg {
|
|
ctx.Module = mod_BODY
|
|
} else if ' ' == ctx.Msg[0] || '\t' == ctx.Msg[0] {
|
|
ctx.Email.Head[len(ctx.Email.Head)-1].Value += "\r\n" + ctx.Msg
|
|
} else {
|
|
attr := strings.Split(ctx.Msg, ": ")
|
|
ele := &base.KV{
|
|
Name: attr[0],
|
|
Value: attr[1],
|
|
}
|
|
ctx.Email.Head = append(ctx.Email.Head, *ele)
|
|
}
|
|
}
|
|
|
|
func dataBody(ctx *smtp_context_t) {
|
|
if "." == ctx.Msg {
|
|
ctx.Module = mod_COMMAND
|
|
ctx.Send("250 2.6.0 Message received\r\n")
|
|
ctx.takeOff()
|
|
return
|
|
}
|
|
ctx.Email.MailContent += ctx.Msg + "\r\n"
|
|
}
|
|
|
|
func Service(ln net.Listener, config SmtpServerConfigure) {
|
|
if nil == config {
|
|
return
|
|
}
|
|
that := &smtpd_t{
|
|
config: config,
|
|
dict: map[string]func(*smtp_context_t){
|
|
"HELO": helo,
|
|
"EHLO": ehlo,
|
|
"AUTH": auth,
|
|
"QUIT": quit,
|
|
"XCLIENT": xclient,
|
|
"STARTTLS": starttls,
|
|
"HELP": help,
|
|
"NOOP": noop,
|
|
"RSET": rset,
|
|
"MAIL": mail,
|
|
"RCPT": rcpt,
|
|
"DATA": data,
|
|
},
|
|
}
|
|
for {
|
|
conn, err := ln.Accept()
|
|
if nil != err {
|
|
log.Println("a connect exception")
|
|
continue
|
|
}
|
|
|
|
go task(that, conn)
|
|
}
|
|
}
|
|
|