annotate cmd/sievemgr/common.go @ 5:4dff4c3f0fbb

Introduce configuration file where account information is specified Introduce a configuration file where account information must be specified instead of passing it with each invocation on the command line. Each account has a name by which it can be selected and one may be specified as the default account. This is intended to improve usability for productive usage. Enforce strict permissions since passwords may be specified for non-interactive usage. Remove command-line flags for passing account information.
author Guido Berhoerster <guido+sievemgr@berhoerster.name>
date Tue, 03 Nov 2020 23:44:45 +0100
parents 0cd5a454dfb4
children 29769b9e2f09
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
0cd5a454dfb4 Add README file
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 0
diff changeset
1 // Copyright (C) 2020 Guido Berhoerster <guido+sievemgr@berhoerster.name>
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
2 //
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
3 // Permission is hereby granted, free of charge, to any person obtaining
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
4 // a copy of this software and associated documentation files (the
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
5 // "Software"), to deal in the Software without restriction, including
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
6 // without limitation the rights to use, copy, modify, merge, publish,
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
7 // distribute, sublicense, and/or sell copies of the Software, and to
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
8 // permit persons to whom the Software is furnished to do so, subject to
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
9 // the following conditions:
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
10 //
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
11 // The above copyright notice and this permission notice shall be included
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
12 // in all copies or substantial portions of the Software.
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
13 //
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
17 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
18 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
19 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
20 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
21
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
22 package main
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
23
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
24 import (
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
25 "crypto/tls"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
26 "errors"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
27 "fmt"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
28 "io"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
29 "io/ioutil"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
30 "net"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
31 "os"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
32 "runtime"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
33 "strings"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
34
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
35 "go.guido-berhoerster.org/managesieve"
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
36 "go.guido-berhoerster.org/sievemgr/cmd/sievemgr/internal/config"
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
37 "golang.org/x/crypto/ssh/terminal"
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
38 )
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
39
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
40 var errTooBig = errors.New("too big")
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
41
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
42 func getAccount(conf *config.Configuration, name string) (*config.Account, error) {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
43 if name == "" {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
44 if conf.Default == nil {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
45 return nil, fmt.Errorf("no default account configured")
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
46 }
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
47 return conf.Default, nil
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
48 }
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
49 for _, acct := range conf.Accounts {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
50 if acct.Name == name {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
51 return acct, nil
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
52 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
53 }
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
54 return nil, fmt.Errorf("account %q does not exist", name)
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
55 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
56
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
57 func readPassword(acct *config.Account) error {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
58 if acct.Password != "" {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
59 return nil
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
60 }
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
61
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
62 var tty *os.File
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
63 var fd int
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
64 var w io.Writer
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
65 if runtime.GOOS == "windows" {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
66 fd = int(os.Stdin.Fd())
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
67 w = os.Stdout
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
68 } else {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
69 var err error
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
70 tty, err = os.OpenFile("/dev/tty", os.O_RDWR, 0666)
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
71 if err != nil {
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
72 return err
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
73 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
74 defer tty.Close()
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
75 fd = int(tty.Fd())
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
76 w = tty
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
77 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
78
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
79 io.WriteString(w, "Password: ")
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
80 rawPassword, err := terminal.ReadPassword(fd)
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
81 io.WriteString(w, "\n")
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
82 if err != nil {
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
83 return fmt.Errorf("failed to read password: %s", err)
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
84 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
85 password := string(rawPassword)
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
86 if password == "" {
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
87 return fmt.Errorf("invalid password")
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
88 }
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
89 acct.Password = password
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
90 return nil
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
91 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
92
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
93 func lookupHostPort(acct *config.Account) error {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
94 if acct.Port != "" {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
95 return nil
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
96 }
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
97 // no port given, try to look up a SRV record for given domain
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
98 // and fall back to the domain and port 4190
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
99 services, err := managesieve.LookupService(acct.Host)
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
100 if err != nil {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
101 return fmt.Errorf("failed to look up service record: %s", err)
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
102 }
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
103 host, port, err := net.SplitHostPort(services[0])
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
104 if err != nil {
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
105 return fmt.Errorf("failed to parse service record: %s", err)
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
106 }
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
107 acct.Host = host
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
108 acct.Port = port
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
109 return nil
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
110 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
111
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
112 func dialPlainAuth(acct *config.Account) (*managesieve.Client, error) {
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
113 c, err := managesieve.Dial(net.JoinHostPort(acct.Host, acct.Port))
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
114 if err != nil {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
115 return nil, fmt.Errorf("failed to connect: %s", err)
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
116 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
117
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
118 // switch to a TLS connection except for localhost
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
119 if acct.Host != "localhost" && acct.Host != "127.0.0.1" &&
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
120 acct.Host != "::1" {
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
121 tlsConf := &tls.Config{
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
122 ServerName: acct.Host,
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
123 InsecureSkipVerify: acct.Insecure,
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
124 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
125 if err := c.StartTLS(tlsConf); err != nil {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
126 return nil,
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
127 fmt.Errorf("failed to start TLS connection: %s",
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
128 err)
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
129 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
130 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
131
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
132 auth := managesieve.PlainAuth("", acct.User, acct.Password, acct.Host)
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
133 if err := c.Authenticate(auth); err != nil {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
134 return nil, fmt.Errorf("failed to authenticate user %s: %s",
5
4dff4c3f0fbb Introduce configuration file where account information is specified
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents: 1
diff changeset
135 acct.User, err)
0
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
136 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
137
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
138 return c, nil
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
139 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
140
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
141 func readLimitedString(r io.Reader, n int64) (string, error) {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
142 var s strings.Builder
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
143 _, err := io.CopyN(&s, r, n)
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
144 if err == nil {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
145 // check for EOF
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
146 _, err = io.CopyN(ioutil.Discard, r, 1)
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
147 if err == nil {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
148 return s.String(), errTooBig
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
149 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
150 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
151 if err != io.EOF {
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
152 return s.String(), err
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
153 }
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
154
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
155 return s.String(), nil
b00673734e58 Initial revision
Guido Berhoerster <guido+sievemgr@berhoerster.name>
parents:
diff changeset
156 }