#!/usr/local/bin/perl # webqstat.cgi by David Efflandt (efflandt@xnet.com) # 10/10/97 - Last modified 1/28/99 # # Displays status of a QuakeWorld or Q2 server in HTML table format. # Includes team totals and players sorted by frags. # Should work with any browser that supports tables (no plugin req'd). # It even displays in lynx. Suitable for use as server side include. # Script tested on Linux and Solaris. # # Requires qstat 2.0b or newer by Steve Jankowski (steve@activesw.com) # available as UNIX source and compiled Win32 versions. # http://www.activesw.com/people/steve/qstat.html # ftp://ftp.activesw.com/pub/quake ### User Variables ### # Comment out following line if it displays in an SSI print "Content-type: text/html\n\n"; # Example to work with different paths depending upon hostname $hostname = `hostname`; if ($hostname =~ /efflandt/) { $qstat = '/usr/local/games/quake2/qstat'; } else { $qstat = '/home/hurricane/efflandt/src/qstat/qstat'; } # Or comment out the above and use actual path to your qstat: # $qstat = '/full_path_to/qstat'; # Your town or nearest major city (for time zone) $city = 'Chicago'; # Display rules? 0 = no, 1 = yes $rules = 1; # For standalone CGI, a non-default server can be poled by following # URL of script with either "?" or "/" and then "server[:port]". # "server" can be IP or hostname. # # Example: webqstat.cgi?198.147.221.120:27910 # # For SSI the following could be edited to add servers by linking # this script to alternative names with dash and option and parsing # the name for options. For example webqstat.cgi for one server and # webqstat-dm.cgi for another. # Get arguments from program name. $arg = $0; $arg =~ s/(\.cgi|\.pl)//; #strip .cgi|.pl name extension $arg =~ s!^(.*-)!!; # chop program name # Other possible sources of options $arg = $ARGV[0] if $ARGV[0]; $arg = $ENV{'PATH_INFO'} if $ENV{'PATH_INFO'}; $arg =~ s!/!!; # strip leading / from path info $arg = $ENV{'QUERY_STRING'} if $ENV{'QUERY_STRING'}; # Hostname or IP address of server. # :port required if not QW default (:27500) if ($arg =~ /^\w+[\.\:]+/) { # specific server[:port] $arg =~ /([\w\.\:]+)/; $server = $1 } elsif ($arg eq 'dm') { # sample option $server = '198.147.221.120'; # QW } else { # default $server = '198.147.221.120:27910'; # Q2 } # Edit switches only for non-QW/Q2 server $buffer = `$qstat -R -P -cn -raw "|,|" -qws $server`; ### Uncomment to test table vs. raw & formatted data # print "
$buffer
\n"; # $test = `$qstat -P -qws $server`; # print "
$test
\n";
### End of User Variables ###
# Browser safe colors
%rgb = (
White => 'FFFFFF',
Brown => 'CC9966',
Lavender => '9966FF',
Khaki => 'CCCC99',
Red => 'FF0000',
'Lt Brown' => 'FFCC99',
Peach => 'FFCC00',
'Lt Peach' => 'FFCCCC',
Purple => 'CC66FF',
'Dk Purple' => 'FF99FF',
Tan => 'FFFFCC',
Green => '00CC99',
Yellow => 'FFFF00',
Blue => '0000FF'
);
# Begin html table with main server data
@lines = split("\n", $buffer);
$_ = shift @lines;
($type,$addr,$server,$map,$max,$players,$response,$retry) =
split /\|,\|/, $_;
$now = scalar localtime();
$response .= "ms";
$map = "none" unless $map;
# Get rules
$rulelist = shift @lines;
if ($type eq "Q2") {
@rules = split /\|,\|/, $rulelist;
while ($_ = shift @rules) {
($key, $value) = split /=/, $_;
if ($key =~ /version/i) { $qver = "$value \n";
# Display rule table (optional, see Variables above)
if ($rules) {
print " \n";
}
\n"; }
}
}
print <
$server
$qver$city Time: $nowADDRESS PLAYERS MAP RESPONSE
EOF
# Organize player data if any
if (@lines) {
while ($_ = shift @lines) {
if ($type eq "Q2") {
($name,$frags,$ping) = split /\|,\|/, $_;
} else {
($id,$name,$frags,$time,$shirt,$pants,$ping,$skin) =
split /\|,\|/, $_;
}
$name =~ s/[<]/<\;/g;
$name =~ s/[>]/>\;/g;
$name = "noname$nn++" unless $name =~ /[\w]/;
push @namelist, $name;
$frags{$pants} += $frags;
if ($ping < 2000) {
$ping{$pants} += $ping;
$pingn{$pants}++;
}
$count{$pants}++;
++$i;
%new_folks = (
frags => $frags,
time => $time,
shirt => $shirt,
pants => $pants,
ping => $ping,
skin => $skin
);
for $what (keys %new_folks) {
$player{$name}{$what} = $new_folks{$what};
}
}
# Display team totals if more than one player per team
$teams = keys %count;
if ($rule{teamplay} && $players > $teams) {
print "$addr $players / $max
$map $response / $retry \n";
print " TEAMS FRAGS AVE PING COLOR\n";
sub frags {$frags{$b} <=> $frags{$a};}
foreach $team (sort frags keys %count) {
$ping = int $ping{$team}/$pingn{$team};
$ping .= "ms ave";
print qq( );
print qq($count{$team} PLAYERS $frags{$team}\n);
print qq( $ping );
print qq($team\n);
}
}
# Display players if any
print " \n";
if ($type eq "Q2") {
print " NAME FRAGS PING\n";
} else {
print " NAME FRAGS TIME";
print " SKIN COLOR\n";
}
sub byfrag {$player{$b}{frags} <=> $player{$a}{frags};}
foreach $name (sort byfrag @namelist) {
$frags = $player{$name}{frags};
$time = $player{$name}{time};
if ($time) {
$time = $time/60 . "m\@";
} else {
$time = "";
}
$shirt = $player{$name}{shirt};
$shirtrgb = $rgb{$shirt};
$pants = $player{$name}{pants};
$pantsrgb = $rgb{$pants};
$ping = $player{$name}{ping};
if ($ping > 0) {
$ping .= "ms";
} else {
$ping = "cl_nodelta";
}
$skin = $player{$name}{skin};
$skin = "?" unless $skin;
if ($type eq "Q2") {
print " $name $frags"
. " $ping\n";
} else {
print " $name $frags"
. " $time$ping $skin";
print qq( );
print qq($shirt);
print qq( );
print qq($pants \n);
}
}
}
print "";
print "
";
print qq(
$server\n);
print " RULE VALUE\n";
@rules = split /\|,\|/, $rulelist;
while ($_ = shift @rules) {
($key, $value) = split /=/, $_;
print " $key $value\n";
}
print "