13 "src.bluestatic.org/mailpopbox/pop3"
16 func runPOP3Server(config Config) <-chan error {
25 type pop3Server struct {
30 func (server *pop3Server) run() {
31 for _, s := range server.config.Servers {
32 if err := os.Mkdir(s.MaildropPath, 0700); err != nil && !os.IsExist(err) {
37 tlsConfig, err := server.config.GetTLSConfig()
43 addr := fmt.Sprintf(":%d", server.config.POP3Port)
47 l, err = net.Listen("tcp", addr)
49 l, err = tls.Listen("tcp", addr, tlsConfig)
57 conn, err := l.Accept()
63 go pop3.AcceptConnection(conn, server)
67 func (server *pop3Server) Name() string {
68 return server.config.Hostname
71 func (server *pop3Server) OpenMailbox(user, pass string) (pop3.Mailbox, error) {
72 for _, s := range server.config.Servers {
73 if user == "mailbox@"+s.Domain && pass == s.MailboxPassword {
74 return server.openMailbox(s.MaildropPath)
77 return nil, errors.New("permission denied")
80 func (server *pop3Server) openMailbox(maildrop string) (*mailbox, error) {
81 files, err := ioutil.ReadDir(maildrop)
83 // TODO: hide error, log instead
88 messages: make([]message, 0, len(files)),
92 for _, file := range files {
98 filename: path.Join(maildrop, file.Name()),
102 mb.messages = append(mb.messages, msg)
109 type mailbox struct {
113 type message struct {
120 func (m message) ID() int {
124 func (m message) Size() int {
128 func (m message) Deleted() bool {
132 func (mb *mailbox) ListMessages() ([]pop3.Message, error) {
133 msgs := make([]pop3.Message, len(mb.messages))
134 for i := 0; i < len(mb.messages); i++ {
135 msgs[i] = &mb.messages[i]
140 func (mb *mailbox) GetMessage(id int) pop3.Message {
141 if id > len(mb.messages) {
144 return &mb.messages[id-1]
147 func (mb *mailbox) Retrieve(msg pop3.Message) (io.ReadCloser, error) {
148 filename := msg.(*message).filename
149 return os.Open(filename)
152 func (mb *mailbox) Delete(msg pop3.Message) error {
153 msg.(*message).deleted = true
157 func (mb *mailbox) Close() error {
158 for _, message := range mb.messages {
160 os.Remove(message.filename)
166 func (mb *mailbox) Reset() {
167 for _, message := range mb.messages {
168 message.deleted = false