]>
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()
57 conn
.log
.Error("ReadLine()", zap
.Error(err
))
63 if _
, err
:= fmt
.Sscanf(conn
.line
, "%s", &cmd
); err
!= nil {
64 conn
.err("invalid command")
68 switch strings
.ToUpper(cmd
) {
89 conn
.err("unknown command")
94 func (conn
*connection
) ok(msg
string) {
98 conn
.tp
.PrintfLine("+OK%s", msg
)
101 func (conn
*connection
) err(msg
string) {
104 conn
.tp
.PrintfLine("-ERR%s", msg
)
108 func (conn
*connection
) doQUIT() {
109 defer conn
.tp
.Close()
112 err
:= conn
.mb
.Close()
114 conn
.err("failed to remove some messages")
121 func (conn
*connection
) doUSER() {
122 if conn
.state
!= stateAuth
{
123 conn
.err(errStateAuth
)
127 conn
.user
= conn
.line
[len("USER "):]
131 func (conn
*connection
) doPASS() {
132 if conn
.state
!= stateAuth
{
133 conn
.err(errStateAuth
)
137 if len(conn
.user
) == 0 {
142 pass
:= conn
.line
[len("PASS "):]
143 if mbox
, err
:= conn
.po
.OpenMailbox(conn
.user
, pass
); err
== nil {
144 conn
.log
.Info("authenticated", zap
.String("user", conn
.user
))
145 conn
.state
= stateTxn
149 conn
.log
.Error("PASS", zap
.Error(err
))
150 conn
.err(err
.Error())
154 func (conn
*connection
) doSTAT() {
155 if conn
.state
!= stateTxn
{
156 conn
.err(errStateTxn
)
160 msgs
, err
:= conn
.mb
.ListMessages()
162 conn
.log
.Error("STAT", zap
.Error(err
))
163 conn
.err(err
.Error())
169 for _
, msg
:= range msgs
{
177 conn
.ok(fmt
.Sprintf("%d %d", num
, size
))
180 func (conn
*connection
) doLIST() {
181 if conn
.state
!= stateTxn
{
182 conn
.err(errStateTxn
)
186 msgs
, err
:= conn
.mb
.ListMessages()
188 conn
.log
.Error("LIST", zap
.Error(err
))
189 conn
.err(err
.Error())
193 conn
.ok("scan listing")
194 for _
, msg
:= range msgs
{
195 conn
.tp
.PrintfLine("%d %d", msg
.ID(), msg
.Size())
197 conn
.tp
.PrintfLine(".")
200 func (conn
*connection
) doRETR() {
201 if conn
.state
!= stateTxn
{
202 conn
.err(errStateTxn
)
206 msg
:= conn
.getRequestedMessage()
212 conn
.err(errDeletedMsg
)
216 rc
, err
:= conn
.mb
.Retrieve(msg
)
218 conn
.log
.Error("RETR", zap
.Error(err
))
219 conn
.err(err
.Error())
223 conn
.ok(fmt
.Sprintf("%d", msg
.Size()))
225 w
:= conn
.tp
.DotWriter()
230 func (conn
*connection
) doDELE() {
231 if conn
.state
!= stateTxn
{
232 conn
.err(errStateTxn
)
236 msg
:= conn
.getRequestedMessage()
242 conn
.err(errDeletedMsg
)
246 if err
:= conn
.mb
.Delete(msg
); err
!= nil {
247 conn
.log
.Error("DELE", zap
.Error(err
))
248 conn
.err(err
.Error())
254 func (conn
*connection
) doRSET() {
255 if conn
.state
!= stateTxn
{
256 conn
.err(errStateTxn
)
263 func (conn
*connection
) getRequestedMessage() Message
{
266 if _
, err
:= fmt
.Sscanf(conn
.line
, "%s %d", &cmd
, &idx
); err
!= nil {
272 conn
.err("invalid message-number")
276 msg
:= conn
.mb
.GetMessage(idx
)
278 conn
.err("no such message")