From c63ff23771a50b160ca119372f1f9accf89c5942 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Thu, 16 Jan 2025 16:31:47 +0800 Subject: Remove IMAP again for now --- README.md | 3 +- common_imap.go | 31 ----------- config.go | 5 -- main.go | 1 - serve_imap.go | 169 --------------------------------------------------------- 5 files changed, 2 insertions(+), 207 deletions(-) delete mode 100644 common_imap.go delete mode 100644 serve_imap.go diff --git a/README.md b/README.md index 8dcc94a..01525fc 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,10 @@ set up correctly. IMO it'd be easier to integrate it into the SMTP daemon. - ESMTP: [8BITMIME](https://www.rfc-editor.org/rfc/rfc6152.html), [SIZE](https://www.rfc-editor.org/rfc/rfc1870.html), [DSN](https://www.rfc-editor.org/rfc/rfc3464.html) -- Receiving mail, IMAP side, with TLS - DKIM, DMARC, SPF, [ARC](https://www.rfc-editor.org/rfc/rfc8617.html) +- Receiving mail and mailbox synchronization via a custom protocol - Sending mail, outgoing side, with STARTTLS - Sending mail, incoming side, with TLS - A UNIX domain socket protocol for integration with mailing list and forge software (might be called the Lindenii Mail Delivery Protocol) +- Receiving mail, IMAP side, with TLS (far future) diff --git a/common_imap.go b/common_imap.go deleted file mode 100644 index 3d79124..0000000 --- a/common_imap.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "errors" - "strings" -) - -var err_imap_generic = errors.New("Error in IMAP command received by server.") - -func parse_imap_line(line string) (tag, cmd, param string, err error) { - line = strings.TrimSuffix(line, "\n") - line = strings.TrimSuffix(line, "\r") - tag_end := strings.IndexByte(line, ' ') - if tag_end == -1 { - err = err_imap_generic - return - } - tag = line[:tag_end] - rest := line[tag_end+1:] - cmd_end := strings.IndexByte(rest, ' ') - var param_start int - if cmd_end == -1 { - cmd_end = len(rest) - param_start = len(rest) - } else { - param_start = cmd_end + 1 - } - cmd = strings.ToUpper(rest[:cmd_end]) - param = rest[param_start:] - return -} diff --git a/config.go b/config.go index b805dbc..e7d6aa4 100644 --- a/config.go +++ b/config.go @@ -25,11 +25,6 @@ var config struct { Net string `scfg:"net"` Addr string `scfg:"addr"` } `scfg:"mx"` - IMAP struct { - Net string `scfg:"net"` - Addr string `scfg:"addr"` - Trans string `scfg:"trans"` - } `scfg:"imap"` _tls_config *tls.Config } var ( diff --git a/main.go b/main.go index 60082da..51540f9 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,6 @@ func main() { } go serve_mx() - go serve_imap() deadlock := make(chan struct{}) deadlock <- struct{}{} 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") - } - }() - } -} -- cgit v1.2.3