]>
src.bluestatic.org Git - mailpopbox.git/blob - pop3/conn.go
10 "github.com/uber-go/zap"
16 stateAuth state
= iota
22 errStateAuth
= "not in AUTHORIZATION"
23 errStateTxn
= "not in TRANSACTION"
24 errSyntax
= "syntax error"
25 errDeletedMsg
= "no such message - deleted"
28 type connection
struct {
43 func AcceptConnection(netConn net
.Conn
, po PostOffice
, log zap
.Logger
) {
46 tp
: textproto
.NewConn(netConn
),
48 log
: log
.With(zap
.Stringer("client", netConn
.RemoteAddr())),
52 conn
.ok(fmt
.Sprintf("POP3 (mailpopbox) server %s", po
.Name()))
55 conn
.line
, err
= conn
.tp
.ReadLine()
60 conn
.log
.Error("ReadLine()", zap
.Error(err
))
61 conn
.err("did't catch that")
66 if _
, err
:= fmt
.Sscanf(conn
.line
, "%s", &cmd
); err
!= nil {
67 conn
.err("invalid command")
71 switch strings
.ToUpper(cmd
) {
92 conn
.err("unknown command")
97 func (conn
*connection
) ok(msg
string) {
101 conn
.tp
.PrintfLine("+OK%s", msg
)
104 func (conn
*connection
) err(msg
string) {
107 conn
.tp
.PrintfLine("-ERR%s", msg
)
111 func (conn
*connection
) doQUIT() {
112 defer conn
.tp
.Close()
115 err
:= conn
.mb
.Close()
117 conn
.err("failed to remove some messages")
124 func (conn
*connection
) doUSER() {
125 if conn
.state
!= stateAuth
{
126 conn
.err(errStateAuth
)
130 conn
.user
= conn
.line
[len("USER "):]
134 func (conn
*connection
) doPASS() {
135 if conn
.state
!= stateAuth
{
136 conn
.err(errStateAuth
)
140 if len(conn
.user
) == 0 {
145 pass
:= conn
.line
[len("PASS "):]
146 if mbox
, err
:= conn
.po
.OpenMailbox(conn
.user
, pass
); err
== nil {
147 conn
.log
.Info("authenticated", zap
.String("user", conn
.user
))
148 conn
.state
= stateTxn
152 conn
.log
.Error("PASS", zap
.Error(err
))
153 conn
.err(err
.Error())
157 func (conn
*connection
) doSTAT() {
158 if conn
.state
!= stateTxn
{
159 conn
.err(errStateTxn
)
163 msgs
, err
:= conn
.mb
.ListMessages()
165 conn
.log
.Error("STAT", zap
.Error(err
))
166 conn
.err(err
.Error())
172 for _
, msg
:= range msgs
{
180 conn
.ok(fmt
.Sprintf("%d %d", num
, size
))
183 func (conn
*connection
) doLIST() {
184 if conn
.state
!= stateTxn
{
185 conn
.err(errStateTxn
)
189 msgs
, err
:= conn
.mb
.ListMessages()
191 conn
.log
.Error("LIST", zap
.Error(err
))
192 conn
.err(err
.Error())
196 conn
.ok("scan listing")
197 for _
, msg
:= range msgs
{
198 conn
.tp
.PrintfLine("%d %d", msg
.ID(), msg
.Size())
200 conn
.tp
.PrintfLine(".")
203 func (conn
*connection
) doRETR() {
204 if conn
.state
!= stateTxn
{
205 conn
.err(errStateTxn
)
209 msg
:= conn
.getRequestedMessage()
215 conn
.err(errDeletedMsg
)
219 rc
, err
:= conn
.mb
.Retrieve(msg
)
221 conn
.log
.Error("RETR", zap
.Error(err
))
222 conn
.err(err
.Error())
226 conn
.ok(fmt
.Sprintf("%d", msg
.Size()))
228 w
:= conn
.tp
.DotWriter()
233 func (conn
*connection
) doDELE() {
234 if conn
.state
!= stateTxn
{
235 conn
.err(errStateTxn
)
239 msg
:= conn
.getRequestedMessage()
245 conn
.err(errDeletedMsg
)
249 if err
:= conn
.mb
.Delete(msg
); err
!= nil {
250 conn
.log
.Error("DELE", zap
.Error(err
))
251 conn
.err(err
.Error())
257 func (conn
*connection
) doRSET() {
258 if conn
.state
!= stateTxn
{
259 conn
.err(errStateTxn
)
266 func (conn
*connection
) getRequestedMessage() Message
{
269 if _
, err
:= fmt
.Sscanf(conn
.line
, "%s %d", &cmd
, &idx
); err
!= nil {
275 conn
.err("invalid message-number")
279 msg
:= conn
.mb
.GetMessage(idx
)
281 conn
.err("no such message")