papero/config/data.go

130 lines
3.1 KiB
Go
Raw Normal View History

2021-01-09 17:06:13 +01:00
package config
import (
"fmt"
"log"
"os/exec"
"strconv"
"strings"
"github.com/BurntSushi/toml"
)
// maybeInt is an integer that may be nil
type maybeInt struct {
int
bool
}
func (m maybeInt) empty() bool {
return !m.bool
}
func (m maybeInt) value() int {
return m.int
}
func initMaybeInt(value int) maybeInt {
return maybeInt{value, true}
}
func (m *maybeInt) UnmarshalText(text []byte) error {
var err error
var i int64
if text != nil {
str := string(text)
i, err = strconv.ParseInt(str, 10, 64)
m.int = int(i)
m.bool = true
}
return err
}
type fileConfig struct {
MailboxPath string `toml:"mailbox_path"`
Accounts []account `toml:"account"`
DefaultMessages maybeInt `toml:"default_messages"`
}
type account struct {
Name string `toml:"name"`
MailboxPath string `toml:"mailbox_path"`
ConnectionInfo *connectionInfo `toml:"connection"`
ExcludedFolders []string `toml:"excluded_folders"`
Messages maybeInt `toml:"messages"`
}
type connectionInfo struct {
Host string `toml:"hostname"`
Port int `toml:"port"`
Username string `toml:"username"`
PasswordExec *ShellScript `toml:"password_exec"`
PasswordFile string `toml:"password_file"`
Password string `toml:"password"`
}
func (c *connectionInfo) String() string {
var res string
res += "{"
res += fmt.Sprintf("Host: %s, ", c.Host)
res += fmt.Sprintf("Port: %d, ", c.Port)
res += fmt.Sprintf("Username: %s, ", c.Username)
res += fmt.Sprintf("Password: **********, ")
res += fmt.Sprintf("PasswordFile: %s, ", c.PasswordFile)
res += fmt.Sprintf("PasswordExec: %s}", c.PasswordExec)
return res
}
// ShellScript might be either:
// - the path to an executable
// - an executable in path
// - a shell command with its argument
// all these must return on stdout the password after successful execution.
type ShellScript struct {
Executable string
}
func (s *ShellScript) UnmarshalText(text []byte) error {
s.Executable = string(text)
return nil
}
func (s *ShellScript) String() string {
return s.Executable
}
// Present indicates if the value has been filled in into the config
func (s *ShellScript) Present() bool {
if s != nil {
return s.Executable != ""
}
return false
}
// Run tries to execute the command, first looking for a corresponding executable and
// invoking it, then invoking the string as a command followed by its parameters.
func (s *ShellScript) Run() (string, error) {
if path, err := exec.LookPath(s.Executable); err == nil {
return doExec(path)
}
parts := strings.Split(s.Executable, " ")
return doExec(parts[0], parts[1:]...)
}
func doExec(path string, args ...string) (string, error) {
cmd := exec.Command(path, args...)
out, err := cmd.Output()
if err != nil {
log.Println("Error running:", cmd)
return "", err
}
return string(out), nil
}
// parseFile reads the given config file and, if succeeding, returns a *FileConfig.
func parseFile(path string) (*fileConfig, error) {
newConfig := fileConfig{}
_, err := toml.DecodeFile(path, &newConfig)
return &newConfig, err
}