all repos — honk @ 303fa380ccb67edb416ed1dfb9b8640774a3f53c

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	Mentions []Mention
 92}
 93
 94type Mention struct {
 95	Who   string
 96	Where string
 97}
 98
 99type OldRevision struct {
100	Precis string
101	Noise  string
102}
103
104const (
105	flagIsAcked    = 1
106	flagIsBonked   = 2
107	flagIsSaved    = 4
108	flagIsUntagged = 8
109)
110
111func (honk *Honk) IsAcked() bool {
112	return honk.Flags&flagIsAcked != 0
113}
114
115func (honk *Honk) IsBonked() bool {
116	return honk.Flags&flagIsBonked != 0
117}
118
119func (honk *Honk) IsSaved() bool {
120	return honk.Flags&flagIsSaved != 0
121}
122
123func (honk *Honk) IsUntagged() bool {
124	return honk.Flags&flagIsUntagged != 0
125}
126
127type Donk struct {
128	FileID int64
129	XID    string
130	Name   string
131	Desc   string
132	URL    string
133	Media  string
134	Local  bool
135}
136
137type Place struct {
138	Name      string
139	Latitude  float64
140	Longitude float64
141	Url       string
142}
143
144type Duration int64
145
146func (d Duration) String() string {
147	s := time.Duration(d).String()
148	if strings.HasSuffix(s, "m0s") {
149		s = s[:len(s)-2]
150	}
151	if strings.HasSuffix(s, "h0m") {
152		s = s[:len(s)-2]
153	}
154	return s
155}
156
157func parseDuration(s string) time.Duration {
158	didx := strings.IndexByte(s, 'd')
159	if didx != -1 {
160		days, _ := strconv.ParseInt(s[:didx], 10, 0)
161		dur, _ := time.ParseDuration(s[didx:])
162		return dur + 24*time.Hour*time.Duration(days)
163	}
164	dur, _ := time.ParseDuration(s)
165	return dur
166}
167
168type Time struct {
169	StartTime time.Time
170	EndTime   time.Time
171	Duration  Duration
172}
173
174type Honker struct {
175	ID     int64
176	UserID int64
177	Name   string
178	XID    string
179	Handle string
180	Flavor string
181	Combos []string
182	Meta   HonkerMeta
183}
184
185type HonkerMeta struct {
186	Notes string
187}
188
189type SomeThing struct {
190	What  int
191	XID   string
192	Owner string
193	Name  string
194}
195
196const (
197	SomeNothing int = iota
198	SomeActor
199	SomeCollection
200)
201
202var serverName string
203var dataDir = "."
204var viewDir = "."
205var iconName = "icon.png"
206var serverMsg template.HTML
207var aboutMsg template.HTML
208var loginMsg template.HTML
209
210func ElaborateUnitTests() {
211}
212
213func main() {
214	flag.StringVar(&dataDir, "datadir", dataDir, "data directory")
215	flag.StringVar(&viewDir, "viewdir", viewDir, "view directory")
216	flag.Parse()
217	args := flag.Args()
218	cmd := "run"
219	if len(args) > 0 {
220		cmd = args[0]
221	}
222	switch cmd {
223	case "init":
224		initdb()
225	case "upgrade":
226		upgradedb()
227	case "version":
228		fmt.Println(softwareVersion)
229		os.Exit(0)
230	}
231	db := opendatabase()
232	dbversion := 0
233	getconfig("dbversion", &dbversion)
234	if dbversion != myVersion {
235		log.Fatal("incorrect database version. run upgrade.")
236	}
237	getconfig("servermsg", &serverMsg)
238	getconfig("aboutmsg", &aboutMsg)
239	getconfig("loginmsg", &loginMsg)
240	getconfig("servername", &serverName)
241	getconfig("usersep", &userSep)
242	getconfig("honksep", &honkSep)
243	prepareStatements(db)
244	switch cmd {
245	case "admin":
246		adminscreen()
247	case "import":
248		if len(args) != 4 {
249			log.Fatal("import username twitter [srcdir]")
250		}
251		importMain(args[1], args[2], args[3])
252	case "debug":
253		if len(args) != 2 {
254			log.Fatal("need an argument: debug (on|off)")
255		}
256		switch args[1] {
257		case "on":
258			updateconfig("debug", 1)
259		case "off":
260			updateconfig("debug", 0)
261		default:
262			log.Fatal("argument must be on or off")
263		}
264	case "adduser":
265		adduser()
266	case "chpass":
267		chpass()
268	case "cleanup":
269		arg := "30"
270		if len(args) > 1 {
271			arg = args[1]
272		}
273		cleanupdb(arg)
274	case "ping":
275		if len(args) < 3 {
276			fmt.Printf("usage: honk ping from to\n")
277			return
278		}
279		name := args[1]
280		targ := args[2]
281		user, err := butwhatabout(name)
282		if err != nil {
283			log.Printf("unknown user")
284			return
285		}
286		ping(user, targ)
287	case "run":
288		serve()
289	case "backend":
290		backendServer()
291	case "test":
292		ElaborateUnitTests()
293	default:
294		log.Fatal("unknown command")
295	}
296}