github.com/segakazzz/buffalo@v0.16.22-0.20210119082501-1f52048d3feb/internal/fakesmtp/server.go (about)

     1  package fakesmtp
     2  
     3  // This server is inspired by https://github.com/andrewarrow/jungle_smtp
     4  // and most of its functionality have been taken from the original repo and updated to
     5  // work better for buffalo.
     6  
     7  import (
     8  	"bufio"
     9  	"net"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  )
    14  
    15  //Server is our fake server that will be listening for SMTP connections.
    16  type Server struct {
    17  	Listener net.Listener
    18  	messages []string
    19  	mutex    sync.Mutex
    20  }
    21  
    22  //Start listens for connections on the given port
    23  func (s *Server) Start(port string) error {
    24  	for {
    25  		conn, err := s.Listener.Accept()
    26  		if err != nil {
    27  			return err
    28  		}
    29  
    30  		s.Handle(&Connection{
    31  			conn:    conn,
    32  			address: conn.RemoteAddr().String(),
    33  			time:    time.Now().Unix(),
    34  			bufin:   bufio.NewReader(conn),
    35  			bufout:  bufio.NewWriter(conn),
    36  		})
    37  	}
    38  }
    39  
    40  //Handle a connection from a client
    41  func (s *Server) Handle(c *Connection) {
    42  	s.mutex.Lock()
    43  	defer s.mutex.Unlock()
    44  
    45  	s.messages = append(s.messages, "")
    46  
    47  	s.readHello(c)
    48  	s.readSender(c)
    49  	s.readRecipients(c)
    50  	s.readData(c)
    51  
    52  	c.conn.Close()
    53  }
    54  
    55  //Requests and notifies readed the Hello
    56  func (s *Server) readHello(c *Connection) {
    57  	c.write("220 Welcome")
    58  	text := c.read()
    59  	s.addMessageLine(text)
    60  
    61  	c.write("250 Received")
    62  }
    63  
    64  //readSender reads the Sender from the connection
    65  func (s *Server) readSender(c *Connection) {
    66  	text := c.read()
    67  	s.addMessageLine(text)
    68  	c.write("250 Sender")
    69  }
    70  
    71  //readRecipients reads recipients from the connection
    72  func (s *Server) readRecipients(c *Connection) {
    73  	text := c.read()
    74  	s.addMessageLine(text)
    75  
    76  	c.write("250 Recipient")
    77  	text = c.read()
    78  	for strings.Contains(text, "RCPT") {
    79  		s.addMessageLine(text)
    80  		c.write("250 Recipient")
    81  		text = c.read()
    82  	}
    83  }
    84  
    85  //readData reads the message data.
    86  func (s *Server) readData(c *Connection) {
    87  	c.write("354 Ok Send data ending with <CRLF>.<CRLF>")
    88  
    89  	for {
    90  		text := c.read()
    91  		bytes := []byte(text)
    92  		s.addMessageLine(text)
    93  		// 46 13 10
    94  		if bytes[0] == 46 && bytes[1] == 13 && bytes[2] == 10 {
    95  			break
    96  		}
    97  	}
    98  	c.write("250 server has transmitted the message")
    99  }
   100  
   101  //addMessageLine ads a line to the last message
   102  func (s *Server) addMessageLine(text string) {
   103  	s.messages[len(s.Messages())-1] = s.LastMessage() + text
   104  }
   105  
   106  //LastMessage returns the last message on the server
   107  func (s *Server) LastMessage() string {
   108  	if len(s.Messages()) == 0 {
   109  		return ""
   110  	}
   111  
   112  	return s.Messages()[len(s.Messages())-1]
   113  }
   114  
   115  //Messages returns the list of messages on the server
   116  func (s *Server) Messages() []string {
   117  	return s.messages
   118  }
   119  
   120  //Clear the server messages
   121  func (s *Server) Clear() {
   122  	s.mutex.Lock()
   123  	defer s.mutex.Unlock()
   124  
   125  	s.messages = []string{}
   126  }
   127  
   128  //New returns a pointer to a new Server instance listening on the given port.
   129  func New(port string) (*Server, error) {
   130  	s := &Server{messages: []string{}}
   131  
   132  	listener, err := net.Listen("tcp", "0.0.0.0:"+port)
   133  	if err != nil {
   134  		return s, err
   135  	}
   136  	s.Listener = listener
   137  	return s, nil
   138  }