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
159type SomeThing struct {
160 What int
161 XID string
162 Owner string
163 Name string
164}
165
166const (
167 SomeNothing int = iota
168 SomeActor
169 SomeCollection
170)
171
172var serverName string
173var iconName = "icon.png"
174var serverMsg template.HTML
175var aboutMsg template.HTML
176var loginMsg template.HTML
177
178func ElaborateUnitTests() {
179}
180
181func main() {
182 cmd := "run"
183 if len(os.Args) > 1 {
184 cmd = os.Args[1]
185 }
186 switch cmd {
187 case "init":
188 initdb()
189 case "upgrade":
190 upgradedb()
191 }
192 db := opendatabase()
193 dbversion := 0
194 getconfig("dbversion", &dbversion)
195 if dbversion != myVersion {
196 log.Fatal("incorrect database version. run upgrade.")
197 }
198 getconfig("servermsg", &serverMsg)
199 getconfig("aboutmsg", &aboutMsg)
200 getconfig("loginmsg", &loginMsg)
201 getconfig("servername", &serverName)
202 getconfig("usersep", &userSep)
203 getconfig("honksep", &honkSep)
204 prepareStatements(db)
205 switch cmd {
206 case "admin":
207 adminscreen()
208 case "debug":
209 if len(os.Args) != 3 {
210 log.Fatal("need an argument: debug (on|off)")
211 }
212 switch os.Args[2] {
213 case "on":
214 updateconfig("debug", 1)
215 case "off":
216 updateconfig("debug", 0)
217 default:
218 log.Fatal("argument must be on or off")
219 }
220 case "adduser":
221 adduser()
222 case "chpass":
223 chpass()
224 case "cleanup":
225 arg := "30"
226 if len(os.Args) > 2 {
227 arg = os.Args[2]
228 }
229 cleanupdb(arg)
230 case "ping":
231 if len(os.Args) < 4 {
232 fmt.Printf("usage: honk ping from to\n")
233 return
234 }
235 name := os.Args[2]
236 targ := os.Args[3]
237 user, err := butwhatabout(name)
238 if err != nil {
239 log.Printf("unknown user")
240 return
241 }
242 ping(user, targ)
243 case "run":
244 serve()
245 case "test":
246 ElaborateUnitTests()
247 default:
248 log.Fatal("unknown command")
249 }
250}