2 SGBlog -- Git-based CGI blogging engine
3 Copyright (C) 2020 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Affero General Public License as
7 published by the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // Git-based CGI blogging engine email to comments adder
37 "go.cypherpunks.ru/netstring/v2"
40 const WhenFmt = "2006-01-02 15:04:05Z07:00"
43 gitCmd := flag.String("git-cmd", "/usr/local/bin/git", "Path to git executable")
44 gitDir := flag.String("git-dir", "", "Path to .git repository")
45 notesRef := flag.String("ref", "comments", "notes reference name")
46 umask := flag.String("umask", "027", "umask value")
48 uid := syscall.Geteuid()
49 if err := syscall.Setuid(uid); err != nil {
52 umaskInt, err := strconv.ParseUint(*umask, 8, 16)
56 syscall.Umask(int(umaskInt))
58 msg, err := mail.ReadMessage(os.Stdin)
62 subj, r, err := parseEmail(msg)
66 body, err := ioutil.ReadAll(r)
70 from := msg.Header.Get("From")
72 log.Fatal("From is missing")
78 if h, err := hex.DecodeString(subj); err != nil || len(h) != sha1.Size {
81 fromCols := strings.Fields(from)
82 from = strings.Join(fromCols[:len(fromCols)-1], " ")
85 *gitCmd, "--git-dir", *gitDir,
86 "notes", "--ref", *notesRef, "show", subj,
88 note, _ := cmd.Output()
89 note = bytes.TrimSuffix(note, []byte{'\n'})
91 // Remove trailing whitespaces, because git-notes-add will remove
92 // them anyway, and we have to know exact bytes count
93 lines := strings.Split(string(body), "\n")
94 for i, line := range lines {
95 lines[i] = strings.TrimRight(line, " ")
97 for lines[len(lines)-1] == "" {
98 lines = lines[:len(lines)-1]
101 buf := bytes.NewBuffer(note)
102 w := netstring.NewWriter(buf)
103 w.WriteChunk([]byte(fmt.Sprintf(
104 "From: %s\nDate: %s\n\n%s",
106 time.Now().Format(WhenFmt),
107 strings.Join(lines, "\n"),
111 *gitCmd, "--git-dir", *gitDir,
112 "notes", "--ref", *notesRef, "add",
113 "-F", "-", "-f", subj,
116 if err = cmd.Run(); err != nil {