]> bicyclesonthemoon.info Git - ott/bsta/blob - chat.1.pl
ac274ba367f235181201402db1293e9996077877
[ott/bsta] / chat.1.pl
1 ###PERL;
2 #
3 # /bsta/coin
4 # chat.pl is generated from chat.1.pl.
5 # 11.01.2017
6 #
7 # The coincidence interface
8 #
9 #    Copyright (C) 2016-2017  Balthasar SzczepaƄski
10 #
11 #    This program is free software: you can redistribute it and/or modify
12 #    it under the terms of the GNU Affero General Public License as
13 #    published by the Free Software Foundation, either version 3 of the
14 #    License, or (at your option) any later version.
15 #
16 #    This program is distributed in the hope that it will be useful,
17 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
18 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 #    GNU Affero General Public License for more details.
20 #
21 #    You should have received a copy of the GNU Affero General Public License
22 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
24 use strict;
25 #use warnings;
26 ###LIB;
27 use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile urlencode);
28 use  File::Copy;
29
30 ###LOGO_PATH;
31 ###FAVICON_PATH;
32 ###COIN_PATH;
33 ###CHAT_PATH;
34 ###WEBSITE_NAME;
35 ###FAVICON_PATH;
36 ###CSS_PATH;
37 ###LOGO_PATH;
38 ###WEBSITE;
39 ###COINCIDENCE_PATH;
40 ###CGI_PATH;
41
42 my %http;
43 my %cgi;
44 my %coin;
45 my %chat;
46
47 my $time = time();
48 srand ($time-$$);
49
50 my $method;
51 my $IP;
52 my $page;
53 my $words;
54 my $username;
55 my $action;
56 my $password;
57 my $chatfile;
58 my $state;
59 my $passwordOK;
60 my @chatlines;
61 my $chatstate;
62 my $message;
63 my $chatid;
64 my $lastid;
65
66 delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
67 ###PATH;
68
69 if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
70         $method=$1;
71 }
72 else{
73         exit failpage("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The interface does not support the $ENV{'REQUEST_METHOD'} method.",$method);
74 }
75
76 %http = gethttpheader (\%ENV);
77 %cgi = getcgi($ENV{'QUERY_STRING'});
78
79 if ($method eq 'POST') {
80         if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
81                 my %cgipost=getcgi( <STDIN> );
82                 foreach my $ind (keys %cgipost) {
83                         $cgi{$ind}=$cgipost{$ind};
84                 }
85         }
86         # multipart not supported
87         else{
88                 exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}.");
89         }
90 }
91
92 if ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) {
93         $page=int($1);
94 }
95 else {
96         $page=-1;
97 }
98
99 if ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) {
100         $IP=$1;
101 }
102 else {
103         $IP='0.0.0.0';
104 }
105
106 if ($cgi{'words'} ne '') {
107         $words=$cgi{'words'};
108 }
109 if ($cgi{'username'} ne '') {
110         $username=$cgi{'username'};
111 }
112 if ($cgi{'join'} ne '') {
113         $action=1;
114 }
115 elsif ($cgi{'leave'} ne '') {
116         $action=2;
117 }
118 elsif ($cgi{'nopost'} ne '') {
119         $action=3;
120 }
121 elsif ($cgi{'file'} ne '') {
122         $action=4;
123 }
124 else {
125         $action=0;
126 }
127 if ($cgi{'p'} ne '') {
128         $password=$cgi{'p'};
129 }
130
131 %coin=readdatafile(COIN_PATH);
132
133 if($password eq $coin{'password'}){
134         $passwordOK = 1;
135 }
136 else{
137         $passwordOK = 0;
138         $username = '';
139 }
140
141 if($page < 0) {
142         if (open ($chatfile,"+<",CHAT_PATH)){
143                 if (flock($chatfile,2)) {
144                         %chat=readdatafile($chatfile);
145                         
146                         $chatstate=int($chat{'state'});
147                         $chatid=int($chat{'id'});
148                         $lastid=$chatid;
149                         
150                         if($action==0 && $cgi{'words'} ne '') {
151                                 if($chatstate < 1 && !$passwordOK) {
152                                         $message = 'Not connected.';
153                                 }
154                                 else {
155                                         if ($cgi{'words'} !~ /[\r\n]/) {
156                                                 if($username =~ /^[A-Za-z]*$/) {
157                                                         $chat{'content'}=$chat{'content'}.$username.': '.$cgi{'words'}."\n";
158                                                         if($chatstate < 2) {
159                                                                 $chat{'state'} = 2;
160                                                                 $chatstate = 2;
161                                                         }
162                                                         writedatafile($chatfile,%chat);
163                                                 }
164                                                 else {
165                                                         $message='Invalid username.';
166                                                 }
167                                         }
168                                         else {
169                                                 $message='Invalid text.';
170                                         }
171                                 }
172                         }
173                         elsif ($action==1) {
174                                 if($chatstate > 0 && !$passwordOK) {
175                                         $message = 'Already connected.';
176                                 }
177                                 else {
178                                         if($username =~ /^[A-Za-z]*$/) {
179                                                 if ($passwordOK || $cgi{'words'} eq $coin{'server'}) {
180                                                         $chat{'content'}=$chat{'content'}.'join@'.$username.': '.$cgi{'words'}."\n";
181                                                         if($chatstate < 1) {
182                                                                 $chat{'state'} = 1;
183                                                                 $chatstate = 1;
184                                                         }
185                                                         writedatafile($chatfile,%chat);
186                                                 }
187                                                 elsif ($cgi{'words'} eq '') {
188                                                         $message='Server ID missing.';
189                                                 }
190                                                 elsif ($cgi{'words'} !~ /^[0-9]+$/) {
191                                                         $message='Invalid server ID.';
192                                                 }
193                                                 else {
194                                                         $message='No active Coincidence server with this ID.';
195                                                 }
196                                         }
197                                         else {
198                                                 $message = 'Invalid username.';
199                                         }
200                                 }
201                         }
202                         elsif ($action==2) {
203                                 if($chatstate < 1 && !$passwordOK) {
204                                         $message = 'Already disconnected.';
205                                 }
206                                 else {
207                                         if($username =~ /^[A-Za-z]*$/) {
208                                                 $chat{'content'}=$chat{'content'}.'leave@'.$username.': '.$cgi{'words'}."\n";
209                                                 if($username ne '') {
210                                                         writedatafile($chatfile,%chat);
211                                                 }
212                                                 elsif ($chatstate > 1) {
213                                                         writedatafile(CHAT_PATH.$chatid,%chat);
214                                                         my %newchat;
215                                                         $newchat{'id'}=$chatid+1;
216                                                         $newchat{'state'}=0;
217                                                         $newchat{'content'}='';
218                                                         writedatafile($chatfile,%newchat);
219                                                 }
220                                                 else {
221                                                         my %newchat;
222                                                         $newchat{'id'}=$chatid;
223                                                         $newchat{'state'}=0;
224                                                         $newchat{'content'}='';
225                                                         writedatafile($chatfile,%newchat);
226                                                 }
227                                         }
228                                         else {
229                                                 $message = 'Invalid username.';
230                                         }
231                                 }
232                         }
233                         elsif($action==4 && $cgi{'file'} ne '' && $cgi{'words'} ne '' &&  $passwordOK) {
234                                 if ($cgi{'words'} !~ /[\r\n]/) {
235                                         if($username =~ /^[A-Za-z]*$/) {
236                                                 $chat{'content'}=$chat{'content'}.'file@'.$username.': '.$cgi{'words'}."\n";
237                                                 if($chatstate < 2) {
238                                                         $chat{'state'} = 2;
239                                                         $chatstate = 2;
240                                                 }
241                                                 writedatafile($chatfile,%chat);
242                                         }
243                                         else {
244                                                 $message='Invalid username.';
245                                         }
246                                 }
247                                 else {
248                                         $message='Invalid text.';
249                                 }
250                         }
251                         
252                         @chatlines = split(/\r?\n/,$chat{'content'});
253                 }
254                 else{
255                         $chatstate=0;
256                         $message='Can\'t lock data file!';
257                 }
258                 
259                 
260                 close($chatfile);
261         }
262         else {
263                 $chatstate=0;
264                 $message='Can\'t open data file!';
265         }
266 }
267 else {
268         # %chat=readdatafile(CHAT_PATH);
269         # $chatid=int($chat{'id'})-$page;
270         %chat=readdatafile(CHAT_PATH);
271         $lastid=int($chat{'id'});
272         %chat=readdatafile(CHAT_PATH.$page);
273         $chatid=int($chat{'id'});
274         $chatstate=int($chat{'state'});
275         @chatlines = split(/\r?\n/,$chat{'content'});
276 }
277
278
279 # print "Content-type: text/plain\n\n";
280 # print CHAT_PATH."\n";
281 # print 'state: '.$chat{'state'}."\n";
282 # print 'id: '.$chat{'id'}."\n\n";
283 # print $chat{'content'};
284
285 print "Content-type: text/html\n\n";
286 if($method eq 'HEAD') {
287         exit;
288 }
289
290 print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
291 print '<html lang="en"><head>'."\n";
292 print '<title>Coincidence &bull; '.WEBSITE_NAME.'</title>'."\n";
293 print '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
294 print '<link rel="icon" type="image/png" href="'.FAVICON_PATH.'">'."\n";
295 print '<link rel="stylesheet" href="'.CSS_PATH.'">'."\n";
296 print '</head><body>'."\n";
297 print '<a href="/"><img id="botmlogo" src="'.LOGO_PATH.'" alt="'.WEBSITE.'"></a>'."\n";
298 print '<div id="all">'."\n";
299
300 print '<div id="inst" class="ins">'."\n";
301
302 print '<div id="title">'."\n";
303 print '<H1 id="titletext">Coincidence</H1>'."\n";
304 print '</div>'."\n";
305
306 print '<div id="storypuzzle">'."\n";
307 if ($page >= 0) {
308         print 'Before: '.$chatid."\n";
309 }
310 elsif ($chatstate>0){
311         print 'Connected to server <span class="br">'.entityencode($coin{'server'}).'</span> as user <span class="ni">'.entityencode(($username ne '')?$username:$coin{'name'}).'</span> (<span class="ni">'.entityencode(abbrname(($username ne '')?$username:$coin{'name'})).'</span>), public key <span class="br">'.entityencode($coin{'key'}).'</span>.'."\n";
312 }
313 else{
314         print 'Not connected.';
315 }
316 print '</div>'."\n";
317 print '<div id="command">'."\n";
318 if ($message ne '') {
319         print '<span class="br">'.entityencode($message).'</span>'."\n";
320 }
321 if ($page < 0) {
322         print '<form method="post" action="'.COINCIDENCE_PATH.'">'."\n";
323         if ($passwordOK) {
324                 print '<input class="intxc" type="text" name="words">'."\n";
325                 print '<input class="inbt" type="submit" value="Send">'."\n";
326                 print "|\n";
327                 print '<input class="intx" type="text" name="username" value="'.entityencode($username).'">'."\n";
328                 print '<input class="inbt" type="submit" name="nopost" value="Refresh">'."\n";
329                 print '<input class="inbt" type="submit" name="join" value="Connect">'."\n";
330                 print '<input class="inbt" type="submit" name="leave" value="Disconnect">'."\n";
331                 print '<input class="inbt" type="submit" name="file" value="Send file">'."\n";
332                 print '<input type="hidden" name="p" value="'.entityencode($coin{'password'}).'">'."\n";
333         }
334         elsif ($chatstate>0) {
335                 print '<input class="intxc" type="text" name="words">'."\n";
336                 print '<input class="inbt" type="submit" value="Send">'."\n";
337                 print "|\n";
338                 print '<input class="inbt" type="submit" name="nopost" value="Refresh">'."\n";
339                 print '<input class="inbt" type="submit" name="leave" value="Disconnect">'."\n";
340         }
341         else {
342                 print '<input class="intx" type="text" name="words">'."\n";
343                 print '<input class="inbt" type="submit" name="join" value="Connect">'."\n";
344         }
345         print '</form>'."\n";
346 }
347 print '</div>'."\n";
348
349 print '</div><div id="insb" class="ins">'."\n";
350
351 print '<div id="chat">'."\n";
352 if ($page < 0) {
353         for (my $i = @chatlines-1; $i>=0; --$i) {
354                 print chatline($chatlines[$i])."<br>\n";
355         }
356 }
357 else {
358         for (my $i = 0; $i<@chatlines; ++$i) {
359                 print chatline($chatlines[$i])."<br>\n";
360         }
361 }
362 print '</div>'."\n";
363
364 print '<div id="underlinks">'."\n";
365 print '<a href="'.CGI_PATH.'">BSTA</a> | <a href="'.COINCIDENCE_PATH.($passwordOK?('?p='.urlencode($coin{'password'})):'').'">Once again</a>';
366 if ($chatid > 0) {
367         print ' | <a href="'.COINCIDENCE_PATH.'/'.($chatid-1).($passwordOK?('?p='.urlencode($coin{'password'})):'').'">Before</a>';
368 }
369 if ($chatid < $lastid) {
370         print ' | <a href="'.COINCIDENCE_PATH.'/'.(($chatid < $lastid-1)?($chatid +1):'').($passwordOK?('?p='.urlencode($coin{'password'})):'').'">Unbefore</a>';
371 }
372 if ($chatid > 0) {
373         print ' | <a href="'.COINCIDENCE_PATH.'/0'.($passwordOK?('?p='.urlencode($coin{'password'})):'').'">Initially</a>';
374 }
375 print ' | (This interface is only a demo, a proof of concept. It is very limited. No autorefresh, no private chat, etc. For full functionality use the actual Coincidence client.)'."\n";
376 print "\n";
377 print '</div>'."\n";
378
379 print '</div>'."\n";
380 print '</div>'."\n";
381 print '<a href="/" class="cz">'.WEBSITE.'</a>'."\n";
382 print '</body></html>'."\n";
383
384
385
386 # print CHAT_PATH."\n";
387 # print 'state: '.$chat{'state'}."\n";
388 # print 'id: '.$chat{'id'}."\n\n";
389 # print $chat{'content'};
390
391 sub abbrname {
392         (my $name) = @_;
393         my $abbr;
394         
395         if($name !~ /^[A-Za-z]+$/) {
396                 return '?';
397         }
398         
399         $abbr = uc(substr($name,0,1));
400         $name = substr($name,1);
401         while($name =~ m/([A-Z])/g) {
402                 $abbr = $abbr.$1;
403         }
404         return $abbr;
405 }
406
407 sub chatline {
408         (my $line) = @_;
409         my $action;
410         my $name;
411         my $text;
412         
413         if ($line =~ /^([a-z]*@)?([A-Za-z]*): (.*)$/) {
414                 $action=$1;
415                 $name=$2;
416                 $text=$3;
417                 
418                 if($action ne ''){
419                         if ($action eq 'join@') {
420                                 return entityencode(($name ne '')?$name:$coin{'name'}).' ('.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).') joined the public chat on server '.entityencode($coin{'server'}).'.';
421                         }
422                         elsif ($action eq 'leave@') {
423                                 return entityencode(($name ne '')?$name:$coin{'name'}).' ('.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).') left the public chat on server '.entityencode($coin{'server'}).'.';
424                         }
425                         elsif ($action eq 'file@') {
426                                 return entityencode(($name ne '')?$name:$coin{'name'}).' ('.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).') sent the file '.entityencode($text).'.';
427                         }
428                         else {
429                                 return 'E:E:E';
430                         }
431                 }
432                 else {
433                         return '<span class="'.(($name ne '')?'br':'ni').'">'.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).': '.entityencode($text).'</span>';
434                 }
435         }
436         else {
437                 return 'E:E:E';
438         }
439 }