sophuwu.site > mailboxxer
uahgeofdiuho
sophuwu sophie@skisiel.com
Sat, 20 Jul 2024 21:26:01 +0200
commit

ccf4aa06d119b52f51fb3614f7be3931f4462492

parent

83786c4a056b9858ee6736c3ff3d6dadb052cdff

3 files changed, 141 insertions(+), 57 deletions(-)

jump to
M db.godb.go

@@ -4,89 +4,154 @@ import (

"bytes" "encoding/json" "github.com/asdine/storm" + "github.com/asdine/storm/q" "go.etcd.io/bbolt" "net" + "os" + "os/signal" ) func DB() error { - Db, err := storm.Open(DBPATH, storm.BoltOptions(0600, nil)) + bb, err := storm.Open(DBPATH, storm.BoltOptions(0600, nil)) + if err != nil { + return err + } + var e EmailMeta + err = bb.Init(&e) if err != nil { return err } - - // update db and add bucket if not exists - if err = db.Update(func(tx *bbolt.Tx) error { + err = bb.Bolt.Update(func(tx *bbolt.Tx) error { _, err = tx.CreateBucketIfNotExists([]byte("data")) return err - }); err != nil { - + }) + if err != nil { return err } - if err = db.Init(&EmailMeta{}); err != nil { - return err - } - db = Db + db = bb return nil } -var db *storm.DB = nil +var db *storm.DB func Listen() { - sock, err := net.ListenUnix("unix", &net.UnixAddr{SOCK, "unix"}) - if err != nil { - FtlLog(err) - } - defer sock.Close() - if err = DB(); err != nil { + err := DB() + FtlLog(err) + _ = os.Remove(SOCK) + var sock *net.UnixListener + sock, err = net.ListenUnix("unix", &net.UnixAddr{SOCK, "socket"}) + FtlLog(err) + + // handle signals + go func() { + chn := make(chan os.Signal, 1) + signal.Notify(chn, os.Kill, os.Interrupt) + <-chn + db.Close() + sock.Close() + os.Remove(SOCK) FtlLog(err) - } - defer db.Close() + os.Exit(0) + }() + var conn *net.UnixConn for { - conn, err := sock.Accept() + conn, err = sock.AcceptUnix() if err != nil { - db.Close() - sock.Close() - FtlLog(err) + continue } go Handle(conn) } } type Req struct { - CMD string `json:"cmd"` - Data []byte `json:"data"` + CMD string `json:"CMD"` + Data []byte `json:"Data"` +} + +func sendToSock(req Req) []byte { + var conn *net.UnixConn + var err error + conn, err = net.DialUnix("unix", &net.UnixAddr{ + Name: SOCK, + Net: "local", + }, &net.UnixAddr{Name: SOCK, Net: "socket"}) + FtlLog(err) + b, err := json.Marshal(req) + FtlLog(err) + var n int + conn.WriteTo(b, &net.UnixAddr{Name: SOCK, Net: "socket"}) + n, err = conn.Write(b) + FtlLog(err) + println(n) + conn.ReadFrom(b) + + return b } -func Search(conn net.Conn, req *Req) { +func Search(req Req) []byte { var err error - var meta EmailMeta - if json.Unmarshal(req.Data, &meta) != nil { - return + var search string + if err = json.Unmarshal(req.Data, &search); err != nil { + return []byte("error unmarshalling request") } + println(search) + search += "*" var emails []EmailMeta - if err = db.Find("Id", meta.Id, &emails); err != nil { - return - } + query := db.Select(q.Or(q.Re("Subject", search), q.Re("From", search), q.Re("To", search))) + _ = query.Find(&emails) var b []byte - b, err = json.Marshal(emails) - conn.Write(b) - conn.Close() + b, _ = json.Marshal(emails) + return b } -func Handle(conn net.Conn) { +func Handle(conn *net.UnixConn) { var b bytes.Buffer + var buf = make([]byte, 1024) + var n int + var err error + for { + buf = make([]byte, 1024) + n, err = conn.Read(buf) + if err != nil || n == 0 { + break + } + b.Write(buf[:n]) + } var req Req - _, err := b.ReadFrom(conn) + err = json.Unmarshal(b.Bytes(), &req) if err != nil { return } - if json.Unmarshal(b.Bytes(), &req) != nil { - return - } + var bb []byte switch req.CMD { case "SEARCH": - Search(conn, &req) + bb = Search(req) + break + case "PUT": + bb = Put(req) + break + } + n, err = conn.Write(bb) + if err != nil { return + } + println(n) + conn.Close() +} + +type PUT struct { + M EmailMeta `json:"M"` + D []byte `json:"D"` +} +func Put(req Req) []byte { + var put PUT + if json.Unmarshal(req.Data, &put) != nil { + return []byte("ERR") } + db.Save(&put.M) + db.Update(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte("data")).Put(put.M.Id, put.D) + }) + return []byte("OK") }
M main.gomain.go

@@ -1,6 +1,7 @@

package main import ( + "encoding/json" "fmt" "os" "path/filepath"

@@ -9,10 +10,14 @@

var DBPATH, SOCK, LOG string func init() { - home, _ := os.UserHomeDir() + home, err := os.UserHomeDir() + FtlLog(err) if home == "" { os.Exit(1) } + if _, err := os.Stat(filepath.Join(home, ".mailbox")); os.IsNotExist(err) { + os.Mkdir(filepath.Join(home, ".mailbox"), 0755) + } DBPATH = filepath.Join(home, ".mailbox", "mail.storm") SOCK = filepath.Join(home, ".mailbox", "mail.sock") LOG = filepath.Join(home, ".mailbox", "box.log")

@@ -23,24 +28,36 @@ if e == nil {

return } log, _ := os.OpenFile(LOG, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) - fmt.Fprintln(log, "Fatal: ", e.Error()) + fmt.Fprintln(log, "Fatal: ", e) log.Close() os.Exit(1) } func main() { - if (len(os.Args) > 0 && filepath.Base(os.Args[0]) == "mailbox-parser") || (len(os.Args) > 1 && os.Args[1] == "parse") { + if (len(os.Args) > 0 && os.Args[0] == "mailbox-parser") || (len(os.Args) > 1 && os.Args[1] == "parse") { meta, filebr := Parse() - fmt.Println("Email ID: ", meta.Id, filebr.Len()) - fmt.Println("From ", meta.From) - fmt.Println("To", meta.To) - fmt.Println("Subject", meta.Subject) - fmt.Println("Date", TimeStr(meta.Date)) + var put PUT + put.M = meta + put.D = filebr.Bytes() + b, err := json.Marshal(put) + FtlLog(err) + var r Req + r.CMD = "PUT" + r.Data = b + FtlLog(err) + b = sendToSock(r) + fmt.Println(string(b)) + } + if (len(os.Args) > 0 && os.Args[0] == "mailbox-db") || (len(os.Args) > 1 && os.Args[1] == "db") { + Listen() return - } - if (len(os.Args) > 0 && filepath.Base(os.Args[0]) == "mailbox-db") || (len(os.Args) > 1 && os.Args[1] == "db") { + } else if len(os.Args) > 1 && os.Args[1] == "search" { + var r Req + r.CMD = "SEARCH" + b, _ := json.Marshal(os.Args[2]) + r.Data = b + fmt.Println(string(sendToSock(r))) - return } }
M parse.goparse.go

@@ -3,8 +3,10 @@

import ( "bytes" "crypto/sha1" + _ "encoding/json" "fmt" "github.com/andybalholm/brotli" + _ "github.com/asdine/storm" "mime" "net/mail" "os"

@@ -104,9 +106,9 @@ }

// EmailMeta contains the fields that will be searchable in the database type EmailMeta struct { - From string `storm:"index"` - To string `storm:"index"` - Subject string `storm:"index"` - Date time.Time `storm:"index"` - Id []byte `storm:"id,unique,hash"` + From string `json:"From" storm:"index"` + To string `json:"To" storm:"index"` + Subject string `json:"Subject" storm:"index"` + Date time.Time `json:"Date" storm:"index"` + Id []byte `json:"Id" storm:"unique,id"` }