]> git.plutz.net Git - httpchat/blob - index.cgi
framework
[httpchat] / index.cgi
1 #!/bin/sh
2
3 _EXEC=.
4 _DATA=.
5 . "$_EXEC/cgilite/logging.sh"
6 . "$_EXEC/cgilite/cgilite.sh"
7 . "$_EXEC/cgilite/session.sh"
8 . "$_EXEC/cgilite/storage.sh"
9
10
11 LOCATION="$(PATH "$PATH_INFO")"
12 LOCATION="${LOCATION#/}"
13 LOCATION="${LOCATION%%/*}"
14
15 yield_css(){
16   printf 'Content-Type: text/css; charset=utf-8\r\n\r\n'
17   cat <<ENDCSS
18 * { box-sizing: border-box;}
19 #chat {
20   position: fixed;
21   bottom: 2.5em;
22   left: 0; right: 0;
23   border: 1px solid #08b;
24   padding: 1ex;
25   margin: .5ex;
26   z-index: -1;
27 }
28 form#channel {
29   position: fixed;
30   bottom: 0;
31   left: 0; right: 0;
32 }
33
34 #check_settings { display: none; }
35 #check_settings + label {
36   display: inline-block;
37 }
38 #check_settings + label:before {
39   content: '\2699';
40   padding: .5ex;
41   margin-left: .5ex;
42   margin-right: 2em;
43 }
44 #check_settings + label + #settings { display: none; }
45 #check_settings:checked + label + #settings {
46   display: block;
47   position: fixed;
48   min-width: 20%; max-width: 90%;
49   width: 30em;
50   top: 3em;
51   left: 50%; transform: translate(-50%);
52   background-color: #FFF;
53   border: 1px solid;
54   border-radius: 1ex 1ex .5ex .5ex;
55 }
56 #settings h1 {
57   background-color: #08b;
58   margin: 0;
59   padding: 0 1ex;
60   font-size: 1em;
61   font-weight: bold;
62   border-bottom: 1px solid;
63   border-radius: 1ex 1ex 0 0;
64 }
65 #settings label[for=check_settings] {
66   position: absolute;
67   top: 0; right: 1px;
68   background-color: #F88;
69   border-left: 1px solid;
70   border-radius: 0 1ex 0 0;
71   width: 3ex;
72   overflow: hidden;
73 }
74 #settings label[for=check_settings]:before {
75   content: "x";
76   padding: 0 1ex;
77 }
78 #settings input[type=radio] { display: none; }
79 #settings input[type=radio] + label + * { display: none; }
80 #settings input[type=radio]:checked + label + * { display: block; }
81 #settings input[type=radio] + label {
82   display: block;
83   font-weight: bold;
84   text-decoration: underline;
85   margin: -1px 1px; padding: 0 1ex;
86   border-top: 1px solid;
87   background-color: #EEE;
88 }
89 #settings input[type=radio] + label + * {
90   padding: 1ex 1ex .5ex 1ex;
91 }
92
93 form#channel input[name=message] {
94   display: inline-block;
95   position: absolute;
96   left: 4.5ex;
97   width: calc(100% - 5ex - 1px);
98 }
99 form#channel button[value=submit] { display: none; }
100 #chat .message .date {
101   color: #888;
102   font-size: .75em;
103 }
104 #chat .message .nick {
105   font-weight: bold;
106 }
107 #chat .message .nick .indicator {
108   color: #888;
109 }
110
111 ENDCSS
112 }
113
114 yield_page(){
115   page="$1"
116   printf 'Content-Type: text/html; charset=utf-8\r\n\r\n'
117   { printf '[html
118     [head
119       [meta name="viewport" content="width=device-width"]
120       [link rel="stylesheet" type="text/css" href="/webchat.css"]
121       [title Webchat]
122     ] [body class="%s"
123   ' "$page"
124   cat
125   printf '] ]'
126   } |"$_EXEC/cgilite/html-sh.sed" -u
127 }
128
129 settings_menu(){
130   printf '
131     [input #check_settings type="checkbox"][label for=check_settings Settings]
132     [div #settings
133       [h1 Settings][label for=check_settings Close]
134       [input #set_nick type=radio name="setting" value="nick" selected][label for=set_nick Nickname]
135       [div [input name="nickname" value="%s"][submit "action" "nick" Set Cookie]]
136     ]
137   ' "$(HTML "${nickname#\?}")"
138 }
139
140 case ${LOCATION} in
141   \&?*) chatfile="$_DATA/${LOCATION}"
142        page=channel
143    ;;
144   @?*) if [ -d "$_DATA/${LOCATION}" ]; then
145         chatfile="$_DATA/${LOCATION}/?${SESSION_ID}"
146         page=channel
147       else
148         REDIRECT /
149       fi
150    ;;
151   ~?*) if [ -d "$_DATA/@${LOCATION#~}" ]; then
152         pubinfo="$_DATA/@${LOCATION#~}/pubinfo"
153         page=pubinfo
154       else 
155         REDIRECT /
156       fi
157    ;;
158   webchat.css) yield_css; exit 0;;
159   '') page=front;;
160   *) REDIRECT /;;
161 esac
162
163 if [ "$(COOKIE nick)" ]; then
164   nickname="?$(COOKIE nick)"
165 else
166   nickname='?Guest'
167 fi
168   
169 if [ -f "$chatfile" ]; then
170   read -r channelkey x <"$chatfile"
171   channelkey="$( printf '%s-%s' "$channelkey" "$SESSION_ID" |sha256sum)"
172 fi
173
174 case "$page $(POST action)" in
175   channel\ create)
176     if [ ! -f "$chatfile" ]; then
177       { randomid; printf ' '; STRING "$nickname"; echo; } >"$chatfile"
178     fi
179     REDIRECT "$(URL "/$LOCATION")"
180     ;;
181   channel\ submit)
182     if [ -f "$chatfile" -a "$channelkey" = "$(POST channelkey)" ]; then
183       printf "%s %s: %s\n" "$(date +%F_%T)" "$(STRING "$nickname")" "$(POST message |STRING)" >>"$chatfile"
184     fi
185     REDIRECT "$(URL "/$LOCATION")"
186     ;;
187   channel\ nick)
188     SET_COOKIE +1209600 "nick=$(POST nickname |URL)"
189     REDIRECT "$(URL "/$LOCATION")"
190     ;;
191   channel\ *)
192     if [ ! -f "$chatfile" ]; then
193       yield_page create <<-EOF
194         [form #nonexist method=POST action="$(URL "/$LOCATION")"
195            There is no channel named $(HTML "$LOCATION")
196            [submit "action" "create" Create]
197         ]
198         EOF
199     else
200       { printf '
201         [form #channel method=POST action="%s"
202           [submit "action" "submit" style="display: none;"]
203           [input type=hidden name=channelkey value="%s"]
204           %s [input name="message" autofocus=true][submit "action" "submit" Send!]
205         ]
206       ' "$(URL "/$LOCATION")" "$channelkey" "$(settings_menu)"
207       SHESCAPE='s;[]&<>#."[];\\&;g;'
208
209       printf '[div #chat'
210       # tail -n30 -f "$chatfile" | {
211       #   read x
212       #   while read -r date nick message; do
213       #     printf '[p .message [span .date %s] [span .nick [span .indicator %s]%s:] [span .message %s]]\n' \
214       #            "${date#*_}" "${nick%${nick#?}}" "$(UNSTRING "${nick#?}" |HTML)" "$(UNSTRING "$message" |HTML)"
215       #     done
216       #   }
217       tail -n50 -f "$chatfile" \
218       | sed -nuE '
219         /^[^ ]+ [^ ]+ [^ ]+$/{
220         h; s;^([^ ]+) ([^ ]+) ([^ ]+)$;\1;; s;.*_;;;         s;.+;[p .message [span .date &];p;
221         g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;a\2;; bESC; :A s;.;;; s;(.)(.+);[span .nick [span .indicator \1]\2];p;
222         g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;b\3;; bESC; :B s;.;;; s;.+;[span .message &]];p;
223         }
224         b; :ESC
225         '"$UNSTRING"' '"$SHESCAPE"'
226         /^a/bA; /^b/bB;
227         '
228       } |yield_page channel
229     fi 
230     ;;
231   pubinfo\ *);;
232   front\ *) yield_page front <<-EOF
233         Front
234         EOF
235     ;;
236 esac