bombadillo/main.go

217 lines
5.3 KiB
Go
Raw Normal View History

package main
2019-10-10 06:05:50 +00:00
2019-09-23 15:49:33 +00:00
// Bombadillo is a gopher and gemini client for the terminal of unix or unix-like systems.
//
// Copyright (C) 2019 Brian Evans
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import (
"flag"
"fmt"
"io/ioutil"
"os"
2019-10-10 06:05:50 +00:00
"os/signal"
"strings"
2019-10-10 06:05:50 +00:00
"syscall"
"tildegit.org/sloum/bombadillo/config"
"tildegit.org/sloum/bombadillo/cui"
2019-10-10 06:05:50 +00:00
_ "tildegit.org/sloum/bombadillo/gemini"
"tildegit.org/sloum/mailcap"
)
2019-10-14 23:29:40 +00:00
var version string
var build string
var conf_path string
var bombadillo *client
var helplocation string = "gopher://colorfield.space:70/1/bombadillo-info"
var settings config.Config
var mc *mailcap.Mailcap
2019-05-01 00:18:28 +00:00
func saveConfig() error {
var opts strings.Builder
bkmrks := bombadillo.BookMarks.IniDump()
2019-09-27 05:08:57 +00:00
certs := bombadillo.Certs.IniDump()
opts.WriteString("\n[SETTINGS]\n")
for k, v := range bombadillo.Options {
if k == "theme" && v != "normal" && v != "inverse" {
v = "normal"
bombadillo.Options["theme"] = "normal"
}
opts.WriteString(k)
opts.WriteRune('=')
opts.WriteString(v)
opts.WriteRune('\n')
}
2019-05-01 00:18:28 +00:00
2019-09-27 05:08:57 +00:00
opts.WriteString(bkmrks)
opts.WriteString(certs)
2019-10-10 06:05:50 +00:00
return ioutil.WriteFile(bombadillo.Options["configlocation"]+"/.bombadillo.ini", []byte(opts.String()), 0644)
}
func validateOpt(opt, val string) bool {
var validOpts = map[string][]string{
2019-10-10 06:05:50 +00:00
"openhttp": []string{"true", "false"},
"theme": []string{"normal", "inverse"},
"terminalonly": []string{"true", "false"},
}
opt = strings.ToLower(opt)
val = strings.ToLower(val)
if _, ok := validOpts[opt]; ok {
for _, item := range validOpts[opt] {
if item == val {
return true
}
}
return false
} else {
return true
}
}
func lowerCaseOpt(opt, val string) string {
switch opt {
case "openhttp", "theme", "terminalonly":
return strings.ToLower(val)
default:
return val
}
}
2019-05-01 00:18:28 +00:00
func loadConfig() error {
2019-10-14 23:29:40 +00:00
// If a compile time override exists for configlocation
// set it before loading the config.
if conf_path != "" {
bombadillo.Options["configlocation"] = conf_path
}
file, err := os.Open(bombadillo.Options["configlocation"] + "/.bombadillo.ini")
if err != nil {
2019-05-01 00:18:28 +00:00
err = saveConfig()
if err != nil {
return err
}
}
2019-05-01 00:18:28 +00:00
confparser := config.NewParser(file)
settings, _ = confparser.Parse()
file.Close()
for _, v := range settings.Settings {
lowerkey := strings.ToLower(v.Key)
if lowerkey == "configlocation" {
2019-10-14 23:29:40 +00:00
// The config defaults to the home folder.
// Users cannot really edit this value. But
// a compile time override is available.
// It is still stored in the ini and as a part
// of the options map.
continue
}
2019-05-01 00:18:28 +00:00
if _, ok := bombadillo.Options[lowerkey]; ok {
2019-10-10 06:05:50 +00:00
if validateOpt(lowerkey, v.Value) {
bombadillo.Options[lowerkey] = v.Value
} else {
bombadillo.Options[lowerkey] = defaultOptions[lowerkey]
}
}
}
for i, v := range settings.Bookmarks.Titles {
bombadillo.BookMarks.Add([]string{v, settings.Bookmarks.Links[i]})
}
2019-09-27 05:08:57 +00:00
for _, v := range settings.Certs {
bombadillo.Certs.Add(v.Key, v.Value)
}
return nil
}
2019-05-01 00:18:28 +00:00
func initClient() error {
bombadillo = MakeClient(" ((( Bombadillo ))) ")
cui.SetCharMode()
err := loadConfig()
if bombadillo.Options["tlscertificate"] != "" && bombadillo.Options["tlskey"] != "" {
bombadillo.Certs.LoadCertificate(bombadillo.Options["tlscertificate"], bombadillo.Options["tlskey"])
}
return err
}
// In the event of SIGCONT, ensure the display is shown correctly. Accepts a
// signal, blocking until it is received. Once not blocked, corrects terminal
// display settings. Loops indefinitely, does not return.
2019-10-10 06:05:50 +00:00
func handleSIGCONT(c <-chan os.Signal) {
for {
<-c
cui.Tput("rmam") // turn off line wrapping
cui.Tput("smcup") // use alternate screen
cui.SetCharMode()
bombadillo.Draw()
}
2019-10-10 06:05:50 +00:00
}
func main() {
getVersion := flag.Bool("v", false, "See version number")
flag.Parse()
if *getVersion {
fmt.Printf("Bombadillo v%s\n", version)
os.Exit(0)
}
args := flag.Args()
// Build the mailcap db
// So that we can open files from gemini
mc = mailcap.NewMailcap()
2019-10-10 06:05:50 +00:00
cui.Tput("rmam") // turn off line wrapping
cui.Tput("smcup") // use alternate screen
defer cui.Exit()
2019-05-01 00:18:28 +00:00
err := initClient()
if err != nil {
// if we can't initialize we should bail out
2019-05-01 00:18:28 +00:00
panic(err)
}
// watch for SIGCONT, send it to be handled
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGCONT)
go handleSIGCONT(c)
// Start polling for terminal size changes
go bombadillo.GetSize()
if len(args) > 0 {
// If a url was passed, move it down the line
// Goroutine so keypresses can be made during
// page load
bombadillo.Visit(args[0])
} else {
// Otherwise, load the homeurl
// Goroutine so keypresses can be made during
// page load
2019-09-14 22:45:23 +00:00
bombadillo.Visit(bombadillo.Options["homeurl"])
}
// Loop indefinitely on user input
for {
bombadillo.TakeControlInput()
}
}