all repos — honk @ f91f3ffe7e2384ba1f52f9784bf181d3f4021354

my fork of honk

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 errx(msg string, args ...interface{}) {
 68	fmt.Fprintf(os.Stderr, msg+"\n", args...)
 69	os.Exit(1)
 70}
 71
 72func main() {
 73	flag.StringVar(&dataDir, "datadir", dataDir, "data directory")
 74	flag.StringVar(&viewDir, "viewdir", viewDir, "view directory")
 75	flag.Parse()
 76
 77	log.Init(log.Options{Progname: "honk", Facility: syslog.LOG_UUCP})
 78	elog = log.E
 79	ilog = log.I
 80	dlog = log.D
 81
 82	if os.Geteuid() == 0 {
 83		elog.Fatalf("do not run honk as root")
 84	}
 85
 86	args := flag.Args()
 87	cmd := "run"
 88	if len(args) > 0 {
 89		cmd = args[0]
 90	}
 91	switch cmd {
 92	case "init":
 93		initdb()
 94	case "upgrade":
 95		upgradedb()
 96	case "version":
 97		fmt.Println(softwareVersion)
 98		os.Exit(0)
 99	}
100	db := opendatabase()
101	dbversion := 0
102	getconfig("dbversion", &dbversion)
103	if dbversion != myVersion {
104		elog.Fatal("incorrect database version. run upgrade.")
105	}
106	getconfig("servermsg", &serverMsg)
107	getconfig("aboutmsg", &aboutMsg)
108	getconfig("loginmsg", &loginMsg)
109	getconfig("servername", &serverName)
110	getconfig("masqname", &masqName)
111	if masqName == "" {
112		masqName = serverName
113	}
114	serverPrefix = fmt.Sprintf("https://%s/", serverName)
115	getconfig("usersep", &userSep)
116	getconfig("honksep", &honkSep)
117	getconfig("devel", &develMode)
118	if develMode {
119		gogglesDoNothing()
120	}
121	getconfig("fasttimeout", &fastTimeout)
122	getconfig("slowtimeout", &slowTimeout)
123	getconfig("honkwindow", &honkwindow)
124	honkwindow *= 24 * time.Hour
125
126	prepareStatements(db)
127
128	dbx := opendatabasex()
129	if dbx == nil {
130		elog.Fatal("dbx is nil")
131	}
132	prepareStatementsx(dbx)
133
134	switch cmd {
135	case "admin":
136		adminscreen()
137	case "import":
138		if len(args) != 4 {
139			errx("import username honk|mastodon|twitter srcdir")
140		}
141		importMain(args[1], args[2], args[3])
142	case "export":
143		if len(args) != 3 {
144			errx("export username destdir")
145		}
146		export(args[1], args[2])
147	case "devel":
148		if len(args) != 2 {
149			errx("need an argument: devel (on|off)")
150		}
151		switch args[1] {
152		case "on":
153			setconfig("devel", 1)
154		case "off":
155			setconfig("devel", 0)
156		default:
157			errx("argument must be on or off")
158		}
159	case "setconfig":
160		if len(args) != 3 {
161			errx("need an argument: setconfig key val")
162		}
163		var val interface{}
164		var err error
165		if val, err = strconv.Atoi(args[2]); err != nil {
166			val = args[2]
167		}
168		setconfig(args[1], val)
169	case "adduser":
170		adduser()
171	case "deluser":
172		if len(args) < 2 {
173			errx("usage: honk deluser username")
174		}
175		deluser(args[1])
176	case "chpass":
177		if len(args) < 2 {
178			errx("usage: honk chpass username")
179		}
180		chpass(args[1])
181	case "follow":
182		if len(args) < 3 {
183			errx("usage: honk follow username url")
184		}
185		user, err := butwhatabout(args[1])
186		if err != nil {
187			errx("user %s not found", args[1])
188		}
189		var meta HonkerMeta
190		mj, _ := jsonify(&meta)
191		honkerid, err := savehonker(user, args[2], "", "presub", "", mj)
192		if err != nil {
193			errx("had some trouble with that: %s", err)
194		}
195		followyou(user, honkerid, true)
196	case "unfollow":
197		if len(args) < 3 {
198			errx("usage: honk unfollow username url")
199		}
200		user, err := butwhatabout(args[1])
201		if err != nil {
202			errx("user not found")
203		}
204		row := db.QueryRow("select honkerid from honkers where xid = ? and userid = ? and flavor in ('sub')", args[2], user.ID)
205		var honkerid int64
206		err = row.Scan(&honkerid)
207		if err != nil {
208			errx("sorry couldn't find them")
209		}
210		unfollowyou(user, honkerid, true)
211	case "sendmsg":
212		if len(args) < 4 {
213			errx("usage: honk send username filename rcpt")
214		}
215		user, err := butwhatabout(args[1])
216		if err != nil {
217			errx("user %s not found", args[1])
218		}
219		data, err := os.ReadFile(args[2])
220		if err != nil {
221			errx("can't read file: %s", err)
222		}
223		deliverate(user.ID, args[3], data)
224	case "cleanup":
225		arg := "30"
226		if len(args) > 1 {
227			arg = args[1]
228		}
229		cleanupdb(arg)
230	case "unplug":
231		if len(args) < 2 {
232			errx("usage: honk unplug servername")
233		}
234		name := args[1]
235		unplugserver(name)
236	case "backup":
237		if len(args) < 2 {
238			errx("usage: honk backup dirname")
239		}
240		name := args[1]
241		svalbard(name)
242	case "ping":
243		if len(args) < 3 {
244			errx("usage: honk ping (from username) (to username or url)")
245		}
246		name := args[1]
247		targ := args[2]
248		user, err := butwhatabout(name)
249		if err != nil {
250			errx("unknown user %s", name)
251		}
252		ping(user, targ)
253	case "run":
254		serve()
255	case "backend":
256		backendServer()
257	case "test":
258		ElaborateUnitTests()
259	default:
260		errx("unknown command")
261	}
262}