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}