uwwahfduoah
sophuwu sophie@skisiel.com
Wed, 24 Jul 2024 14:57:55 +0200
M
go.mod
→
go.mod
@@ -3,18 +3,17 @@
go 1.22.5 require ( - github.com/DusanKasan/parsemail v1.2.0 github.com/andybalholm/brotli v1.1.0 + github.com/glebarez/go-sqlite v1.22.0 + golang.org/x/crypto v0.25.0 golang.org/x/net v0.27.0 ) require ( github.com/dustin/go-humanize v1.0.1 // indirect - github.com/glebarez/go-sqlite v1.22.0 // indirect github.com/google/uuid v1.5.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - golang.org/x/crypto v0.25.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.22.0 // indirect modernc.org/libc v1.37.6 // indirect
M
go.sum
→
go.sum
@@ -1,11 +1,11 @@
-github.com/DusanKasan/parsemail v1.2.0 h1:CrzTL1nuPLxB41aO4zE/Tzc9GVD8jjifUftlbTKQQl4= -github.com/DusanKasan/parsemail v1.2.0/go.mod h1:B9lfMbpVe4DMqPImAOCGti7KEwasnRTrKKn66iQefVs= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
M
http.go
→
http.go
@@ -1,1 +1,168 @@
package main + +import ( + "bytes" + "database/sql" + "encoding/gob" + "fmt" + "html" + "net/http" + "net/mail" + "strings" +) + +var ch = make(chan []byte) + +func Web(db *sql.DB) { + go func() { + err := http.ListenAndServe("127.0.1.69:3141", http.HandlerFunc(Http)) + if err != nil { + ch <- []byte("EXIT") + } + }() + var b []byte + var r *sql.Rows + var m []EmailMeta + var bb bytes.Buffer + for { + b = <-ch + if string(b) == "EXIT" { + break + } + r, _ = db.Query(string(b)) + m, _ = ReadRows(r) + gob.NewEncoder(&bb).Encode(m) + ch <- bb.Bytes() + bb.Reset() + r.Close() + } +} + +func E(s ...string) []any { + a := make([]any, len(s)) + for i, v := range s { + a[i] = html.EscapeString(v) + } + return a +} + +func Http(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + r.ParseForm() + var q []string + if r.Form.Get("to") != "" { + q = append(q, fmt.Sprintf(` toaddr LIKE '%%%s%%'`, r.Form.Get("to"))) + } + if r.Form.Get("from") != "" { + q = append(q, fmt.Sprintf(` fromaddr LIKE '%%%s%%'`, r.Form.Get("from"))) + } + if r.Form.Get("subject") != "" { + q = append(q, fmt.Sprintf(` subject LIKE '%%%s%%'`, r.Form.Get("subject"))) + } + if r.Form.Get("date") != "" { + q = append(q, fmt.Sprintf(` date LIKE '%%%s%%'`, r.Form.Get("date"))) + } + ch <- []byte(fmt.Sprintf("SELECT * FROM emails %s ORDER BY date DESC", func() string { + if len(q) == 0 { + return "" + } + return "WHERE " + strings.Join(q, " AND ") + }())) + var metas []EmailMeta + var b []byte + b = <-ch + dec := gob.NewDecoder(strings.NewReader(string(b))) + if dec.Decode(&metas) != nil { + http.Error(w, "Internal Server Error", 500) + return + } + fmt.Fprint(w, `<html><head><title>Emails</title> +<style> +section { + display: flex; + flex-direction: row; + cursor: pointer; + border-bottom: 1px solid #666; + width: 100%; +} +section > *{ + display: inline-block; + padding: 5px; +} +section > div:last-child { + border-right: none!important; +} +section > div { + border-right: 1px solid #666; +} +section:hover { + background-color: rgba(0,0,0,0.2); +} +.addr { + font-weight: bold; +} +body { + margin: 10px; + display: flex; + flex-direction: column; +} +marquee { + width: 100%; +} +.addr > marquee { + display: none; +} +.addr:hover > marquee { + display: inline; +} +.addr:hover > span { + display: none; +} +.addr > span { + display: inline; +} +div { + margin: 5px auto 5px auto; + overflow: hidden; +} +.time { + width: 13ch; +} +.sub { + width: calc(100% - 13ch - 20%); +} +.addr { + width: 15%; + font-size: 0.8em; +} +</style> +</head><body>`) + var from *mail.Address + for _, em := range metas { + from, _ = mail.ParseAddress(em.From) + if from.Name == "" { + if strings.Contains(from.Address, "@") { + from.Name = strings.Split(from.Address, "@")[0] + } else { + from.Name = from.Address + } + } + + fmt.Fprintf(w, `<section onclick="location.href='%s'"> + <div class="time">%s</div> + <div class="addr" title="%s">%s</div> + <div class="addr" title="%s">%s</div> + <div class="sub">%s</div> +</section>`, E(em.Id, TimeStr(em.Date), from.Address, from.Name, em.To, func() string { + a, err := mail.ParseAddressList(em.To) + if err != nil { + return em.To + } + return strings.Split(a[0].Address+"@", "@")[0] + }(), em.Subject)...) + } + fmt.Fprintf(w, "</body></html>") + return + } + http.FileServer(http.Dir(SAVEPATH)).ServeHTTP(w, r) +}
M
main.go
→
main.go
@@ -1,7 +1,6 @@
package main import ( - "bytes" "database/sql" "fmt" _ "github.com/glebarez/go-sqlite"@@ -95,29 +94,17 @@ if err != nil {
fmt.Fprintln(os.Stderr, err) return } - for _, v := range os.Args[1:] { - if v == "--cli" { + for _, arg := range os.Args[1:] { + if arg == "--cli" { CLI(&metas) return } - if v == "--" { - var b bytes.Buffer - b.ReadFrom(os.Stdin) - fl, e := GetFiles(&b) - if e != nil { - fmt.Fprintln(os.Stderr, e) - return - } - path := filepath.Dir(DBPATH) - path = filepath.Join(path, "stdin") - _ = os.MkdirAll(path, 0700) - for name, data := range fl { - err = os.WriteFile(filepath.Join(path, name), data, 0600) - if err != nil { - fmt.Fprintln(os.Stderr, err) - return - } - } + if arg == "--" { + stdin() + return + } + if arg == "--web" { + Web(db) return } }
M
parse.go
→
parse.go
@@ -179,3 +179,25 @@ Subject string `json:"Subject"`
Date string `json:"Date"` Id string `json:"Id" ` } + +func stdin() { + var err error + var b bytes.Buffer + b.ReadFrom(os.Stdin) + fl, e := GetFiles(&b) + if e != nil { + fmt.Fprintln(os.Stderr, e) + return + } + path := filepath.Dir(DBPATH) + path = filepath.Join(path, "stdin") + _ = os.MkdirAll(path, 0700) + for name, data := range fl { + err = os.WriteFile(filepath.Join(path, name), data, 0600) + if err != nil { + fmt.Fprintln(os.Stderr, err) + return + } + } + os.Exit(0) +}