]> source.dussan.org Git - gitea.git/commitdiff
Add support for extra sendmail arguments (#2731)
authorJonas Bröms <cez81@users.noreply.github.com>
Wed, 25 Oct 2017 19:27:25 +0000 (21:27 +0200)
committerLauris BH <lauris@nix.lv>
Wed, 25 Oct 2017 19:27:25 +0000 (22:27 +0300)
* Add support for extra sendmail arguments

* Sendmail args to exec.command should be a list

* Add go-shellquote package

* Use go-shellquote lib for parsing Sendmail args

* Only parse if sendmail is configured

conf/app.ini
modules/mailer/mailer.go
modules/setting/setting.go
vendor/github.com/kballard/go-shellquote/LICENSE [new file with mode: 0644]
vendor/github.com/kballard/go-shellquote/README [new file with mode: 0644]
vendor/github.com/kballard/go-shellquote/doc.go [new file with mode: 0644]
vendor/github.com/kballard/go-shellquote/quote.go [new file with mode: 0644]
vendor/github.com/kballard/go-shellquote/unquote.go [new file with mode: 0644]
vendor/vendor.json

index 3e07b98e699a3efcb2c8d3895eeb5349233eb766..0ce8aae52e7d25e5df245afd04e5c2dcaade420f 100644 (file)
@@ -327,6 +327,8 @@ SEND_AS_PLAIN_TEXT = false
 USE_SENDMAIL = false
 ; Specify an alternative sendmail binary
 SENDMAIL_PATH = sendmail
+; Specify any extra sendmail arguments
+SENDMAIL_ARGS =
 
 [cache]
 ; Either "memory", "redis", or "memcache", default is "memory"
index 0bb78de92afbf0d0f49bb76a21ac617e4c25e3f4..a54e8361735dde4e125b386b679cf8bbe641bc93 100644 (file)
@@ -209,6 +209,7 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error {
        var waitError error
 
        args := []string{"-F", from, "-i"}
+       args = append(args, setting.MailService.SendmailArgs...)
        args = append(args, to...)
        log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args)
        cmd := exec.Command(setting.MailService.SendmailPath, args...)
index cb8cf7d39aaf36d61f663b90823a207b468107fe..7706ee3e9578022761660d9bee94069876715e68 100644 (file)
@@ -35,6 +35,7 @@ import (
        "github.com/go-macaron/session"
        _ "github.com/go-macaron/session/redis" // redis plugin for store session
        "github.com/go-xorm/core"
+       "github.com/kballard/go-shellquote"
        "gopkg.in/ini.v1"
        "strk.kbt.io/projects/go/libravatar"
 )
@@ -1326,6 +1327,7 @@ type Mailer struct {
        // Sendmail sender
        UseSendmail  bool
        SendmailPath string
+       SendmailArgs []string
 }
 
 var (
@@ -1372,6 +1374,13 @@ func newMailService() {
        MailService.FromName = parsed.Name
        MailService.FromEmail = parsed.Address
 
+       if MailService.UseSendmail {
+               MailService.SendmailArgs, err = shellquote.Split(sec.Key("SENDMAIL_ARGS").String())
+               if err != nil {
+                       log.Error(4, "Failed to parse Sendmail args: %v", CustomConf, err)
+               }
+       }
+
        log.Info("Mail Service Enabled")
 }
 
diff --git a/vendor/github.com/kballard/go-shellquote/LICENSE b/vendor/github.com/kballard/go-shellquote/LICENSE
new file mode 100644 (file)
index 0000000..a6d7731
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (C) 2014 Kevin Ballard
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/kballard/go-shellquote/README b/vendor/github.com/kballard/go-shellquote/README
new file mode 100644 (file)
index 0000000..4d34e87
--- /dev/null
@@ -0,0 +1,36 @@
+PACKAGE
+
+package shellquote
+    import "github.com/kballard/go-shellquote"
+
+    Shellquote provides utilities for joining/splitting strings using sh's
+    word-splitting rules.
+
+VARIABLES
+
+var (
+    UnterminatedSingleQuoteError = errors.New("Unterminated single-quoted string")
+    UnterminatedDoubleQuoteError = errors.New("Unterminated double-quoted string")
+    UnterminatedEscapeError      = errors.New("Unterminated backslash-escape")
+)
+
+
+FUNCTIONS
+
+func Join(args ...string) string
+    Join quotes each argument and joins them with a space. If passed to
+    /bin/sh, the resulting string will be split back into the original
+    arguments.
+
+func Split(input string) (words []string, err error)
+    Split splits a string according to /bin/sh's word-splitting rules. It
+    supports backslash-escapes, single-quotes, and double-quotes. Notably it
+    does not support the $'' style of quoting. It also doesn't attempt to
+    perform any other sort of expansion, including brace expansion, shell
+    expansion, or pathname expansion.
+
+    If the given input has an unterminated quoted string or ends in a
+    backslash-escape, one of UnterminatedSingleQuoteError,
+    UnterminatedDoubleQuoteError, or UnterminatedEscapeError is returned.
+
+
diff --git a/vendor/github.com/kballard/go-shellquote/doc.go b/vendor/github.com/kballard/go-shellquote/doc.go
new file mode 100644 (file)
index 0000000..9445fa4
--- /dev/null
@@ -0,0 +1,3 @@
+// Shellquote provides utilities for joining/splitting strings using sh's
+// word-splitting rules.
+package shellquote
diff --git a/vendor/github.com/kballard/go-shellquote/quote.go b/vendor/github.com/kballard/go-shellquote/quote.go
new file mode 100644 (file)
index 0000000..72a8cb3
--- /dev/null
@@ -0,0 +1,102 @@
+package shellquote
+
+import (
+       "bytes"
+       "strings"
+       "unicode/utf8"
+)
+
+// Join quotes each argument and joins them with a space.
+// If passed to /bin/sh, the resulting string will be split back into the
+// original arguments.
+func Join(args ...string) string {
+       var buf bytes.Buffer
+       for i, arg := range args {
+               if i != 0 {
+                       buf.WriteByte(' ')
+               }
+               quote(arg, &buf)
+       }
+       return buf.String()
+}
+
+const (
+       specialChars      = "\\'\"`${[|&;<>()*?!"
+       extraSpecialChars = " \t\n"
+       prefixChars       = "~"
+)
+
+func quote(word string, buf *bytes.Buffer) {
+       // We want to try to produce a "nice" output. As such, we will
+       // backslash-escape most characters, but if we encounter a space, or if we
+       // encounter an extra-special char (which doesn't work with
+       // backslash-escaping) we switch over to quoting the whole word. We do this
+       // with a space because it's typically easier for people to read multi-word
+       // arguments when quoted with a space rather than with ugly backslashes
+       // everywhere.
+       origLen := buf.Len()
+
+       if len(word) == 0 {
+               // oops, no content
+               buf.WriteString("''")
+               return
+       }
+
+       cur, prev := word, word
+       atStart := true
+       for len(cur) > 0 {
+               c, l := utf8.DecodeRuneInString(cur)
+               cur = cur[l:]
+               if strings.ContainsRune(specialChars, c) || (atStart && strings.ContainsRune(prefixChars, c)) {
+                       // copy the non-special chars up to this point
+                       if len(cur) < len(prev) {
+                               buf.WriteString(prev[0 : len(prev)-len(cur)-l])
+                       }
+                       buf.WriteByte('\\')
+                       buf.WriteRune(c)
+                       prev = cur
+               } else if strings.ContainsRune(extraSpecialChars, c) {
+                       // start over in quote mode
+                       buf.Truncate(origLen)
+                       goto quote
+               }
+               atStart = false
+       }
+       if len(prev) > 0 {
+               buf.WriteString(prev)
+       }
+       return
+
+quote:
+       // quote mode
+       // Use single-quotes, but if we find a single-quote in the word, we need
+       // to terminate the string, emit an escaped quote, and start the string up
+       // again
+       inQuote := false
+       for len(word) > 0 {
+               i := strings.IndexRune(word, '\'')
+               if i == -1 {
+                       break
+               }
+               if i > 0 {
+                       if !inQuote {
+                               buf.WriteByte('\'')
+                               inQuote = true
+                       }
+                       buf.WriteString(word[0:i])
+               }
+               word = word[i+1:]
+               if inQuote {
+                       buf.WriteByte('\'')
+                       inQuote = false
+               }
+               buf.WriteString("\\'")
+       }
+       if len(word) > 0 {
+               if !inQuote {
+                       buf.WriteByte('\'')
+               }
+               buf.WriteString(word)
+               buf.WriteByte('\'')
+       }
+}
diff --git a/vendor/github.com/kballard/go-shellquote/unquote.go b/vendor/github.com/kballard/go-shellquote/unquote.go
new file mode 100644 (file)
index 0000000..ba3a0f2
--- /dev/null
@@ -0,0 +1,144 @@
+package shellquote
+
+import (
+       "bytes"
+       "errors"
+       "strings"
+       "unicode/utf8"
+)
+
+var (
+       UnterminatedSingleQuoteError = errors.New("Unterminated single-quoted string")
+       UnterminatedDoubleQuoteError = errors.New("Unterminated double-quoted string")
+       UnterminatedEscapeError      = errors.New("Unterminated backslash-escape")
+)
+
+var (
+       splitChars        = " \n\t"
+       singleChar        = '\''
+       doubleChar        = '"'
+       escapeChar        = '\\'
+       doubleEscapeChars = "$`\"\n\\"
+)
+
+// Split splits a string according to /bin/sh's word-splitting rules. It
+// supports backslash-escapes, single-quotes, and double-quotes. Notably it does
+// not support the $'' style of quoting. It also doesn't attempt to perform any
+// other sort of expansion, including brace expansion, shell expansion, or
+// pathname expansion.
+//
+// If the given input has an unterminated quoted string or ends in a
+// backslash-escape, one of UnterminatedSingleQuoteError,
+// UnterminatedDoubleQuoteError, or UnterminatedEscapeError is returned.
+func Split(input string) (words []string, err error) {
+       var buf bytes.Buffer
+       words = make([]string, 0)
+
+       for len(input) > 0 {
+               // skip any splitChars at the start
+               c, l := utf8.DecodeRuneInString(input)
+               if strings.ContainsRune(splitChars, c) {
+                       input = input[l:]
+                       continue
+               }
+
+               var word string
+               word, input, err = splitWord(input, &buf)
+               if err != nil {
+                       return
+               }
+               words = append(words, word)
+       }
+       return
+}
+
+func splitWord(input string, buf *bytes.Buffer) (word string, remainder string, err error) {
+       buf.Reset()
+
+raw:
+       {
+               cur := input
+               for len(cur) > 0 {
+                       c, l := utf8.DecodeRuneInString(cur)
+                       cur = cur[l:]
+                       if c == singleChar {
+                               buf.WriteString(input[0 : len(input)-len(cur)-l])
+                               input = cur
+                               goto single
+                       } else if c == doubleChar {
+                               buf.WriteString(input[0 : len(input)-len(cur)-l])
+                               input = cur
+                               goto double
+                       } else if c == escapeChar {
+                               buf.WriteString(input[0 : len(input)-len(cur)-l])
+                               input = cur
+                               goto escape
+                       } else if strings.ContainsRune(splitChars, c) {
+                               buf.WriteString(input[0 : len(input)-len(cur)-l])
+                               return buf.String(), cur, nil
+                       }
+               }
+               if len(input) > 0 {
+                       buf.WriteString(input)
+                       input = ""
+               }
+               goto done
+       }
+
+escape:
+       {
+               if len(input) == 0 {
+                       return "", "", UnterminatedEscapeError
+               }
+               c, l := utf8.DecodeRuneInString(input)
+               if c == '\n' {
+                       // a backslash-escaped newline is elided from the output entirely
+               } else {
+                       buf.WriteString(input[:l])
+               }
+               input = input[l:]
+       }
+       goto raw
+
+single:
+       {
+               i := strings.IndexRune(input, singleChar)
+               if i == -1 {
+                       return "", "", UnterminatedSingleQuoteError
+               }
+               buf.WriteString(input[0:i])
+               input = input[i+1:]
+               goto raw
+       }
+
+double:
+       {
+               cur := input
+               for len(cur) > 0 {
+                       c, l := utf8.DecodeRuneInString(cur)
+                       cur = cur[l:]
+                       if c == doubleChar {
+                               buf.WriteString(input[0 : len(input)-len(cur)-l])
+                               input = cur
+                               goto raw
+                       } else if c == escapeChar {
+                               // bash only supports certain escapes in double-quoted strings
+                               c2, l2 := utf8.DecodeRuneInString(cur)
+                               cur = cur[l2:]
+                               if strings.ContainsRune(doubleEscapeChars, c2) {
+                                       buf.WriteString(input[0 : len(input)-len(cur)-l-l2])
+                                       if c2 == '\n' {
+                                               // newline is special, skip the backslash entirely
+                                       } else {
+                                               buf.WriteRune(c2)
+                                       }
+                                       input = cur
+                               }
+                       }
+               }
+               return "", "", UnterminatedDoubleQuoteError
+       }
+
+done:
+       return buf.String(), input, nil
+}
index df0dcec81474fa0d75dbc25fccbd167eacf32c6e..fb748b3e472d0d145d21c2ee68d38a0066cbfdf8 100644 (file)
                        "revision": "b2c7a7da5b2995941048f60146e67702a292e468",
                        "revisionTime": "2016-02-12T04:00:40Z"
                },
+               {
+                       "checksumSHA1": "+IzngblnBQNh+GmsS2O7jqmzSVQ=",
+                       "path": "github.com/kballard/go-shellquote",
+                       "revision": "cd60e84ee657ff3dc51de0b4f55dd299a3e136f2",
+                       "revisionTime": "2017-06-19T18:30:22Z"
+               },
                {
                        "checksumSHA1": "VJk3rOWfxEV9Ilig5lgzH1qg8Ss=",
                        "path": "github.com/keybase/go-crypto/brainpool",