x

Programs, configuration and documentation that don't fit anywhere else
Log | Files | Refs | README | LICENSE

commit e9e55ec0fc4f4626523dc296d3ccec82a3cef5da
parent 63edc7a0589cf429104cdf23b74fb7f281501865
Author: Oliver Lowe <o@olowe.co>
Date:   Tue, 30 Jul 2024 18:20:06 +1000

sieve: WIP new package.. just a command?

Diffstat:
Asrc/sieve/sieve.go | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sieve/sieve_test.go | 15+++++++++++++++
2 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/src/sieve/sieve.go b/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") +} diff --git a/src/sieve/sieve_test.go b/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() +}