git.sophuwu.com > manweb   
              192
            
             package main

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

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

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")
	logs.CheckFatal("getting passwd flag", err)
	if b {
		err = authuwu.OpenDB(CFG.PasswdFile)
		if err != nil {
			if err.Error() == "timeout" {
				logs.Error("The database is currently opened by another process.")
				return
			}
			logs.Fatal("opening password database", err)
		}
		setPasswd()
		authuwu.CloseDB()
		return
	}
	if CFG.RequireAuth {
		err = authuwu.OpenDB(CFG.PasswdFile)
		logs.CheckFatal("opening password database", err)
		_ = cookies.PurgeExpiredCookies()
		PageHandler = authuwu.NewAuthuwuHandler(PageHandler, time.Hour*24*3, embeds.LoginPage)
		logs.AddOnExit(func() { authuwu.CloseDB() })
	}
	if CFG.EnableStats {
		stats.OpenDB()
		logs.AddOnExit(func() { stats.CloseDB() })
	}
	CFG.ListenAndServe(Handler)
	logs.Exit(0)
}

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, q string) {
	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) {
		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, "")
	stats.SpecialCount("Search")
}

var PageHandler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	name := r.URL.RawQuery
	name = strings.TrimSpace(name)
	if r.Method == "POST" {
		n := r.PostFormValue("q")
		n = strings.TrimSpace(n)
		if n == "" {
			name = ""
		} else if n != "" {
			name = n
			if strings.ContainsAny(name, `"*?^|`) {
				SearchHandler(w, r, name)
				return
			}
		}
	}
	if name == "" {
		embeds.WriteHtml(w, r, "Index", stats.Html(), "", "")
		return
	}
	if embeds.Help(w, r, name) {
		return
	}
	if manpage.Http(w, r, name) {
		return
	}
	if CFG.TldrPages && tldr.Http(w, r, name) {
		return
	}
	SearchHandler(w, r, 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)
})

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
	}
}