1 #!/usr/bin/perl -Tw 2 $|++; 3 use strict; 4 use CGI qw(:standard escapeHTML); 5 use HTTP::Daemon; 6 use HTTP::Status; 7 use URI::Find; 8 9 ## config 10 my $PORT = 42001; # at what port 11 my $TIMEOUT = 90; # number of quiet seconds before abort 12 my $CHAT_TIME_MAX = 300; # how long to keep old scrollback 13 my $CHAT_COUNT_MAX = 12; # how many messages max 14 my $NAME_MAX = 30; # how long can a name be 15 my $MESS_MAX = 120; # how long can a message be 16 ## end config 17 18 my ($HOST) = $ENV{SERVER_NAME} =~ /(.*)/s; # untaint 19 20 my $d = do { 21 local($^W) = 0; 22 new HTTP::Daemon (LocalAddr => $HOST, LocalPort => $PORT, Reuse => 1) 23 }; 24 my $url = "http://$HOST:$PORT"; 25 26 print header; 27 # durn - no shortcuts for this! what was lincoln thinkin'? :) 28 print <<END; 29 <html><head><title>Chat with us!</title></head> 30 <frameset rows="75%,25%"> 31 <frame src="$url/read10" name=read><frame src="$url/write" name=write> 32 </frameset></html> 33 END 34 35 exit 0 unless defined $d; # do we need to become the server? 36 37 defined(my $pid = fork) or die "Cannot fork: $!"; 38 exit 0 if $pid; # I am the parent 39 close(STDOUT); 40 41 my @CHAT; 42 { 43 alarm($TIMEOUT); # (re-)set the deadman timer 44 my $c = $d->accept or redo; # $c is a connection 45 my $r = $c->get_request; # $r is a request 46 close $c, redo unless $r; # not sure why I need this 47 48 (my $code = $r->url->epath) =~ s{^/}{}; 49 $c->send_basic_header; 50 $CGI::Q = new CGI $r->content; 51 52 print $c header; # start_html is inside switch 53 if (my ($secs) = $code =~ /read(\d+)/) { 54 print $c start_html(-head => ["<meta http-equiv=refresh content=$secs>"]); 55 56 print $c h1("Chat responses"), "Change update to"; 57 print $c " ",a({-href => "$url/read$_"}, $_) for qw(1 2 5 10 15 30 60); 58 print $c " seconds", br; 59 60 shift @CHAT while @CHAT > $CHAT_COUNT_MAX or 61 @CHAT and $CHAT[0][0] < time - $CHAT_TIME_MAX; 62 print $c table( {-border => 0, -cellspacing => 0, -cellpadding => 2 }, 63 map { Tr(td([substr(localtime($_->[0]),11,8).' from '. 64 fix($_->[1]).':', fix($_->[2],1) ]))} @CHAT); 65 66 } elsif ($code =~ /write/) { 67 if (defined(my $name = param('name')) 68 and defined(my $message = param('message'))) { # we have input! 69 tr/\x00-\x1f//d for $name, $message; # remove nasties 70 $name = substr($name, 0, $NAME_MAX) if length $name > $NAME_MAX; 71 $message = substr($message, 0, $MESS_MAX) if length $message > $MESS_MAX; 72 push @CHAT, [time, $name, $message] if length $name and length $message; 73 } 74 75 print $c start_html, h1("Chat write"); 76 print $c start_form(-action => "$url/write"); 77 print $c textfield("name","[I must change my name]", $NAME_MAX), 78 submit("says:"), textfield("message", "", $MESS_MAX, $MESS_MAX, 1); 79 print $c end_form; 80 } 81 82 print $c end_html; 83 84 close $c; 85 redo; 86 } 87 88 sub fix { # HTML escape, plus find URIs if $_[1] 89 local $_ = shift; return escapeHTML($_) unless shift; 90 # use \001 as "shift out", "shift in", presume data doesn't have \001 91 find_uris($_, sub {my ($uri, $text) = @_; 92 qq{\1<a href="\1$uri\1 " target=_blank>\1$text\1</a>\1} }); 93 s/\G(.*?)(?:\001(.*?)\001)?/escapeHTML($1).(defined $2 ? $2 : "")/eig; 94 $_; 95 }