diff options
Diffstat (limited to 'serve_imap.go')
-rw-r--r-- | serve_imap.go | 169 |
1 files changed, 0 insertions, 169 deletions
diff --git a/serve_imap.go b/serve_imap.go deleted file mode 100644 index ad50c27..0000000 --- a/serve_imap.go +++ /dev/null @@ -1,169 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "context" - "crypto/tls" - "encoding/base64" - "fmt" - "io" - "net" - "strings" - - "github.com/jackc/pgx/v5/pgxpool" - "go.lindenii.runxiyu.org/lindenii-common/clog" -) - -type imap_server_state_t uint - -const ( - imap_server_state_not_authenticated imap_server_state_t = iota - imap_server_state_authenticated - imap_server_state_selected - imap_server_state_logout -) - -type imap_recv_session struct { - buf_conn *bufio.ReadWriter - net_conn net.Conn - tls_conn *tls.Conn - my_server_name string - db *pgxpool.Pool - server_state imap_server_state_t -} - -const IMAP_CAPABILITIES = "CAPABILITY IMAP4rev2 AUTH=PLAIN" - -func (session *imap_recv_session) handle(ctx context.Context) error { - session.server_state = imap_server_state_not_authenticated - session.buf_conn = bufio.NewReadWriter(bufio.NewReader(session.net_conn), bufio.NewWriter(session.net_conn)) - _, _ = session.buf_conn.WriteString("* OK [" + IMAP_CAPABILITIES + "] " + VERSION + "\r\n") - _ = session.buf_conn.Flush() - - for { - line, err := session.buf_conn.ReadString('\n') - if err != nil { - if err == io.EOF { - return err_connection_handler_eof - } - return err - } - tag, cmd, param, err := parse_imap_line(line) - if err != nil { - _, _ = session.buf_conn.WriteString(line + " BAD " + err.Error() + "\r\n") - _ = session.buf_conn.Flush() - continue - } - clog.Debug(fmt.Sprintf("tag=%#v, cmd=%#v, param=%#v", tag, cmd, param)) - switch_cmd: - switch cmd { - case "CAPABILITY": - _, _ = session.buf_conn.WriteString("* CAPABILITY " + IMAP_CAPABILITIES + "\r\n") - _, _ = session.buf_conn.WriteString(tag + " OK CAPABILITY completed\r\n") - _ = session.buf_conn.Flush() - case "AUTHENTICATE": - if session.server_state != imap_server_state_authenticated { - _, _ = session.buf_conn.WriteString(line + " TODO you are already authenticated") - _ = session.buf_conn.Flush() - break switch_cmd - } - space_that_ends_the_method := strings.IndexByte(param, ' ') - method := param[:space_that_ends_the_method] - switch method { - case "PLAIN": - argument_base64 := param[space_that_ends_the_method+1:] - if strings.IndexByte(argument_base64, ' ') != -1 { - _, _ = session.buf_conn.WriteString(tag + " TODO too many parameters\r\n") - _ = session.buf_conn.Flush() - break switch_cmd - } - argument := make([]byte, base64.StdEncoding.DecodedLen(len(argument_base64))) - _, err := base64.StdEncoding.Decode(argument, []byte(argument_base64)) - if err != nil { - _, _ = session.buf_conn.WriteString(tag + " TODO cannot decode base64\r\n") - _ = session.buf_conn.Flush() - break switch_cmd - } - segments := bytes.Split(argument, []byte{0}) - if len(segments) != 3 { - session.buf_conn.WriteString(" TODO need three sasl segments\r\n") - break switch_cmd - } - authcid, passwd := string(segments[1]), string(segments[2]) - if authcid == "test" && passwd == "test" { // TODO - session.server_state = imap_server_state_authenticated - } else { - - } - default: - _, _ = session.buf_conn.WriteString(line + " TODO i don't know this authentication method\r\n") - _ = session.buf_conn.Flush() - break switch_cmd - } - } - } -} - -func imap_new_session(ctx context.Context, net_conn net.Conn) error { - session := imap_recv_session{ - net_conn: net_conn, - } - return session.handle(ctx) -} - -func serve_imap() { - var imap_net, imap_addr, imap_trans string - var tls_config *tls.Config - config_consistent_run(func() { - imap_net = config.IMAP.Net - imap_addr = config.IMAP.Addr - imap_trans = config.IMAP.Trans - tls_config = config._tls_config - }) - var listener net.Listener - var err error - switch imap_trans { - case "tls", "": - listener, err = tls.Listen(imap_net, imap_addr, tls_config) - if err != nil { - clog.Fatal(1, "IMAP: Cannot listen TLS: "+err.Error()) - } - case "plain": - listener, err = net.Listen(imap_net, imap_addr) - if err != nil { - clog.Fatal(1, "IMAP: Cannot listen plain: "+err.Error()) - } - default: - clog.Fatal(1, fmt.Sprintf("IMAP: Listen transport %#v is invalid", imap_trans)) - } - - if err != nil { - clog.Fatal(1, "IMAP: Cannot listen: "+err.Error()) - } - defer listener.Close() - clog.Info("IMAP: Listening via " + imap_net + " on " + imap_addr) - - for { - conn, err := listener.Accept() - if err != nil { - clog.Error("IMAP: Cannot accept connection: " + err.Error()) - } - clog.Info("IMAP: Accepted connection from " + conn.RemoteAddr().String()) - - go func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - err := imap_new_session(ctx, conn) - if err != nil { - if err == err_connection_handler_eof { - clog.Info("IMAP: Connection for " + conn.RemoteAddr().String() + " closed with EOF") - } else { - clog.Error("IMAP: Connection handler for " + conn.RemoteAddr().String() + " returned error: " + err.Error()) - } - } else { - clog.Info("IMAP: Connection for " + conn.RemoteAddr().String() + " closed gracefully") - } - }() - } -} |