projects/sievemgr
changeset 0:b00673734e58
Initial revision
Split off sievemgr command from the managesieve repository.
Split off sievemgr command from the managesieve repository.
author | Guido Berhoerster <guido+sievemgr@berhoerster.name> |
---|---|
date | Mon Oct 26 14:19:24 2020 +0100 (4 months ago) |
parents | |
children | 0cd5a454dfb4 |
files | COPYING cmd/sievemgr/activate.go cmd/sievemgr/command.go cmd/sievemgr/common.go cmd/sievemgr/delete.go cmd/sievemgr/get.go cmd/sievemgr/info.go cmd/sievemgr/list.go cmd/sievemgr/main.go cmd/sievemgr/put.go go.mod go.sum |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/COPYING Mon Oct 26 14:19:24 2020 +0100 1.3 @@ -0,0 +1,20 @@ 1.4 +Copyright (C) 2020 Guido Berhoerster <guido+sievemgr@berhoerster.name> 1.5 + 1.6 +Permission is hereby granted, free of charge, to any person obtaining 1.7 +a copy of this software and associated documentation files (the 1.8 +"Software"), to deal in the Software without restriction, including 1.9 +without limitation the rights to use, copy, modify, merge, publish, 1.10 +distribute, sublicense, and/or sell copies of the Software, and to 1.11 +permit persons to whom the Software is furnished to do so, subject to 1.12 +the following conditions: 1.13 + 1.14 +The above copyright notice and this permission notice shall be included 1.15 +in all copies or substantial portions of the Software. 1.16 + 1.17 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1.18 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1.19 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1.20 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 1.21 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 1.22 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1.23 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/cmd/sievemgr/activate.go Mon Oct 26 14:19:24 2020 +0100 2.3 @@ -0,0 +1,81 @@ 2.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 2.5 +// 2.6 +// Permission is hereby granted, free of charge, to any person obtaining 2.7 +// a copy of this software and associated documentation files (the 2.8 +// "Software"), to deal in the Software without restriction, including 2.9 +// without limitation the rights to use, copy, modify, merge, publish, 2.10 +// distribute, sublicense, and/or sell copies of the Software, and to 2.11 +// permit persons to whom the Software is furnished to do so, subject to 2.12 +// the following conditions: 2.13 +// 2.14 +// The above copyright notice and this permission notice shall be included 2.15 +// in all copies or substantial portions of the Software. 2.16 +// 2.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 2.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 2.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 2.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 2.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2.24 + 2.25 +package main 2.26 + 2.27 +import ( 2.28 + "net" 2.29 +) 2.30 + 2.31 +func init() { 2.32 + cmdActivate.Flag.StringVar(&username, "u", "", "Set the username") 2.33 + cmdActivate.Flag.StringVar(&passwordFilename, "P", "", 2.34 + "Set the name of the password file") 2.35 + cmdDeactivate.Flag.StringVar(&username, "u", "", "Set the username") 2.36 + cmdDeactivate.Flag.StringVar(&passwordFilename, "P", "", 2.37 + "Set the name of the password file") 2.38 +} 2.39 + 2.40 +var cmdActivate = &command{ 2.41 + UsageLine: "activate [options] host[:port] name", 2.42 + Run: runActivate, 2.43 +} 2.44 + 2.45 +var cmdDeactivate = &command{ 2.46 + UsageLine: "deactivate [options] host[:port]", 2.47 + Run: runActivate, 2.48 +} 2.49 + 2.50 +func runActivate(cmd *command, args []string) error { 2.51 + if (cmd.Name() == "activate" && len(args) != 2) || 2.52 + (cmd.Name() == "deactivate" && len(args) != 1) { 2.53 + return usageError("invalid number of arguments") 2.54 + } 2.55 + 2.56 + host, port, err := parseHostPort(args[0]) 2.57 + if err != nil { 2.58 + return err 2.59 + } 2.60 + 2.61 + var scriptName string 2.62 + if len(args) > 1 { 2.63 + scriptName = args[1] 2.64 + } 2.65 + 2.66 + username, password, err := usernamePassword(host, port, username, 2.67 + passwordFilename) 2.68 + if err != nil { 2.69 + return err 2.70 + } 2.71 + 2.72 + c, err := dialPlainAuth(net.JoinHostPort(host, port), username, 2.73 + password) 2.74 + if err != nil { 2.75 + return err 2.76 + } 2.77 + defer c.Logout() 2.78 + 2.79 + if err := c.ActivateScript(scriptName); err != nil { 2.80 + return err 2.81 + } 2.82 + 2.83 + return nil 2.84 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/cmd/sievemgr/command.go Mon Oct 26 14:19:24 2020 +0100 3.3 @@ -0,0 +1,45 @@ 3.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 3.5 +// 3.6 +// Permission is hereby granted, free of charge, to any person obtaining 3.7 +// a copy of this software and associated documentation files (the 3.8 +// "Software"), to deal in the Software without restriction, including 3.9 +// without limitation the rights to use, copy, modify, merge, publish, 3.10 +// distribute, sublicense, and/or sell copies of the Software, and to 3.11 +// permit persons to whom the Software is furnished to do so, subject to 3.12 +// the following conditions: 3.13 +// 3.14 +// The above copyright notice and this permission notice shall be included 3.15 +// in all copies or substantial portions of the Software. 3.16 +// 3.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 3.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 3.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 3.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 3.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 3.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 3.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 3.24 + 3.25 +package main 3.26 + 3.27 +import ( 3.28 + "flag" 3.29 + "fmt" 3.30 + "strings" 3.31 +) 3.32 + 3.33 +type command struct { 3.34 + UsageLine string 3.35 + Flag flag.FlagSet 3.36 + Run func(cmd *command, args []string) error 3.37 +} 3.38 + 3.39 +func (c *command) Usage() { 3.40 + fmt.Fprintf(flag.CommandLine.Output(), "usage:\n %s %s\n", 3.41 + flag.CommandLine.Name(), c.UsageLine) 3.42 + fmt.Fprintln(flag.CommandLine.Output(), "options:") 3.43 + c.Flag.PrintDefaults() 3.44 +} 3.45 + 3.46 +func (c *command) Name() string { 3.47 + return strings.SplitN(strings.Trim(c.UsageLine, " "), " ", 2)[0] 3.48 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/cmd/sievemgr/common.go Mon Oct 26 14:19:24 2020 +0100 4.3 @@ -0,0 +1,192 @@ 4.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 4.5 +// 4.6 +// Permission is hereby granted, free of charge, to any person obtaining 4.7 +// a copy of this software and associated documentation files (the 4.8 +// "Software"), to deal in the Software without restriction, including 4.9 +// without limitation the rights to use, copy, modify, merge, publish, 4.10 +// distribute, sublicense, and/or sell copies of the Software, and to 4.11 +// permit persons to whom the Software is furnished to do so, subject to 4.12 +// the following conditions: 4.13 +// 4.14 +// The above copyright notice and this permission notice shall be included 4.15 +// in all copies or substantial portions of the Software. 4.16 +// 4.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 4.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 4.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 4.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 4.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 4.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 4.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 4.24 + 4.25 +package main 4.26 + 4.27 +import ( 4.28 + "bufio" 4.29 + "crypto/tls" 4.30 + "errors" 4.31 + "fmt" 4.32 + "io" 4.33 + "io/ioutil" 4.34 + "net" 4.35 + "os" 4.36 + "os/user" 4.37 + "runtime" 4.38 + "strings" 4.39 + 4.40 + "go.guido-berhoerster.org/managesieve" 4.41 + "golang.org/x/crypto/ssh/terminal" 4.42 +) 4.43 + 4.44 +var errTooBig = errors.New("too big") 4.45 + 4.46 +func parseHostPort(s string) (string, string, error) { 4.47 + var host string 4.48 + host, port, err := net.SplitHostPort(s) 4.49 + if err != nil { 4.50 + // error may be due to a missing port but there is no usable 4.51 + // error value to test for, thus try again with a port added 4.52 + var tmpErr error 4.53 + host, _, tmpErr = net.SplitHostPort(s + ":4190") 4.54 + if tmpErr != nil { 4.55 + return "", "", err 4.56 + } 4.57 + } 4.58 + if port == "" { 4.59 + // no port given, try to look up a SRV record for given domain 4.60 + // and fall back to the domain and port 4190 4.61 + services, err := managesieve.LookupService(host) 4.62 + if err != nil { 4.63 + return "", "", err 4.64 + } 4.65 + host, port, err = net.SplitHostPort(services[0]) 4.66 + if err != nil { 4.67 + return "", "", err 4.68 + } 4.69 + } 4.70 + return host, port, nil 4.71 +} 4.72 + 4.73 +func readPassword() (string, error) { 4.74 + var tty *os.File 4.75 + var fd int 4.76 + var w io.Writer 4.77 + if runtime.GOOS == "windows" { 4.78 + fd = int(os.Stdin.Fd()) 4.79 + w = os.Stdout 4.80 + } else { 4.81 + var err error 4.82 + tty, err = os.OpenFile("/dev/tty", os.O_RDWR, 0666) 4.83 + if err != nil { 4.84 + return "", err 4.85 + } 4.86 + defer tty.Close() 4.87 + fd = int(tty.Fd()) 4.88 + w = tty 4.89 + } 4.90 + 4.91 + io.WriteString(w, "Password: ") 4.92 + rawPassword, err := terminal.ReadPassword(fd) 4.93 + io.WriteString(w, "\n") 4.94 + if err != nil { 4.95 + return "", fmt.Errorf("failed to read password: %s", err) 4.96 + } 4.97 + password := string(rawPassword) 4.98 + if password == "" { 4.99 + return "", fmt.Errorf("invalid password") 4.100 + } 4.101 + return password, nil 4.102 +} 4.103 + 4.104 +func readPasswordFile(filename string) (string, error) { 4.105 + f, err := os.Open(filename) 4.106 + if err != nil { 4.107 + return "", err 4.108 + } 4.109 + defer f.Close() 4.110 + scanner := bufio.NewScanner(f) 4.111 + if !scanner.Scan() { 4.112 + err := scanner.Err() 4.113 + if err == nil { 4.114 + err = fmt.Errorf("failed to read from %q: unexpected EOF", 4.115 + filename) 4.116 + } 4.117 + return "", err 4.118 + } 4.119 + password := scanner.Text() 4.120 + if password == "" { 4.121 + return "", fmt.Errorf("invalid password") 4.122 + } 4.123 + return password, nil 4.124 +} 4.125 + 4.126 +func usernamePassword(host, port, username, passwordFile string) (string, string, error) { 4.127 + // fall back to the system username 4.128 + if username == "" { 4.129 + u, err := user.Current() 4.130 + if err != nil { 4.131 + return "", "", 4.132 + fmt.Errorf("failed to obtain username: %s", err) 4.133 + } 4.134 + username = u.Username 4.135 + } 4.136 + 4.137 + var password string 4.138 + var err error 4.139 + if passwordFile != "" { 4.140 + password, err = readPasswordFile(passwordFilename) 4.141 + } else { 4.142 + password, err = readPassword() 4.143 + } 4.144 + if err != nil { 4.145 + return "", "", err 4.146 + } 4.147 + 4.148 + return username, password, nil 4.149 +} 4.150 + 4.151 +func dialPlainAuth(hostport, username, password string) (*managesieve.Client, error) { 4.152 + c, err := managesieve.Dial(hostport) 4.153 + if err != nil { 4.154 + return nil, fmt.Errorf("failed to connect: %s", err) 4.155 + } 4.156 + 4.157 + host, _, _ := net.SplitHostPort(hostport) 4.158 + // switch to a TLS connection except for localhost 4.159 + if host != "localhost" && host != "127.0.0.1" && host != "::1" { 4.160 + tlsConf := &tls.Config{ 4.161 + ServerName: host, 4.162 + InsecureSkipVerify: skipCertVerify, 4.163 + } 4.164 + if err := c.StartTLS(tlsConf); err != nil { 4.165 + return nil, 4.166 + fmt.Errorf("failed to start TLS connection: %s", 4.167 + err) 4.168 + } 4.169 + } 4.170 + 4.171 + auth := managesieve.PlainAuth("", username, password, host) 4.172 + if err := c.Authenticate(auth); err != nil { 4.173 + return nil, fmt.Errorf("failed to authenticate user %s: %s", 4.174 + username, err) 4.175 + } 4.176 + 4.177 + return c, nil 4.178 +} 4.179 + 4.180 +func readLimitedString(r io.Reader, n int64) (string, error) { 4.181 + var s strings.Builder 4.182 + _, err := io.CopyN(&s, r, n) 4.183 + if err == nil { 4.184 + // check for EOF 4.185 + _, err = io.CopyN(ioutil.Discard, r, 1) 4.186 + if err == nil { 4.187 + return s.String(), errTooBig 4.188 + } 4.189 + } 4.190 + if err != io.EOF { 4.191 + return s.String(), err 4.192 + } 4.193 + 4.194 + return s.String(), nil 4.195 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/cmd/sievemgr/delete.go Mon Oct 26 14:19:24 2020 +0100 5.3 @@ -0,0 +1,69 @@ 5.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 5.5 +// 5.6 +// Permission is hereby granted, free of charge, to any person obtaining 5.7 +// a copy of this software and associated documentation files (the 5.8 +// "Software"), to deal in the Software without restriction, including 5.9 +// without limitation the rights to use, copy, modify, merge, publish, 5.10 +// distribute, sublicense, and/or sell copies of the Software, and to 5.11 +// permit persons to whom the Software is furnished to do so, subject to 5.12 +// the following conditions: 5.13 +// 5.14 +// The above copyright notice and this permission notice shall be included 5.15 +// in all copies or substantial portions of the Software. 5.16 +// 5.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 5.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 5.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 5.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 5.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 5.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 5.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 5.24 + 5.25 +package main 5.26 + 5.27 +import ( 5.28 + "net" 5.29 +) 5.30 + 5.31 +func init() { 5.32 + cmdDelete.Flag.StringVar(&username, "u", "", "Set the username") 5.33 + cmdDelete.Flag.StringVar(&passwordFilename, "P", "", 5.34 + "Set the name of the password file") 5.35 +} 5.36 + 5.37 +var cmdDelete = &command{ 5.38 + UsageLine: "delete [options] host[:port] name", 5.39 + Run: runDelete, 5.40 +} 5.41 + 5.42 +func runDelete(cmd *command, args []string) error { 5.43 + if len(args) != 2 { 5.44 + return usageError("invalid number of arguments") 5.45 + } 5.46 + 5.47 + host, port, err := parseHostPort(args[0]) 5.48 + if err != nil { 5.49 + return err 5.50 + } 5.51 + 5.52 + scriptName := args[1] 5.53 + 5.54 + username, password, err := usernamePassword(host, port, username, 5.55 + passwordFilename) 5.56 + if err != nil { 5.57 + return err 5.58 + } 5.59 + 5.60 + c, err := dialPlainAuth(net.JoinHostPort(host, port), username, 5.61 + password) 5.62 + if err != nil { 5.63 + return err 5.64 + } 5.65 + defer c.Logout() 5.66 + 5.67 + if err := c.DeleteScript(scriptName); err != nil { 5.68 + return err 5.69 + } 5.70 + 5.71 + return nil 5.72 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/cmd/sievemgr/get.go Mon Oct 26 14:19:24 2020 +0100 6.3 @@ -0,0 +1,72 @@ 6.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 6.5 +// 6.6 +// Permission is hereby granted, free of charge, to any person obtaining 6.7 +// a copy of this software and associated documentation files (the 6.8 +// "Software"), to deal in the Software without restriction, including 6.9 +// without limitation the rights to use, copy, modify, merge, publish, 6.10 +// distribute, sublicense, and/or sell copies of the Software, and to 6.11 +// permit persons to whom the Software is furnished to do so, subject to 6.12 +// the following conditions: 6.13 +// 6.14 +// The above copyright notice and this permission notice shall be included 6.15 +// in all copies or substantial portions of the Software. 6.16 +// 6.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 6.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 6.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 6.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 6.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 6.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 6.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 6.24 + 6.25 +package main 6.26 + 6.27 +import ( 6.28 + "net" 6.29 + "os" 6.30 +) 6.31 + 6.32 +func init() { 6.33 + cmdGet.Flag.StringVar(&username, "u", "", "Set the username") 6.34 + cmdGet.Flag.StringVar(&passwordFilename, "P", "", 6.35 + "Set the name of the password file") 6.36 +} 6.37 + 6.38 +var cmdGet = &command{ 6.39 + UsageLine: "get [options] host[:port] name", 6.40 + Run: runGet, 6.41 +} 6.42 + 6.43 +func runGet(cmd *command, args []string) error { 6.44 + if len(args) != 2 { 6.45 + return usageError("invalid number of arguments") 6.46 + } 6.47 + 6.48 + host, port, err := parseHostPort(args[0]) 6.49 + if err != nil { 6.50 + return err 6.51 + } 6.52 + 6.53 + scriptName := args[1] 6.54 + 6.55 + username, password, err := usernamePassword(host, port, username, 6.56 + passwordFilename) 6.57 + if err != nil { 6.58 + return err 6.59 + } 6.60 + 6.61 + c, err := dialPlainAuth(net.JoinHostPort(host, port), username, 6.62 + password) 6.63 + if err != nil { 6.64 + return err 6.65 + } 6.66 + defer c.Logout() 6.67 + 6.68 + script, err := c.GetScript(scriptName) 6.69 + if err != nil { 6.70 + return err 6.71 + } 6.72 + os.Stdout.WriteString(script) 6.73 + 6.74 + return nil 6.75 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/cmd/sievemgr/info.go Mon Oct 26 14:19:24 2020 +0100 7.3 @@ -0,0 +1,84 @@ 7.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 7.5 +// 7.6 +// Permission is hereby granted, free of charge, to any person obtaining 7.7 +// a copy of this software and associated documentation files (the 7.8 +// "Software"), to deal in the Software without restriction, including 7.9 +// without limitation the rights to use, copy, modify, merge, publish, 7.10 +// distribute, sublicense, and/or sell copies of the Software, and to 7.11 +// permit persons to whom the Software is furnished to do so, subject to 7.12 +// the following conditions: 7.13 +// 7.14 +// The above copyright notice and this permission notice shall be included 7.15 +// in all copies or substantial portions of the Software. 7.16 +// 7.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 7.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 7.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 7.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 7.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 7.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 7.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7.24 + 7.25 +package main 7.26 + 7.27 +import ( 7.28 + "fmt" 7.29 + "net" 7.30 +) 7.31 + 7.32 +func init() { 7.33 + cmdInfo.Flag.StringVar(&username, "u", "", "Set the username") 7.34 + cmdInfo.Flag.StringVar(&passwordFilename, "P", "", 7.35 + "Set the name of the password file") 7.36 +} 7.37 + 7.38 +var cmdInfo = &command{ 7.39 + UsageLine: "info [options] host[:port]", 7.40 + Run: runInfo, 7.41 +} 7.42 + 7.43 +func runInfo(cmd *command, args []string) error { 7.44 + if len(args) != 1 { 7.45 + return usageError("invalid number of arguments") 7.46 + } 7.47 + 7.48 + host, port, err := parseHostPort(args[0]) 7.49 + if err != nil { 7.50 + return err 7.51 + } 7.52 + 7.53 + username, password, err := usernamePassword(host, port, username, 7.54 + passwordFilename) 7.55 + if err != nil { 7.56 + return err 7.57 + } 7.58 + 7.59 + c, err := dialPlainAuth(net.JoinHostPort(host, port), username, 7.60 + password) 7.61 + if err != nil { 7.62 + return err 7.63 + } 7.64 + defer c.Logout() 7.65 + 7.66 + fmt.Println(net.JoinHostPort(host, port)) 7.67 + if c.SupportsRFC5804() { 7.68 + fmt.Println("RFC5804 supported") 7.69 + } 7.70 + if c.SupportsTLS() { 7.71 + fmt.Println("STARTTLS supported") 7.72 + } 7.73 + fmt.Printf("SASL mechanisms:\n") 7.74 + for _, m := range c.SASLMechanisms() { 7.75 + fmt.Printf(" %s\n", m) 7.76 + } 7.77 + fmt.Printf("Extensions:\n") 7.78 + for _, e := range c.Extensions() { 7.79 + fmt.Printf(" %s\n", e) 7.80 + } 7.81 + fmt.Printf("Notification methods:\n") 7.82 + for _, m := range c.NotifyMethods() { 7.83 + fmt.Printf(" %s\n", m) 7.84 + } 7.85 + 7.86 + return nil 7.87 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/cmd/sievemgr/list.go Mon Oct 26 14:19:24 2020 +0100 8.3 @@ -0,0 +1,77 @@ 8.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 8.5 +// 8.6 +// Permission is hereby granted, free of charge, to any person obtaining 8.7 +// a copy of this software and associated documentation files (the 8.8 +// "Software"), to deal in the Software without restriction, including 8.9 +// without limitation the rights to use, copy, modify, merge, publish, 8.10 +// distribute, sublicense, and/or sell copies of the Software, and to 8.11 +// permit persons to whom the Software is furnished to do so, subject to 8.12 +// the following conditions: 8.13 +// 8.14 +// The above copyright notice and this permission notice shall be included 8.15 +// in all copies or substantial portions of the Software. 8.16 +// 8.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 8.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 8.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 8.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 8.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 8.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 8.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8.24 + 8.25 +package main 8.26 + 8.27 +import ( 8.28 + "fmt" 8.29 + "net" 8.30 +) 8.31 + 8.32 +func init() { 8.33 + cmdList.Flag.StringVar(&username, "u", "", "Set the username") 8.34 + cmdList.Flag.StringVar(&passwordFilename, "P", "", 8.35 + "Set the name of the password file") 8.36 +} 8.37 + 8.38 +var cmdList = &command{ 8.39 + UsageLine: "list [options] host[:port]", 8.40 + Run: runList, 8.41 +} 8.42 + 8.43 +func runList(cmd *command, args []string) error { 8.44 + if len(args) != 1 { 8.45 + return usageError("invalid number of arguments") 8.46 + } 8.47 + 8.48 + host, port, err := parseHostPort(args[0]) 8.49 + if err != nil { 8.50 + return err 8.51 + } 8.52 + 8.53 + username, password, err := usernamePassword(host, port, username, 8.54 + passwordFilename) 8.55 + if err != nil { 8.56 + return err 8.57 + } 8.58 + 8.59 + c, err := dialPlainAuth(net.JoinHostPort(host, port), username, 8.60 + password) 8.61 + if err != nil { 8.62 + return err 8.63 + } 8.64 + defer c.Logout() 8.65 + 8.66 + scripts, active, _ := c.ListScripts() 8.67 + if err != nil { 8.68 + return err 8.69 + } 8.70 + fmt.Println("ACTIVE SCRIPT") 8.71 + for _, script := range scripts { 8.72 + isActive := "no" 8.73 + if script == active { 8.74 + isActive = "yes" 8.75 + } 8.76 + fmt.Printf("%-3s %s\n", isActive, script) 8.77 + } 8.78 + 8.79 + return nil 8.80 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/cmd/sievemgr/main.go Mon Oct 26 14:19:24 2020 +0100 9.3 @@ -0,0 +1,116 @@ 9.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 9.5 +// 9.6 +// Permission is hereby granted, free of charge, to any person obtaining 9.7 +// a copy of this software and associated documentation files (the 9.8 +// "Software"), to deal in the Software without restriction, including 9.9 +// without limitation the rights to use, copy, modify, merge, publish, 9.10 +// distribute, sublicense, and/or sell copies of the Software, and to 9.11 +// permit persons to whom the Software is furnished to do so, subject to 9.12 +// the following conditions: 9.13 +// 9.14 +// The above copyright notice and this permission notice shall be included 9.15 +// in all copies or substantial portions of the Software. 9.16 +// 9.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 9.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 9.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 9.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 9.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 9.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9.24 + 9.25 +package main 9.26 + 9.27 +import ( 9.28 + "errors" 9.29 + "flag" 9.30 + "fmt" 9.31 + "os" 9.32 +) 9.33 + 9.34 +const ( 9.35 + exitSuccess = iota 9.36 + exitFailure 9.37 + exitUsage 9.38 +) 9.39 + 9.40 +type usageError string 9.41 + 9.42 +func (e usageError) Error() string { 9.43 + return string(e) 9.44 +} 9.45 + 9.46 +var ( 9.47 + skipCertVerify bool 9.48 + username string 9.49 + passwordFilename string 9.50 +) 9.51 + 9.52 +var cmds = []*command{ 9.53 + cmdList, 9.54 + cmdPut, 9.55 + cmdGet, 9.56 + cmdActivate, 9.57 + cmdDeactivate, 9.58 + cmdDelete, 9.59 + cmdInfo, 9.60 +} 9.61 + 9.62 +func usage() { 9.63 + fmt.Fprintf(flag.CommandLine.Output(), 9.64 + "usage:\n %s [options] [subcommand [options] [arguments]]\n", 9.65 + flag.CommandLine.Name()) 9.66 + fmt.Fprintln(flag.CommandLine.Output(), "subcommands:") 9.67 + for _, cmd := range cmds { 9.68 + fmt.Fprintf(flag.CommandLine.Output(), " %s\n", cmd.Name()) 9.69 + } 9.70 + fmt.Fprintln(flag.CommandLine.Output(), "global options:") 9.71 + flag.PrintDefaults() 9.72 +} 9.73 + 9.74 +func main() { 9.75 + flag.Usage = usage 9.76 + flag.BoolVar(&skipCertVerify, "I", false, 9.77 + "Skip TLS certificate verification") 9.78 + flag.Parse() 9.79 + if flag.NArg() == 0 { 9.80 + fmt.Fprintln(flag.CommandLine.Output(), "missing subcommand") 9.81 + usage() 9.82 + os.Exit(exitUsage) 9.83 + } 9.84 + 9.85 + name := flag.Arg(0) 9.86 + var cmd *command 9.87 + for _, c := range cmds { 9.88 + if c.Name() == name { 9.89 + cmd = c 9.90 + break 9.91 + } 9.92 + } 9.93 + if cmd == nil { 9.94 + fmt.Fprintf(flag.CommandLine.Output(), 9.95 + "unknown subcommand %q\n", name) 9.96 + usage() 9.97 + os.Exit(exitUsage) 9.98 + } 9.99 + 9.100 + cmd.Flag.Init(cmd.Name(), flag.ExitOnError) 9.101 + cmd.Flag.Usage = cmd.Usage 9.102 + args := flag.Args() 9.103 + if err := cmd.Flag.Parse(args[1:]); err != nil { 9.104 + fmt.Fprintln(flag.CommandLine.Output(), err) 9.105 + os.Exit(exitFailure) 9.106 + } 9.107 + 9.108 + if err := cmd.Run(cmd, cmd.Flag.Args()); err != nil { 9.109 + fmt.Fprintln(flag.CommandLine.Output(), err) 9.110 + 9.111 + var uerr usageError 9.112 + if errors.As(err, &uerr) { 9.113 + cmd.Usage() 9.114 + os.Exit(exitUsage) 9.115 + } 9.116 + 9.117 + os.Exit(exitFailure) 9.118 + } 9.119 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/cmd/sievemgr/put.go Mon Oct 26 14:19:24 2020 +0100 10.3 @@ -0,0 +1,93 @@ 10.4 +// Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> 10.5 +// 10.6 +// Permission is hereby granted, free of charge, to any person obtaining 10.7 +// a copy of this software and associated documentation files (the 10.8 +// "Software"), to deal in the Software without restriction, including 10.9 +// without limitation the rights to use, copy, modify, merge, publish, 10.10 +// distribute, sublicense, and/or sell copies of the Software, and to 10.11 +// permit persons to whom the Software is furnished to do so, subject to 10.12 +// the following conditions: 10.13 +// 10.14 +// The above copyright notice and this permission notice shall be included 10.15 +// in all copies or substantial portions of the Software. 10.16 +// 10.17 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 10.18 +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10.19 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 10.20 +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 10.21 +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 10.22 +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 10.23 +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10.24 + 10.25 +package main 10.26 + 10.27 +import ( 10.28 + "fmt" 10.29 + "io" 10.30 + "net" 10.31 + "os" 10.32 + 10.33 + "go.guido-berhoerster.org/managesieve" 10.34 +) 10.35 + 10.36 +func init() { 10.37 + cmdPut.Flag.StringVar(&username, "u", "", "Set the username") 10.38 + cmdPut.Flag.StringVar(&passwordFilename, "P", "", 10.39 + "Set the name of the password file") 10.40 +} 10.41 + 10.42 +var cmdPut = &command{ 10.43 + UsageLine: "put [options] host[:port] name [file]", 10.44 + Run: runPut, 10.45 +} 10.46 + 10.47 +func runPut(cmd *command, args []string) error { 10.48 + var scriptName string 10.49 + var r io.Reader = os.Stdin 10.50 + var host, port string 10.51 + var err error 10.52 + switch len(args) { 10.53 + case 3: // name and filename 10.54 + scriptFile, err := os.Open(args[2]) 10.55 + if err != nil { 10.56 + return fmt.Errorf("failed to open script file: %s\n", 10.57 + err) 10.58 + } 10.59 + defer scriptFile.Close() 10.60 + r = scriptFile 10.61 + fallthrough 10.62 + case 2: // only name 10.63 + host, port, err = parseHostPort(args[0]) 10.64 + if err != nil { 10.65 + return err 10.66 + } 10.67 + 10.68 + scriptName = args[1] 10.69 + default: 10.70 + return usageError("invalid number of arguments") 10.71 + } 10.72 + 10.73 + script, err := readLimitedString(r, managesieve.ReadLimit) 10.74 + if err != nil { 10.75 + return fmt.Errorf("failed to read script: %s\n", err) 10.76 + } 10.77 + 10.78 + username, password, err := usernamePassword(host, port, username, 10.79 + passwordFilename) 10.80 + if err != nil { 10.81 + return err 10.82 + } 10.83 + 10.84 + c, err := dialPlainAuth(net.JoinHostPort(host, port), username, 10.85 + password) 10.86 + if err != nil { 10.87 + return err 10.88 + } 10.89 + defer c.Logout() 10.90 + 10.91 + if err := c.PutScript(scriptName, script); err != nil { 10.92 + return err 10.93 + } 10.94 + 10.95 + return nil 10.96 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/go.mod Mon Oct 26 14:19:24 2020 +0100 11.3 @@ -0,0 +1,8 @@ 11.4 +module go.guido-berhoerster.org/sievemgr 11.5 + 11.6 +go 1.14 11.7 + 11.8 +require ( 11.9 + go.guido-berhoerster.org/managesieve v0.0.0-20201026131555-3fe1614de42c 11.10 + golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 11.11 +)
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/go.sum Mon Oct 26 14:19:24 2020 +0100 12.3 @@ -0,0 +1,12 @@ 12.4 +go.guido-berhoerster.org/managesieve v0.0.0-20201026131555-3fe1614de42c h1:4HErjjy83de5F6xWn9Fd+N31KDJh0h1jibO6n0Ye6lw= 12.5 +go.guido-berhoerster.org/managesieve v0.0.0-20201026131555-3fe1614de42c/go.mod h1:uvqvWGFO2zONQiEQuDNH37Mg2pM7gTsDZSXtBOSmj98= 12.6 +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 12.7 +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 12.8 +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= 12.9 +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 12.10 +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 12.11 +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 12.12 +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 12.13 +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 12.14 +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 12.15 +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=