git.sophuwu.com > manhttpd   
              200
            
             package main

import (
	"fmt"
	"git.sophuwu.com/authuwu"
	"git.sophuwu.com/authuwu/userpass"
	"git.sophuwu.com/gophuwu/flags"
	"git.sophuwu.com/manhttpd/CFG"
	"git.sophuwu.com/manhttpd/embeds"
	"git.sophuwu.com/manhttpd/manpage"
	"git.sophuwu.com/manhttpd/neterr"
	"golang.org/x/term"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"
)

func init() {
	err := flags.NewFlag("conf", "c", "configuration file to use", "/etc/manhttpd/manhttpd.conf")
	neterr.ChkFtl("creating conf flag:", err)
	err = flags.NewFlag("passwd", "p", "open the program in password edit mode", false)
	neterr.ChkFtl("creating passwd flag:", err)
	err = flags.NewFlag("user", "u", "choose a username to set/change/delete password for", "")
	neterr.ChkFtl("creating user flag:", err)
	err = flags.ParseArgs()
	neterr.ChkFtl("parsing flags:", err)
	CFG.ParseConfig()
	embeds.OpenAndParse()
}

func setPasswd() {
	u, err := flags.GetStringFlag("user")
	if err != nil {
		fmt.Println("getting user flag:", err)
		return
	}
	if u == "" {
		fmt.Println("no user specified, use -u <username> to set a password for a user")
		return
	}
	var in []byte
	fmt.Printf("Enter password for user %s (leave empty to delete user): \n", u)
	in, err = term.ReadPassword(0)
	if err != nil {
		fmt.Println("could not read password:", err)
		return
	}
	password := string(in)
	if password == "" {
		fmt.Printf("delete user %s? (y/N): ", u)
		in = make([]byte, 1)
		os.Stdin.Read(in)
		if in[0] != 'y' && in[0] != 'Y' {
			userpass.DeleteUser(u)
			fmt.Printf("User %s deleted.\n", u)
			return
		}
		fmt.Printf("exiting with no changes\n")
		return
	}
	fmt.Println("Enter password again: ")
	in, err = term.ReadPassword(0)
	if err != nil {
		fmt.Println("could not read password:", err)
		return
	}
	if string(in) != password {
		fmt.Println("Passwords do not match, please try again.")
		return
	}
	err = userpass.NewUser(u, password)
}

func main() {
	b, err := flags.GetBoolFlag("passwd")
	neterr.ChkFtl("getting passwd flag:", err)
	if b {
		err = authuwu.OpenDB(CFG.PasswdFile)
		neterr.ChkFtl("opening password database:", err)
		setPasswd()
		authuwu.CloseDB()
		return
	}
	if CFG.RequireAuth {
		err = authuwu.OpenDB(CFG.PasswdFile)
		neterr.ChkFtl("error opening password database:", err)
		PageHandler = authuwu.NewAuthuwuHandler(PageHandler, time.Hour*24*3, embeds.LoginPage)
	}
	CFG.ListenAndServe(Handler)
}

var RxWords = regexp.MustCompile(`("[^"]+")|([^ ]+)`).FindAllString
var RxWhatIs = regexp.MustCompile(`([a-zA-Z0-9_\-]+) [(]([0-9a-z]+)[)][\- ]+(.*)`).FindAllStringSubmatch

func SearchHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if neterr.Err400.Is(err) {
		embeds.WriteError(w, r, neterr.Err400, r.Form.Get("q"))
		return
	}
	q := r.Form.Get("q")
	if q == "" {
		http.Redirect(w, r, r.URL.Path, http.StatusFound)
	}
	if strings.HasPrefix(q, "manweb:") {
		http.Redirect(w, r, "?"+q, http.StatusFound)
		return
	}
	if func() bool {
		m := manpage.New(q)
		return m.Where() == nil
	}() {
		http.Redirect(w, r, "?"+q, http.StatusFound)
		return
	}

	var args = RxWords("-lw "+q, -1)

	for i := range args {
		args[i] = strings.TrimSpace(args[i])
		args[i] = strings.TrimPrefix(args[i], `"`)
		args[i] = strings.TrimSuffix(args[i], `"`)
		if (args[i] == "-r" || args[i] == "-w") && args[0] != "-l" {
			args[0] = "-l"
		}
	}

	cmd := exec.Command(CFG.DbCmd, args...)
	b, e := cmd.Output()
	if len(b) < 1 || e != nil {
		embeds.WriteError(w, r, neterr.Err404, q)
		return
	}
	var output string
	for _, line := range RxWhatIs(string(b), -1) { // strings.Split(string(b), "\n") {
		if len(line) == 4 {
			output += fmt.Sprintf(`<p><a href="?%s.%s">%s (%s)</a> - %s</p>%c`, line[1], line[2], line[1], line[2], line[3], 10)
		}
	}
	embeds.WriteHtml(w, r, "Search", output, q)
}

var PageHandler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		SearchHandler(w, r)
		return
	}
	name := r.URL.RawQuery
	if name == "manweb:help" {
		embeds.Help(w, r)
		return
	}

	var nerr neterr.NetErr
	title := "Index"
	var html string
	if name != "" {
		man := manpage.New(name)
		html, nerr = man.Html()
		if nerr != nil {
			embeds.WriteError(w, r, nerr, name)
			return
		}
		title = man.Name
	}
	embeds.WriteHtml(w, r, title, html, name)
})

var Handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	if r.URL.Query().Has("static") {
		StaticHandler(w, r)
		return
	}
	PageHandler.ServeHTTP(w, r)
})

type ManHandler struct {
	h http.Handler
}

func (m ManHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Query().Has("static") {
		StaticHandler(w, r)
		return
	}
	m.h.ServeHTTP(w, r)
}

func StaticHandler(w http.ResponseWriter, r *http.Request) {
	q := r.URL.Query().Get("static")
	if f, ok := embeds.StaticFile(q); ok {
		w.Header().Set("Content-Type", f.ContentType)
		w.Header().Set("Content-Length", f.Length)
		f.WriteTo(w)
		return
	}
}