diff --git a/cmd/mailhash/mailhash.go b/cmd/mailhash/mailhash.go index cf5c17c..a600f65 100644 --- a/cmd/mailhash/mailhash.go +++ b/cmd/mailhash/mailhash.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "xinu.tv/email" @@ -13,10 +14,12 @@ import ( ) var ( - dryrun = flag.Bool("dryrun", true, "don't actually rename files, just log actions.") - saveFile = flag.String("save", "", "filename to store unread status.") - loadFile = flag.String("load", "", "filename to load unread status.") - maildir = flag.String("maildir", "", "Maildir root") + dryrun = flag.Bool("dryrun", true, "don't actually rename files, just log actions.") + saveFile = flag.String("save", "", "filename to store unread status.") + loadFile = flag.String("load", "", "filename to load unread status.") + maildir = flag.String("maildir", "", "Maildir root") + skipFiles = flag.String("skip", "maildirfolder,log,msgid.cache,razor-agent.log", + "comma separated files to skip") ) type Status struct { @@ -25,7 +28,12 @@ type Status struct { Read bool `json:"read,omitempty"` } -type Messages []Status +type Messages struct { + // Filenames to skip when hash mail. + Skip map[string]struct{} + // Read mail status. + Statuses []Status +} var headers = []string{"to", "from", "cc", "date", "subject"} @@ -38,17 +46,19 @@ func (m *Messages) hashMail(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } + r, err := os.Open(path) if err != nil { glog.Fatal(err) } h, err := email.Hash(r, headers) if err != nil { - glog.Errorf("%s %q", path, err.Error()) + glog.Errorf("%s not an mail file", path) + glog.Info("%q", err.Error()) return nil } md := email.NewInfo(path) - *m = append(*m, Status{ + m.Statuses = append(m.Statuses, Status{ Path: path, Hash: fmt.Sprintf("%x", h.Sum(nil)), Read: md.Seen, @@ -64,7 +74,7 @@ func (m *Messages) LoadStatus(statusFile string) error { } defer r.Close() dec := json.NewDecoder(r) - return dec.Decode(m) + return dec.Decode(&m.Statuses) } func (m *Messages) SaveStatus(maildir, statusFile string) error { @@ -96,9 +106,9 @@ func (m *Messages) SaveStatus(maildir, statusFile string) error { } func (m Messages) Reconcile(maildir string) error { - hashMap := make(map[string]*Status, len(m)) - for i, msg := range m { - hashMap[msg.Hash] = &m[i] + hashMap := make(map[string]*Status, len(m.Statuses)) + for i, msg := range m.Statuses { + hashMap[msg.Hash] = &m.Statuses[i] } return filepath.Walk(maildir, func(path string, info os.FileInfo, err error) error { @@ -110,6 +120,12 @@ func (m Messages) Reconcile(maildir string) error { return nil } + base := filepath.Base(path) + if _, ok := m.Skip[base]; ok { + glog.Infoln("Skipping", path) + return nil + } + r, err := os.Open(path) if err != nil { glog.Fatal(err) @@ -117,7 +133,8 @@ func (m Messages) Reconcile(maildir string) error { h, err := email.Hash(r, headers) if err != nil { - glog.Errorf("%s %q", path, err.Error()) + glog.Errorf("%s not an mail file", path) + glog.Infof("%q", err.Error()) return nil } @@ -143,7 +160,7 @@ func (m Messages) Reconcile(maildir string) error { func (m Messages) PrintStats() { r, u, t := 0, 0, 0 - for _, msg := range m { + for _, msg := range m.Statuses { t++ if msg.Read { r++ @@ -159,7 +176,16 @@ func (m Messages) PrintStats() { func main() { defer glog.Flush() flag.Parse() - m := Messages{} + skipStr := strings.Split(*skipFiles, ",") + skip := make(map[string]struct{}, len(skipStr)) + for _, s := range skipStr { + skip[s] = struct{}{} + } + glog.Infoln("Skip files", skip) + + m := Messages{ + Skip: skip, + } if *maildir == "" { fmt.Println("Must specify Maildir with -maildir") @@ -184,6 +210,7 @@ func main() { } m.PrintStats() if err := m.Reconcile(*maildir); err != nil { + glog.Fatal(err) } } }