1
0
mirror of https://github.com/directorz/mailfull-go.git synced 2025-12-20 19:17:02 +00:00

66 Commits

Author SHA1 Message Date
teru
e1ecad7df3 Merge pull request #43 from directorz/release/v1.0.3
Release/v1.0.3
2018-03-16 12:21:25 +09:00
teru
0f0a3835fc Bump up version to v1.0.3 2018-03-16 12:19:53 +09:00
teru
a145712856 Update vendor packages 2018-03-16 12:19:38 +09:00
teru
ad18a41b64 Merge pull request #41 from directorz/feature/fix_removed_user
Feature/fix removed user
2018-03-16 12:17:15 +09:00
teru
ac6a8526b1 Fix userlist 2018-03-16 12:16:05 +09:00
teru
067c8f6903 Merge pull request #40 from directorz/feature/build
Feature/build
2018-03-16 11:29:35 +09:00
teru
e7254c6df6 Use internal ghr command 2018-03-16 11:27:48 +09:00
teru
8ecd1f0f79 Update go to 1.10 2018-03-16 11:07:40 +09:00
teru
de6ddf7e1b Simplify PHONY targets 2018-03-16 11:06:59 +09:00
teru
58b508b7fa Merge pull request #39 from directorz/release/v1.0.2
Release/v1.0.2
2017-12-13 15:24:10 +09:00
teru
78ba1d2674 Bump version to v1.0.2 2017-12-13 15:22:57 +09:00
teru
b4461b66ca Updated go version: 1.9.2 2017-12-13 15:22:25 +09:00
teru
afb8e4eaf4 Merge pull request #37 from directorz/release/v1.0.1
Release/v1.0.1
2017-12-13 15:17:58 +09:00
teru
e32523d0b2 Bump version to v1.0.1 2017-12-13 15:16:35 +09:00
teru
188be4c3e8 Update libraries 2017-12-13 15:15:54 +09:00
teru
de4bddc161 Merge pull request #35 from directorz/feature/dep_flag
Added `-vendor-only` flag
2017-12-13 15:13:05 +09:00
teru
f618eb24e6 Added -vendor-only flag 2017-12-13 15:12:07 +09:00
teru
096193d93d Merge pull request #34 from directorz/feature/show_runtime_version
Now show runtime version in `mailfull --version`
2017-12-13 15:11:23 +09:00
teru
e32ed61771 Now show runtime version in mailfull --version 2017-12-13 15:07:44 +09:00
teru
3ae4d8d590 Merge pull request #30 from directorz/feature/v1.0.0
Feature/v1.0.0
2017-07-25 13:05:27 +09:00
teru
d4343eacce Merge pull request #29 from directorz/feature/bump_version
Bump version to v1.0.0
2017-07-25 13:05:04 +09:00
teru
a97a9e343b Bump version to v1.0.0 2017-07-25 13:04:25 +09:00
teru
f61d18f31f Merge pull request #28 from directorz/feature/remove_type_maildata
Remove type MailData
2017-07-25 13:02:30 +09:00
teru
9c92ac9656 Remove type MailData 2017-07-25 12:48:54 +09:00
teru
30f0279751 Merge pull request #27 from directorz/feature/remove_types_for_sort
Remove types for sort.Interface #26
2017-07-25 12:31:39 +09:00
teru
c7e56f26af Remove types for sort.Interface 2017-07-25 12:29:23 +09:00
teru
58b50cb3f6 Merge pull request #25 from directorz/feature/flatten
Feature/flatten
2017-07-25 11:58:26 +09:00
teru
146ab299d0 Use Errorf 2017-07-25 11:57:30 +09:00
teru
2e87209ad2 Move Meta to cmd package 2017-07-25 11:40:51 +09:00
teru
5a178c350b Change structs name 2017-07-25 11:35:42 +09:00
teru
b884655a7c Renamed 2017-07-25 11:22:11 +09:00
teru
552ed95a0f Integrate subpackage 2017-07-25 11:19:25 +09:00
teru
2bb46731d0 Merge pull request #24 from directorz/feature/cosme
cosmetic
2017-07-25 11:06:30 +09:00
teru
5a64a543ca cosmetic 2017-07-25 11:05:28 +09:00
teru
d0dd68e2b6 Merge pull request #23 from directorz/feature/build
Feature/build
2017-07-25 11:03:49 +09:00
teru
1daea44e49 Use golang:1.8.3 2017-07-25 11:01:55 +09:00
teru
3ac5856917 Use golang/dep instead of glide #21 2017-07-25 10:43:07 +09:00
teru
3cf4815565 Merge pull request #20 from directorz/feature/update_golang
Feature/update golang
2016-12-19 13:25:09 +09:00
teru
52e5d32c01 Bump version to v0.0.7 2016-12-19 13:24:41 +09:00
teru
b1d13b49f5 Use golang:1.7.4 2016-12-19 13:24:16 +09:00
teru
46cf349015 Merge pull request #19 from directorz/feature/vendoring_glide
Feature/vendoring glide
2016-09-29 12:12:28 +09:00
teru
9be507565d Bump version to v0.0.6 2016-09-29 12:12:03 +09:00
teru
58b4e49fe8 Use golang:1.7.1 2016-09-29 12:10:15 +09:00
teru
cb6e9ce2c5 Use Glide instead of gom 2016-09-29 12:08:07 +09:00
teru
db554a1da1 Merge pull request #18 from directorz/feature/no_commit_flag
Feature/no commit flag
2016-08-28 17:12:46 +09:00
teru
708e132ccc Bump version to v0.0.5 2016-08-28 17:10:32 +09:00
teru
3a1d4a588c Add a option to subcommands #7 2016-08-28 17:09:09 +09:00
teru
50d429ad78 Implement to parse -n flag #7 2016-08-28 17:06:52 +09:00
teru
0118652074 Merge pull request #17 from directorz/feature/implements
Feature/implements
2016-08-23 18:08:22 +09:00
teru
bf4b63556a Bump version to v0.0.4 2016-08-23 18:05:52 +09:00
teru
24ee3c26b0 Rename a file 2016-08-23 18:04:55 +09:00
teru
49dd05f3bf Change output format of domains subcommands #8 2016-08-23 18:04:30 +09:00
teru
009ee84e63 Implement subcommands: domaindisable, domainenable #8 2016-08-23 18:04:08 +09:00
teru
281d5a4a9d Implement disable/enable a Domain #8 2016-08-23 18:03:45 +09:00
teru
c2dca41057 Add a field to Domain struct 2016-08-23 13:40:20 +09:00
teru
4f99f11732 Update installation guide 2016-08-23 13:39:35 +09:00
teru
a3d3684fda Merge pull request #16 from directorz/feature/implements
Feature/implements
2016-08-22 15:20:37 +09:00
teru
c183bba7aa Bump version to v0.0.3 2016-08-22 15:19:59 +09:00
teru
b52a7cde7f Add support for creating GitHub Releases page 2016-08-22 15:15:08 +09:00
teru
0926ffd318 Change the path of session cache database 2016-08-18 20:33:19 +09:00
teru
c9201c8fc1 Fix README.md 2016-08-18 19:53:43 +09:00
teru
fe16bb86f9 Disable to delete postmaster #14 2016-08-18 19:53:16 +09:00
teru
bd6228197a cosmetic changes 2016-08-18 19:52:42 +09:00
teru
1329747f54 Merge pull request #15 from directorz/feature/documentation
Feature/documentation
2016-08-18 12:18:11 +09:00
teru
ab3c3315f9 Add configuration guide 2016-08-18 12:11:17 +09:00
teru
a76596c348 Add migration guide from directorz/mailfull #9 2016-08-18 12:09:44 +09:00
47 changed files with 1219 additions and 586 deletions

7
.gitignore vendored
View File

@@ -1 +1,6 @@
/cli/mailfull/mailfull
/vendor
/build
/release
/github_token
/cmd/mailfull/mailfull

74
Gopkg.lock generated Normal file
View File

