Add utility to generate and save hashes of email and unread state.

This commit is contained in:
Bill Thiede 2014-02-15 21:29:44 -08:00
parent 8523965168
commit 9a42a60278
2 changed files with 132 additions and 0 deletions

94
cmd/mailhash/mailhash.go Normal file
View File

@ -0,0 +1,94 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"path/filepath"
"xinu.tv/email"
"github.com/golang/glog"
)
var (
saveFile = flag.String("save", "", "filename to store unread status.")
loadFile = flag.String("load", "", "filename to load unread status.")
maildir = flag.String("maildir", "", "Maildir root")
)
type Status struct {
Hash string `json:"hash"`
Path string `json:"path,omitempthashy"`
Unread bool `json:"unread,omitempty"`
}
type Messages []Status
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)
}
headers := []string{"to", "from", "cc", "date", "subject"}
h, err := email.Hash(r, headers)
if err != nil {
glog.Errorln(path, err)
return nil
}
md := email.NewInfo(path)
//fmt.Printf("%x %s\n", h.Sum(nil), path)
*m = append(*m, Status{
Path: path,
Hash: fmt.Sprintf("%x", h.Sum(nil)),
Unread: !md.Seen,
})
return nil
}
func (m *Messages) SaveStatus(maildir, saveFile string) error {
if err := filepath.Walk(maildir, m.hashMail); err != nil {
return err
}
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return err
}
f, err := os.Create(saveFile)
if err != nil {
return err
}
defer f.Close()
n, err := f.Write(b)
if err != nil {
return err
}
if n != len(b) {
return fmt.Errorf("Short write of save status: wrote %d of %d", n,
len(b))
}
return nil
}
func main() {
defer glog.Flush()
flag.Parse()
m := Messages{}
if *maildir == "" {
glog.Fatal("Must specify Maildir with -maildir")
}
if *saveFile != "" {
if err := m.SaveStatus(*maildir, *saveFile); err != nil {
glog.Fatal(err)
}
}
}

38
hash.go Normal file
View File

@ -0,0 +1,38 @@
package email
import (
"crypto/sha1"
"hash"
"io"
"net/mail"
"os"
"sort"
"github.com/golang/glog"
)
// Hash will parse r as an email, and return a hash.Hash that has been applied
// to the values of the specified headers.
func Hash(r io.Reader, headers []string) (hash.Hash, error) {
// Add deterministic behavior regardless of the order the users specified.
sort.Strings(headers)
var name string
if f, ok := r.(*os.File); ok {
name = f.Name()
}
h := sha1.New()
msg, err := mail.ReadMessage(r)
if err != nil {
return nil, err
}
for _, header := range headers {
v := msg.Header.Get(header)
if v == "" {
glog.V(2).Infoln(name, "Empty", header, "header")
}
io.WriteString(h, v)
}
return h, nil
}