git.sophuwu.com > mailboxxer   
              248
            
             package web

import (
	_ "embed"
	"fmt"
	"html"
	"html/template"
	"net/http"
	"net/mail"
	"os"
	"path/filepath"
	"sophuwu.site/mailboxxer/db"
	"strings"
)

//go:embed templates/index.html
var htmlTemplate string

var t *template.Template

func ServeHttp() {
	t = template.Must(template.New("index").Parse(htmlTemplate))
	http.ListenAndServe("127.0.1.69:3141", Http())
}

func E(s ...string) []any {
	a := make([]any, len(s))
	for i, v := range s {
		a[i] = html.EscapeString(v)
	}
	return a
}

type HtmlEM struct {
	Id       string
	Date     string
	Subject  string
	ToName   string
	ToAddr   string
	FromName string
	FromAddr string
}

func ParseInt(s string) int {
	n := 0
	for _, r := range s {
		if r < '0' || r > '9' {
			break
		}
		n = n*10 + int(r-'0')
	}
	return n
}

func TempErr(w http.ResponseWriter, code int) {
	msg := "An error occurred"
	switch code {
	case 404:
		msg = "Not found"
	case 500:
		msg = "Internal server error"
	}
	var dat = map[string]any{
		"Error":     msg,
		"ErrorCode": code,
	}
	t.Execute(w, dat)
}

func Http() http.HandlerFunc {
	qu, errr := db.NewQuery(30)
	if errr != nil {
		fmt.Fprintln(os.Stderr, "Error creating query:", errr)
		db.Close()
		os.Exit(1)
	}
	return func(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")))
			}
			where := func() string {
				if len(q) == 0 {
					return ""
				}
				return strings.Join(q, " AND ")
			}()
			var err error
			if where != qu.GetWhere() {
				err = qu.SetWhere(where)
				if err != nil {
					TempErr(w, 500)
					return
				}
			}
			err = qu.SetPage(ParseInt(r.Form.Get("page")) - 1)
			if err != nil {
				TempErr(w, 500)
				return
			}
			if qu.TotalRows() == 0 {
				TempErr(w, 404)
				return
			}

			var htmlMetas []HtmlEM
			var from *mail.Address
			var to []*mail.Address
			var addrlist []string
			var htmlMeta HtmlEM
			for _, em := range qu.Rows() {
				htmlMeta = HtmlEM{
					Id:      em.Id,
					Date:    db.TimeStr(em.Date),
					Subject: em.Subject,
				}
				from, err = mail.ParseAddress(em.From)
				if err != nil {
					htmlMeta.FromAddr = em.From
				} else {
					htmlMeta.FromAddr = from.Address
					htmlMeta.FromName = from.Name
				}
				if htmlMeta.FromName == "" {
					htmlMeta.FromName = htmlMeta.FromAddr
				}
				to, err = mail.ParseAddressList(em.To)
				if err != nil || len(to) == 0 {
					addrlist = strings.Split(em.To, ", ")
					if len(addrlist) == 0 {
						htmlMeta.ToAddr = em.To
					} else {
						htmlMeta.ToAddr = addrlist[0]
					}
				} else {
					htmlMeta.ToAddr = to[0].Address
					htmlMeta.ToName = to[0].Name
				}
				if htmlMeta.ToName == "" {
					htmlMeta.ToName = htmlMeta.ToAddr
				}
				htmlMetas = append(htmlMetas, htmlMeta)
			}
			dat := map[string]any{
				"ToAddr":     r.Form.Get("to"),
				"FromAddr":   r.Form.Get("from"),
				"Subject":    r.Form.Get("subject"),
				"Date":       r.Form.Get("date"),
				"Page":       qu.Page(),
				"TotalPages": qu.TotalPages(),
				"HtmlMetas":  htmlMetas,
			}
			t.Execute(w, dat)
			return
		}
		if filepath.Base(r.URL.Path) == "html.html" && len(strings.Split(r.URL.Path[1:], "/")) == 2 {
			id := filepath.Base(filepath.Dir(r.URL.Path))
			s, _ := os.ReadFile(filepath.Join(db.SAVEPATH, id, "header.txt"))
			b, _ := os.ReadFile(filepath.Join(db.SAVEPATH, id, "body.txt"))
			fmt.Fprintf(w, `<html><head><title>%s</title></head>
<body style="display: flex; flex-direction: row;">
<div style="width: 50%%;display:inline;height:100%%;overflow:scroll;"><pre>%s</pre><br><pre>%s</pre></div>
<iframe style="width: 50%%;display:inline;height:100%%;overflow:scroll;" src="%s"></iframe>
</body></html>`, id, string(s), string(b), "/"+id)
			return
		}
		if func(w http.ResponseWriter, r *http.Request) bool {
			var file string
			var id string
			l := strings.SplitN(r.URL.Path[1:], "/", 2)
			if len(l) == 0 {
				return false
			}
			if len(l) >= 1 {
				id = l[0]
			}
			if len(l) >= 2 {
				file = l[1]
			}
			if file != "" && filepath.Ext(file) != ".txt" {
				return false
			}
			de, err := os.ReadDir(filepath.Join(db.SAVEPATH, id))
			if err != nil {
				return false
			}

			darkMode := r.URL.Query().Get("dark")
			if darkMode == "" || darkMode == "0" || darkMode == "false" {
				darkMode = "0"
			} else {
				darkMode = "1"
			}
			dat := map[string]any{
				"DarkMode": darkMode,
				"Style":    `style="overflow: auto;"`,
			}

			var ss string
			var f os.DirEntry
			if file != "" {
				var b []byte
				for _, f = range de {
					if f.Name() == file && f.Type().IsRegular() {
						b, err = os.ReadFile(filepath.Join(db.SAVEPATH, id, file))
						break
					}
				}
				if err != nil || len(b) == 0 {
					return false
				}
				ss = string(b)
				if filepath.Ext(f.Name()) == ".txt" {
					dat["Text"] = ss
				} else {
					return false
				}
			} else {
				for _, f = range de {
					ss += fmt.Sprintf(`<a href="/%s`, filepath.Join(id, f.Name()))
					if filepath.Ext(f.Name()) == ".txt" {
						ss += fmt.Sprintf(`?dark=%s`, darkMode)
					}
					ss += fmt.Sprintf(`">%s</a><br>%c`, html.EscapeString(f.Name()), '\n')
				}
				ss = `<main ` + fmt.Sprint(dat["Style"]) + `>` + ss + `</main>`
				dat["Html"] = template.HTML(ss)
			}
			w.Header().Set("Content-Type", "text/html; charset=utf-8")
			t.Execute(w, dat)
			return true
		}(w, r) {
			return
		}
		http.FileServer(http.Dir(db.SAVEPATH)).ServeHTTP(w, r)
	}
}