Initial POP3 server.
[mailpopbox.git] / pop3.go
1 package main
2
3 import (
4 "errors"
5 "fmt"
6 "io"
7 "net"
8 "os"
9
10 "src.bluestatic.org/mailpopbox/pop3"
11 )
12
13 func runPOP3Server(config Config) <-chan error {
14 server := pop3Server{
15 config: config,
16 rc: make(chan error),
17 }
18 go server.run()
19 return server.rc
20 }
21
22 type pop3Server struct {
23 config Config
24 rc chan error
25 }
26
27 func (server *pop3Server) run() {
28 for _, s := range server.config.Servers {
29 if err := os.Mkdir(s.MaildropPath, 0700); err != nil && !os.IsExist(err) {
30 server.rc <- err
31 }
32 }
33
34 l, err := net.Listen("tcp", fmt.Sprintf(":%d", server.config.POP3Port))
35 if err != nil {
36 server.rc <- err
37 return
38 }
39
40 for {
41 conn, err := l.Accept()
42 if err != nil {
43 server.rc <- err
44 break
45 }
46
47 go pop3.AcceptConnection(conn, server)
48 }
49 }
50
51 func (server *pop3Server) Name() string {
52 return server.config.Hostname
53 }
54
55 func (server *pop3Server) OpenMailbox(user, pass string) (pop3.Mailbox, error) {
56 for _, s := range server.config.Servers {
57 if user == "mailbox@"+s.Domain && pass == s.MailboxPassword {
58 return server.openMailbox(s.MaildropPath)
59 }
60 }
61 return nil, errors.New("permission denied")
62 }
63
64 func (server *pop3Server) openMailbox(maildrop string) (*mailbox, error) {
65 mb := &mailbox{
66 messages: make([]message, 0),
67 }
68 return mb, nil
69 }
70
71 type mailbox struct {
72 messages []message
73 }
74
75 type message struct {
76 filename string
77 index int
78 size int
79 deleted bool
80 }
81
82 func (m message) ID() int {
83 return m.index + 1
84 }
85
86 func (m message) Size() int {
87 return m.size
88 }
89
90 func (mb *mailbox) ListMessages() ([]pop3.Message, error) {
91 msgs := make([]pop3.Message, len(mb.messages))
92 for i := 0; i < len(mb.messages); i++ {
93 msgs[i] = &mb.messages[i]
94 }
95 return msgs, nil
96 }
97
98 func (mb *mailbox) Retrieve(msg pop3.Message) (io.ReadCloser, error) {
99 filename := msg.(*message).filename
100 return os.Open(filename)
101 }
102
103 func (mb *mailbox) Delete(msg pop3.Message) error {
104 message := msg.(*message)
105 if message.deleted {
106 return errors.New("already deleted")
107 }
108 message.deleted = true
109 return nil
110 }
111
112 func (mb *mailbox) Close() error {
113 for _, message := range mb.messages {
114 if message.deleted {
115 os.Remove(message.filename)
116 }
117 }
118 return nil
119 }
120
121 func (mb *mailbox) Reset() {
122 for _, message := range mb.messages {
123 message.deleted = false
124 }
125 }