From efa0d81ff6e07efab8f13465628edd7e1ab31bab Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Tue, 13 Dec 2016 00:59:58 -0500 Subject: [PATCH] Implement POP3 LIST, RETR, and DELE. --- pop3.go | 45 +++++++++++++++++++++++++++------ pop3/conn.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ pop3/server.go | 5 ++-- 3 files changed, 108 insertions(+), 9 deletions(-) diff --git a/pop3.go b/pop3.go index 84e075b..ad4d1a4 100644 --- a/pop3.go +++ b/pop3.go @@ -4,8 +4,10 @@ import ( "errors" "fmt" "io" + "io/ioutil" "net" "os" + "path" "src.bluestatic.org/mailpopbox/pop3" ) @@ -62,9 +64,31 @@ func (server *pop3Server) OpenMailbox(user, pass string) (pop3.Mailbox, error) { } func (server *pop3Server) openMailbox(maildrop string) (*mailbox, error) { + files, err := ioutil.ReadDir(maildrop) + if err != nil { + // TODO: hide error, log instead + return nil, err + } + mb := &mailbox{ - messages: make([]message, 0), + messages: make([]message, 0, len(files)), + } + + i := 0 + for _, file := range files { + if file.IsDir() { + continue + } + + msg := message{ + filename: path.Join(maildrop, file.Name()), + index: i, + size: file.Size(), + } + mb.messages = append(mb.messages, msg) + i++ } + return mb, nil } @@ -75,7 +99,7 @@ type mailbox struct { type message struct { filename string index int - size int + size int64 deleted bool } @@ -84,7 +108,11 @@ func (m message) ID() int { } func (m message) Size() int { - return m.size + return int(m.size) +} + +func (m message) Deleted() bool { + return m.deleted } func (mb *mailbox) ListMessages() ([]pop3.Message, error) { @@ -95,13 +123,16 @@ func (mb *mailbox) ListMessages() ([]pop3.Message, error) { return msgs, nil } -func (mb *mailbox) Retrieve(msg pop3.Message) (io.ReadCloser, error) { - filename := msg.(*message).filename +func (mb *mailbox) Retrieve(idx int) (io.ReadCloser, error) { + if idx > len(mb.messages) { + return nil, errors.New("no such message") + } + filename := mb.messages[idx-1].filename return os.Open(filename) } -func (mb *mailbox) Delete(msg pop3.Message) error { - message := msg.(*message) +func (mb *mailbox) Delete(idx int) error { + message := &mb.messages[idx-1] if message.deleted { return errors.New("already deleted") } diff --git a/pop3/conn.go b/pop3/conn.go index c909bae..5341bcb 100644 --- a/pop3/conn.go +++ b/pop3/conn.go @@ -2,6 +2,7 @@ package pop3 import ( "fmt" + "io" "net" "net/textproto" "strings" @@ -150,6 +151,24 @@ func (conn *connection) doSTAT() { conn.err(errStateTxn) return } + + msgs, err := conn.mb.ListMessages() + if err != nil { + conn.err(err.Error()) + return + } + + size := 0 + num := 0 + for _, msg := range msgs { + if msg.Deleted() { + continue + } + size += msg.Size() + num++ + } + + conn.ok(fmt.Sprintf("%d %d", num, size)) } func (conn *connection) doLIST() { @@ -157,6 +176,18 @@ func (conn *connection) doLIST() { conn.err(errStateTxn) return } + + msgs, err := conn.mb.ListMessages() + if err != nil { + conn.err(err.Error()) + return + } + + conn.ok("scan listing") + for _, msg := range msgs { + conn.tp.PrintfLine("%d %d", msg.ID(), msg.Size()) + } + conn.tp.PrintfLine(".") } func (conn *connection) doRETR() { @@ -164,6 +195,21 @@ func (conn *connection) doRETR() { conn.err(errStateTxn) return } + + idx, ok := conn.intParam() + if !ok { + return + } + + rc, err := conn.mb.Retrieve(idx) + if err != nil { + conn.err(err.Error()) + return + } + + w := conn.tp.DotWriter() + io.Copy(w, rc) + w.Close() } func (conn *connection) doDELE() { @@ -171,6 +217,17 @@ func (conn *connection) doDELE() { conn.err(errStateTxn) return } + + idx, ok := conn.intParam() + if !ok { + return + } + + if err := conn.mb.Delete(idx); err != nil { + conn.err(err.Error()) + } else { + conn.ok("") + } } func (conn *connection) doRSET() { @@ -181,3 +238,13 @@ func (conn *connection) doRSET() { conn.mb.Reset() conn.ok("") } + +func (conn *connection) intParam() (int, bool) { + var cmd string + var param int + if _, err := fmt.Sscanf(conn.line, "%s %d", &cmd, ¶m); err != nil { + conn.err(errSyntax) + return 0, false + } + return param, true +} diff --git a/pop3/server.go b/pop3/server.go index 1bce28f..f0377b5 100644 --- a/pop3/server.go +++ b/pop3/server.go @@ -7,12 +7,13 @@ import ( type Message interface { ID() int Size() int + Deleted() bool } type Mailbox interface { ListMessages() ([]Message, error) - Retrieve(Message) (io.ReadCloser, error) - Delete(Message) error + Retrieve(int) (io.ReadCloser, error) + Delete(int) error Close() error Reset() } -- 2.22.5