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