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