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 }