all repos — honk @ 9e4b327704b0a58096fbac8285feb9619907464d

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