all repos — honk @ v1.2.1

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