Add import for 'important' headers.
Process and normalize some headers that will be used in quickly recalling messages.
This commit is contained in:
parent
aebb1a2c92
commit
14bd95851c
@ -20,10 +20,19 @@ func insertHeaders(c *db.Conn, hash string, r io.Reader) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
glog.Infoln("Insert", hash)
|
glog.Infoln("Insert headers", hash)
|
||||||
return c.InsertHeaders(hash, msg.Header)
|
return c.InsertHeaders(hash, msg.Header)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func insertSearchHeaders(c *db.Conn, hash string, r io.Reader) error {
|
||||||
|
msg, err := mail.ReadMessage(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
glog.Infoln("Insert search headers", hash)
|
||||||
|
return c.InsertSearchHeaders(hash, msg.Header)
|
||||||
|
}
|
||||||
|
|
||||||
func insertAllHeaders(c *db.Conn, all bool) error {
|
func insertAllHeaders(c *db.Conn, all bool) error {
|
||||||
oCh := make(chan db.Original)
|
oCh := make(chan db.Original)
|
||||||
errc := make(chan error)
|
errc := make(chan error)
|
||||||
@ -39,6 +48,31 @@ func insertAllHeaders(c *db.Conn, all bool) error {
|
|||||||
case o := <-oCh:
|
case o := <-oCh:
|
||||||
r := bytes.NewReader(o.Blob)
|
r := bytes.NewReader(o.Blob)
|
||||||
if err := insertHeaders(c, o.Hash, r); err != nil {
|
if err := insertHeaders(c, o.Hash, r); err != nil {
|
||||||
|
glog.Errorln(o, "insertHeaders", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case err := <-errc:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertAllSearchHeaders(c *db.Conn, all bool) error {
|
||||||
|
oCh := make(chan db.Original)
|
||||||
|
errc := make(chan error)
|
||||||
|
donec := make(chan struct{})
|
||||||
|
defer close(donec)
|
||||||
|
if all {
|
||||||
|
go c.Originals(oCh, errc, donec)
|
||||||
|
} else {
|
||||||
|
go c.OriginalsNotInTable("search_header", oCh, errc, donec)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case o := <-oCh:
|
||||||
|
r := bytes.NewReader(o.Blob)
|
||||||
|
if err := insertSearchHeaders(c, o.Hash, r); err != nil {
|
||||||
|
glog.Errorln(o.Hash, "insertSearchHeaders", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case err := <-errc:
|
case err := <-errc:
|
||||||
@ -60,4 +94,8 @@ func main() {
|
|||||||
glog.Fatal(err)
|
glog.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := insertAllSearchHeaders(c, *all); err != nil {
|
||||||
|
glog.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
75
db/util.go
75
db/util.go
@ -5,6 +5,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -140,7 +141,7 @@ VALUES
|
|||||||
for k, vs := range hdrs {
|
for k, vs := range hdrs {
|
||||||
for _, v := range vs {
|
for _, v := range vs {
|
||||||
if !utf8.ValidString(v) {
|
if !utf8.ValidString(v) {
|
||||||
glog.Infof("%s: value for %q invalid UTF-8 %q", hash, k, v)
|
glog.Warningf("%s: value for %q invalid UTF-8 %q", hash, k, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, err := stmt.Exec(hash, k, v); err != nil {
|
if _, err := stmt.Exec(hash, k, v); err != nil {
|
||||||
@ -150,3 +151,75 @@ VALUES
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) InsertSearchHeaders(hash string, hdrs mail.Header) (err error) {
|
||||||
|
var tx *sql.Tx
|
||||||
|
tx, err = c.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
if err := tx.Rollback(); err != nil {
|
||||||
|
glog.Error(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
}()
|
||||||
|
|
||||||
|
stmt, err := tx.Prepare(`
|
||||||
|
INSERT INTO
|
||||||
|
search_header (hash, name, value)
|
||||||
|
VALUES
|
||||||
|
($1, $2, $3)
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the following headers to the database untouched.
|
||||||
|
otherHdrs := []string{"Subject", "Message-Id", "In-Reply-To", "References"}
|
||||||
|
for _, k := range otherHdrs {
|
||||||
|
for _, v := range hdrs[k] {
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
glog.Warningf("%s: value for %q invalid UTF-8 %q", hash, k, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := stmt.Exec(hash, k, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the following headers as addresses, and save each email address
|
||||||
|
// found to the database independently.
|
||||||
|
addrHdrs := []string{"To", "From", "Cc"}
|
||||||
|
for _, k := range addrHdrs {
|
||||||
|
for _, value := range hdrs[k] {
|
||||||
|
addrs, err := mail.ParseAddressList(value)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("%s: error parsing address list for %q: %v", hash, k, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range addrs {
|
||||||
|
if _, err := stmt.Exec(hash, k, v.Address); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize date field.
|
||||||
|
t, err := hdrs.Date()
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("%s: failed to parse date header: %v", hash, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := t.UTC().Format(time.RFC3339Nano)
|
||||||
|
if _, err := stmt.Exec(hash, "Date", v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
2
hash.go
2
hash.go
@ -43,7 +43,7 @@ func (h Hasher) HashReader(r io.Reader) (hash.Hash, error) {
|
|||||||
|
|
||||||
var std = Hasher([]string{"to", "from", "cc", "date", "subject", "message-id"})
|
var std = Hasher([]string{"to", "from", "cc", "date", "subject", "message-id"})
|
||||||
|
|
||||||
// Hash will parse r as an email, and return the hash as a hexidecimal string
|
// Hash will parse r as an email, and return the hash as a hexadecimal string
|
||||||
// using a default set of headers.
|
// using a default set of headers.
|
||||||
func HashReader(r io.Reader) (string, error) {
|
func HashReader(r io.Reader) (string, error) {
|
||||||
h, err := std.HashReader(r)
|
h, err := std.HashReader(r)
|
||||||
|
|||||||
7
pg/init-search-header.sql
Normal file
7
pg/init-search-header.sql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
DROP TABLE search_header;
|
||||||
|
|
||||||
|
CREATE TABLE search_header (
|
||||||
|
hash CHAR(40) REFERENCES original (hash),
|
||||||
|
name TEXT,
|
||||||
|
value TEXT
|
||||||
|
);
|
||||||
Loading…
x
Reference in New Issue
Block a user