Initial commit
This commit is contained in:
187
vendor/github.com/emersion/go-smtp/server.go
generated
vendored
Executable file
187
vendor/github.com/emersion/go-smtp/server.go
generated
vendored
Executable file
@@ -0,0 +1,187 @@
|
||||
package smtp
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/emersion/go-sasl"
|
||||
)
|
||||
|
||||
// A function that creates SASL servers.
|
||||
type SaslServerFactory func(conn *Conn) sasl.Server
|
||||
|
||||
// A SMTP server.
|
||||
type Server struct {
|
||||
// TCP address to listen on.
|
||||
Addr string
|
||||
// The server TLS configuration.
|
||||
TLSConfig *tls.Config
|
||||
|
||||
Domain string
|
||||
MaxRecipients int
|
||||
MaxIdleSeconds int
|
||||
MaxMessageBytes int
|
||||
AllowInsecureAuth bool
|
||||
Debug io.Writer
|
||||
|
||||
// The server backend.
|
||||
Backend Backend
|
||||
|
||||
listener net.Listener
|
||||
caps []string
|
||||
auths map[string]SaslServerFactory
|
||||
|
||||
locker sync.Mutex
|
||||
conns map[*Conn]struct{}
|
||||
}
|
||||
|
||||
// New creates a new SMTP server.
|
||||
func NewServer(be Backend) *Server {
|
||||
return &Server{
|
||||
Backend: be,
|
||||
caps: []string{"PIPELINING", "8BITMIME"},
|
||||
auths: map[string]SaslServerFactory{
|
||||
sasl.Plain: func(conn *Conn) sasl.Server {
|
||||
return sasl.NewPlainServer(func(identity, username, password string) error {
|
||||
if identity != "" && identity != username {
|
||||
return errors.New("Identities not supported")
|
||||
}
|
||||
|
||||
user, err := be.Login(username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn.SetUser(user)
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
conns: make(map[*Conn]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Serve accepts incoming connections on the Listener l.
|
||||
func (s *Server) Serve(l net.Listener) error {
|
||||
s.listener = l
|
||||
defer s.Close()
|
||||
|
||||
for {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go s.handleConn(newConn(c, s))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleConn(c *Conn) error {
|
||||
s.locker.Lock()
|
||||
s.conns[c] = struct{}{}
|
||||
s.locker.Unlock()
|
||||
|
||||
defer func() {
|
||||
c.Close()
|
||||
|
||||
s.locker.Lock()
|
||||
delete(s.conns, c)
|
||||
s.locker.Unlock()
|
||||
}()
|
||||
|
||||
c.greet()
|
||||
|
||||
for {
|
||||
line, err := c.ReadLine()
|
||||
if err == nil {
|
||||
cmd, arg, err := parseCmd(line)
|
||||
if err != nil {
|
||||
c.nbrErrors++
|
||||
c.WriteResponse(501, "Bad command")
|
||||
continue
|
||||
}
|
||||
|
||||
c.handle(cmd, arg)
|
||||
} else {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
|
||||
c.WriteResponse(221, "Idle timeout, bye bye")
|
||||
return nil
|
||||
}
|
||||
|
||||
c.WriteResponse(221, "Connection error, sorry")
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ListenAndServe listens on the TCP network address s.Addr and then calls Serve
|
||||
// to handle requests on incoming connections.
|
||||
//
|
||||
// If s.Addr is blank, ":smtp" is used.
|
||||
func (s *Server) ListenAndServe() error {
|
||||
addr := s.Addr
|
||||
if addr == "" {
|
||||
addr = ":smtp"
|
||||
}
|
||||
|
||||
l, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Serve(l)
|
||||
}
|
||||
|
||||
// ListenAndServeTLS listens on the TCP network address s.Addr and then calls
|
||||
// Serve to handle requests on incoming TLS connections.
|
||||
//
|
||||
// If s.Addr is blank, ":smtps" is used.
|
||||
func (s *Server) ListenAndServeTLS() error {
|
||||
addr := s.Addr
|
||||
if addr == "" {
|
||||
addr = ":smtps"
|
||||
}
|
||||
|
||||
l, err := tls.Listen("tcp", addr, s.TLSConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Serve(l)
|
||||
}
|
||||
|
||||
// Close stops the server.
|
||||
func (s *Server) Close() {
|
||||
s.listener.Close()
|
||||
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
|
||||
for conn := range s.conns {
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAuth enables an authentication mechanism on this server.
|
||||
//
|
||||
// This function should not be called directly, it must only be used by
|
||||
// libraries implementing extensions of the SMTP protocol.
|
||||
func (s *Server) EnableAuth(name string, f SaslServerFactory) {
|
||||
s.auths[name] = f
|
||||
}
|
||||
|
||||
// ForEachConn iterates through all opened connections.
|
||||
func (s *Server) ForEachConn(f func(*Conn)) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
for conn := range s.conns {
|
||||
f(conn)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user