main.go (view raw)
1//
2// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
3//
4// Permission to use, copy, modify, and distribute this software for any
5// purpose with or without fee is hereby granted, provided that the above
6// copyright notice and this permission notice appear in all copies.
7//
8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16package main
17
18import (
19 "flag"
20 "fmt"
21 "html/template"
22 golog "log"
23 "log/syslog"
24 notrand "math/rand"
25 "os"
26 "strconv"
27 "time"
28
29 "humungus.tedunangst.com/r/webs/log"
30)
31
32var softwareVersion = "develop"
33
34func init() {
35 notrand.Seed(time.Now().Unix())
36}
37
38var serverName string
39var serverPrefix string
40var masqName string
41var dataDir = "."
42var viewDir = "."
43var iconName = "icon.png"
44var serverMsg template.HTML
45var aboutMsg template.HTML
46var loginMsg template.HTML
47
48func ElaborateUnitTests() {
49}
50
51func unplugserver(hostname string) {
52 db := opendatabase()
53 xid := fmt.Sprintf("%%https://%s/%%", hostname)
54 db.Exec("delete from honkers where xid like ? and flavor = 'dub'", xid)
55 db.Exec("delete from doovers where rcpt like ?", xid)
56}
57
58func reexecArgs(cmd string) []string {
59 args := []string{"-datadir", dataDir}
60 args = append(args, log.Args()...)
61 args = append(args, cmd)
62 return args
63}
64
65var elog, ilog, dlog *golog.Logger
66
67func main() {
68 flag.StringVar(&dataDir, "datadir", dataDir, "data directory")
69 flag.StringVar(&viewDir, "viewdir", viewDir, "view directory")
70 flag.Parse()
71
72 log.Init(log.Options{Progname: "honk", Facility: syslog.LOG_UUCP})
73 elog = log.E
74 ilog = log.I
75 dlog = log.D
76
77 args := flag.Args()
78 cmd := "run"
79 if len(args) > 0 {
80 cmd = args[0]
81 }
82 switch cmd {
83 case "init":
84 initdb()
85 case "upgrade":
86 upgradedb()
87 case "version":
88 fmt.Println(softwareVersion)
89 os.Exit(0)
90 }
91 db := opendatabase()
92 dbversion := 0
93 getconfig("dbversion", &dbversion)
94 if dbversion != myVersion {
95 elog.Fatal("incorrect database version. run upgrade.")
96 }
97 getconfig("servermsg", &serverMsg)
98 getconfig("aboutmsg", &aboutMsg)
99 getconfig("loginmsg", &loginMsg)
100 getconfig("servername", &serverName)
101 getconfig("masqname", &masqName)
102 if masqName == "" {
103 masqName = serverName
104 }
105 serverPrefix = fmt.Sprintf("https://%s/", serverName)
106 getconfig("usersep", &userSep)
107 getconfig("honksep", &honkSep)
108 getconfig("devel", &develMode)
109 getconfig("fasttimeout", &fastTimeout)
110 getconfig("slowtimeout", &slowTimeout)
111 getconfig("signgets", &signGets)
112 prepareStatements(db)
113 switch cmd {
114 case "admin":
115 adminscreen()
116 case "import":
117 if len(args) != 4 {
118 elog.Fatal("import username mastodon|twitter srcdir")
119 }
120 importMain(args[1], args[2], args[3])
121 case "devel":
122 if len(args) != 2 {
123 elog.Fatal("need an argument: devel (on|off)")
124 }
125 switch args[1] {
126 case "on":
127 setconfig("devel", 1)
128 case "off":
129 setconfig("devel", 0)
130 default:
131 elog.Fatal("argument must be on or off")
132 }
133 case "setconfig":
134 if len(args) != 3 {
135 elog.Fatal("need an argument: setconfig key val")
136 }
137 var val interface{}
138 var err error
139 if val, err = strconv.Atoi(args[2]); err != nil {
140 val = args[2]
141 }
142 setconfig(args[1], val)
143 case "adduser":
144 adduser()
145 case "deluser":
146 if len(args) < 2 {
147 fmt.Printf("usage: honk deluser username\n")
148 return
149 }
150 deluser(args[1])
151 case "chpass":
152 if len(args) < 2 {
153 fmt.Printf("usage: honk chpass username\n")
154 return
155 }
156 chpass(args[1])
157 case "follow":
158 if len(args) < 3 {
159 fmt.Printf("usage: honk follow username url\n")
160 return
161 }
162 user, err := butwhatabout(args[1])
163 if err != nil {
164 fmt.Printf("user not found\n")
165 return
166 }
167 var meta HonkerMeta
168 mj, _ := jsonify(&meta)
169 honkerid, err := savehonker(user, args[2], "", "presub", "", mj)
170 if err != nil {
171 fmt.Printf("had some trouble with that: %s\n", err)
172 return
173 }
174 followyou(user, honkerid, true)
175 case "unfollow":
176 if len(args) < 3 {
177 fmt.Printf("usage: honk unfollow username url\n")
178 return
179 }
180 user, err := butwhatabout(args[1])
181 if err != nil {
182 fmt.Printf("user not found\n")
183 return
184 }
185 row := db.QueryRow("select honkerid from honkers where xid = ? and userid = ? and flavor in ('sub')", args[2], user.ID)
186 var honkerid int64
187 err = row.Scan(&honkerid)
188 if err != nil {
189 fmt.Printf("sorry couldn't find them\n")
190 return
191 }
192 unfollowyou(user, honkerid, true)
193 case "sendmsg":
194 if len(args) < 4 {
195 fmt.Printf("usage: honk send username filename rcpt\n")
196 return
197 }
198 user, err := butwhatabout(args[1])
199 if err != nil {
200 fmt.Printf("user not found\n")
201 return
202 }
203 data, err := os.ReadFile(args[2])
204 if err != nil {
205 fmt.Printf("can't read file\n")
206 return
207 }
208 deliverate(user.ID, args[3], data)
209 case "cleanup":
210 arg := "30"
211 if len(args) > 1 {
212 arg = args[1]
213 }
214 cleanupdb(arg)
215 case "unplug":
216 if len(args) < 2 {
217 fmt.Printf("usage: honk unplug servername\n")
218 return
219 }
220 name := args[1]
221 unplugserver(name)
222 case "backup":
223 if len(args) < 2 {
224 fmt.Printf("usage: honk backup dirname\n")
225 return
226 }
227 name := args[1]
228 svalbard(name)
229 case "ping":
230 if len(args) < 3 {
231 fmt.Printf("usage: honk ping (from username) (to username or url)\n")
232 return
233 }
234 name := args[1]
235 targ := args[2]
236 user, err := butwhatabout(name)
237 if err != nil {
238 elog.Printf("unknown user")
239 return
240 }
241 ping(user, targ)
242 case "run":
243 serve()
244 case "backend":
245 backendServer()
246 case "test":
247 ElaborateUnitTests()
248 default:
249 elog.Fatal("unknown command")
250 }
251}