mirror of
https://github.com/directorz/mailfull-go.git
synced 2025-12-20 11:07:02 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db554a1da1 | ||
|
|
708e132ccc | ||
|
|
3a1d4a588c | ||
|
|
50d429ad78 | ||
|
|
0118652074 | ||
|
|
bf4b63556a | ||
|
|
24ee3c26b0 | ||
|
|
49dd05f3bf | ||
|
|
009ee84e63 | ||
|
|
281d5a4a9d | ||
|
|
c2dca41057 | ||
|
|
4f99f11732 | ||
|
|
a3d3684fda | ||
|
|
c183bba7aa | ||
|
|
b52a7cde7f | ||
|
|
0926ffd318 | ||
|
|
c9201c8fc1 | ||
|
|
fe16bb86f9 | ||
|
|
bd6228197a | ||
|
|
1329747f54 | ||
|
|
ab3c3315f9 | ||
|
|
a76596c348 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1 +1,6 @@
|
|||||||
/cli/mailfull/mailfull
|
/vendor
|
||||||
|
/build
|
||||||
|
/release
|
||||||
|
/github_token
|
||||||
|
|
||||||
|
/cmd/mailfull/mailfull
|
||||||
|
|||||||
6
Gomfile
Normal file
6
Gomfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
gom 'github.com/BurntSushi/toml'
|
||||||
|
gom 'github.com/armon/go-radix'
|
||||||
|
gom 'github.com/bgentry/speakeasy'
|
||||||
|
gom 'github.com/jsimonetti/pwscheme'
|
||||||
|
gom 'github.com/mattn/go-isatty'
|
||||||
|
gom 'github.com/mitchellh/cli'
|
||||||
53
Makefile
Normal file
53
Makefile
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
GOVERSION=$(shell go version)
|
||||||
|
GOOS=$(word 1,$(subst /, ,$(lastword $(GOVERSION))))
|
||||||
|
GOARCH=$(word 2,$(subst /, ,$(lastword $(GOVERSION))))
|
||||||
|
DIR_BUILD=build
|
||||||
|
DIR_RELEASE=release
|
||||||
|
VERSION=$(patsubst "%",%,$(lastword $(shell grep 'const Version' version.go)))
|
||||||
|
|
||||||
|
.PHONY: build build-linux-amd64 build-linux-386 clean
|
||||||
|
|
||||||
|
default: build
|
||||||
|
|
||||||
|
installdeps:
|
||||||
|
gom install
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -v -ldflags "-X main.gittag=`git rev-parse --short HEAD`" -o build/mailfull_$(GOOS)_$(GOARCH)/mailfull cmd/mailfull/mailfull.go
|
||||||
|
|
||||||
|
build-linux-amd64:
|
||||||
|
docker run --rm -v $(PWD):/go/src/github.com/directorz/mailfull-go -w /go/src/github.com/directorz/mailfull-go \
|
||||||
|
-e GOOS=linux -e GOARCH=amd64 golang:1.7 \
|
||||||
|
go build -v -ldflags "-X main.gittag=`git rev-parse --short HEAD`" -o "build/mailfull_linux_amd64/mailfull" cmd/mailfull/mailfull.go
|
||||||
|
|
||||||
|
build-linux-386:
|
||||||
|
docker run --rm -v $(PWD):/go/src/github.com/directorz/mailfull-go -w /go/src/github.com/directorz/mailfull-go \
|
||||||
|
-e GOOS=linux -e GOARCH=386 golang:1.7 \
|
||||||
|
go build -v -ldflags "-X main.gittag=`git rev-parse --short HEAD`" -o "build/mailfull_linux_386/mailfull" cmd/mailfull/mailfull.go
|
||||||
|
|
||||||
|
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: release-linux-amd64 release-linux-386 release-github-token
|
||||||
|
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)
|
||||||
11
README.md
11
README.md
@@ -16,6 +16,11 @@ Features
|
|||||||
Installation
|
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
|
### go get
|
||||||
|
|
||||||
Installed in `$GOPATH/bin`
|
Installed in `$GOPATH/bin`
|
||||||
@@ -39,6 +44,7 @@ Initialize a directory as a Mailfull repository.
|
|||||||
```
|
```
|
||||||
$ mkdir /path/to/repo && cd /path/to/repo
|
$ mkdir /path/to/repo && cd /path/to/repo
|
||||||
$ mailfull init
|
$ mailfull init
|
||||||
|
$ mailfull commit
|
||||||
```
|
```
|
||||||
|
|
||||||
Generate configurations for Postfix and Dovecot. (Edit as needed.)
|
Generate configurations for Postfix and Dovecot. (Edit as needed.)
|
||||||
@@ -66,3 +72,8 @@ Add a new domain and user.
|
|||||||
```
|
```
|
||||||
|
|
||||||
Enjoy!
|
Enjoy!
|
||||||
|
|
||||||
|
More info
|
||||||
|
---------
|
||||||
|
|
||||||
|
See [documentation](doc/README.md)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (c *AliasDomainAddCommand) Synopsis() string {
|
|||||||
func (c *AliasDomainAddCommand) Help() string {
|
func (c *AliasDomainAddCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s domain target
|
%s %s [-n] domain target
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -30,6 +30,10 @@ Required Args:
|
|||||||
The domain name that you want to create.
|
The domain name that you want to create.
|
||||||
target
|
target
|
||||||
The target domain name.
|
The target domain name.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -39,6 +43,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *AliasDomainAddCommand) Run(args []string) int {
|
func (c *AliasDomainAddCommand) 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 {
|
if len(args) != 2 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -64,6 +74,10 @@ func (c *AliasDomainAddCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (c *AliasDomainDelCommand) Synopsis() string {
|
|||||||
func (c *AliasDomainDelCommand) Help() string {
|
func (c *AliasDomainDelCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s domain
|
%s %s [-n] domain
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -28,6 +28,10 @@ Description:
|
|||||||
Required Args:
|
Required Args:
|
||||||
domain
|
domain
|
||||||
The domain name that you want to delete.
|
The domain name that you want to delete.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -37,6 +41,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *AliasDomainDelCommand) Run(args []string) int {
|
func (c *AliasDomainDelCommand) 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 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -55,6 +65,10 @@ func (c *AliasDomainDelCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (c *AliasUserAddCommand) Synopsis() string {
|
|||||||
func (c *AliasUserAddCommand) Help() string {
|
func (c *AliasUserAddCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s address target [target...]
|
%s %s [-n] address target [target...]
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -31,6 +31,10 @@ Required Args:
|
|||||||
The email address that you want to create.
|
The email address that you want to create.
|
||||||
target
|
target
|
||||||
Target email addresses.
|
Target email addresses.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -40,6 +44,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *AliasUserAddCommand) Run(args []string) int {
|
func (c *AliasUserAddCommand) 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 {
|
if len(args) < 2 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -73,6 +83,10 @@ func (c *AliasUserAddCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (c *AliasUserDelCommand) Synopsis() string {
|
|||||||
func (c *AliasUserDelCommand) Help() string {
|
func (c *AliasUserDelCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s address
|
%s %s [-n] address
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -29,6 +29,10 @@ Description:
|
|||||||
Required Args:
|
Required Args:
|
||||||
address
|
address
|
||||||
The email address that you want to delete.
|
The email address that you want to delete.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -38,6 +42,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *AliasUserDelCommand) Run(args []string) int {
|
func (c *AliasUserDelCommand) 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 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -63,6 +73,10 @@ func (c *AliasUserDelCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (c *AliasUserModCommand) Synopsis() string {
|
|||||||
func (c *AliasUserModCommand) Help() string {
|
func (c *AliasUserModCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s address target [target...]
|
%s %s [-n] address target [target...]
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -31,6 +31,10 @@ Required Args:
|
|||||||
The email address that you want to modify.
|
The email address that you want to modify.
|
||||||
target
|
target
|
||||||
Target email addresses.
|
Target email addresses.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -40,6 +44,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *AliasUserModCommand) Run(args []string) int {
|
func (c *AliasUserModCommand) 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 {
|
if len(args) < 2 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -82,6 +92,10 @@ func (c *AliasUserModCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (c *CatchAllSetCommand) Synopsis() string {
|
|||||||
func (c *CatchAllSetCommand) Help() string {
|
func (c *CatchAllSetCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s domain user
|
%s %s [-n] domain user
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -30,6 +30,10 @@ Required Args:
|
|||||||
The domain name.
|
The domain name.
|
||||||
user
|
user
|
||||||
The user name that you want to set as catchall user.
|
The user name that you want to set as catchall user.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -39,6 +43,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *CatchAllSetCommand) Run(args []string) int {
|
func (c *CatchAllSetCommand) 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 {
|
if len(args) != 2 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -64,6 +74,10 @@ func (c *CatchAllSetCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (c *CatchAllUnsetCommand) Synopsis() string {
|
|||||||
func (c *CatchAllUnsetCommand) Help() string {
|
func (c *CatchAllUnsetCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s domain
|
%s %s [-n] domain
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -28,6 +28,10 @@ Description:
|
|||||||
Required Args:
|
Required Args:
|
||||||
domain
|
domain
|
||||||
The domain name.
|
The domain name.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -37,6 +41,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *CatchAllUnsetCommand) Run(args []string) int {
|
func (c *CatchAllUnsetCommand) 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 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -55,6 +65,10 @@ func (c *CatchAllUnsetCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (c *DomainAddCommand) Synopsis() string {
|
|||||||
func (c *DomainAddCommand) Help() string {
|
func (c *DomainAddCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s domain
|
%s %s [-n] domain
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -28,6 +28,10 @@ Description:
|
|||||||
Required Args:
|
Required Args:
|
||||||
domain
|
domain
|
||||||
The domain name that you want to create.
|
The domain name that you want to create.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -37,6 +41,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *DomainAddCommand) Run(args []string) int {
|
func (c *DomainAddCommand) 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 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -72,6 +82,10 @@ func (c *DomainAddCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (c *DomainDelCommand) Synopsis() string {
|
|||||||
func (c *DomainDelCommand) Help() string {
|
func (c *DomainDelCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s domain
|
%s %s [-n] domain
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -28,6 +28,10 @@ Description:
|
|||||||
Required Args:
|
Required Args:
|
||||||
domain
|
domain
|
||||||
The domain name that you want to delete.
|
The domain name that you want to delete.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -37,6 +41,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *DomainDelCommand) Run(args []string) int {
|
func (c *DomainDelCommand) 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 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -55,6 +65,10 @@ func (c *DomainDelCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
97
cmd/mailfull/command/domaindisable.go
Normal file
97
cmd/mailfull/command/domaindisable.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/directorz/mailfull-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DomainDisableCommand represents a DomainDisableCommand.
|
||||||
|
type DomainDisableCommand struct {
|
||||||
|
Meta
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis returns a one-line synopsis.
|
||||||
|
func (c *DomainDisableCommand) Synopsis() string {
|
||||||
|
return "Disable a domain temporarily."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help returns long-form help text.
|
||||||
|
func (c *DomainDisableCommand) 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 *DomainDisableCommand) 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 {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
domain, err := repo.Domain(domainName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if domain == nil {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", mailfull.ErrDomainNotExist)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
domain.SetDisabled(true)
|
||||||
|
|
||||||
|
if err := repo.DomainUpdate(domain); err != nil {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
97
cmd/mailfull/command/domainenable.go
Normal file
97
cmd/mailfull/command/domainenable.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/directorz/mailfull-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DomainEnableCommand represents a DomainEnableCommand.
|
||||||
|
type DomainEnableCommand struct {
|
||||||
|
Meta
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis returns a one-line synopsis.
|
||||||
|
func (c *DomainEnableCommand) Synopsis() string {
|
||||||
|
return "Enable a domain."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help returns long-form help text.
|
||||||
|
func (c *DomainEnableCommand) 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 *DomainEnableCommand) 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 {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
domain, err := repo.Domain(domainName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if domain == nil {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", mailfull.ErrDomainNotExist)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
domain.SetDisabled(false)
|
||||||
|
|
||||||
|
if err := repo.DomainUpdate(domain); err != nil {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ Usage:
|
|||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
|
Disabled domains are marked "!" the beginning.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -48,7 +49,12 @@ func (c *DomainsCommand) Run(args []string) int {
|
|||||||
sort.Sort(mailfull.DomainSlice(domains))
|
sort.Sort(mailfull.DomainSlice(domains))
|
||||||
|
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
fmt.Fprintf(c.UI.Writer, "%s\n", domain.Name())
|
disableStr := ""
|
||||||
|
if domain.Disabled() {
|
||||||
|
disableStr = "!"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(c.UI.Writer, "%s%s\n", disableStr, domain.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -11,3 +14,17 @@ type Meta struct {
|
|||||||
SubCmdName string
|
SubCmdName string
|
||||||
Version string
|
Version string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (c *UserAddCommand) Synopsis() string {
|
|||||||
func (c *UserAddCommand) Help() string {
|
func (c *UserAddCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s address
|
%s %s [-n] address
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -29,6 +29,10 @@ Description:
|
|||||||
Required Args:
|
Required Args:
|
||||||
address
|
address
|
||||||
The email address that you want to create.
|
The email address that you want to create.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -38,6 +42,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *UserAddCommand) Run(args []string) int {
|
func (c *UserAddCommand) 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 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -70,6 +80,10 @@ func (c *UserAddCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Required Args:
|
|||||||
Optional Args:
|
Optional Args:
|
||||||
password
|
password
|
||||||
Specify the password instead of your typing.
|
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.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -81,9 +81,9 @@ func (c *UserCheckPwCommand) Run(args []string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
input, err1 := c.UI.AskSecret(fmt.Sprintf("Enter password for %s:", address))
|
input, err := c.UI.AskSecret(fmt.Sprintf("Enter password for %s:", address))
|
||||||
if err1 != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err1)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (c *UserDelCommand) Synopsis() string {
|
|||||||
func (c *UserDelCommand) Help() string {
|
func (c *UserDelCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s address
|
%s %s [-n] address
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -29,6 +29,10 @@ Description:
|
|||||||
Required Args:
|
Required Args:
|
||||||
address
|
address
|
||||||
The email address that you want to delete.
|
The email address that you want to delete.
|
||||||
|
|
||||||
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
`,
|
`,
|
||||||
c.CmdName, c.SubCmdName,
|
c.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -38,6 +42,12 @@ Required Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *UserDelCommand) Run(args []string) int {
|
func (c *UserDelCommand) 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 {
|
if len(args) != 1 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -59,11 +69,20 @@ func (c *UserDelCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if userName == "postmaster" {
|
||||||
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] Cannot delete postmaster.\n")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
if err := repo.UserRemove(domainName, userName); err != nil {
|
if err := repo.UserRemove(domainName, userName); err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func (c *UserPasswdCommand) Synopsis() string {
|
|||||||
func (c *UserPasswdCommand) Help() string {
|
func (c *UserPasswdCommand) Help() string {
|
||||||
txt := fmt.Sprintf(`
|
txt := fmt.Sprintf(`
|
||||||
Usage:
|
Usage:
|
||||||
%s %s address [password]
|
%s %s [-n] address [password]
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
%s
|
%s
|
||||||
@@ -32,9 +32,11 @@ Required Args:
|
|||||||
The email address that you want to update the password.
|
The email address that you want to update the password.
|
||||||
|
|
||||||
Optional Args:
|
Optional Args:
|
||||||
|
-n
|
||||||
|
Don't update databases.
|
||||||
password
|
password
|
||||||
Specify the password instead of your typing.
|
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.CmdName, c.SubCmdName,
|
||||||
c.Synopsis())
|
c.Synopsis())
|
||||||
@@ -44,6 +46,12 @@ Optional Args:
|
|||||||
|
|
||||||
// Run runs the command and returns the exit status.
|
// Run runs the command and returns the exit status.
|
||||||
func (c *UserPasswdCommand) Run(args []string) int {
|
func (c *UserPasswdCommand) 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 {
|
if len(args) != 1 && len(args) != 2 {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help())
|
||||||
return 1
|
return 1
|
||||||
@@ -81,14 +89,14 @@ func (c *UserPasswdCommand) Run(args []string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
input1, err1 := c.UI.AskSecret(fmt.Sprintf("Enter new password for %s:", address))
|
input1, err := c.UI.AskSecret(fmt.Sprintf("Enter new password for %s:", address))
|
||||||
if err1 != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err1)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
input2, err2 := c.UI.AskSecret("Retype new password:")
|
input2, err := c.UI.AskSecret("Retype new password:")
|
||||||
if err2 != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err2)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if input1 != input2 {
|
if input1 != input2 {
|
||||||
@@ -100,9 +108,9 @@ func (c *UserPasswdCommand) Run(args []string) int {
|
|||||||
|
|
||||||
hashedPassword := mailfull.NeverMatchHashedPassword
|
hashedPassword := mailfull.NeverMatchHashedPassword
|
||||||
if rawPassword != "" {
|
if rawPassword != "" {
|
||||||
str, errHash := ssha.Generate(rawPassword, 4)
|
str, err := ssha.Generate(rawPassword, 4)
|
||||||
if errHash != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", errHash)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
hashedPassword = str
|
hashedPassword = str
|
||||||
@@ -115,6 +123,10 @@ func (c *UserPasswdCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if noCommit {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mailData, err := repo.MailData()
|
mailData, err := repo.MailData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err)
|
||||||
|
|||||||
@@ -62,6 +62,14 @@ func main() {
|
|||||||
meta.SubCmdName = c.Subcommand()
|
meta.SubCmdName = c.Subcommand()
|
||||||
return &command.DomainDelCommand{Meta: meta}, nil
|
return &command.DomainDelCommand{Meta: meta}, nil
|
||||||
},
|
},
|
||||||
|
"domaindisable": func() (cli.Command, error) {
|
||||||
|
meta.SubCmdName = c.Subcommand()
|
||||||
|
return &command.DomainDisableCommand{Meta: meta}, nil
|
||||||
|
},
|
||||||
|
"domainenable": func() (cli.Command, error) {
|
||||||
|
meta.SubCmdName = c.Subcommand()
|
||||||
|
return &command.DomainEnableCommand{Meta: meta}, nil
|
||||||
|
},
|
||||||
"aliasdomains": func() (cli.Command, error) {
|
"aliasdomains": func() (cli.Command, error) {
|
||||||
meta.SubCmdName = c.Subcommand()
|
meta.SubCmdName = c.Subcommand()
|
||||||
return &command.AliasDomainsCommand{Meta: meta}, nil
|
return &command.AliasDomainsCommand{Meta: meta}, nil
|
||||||
1
const.go
1
const.go
@@ -5,6 +5,7 @@ const (
|
|||||||
DirNameConfig = ".mailfull"
|
DirNameConfig = ".mailfull"
|
||||||
FileNameConfig = "config"
|
FileNameConfig = "config"
|
||||||
|
|
||||||
|
FileNameDomainDisable = ".vdomaindisable"
|
||||||
FileNameAliasDomains = ".valiasdomains"
|
FileNameAliasDomains = ".valiasdomains"
|
||||||
FileNameUsersPassword = ".vpasswd"
|
FileNameUsersPassword = ".vpasswd"
|
||||||
FileNameUserForwards = ".forward"
|
FileNameUserForwards = ".forward"
|
||||||
|
|||||||
24
database.go
24
database.go
@@ -70,6 +70,10 @@ func (r *Repository) generateDbDomains(md *MailData) error {
|
|||||||
defer dbDomains.Close()
|
defer dbDomains.Close()
|
||||||
|
|
||||||
for _, domain := range md.Domains {
|
for _, domain := range md.Domains {
|
||||||
|
if domain.Disabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := fmt.Fprintf(dbDomains, "%s virtual\n", domain.Name()); err != nil {
|
if _, err := fmt.Fprintf(dbDomains, "%s virtual\n", domain.Name()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -95,6 +99,10 @@ func (r *Repository) generateDbDestinations(md *MailData) error {
|
|||||||
defer dbDestinations.Close()
|
defer dbDestinations.Close()
|
||||||
|
|
||||||
for _, domain := range md.Domains {
|
for _, domain := range md.Domains {
|
||||||
|
if domain.Disabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// ho-ge.example.com -> ho_ge.example.com
|
// ho-ge.example.com -> ho_ge.example.com
|
||||||
underscoredDomainName := domain.Name()
|
underscoredDomainName := domain.Name()
|
||||||
underscoredDomainName = strings.Replace(underscoredDomainName, `-`, `_`, -1)
|
underscoredDomainName = strings.Replace(underscoredDomainName, `-`, `_`, -1)
|
||||||
@@ -153,6 +161,10 @@ func (r *Repository) generateDbMaildirs(md *MailData) error {
|
|||||||
defer dbMaildirs.Close()
|
defer dbMaildirs.Close()
|
||||||
|
|
||||||
for _, domain := range md.Domains {
|
for _, domain := range md.Domains {
|
||||||
|
if domain.Disabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, user := range domain.Users {
|
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 {
|
if _, err := fmt.Fprintf(dbMaildirs, "%s@%s %s/%s/Maildir/\n", user.Name(), domain.Name(), domain.Name(), user.Name()); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -174,6 +186,10 @@ func (r *Repository) generateDbLocaltable(md *MailData) error {
|
|||||||
defer dbLocaltable.Close()
|
defer dbLocaltable.Close()
|
||||||
|
|
||||||
for _, domain := range md.Domains {
|
for _, domain := range md.Domains {
|
||||||
|
if domain.Disabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// ho-ge.example.com -> ho_ge\.example\.com
|
// ho-ge.example.com -> ho_ge\.example\.com
|
||||||
escapedDomainName := domain.Name()
|
escapedDomainName := domain.Name()
|
||||||
escapedDomainName = strings.Replace(escapedDomainName, `-`, `_`, -1)
|
escapedDomainName = strings.Replace(escapedDomainName, `-`, `_`, -1)
|
||||||
@@ -198,6 +214,10 @@ func (r *Repository) generateDbForwards(md *MailData) error {
|
|||||||
defer dbForwards.Close()
|
defer dbForwards.Close()
|
||||||
|
|
||||||
for _, domain := range md.Domains {
|
for _, domain := range md.Domains {
|
||||||
|
if domain.Disabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// ho-ge.example.com -> ho_ge.example.com
|
// ho-ge.example.com -> ho_ge.example.com
|
||||||
underscoredDomainName := domain.Name()
|
underscoredDomainName := domain.Name()
|
||||||
underscoredDomainName = strings.Replace(underscoredDomainName, `-`, `_`, -1)
|
underscoredDomainName = strings.Replace(underscoredDomainName, `-`, `_`, -1)
|
||||||
@@ -234,6 +254,10 @@ func (r *Repository) generateDbPasswords(md *MailData) error {
|
|||||||
defer dbPasswords.Close()
|
defer dbPasswords.Close()
|
||||||
|
|
||||||
for _, domain := range md.Domains {
|
for _, domain := range md.Domains {
|
||||||
|
if domain.Disabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, user := range domain.Users {
|
for _, user := range domain.Users {
|
||||||
if _, err := fmt.Fprintf(dbPasswords, "%s@%s:%s\n", user.Name(), domain.Name(), user.HashedPassword()); err != nil {
|
if _, err := fmt.Fprintf(dbPasswords, "%s@%s:%s\n", user.Name(), domain.Name(), user.HashedPassword()); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
5
doc/README.md
Normal file
5
doc/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
- [Configuration](configuration.md)
|
||||||
|
- [Migrating from mailfull](migrating_from_mailfull.md)
|
||||||
12
doc/configuration.md
Normal file
12
doc/configuration.md
Normal 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 |
|
||||||
24
doc/migrating_from_mailfull.md
Normal file
24
doc/migrating_from_mailfull.md
Normal 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
|
||||||
|
```
|
||||||
121
domain.go
121
domain.go
@@ -11,6 +11,7 @@ import (
|
|||||||
// Domain represents a Domain.
|
// Domain represents a Domain.
|
||||||
type Domain struct {
|
type Domain struct {
|
||||||
name string
|
name string
|
||||||
|
disabled bool
|
||||||
Users []*User
|
Users []*User
|
||||||
AliasUsers []*AliasUser
|
AliasUsers []*AliasUser
|
||||||
CatchAllUser *CatchAllUser
|
CatchAllUser *CatchAllUser
|
||||||
@@ -25,22 +26,41 @@ func (p DomainSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|||||||
|
|
||||||
// NewDomain creates a new Domain instance.
|
// NewDomain creates a new Domain instance.
|
||||||
func NewDomain(name string) (*Domain, error) {
|
func NewDomain(name string) (*Domain, error) {
|
||||||
if !validDomainName(name) {
|
d := &Domain{}
|
||||||
return nil, ErrInvalidDomainName
|
|
||||||
}
|
|
||||||
|
|
||||||
d := &Domain{
|
if err := d.setName(name); err != nil {
|
||||||
name: name,
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return d, nil
|
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.
|
// Name returns name.
|
||||||
func (d *Domain) Name() string {
|
func (d *Domain) Name() string {
|
||||||
return d.name
|
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.
|
// Domains returns a Domain slice.
|
||||||
func (r *Repository) Domains() ([]*Domain, error) {
|
func (r *Repository) Domains() ([]*Domain, error) {
|
||||||
fileInfos, err := ioutil.ReadDir(r.DirMailDataPath)
|
fileInfos, err := ioutil.ReadDir(r.DirMailDataPath)
|
||||||
@@ -62,6 +82,12 @@ func (r *Repository) Domains() ([]*Domain, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disabled, err := r.domainDisabled(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
domain.SetDisabled(disabled)
|
||||||
|
|
||||||
domains = append(domains, domain)
|
domains = append(domains, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +120,38 @@ func (r *Repository) Domain(domainName string) (*Domain, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disabled, err := r.domainDisabled(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
domain.SetDisabled(disabled)
|
||||||
|
|
||||||
return domain, nil
|
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.
|
// DomainCreate creates the input Domain.
|
||||||
func (r *Repository) DomainCreate(domain *Domain) error {
|
func (r *Repository) DomainCreate(domain *Domain) error {
|
||||||
existDomain, err := r.Domain(domain.Name())
|
existDomain, err := r.Domain(domain.Name())
|
||||||
@@ -150,6 +205,29 @@ func (r *Repository) DomainCreate(domain *Domain) error {
|
|||||||
}
|
}
|
||||||
catchAllUserFile.Close()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,3 +260,36 @@ func (r *Repository) DomainRemove(domainName string) error {
|
|||||||
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ smtpd_sasl_path = private/auth
|
|||||||
smtpd_tls_cert_file = /etc/pki/dovecot/certs/dovecot.pem
|
smtpd_tls_cert_file = /etc/pki/dovecot/certs/dovecot.pem
|
||||||
smtpd_tls_key_file = /etc/pki/dovecot/private/dovecot.pem
|
smtpd_tls_key_file = /etc/pki/dovecot/private/dovecot.pem
|
||||||
#smtpd_tls_CAfile =
|
#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
|
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
|
||||||
|
|
||||||
smtp_tls_security_level = may
|
smtp_tls_security_level = may
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ var (
|
|||||||
ErrAliasUserNotExist = errors.New("AliasUser: not exist")
|
ErrAliasUserNotExist = errors.New("AliasUser: not exist")
|
||||||
ErrAliasUserAlreadyExist = errors.New("AliasUser: already exist")
|
ErrAliasUserAlreadyExist = errors.New("AliasUser: already exist")
|
||||||
|
|
||||||
ErrInvalidFormatUsersPassword = errors.New("User: password file invalid format")
|
ErrInvalidFormatDomainDisabled = errors.New("Domain: disabled file invalid format")
|
||||||
ErrInvalidFormatAliasDomain = errors.New("AliasDomain: file invalid format")
|
ErrInvalidFormatUsersPassword = errors.New("User: password file invalid format")
|
||||||
ErrInvalidFormatAliasUsers = errors.New("AliasUsers: file invalid format")
|
ErrInvalidFormatAliasDomain = errors.New("AliasDomain: file invalid format")
|
||||||
|
ErrInvalidFormatAliasUsers = errors.New("AliasUsers: file invalid format")
|
||||||
)
|
)
|
||||||
|
|
||||||
// RepositoryConfig is used to configure a Repository.
|
// RepositoryConfig is used to configure a Repository.
|
||||||
@@ -126,10 +127,10 @@ func OpenRepository(basePath string) (*Repository, error) {
|
|||||||
for {
|
for {
|
||||||
configDirPath := filepath.Join(rootPath, DirNameConfig)
|
configDirPath := filepath.Join(rootPath, DirNameConfig)
|
||||||
|
|
||||||
fi, errStat := os.Stat(configDirPath)
|
fi, err := os.Stat(configDirPath)
|
||||||
if errStat != nil {
|
if err != nil {
|
||||||
if errStat.(*os.PathError).Err != syscall.ENOENT {
|
if err.(*os.PathError).Err != syscall.ENOENT {
|
||||||
return nil, errStat
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package mailfull
|
package mailfull
|
||||||
|
|
||||||
// Version is a version number.
|
// Version is a version number.
|
||||||
const Version = "0.0.2"
|
const Version = "v0.0.5"
|
||||||
|
|||||||
Reference in New Issue
Block a user