// Copyright (C) 2026 Marius Schellenberger

package main

import (
	"errors"
	"flag"
	"fmt"
	"log/slog"
	"net/http"
	"net/smtp"
	"os"
	"strings"

	"git.giftfish.de/ston1th/godrop/v2"
	"github.com/go-logr/logr"
)

var (
	version string
	listen  string
	addr    string
	domain  string
	log     logr.Logger
)

var allowedFiles = []string{
	"/etc/resolv.conf",
	"/etc/localtime",
	"/etc/hosts",
	"/etc/ssl/cert.pem",
}

func fatal(err error) {
	log.Error(err, "fatal error")
	os.Exit(1)
}

func main() {
	flag.StringVar(&listen, "listen", ":7979", "listen addr")
	flag.StringVar(&addr, "addr", "", "smtp server addr")
	flag.StringVar(&domain, "domain", "", "base sender domain (example: example.com)")
	flag.Parse()

	log = logr.FromSlogHandler(slog.NewTextHandler(os.Stdout, nil))
	log.Info("starting mailgo", "version", version)

	if addr == "" {
		fatal(errors.New("missing smtp server addr"))
	}
	if domain == "" {
		fatal(errors.New("missing base sender domain"))
	}
	log.Info("config",
		"listen", listen,
		"addr", addr,
		"domain", domain,
	)

	if err := godrop.PledgePromises("stdio inet rpath unveil"); err != nil {
		fatal(err)
	}
	for _, file := range allowedFiles {
		if err := godrop.Unveil(file, "r"); err != nil {
			fatal(err)
		}
	}
	if err := godrop.UnveilBlock(); err != nil {
		fatal(err)
	}

	mc := &mailClient{
		server: addr,
		domain: domain,
	}

	http.HandleFunc("/send", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Redirect(w, r, "/?err=method", http.StatusFound)
			return
		}
		log := log.WithName("send")
		err := r.ParseForm()
		if err != nil {
			http.Redirect(w, r, "/?err=parse", http.StatusFound)
			return
		}
		from := r.PostForm.Get("from")
		to := r.PostForm.Get("to")
		subject := r.PostForm.Get("subject")
		if from == "" ||
			to == "" ||
			subject == "" {
			http.Redirect(w, r, "/?err=missing", http.StatusFound)
			return
		}
		if !strings.ContainsAny(to, "@") {
			http.Redirect(w, r, "/?err=invalid", http.StatusFound)
			return
		}
		log = log.WithValues("to", to, "from", from, "subject", subject)
		log.Info("sending mail")
		msg := r.PostForm.Get("message")
		err = mc.sendMail(from, to, subject, msg)
		if err != nil {
			http.Redirect(w, r, "/?err=send", http.StatusFound)
			log.Error(err, "mail send failed")
			return
		}
		http.Redirect(w, r, "/", http.StatusFound)
	})
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(page))
	})
	err := http.ListenAndServe(listen, nil)
	if err != nil {
		fatal(err)
	}
}

type mailClient struct {
	server string
	domain string
}

const msgTmpl = "From: %s\r\n" +
	"To: %s\r\n" +
	"Subject: %s\r\n\r\n" +
	"%s\r\n"

func (mc *mailClient) sendMail(from, to, subj, msg string) error {
	from += "@" + mc.domain
	message := fmt.Sprintf(msgTmpl, from, to, subj, msg)
	return smtp.SendMail(mc.server, nil, from, []string{to}, []byte(message))
}

const page = `<!doctype html><html lang="en">
<head>
<title>MailGo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#009670">
<meta name="description" content="MailGo">
<style>
body {
  font: 20px Helvetica, sans-serif;
  background-color: #303030;
  color: #e6e6e6;
  margin: 0px;
  padding: 0 150px 0 150px;
}
@media only screen and (max-width: 800px) {
  body {
    padding: 0;
  }
}
div {
  margin-bottom: 10px;
}
label {
  display: inline-block;
  width: 100px;
  text-align: left;
}
input, textarea {
  color: #e2e2e2;
  background-color: #444444;
  border-radius: 0.375rem;
  border: 1px solid #222;
  font-size: 1rem;
  font-weight: 400;
}
textarea {
  width: 80%;
}
h3 {
  background-color: #009670;
  margin: 0 0 20px 0;
  padding: 10px 0 10px 0;
  text-align: center;
  color: #fff;
}
</style>
</head>
<body>
<h3>MailGo</h3>
<center>
<form action="/send" method="post" autocomplete="off">
<div><label for="from">From:</label></div>
<div><input type="text" id="from" name="from" required autofocus></input></div>
<div><label for="to">To:</label></div>
<div><input type="text" id="to" name="to" required></input></div>
<div><label for="subject">Subject:</label></div>
<div><input type="text" id="subject" name="subject" required></input></div>
<div><label for="message">Message:</label></div>
<div><textarea id="message" name="message" rows="10" spellcheck="false"></textarea></div>
<input type="submit" style="font-size:1em;" value="Send"></input>
</form>
</center></body></html>`
