email/cmd/dumporiginal/dumporiginal.go
Bill Thiede 2f6b083f47 Header import, and dumporiginal extensions.
Add ability to dump headers or mimetypes for original messages.
Add ability to dump all messages, instead of just hashes listed.
Add new command  cmd/headers to import all headers from messages in table
    original.  Utility can work incrementally or do fully table imports.
Moved 'fetch all original messages' code to db/util.go.  Added conditional
version given table name that will only return original messages that do not
    have matching hashes in the specified table.
2014-04-01 23:18:12 -07:00

131 lines
2.3 KiB
Go

package main
import (
"bytes"
"flag"
"fmt"
"io"
"mime"
"net/mail"
"sort"
"xinu.tv/email/db"
"github.com/golang/glog"
)
var (
dumpMime = flag.Bool("mime", false, "show multipart mime types for message")
headers = flag.Bool("headers", false, "show only headers")
)
func printMultipartMime(hash string, r io.Reader) error {
msg, err := mail.ReadMessage(r)
if err != nil {
return err
}
mediatype, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
if err != nil {
return err
}
glog.Infof("%s mt: %s p: %v", hash, mediatype, params)
return nil
}
func printHeaders(hash string, r io.Reader) error {
msg, err := mail.ReadMessage(r)
if err != nil {
return err
}
hdrs := make([]string, 0, len(msg.Header))
for k := range msg.Header {
hdrs = append(hdrs, k)
}
fmt.Println(hash)
sort.Strings(hdrs)
for _, k := range hdrs {
vs := msg.Header[k]
fmt.Printf("%s:", k)
for _, v := range vs {
fmt.Printf(" %s", v)
}
fmt.Println()
}
return nil
}
func printOneBlob(hash string, blob []byte) error {
r := bytes.NewReader(blob)
switch {
case *dumpMime:
if err := printMultipartMime(hash, r); err != nil {
// err != nil expected when mime type not found, so we log and
// squelch the error.
glog.Warningf("%s: %v", hash, err)
return nil
}
case *headers:
if err := printHeaders(hash, r); err != nil {
return err
}
default:
fmt.Println(string(blob))
}
return nil
}
type hashError struct {
hash string
error
}
func (he hashError) Error() string {
return fmt.Sprintf("%s: %v", he.hash, he.error)
}
func printAllBlobs(c *db.Conn) error {
oCh := make(chan db.Original)
errc := make(chan error)
donec := make(chan struct{})
defer close(donec)
go c.Originals(oCh, errc, donec)
for {
select {
case o := <-oCh:
if err := printOneBlob(o.Hash, o.Blob); err != nil {
return hashError{hash: o.Hash, error: err}
}
case err := <-errc:
return err
}
}
}
func main() {
defer glog.Flush()
flag.Parse()
c, err := db.NewConn("")
if err != nil {
glog.Fatal(err)
}
if flag.NArg() == 0 {
if err := printAllBlobs(c); err != nil {
glog.Fatal(err)
}
return
}
var blob []byte
for _, hash := range flag.Args() {
if err := c.OriginalBlobByHash(hash, &blob); err != nil {
glog.Fatal(err)
}
if err := printOneBlob(hash, blob); err != nil {
glog.Fatal(err)
}
}
}