Blob


1 package mailmux
3 import (
4 "errors"
5 "fmt"
6 "io"
7 "net"
8 "os"
9 )
11 type Server struct {
12 ln net.Listener
13 Aliases AliasStore
14 Users UserStore
15 }
17 func (srv *Server) ListenAndServe() error {
18 if srv.ln == nil {
19 return errors.New("nil listener")
20 }
21 return srv.Serve(srv.ln)
22 }
24 func (srv *Server) Serve(ln net.Listener) error {
25 if ln == nil {
26 return errors.New("nil listener")
27 }
28 for {
29 conn, err := ln.Accept()
30 if err != nil {
31 return err
32 }
33 go func() {
34 if err := srv.handleConn(conn); err != nil {
35 fmt.Fprintln(os.Stderr, err)
36 }
37 conn.Close()
38 }()
39 }
40 return errors.New("unreachable?")
41 }
43 func (srv *Server) handleConn(conn net.Conn) error {
44 tmsg, err := ParseMcall(conn)
45 if err != nil {
46 err = fmt.Errorf("parse mcall: %w", err)
47 rerror(conn, err.Error())
48 return err
49 }
50 if tmsg.Type != Tauth {
51 rerror(conn, "unauthorised")
52 return nil
53 }
54 if err := srv.Users.Authenticate(tmsg.Username, Password(tmsg.Password)); err != nil {
55 rerror(conn, "authentication failed")
56 return err
57 }
58 rmsg := &Mcall{Type: Rauth, Username: tmsg.Username}
59 writeMcall(conn, rmsg)
61 user := tmsg.Username
62 for {
63 tmsg, err := ParseMcall(conn)
64 if errors.Is(err, io.EOF) {
65 return nil
66 } else if err != nil {
67 rerror(conn, err.Error())
68 continue
69 }
70 rmsg := &Mcall{}
71 switch tmsg.Type {
72 case Tauth:
73 rmsg = &Mcall{Type: Rerror, Error: "already authenticated"}
74 case Tlist:
75 rmsg = srv.listAliases(user)
76 case Tcreate:
77 rmsg = srv.createAlias(user)
78 default:
79 rmsg = &Mcall{Type: Rerror, Error: "this tmessage not implemented yet"}
80 }
81 writeMcall(conn, rmsg)
82 }
83 }
85 func (srv *Server) createAlias(username string) *Mcall {
86 alias, err := srv.Aliases.Create(username)
87 if err != nil {
88 return &Mcall{Type: Rerror, Error: err.Error()}
89 }
90 return &Mcall{Type: Rcreate, Aliases: []Alias{alias}}
91 }
93 func (srv *Server) listAliases(username string) *Mcall {
94 a, err := srv.Aliases.Aliases(username)
95 if err != nil {
96 return &Mcall{Type: Rerror, Error: fmt.Sprintf("aliases for %s: %v", username, err)}
97 }
98 return &Mcall{Type: Rlist, Aliases: a}
99 }