]> git.etc.gen.nz Git - spong.git/commitdiff
added program into CVS tree
authorStephen L Johnson <sjohnson@monsters.org>
Mon, 25 Sep 2000 20:53:33 +0000 (20:53 +0000)
committerStephen L Johnson <sjohnson@monsters.org>
Mon, 25 Sep 2000 20:53:33 +0000 (20:53 +0000)
src/wap-spong.pl [new file with mode: 0644]

diff --git a/src/wap-spong.pl b/src/wap-spong.pl
new file mode 100644 (file)
index 0000000..0efbf7f
--- /dev/null
@@ -0,0 +1,819 @@
+#@@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>";
+}
+