mirror of
https://github.com/directorz/mailfull-go.git
synced 2025-12-17 09:37:02 +00:00
239 lines
5.0 KiB
Go
239 lines
5.0 KiB
Go
package mailfull
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
// Errors for the Repository.
|
|
var (
|
|
ErrInvalidRepository = errors.New("invalid repository")
|
|
ErrNotRepository = errors.New("not a Mailfull repository (or any of the parent directories)")
|
|
ErrRepositoryExist = errors.New("a Mailfull repository exists")
|
|
)
|
|
|
|
// Errors for the operation of the Repository.
|
|
var (
|
|
ErrDomainNotExist = errors.New("Domain: not exist")
|
|
ErrUserNotExist = errors.New("User: not exist")
|
|
|
|
ErrInvalidFormatUsersPassword = errors.New("User: password file invalid format")
|
|
ErrInvalidFormatAliasDomain = errors.New("AliasDomain: file invalid format")
|
|
ErrInvalidFormatAliasUsers = errors.New("AliasUsers: file invalid format")
|
|
)
|
|
|
|
// RepositoryConfig is used to configure a Repository.
|
|
type RepositoryConfig struct {
|
|
DirDatabasePath string `toml:"dir_database"`
|
|
DirMailDataPath string `toml:"dir_maildata"`
|
|
Username string `toml:"username"`
|
|
Groupname string `toml:"groupname"`
|
|
}
|
|
|
|
// Normalize normalizes paramaters of the RepositoryConfig.
|
|
func (c *RepositoryConfig) Normalize(rootPath string) {
|
|
if !filepath.IsAbs(c.DirDatabasePath) {
|
|
c.DirDatabasePath = filepath.Join(rootPath, c.DirDatabasePath)
|
|
}
|
|
if !filepath.IsAbs(c.DirMailDataPath) {
|
|
c.DirMailDataPath = filepath.Join(rootPath, c.DirMailDataPath)
|
|
}
|
|
}
|
|
|
|
// DefaultRepositoryConfig returns a RepositoryConfig with default parameter.
|
|
func DefaultRepositoryConfig() *RepositoryConfig {
|
|
c := &RepositoryConfig{
|
|
DirDatabasePath: "./etc",
|
|
DirMailDataPath: "./domains",
|
|
Username: "mailfull",
|
|
Groupname: "mailfull",
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
// Repository represents a Repository.
|
|
type Repository struct {
|
|
*RepositoryConfig
|
|
}
|
|
|
|
// NewRepository creates a new Repository instance.
|
|
func NewRepository(c *RepositoryConfig) (*Repository, error) {
|
|
r := &Repository{
|
|
RepositoryConfig: c,
|
|
}
|
|
|
|
return r, nil
|
|
}
|
|
|
|
// OpenRepository opens a Repository and creates a new Repository instance.
|
|
func OpenRepository(basePath string) (*Repository, error) {
|
|
rootPath, err := filepath.Abs(basePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for {
|
|
configDirPath := filepath.Join(rootPath, DirNameConfig)
|
|
|
|
fi, errStat := os.Stat(configDirPath)
|
|
if errStat != nil {
|
|
if errStat.(*os.PathError).Err != syscall.ENOENT {
|
|
return nil, errStat
|
|
}
|
|
} else {
|
|
if fi.IsDir() {
|
|
break
|
|
} else {
|
|
return nil, ErrInvalidRepository
|
|
}
|
|
}
|
|
|
|
parentPath := filepath.Clean(filepath.Join(rootPath, ".."))
|
|
if rootPath == parentPath {
|
|
return nil, ErrNotRepository
|
|
}
|
|
rootPath = parentPath
|
|
}
|
|
|
|
configFilePath := filepath.Join(rootPath, DirNameConfig, FileNameConfig)
|
|
|
|
fi, err := os.Stat(configFilePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if fi.IsDir() {
|
|
return nil, ErrInvalidRepository
|
|
}
|
|
|
|
configFile, err := os.Open(configFilePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer configFile.Close()
|
|
|
|
c := DefaultRepositoryConfig()
|
|
if _, err = toml.DecodeReader(configFile, c); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c.Normalize(rootPath)
|
|
|
|
r, err := NewRepository(c)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return r, nil
|
|
}
|
|
|
|
// InitRepository initializes the input directory as a Repository.
|
|
func InitRepository(rootPath string) error {
|
|
rootPath, err := filepath.Abs(rootPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
configDirPath := filepath.Join(rootPath, DirNameConfig)
|
|
|
|
fi, err := os.Stat(configDirPath)
|
|
if err != nil {
|
|
if err.(*os.PathError).Err == syscall.ENOENT {
|
|
if err = os.Mkdir(configDirPath, 0777); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
} else {
|
|
if !fi.IsDir() {
|
|
return ErrInvalidRepository
|
|
}
|
|
}
|
|
|
|
configFilePath := filepath.Join(configDirPath, FileNameConfig)
|
|
|
|
fi, err = os.Stat(configFilePath)
|
|
if err != nil {
|
|
if err.(*os.PathError).Err != syscall.ENOENT {
|
|
return err
|
|
}
|
|
} else {
|
|
if fi.IsDir() {
|
|
return ErrInvalidRepository
|
|
}
|
|
|
|
return ErrRepositoryExist
|
|
}
|
|
|
|
configFile, err := os.Create(configFilePath)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
defer configFile.Close()
|
|
|
|
c := DefaultRepositoryConfig()
|
|
|
|
enc := toml.NewEncoder(configFile)
|
|
if err := enc.Encode(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Normalize(rootPath)
|
|
|
|
fi, err = os.Stat(c.DirDatabasePath)
|
|
if err != nil {
|
|
if err.(*os.PathError).Err == syscall.ENOENT {
|
|
if err = os.Mkdir(c.DirDatabasePath, 0777); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
} else {
|
|
if !fi.IsDir() {
|
|
return ErrInvalidRepository
|
|
}
|
|
}
|
|
|
|
fi, err = os.Stat(c.DirMailDataPath)
|
|
if err != nil {
|
|
if err.(*os.PathError).Err == syscall.ENOENT {
|
|
if err = os.Mkdir(c.DirMailDataPath, 0777); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return err
|
|
}
|
|
} else {
|
|
if !fi.IsDir() {
|
|
return ErrInvalidRepository
|
|
}
|
|
}
|
|
|
|
aliasDomainFileName := filepath.Join(c.DirMailDataPath, FileNameAliasDomains)
|
|
|
|
fi, err = os.Stat(aliasDomainFileName)
|
|
if err != nil {
|
|
if err.(*os.PathError).Err != syscall.ENOENT {
|
|
return err
|
|
}
|
|
} else {
|
|
if fi.IsDir() {
|
|
return ErrInvalidRepository
|
|
}
|
|
}
|
|
|
|
aliasDomainFile, err := os.Create(aliasDomainFileName)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
defer aliasDomainFile.Close()
|
|
|
|
return nil
|
|
}
|