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