view cmd/sievemgr/internal/config/config.go @ 22:fc5e6970a0d5 default tip

Add support for specifying an authorization identity on the command line
author Guido Berhoerster <guido+sievemgr@berhoerster.name>
date Wed, 17 Feb 2021 07:50:55 +0100
parents 4dff4c3f0fbb
children
line wrap: on
line source

// Copyright (C) 2020 Guido Berhoerster <guido+sievemgr@berhoerster.name>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package config

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
)

const bom = '\ufeff'

type ParserError struct {
	Message string
	LineNo  int
}

func (e *ParserError) Error() string {
	if e.LineNo > 0 {
		return fmt.Sprintf("error in line %d: %s", e.LineNo, e.Message)
	}
	return e.Message
}

func NewParserError(message string, lineNo int) *ParserError {
	return &ParserError{message, lineNo}
}

type Configuration struct {
	Accounts []*Account
	Default  *Account
}

type Account struct {
	Name     string
	Host     string
	Port     string
	User     string
	Password string
	Insecure bool
}

func Parse(data []byte, conf *Configuration) error {
	rd := bytes.NewReader(data)
	s := newScanner(bufio.NewReader(rd))
	p := &parser{s: s}
	return p.parse(conf)
}

func DefaultFilename() (string, error) {
	dir, err := os.UserConfigDir()
	if err != nil {
		return "", fmt.Errorf("failed to determine the name of the configuration file: %s", err)
	}
	return filepath.Join(dir, "sievemgr", "sievemgr.conf"), nil
}

func ParseFile(filename string, conf *Configuration) error {
	f, err := os.Open(filename)
	if os.IsNotExist(err) {
		return nil
	} else if err != nil {
		return fmt.Errorf("failed to open configuration file: %s", err)
	}
	defer f.Close()

	// configutaion file must be a regular file with no more than 0600
	// permissions
	info, err := f.Stat()
	if err != nil {
		return fmt.Errorf("failed to stat configuration file: %s", err)
	}
	mode := info.Mode()
	if !mode.IsRegular() {
		return fmt.Errorf("configuration file is not a regular file")
	}
	if perm := mode.Perm(); perm&0077 != 0 {
		return fmt.Errorf("permissions %04o on configuration file are too open", perm)
	}

	s := newScanner(bufio.NewReader(f))
	p := &parser{s: s}
	return p.parse(conf)
}