From 298ccb9a95bca9af93eca335214ac4bf452af7c1 Mon Sep 17 00:00:00 2001
From: Runxi Yu <me@runxiyu.org>
Date: Thu, 16 Jan 2025 11:16:03 +0800
Subject: IMAP: Add CAPABILITY, and a stub for AUTHENTICATE

---
 serve_imap.go | 41 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 3 deletions(-)

diff --git a/serve_imap.go b/serve_imap.go
index 86a2db9..58da901 100644
--- a/serve_imap.go
+++ b/serve_imap.go
@@ -3,10 +3,12 @@ package main
 import (
 	"bufio"
 	"context"
-	"crypto/tls"
 	"fmt"
+	"crypto/tls"
+	"encoding/base64"
 	"io"
 	"net"
+	"strings"
 
 	"github.com/jackc/pgx/v5/pgxpool"
 	"go.lindenii.runxiyu.org/lindenii-common/clog"
@@ -20,9 +22,11 @@ type imap_recv_session struct {
 	db             *pgxpool.Pool
 }
 
+const IMAP_CAPABILITIES = "CAPABILITY IMAP4rev2 AUTH=PLAIN"
+
 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.WriteString("* OK [" + IMAP_CAPABILITIES + "] " + VERSION + "\r\n")
 	_ = session.buf_conn.Flush()
 
 	for {
@@ -39,7 +43,38 @@ func (session *imap_recv_session) handle(ctx context.Context) error {
 			_ = session.buf_conn.Flush()
 			continue
 		}
-		fmt.Printf("received tag=%s, cmd=%s, param=%s\n", tag, cmd, param)
+		fmt.Printf("tag=%#v, cmd=%#v, param=%#v\n", 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":
+			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
+				}
+				fmt.Printf("argumetn=%#v\n", string(argument))
+			default:
+				_, _ = session.buf_conn.WriteString(line + " TODO i don't know this authentication method\r\n")
+				_ = session.buf_conn.Flush()
+				break switch_cmd
+			}
+		}
 	}
 }
 
-- 
cgit v1.2.3