archive-mail

Maintains maildir archives synced with current maildirs

git clone https://git.8pit.net/archive-mail.git

 1package main
 2
 3import (
 4	"crypto/sha256"
 5	"errors"
 6	"hash"
 7	"io"
 8	"os"
 9	"path/filepath"
10	"strings"
11)
12
13var chkSum hash.Hash = sha256.New()
14
15type Mail struct {
16	maildir   string // path to maildir
17	directory string // new, cur, or tmp
18	name      string // basename of message
19}
20
21func NewMail(maildir string, fp string) (*Mail, error) {
22	cdir := filepath.Clean(maildir)
23	cmsg := filepath.Clean(fp)
24	if !strings.HasPrefix(cmsg, cdir) {
25		return nil, errors.New("mail is not in given maildir")
26	}
27
28	return &Mail{
29		maildir:   maildir,
30		directory: getDir(fp),
31		name:      filepath.Base(fp),
32	}, nil
33}
34
35func (m *Mail) String() string {
36	return filepath.Join(filepath.Base(m.maildir), m.directory, m.name)
37}
38
39func (m *Mail) Path() string {
40	return filepath.Join(m.maildir, m.directory, m.name)
41}
42
43func (m *Mail) Checksum() (string, error) {
44	data, err := os.ReadFile(m.Path())
45	if err != nil {
46		return "", err
47	}
48
49	return string(chkSum.Sum(data)), nil
50}
51
52func (m *Mail) IsSame(other *Mail) bool {
53	return filepath.Base(m.maildir) == filepath.Base(other.maildir) &&
54		m.directory == other.directory &&
55		m.name == other.name
56}
57
58// TODO: fsync
59func (m *Mail) CopyTo(maildir string) error {
60	file, err := os.Open(m.Path())
61	if err != nil {
62		return err
63	}
64	defer file.Close()
65
66	tmpFp := filepath.Join(maildir, "tmp", m.name)
67	newFile, err := os.Create(tmpFp)
68	if err != nil {
69		return err
70	}
71	defer newFile.Close()
72
73	_, err = io.Copy(newFile, file)
74	if err != nil {
75		return err
76	}
77
78	newFp := filepath.Join(maildir, m.directory, m.name)
79	return os.Rename(tmpFp, newFp)
80}