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.
This commit is contained in:
@@ -1,14 +1,107 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"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()
|
||||
@@ -19,8 +112,10 @@ func main() {
|
||||
}
|
||||
|
||||
if flag.NArg() == 0 {
|
||||
fmt.Println("Must specify message hashes to print")
|
||||
os.Exit(1)
|
||||
if err := printAllBlobs(c); err != nil {
|
||||
glog.Fatal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var blob []byte
|
||||
@@ -28,6 +123,8 @@ func main() {
|
||||
if err := c.OriginalBlobByHash(hash, &blob); err != nil {
|
||||
glog.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(blob))
|
||||
if err := printOneBlob(hash, blob); err != nil {
|
||||
glog.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user