package main import ( "bufio" "context" "crypto/tls" "fmt" "io" "net" "github.com/jackc/pgx/v5/pgxpool" "go.lindenii.runxiyu.org/lindenii-common/clog" ) type imap_recv_session struct { buf_conn *bufio.ReadWriter net_conn net.Conn tls_conn *tls.Conn my_server_name string db *pgxpool.Pool } func (session *imap_recv_session) handle(ctx context.Context) error { session.buf_conn = bufio.NewReadWriter(bufio.NewReader(session.net_conn), bufio.NewWriter(session.net_conn)) _, _ = session.buf_conn.WriteString("* OK [CAPABILITY IMAP4rev2 AUTH=PLAIN] " + 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 } fmt.Printf("received tag=%s, cmd=%s, param=%s\n", tag, cmd, param) } } 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 string config_consistent_run(func() { imap_net = config.IMAP.Net imap_addr = config.IMAP.Addr }) listener, err := net.Listen(imap_net, imap_addr) 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") } }() } }