all repos — honk @ db582287736dac7593852ab064267de1d2d37b55

my fork of honk

honk.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	"crypto/rsa"
 20	"flag"
 21	"fmt"
 22	"html/template"
 23	"log"
 24	notrand "math/rand"
 25	"os"
 26	"strconv"
 27	"strings"
 28	"time"
 29)
 30
 31var softwareVersion = "develop"
 32
 33func init() {
 34	notrand.Seed(time.Now().Unix())
 35}
 36
 37type WhatAbout struct {
 38	ID      int64
 39	Name    string
 40	Display string
 41	About   string
 42	Key     string
 43	URL     string
 44	Options UserOptions
 45	SecKey  *rsa.PrivateKey
 46}
 47
 48type UserOptions struct {
 49	SkinnyCSS bool   `json:",omitempty"`
 50	Avatar    string `json:",omitempty"`
 51	MapLink   string `json:",omitempty"`
 52}
 53
 54type KeyInfo struct {
 55	keyname string
 56	seckey  *rsa.PrivateKey
 57}
 58
 59const serverUID int64 = -2
 60
 61type Honk struct {
 62	ID       int64
 63	UserID   int64
 64	Username string
 65	What     string
 66	Honker   string
 67	Handle   string
 68	Oonker   string
 69	Oondle   string
 70	XID      string
 71	RID      string
 72	Date     time.Time
 73	URL      string
 74	Noise    string
 75	Precis   string
 76	Format   string
 77	Convoy   string
 78	Audience []string
 79	Public   bool
 80	Whofore  int64
 81	Replies  []*Honk
 82	Flags    int64
 83	HTPrecis template.HTML
 84	HTML     template.HTML
 85	Style    string
 86	Open     string
 87	Donks    []*Donk
 88	Onts     []string
 89	Place    *Place
 90	Time     *Time
 91}
 92
 93type OldRevision struct {
 94	Precis string
 95	Noise  string
 96}
 97
 98const (
 99	flagIsAcked    = 1
100	flagIsBonked   = 2
101	flagIsSaved    = 4
102	flagIsUntagged = 8
103)
104
105func (honk *Honk) IsAcked() bool {
106	return honk.Flags&flagIsAcked != 0
107}
108
109func (honk *Honk) IsBonked() bool {
110	return honk.Flags&flagIsBonked != 0
111}
112
113func (honk *Honk) IsSaved() bool {
114	return honk.Flags&flagIsSaved != 0
115}
116
117func (honk *Honk) IsUntagged() bool {
118	return honk.Flags&flagIsUntagged != 0
119}
120
121type Donk struct {
122	FileID int64
123	XID    string
124	Name   string
125	Desc   string
126	URL    string
127	Media  string
128	Local  bool
129}
130
131type Place struct {
132	Name      string
133	Latitude  float64
134	Longitude float64
135	Url       string
136}
137
138type Duration int64
139
140func (d Duration) String() string {
141	s := time.Duration(d).String()
142	if strings.HasSuffix(s, "m0s") {
143		s = s[:len(s)-2]
144	}
145	if strings.HasSuffix(s, "h0m") {
146		s = s[:len(s)-2]
147	}
148	return s
149}
150
151func parseDuration(s string) time.Duration {
152	didx := strings.IndexByte(s, 'd')
153	if didx != -1 {
154		days, _ := strconv.ParseInt(s[:didx], 10, 0)
155		dur, _ := time.ParseDuration(s[didx:])
156		return dur + 24*time.Hour*time.Duration(days)
157	}
158	dur, _ := time.ParseDuration(s)
159	return dur
160}
161
162type Time struct {
163	StartTime time.Time
164	EndTime   time.Time
165	Duration  Duration
166}
167
168type Honker struct {
169	ID     int64
170	UserID int64
171	Name   string
172	XID    string
173	Handle string
174	Flavor string
175	Combos []string
176}
177
178type SomeThing struct {
179	What  int
180	XID   string
181	Owner string
182	Name  string
183}
184
185const (
186	SomeNothing int = iota
187	SomeActor
188	SomeCollection
189)
190
191var serverName string
192var dataDir = "."
193var viewDir = "."
194var iconName = "icon.png"
195var serverMsg template.HTML
196var aboutMsg template.HTML
197var loginMsg template.HTML
198
199func ElaborateUnitTests() {
200}
201
202func main() {
203	flag.StringVar(&dataDir, "datadir", dataDir, "data directory")
204	flag.StringVar(&viewDir, "viewdir", viewDir, "view directory")
205	flag.Parse()
206	args := flag.Args()
207	cmd := "run"
208	if len(args) > 0 {
209		cmd = args[0]
210	}
211	switch cmd {
212	case "init":
213		initdb()
214	case "upgrade":
215		upgradedb()
216	case "version":
217		fmt.Println(softwareVersion)
218		os.Exit(0)
219	}
220	db := opendatabase()
221	dbversion := 0
222	getconfig("dbversion", &dbversion)
223	if dbversion != myVersion {
224		log.Fatal("incorrect database version. run upgrade.")
225	}
226	getconfig("servermsg", &serverMsg)
227	getconfig("aboutmsg", &aboutMsg)
228	getconfig("loginmsg", &loginMsg)
229	getconfig("servername", &serverName)
230	getconfig("usersep", &userSep)
231	getconfig("honksep", &honkSep)
232	prepareStatements(db)
233	switch cmd {
234	case "admin":
235		adminscreen()
236	case "import":
237		if len(args) != 4 {
238			log.Fatal("import username twitter [srcdir]")
239		}
240		importMain(args[1], args[2], args[3])
241	case "debug":
242		if len(args) != 2 {
243			log.Fatal("need an argument: debug (on|off)")
244		}
245		switch args[1] {
246		case "on":
247			updateconfig("debug", 1)
248		case "off":
249			updateconfig("debug", 0)
250		default:
251			log.Fatal("argument must be on or off")
252		}
253	case "adduser":
254		adduser()
255	case "deluser":
256		if len(args) < 2 {
257			fmt.Printf("usage: honk deluser username\n")
258			return
259		}
260		deluser(args[1])
261	case "chpass":
262		chpass()
263	case "cleanup":
264		arg := "30"
265		if len(args) > 1 {
266			arg = args[1]
267		}
268		cleanupdb(arg)
269	case "ping":
270		if len(args) < 3 {
271			fmt.Printf("usage: honk ping from to\n")
272			return
273		}
274		name := args[1]
275		targ := args[2]
276		user, err := butwhatabout(name)
277		if err != nil {
278			log.Printf("unknown user")
279			return
280		}
281		ping(user, targ)
282	case "run":
283		serve()
284	case "backend":
285		backendServer()
286	case "test":
287		ElaborateUnitTests()
288	default:
289		log.Fatal("unknown command")
290	}
291}