Implement the POP3 CAPA command from RFC 2449.
authorRobert Sesek <rsesek@bluestatic.org>
Mon, 2 Jan 2017 08:14:15 +0000 (03:14 -0500)
committerRobert Sesek <rsesek@bluestatic.org>
Mon, 2 Jan 2017 08:14:15 +0000 (03:14 -0500)
README.md
pop3/conn.go
pop3/conn_test.go

index e95722894ac0eb299a0550275a654c8f09611b64..827db6b445775e8b4a27d57701ec120212a17c6a 100644 (file)
--- 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)
index a15c1f657901be9656a6118a08b0566a04685902..0af572431cc2f1f4770ae971554571f9085770f2 100644 (file)
@@ -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
index 31baad9ebe6a4d8dd0f302d16ceb1c59db9d58f5..50115e7514a1db2997b4413594a5608bfe98d4d7 100644 (file)
@@ -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},
+       })
+}