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