]>
src.bluestatic.org Git - mailpopbox.git/blob - pop3.go
2 // Copyright 2020 Blue Static <https://www.bluestatic.org>
3 // This program is free software licensed under the GNU General Public License,
4 // version 3.0. The full text of the license can be found in LICENSE.txt.
5 // SPDX-License-Identifier: GPL-3.0-only
21 "src.bluestatic.org/mailpopbox/pop3"
24 func runPOP3Server(config Config
, log
*zap
.Logger
) <-chan ServerControlMessage
{
27 controlChan
: make(chan ServerControlMessage
),
28 log
: log
.With(zap
.String("server", "pop3")),
31 return server
.controlChan
34 type pop3Server
struct {
36 controlChan
chan ServerControlMessage
40 func (server
*pop3Server
) run() {
41 for _
, s
:= range server
.config
.Servers
{
42 if err
:= os
.Mkdir(s
.MaildropPath
, 0700); err
!= nil && !os
.IsExist(err
) {
43 server
.log
.Error("failed to open maildrop", zap
.Error(err
))
44 server
.controlChan
<- ServerControlFatalError
48 l
, err
:= server
.newListener()
50 server
.controlChan
<- ServerControlFatalError
54 connChan
:= make(chan net
.Conn
)
55 go RunAcceptLoop(l
, connChan
, server
.log
)
57 reloadChan
:= CreateReloadSignal()
62 server
.log
.Info("restarting server")
64 server
.controlChan
<- ServerControlRestart
66 case conn
, ok
:= <-connChan
:
68 go pop3
.AcceptConnection(conn
, server
, server
.log
)
70 server
.controlChan
<- ServerControlFatalError
77 func (server
*pop3Server
) newListener() (net
.Listener
, error
) {
78 tlsConfig
, err
:= server
.config
.GetTLSConfig()
80 server
.log
.Error("failed to configure TLS", zap
.Error(err
))
84 addr
:= fmt
.Sprintf(":%d", server
.config
.POP3Port
)
85 server
.log
.Info("starting server", zap
.String("address", addr
))
89 l
, err
= net
.Listen("tcp", addr
)
91 l
, err
= tls
.Listen("tcp", addr
, tlsConfig
)
94 server
.log
.Error("listen", zap
.Error(err
))
101 func (server
*pop3Server
) Name() string {
102 return server
.config
.Hostname
105 func (server
*pop3Server
) OpenMailbox(user
, pass
string) (pop3
.Mailbox
, error
) {
106 for _
, s
:= range server
.config
.Servers
{
107 if user
== MailboxAccount
+s
.Domain
&& pass
== s
.MailboxPassword
{
108 return server
.openMailbox(s
.MaildropPath
)
111 return nil, errors
.New("permission denied")
114 func (server
*pop3Server
) openMailbox(maildrop
string) (*mailbox
, error
) {
115 files
, err
:= ioutil
.ReadDir(maildrop
)
117 server
.log
.Error("failed read maildrop dir", zap
.String("dir", maildrop
), zap
.Error(err
))
118 return nil, errors
.New("error opening maildrop")
122 messages
: make([]message
, 0, len(files
)),
126 for _
, file
:= range files
{
132 filename
: path
.Join(maildrop
, file
.Name()),
136 mb
.messages
= append(mb
.messages
, msg
)
143 type mailbox
struct {
147 type message
struct {
154 func (m message
) UniqueID() string {
156 return path
.Base(m
.filename
[:l
-len(".msg")])
159 func (m message
) ID() int {
163 func (m message
) Size() int {
167 func (m message
) Deleted() bool {
171 func (mb
*mailbox
) ListMessages() ([]pop3
.Message
, error
) {
172 msgs
:= make([]pop3
.Message
, len(mb
.messages
))
173 for i
:= 0; i
< len(mb
.messages
); i
++ {
174 msgs
[i
] = &mb
.messages
[i
]
179 func (mb
*mailbox
) GetMessage(id
int) pop3
.Message
{
180 if id
== 0 || id
> len(mb
.messages
) {
183 return &mb
.messages
[id
-1]
186 func (mb
*mailbox
) Retrieve(msg pop3
.Message
) (io
.ReadCloser
, error
) {
187 filename
:= msg
.(*message
).filename
188 return os
.Open(filename
)
191 func (mb
*mailbox
) Delete(msg pop3
.Message
) error
{
192 msg
.(*message
).deleted
= true
196 func (mb
*mailbox
) Close() error
{
197 for _
, message
:= range mb
.messages
{
199 os
.Remove(message
.filename
)
205 func (mb
*mailbox
) Reset() {
206 for i
, _
:= range mb
.messages
{
207 mb
.messages
[i
].deleted
= false