1package main23import (4 "crypto/sha256"5 "errors"6 "hash"7 "io"8 "os"9 "path/filepath"10 "strings"11)1213var chkSum hash.Hash = sha256.New()1415type Mail struct {16 maildir string // path to maildir17 directory string // new, cur, or tmp18 name string // basename of message19}2021func 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 }2728 return &Mail{29 maildir: maildir,30 directory: getDir(fp),31 name: filepath.Base(fp),32 }, nil33}3435func (m *Mail) String() string {36 return filepath.Join(filepath.Base(m.maildir), m.directory, m.name)37}3839func (m *Mail) Path() string {40 return filepath.Join(m.maildir, m.directory, m.name)41}4243func (m *Mail) Checksum() (string, error) {44 data, err := os.ReadFile(m.Path())45 if err != nil {46 return "", err47 }4849 return string(chkSum.Sum(data)), nil50}5152func (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.name56}5758// TODO: fsync59func (m *Mail) CopyTo(maildir string) error {60 file, err := os.Open(m.Path())61 if err != nil {62 return err63 }64 defer file.Close()6566 tmpFp := filepath.Join(maildir, "tmp", m.name)67 newFile, err := os.Create(tmpFp)68 if err != nil {69 return err70 }71 defer newFile.Close()7273 _, err = io.Copy(newFile, file)74 if err != nil {75 return err76 }7778 newFp := filepath.Join(maildir, m.directory, m.name)79 return os.Rename(tmpFp, newFp)80}