@@ -0,0 +1,74 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/BurntSushi/toml"
packages = ["."]
revision = "b26d9c308763d68093482582cea63d69be07a0f0"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "github.com/armon/go-radix"
packages = ["."]
revision = "1fca145dffbcaa8fe914309b1ec0cfc67500fe61"
[[projects]]
name = "github.com/bgentry/speakeasy"
packages = ["."]
revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd"
version = "v0.1.0"
[[projects]]
branch = "master"
name = "github.com/hashicorp/errwrap"
packages = ["."]
revision = "7554cd9344cec97297fa6649b055a8c98c2a1e55"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-multierror"
packages = ["."]
revision = "b7773ae218740a7be65057fc60b366a49b538a44"
[[projects]]
branch = "master"
name = "github.com/jsimonetti/pwscheme"
packages = ["ssha"]
revision = "76804708ecad54773871b35dbaa44f517973e395"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
branch = "master"
name = "github.com/mitchellh/cli"
packages = ["."]
revision = "518dc677a1e1222682f4e7db06721942cb8e9e4c"
[[projects]]
name = "github.com/posener/complete"
packages = [
".",
"cmd",
"cmd/install",
"match"
]
revision = "98eb9847f27ba2008d380a32c98be474dea55bdf"
version = "v1.1.1"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "cc7307a45468e49eaf2997c890f14aa03a26917b"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "d88d2668ae10b500606e3ebb1e719897e62e423f5ede8e4b470d12c1d255fe31"
solver-name = "gps-cdcl"
solver-version = 1

0
Gopkg.toml Normal file
View File

78
Makefile Normal file
View File

