aboutsummaryrefslogtreecommitdiff
path: root/serve_imap.go
diff options
context:
space:
mode:
Diffstat (limited to 'serve_imap.go')
-rw-r--r--serve_imap.go169
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")
- }
- }()
- }
-}