package main import ( "flag" "fmt" "log" "reflect" "strings" toml "github.com/pelletier/go-toml" // mail "gopkg.in/gomail.v2" ) type ServerConfig struct { Address string `toml:address,omitempty` Port int64 `toml:port,omitempty` Encryption string `toml:encryption,omitempty` User string `toml:user,omitempty` Password string `toml:password,omitempty` } func (s ServerConfig) String() string { return fmt.Sprintf( "\tAddress: %s\n\tPort: %d\n\tEncryption: %s\n\tUser: %s\n\tPassword: %s\n", s.Address, s.Port, s.Encryption, s.User, s.Password, ) } type Config struct { Server *ServerConfig `toml:server,omitempty` From string `toml:from,omitempty` To []string `toml:to,omitempty` Cc []string `toml:cc,omitempty` Bcc []string `toml:bcc,omitempty` Subject string `toml:subject,omitempty` Text string `toml:text,omitempty` } func (c Config) String() string { return fmt.Sprintf( "From: %s\nTo: %s\nCc: %s\nBcc: %s\nSubject: %s\nText:\n%s\nServer:\n%s", c.From, c.To, c.Cc, c.Bcc, c.Subject, c.Text, c.Server, ) } func NewConfig() *Config { server := &ServerConfig{} config := &Config{} config.Server = server return config } func debug(active bool, fmt string, msg ...interface{}) { if active { log.Printf(fmt, msg...) } } func isPresent(slice []string, val string) bool { for _, item := range slice { if item == val { return true } } return false } func isEmpty(value interface{}) bool { t := reflect.TypeOf(value) v := reflect.ValueOf(value) switch v.Kind() { case reflect.Slice: return v.Len() == 1 default: return value == reflect.Zero(t).Interface() } } func readConfig(configPath, section string) *Config { config := NewConfig() tree, err := toml.LoadFile(configPath) if err != nil { log.Panicln(err) } keys := tree.Keys() if !isPresent(keys, section) { return config } sub := tree.Get(section).(*toml.Tree) err = sub.Unmarshal(config) return config } func (c *Config) Validate() error { return nil } func merge(key string, value, obj interface{}) { if isEmpty(value) { return } var elem reflect.Value if reflect.TypeOf(obj) != reflect.TypeOf(reflect.Value{}) { log.Println("Not Value") elem = reflect.ValueOf(obj).Elem() } else { log.Println("Value") elem = obj.(reflect.Value) } field := elem.FieldByName(key) if field.CanSet() { switch field.Kind() { case reflect.Int64: field.SetInt(value.(int64)) case reflect.Bool: field.SetBool(value.(bool)) case reflect.String: field.SetString(value.(string)) case reflect.Slice: field.Set(reflect.ValueOf(value)) default: merge(key, reflect.ValueOf(value), field) //merge(key, value, field.Pointer()) } } } func (s *ServerConfig) Merge(key string, value interface{}) { merge(key, value, s) } func (c *Config) Merge(key string, value interface{}) { merge(key, value, c) } func main() { //var err error var configPath, section, serverAddress, encryption, user, password, to, cc, bcc, from, subject string var dbg bool var serverPort_ int var serverPort int64 flag.StringVar(&configPath, "conf", "/etc/sendmail.toml", "Path to a config file (defaults to /etc/sendmail.toml)") flag.StringVar(§ion, "section", "default", "Section of the conf to read (defaults to \"default\")") flag.BoolVar(&dbg, "dbg", false, "Enable debugging output") flag.StringVar(&serverAddress, "server-address", "", "The SMTP server address") flag.IntVar(&serverPort_, "server-port", 0, "The SMTP server") flag.StringVar(&encryption, "encryption", "", "The encryption type (no, starttls, tls)") flag.StringVar(&user, "user", "", "The user to authenticate with to the server") flag.StringVar(&password, "password", "", "The password to authenticate with to the server") flag.StringVar(&to, "to", "", "Comma-separated list of recipient(s)") flag.StringVar(&cc, "cc", "", "Comma-separated list of carbon-copy recipient(s)") flag.StringVar(&bcc, "bcc", "", "Comma-separated list of blind carbon-copy recipient(s)") flag.StringVar(&from, "from", "", "Sender of the mail (used as default account user to log in on the SMTP server)") flag.StringVar(&subject, "sub", "", "Subject of the mail") flag.Parse() serverPort = int64(serverPort_) debug( dbg, `parameters: conf: %s dbg: %t address: %s port: %d encryption: %s user: %s password: %s to: %s from: %s subject: %s`, configPath, dbg, serverAddress, serverPort, encryption, user, password, to, from, subject, ) config := readConfig(configPath, section) debug(dbg, "\n%s", *config) // config.Server.Merge("Address", serverAddress) // config.Server.Merge("Port", serverPort) // config.Server.Merge("Encryption", encryption) // config.Server.Merge("User", user) // config.Server.Merge("Password", password) config.Merge("Server", &ServerConfig{serverAddress, serverPort, encryption, user, password}) config.Merge("From", from) config.Merge("To", strings.Split(to, ",")) config.Merge("Cc", strings.Split(cc, ",")) config.Merge("Bcc", strings.Split(bcc, ",")) config.Merge("Subject", subject) // config.Merge("Text", text) debug(dbg, "\n%s", config) }