@@ -0,0 +1,78 @@
GOVERSION=$(shell go version)
THIS_GOOS=$(word 1,$(subst /, ,$(lastword $(GOVERSION))))
THIS_GOARCH=$(word 2,$(subst /, ,$(lastword $(GOVERSION))))
GOOS?=$(THIS_GOOS)
GOARCH?=$(THIS_GOARCH)
DIR_PKG=$(subst /src/github.com/directorz/mailfull-go,/pkg,$(PWD))
DIR_BUILD=build
DIR_RELEASE=release
VERSION=$(patsubst "%",%,$(lastword $(shell grep 'const Version' version.go)))
GITTAG=$(shell git rev-parse --short HEAD)
default: build
FORCE:
.PHONY: FORCE
$(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/dep:
mkdir -p /tmp/go
GOPATH=/tmp/go go get -d -v github.com/golang/dep
GOPATH=/tmp/go go build -v -o $(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/dep github.com/golang/dep/cmd/dep
rm -rf /tmp/go
dep: $(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/dep
$(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/ghr:
mkdir -p /tmp/go
GOPATH=/tmp/go go get -d -v github.com/tcnksm/ghr
GOPATH=/tmp/go go build -v -o $(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/ghr github.com/tcnksm/ghr
rm -rf /tmp/go
ghr: $(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/ghr
installdeps: dep
$(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/dep ensure -v -vendor-only
build: FORCE
go build -v -ldflags "-X main.gittag=$(GITTAG)" -o $(DIR_BUILD)/mailfull_$(GOOS)_$(GOARCH)/mailfull cmd/mailfull/*.go
.build-docker:
docker run --rm -v $(DIR_PKG):/go/pkg -v $(PWD):/go/src/github.com/directorz/mailfull-go -w /go/src/github.com/directorz/mailfull-go \
-e GOOS=$(GOOS) -e GOARCH=$(GOARCH) golang:1.10 \
go build -v -ldflags "-X main.gittag=$(GITTAG)" -o $(DIR_BUILD)/mailfull_$(GOOS)_$(GOARCH)/mailfull cmd/mailfull/*.go
build-linux-amd64:
@$(MAKE) .build-docker GOOS=linux GOARCH=amd64
build-linux-386:
@$(MAKE) .build-docker GOOS=linux GOARCH=386
release: release-linux-amd64 release-linux-386
release-linux-amd64: build-linux-amd64
@$(MAKE) release-doc release-targz GOOS=linux GOARCH=amd64
release-linux-386: build-linux-386
@$(MAKE) release-doc release-targz GOOS=linux GOARCH=386
release-doc:
cp -a README.md doc $(DIR_BUILD)/mailfull_$(GOOS)_$(GOARCH)
release-targz: dir-$(DIR_RELEASE)
tar zcfp $(DIR_RELEASE)/mailfull_$(GOOS)_$(GOARCH).tar.gz -C $(DIR_BUILD) mailfull_$(GOOS)_$(GOARCH)
dir-$(DIR_RELEASE):
mkdir -p $(DIR_RELEASE)
release-upload: ghr release-linux-amd64 release-linux-386 release-github-token
$(DIR_BUILD)/bin/$(THIS_GOOS)_$(THIS_GOARCH)/ghr -u directorz -r mailfull-go -t $(shell cat github_token) --replace --draft $(VERSION) $(DIR_RELEASE)
release-github-token: github_token
@echo "file \"github_token\" is required"
clean:
-rm -rf $(DIR_BUILD)
-rm -rf $(DIR_RELEASE)

View File

@@ -16,6 +16,11 @@ Features
Installation
------------
### Binary
You can download archive file from [releases page](https://github.com/directorz/mailfull-go/releases) .
Download and unpack the archive file, and put the binary file to somewhere you want.
### go get
Installed in `$GOPATH/bin`
@@ -39,6 +44,7 @@ Initialize a directory as a Mailfull repository.
```
$ mkdir /path/to/repo && cd /path/to/repo
$ mailfull init
$ mailfull commit
```
Generate configurations for Postfix and Dovecot. (Edit as needed.)
@@ -66,3 +72,8 @@ Add a new domain and user.
```
Enjoy!
More info
---------
See [documentation](doc/README.md)

View File

@@ -15,13 +15,6 @@ type AliasDomain struct {
target string
}
// AliasDomainSlice attaches the methods of sort.Interface to []*AliasDomain.
type AliasDomainSlice []*AliasDomain
func (p AliasDomainSlice) Len() int { return len(p) }
func (p AliasDomainSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }
func (p AliasDomainSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// NewAliasDomain creates a new AliasDomain instance.
func NewAliasDomain(name, target string) (*AliasDomain, error) {
ad := &AliasDomain{}
@@ -190,7 +183,7 @@ func (r *Repository) writeAliasDomainsFile(aliasDomains []*AliasDomain) error {
}
defer file.Close()
sort.Sort(AliasDomainSlice(aliasDomains))
sort.Slice(aliasDomains, func(i, j int) bool { return aliasDomains[i].Name() < aliasDomains[j].Name() })
for _, aliasDomain := range aliasDomains {
if _, err := fmt.Fprintf(file, "%s:%s\n", aliasDomain.Name(), aliasDomain.Target()); err != nil {

View File

@@ -21,13 +21,6 @@ type AliasUser struct {
targets []string
}
// AliasUserSlice attaches the methods of sort.Interface to []*AliasUser.
type AliasUserSlice []*AliasUser
func (p AliasUserSlice) Len() int { return len(p) }
func (p AliasUserSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }
func (p AliasUserSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// NewAliasUser creates a new AliasUser instance.
func NewAliasUser(name string, targets []string) (*AliasUser, error) {
au := &AliasUser{}
@@ -233,7 +226,7 @@ func (r *Repository) writeAliasUsersFile(domainName string, aliasUsers []*AliasU
}
defer file.Close()
sort.Sort(AliasUserSlice(aliasUsers))
sort.Slice(aliasUsers, func(i, j int) bool { return aliasUsers[i].Name() < aliasUsers[j].Name() })
for _, aliasUser := range aliasUsers {
if _, err := fmt.Fprintf(file, "%s:%s\n", aliasUser.Name(), strings.Join(aliasUser.Targets(), ",")); err != nil {

View File

@@ -1,26 +1,27 @@
package command
package main
import (
"fmt"
mailfull "github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// AliasDomainAddCommand represents a AliasDomainAddCommand.
type AliasDomainAddCommand struct {
Meta
// CmdAliasDomainAdd represents a CmdAliasDomainAdd.
type CmdAliasDomainAdd struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *AliasDomainAddCommand) Synopsis() string {
func (c *CmdAliasDomainAdd) Synopsis() string {
return "Create a new aliasdomain."
}
// Help returns long-form help text.
func (c *AliasDomainAddCommand) Help() string {
func (c *CmdAliasDomainAdd) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain target
%s %s [-n] domain target
Description:
%s
@@ -30,6 +31,10 @@ Required Args:
The domain name that you want to create.
target
The target domain name.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -38,7 +43,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *AliasDomainAddCommand) Run(args []string) int {
func (c *CmdAliasDomainAdd) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 2 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -49,30 +60,26 @@ func (c *AliasDomainAddCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
aliasDomain, err := mailfull.NewAliasDomain(aliasDomainName, targetDomainName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.AliasDomainCreate(aliasDomain); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,26 +1,27 @@
package command
package main
import (
"fmt"
mailfull "github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// AliasDomainDelCommand represents a AliasDomainDelCommand.
type AliasDomainDelCommand struct {
Meta
// CmdAliasDomainDel represents a CmdAliasDomainDel.
type CmdAliasDomainDel struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *AliasDomainDelCommand) Synopsis() string {
func (c *CmdAliasDomainDel) Synopsis() string {
return "Delete a aliasdomain."
}
// Help returns long-form help text.
func (c *AliasDomainDelCommand) Help() string {
func (c *CmdAliasDomainDel) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain
%s %s [-n] domain
Description:
%s
@@ -28,6 +29,10 @@ Description:
Required Args:
domain
The domain name that you want to delete.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -36,7 +41,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *AliasDomainDelCommand) Run(args []string) int {
func (c *CmdAliasDomainDel) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -46,24 +57,20 @@ func (c *AliasDomainDelCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.AliasDomainRemove(aliasDomainName); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,24 +1,25 @@
package command
package main
import (
"fmt"
"sort"
mailfull "github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// AliasDomainsCommand represents a AliasDomainsCommand.
type AliasDomainsCommand struct {
Meta
// CmdAliasDomains represents a CmdAliasDomains.
type CmdAliasDomains struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *AliasDomainsCommand) Synopsis() string {
func (c *CmdAliasDomains) Synopsis() string {
return "Show aliasdomains."
}
// Help returns long-form help text.
func (c *AliasDomainsCommand) Help() string {
func (c *CmdAliasDomains) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s [domain]
@@ -37,7 +38,7 @@ Optional Args:
}
// Run runs the command and returns the exit status.
func (c *AliasDomainsCommand) Run(args []string) int {
func (c *CmdAliasDomains) Run(args []string) int {
if len(args) > 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -50,16 +51,16 @@ func (c *AliasDomainsCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
aliasDomains, err := repo.AliasDomains()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
sort.Sort(mailfull.AliasDomainSlice(aliasDomains))
sort.Slice(aliasDomains, func(i, j int) bool { return aliasDomains[i].Name() < aliasDomains[j].Name() })
for _, aliasDomain := range aliasDomains {
if targetDomainName != "" {

View File

@@ -1,27 +1,28 @@
package command
package main
import (
"fmt"
"strings"
mailfull "github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// AliasUserAddCommand represents a AliasUserAddCommand.
type AliasUserAddCommand struct {
Meta
// CmdAliasUserAdd represents a CmdAliasUserAdd.
type CmdAliasUserAdd struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *AliasUserAddCommand) Synopsis() string {
func (c *CmdAliasUserAdd) Synopsis() string {
return "Create a new aliasuser."
}
// Help returns long-form help text.
func (c *AliasUserAddCommand) Help() string {
func (c *CmdAliasUserAdd) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s address target [target...]
%s %s [-n] address target [target...]
Description:
%s
@@ -31,6 +32,10 @@ Required Args:
The email address that you want to create.
target
Target email addresses.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -39,7 +44,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *AliasUserAddCommand) Run(args []string) int {
func (c *CmdAliasUserAdd) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) < 2 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -58,30 +69,26 @@ func (c *AliasUserAddCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
aliasUser, err := mailfull.NewAliasUser(aliasUserName, targets)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.AliasUserCreate(domainName, aliasUser); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,27 +1,28 @@
package command
package main
import (
"fmt"
"strings"
mailfull "github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// AliasUserDelCommand represents a AliasUserDelCommand.
type AliasUserDelCommand struct {
Meta
// CmdAliasUserDel represents a CmdAliasUserDel.
type CmdAliasUserDel struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *AliasUserDelCommand) Synopsis() string {
func (c *CmdAliasUserDel) Synopsis() string {
return "Delete a aliasuser."
}
// Help returns long-form help text.
func (c *AliasUserDelCommand) Help() string {
func (c *CmdAliasUserDel) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s address
%s %s [-n] address
Description:
%s
@@ -29,6 +30,10 @@ Description:
Required Args:
address
The email address that you want to delete.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -37,7 +42,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *AliasUserDelCommand) Run(args []string) int {
func (c *CmdAliasUserDel) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -54,24 +65,20 @@ func (c *AliasUserDelCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.AliasUserRemove(domainName, aliasUserName); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,27 +1,28 @@
package command
package main
import (
"fmt"
"strings"
mailfull "github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// AliasUserModCommand represents a AliasUserModCommand.
type AliasUserModCommand struct {
Meta
// CmdAliasUserMod represents a CmdAliasUserMod.
type CmdAliasUserMod struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *AliasUserModCommand) Synopsis() string {
func (c *CmdAliasUserMod) Synopsis() string {
return "Modify a aliasuser."
}
// Help returns long-form help text.
func (c *AliasUserModCommand) Help() string {
func (c *CmdAliasUserMod) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s address target [target...]
%s %s [-n] address target [target...]
Description:
%s
@@ -31,6 +32,10 @@ Required Args:
The email address that you want to modify.
target
Target email addresses.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -39,7 +44,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *AliasUserModCommand) Run(args []string) int {
func (c *CmdAliasUserMod) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) < 2 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -58,39 +69,35 @@ func (c *AliasUserModCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
aliasUser, err := repo.AliasUser(domainName, aliasUserName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if aliasUser == nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", mailfull.ErrAliasUserNotExist)
c.Meta.Errorf("%v\n", mailfull.ErrAliasUserNotExist)
return 1
}
if err := aliasUser.SetTargets(targets); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.AliasUserUpdate(domainName, aliasUser); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,24 +1,25 @@
package command
package main
import (
"fmt"
"sort"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// AliasUsersCommand represents a AliasUsersCommand.
type AliasUsersCommand struct {
Meta
// CmdAliasUsers represents a CmdAliasUsers.
type CmdAliasUsers struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *AliasUsersCommand) Synopsis() string {
func (c *CmdAliasUsers) Synopsis() string {
return "Show aliasusers."
}
// Help returns long-form help text.
func (c *AliasUsersCommand) Help() string {
func (c *CmdAliasUsers) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain
@@ -37,7 +38,7 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *AliasUsersCommand) Run(args []string) int {
func (c *CmdAliasUsers) Run(args []string) int {
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -47,16 +48,16 @@ func (c *AliasUsersCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
aliasUsers, err := repo.AliasUsers(targetDomainName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
sort.Sort(mailfull.AliasUserSlice(aliasUsers))
sort.Slice(aliasUsers, func(i, j int) bool { return aliasUsers[i].Name() < aliasUsers[j].Name() })
for _, aliasUser := range aliasUsers {
fmt.Fprintf(c.UI.Writer, "%s\n", aliasUser.Name())

View File

@@ -1,23 +1,24 @@
package command
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// CatchAllCommand represents a CatchAllCommand.
type CatchAllCommand struct {
Meta
// CmdCatchAll represents a CmdCatchAll.
type CmdCatchAll struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *CatchAllCommand) Synopsis() string {
func (c *CmdCatchAll) Synopsis() string {
return "Show a catchall user."
}
// Help returns long-form help text.
func (c *CatchAllCommand) Help() string {
func (c *CmdCatchAll) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain
@@ -36,7 +37,7 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *CatchAllCommand) Run(args []string) int {
func (c *CmdCatchAll) Run(args []string) int {
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -46,13 +47,13 @@ func (c *CatchAllCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
catchAllUser, err := repo.CatchAllUser(domainName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,26 +1,27 @@
package command
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// CatchAllSetCommand represents a CatchAllSetCommand.
type CatchAllSetCommand struct {
Meta
// CmdCatchAllSet represents a CmdCatchAllSet.
type CmdCatchAllSet struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *CatchAllSetCommand) Synopsis() string {
func (c *CmdCatchAllSet) Synopsis() string {
return "Set a catchall user."
}
// Help returns long-form help text.
func (c *CatchAllSetCommand) Help() string {
func (c *CmdCatchAllSet) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain user
%s %s [-n] domain user
Description:
%s
@@ -30,6 +31,10 @@ Required Args:
The domain name.
user
The user name that you want to set as catchall user.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -38,7 +43,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *CatchAllSetCommand) Run(args []string) int {
func (c *CmdCatchAllSet) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 2 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -49,30 +60,26 @@ func (c *CatchAllSetCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
catchAllUser, err := mailfull.NewCatchAllUser(userName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.CatchAllUserSet(domainName, catchAllUser); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,26 +1,27 @@
package command
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// CatchAllUnsetCommand represents a CatchAllUnsetCommand.
type CatchAllUnsetCommand struct {
Meta
// CmdCatchAllUnset represents a CmdCatchAllUnset.
type CmdCatchAllUnset struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *CatchAllUnsetCommand) Synopsis() string {
func (c *CmdCatchAllUnset) Synopsis() string {
return "Unset a catchall user."
}
// Help returns long-form help text.
func (c *CatchAllUnsetCommand) Help() string {
func (c *CmdCatchAllUnset) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain
%s %s [-n] domain
Description:
%s
@@ -28,6 +29,10 @@ Description:
Required Args:
domain
The domain name.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -36,7 +41,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *CatchAllUnsetCommand) Run(args []string) int {
func (c *CmdCatchAllUnset) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -46,24 +57,20 @@ func (c *CatchAllUnsetCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.CatchAllUserUnset(domainName); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -0,0 +1,49 @@
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// CmdCommit represents a CmdCommit.
type CmdCommit struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *CmdCommit) Synopsis() string {
return "Create databases from the structure of the MailData directory."
}
// Help returns long-form help text.
func (c *CmdCommit) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s
Description:
%s
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
return txt[1:]
}
// Run runs the command and returns the exit status.
func (c *CmdCommit) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
return 0
}

View File

@@ -1,26 +1,27 @@
package command
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// DomainAddCommand represents a DomainAddCommand.
type DomainAddCommand struct {
Meta
// CmdDomainAdd represents a CmdDomainAdd.
type CmdDomainAdd struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *DomainAddCommand) Synopsis() string {
func (c *CmdDomainAdd) Synopsis() string {
return "Create a new domain and postmaster."
}
// Help returns long-form help text.
func (c *DomainAddCommand) Help() string {
func (c *CmdDomainAdd) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain
%s %s [-n] domain
Description:
%s
@@ -28,6 +29,10 @@ Description:
Required Args:
domain
The domain name that you want to create.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -36,7 +41,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *DomainAddCommand) Run(args []string) int {
func (c *CmdDomainAdd) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -46,41 +57,37 @@ func (c *DomainAddCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
domain, err := mailfull.NewDomain(domainName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.DomainCreate(domain); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
user, err := mailfull.NewUser("postmaster", mailfull.NeverMatchHashedPassword, nil)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.UserCreate(domainName, user); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,26 +1,27 @@
package command
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// DomainDelCommand represents a DomainDelCommand.
type DomainDelCommand struct {
Meta
// CmdDomainDel represents a CmdDomainDel.
type CmdDomainDel struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *DomainDelCommand) Synopsis() string {
func (c *CmdDomainDel) Synopsis() string {
return "Delete and backup a domain."
}
// Help returns long-form help text.
func (c *DomainDelCommand) Help() string {
func (c *CmdDomainDel) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain
%s %s [-n] domain
Description:
%s
@@ -28,6 +29,10 @@ Description:
Required Args:
domain
The domain name that you want to delete.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -36,7 +41,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *DomainDelCommand) Run(args []string) int {
func (c *CmdDomainDel) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -46,24 +57,20 @@ func (c *DomainDelCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.DomainRemove(domainName); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -0,0 +1,90 @@
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// CmdDomainDisable represents a CmdDomainDisable.
type CmdDomainDisable struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *CmdDomainDisable) Synopsis() string {
return "Disable a domain temporarily."
}
// Help returns long-form help text.
func (c *CmdDomainDisable) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s [-n] domain
Description:
%s
Required Args:
domain
The domain name that you want to disable.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
return txt[1:]
}
// Run runs the command and returns the exit status.
func (c *CmdDomainDisable) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
domainName := args[0]
repo, err := mailfull.OpenRepository(".")
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
domain, err := repo.Domain(domainName)
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
if domain == nil {
c.Meta.Errorf("%v\n", mailfull.ErrDomainNotExist)
return 1
}
domain.SetDisabled(true)
if err := repo.DomainUpdate(domain); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
if noCommit {
return 0
}
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
return 0
}

View File

@@ -0,0 +1,90 @@
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// CmdDomainEnable represents a CmdDomainEnable.
type CmdDomainEnable struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *CmdDomainEnable) Synopsis() string {
return "Enable a domain."
}
// Help returns long-form help text.
func (c *CmdDomainEnable) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s [-n] domain
Description:
%s
Required Args:
domain
The domain name that you want to enable.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
return txt[1:]
}
// Run runs the command and returns the exit status.
func (c *CmdDomainEnable) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
domainName := args[0]
repo, err := mailfull.OpenRepository(".")
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
domain, err := repo.Domain(domainName)
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
if domain == nil {
c.Meta.Errorf("%v\n", mailfull.ErrDomainNotExist)
return 1
}
domain.SetDisabled(false)
if err := repo.DomainUpdate(domain); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
if noCommit {
return 0
}
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
return 0
}

View File

@@ -0,0 +1,62 @@
package main
import (
"fmt"
"sort"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// CmdDomains represents a CmdDomains.
type CmdDomains struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *CmdDomains) Synopsis() string {
return "Show domains."
}
// Help returns long-form help text.
func (c *CmdDomains) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s
Description:
%s
Disabled domains are marked "!" the beginning.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
return txt[1:]
}
// Run runs the command and returns the exit status.
func (c *CmdDomains) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
domains, err := repo.Domains()
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
sort.Slice(domains, func(i, j int) bool { return domains[i].Name() < domains[j].Name() })
for _, domain := range domains {
disableStr := ""
if domain.Disabled() {
disableStr = "!"
}
fmt.Fprintf(c.UI.Writer, "%s%s\n", disableStr, domain.Name())
}
return 0
}

View File

@@ -1,23 +1,24 @@
package command
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// GenConfigCommand represents a GenConfigCommand.
type GenConfigCommand struct {
Meta
// CmdGenConfig represents a CmdGenConfig.
type CmdGenConfig struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *GenConfigCommand) Synopsis() string {
func (c *CmdGenConfig) Synopsis() string {
return "Write a Postfix or Dovecot configuration to stdout."
}
// Help returns long-form help text.
func (c *GenConfigCommand) Help() string {
func (c *CmdGenConfig) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s name
@@ -37,7 +38,7 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *GenConfigCommand) Run(args []string) int {
func (c *CmdGenConfig) Run(args []string) int {
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -47,7 +48,7 @@ func (c *GenConfigCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
@@ -59,7 +60,7 @@ func (c *GenConfigCommand) Run(args []string) int {
fmt.Fprintf(c.UI.Writer, "%s", repo.GenerateConfigDovecot())
default:
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] Specify \"postfix\" or \"dovecot\".\n")
c.Meta.Errorf("Specify \"postfix\" or \"dovecot\".\n")
return 1
}

View File

@@ -1,23 +1,24 @@
package command
package main
import (
"fmt"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// InitCommand represents a InitCommand.
type InitCommand struct {
Meta
// CmdInit represents a CmdInit.
type CmdInit struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *InitCommand) Synopsis() string {
func (c *CmdInit) Synopsis() string {
return "Initializes current directory as a Mailfull repository."
}
// Help returns long-form help text.
func (c *InitCommand) Help() string {
func (c *CmdInit) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s
@@ -32,9 +33,9 @@ Description:
}
// Run runs the command and returns the exit status.
func (c *InitCommand) Run(args []string) int {
func (c *CmdInit) Run(args []string) int {
if err := mailfull.InitRepository("."); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,27 +1,28 @@
package command
package main
import (
"fmt"
"strings"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// UserAddCommand represents a UserAddCommand.
type UserAddCommand struct {
Meta
// CmdUserAdd represents a CmdUserAdd.
type CmdUserAdd struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *UserAddCommand) Synopsis() string {
func (c *CmdUserAdd) Synopsis() string {
return "Create a new user."
}
// Help returns long-form help text.
func (c *UserAddCommand) Help() string {
func (c *CmdUserAdd) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s address
%s %s [-n] address
Description:
%s
@@ -29,6 +30,10 @@ Description:
Required Args:
address
The email address that you want to create.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -37,7 +42,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *UserAddCommand) Run(args []string) int {
func (c *CmdUserAdd) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -55,30 +66,26 @@ func (c *UserAddCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
user, err := mailfull.NewUser(userName, mailfull.NeverMatchHashedPassword, nil)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if err := repo.UserCreate(domainName, user); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,25 +1,26 @@
package command
package main
import (
"fmt"
"strings"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
"github.com/jsimonetti/pwscheme/ssha"
)
// UserCheckPwCommand represents a UserCheckPwCommand.
type UserCheckPwCommand struct {
Meta
// CmdUserCheckPw represents a CmdUserCheckPw.
type CmdUserCheckPw struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *UserCheckPwCommand) Synopsis() string {
func (c *CmdUserCheckPw) Synopsis() string {
return "Check user's password."
}
// Help returns long-form help text.
func (c *UserCheckPwCommand) Help() string {
func (c *CmdUserCheckPw) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s address [password]
@@ -34,7 +35,7 @@ Required Args:
Optional Args:
password
Specify the password instead of your typing.
This option is not recommended because the password will be visible in your shell history.
This option is NOT recommended because the password will be visible in your shell history.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -43,7 +44,7 @@ Optional Args:
}
// Run runs the command and returns the exit status.
func (c *UserCheckPwCommand) Run(args []string) int {
func (c *CmdUserCheckPw) Run(args []string) int {
if len(args) != 1 && len(args) != 2 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -66,24 +67,24 @@ func (c *UserCheckPwCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
user, err := repo.User(domainName, userName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if user == nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", mailfull.ErrUserNotExist)
c.Meta.Errorf("%v\n", mailfull.ErrUserNotExist)
return 1
}
if len(args) != 2 {
input, err1 := c.UI.AskSecret(fmt.Sprintf("Enter password for %s:", address))
if err1 != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err1)
input, err := c.UI.AskSecret(fmt.Sprintf("Enter password for %s:", address))
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,27 +1,28 @@
package command
package main
import (
"fmt"
"strings"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// UserDelCommand represents a UserDelCommand.
type UserDelCommand struct {
Meta
// CmdUserDel represents a CmdUserDel.
type CmdUserDel struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *UserDelCommand) Synopsis() string {
func (c *CmdUserDel) Synopsis() string {
return "Delete and backup a user."
}
// Help returns long-form help text.
func (c *UserDelCommand) Help() string {
func (c *CmdUserDel) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s address
%s %s [-n] address
Description:
%s
@@ -29,6 +30,10 @@ Description:
Required Args:
address
The email address that you want to delete.
Optional Args:
-n
Don't update databases.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -37,7 +42,13 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *UserDelCommand) Run(args []string) int {
func (c *CmdUserDel) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -55,24 +66,25 @@ func (c *UserDelCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if userName == "postmaster" {
c.Meta.Errorf("Cannot delete postmaster.\n")
return 1
}
if err := repo.UserRemove(domainName, userName); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,28 +1,29 @@
package command
package main
import (
"fmt"
"strings"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
"github.com/jsimonetti/pwscheme/ssha"
)
// UserPasswdCommand represents a UserPasswdCommand.
type UserPasswdCommand struct {
Meta
// CmdUserPasswd represents a CmdUserPasswd.
type CmdUserPasswd struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *UserPasswdCommand) Synopsis() string {
func (c *CmdUserPasswd) Synopsis() string {
return "Update user's password."
}
// Help returns long-form help text.
func (c *UserPasswdCommand) Help() string {
func (c *CmdUserPasswd) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s address [password]
%s %s [-n] address [password]
Description:
%s
@@ -32,9 +33,11 @@ Required Args:
The email address that you want to update the password.
Optional Args:
-n
Don't update databases.
password
Specify the password instead of your typing.
This option is not recommended because the password will be visible in your shell history.
This option is NOT recommended because the password will be visible in your shell history.
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
@@ -43,7 +46,13 @@ Optional Args:
}
// Run runs the command and returns the exit status.
func (c *UserPasswdCommand) Run(args []string) int {
func (c *CmdUserPasswd) Run(args []string) int {
noCommit, err := noCommitFlag(&args)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
}
if len(args) != 1 && len(args) != 2 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -66,33 +75,33 @@ func (c *UserPasswdCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
user, err := repo.User(domainName, userName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
if user == nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", mailfull.ErrUserNotExist)
c.Meta.Errorf("%v\n", mailfull.ErrUserNotExist)
return 1
}
if len(args) != 2 {
input1, err1 := c.UI.AskSecret(fmt.Sprintf("Enter new password for %s:", address))
if err1 != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err1)
input1, err := c.UI.AskSecret(fmt.Sprintf("Enter new password for %s:", address))
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
input2, err2 := c.UI.AskSecret("Retype new password:")
if err2 != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err2)
input2, err := c.UI.AskSecret("Retype new password:")
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
if input1 != input2 {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] inputs do not match.\n")
c.Meta.Errorf("inputs do not match.\n")
return 1
}
rawPassword = input1
@@ -100,9 +109,9 @@ func (c *UserPasswdCommand) Run(args []string) int {
hashedPassword := mailfull.NeverMatchHashedPassword
if rawPassword != "" {
str, errHash := ssha.Generate(rawPassword, 4)
if errHash != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", errHash)
str, err := ssha.Generate(rawPassword, 4)
if err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}
hashedPassword = str
@@ -111,19 +120,15 @@ func (c *UserPasswdCommand) Run(args []string) int {
user.SetHashedPassword(hashedPassword)
if err := repo.UserUpdate(domainName, user); err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
if noCommit {
return 0
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
if err = repo.GenerateDatabases(); err != nil {
c.Meta.Errorf("%v\n", err)
return 1
}

View File

@@ -1,24 +1,25 @@
package command
package main
import (
"fmt"
"sort"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd"
)
// UsersCommand represents a UsersCommand.
type UsersCommand struct {
Meta
// CmdUsers represents a CmdUsers.
type CmdUsers struct {
cmd.Meta
}
// Synopsis returns a one-line synopsis.
func (c *UsersCommand) Synopsis() string {
func (c *CmdUsers) Synopsis() string {
return "Show users."
}
// Help returns long-form help text.
func (c *UsersCommand) Help() string {
func (c *CmdUsers) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s domain
@@ -37,7 +38,7 @@ Required Args:
}
// Run runs the command and returns the exit status.
func (c *UsersCommand) Run(args []string) int {
func (c *CmdUsers) Run(args []string) int {
if len(args) != 1 {
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
return 1
@@ -47,16 +48,16 @@ func (c *UsersCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
users, err := repo.Users(targetDomainName)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
c.Meta.Errorf("%v\n", err)
return 1
}
sort.Sort(mailfull.UserSlice(users))
sort.Slice(users, func(i, j int) bool { return users[i].Name() < users[j].Name() })
for _, user := range users {
fmt.Fprintf(c.UI.Writer, "%s\n", user.Name())

View File

@@ -1,55 +0,0 @@
package command
import (
"fmt"
"github.com/directorz/mailfull-go"
)
// CommitCommand represents a CommitCommand.
type CommitCommand struct {
Meta
}
// Synopsis returns a one-line synopsis.
func (c *CommitCommand) Synopsis() string {
return "Create databases from the structure of the MailData directory."
}
// Help returns long-form help text.
func (c *CommitCommand) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s
Description:
%s
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
return txt[1:]
}
// Run runs the command and returns the exit status.
func (c *CommitCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
}
mailData, err := repo.MailData()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
}
err = repo.GenerateDatabases(mailData)
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
}
return 0
}

View File

@@ -1,55 +0,0 @@
package command
import (
"fmt"
"sort"
"github.com/directorz/mailfull-go"
)
// DomainsCommand represents a DomainsCommand.
type DomainsCommand struct {
Meta
}
// Synopsis returns a one-line synopsis.
func (c *DomainsCommand) Synopsis() string {
return "Show domains."
}
// Help returns long-form help text.
func (c *DomainsCommand) Help() string {
txt := fmt.Sprintf(`
Usage:
%s %s
Description:
%s
`,
c.CmdName, c.SubCmdName,
c.Synopsis())
return txt[1:]
}
// Run runs the command and returns the exit status.
func (c *DomainsCommand) Run(args []string) int {
repo, err := mailfull.OpenRepository(".")
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
}
domains, err := repo.Domains()
if err != nil {
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
return 1
}
sort.Sort(mailfull.DomainSlice(domains))
for _, domain := range domains {
fmt.Fprintf(c.UI.Writer, "%s\n", domain.Name())
}
return 0
}

View File

@@ -1,13 +0,0 @@
package command
import (
"github.com/mitchellh/cli"
)
// Meta is for `*Command` struct.
type Meta struct {
UI *cli.BasicUi
CmdName string
SubCmdName string
Version string
}

View File

@@ -4,12 +4,15 @@ Command mailfull is a CLI application using the mailfull package.
package main
import (
"bytes"
"flag"
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/directorz/mailfull-go"
"github.com/directorz/mailfull-go/cmd/mailfull/command"
"github.com/directorz/mailfull-go/cmd"
"github.com/mitchellh/cli"
)
@@ -20,8 +23,9 @@ var (
func init() {
if gittag != "" {
version = version + "-" + gittag
version += "-" + gittag
}
version += fmt.Sprintf(" (built with %s)", runtime.Version())
}
func main() {
@@ -31,7 +35,7 @@ func main() {
Args: os.Args[1:],
}
meta := command.Meta{
meta := cmd.Meta{
UI: &cli.BasicUi{
Reader: os.Stdin,
Writer: os.Stdout,
@@ -44,87 +48,95 @@ func main() {
c.Commands = map[string]cli.CommandFactory{
"init": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.InitCommand{Meta: meta}, nil
return &CmdInit{Meta: meta}, nil
},
"genconfig": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.GenConfigCommand{Meta: meta}, nil
return &CmdGenConfig{Meta: meta}, nil
},
"domains": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.DomainsCommand{Meta: meta}, nil
return &CmdDomains{Meta: meta}, nil
},
"domainadd": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.DomainAddCommand{Meta: meta}, nil
return &CmdDomainAdd{Meta: meta}, nil
},
"domaindel": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.DomainDelCommand{Meta: meta}, nil
return &CmdDomainDel{Meta: meta}, nil
},
"domaindisable": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &CmdDomainDisable{Meta: meta}, nil
},
"domainenable": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &CmdDomainEnable{Meta: meta}, nil
},
"aliasdomains": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.AliasDomainsCommand{Meta: meta}, nil
return &CmdAliasDomains{Meta: meta}, nil
},
"aliasdomainadd": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.AliasDomainAddCommand{Meta: meta}, nil
return &CmdAliasDomainAdd{Meta: meta}, nil
},
"aliasdomaindel": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.AliasDomainDelCommand{Meta: meta}, nil
return &CmdAliasDomainDel{Meta: meta}, nil
},
"users": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.UsersCommand{Meta: meta}, nil
return &CmdUsers{Meta: meta}, nil
},
"useradd": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.UserAddCommand{Meta: meta}, nil
return &CmdUserAdd{Meta: meta}, nil
},
"userdel": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.UserDelCommand{Meta: meta}, nil
return &CmdUserDel{Meta: meta}, nil
},
"userpasswd": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.UserPasswdCommand{Meta: meta}, nil
return &CmdUserPasswd{Meta: meta}, nil
},
"usercheckpw": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.UserCheckPwCommand{Meta: meta}, nil
return &CmdUserCheckPw{Meta: meta}, nil
},
"aliasusers": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.AliasUsersCommand{Meta: meta}, nil
return &CmdAliasUsers{Meta: meta}, nil
},
"aliasuseradd": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.AliasUserAddCommand{Meta: meta}, nil
return &CmdAliasUserAdd{Meta: meta}, nil
},
"aliasusermod": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.AliasUserModCommand{Meta: meta}, nil
return &CmdAliasUserMod{Meta: meta}, nil
},
"aliasuserdel": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.AliasUserDelCommand{Meta: meta}, nil
return &CmdAliasUserDel{Meta: meta}, nil
},
"catchall": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.CatchAllCommand{Meta: meta}, nil
return &CmdCatchAll{Meta: meta}, nil
},
"catchallset": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.CatchAllSetCommand{Meta: meta}, nil
return &CmdCatchAllSet{Meta: meta}, nil
},
"catchallunset": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.CatchAllUnsetCommand{Meta: meta}, nil
return &CmdCatchAllUnset{Meta: meta}, nil
},
"commit": func() (cli.Command, error) {
meta.SubCmdName = c.Subcommand()
return &command.CommitCommand{Meta: meta}, nil
return &CmdCommit{Meta: meta}, nil
},
}
@@ -135,3 +147,17 @@ func main() {
os.Exit(exitCode)
}
// noCommitFlag returns true if `pargs` has "-n" flag.
// `pargs` is overwrites with non-flag arguments.
func noCommitFlag(pargs *[]string) (bool, error) {
nFlag := false
flagSet := flag.NewFlagSet("", flag.ContinueOnError)
flagSet.SetOutput(&bytes.Buffer{})
flagSet.BoolVar(&nFlag, "n", nFlag, "")
err := flagSet.Parse(*pargs)
*pargs = flagSet.Args()
return nFlag, err
}

20
cmd/meta.go Normal file
View File

@@ -0,0 +1,20 @@
package cmd
import (
"fmt"
"github.com/mitchellh/cli"
)
// Meta contains options to execute a command.
type Meta struct {
UI *cli.BasicUi
CmdName string
SubCmdName string
Version string
}
// Errorf prints the error to ErrorWriter with the prefix string.
func (m Meta) Errorf(format string, v ...interface{}) {
fmt.Fprintf(m.UI.ErrorWriter, "[ERR] "+format, v...)
}

View File

@@ -5,6 +5,7 @@ const (
DirNameConfig = ".mailfull"
FileNameConfig = "config"
FileNameDomainDisable = ".vdomaindisable"
FileNameAliasDomains = ".valiasdomains"
FileNameUsersPassword = ".vpasswd"
FileNameUserForwards = ".forward"

View File

@@ -9,33 +9,84 @@ import (
"strings"
)
// GenerateDatabases generates databases from the MailData directory.
func (r *Repository) GenerateDatabases(md *MailData) error {
sort.Sort(DomainSlice(md.Domains))
sort.Sort(AliasDomainSlice(md.AliasDomains))
// repoData represents a repoData.
type repoData struct {
Domains []*Domain
AliasDomains []*AliasDomain
}
for _, domain := range md.Domains {
sort.Sort(UserSlice(domain.Users))
sort.Sort(AliasUserSlice(domain.AliasUsers))
// repoData returns a repoData.
func (r *Repository) repoData() (*repoData, error) {
domains, err := r.Domains()
if err != nil {
return nil, err
}
aliasDomains, err := r.AliasDomains()
if err != nil {
return nil, err
}
for _, domain := range domains {
users, err := r.Users(domain.Name())
if err != nil {
return nil, err
}
domain.Users = users
aliasUsers, err := r.AliasUsers(domain.Name())
if err != nil {
return nil, err
}
domain.AliasUsers = aliasUsers
catchAllUser, err := r.CatchAllUser(domain.Name())
if err != nil {
return nil, err
}
domain.CatchAllUser = catchAllUser
}
rd := &repoData{
Domains: domains,
AliasDomains: aliasDomains,
}
return rd, nil
}
// GenerateDatabases generates databases from the Repository.
func (r *Repository) GenerateDatabases() error {
rd, err := r.repoData()
if err != nil {
return err
}
sort.Slice(rd.Domains, func(i, j int) bool { return rd.Domains[i].Name() < rd.Domains[j].Name() })
sort.Slice(rd.AliasDomains, func(i, j int) bool { return rd.AliasDomains[i].Name() < rd.AliasDomains[j].Name() })
for _, domain := range rd.Domains {
sort.Slice(domain.Users, func(i, j int) bool { return domain.Users[i].Name() < domain.Users[j].Name() })
sort.Slice(domain.AliasUsers, func(i, j int) bool { return domain.AliasUsers[i].Name() < domain.AliasUsers[j].Name() })
}
// Generate files
if err := r.generateDbDomains(md); err != nil {
if err := r.generateDbDomains(rd); err != nil {
return err
}
if err := r.generateDbDestinations(md); err != nil {
if err := r.generateDbDestinations(rd); err != nil {
return err
}
if err := r.generateDbMaildirs(md); err != nil {
if err := r.generateDbMaildirs(rd); err != nil {
return err
}
if err := r.generateDbLocaltable(md); err != nil {
if err := r.generateDbLocaltable(rd); err != nil {
return err
}
if err := r.generateDbForwards(md); err != nil {
if err := r.generateDbForwards(rd); err != nil {
return err
}
if err := r.generateDbPasswords(md); err != nil {
if err := r.generateDbPasswords(rd); err != nil {
return err
}
@@ -59,7 +110,7 @@ func (r *Repository) GenerateDatabases(md *MailData) error {
return nil
}
func (r *Repository) generateDbDomains(md *MailData) error {
func (r *Repository) generateDbDomains(rd *repoData) error {
dbDomains, err := os.Create(filepath.Join(r.DirDatabasePath, FileNameDbDomains))
if err != nil {
return err
@@ -69,13 +120,17 @@ func (r *Repository) generateDbDomains(md *MailData) error {
}
defer dbDomains.Close()
for _, domain := range md.Domains {
for _, domain := range rd.Domains {
if domain.Disabled() {
continue
}
if _, err := fmt.Fprintf(dbDomains, "%s virtual\n", domain.Name()); err != nil {
return err
}
}
for _, aliasDomain := range md.AliasDomains {
for _, aliasDomain := range rd.AliasDomains {
if _, err := fmt.Fprintf(dbDomains, "%s virtual\n", aliasDomain.Name()); err != nil {
return err
}
@@ -84,7 +139,7 @@ func (r *Repository) generateDbDomains(md *MailData) error {
return nil
}
func (r *Repository) generateDbDestinations(md *MailData) error {
func (r *Repository) generateDbDestinations(rd *repoData) error {
dbDestinations, err := os.Create(filepath.Join(r.DirDatabasePath, FileNameDbDestinations))
if err != nil {
return err
@@ -94,7 +149,11 @@ func (r *Repository) generateDbDestinations(md *MailData) error {
}
defer dbDestinations.Close()
for _, domain := range md.Domains {
for _, domain := range rd.Domains {
if domain.Disabled() {
continue
}
// ho-ge.example.com -> ho_ge.example.com
underscoredDomainName := domain.Name()
underscoredDomainName = strings.Replace(underscoredDomainName, `-`, `_`, -1)
@@ -115,7 +174,7 @@ func (r *Repository) generateDbDestinations(md *MailData) error {
}
}
for _, aliasDomain := range md.AliasDomains {
for _, aliasDomain := range rd.AliasDomains {
if aliasDomain.Target() == domain.Name() {
if _, err := fmt.Fprintf(dbDestinations, "%s@%s %s@%s\n", userName, aliasDomain.Name(), user.Name(), domain.Name()); err != nil {
return err
@@ -129,7 +188,7 @@ func (r *Repository) generateDbDestinations(md *MailData) error {
return err
}
for _, aliasDomain := range md.AliasDomains {
for _, aliasDomain := range rd.AliasDomains {
if aliasDomain.Target() == domain.Name() {
if _, err := fmt.Fprintf(dbDestinations, "%s@%s %s@%s\n", aliasUser.Name(), aliasDomain.Name(), aliasUser.Name(), domain.Name()); err != nil {
return err
@@ -142,7 +201,7 @@ func (r *Repository) generateDbDestinations(md *MailData) error {
return nil
}
func (r *Repository) generateDbMaildirs(md *MailData) error {
func (r *Repository) generateDbMaildirs(rd *repoData) error {
dbMaildirs, err := os.Create(filepath.Join(r.DirDatabasePath, FileNameDbMaildirs))
if err != nil {
return err
@@ -152,7 +211,11 @@ func (r *Repository) generateDbMaildirs(md *MailData) error {
}
defer dbMaildirs.Close()
for _, domain := range md.Domains {
for _, domain := range rd.Domains {
if domain.Disabled() {
continue
}
for _, user := range domain.Users {
if _, err := fmt.Fprintf(dbMaildirs, "%s@%s %s/%s/Maildir/\n", user.Name(), domain.Name(), domain.Name(), user.Name()); err != nil {
return err
@@ -163,7 +226,7 @@ func (r *Repository) generateDbMaildirs(md *MailData) error {
return nil
}
func (r *Repository) generateDbLocaltable(md *MailData) error {
func (r *Repository) generateDbLocaltable(rd *repoData) error {
dbLocaltable, err := os.Create(filepath.Join(r.DirDatabasePath, FileNameDbLocaltable))
if err != nil {
return err
@@ -173,7 +236,11 @@ func (r *Repository) generateDbLocaltable(md *MailData) error {
}
defer dbLocaltable.Close()
for _, domain := range md.Domains {
for _, domain := range rd.Domains {
if domain.Disabled() {
continue
}
// ho-ge.example.com -> ho_ge\.example\.com
escapedDomainName := domain.Name()
escapedDomainName = strings.Replace(escapedDomainName, `-`, `_`, -1)
@@ -187,7 +254,7 @@ func (r *Repository) generateDbLocaltable(md *MailData) error {
return nil
}
func (r *Repository) generateDbForwards(md *MailData) error {
func (r *Repository) generateDbForwards(rd *repoData) error {
dbForwards, err := os.Create(filepath.Join(r.DirDatabasePath, FileNameDbForwards))
if err != nil {
return err
@@ -197,7 +264,11 @@ func (r *Repository) generateDbForwards(md *MailData) error {
}
defer dbForwards.Close()
for _, domain := range md.Domains {
for _, domain := range rd.Domains {
if domain.Disabled() {
continue
}
// ho-ge.example.com -> ho_ge.example.com
underscoredDomainName := domain.Name()
underscoredDomainName = strings.Replace(underscoredDomainName, `-`, `_`, -1)
@@ -223,7 +294,7 @@ func (r *Repository) generateDbForwards(md *MailData) error {
return nil
}
func (r *Repository) generateDbPasswords(md *MailData) error {
func (r *Repository) generateDbPasswords(rd *repoData) error {
dbPasswords, err := os.Create(filepath.Join(r.DirDatabasePath, FileNameDbPasswords))
if err != nil {
return err
@@ -233,7 +304,11 @@ func (r *Repository) generateDbPasswords(md *MailData) error {
}
defer dbPasswords.Close()
for _, domain := range md.Domains {
for _, domain := range rd.Domains {
if domain.Disabled() {
continue
}
for _, user := range domain.Users {
if _, err := fmt.Fprintf(dbPasswords, "%s@%s:%s\n", user.Name(), domain.Name(), user.HashedPassword()); err != nil {
return err

5
doc/README.md Normal file
View File

@@ -0,0 +1,5 @@
Documentation
=============
- [Configuration](configuration.md)
- [Migrating from mailfull](migrating_from_mailfull.md)

12
doc/configuration.md Normal file
View File

@@ -0,0 +1,12 @@
Configuration
=============
`.mailfull/config`
| key | type | default | required | description |
|:--------------|:-------|:------------------------------------------|:---------|:----------------------------------------------------------------|
| dir_database | string | `"./etc"` | no | A relative path from repository dir (or a absolute path) |
| dir_maildata | string | `"./domains"` | no | A relative path from repository dir (or a absolute path) |
| username | string | The username who executed `mailfull init` | **yes** | It used for setting owner of database files and maildata files. |
| cmd_postalias | string | `"postalias"` | no | Command name or path |
| cmd_postmap | string | `"postmap"` | no | Command name or path |

View File

@@ -0,0 +1,24 @@
Migrating from mailfull
=======================
Migrating from [directorz/mailfull](https://github.com/directorz/mailfull)
Change directory to Mailfull directory.
```
# su - mailfull
$ cd /home/mailfull
```
Initialize a directory as a Mailfull repository.
```
$ mailfull init
```
Delete unnecessary files.
```
$ rm -rf .git .gitignore bin docs lib README.md README.ja.md
$ find domains -maxdepth 2 -name '.vforward' | xargs rm -f
```

128
domain.go
View File

@@ -11,36 +11,49 @@ import (
// Domain represents a Domain.
type Domain struct {
name string
disabled bool
Users []*User
AliasUsers []*AliasUser
CatchAllUser *CatchAllUser
}
// DomainSlice attaches the methods of sort.Interface to []*Domain.
type DomainSlice []*Domain
func (p DomainSlice) Len() int { return len(p) }
func (p DomainSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }
func (p DomainSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// NewDomain creates a new Domain instance.
func NewDomain(name string) (*Domain, error) {
if !validDomainName(name) {
return nil, ErrInvalidDomainName
}
d := &Domain{}
d := &Domain{
name: name,
if err := d.setName(name); err != nil {
return nil, err
}
return d, nil
}
// setName sets the name.
func (d *Domain) setName(name string) error {
if !validDomainName(name) {
return ErrInvalidDomainName
}
d.name = name
return nil
}
// Name returns name.
func (d *Domain) Name() string {
return d.name
}
// SetDisabled disables the Domain if the input is true.
func (d *Domain) SetDisabled(disabled bool) {
d.disabled = disabled
}
// Disabled returns true if the Domain is disabled.
func (d *Domain) Disabled() bool {
return d.disabled
}
// Domains returns a Domain slice.
func (r *Repository) Domains() ([]*Domain, error) {
fileInfos, err := ioutil.ReadDir(r.DirMailDataPath)
@@ -62,6 +75,12 @@ func (r *Repository) Domains() ([]*Domain, error) {
continue
}
disabled, err := r.domainDisabled(name)
if err != nil {
return nil, err
}
domain.SetDisabled(disabled)
domains = append(domains, domain)
}
@@ -94,9 +113,38 @@ func (r *Repository) Domain(domainName string) (*Domain, error) {
return nil, err
}
disabled, err := r.domainDisabled(name)
if err != nil {
return nil, err
}
domain.SetDisabled(disabled)
return domain, nil
}
// domainDisabled returns true if the input Domain is disabled.
func (r *Repository) domainDisabled(domainName string) (bool, error) {
if !validDomainName(domainName) {
return false, ErrInvalidDomainName
}
fi, err := os.Stat(filepath.Join(r.DirMailDataPath, domainName, FileNameDomainDisable))
if err != nil {
if err.(*os.PathError).Err == syscall.ENOENT {
return false, nil
}
return false, err
}
if fi.IsDir() {
return false, ErrInvalidFormatDomainDisabled
}
return true, nil
}
// DomainCreate creates the input Domain.
func (r *Repository) DomainCreate(domain *Domain) error {
existDomain, err := r.Domain(domain.Name())
@@ -150,6 +198,29 @@ func (r *Repository) DomainCreate(domain *Domain) error {
}
catchAllUserFile.Close()
if domain.Disabled() {
if err := r.writeDomainDisabledFile(domain.Name(), domain.Disabled()); err != nil {
return err
}
}
return nil
}
// DomainUpdate updates the input Domain.
func (r *Repository) DomainUpdate(domain *Domain) error {
existDomain, err := r.Domain(domain.Name())
if err != nil {
return err
}
if existDomain == nil {
return ErrDomainNotExist
}
if err := r.writeDomainDisabledFile(domain.Name(), domain.Disabled()); err != nil {
return err
}
return nil
}
@@ -182,3 +253,36 @@ func (r *Repository) DomainRemove(domainName string) error {
return nil
}
// writeDomainDisabledFile creates/removes the disabled file.
func (r *Repository) writeDomainDisabledFile(domainName string, disabled bool) error {
if !validDomainName(domainName) {
return ErrInvalidDomainName
}
nowDisabled, err := r.domainDisabled(domainName)
if err != nil {
return err
}
domainDisabledFileName := filepath.Join(r.DirMailDataPath, domainName, FileNameDomainDisable)
if !nowDisabled && disabled {
file, err := os.OpenFile(domainDisabledFileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
if err := file.Chown(r.uid, r.gid); err != nil {
return err
}
file.Close()
}
if nowDisabled && !disabled {
if err := os.Remove(domainDisabledFileName); err != nil {
return err
}
}
return nil
}

View File

@@ -45,7 +45,7 @@ smtpd_sasl_path = private/auth
smtpd_tls_cert_file = /etc/pki/dovecot/certs/dovecot.pem
smtpd_tls_key_file = /etc/pki/dovecot/private/dovecot.pem
#smtpd_tls_CAfile =
smtpd_tls_session_cache_database = btree:/etc/postfix/smtpd_scache
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtp_tls_security_level = may

View File

@@ -1,47 +0,0 @@
package mailfull
// MailData represents a MailData.
type MailData struct {
Domains []*Domain
AliasDomains []*AliasDomain
}
// MailData returns a MailData.
func (r *Repository) MailData() (*MailData, error) {
domains, err := r.Domains()
if err != nil {
return nil, err
}
aliasDomains, err := r.AliasDomains()
if err != nil {
return nil, err
}
for _, domain := range domains {
users, err := r.Users(domain.Name())
if err != nil {
return nil, err
}
domain.Users = users
aliasUsers, err := r.AliasUsers(domain.Name())
if err != nil {
return nil, err
}
domain.AliasUsers = aliasUsers
catchAllUser, err := r.CatchAllUser(domain.Name())
if err != nil {
return nil, err
}
domain.CatchAllUser = catchAllUser
}
mailData := &MailData{
Domains: domains,
AliasDomains: aliasDomains,
}
return mailData, nil
}

View File

@@ -34,6 +34,7 @@ var (
ErrAliasUserNotExist = errors.New("AliasUser: not exist")
ErrAliasUserAlreadyExist = errors.New("AliasUser: already exist")
ErrInvalidFormatDomainDisabled = errors.New("Domain: disabled file invalid format")
ErrInvalidFormatUsersPassword = errors.New("User: password file invalid format")
ErrInvalidFormatAliasDomain = errors.New("AliasDomain: file invalid format")
ErrInvalidFormatAliasUsers = errors.New("AliasUsers: file invalid format")
@@ -126,10 +127,10 @@ func OpenRepository(basePath string) (*Repository, error) {
for {
configDirPath := filepath.Join(rootPath, DirNameConfig)
fi, errStat := os.Stat(configDirPath)
if errStat != nil {
if errStat.(*os.PathError).Err != syscall.ENOENT {
return nil, errStat
fi, err := os.Stat(configDirPath)
if err != nil {
if err.(*os.PathError).Err != syscall.ENOENT {
return nil, err
}
} else {
if fi.IsDir() {

10
user.go
View File

@@ -19,13 +19,6 @@ type User struct {
forwards []string
}
// UserSlice attaches the methods of sort.Interface to []*User.
type UserSlice []*User
func (p UserSlice) Len() int { return len(p) }
func (p UserSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }
func (p UserSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// NewUser creates a new User instance.
func NewUser(name, hashedPassword string, forwards []string) (*User, error) {
u := &User{}
@@ -107,6 +100,9 @@ func (r *Repository) Users(domainName string) ([]*User, error) {
forwards, err := r.userForwards(domainName, name)
if err != nil {
if err == ErrInvalidUserName {
continue
}
return nil, err
}

View File

@@ -33,20 +33,20 @@ func validAliasDomainTarget(target string) bool {
// validUserName returns true if the input is correct format.
func validUserName(name string) bool {
return regexp.MustCompile(`^[^\s@]+$`).MatchString(name)
return regexp.MustCompile(`^[^\.\s@][^\s@]+$`).MatchString(name)
}
// validAliasUserName returns true if the input is correct format.
func validAliasUserName(name string) bool {
return regexp.MustCompile(`^[^\s@]+$`).MatchString(name)
return regexp.MustCompile(`^[^\.\s@][^\s@]+$`).MatchString(name)
}
// validAliasUserTarget returns true if the input is correct format.
func validAliasUserTarget(target string) bool {
return regexp.MustCompile(`^[^\s@]+@([A-Za-z0-9\-]+\.)*[A-Za-z]+$`).MatchString(target)
return regexp.MustCompile(`^[^\.\s@][^\s@]+@([A-Za-z0-9\-]+\.)*[A-Za-z]+$`).MatchString(target)
}
// validCatchAllUserName returns true if the input is correct format.
func validCatchAllUserName(name string) bool {
return regexp.MustCompile(`^[^\s@]+$`).MatchString(name)
return regexp.MustCompile(`^[^\.\s@][^\s@]+$`).MatchString(name)
}

View File

@@ -1,4 +1,4 @@
package mailfull
// Version is a version number.
const Version = "0.0.2"
const Version = "v1.0.3"