commit e9e55ec0fc4f4626523dc296d3ccec82a3cef5da from: Oliver Lowe date: Tue Jul 30 08:20:06 2024 UTC sieve: WIP new package.. just a command? commit - 63edc7a0589cf429104cdf23b74fb7f281501865 commit + e9e55ec0fc4f4626523dc296d3ccec82a3cef5da blob - /dev/null blob + 1bea1598d7abd918d1f17ff330fb03fe5695c3d6 (mode 644) --- /dev/null +++ src/sieve/sieve.go @@ -0,0 +1,97 @@ +// Package sieve provides a client of the ManageSieve protocol +// specified in RFC 5804. +package sieve + +import ( + "crypto/tls" + "errors" + "fmt" + "net/textproto" + "os" + "strings" +) + +const DefaultPort int = 4190 + +func Dial(net, addr string) (*textproto.Conn, error) { + conn, err := textproto.Dial(net, addr) + if err != nil { + return nil, err + } + for i := 0; i <= 10; i++ { + line, err := conn.ReadLine() + if err != nil { + return nil, err + } + fmt.Fprintln(os.Stderr, line) + if strings.HasPrefix(line, "OK") { + break + } + } + return conn, nil +} + +// Logout sends the LOGOUT command and closes conn. +// Implementations should not use conn afterwards. +func Logout(conn *textproto.Conn) error { + id, err := conn.Cmd("LOGOUT") + if err != nil { + return err + } + conn.StartResponse(id) + defer conn.EndResponse(id) + line, err := conn.ReadLine() + if err != nil { + return err + } + code, msg, found := strings.Cut(line, " ") + if code != "OK" { + if !found { + return fmt.Errorf("logout failed with no message") + } + return errors.New(msg) + } + return conn.Close() +} + +func Noop(conn *textproto.Conn) error { + id, err := conn.Cmd("NOOP") + if err != nil { + return err + } + conn.StartResponse(id) + defer conn.EndResponse(id) + line, err := conn.ReadLine() + if err != nil { + return err + } + code, msg, found := strings.Cut(line, " ") + if code != "OK" { + if !found { + return fmt.Errorf("noop failed with no message") + } + return errors.New(msg) + } + return nil +} + +func StartTLS(conn *textproto.Conn, config *tls.Config) error { + id, err := conn.Cmd("STARTTLS") + if err != nil { + return err + } + conn.StartResponse(id) + defer conn.EndResponse(id) + line, err := conn.ReadLine() + if err != nil { + return err + } + code, msg, found := strings.Cut(line, " ") + if code != "OK" { + if !found { + return fmt.Errorf("starttls failed with no message") + } + return errors.New(msg) + } + return errors.New("TODO not yet implemented") +} blob - /dev/null blob + 7d961d3003d0e78beedd166867bae90bce8ad938 (mode 644) --- /dev/null +++ src/sieve/sieve_test.go @@ -0,0 +1,15 @@ +package sieve + +import ( + "fmt" + "testing" +) + +func TestDial(t *testing.T) { + addr := fmt.Sprintf("imap.migadu.com:%d", DefaultPort) + conn, err := Dial("tcp", addr) + if err != nil { + t.Fatal(err) + } + conn.Close() +}