all repos — honk @ 33e0413e01d0e70f3b2ca06bdc9b0c7ed6ad394b

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