package main
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.sr.ht/~sircmpwn/getopt"
|
|
)
|
|
|
|
type Config struct {
|
|
Host string //irc-server
|
|
Pass string //pass
|
|
User string //user
|
|
Nick string //nick
|
|
Match []string //match
|
|
AppToken string //app-token
|
|
UserToken string //user-token
|
|
ExcludeChannels []string //exclude-channels
|
|
ExcludeUsers []string //exclude-users
|
|
}
|
|
|
|
//Partially adapted from:
|
|
//https://stackoverflow.com/questions/40022861/parsing-values-from-property-file-in-golang/46860900
|
|
func LoadConfig() (*Config, error) {
|
|
opts, optind, err := getopt.Getopts(os.Args, "h:u:p:m:n:a:t:")
|
|
if err != nil {
|
|
log.Fatalf("Unable to get options %s", err)
|
|
}
|
|
var config *Config
|
|
if optind < len(os.Args) {
|
|
filePath := os.Args[optind]
|
|
config, err = loadConfigFromFile(filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Unable to read config file: %w", err)
|
|
}
|
|
} else {
|
|
config = &Config{User: "-bell"}
|
|
}
|
|
for _, opt := range opts {
|
|
switch opt.Option {
|
|
case 'h':
|
|
config.Host = opt.Value
|
|
case 'u':
|
|
config.User = opt.Value
|
|
case 'p':
|
|
config.Pass = opt.Value
|
|
case 'm':
|
|
config.Match = splitClean(opt.Value)
|
|
case 'n':
|
|
config.Nick = opt.Value
|
|
case 'a':
|
|
config.AppToken = opt.Value
|
|
case 't':
|
|
config.UserToken = opt.Value
|
|
case 'e':
|
|
config.ExcludeChannels = splitClean(opt.Value)
|
|
case 'x':
|
|
config.ExcludeUsers = splitClean(opt.Value)
|
|
}
|
|
}
|
|
if config.Host == "" {
|
|
return nil, errors.New("Most specify host either in config file or with -h")
|
|
}
|
|
if config.Nick == "" {
|
|
config.Nick = config.User
|
|
}
|
|
if len(config.Match) == 0 {
|
|
config.Match = []string{config.Nick}
|
|
}
|
|
if config.AppToken == "" || config.UserToken == "" {
|
|
return nil, errors.New("Must specify app-token and user-token for pushover")
|
|
}
|
|
return config, nil
|
|
}
|
|
|
|
func loadConfigFromFile(path string) (*Config, error) {
|
|
if len(path) == 0 {
|
|
return nil, errors.New("Cannot read empty path")
|
|
}
|
|
config := &Config{
|
|
User: "-bell",
|
|
}
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Unable to open config file: %w", err)
|
|
}
|
|
defer file.Close()
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
//handle comments
|
|
if line[0] == '#' {
|
|
continue
|
|
}
|
|
// This is big and ugly
|
|
if equal := strings.Index(line, "="); equal >= 0 {
|
|
if key := strings.TrimSpace(line[:equal]); len(key) > 0 {
|
|
value := ""
|
|
if len(line) > equal {
|
|
value = strings.TrimSpace(line[equal+1:])
|
|
}
|
|
//TODO (noah): parse into config
|
|
switch key {
|
|
case "irc-server":
|
|
config.Host = value
|
|
case "pass":
|
|
config.Pass = value
|
|
case "user":
|
|
config.User = value
|
|
case "nick":
|
|
config.Nick = value
|
|
case "match":
|
|
config.Match = splitClean(value)
|
|
case "app-token":
|
|
config.AppToken = value
|
|
case "user-token":
|
|
config.UserToken = value
|
|
case "exclude-channels":
|
|
config.ExcludeChannels = splitClean(value)
|
|
case "exclude-users":
|
|
config.ExcludeUsers = splitClean(value)
|
|
default:
|
|
log.Printf("Unknown property in config file: %s=%s", key, value)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return nil, fmt.Errorf("Unable to scan through config file: %w", err)
|
|
}
|
|
return config, nil
|
|
}
|
|
|
|
func splitClean(s string) []string {
|
|
split := strings.Split(strings.TrimSpace(s), ",")
|
|
output := make([]string, 0, len(split))
|
|
for _, v := range split {
|
|
if v != "" && v != " " {
|
|
output = append(output, strings.TrimSpace(v))
|
|
}
|
|
}
|
|
return output
|
|
}
|