From bb427850af72b481a467df7de0bfa095735397b6 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Mon, 2 Jan 2017 03:14:15 -0500 Subject: [PATCH] Implement the POP3 CAPA command from RFC 2449. --- README.md | 1 + pop3/conn.go | 15 +++++++++++++ pop3/conn_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/README.md b/README.md index e957228..827db6b 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,4 @@ This server implements the following RFCs: - [Post Office Protocol - Version 3, RFC 1939](https://tools.ietf.org/html/rfc1939) - [Simple Mail Transfer Protocol, RFC 5321](https://tools.ietf.org/html/rfc5321) - [SMTP Service Extension for Secure SMTP over Transport Layer Security, RFC 3207](https://tools.ietf.org/html/rfc3207) +- [POP3 Extension Mechanism, RFC 2449](https://tools.ietf.org/html/rfc2449) diff --git a/pop3/conn.go b/pop3/conn.go index a15c1f6..0af5724 100644 --- a/pop3/conn.go +++ b/pop3/conn.go @@ -92,6 +92,8 @@ func AcceptConnection(netConn net.Conn, po PostOffice, log zap.Logger) { conn.doRSET() case "UIDL": conn.doUIDL() + case "CAPA": + conn.doCAPA() default: conn.err("unknown command") } @@ -306,6 +308,19 @@ func (conn *connection) doUIDL() { conn.tp.PrintfLine(".") } +func (conn *connection) doCAPA() { + conn.ok("capabilitiy list") + + caps := []string{ + "USER", + "UIDL", + ".", + } + for _, c := range caps { + conn.tp.PrintfLine(c) + } +} + func (conn *connection) getRequestedMessage() Message { var cmd string var idx int diff --git a/pop3/conn_test.go b/pop3/conn_test.go index 31baad9..50115e7 100644 --- a/pop3/conn_test.go +++ b/pop3/conn_test.go @@ -425,3 +425,57 @@ func TestDele(t *testing.T) { t.Errorf("DELE the wrong message") } } + +func TestCapa(t *testing.T) { + s := newTestServer() + + capaTest := func(t testing.TB, tp *textproto.Conn) string { + responseOK(t, tp) + if t.Failed() { + return "" + } + + resp, err := tp.ReadDotLines() + if err != nil { + t.Error(err) + return "" + } + + const ( + capNeeded = iota + capSeen + capOK + ) + + caps := map[string]int{ + "USER": capNeeded, + "UIDL": capNeeded, + } + for _, line := range resp { + if val, ok := caps[line]; ok { + if val == capNeeded { + caps[line] = capOK + } else { + t.Errorf("unxpected capa value %q", line) + } + } else { + caps[line] = capSeen + } + } + for c, val := range caps { + if val != capOK { + t.Errorf("unexpected capa value for %q: %d", c, val) + } + } + return "" + } + + clientServerTest(t, s, []requestResponse{ + {"CAPA", capaTest}, + {"USER u", responseOK}, + {"CAPA", capaTest}, + {"PASS p", responseOK}, + {"CAPA", capaTest}, + {"QUIT", responseOK}, + }) +} -- 2.22.5