--- /dev/null
+#@@PERL@@
+
+# $Id: wap-spong.pl,v 1.1 2000/09/25 20:53:33 sljohnson Exp $
+
+#
+# This program is used to display information collected by the spong server to
+# people using WAP enabled clients. This provides the same type of interface to
+# the data as the text based client does. You can run this program as a CGI
+# program to provide an interactive experience, or you can use it from a cron
+# job, or some other automated process to just generate static web pages.
+#
+
+# !!!!! This is a very beta program. Not all of the WAP display options
+# are present. The old HTML code is present in several cases.
+
+use Sys::Hostname;
+use Getopt::Long;
+use Socket;
+use POSIX;
+
+# Load our configuration variables, including the user specified configuration
+# information (spong.conf, spong.hosts, and spong.groups files).
+
+$|++;
+$conf_file = "@@ETCDIR@@/spong.conf";
+$hosts_file = "@@ETCDIR@@/spong.hosts";
+$groups_file = "@@ETCDIR@@/spong.groups";
+$SPONGVER = "@@SPONGVER@@";
+($HOST) = gethostbyname(&Sys::Hostname::hostname());
+$HOST =~ tr/A-Z/a-z/;
+$view = "";
+$actionbar = 1;
+$interactive = 0;
+
+%HUMANS = ();
+%HOSTS = ();
+%GROUPS = ();
+
+&load_config_files(); # Loads the user specified configuration information
+
+# Check to see if I am being run as a command line program (in which case I
+# just generate static WML documents), or a CGI program (in which case I
+# present back an interactive WAP interface). The command line arguments are
+# the same as the text based spong program, and produce similar results
+
+if( $ENV{'SCRIPT_NAME'} eq "" ) {
+ # Get the user options and spit back a message if they do something silly
+
+ my %opt;
+ my @options = ( "help", "summary:s", "problems:s", "history:s", "host=s",
+ "services=s", "stats=s", "config=s", "info=s", "service=s",
+ "histservice=s", "grp-summary:s", "grp-problems",
+ "brief", "standard", "full" );
+
+ if( ! GetOptions( \%opt, @options )) {warn "Incorrect usage:\n\n"; &help();}
+
+ &help if defined $opt{'help'};
+
+ if( defined $opt{'brief'} ) { $view = "brief"; }
+ if( defined $opt{'standard'} ) { $view = "standard"; }
+ if( defined $opt{'full'} ) { $view = "full"; }
+
+ if( defined $opt{'problems'} ) { &problems( $opt{'problems'} ); $opt = 1; }
+ if( defined $opt{'summary'} ) { &summary( $opt{'summary'} ); $opt = 1; }
+ if( defined $opt{'history'} ) { &history( $opt{'history'} ); $opt = 1; }
+
+ if( defined $opt{'host'} ) { &host( $opt{'host'} ); $opt = 1; }
+ if( defined $opt{'services'} ) { &services( $opt{'services'} ); $opt = 1; }
+ if( defined $opt{'stats'} ) { &stats( $opt{'stats'} ); $opt = 1; }
+ if( defined $opt{'config'} ) { &config( $opt{'config'} ); $opt = 1; }
+ if( defined $opt{'info'} ) { &info( $opt{'info'} ); $opt = 1; }
+
+ if( defined $opt{'service'} ) {
+ my( $host, $service ) = split( ':', $opt{'service'} );
+ &service( $host, $service );
+ $opt = 1;
+ }
+
+ if ( defined $opt{'histservice'} ) {
+ my( $host, $service, $time ) = split ( ':', $opt{'histservice'} );
+ &histservice( $host, "$service $time" );
+ $opt=1;
+ }
+
+ if ( defined $opt{'grp-summary'} ) { &grp_summary( $opt{'grp-summary'} ); $opt= 1; }
+ if ( defined $opt{'grp-problems'} ) { &grp_problems( $opt{'grp-problems'} ); $opt= 1; }
+
+ if( ! $opt ) { &summary( "all" ); }
+
+ exit(0);
+}
+
+
+# If we make it to this point, then we are a CGI program so pull apart the
+# commands given to us via the URL path, and treat them as if they are command
+# line options
+
+$interactive = 1;
+
+$cmd = $ENV{'PATH_INFO'};
+
+# Commands that are more applicable to spong running in interactive mode.
+
+if( $cmd eq "" || $cmd eq "/" ) {
+ $view = "brief";
+ grp_summary("ALL");
+ exit;
+}
+if ($cmd =~ m!^/title$! ) { &title(); exit; }
+
+if( $cmd =~ m!^/group/(.*)$! ) { &interactive( $1 ); exit; }
+if( $cmd =~ m!^/bygroup/(.*)$! ) { &ovinteractive( $1 ); exit; }
+if( $cmd =~ m!^/commands/(.*)$! ) { &commands( $1 ); exit; }
+
+if( $cmd =~ m!^/ovcommands/(.*)$! ) { &ovcommands( $1 ); exit; }
+if( $cmd =~ m!^/igrp-summary/(.*)$! ) { &igrp_summary( $1 ); exit; }
+if( $cmd =~ m!^/igrp-overview/(.*)$! ) { &igrp_overview( $1 ); exit; }
+
+if( $cmd =~ m!^/isummary/(.*)$! ) { &isummary( $1 ); exit; }
+if( $cmd =~ m!^/ihistory/(.*)$! ) { &ihistory( $1 ); exit; }
+
+if( $cmd =~ m!^/groups$! ) { &groups(); exit; }
+if( $cmd =~ m!^/groups-doit$! ) { &groups_doit(); exit; }
+
+if( $cmd =~ m!^/help$! ) { &show( "help" ); exit; }
+if( $cmd =~ m!^/help/(.*)$! ) { &show( "$1" ); exit; }
+
+# Simple commands to just display a specific host attribute, or other specific
+# information. These commands can easily be called by pages outside of spong
+
+if( $cmd =~ m!^/brief/(.*)$! ) { $view = "brief"; $cmd = "/$1"; }
+if( $cmd =~ m!^/standard/(.*)$! ) { $view = "standard"; $cmd = "/$1"; }
+if( $cmd =~ m!^/full/(.*)$! ) { $view = "full"; $cmd = "/$1"; }
+
+if( $cmd =~ m!^/problems/(.*)$! ) { &problems($1); exit;}
+if( $cmd =~ m!^/summary/(.*)$! ) { &summary($1); exit;}
+if( $cmd =~ m!^/history/(.*)$! ) { &history($1); exit;}
+
+if( $cmd =~ m!^/host/(.*)$! ) { &host($1); exit;}
+if( $cmd =~ m!^/services/(.*)$! ) { &services($1); exit;}
+if( $cmd =~ m!^/stats/(.*)$! ) { &stats($1); exit;}
+if( $cmd =~ m!^/config/(.*)$! ) { &config($1); exit;}
+if( $cmd =~ m!^/info/(.*)$! ) { &info($1); exit;}
+
+if( $cmd =~ m!^/service/(.*)/(.*)$! ) { &service( $1, $2 ); exit; }
+
+if( $cmd =~ m!^/histservice/(.*)/(.*)/(.*)$! ) { &histservice( $1, "$2 $3" ); exit; }
+
+if( $cmd =~ m!^/grp-summary/(.*)$! ) { &grp_summary( $1 ); exit;}
+if( $cmd =~ m!^/grp-problems/(.*)$! ) { &grp_problems( $1 ); exit;}
+
+# Need to do something when an invalid request comes through...
+exit(0);
+
+
+
+# ---------------------------------------------------------------------------
+# Functions that support the interactive WWWSPONG client
+# ---------------------------------------------------------------------------
+
+# This sets up the wwwspong interface, it defines the frame that both the
+# commands & error summary information is shown, and the frame for more
+# detailed host information.
+
+
+sub toplevel {
+
+ print "Content-type: text/html\n\n";
+ print "<html><head>\n";
+ print "<title>Spong v$SPONGVER - System Status Monitor</title></head>\n";
+ print "<frameset rows=\"40,*\" border=5 frameboard=no>";
+ print "<frame src=\"$main::WWWSPONG/title\" marginwidth=5 ";
+ print "marginheight=5 noshade name=\"title\">\n";
+ print "<frame src=\"";
+
+ print "$main::WWWSPONG/bygroup/" if $main::WWW_DEFAULT_VIEW eq "GROUPS";
+ print "$main::WWWSPONG/group/all" if $main::WWW_DEFAULT_VIEW eq "HOSTS";
+
+ print "\" marginwidth=10 ";
+ print "marginheight=5 noshade name=\"view\" border=1>\n";
+ print "</frameset>\n";
+ print "<noframe>\n";
+ print "Frameless version not currently available.\n";
+ print "</noframes>\n</html>\n";
+}
+
+sub interactive {
+ my $group = shift;
+
+ print "Content-type: text/html\n\n";
+ print "<html><head>\n";
+ print "<title>Spong v$SPONGVER - System Status Monitor</title></head>\n";
+ print "<frameset cols=\"240,*\" border=5 frameboard=no>";
+ print "<frame src=\"$main::WWWSPONG/commands/$group\" marginwidth=5 ";
+ print "marginheight=5 noshade>\n";
+ print "<frame src=\"$main::WWWSPONG/isummary/$group\" marginwidth=10 ";
+ print "marginheight=5 noshade name=\"right\" border=1>\n";
+ print "</frameset>\n";
+ print "<noframe>\n";
+ print "Frameless version not currently available.\n";
+ print "</noframes>\n</html>\n";
+}
+
+sub ovinteractive {
+ my $group = shift;
+
+ print "Content-type: text/html\n\n";
+ print "<html><head>\n";
+ print "<title>Spong v$SPONGVER - System Status Monitor</title></head>\n";
+ print "<frameset cols=\"240,*\" border=5 frameboard=no>";
+ print "<frame src=\"$main::WWWSPONG/ovcommands/\" marginwidth=5 ";
+ print "marginheight=5 noshade>\n";
+ print "<frame src=\"$main::WWWSPONG/igrp-summary/\" marginwidth=10 ";
+ print "marginheight=5 noshade name=\"right\" border=1>\n";
+ print "</frameset>\n";
+ print "<noframe>\n";
+ print "Frameless version not currently available.\n";
+ print "</noframes>\n</html>\n";
+}
+
+# This function fills out the Title header. It had a command bar that changes
+# the the current View type in the 'view' frame
+
+sub title {
+ &header(0);
+
+ my $me = $main::WWWSPONG;
+
+ print "<base target=view>\n";
+# print "<center>";
+ print "<font size=+2><b>Spong v$SPONGVER</b></font>\n";
+# print "</center>\n";
+# print "<br>";
+ print "<a href=\"$me/bygroup/\">Groups</a> || \n";
+ print "<a href=\"$me/group/all\">Hosts</a> \n";
+
+# print "<b>Extra Tool Bar Commands:</b> ";
+# print " <a href=\"/spong-rrd/index.html\">Spong RRD Charts</a>\n";
+# print " || <a href=\"/cgi-bin/sysquery.pl?target=showall\">System Summaries</a>\n";
+
+ if ( $main::WWW_TITLE_ACTIONBAR ) { print $main::WWW_TITLE_ACTIONBAR,"\n"; }
+}
+
+
+# This function fills out the action bar of the interactive spong display.
+# This lists the functions that you can perform via the web interface.
+
+sub commands {
+ my $group = shift;
+ my $me = $main::WWWSPONG;
+
+ $group = "all" unless $group;
+ my $gname = $main::GROUPS{$group}->{'name'} if $main::GROUPS{$group};
+ $gname = "Selected Hosts" unless $gname;
+
+ &header( 1 );
+
+ print "<base target=right>\n";
+# print "<font size=+2><b>Spong v$SPONGVER</b></font>\n";
+ print "<font size=+2><b>Hosts View</b></font>\n";
+ unless ($WWWFRAMES == 3) {
+ print "<hr>\n";
+ print "<b>Views: <a href=\"$me/bygroup/\" target=_top>Groups</a> || \n";
+ print "<a href=\"$me/group/all\" target=_top>Hosts</a> \n";
+ }
+ print "<hr>\n";
+
+ print "<a href=\"$main::WWWACK\">Ack</a> || \n";
+ print "<a href=\"$me/isummary/$group\">Summary</a> || \n";
+ print "<a href=\"$me/ihistory/$group\">History</a> || \n";
+ print "<a href=\"$me/help\">Help</a>\n";
+ print "<hr>\n<p>\n";
+
+ &problems( $group );
+
+ print "<p><hr><a href=\"$me/groups\">Group</a>: <b>$gname</b>\n<hr>\n";
+ print "Updated at ", POSIX::strftime( "$TIMEFMTNOSEC, on $DATEFMT", localtime() ), "\n";
+ &footer();
+}
+
+
+sub ovcommands {
+ my $group = shift;
+ my $me = $main::WWWSPONG;
+
+ $group = "all" unless $group;
+# my $gname = $main::GROUPS{$group}->{'name'} if $main::GROUPS{$group};
+# $gname = "Selected Hosts" unless $gname;
+
+ &header( 1 );
+
+ print "<base target=right>\n";
+# print "<font size=+2><b>Spong v$SPONGVER</b></font>\n";
+ print "<font size=+2><b>Groups View</b></font>\n";
+ unless ($WWWFRAMES == 3) {
+ print "<hr>\n";
+ print "<b>Views: </b><a href=\"$me/bygroup/\" target=_top>Groups</a> || \n";
+ print "<a href=\"$me/group/all\" target=_top>Hosts</a> \n";
+ }
+ print "<hr>\n";
+
+ print "<a href=\"$me/igrp-summary/\">Groups</a> || \n";
+ print "<a href=\"$me/igrp-overview/\">Group Summary</a>\n";
+ print "<hr>\n";
+
+ print "<a href=\"$main::WWWACK\">Ack</a> || \n";
+# print "<a href=\"$me/isummary/$group\">Summary</a> || \n";
+ print "<a href=\"$me/ihistory/all\">History</a> || \n";
+ print "<a href=\"$me/help\">Help</a>\n";
+ print "<hr>\n<p>\n";
+
+ &grp_problems( $group );
+
+ print "<p><hr>";
+# print "<a href=\"$me/groups\">Group</a>: <b>$gname</b>\n<hr>\n";
+ print "Updated at ", POSIX::strftime( "$TIMEFMTNOSEC, on $DATEFMT", localtime() ), "\n";
+ &footer();
+}
+
+
+# A couple of slightly different functions to display summary and history
+# information for people using the wwwspong program interactivly. This just
+# puts a little header above each output, so that you know what group it
+# corresponds to.
+
+sub isummary {
+ my $group = shift;
+ my $gname = $main::GROUPS{$group}->{'name'} if $main::GROUPS{$group};
+ $gname = "Selected Hosts" unless $gname;
+
+ &header( 1 );
+ print "<font size=+2><b>$gname</b></font>\n<hr>\n";
+ &summary( $group );
+ &footer();
+}
+
+sub ihistory {
+ my $group = shift;
+ my $gname = $main::GROUPS{$group}->{'name'} if $main::GROUPS{$group};
+ $gname = "Selected Hosts" unless $gname;
+
+ &header( 1 );
+ print "<font size=+2><b>$gname</b></font>\n<hr>\n";
+ &history( $group );
+ &footer();
+}
+
+sub igrp_summary {
+ my $group = shift;
+# my $gname = $main::GROUPS{$group}->{'name'} if $main::GROUPS{$group};
+# $gname = "Selected Hosts" unless $gname;
+
+ &header( 1 );
+ print "<font size=+2><b>Host Groups</b></font>\n<hr>\n";
+ $main::view = "full";
+ &grp_summary($group);
+ &footer();
+}
+
+sub igrp_overview {
+ my $group = shift;
+# my $gname = $main::GROUPS{$group}->{'name'} if $main::GROUPS{$group};
+# $gname = "Selected Hosts" unless $gname;
+
+ &header( 1 );
+ print "<font size=+2><b>Host Groups Summary</b></font>\n<hr>\n";
+ $view = "standard";
+ &grp_summary($group);
+ &footer();
+}
+
+
+
+# This provides a page that lists the groups that are defined in spong, and
+# you can select a group to monitor (summary information will then only be
+# shown about that group).
+
+sub groups {
+ my $group;
+
+ &header( $group, "Groups", '', 0 );
+ print "<base target=view>\n";
+ print "<font size=+2><b>Spong Groups</b></font>\n<hr>\n";
+
+ print "You can select a specific group to show only information about ";
+ print "those hosts. The groups below have been defined by the spong ";
+ print "administrator.<p>\n";
+
+ print "<ul>\n";
+ foreach $group ( @main::GROUPS_LIST ) {
+ my $name = $main::GROUPS{$group}->{'name'};
+ my $summary = $main::GROUPS{$group}->{'summary'};
+
+ print "<li><a href=\"$main::WWWSPONG/group/$group\">$name</a> ";
+ print "($group)<br>\n$summary<p>\n";
+ }
+ print "</ul><p>\n";
+ print "<hr noshade>\n";
+
+ print "You can also build a custom group to monitor by selecting one or ";
+ print "hosts from the list below.<p>\n";
+ print "<form action=\"$WWWSPONG/groups-doit\" method=get>\n";
+ print "<center><table width=80% border=0>\n";
+ print "<tr><td width=50% valign=top align=center>\n";
+ print "<select name=\"hosts\" size=10 multiple>\n";
+
+ foreach $host ( @main::HOSTS_LIST ) { print "<option>$host\n"; }
+
+ print "</select>\n";
+ print "</td><td width=50% valign=center align=center>\n";
+ print "<input type=submit name=\" Show Hosts \" value=\" Show Hosts \">\n";
+ print "</td></tr></table>\n";
+ print "</form>\n";
+ print "<hr>\n";
+
+ &footer();
+}
+
+# The action part of the above form. The hosts are pulled out of the query
+# string and passed as a group name to the &interactive() functions.
+
+sub groups_doit {
+ my $group = "";
+ while( $ENV{'QUERY_STRING'} =~ /hosts=([^\&]+)/isg ) { $group .= "$1,"; }
+ chop $group;
+ &interactive( $group );
+}
+
+
+# ---------------------------------------------------------------------------
+# Functions that correspond to command line/URL line arguments
+# ---------------------------------------------------------------------------
+
+sub problems {
+ my $group = shift;
+ my $view = $main::view || "full";
+
+ $group = "all" unless $group;
+
+ &header( 1 );
+ print &query( $SPONGSERVER, "problems", $group, "html", $view );
+ &footer();
+}
+
+sub summary {
+ my $group = shift;
+ my $view = $main::view || "standard";
+
+ $group = "all" unless $group;
+
+ &header( 1 );
+
+ print "<p align=\"center\">\n";
+ print "<anchor title=\"Probs\">Problems";
+ print "<go href=\"$main::WAPSPONG/problems\"/></anchor><br/>\n";
+ print POSIX::strftime($DATETIMEFMT,localtime()),"<br/><br/></p>\n";
+ print "<p align=\"center\">\n";
+ print &query( $SPONGSERVER, "summary", $group, "wml", $view );
+ print "</p>\n";
+ &footer();
+}
+
+sub history {
+ my $group = shift;
+ my $view = $main::view || "standard";
+
+ $group = "all" unless $group;
+
+ &header( 1 );
+ print &query( $SPONGSERVER, "history", $group, "html", $view );
+ &footer();
+}
+
+
+sub host {
+ my $host = shift;
+ my $view = $main::view || "standard";
+
+ &header( 0 );
+ print &query( $SPONGSERVER, "host", $host, "html", $view );
+ &footer();
+}
+
+sub services {
+ my $host = shift;
+ my $view = $main::view || "standard";
+
+ header(1);
+
+ print "<p align=\"center\">\n";
+ print "<anchor title=\"Summary\">Summary";
+ print "<go href=\"$main::WAPSPONG/brief/grp-summary/ALL\"/></anchor><br/>\n";
+ print POSIX::strftime($DATETIMEFMT,localtime()),"<br/><br/></p>\n";
+ print "<p align=\"center\">\n";
+ print "<b> $host </b><br/><br/>\n";
+ print &query( $SPONGSERVER, "services", $host, "wml", $view );
+ print "</p>\n";
+
+ &footer();
+}
+
+sub stats {
+ my $host = shift;
+ my $view = $main::view || "standard";
+
+ &header( 0 );
+ print &query( $SPONGSERVER, "stats", $host, "html", $view );
+ &footer();
+}
+
+sub config {
+ my $host = shift;
+ my $view = $main::view || "standard";
+
+ &header( 0 );
+ print &query( $SPONGSERVER, "config", $host, "html", $view );
+ &footer();
+}
+
+sub info {
+ my $host = shift;
+ my $view = $main::view || "standard";
+
+ &header( 0 );
+ print &query( $SPONGSERVER, "info", $host, "html", $view );
+ &footer();
+}
+
+
+sub service {
+ my( $host, $service ) = @_;
+ my $view = $main::view || "full";
+
+ header(1);
+
+ print "<p align=\"center\">\n";
+ print "<anchor title=\"Host\">Host";
+ print "<go href=\"$main::WAPSPONG/services/$host\"/></anchor><br/>\n";
+ print POSIX::strftime($DATETIMEFMT,localtime()),"<br/><br/></p>\n";
+ print "<p align=\"center\">\n";
+ print "<b> $host </b><br/>\n";
+ print &query( $SPONGSERVER, "service", $host, "wml", $view, $service );
+ print "</p>\n";
+ &footer();
+}
+
+sub histservice {
+ my ($host, $service, $time ) = @_;
+ my $view = $main::view || "full";
+
+ &header( 0 );
+ print &query( $SPONGSERVER, "histservice", $host, "html", $view, $service,
+ $time );
+ &footer();
+}
+
+sub grp_summary {
+ my( $other ) = @_;
+ my $view = $main::view || 'standard';
+
+ &header(1);
+
+ print "<p align=\"center\">\n";
+ print "<anchor title=\"GrpSum\">Grp Summary";
+ print "<go href=\"$main::WAPSPONG/\"/></anchor><br/>\n";
+ print POSIX::strftime($DATETIMEFMT,localtime()),"</p>\n";
+ print "<p align=\"center\" mode=\"nowrap\"><br/>\n";
+ print &query( $SPONGSERVER, "grpsummary", '', "wml", $view, $other);
+ print "</p>\n";
+
+
+ &footer();
+
+}
+
+sub grp_problems {
+ my( $other ) = @_;
+ my $view = $main::view || 'full';
+
+ &header(0);
+ print &query( $SPONGSERVER, "grpproblems", $other, "html", $view );
+ &footer();
+}
+
+# Just print a little message to stdout showing what valid options are to
+# the command line interface to spong, and then exit the program.
+
+sub help {
+ print <<'_EOF_';
+Usage: wwwspong [options]
+
+Where "options" are one of the arguments listed below. If no arguments are
+supplied, then a table showing the status of all hosts is shown.
+
+ --summary [hostlist] Summarizes the status of services on the host(s)
+ --problems [hostlist] Shows a summary of problems on the host(s)
+ --history [hostlist] Show history information for the host(s)
+
+ --host host Shows all information available for the given host
+ --services host Shows detailed service info for the given host
+ --stats host Shows statistical information for the given host
+ --config host Shows configuration information for the given host
+ --info host Shows admin supplied text for the given host
+
+ --service host:service Shows detailed info for the given service/host
+
+ --brief Display output in a brief format
+ --standard Display output in standard format (the default)
+ --full Display more information then you probably want
+
+All host names used as options must be fully qualified domain names. For the
+options above that take an optional hostlist, the hosts listed should be
+either a group name, or a list of individual hosts seperated by commas. If
+the host list is omitted, then information about all hosts monitored by spong
+is returned.
+
+_EOF_
+ exit(0);
+}
+
+# ---------------------------------------------------------------------------
+# Private/Internal functions
+# ---------------------------------------------------------------------------
+
+# This function just loads in all the configuration information from the
+# spong.conf, spong.hosts, and spong.groups files.
+
+sub load_config_files {
+ my( $evalme, $inhosts, $ingroups );
+
+ require $conf_file || die "Can't load $conf_file: $!";
+ if( -f "$conf_file.$HOST" ) {
+ require "$conf_file.$HOST" || die "Can't load $conf_file.$HOST: $!";
+ } else {
+ my $tmp = (split( /\./, $HOST ))[0];
+ if( -f "$conf_file.$tmp" ) { # for lazy typist
+ require "$conf_file.$tmp" || die "Can't load $conf_file.$tmp: $!";
+ }
+ }
+
+ # Read in the spong.hosts file. We are a little nasty here in that we do
+ # some junk to scan through the file so that we can maintain the order of
+ # the hosts as they appear in the file.
+
+ open( HOSTS, $hosts_file ) || die "Can't load $hosts_file: $!";
+ while( <HOSTS> ) {
+ $evalme .= $_;
+ if( /^\s*%HOSTS\s*=\s*\(/ ) { $inhosts = 1; }
+ if( $inhosts && /^\s*[\'\"]?([^\s\'\"]+)[\'\"]?\s*\=\>\s*\{/ ) {
+ push( @HOSTS_LIST, $1 ); }
+ }
+ close( HOSTS );
+ eval $evalme || die "Invalid spong.hosts file: $@";
+
+ # Fallback, if we didn't read things correctly...
+
+ if( sort @HOSTS_LIST != sort keys %HOSTS ) {
+ @HOSTS_LIST = sort keys %HOSTS; }
+
+ # Do the same thing for the groups file.
+
+ $evalme = "";
+ open( GROUPS, $groups_file ) || die "Can't load $groups_file: $!";
+ while( <GROUPS> ) {
+ $evalme .= $_;
+ if( /^\s*%GROUPS\s*=\s*\(/ ) { $ingroups = 1; }
+ if( $ingroups && /^\s*[\'\"]?([^\s\'\"]+)[\'\"]?\s*\=\>\s*\{/ ) {
+ push( @GROUPS_LIST, $1 ); }
+ }
+ close( GROUPS );
+ eval $evalme || die "Invalid spong.groups file: $@";
+
+ if( sort @GROUPS_LIST != sort keys %GROUPS ) {
+ @GROUPS_LIST = sort keys %GROUPS; }
+}
+
+
+# ----------------------------------------------------------------------------
+# Display helper functions
+# ----------------------------------------------------------------------------
+
+# These allow users to easily customize some aspects of spong, by providing
+# their own header and footer information for each page.
+
+sub header {
+ my( $reload ) = shift;
+
+ if( $main::header_printed == 1 ) { return; }
+ $main::header_printed = 1;
+
+ my $datestr = POSIX::strftime($main::DATETIMEFMT,localtime());
+
+ print <<HEADER
+Content-type: text/vnd.wap.wml
+
+<?xml version="1.0"?>
+<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
+<wml>
+<head>
+<meta http-equiv="Cache-Control" content="max-age=0"/>
+</head>
+<card id="card1" title="Spong">
+HEADER
+;
+
+
+# &show( "header", 1 ) if -f "$main::WWWHTML/header.html";
+
+}
+
+sub footer {
+ if ($main::footer_printer == 1 ) { return; }
+ $main::footer_printer = 1;
+
+# &show( "footer", 1 ) if -f "$main::WWWHTML/footer.html";
+
+ print "</card></wml>\n";
+ }
+
+
+# This just takes a HTML template with a given name, and sends it to STDOUT.
+# This is used primarily for the help documentation.
+
+sub show {
+ my ($file, $hf) = @_;
+ my $show = $main::WWWSPONG . "/help";
+
+ if( -f "$main::WWWHTML/$file.html" ) {
+ &header( '', "Help", '', 0 ) unless $hf;
+ open( FILE, "$main::WWWHTML/$file.html" );
+ while( <FILE> ) { s/!!WWWSHOW!!/$show/g; print $_; }
+ close( FILE );
+ &footer() unless $hf;
+ } else {
+ &header( '', "Help", '', 0 ) unless $hf;
+ print "<h1>Help Not Available</h1>\n";
+ print "Sorry, but no help has been provided for that topic.\n";
+ &footer() unless $hf;
+ }
+}
+
+# This checks to see if the person connecting should be given back pages that
+# auto-matically reload (we don't want everyone to be banging against the
+# server).
+
+sub can_reload {
+ my $ok = 0;
+ my $regex;
+
+ foreach $regex ( @main::WWW_REFRESH_ALLOW ) {
+ if( $ENV{'REMOTE_ADDR'} =~ m/$regex/i ) { $ok = 1; }
+ if( $ENV{'REMOTE_HOST'} =~ m/$regex/i ) { $ok = 1; }
+ if( $ENV{'REMOTE_USER'} =~ m/$regex/i ) { $ok = 1; }
+ }
+
+ foreach $regex ( @main::WWW_REFRESH_DENY ) {
+ if( $ENV{'REMOTE_ADDR'} =~ m/$regex/i ) { $ok = 0; last; }
+ if( $ENV{'REMOTE_HOST'} =~ m/$regex/i ) { $ok = 0; last; }
+ if( $ENV{'REMOTE_USER'} =~ m/$regex/i ) { $ok = 0; last; }
+ }
+
+ return $ok;
+}
+
+# ----------------------------------------------------------------------------
+# Networking functions...
+# ----------------------------------------------------------------------------
+
+# This function sends a query to the spong server. It takes the results it
+# gets back based on the user's query and returns the string back to the
+# code that called this function.
+#
+# This query is a slightly different then the text client query function in
+# that it translates some template tags into directories on the www server, so
+# that links and gifs appear in the correct place.
+
+sub query {
+ my( $addr, $query, $hosts, $display, $view, $other ) = @_;
+ my( $iaddr, $paddr, $proto, $line, $ip, $ok, $msg );
+
+ if( $addr =~ /^\s*((\d+\.){3}\d+)\s*$/ ) {
+ $ip = $addr;
+ } else {
+ my( @addrs ) = (gethostbyname($addr))[4];
+ my( $a, $b, $c, $d ) = unpack( 'C4', $addrs[0] );
+ $ip = "$a.$b.$c.$d";
+ }
+
+ $iaddr = inet_aton( $ip ) || die "no host: $host\n";
+ $paddr = sockaddr_in( $SPONG_QUERY_PORT, $iaddr );
+ $proto = getprotobyname( 'tcp' );
+
+ # Set an alarm so that if we can't connect "immediately" it times out.
+
+ $SIG{'ALRM'} = sub { die };
+ alarm(30);
+
+ eval <<'_EOM_';
+ socket( SOCK, PF_INET, SOCK_STREAM, $proto ) || die "socket: $!";
+ connect( SOCK, $paddr ) || die "connect: $!";
+ select((select(SOCK), $| = 1)[0]);
+ print SOCK "$query [$hosts] $display $view $other\n";
+ while( <SOCK> ) {
+ s/!!WWWGIFS!!/$main::WWWGIFS/g; # Gif directory
+ s/!!WWWSPONG!!/$main::WWWSPONG/g; # Spong program
+ s/!!WAPSPONG!!/$main::WAPSPONG/g; # Spong program
+ s/!!WWWHTML!!/$main::WWWHTML/g; # Html help files
+ $msg .= $_;
+ }
+ close( SOCK ) || die "close: $!";
+ $ok = 1;
+_EOM_
+
+ alarm(0);
+
+ return $msg if $ok;
+ return "<font color=red><b>Can't connect to spong server!</b></font>";
+}
+