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