mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +00:00
114 lines
2.4 KiB
Go
114 lines
2.4 KiB
Go
package inbucket
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"github.com/robfig/revel"
|
|
"os"
|
|
"path/filepath"
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
var ErrNotWritable = errors.New("MailObject not writable")
|
|
|
|
// Global because we only want one regardless of the number of DataStore objects
|
|
var countChannel = make(chan int, 10)
|
|
|
|
func init() {
|
|
// Start generator
|
|
go countGenerator(countChannel)
|
|
}
|
|
|
|
// Populates the channel with numbers
|
|
func countGenerator(c chan int) {
|
|
for i := 0; true; i = (i + 1) % 10000 {
|
|
c <- i
|
|
}
|
|
}
|
|
|
|
type DataStore struct {
|
|
path string
|
|
mailPath string
|
|
}
|
|
|
|
func NewDataStore() *DataStore {
|
|
path, found := rev.Config.String("datastore.path")
|
|
if found {
|
|
mailPath := filepath.Join(path, "mail")
|
|
return &DataStore{path: path, mailPath: mailPath}
|
|
}
|
|
rev.ERROR.Printf("No value configured for datastore.path")
|
|
return nil
|
|
}
|
|
|
|
type MailObject struct {
|
|
store *DataStore
|
|
mailbox string
|
|
rawPath string
|
|
gobPath string
|
|
writable bool
|
|
writerFile *os.File
|
|
writer *bufio.Writer
|
|
}
|
|
|
|
func (ds *DataStore) NewMailObject(emailAddress string) *MailObject {
|
|
mailbox := ParseMailboxName(emailAddress)
|
|
maildir := HashMailboxName(mailbox)
|
|
fileBase := time.Now().Format("20060102T150405") + "-" + fmt.Sprintf("%04d", <-countChannel)
|
|
boxPath := filepath.Join(ds.mailPath, maildir)
|
|
if err := os.MkdirAll(boxPath, 0770); err != nil {
|
|
rev.ERROR.Printf("Failed to create directory %v, %v", boxPath, err)
|
|
return nil
|
|
}
|
|
pathBase := filepath.Join(boxPath, fileBase)
|
|
|
|
return &MailObject{store: ds, mailbox: mailbox, rawPath: pathBase + ".raw",
|
|
gobPath: pathBase + ".gob", writable: true}
|
|
}
|
|
|
|
func (m *MailObject) Mailbox() string {
|
|
return m.mailbox
|
|
}
|
|
|
|
func (m *MailObject) Append(data []byte) error {
|
|
// Prevent Appending to a pre-existing MailObject
|
|
if !m.writable {
|
|
return ErrNotWritable
|
|
}
|
|
// Open file for writing if we haven't yet
|
|
if m.writer == nil {
|
|
file, err := os.Create(m.rawPath)
|
|
if err != nil {
|
|
// Set writable false just in case something calls me a million times
|
|
m.writable = false
|
|
return err
|
|
}
|
|
m.writerFile = file
|
|
m.writer = bufio.NewWriter(file)
|
|
}
|
|
_, err := m.writer.Write(data)
|
|
return err
|
|
}
|
|
|
|
func (m *MailObject) Close() error {
|
|
// nil out the fields so they can't be used
|
|
writer := m.writer
|
|
writerFile := m.writerFile
|
|
m.writer = nil
|
|
m.writerFile = nil
|
|
|
|
if (writer != nil) {
|
|
if err := writer.Flush(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if (writerFile != nil) {
|
|
if err := writerFile.Close(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|