--- /dev/null
+#!/usr/local/bin/perl
+#
+# This class encapsulates information about a Host that is monitored by spong.
+#
+# This class knows about the internals of how data is stored, because it needs
+# to do tricks in order to get at information in a fast way (like a list of
+# services running on a host, and the current state of a host).
+#
+# name - name of the group the HostList represents
+# services - a ServiceList object representing the services on the host
+# acks - a AckList object representing the Acks on the host
+# history - a HistoryList object representing events that have happen
+# info - a Info object that provides some documentation
+#
+# + new() - constructor (sets instance vars to arguments passed in)
+# + gets/sets() - magical set/get functions (autoloaded based on func name)
+# + display() - output format and view
+#
+# + display_problem() - displays info about specific problems on the host
+# + service() - returns a specific service object based on name
+# + service_objects() - returns a list of service objects
+# + service_names() - returns a list of service names
+# + color() - returns the LCD color of the host
+# + has_color() - returns if the host has a service of the given color
+# + has_problem() - returns true if the host has a problem
+# + problem() - need to clean this up...
+#
+# History:
+# (1) Cleaned up (Ed July 31, 1997);
+
+use Spong::AckList;
+use Spong::Ack;
+use Spong::ServiceList;
+use Spong::Service;
+use Spong::HistoryList;
+use Spong::History;
+use Spong::Info;
+use POSIX;
+
+package Spong::Host;
+
+# Constructor. This is a lazy constructor in that it doesn't get all it's
+# instance vars set at the time of creation. The only thing that is set at
+# construction is the name of the host and the ServiceList, the rest of the
+# host attributes are loaded as they are needed (performance reasons). This
+# returns undef if there is no host information associated with the FQDN given
+
+sub new {
+ my( $class, $host ) = @_;
+ my $self = {};
+ my( %servicehash );
+
+ return undef if ! -d "$main::SPONGDB/$host";
+
+ # We only load the data that is needed almost everytime this object is
+ # used. The rest of the data gets loaded on demand, as it is needed.
+
+ $self->{'name'} = $host;
+ $self->{'services'} = Spong::ServiceList->new( $host );
+ $self->{'acks'} = "";
+ $self->{'history'} = "";
+ $self->{'info'} = "";
+
+ bless $self;
+ return $self;
+}
+
+
+# Get/Set methods, nothing fancy here...
+
+sub name { my $var = 'name';
+ if( defined $_[1] ) { $_[0]->{$var} = $_[1]; } return $_[0]->{$var}; }
+sub services { my $var = 'services';
+ if( defined $_[1] ) { $_[0]->{$var} = $_[1]; } return $_[0]->{$var}; }
+
+
+# Some lazy loading functions, these go out and grab the data if we don't
+# already have it loaded.
+
+sub info {
+ my $self = $_[0];
+
+ if( defined( $_[1] ) ) {
+ $self->{'info'} = $_[1];
+ } else {
+ if( $self->{'info'} eq "" ) {
+ $self->{'info'} = Spong::Info->new( $self->name() ); }
+ }
+
+ return $self->{'info'};
+}
+
+sub acks {
+ my $self = $_[0];
+
+ if( defined( $_[1] ) ) {
+ $self->{'acks'} = $_[1];
+ } else {
+ if( $self->{'acks'} eq "" ) {
+ $self->{'acks'} = Spong::AckList->new( $self->name() ); }
+ }
+
+ return $self->{'acks'};
+}
+
+sub history {
+ my $self = $_[0];
+
+ if( defined( $_[1] ) ) {
+ $self->{'history'} = $_[1];
+ } else {
+ if( $self->{'history'} eq "" ) {
+ $self->{'history'} = Spong::HistoryList->new( $self->name() ); }
+ }
+
+ return $self->{'history'};
+}
+
+
+# These methods allow you to get at specific instance in a quicker way.
+
+sub service {
+ my( $self, $name ) = @_;
+ my $servicelist = $self->services();
+ return $servicelist->service( $name ) if $servicelist;
+}
+
+sub service_objects {
+ my( $self, $name ) = @_;
+ my $servicelist = $self->services();
+ return $servicelist->services() if $servicelist;
+}
+
+sub service_names {
+ my $self = shift;
+ my $servicelist = $self->services();
+ return $servicelist->names() if $servicelist;
+}
+
+sub color {
+ my $self = shift;
+ my $servicelist = $self->services();
+ return $servicelist->color() if $servicelist;
+}
+
+sub has_color {
+ my( $self, $color ) = @_;
+
+ foreach( $self->service_objects() ) {
+ if( $_->color() eq $color ) { return 1; } }
+
+ return 0;
+}
+
+sub has_problem {
+ my $self = shift;
+
+ return( $self->color() eq "red" );
+}
+
+sub problem {
+ my( $self ) = @_;
+ my $name = $self->name();
+ my $problem;
+
+ foreach( $self->servce_objects() ) {
+ if( $_ && ($_->color() eq "red") ) { $problem = "red"; }
+ if( $_ && ($_->color() eq "purple") ) {
+ $problem = "purple" unless $problem eq "red"; }
+ }
+
+ return $problem;
+}
+
+
+# Display summary. Does both text and html. This relies on pretty much every
+# other object to do the actual displaying of information
+#
+# brief: Just show the color of the host
+# standard: Shows a page with the standard views from the other objects
+# full: Shows a page with the full views from the other objects
+
+sub display {
+ my( $self, $type, $view ) = @_;
+
+ if( $type eq "text" ) { return $self->display_text( $view ); }
+ if( $type eq "html" ) { return $self->display_html( $view ); }
+}
+
+sub display_text {
+ my( $self, $format ) = @_;
+
+ if( $format eq "brief" ) {
+ print $self->color(), "\n";
+ } elsif( $format eq "standard" || $format eq "full" ) {
+
+ my $acklist = $self->acks();
+ if( $acklist ) {
+ print "Acknowledgments\n", "="x78, "\n";
+ $acklist->display( "text", $format ); }
+
+ my $servicelist = $self->services();
+ if( $servicelist ) {
+ print "\n\nServices\n", "="x78, "\n";
+ $servicelist->display( "text", $format ); }
+
+ my $info = Spong::Info->new( $self->name() );
+ if( $info ) {
+ print "\n\nInformation\n", "="x78, "\n";
+ $info->display( "text", $format ); }
+
+ my $historylist = $self->history();
+ if( $historylist ) {
+ print "\n\nHistory\n", "="x78, "\n";
+ $historylist->display( "text", $format ); }
+ }
+}
+
+sub display_html {
+ my( $self, $format ) = @_;
+ my $name = $self->name();
+
+ if( $format eq "brief" ) {
+ my $color = $self->color();
+
+ print "<a href=\"!!WWWSPONG!!/host/$name\">\n";
+
+ if( $main::WWW_USE_IMAGES == 1 ) {
+ print "<img src=\"!!WWWGIFS!!/$color.gif\" alt=$color border=0>";
+ } else {
+ print "<table border=0 cellspacing=0 cellpadding=0><tr>";
+ print "<td width=20 bgcolor=\"" . $main::WWW_COLOR{$color} ;
+ print "\"><font color=\"" . $main::WWW_COLOR{$color} . "\">";
+ print "___</font></td></tr></table>\n";
+ }
+ print "</a>";
+ } elsif( $format eq "standard" || $format eq "full" ) {
+ print "<font size=+2><b>$name</b></font>\n";
+
+ # This breaks the generic interactive vs non-interactive model
+ $self->add_action_bar();
+
+ my $color = $self->color();
+
+ print "<table width=100% cellspacing=0 cellpadding=0 border=0>";
+ print "<tr><td bgcolor=\"" . $main::WWW_COLOR{$color} . "\"> </td>";
+ print "</tr></table><p>";
+
+ my $acklist = $self->acks();
+ if( $acklist ) {
+ print "<font size=+1><b>Acknowledgments</b></font><br><hr>\n";
+ $acklist->display( "html", $format ); }
+
+ my $servicelist = $self->services();
+ if( $servicelist ) {
+ print "<p><font size=+1><b>Services</b></font><br><hr>\n";
+ $servicelist->display( "html", $format ); }
+
+ my $info = Spong::Info->new( $self->name() );
+ if( $info ) {
+ print "<p><font size=+1><b>Information</b></font><br><hr>\n";
+ $info->display( "html", $format ); }
+
+ my $historylist = $self->history();
+ if( $historylist ) {
+ print "<p><font size=+1><b>History</b></font><br><hr>\n";
+ $historylist->display( "html", $format ); }
+ }
+}
+
+
+# These functions display a textual record of any problems that the host is
+# currently having, this would include a summary of the problem services,
+# date/time the problem occurred, and contact information (as well as
+# acknowledgments if they are available).
+
+sub display_problem {
+ my( $self, $type ) = @_;
+
+ if( $type eq "text" ) { return $self->display_problem_text(); }
+ if( $type eq "html" ) { return $self->display_problem_html(); }
+}
+
+sub display_problem_text {
+ my $self = shift;
+ my $contact = $main::HOSTS{$self->name()}->{'contact'};
+ my $human = $main::HUMANS{$contact}->{'name'};
+ my $email = $main::HUMANS{$contact}->{'email'};
+ my( $prob, $summ, $time ) = $self->_problem_service();
+
+ print "(", $self->color(), ") ", $self->name(), "\n";
+ print "-"x(length($self->color()) + 3 + length($self->name())), "\n";
+ print " problem: $prob ";
+ if( $summ ) { print "($summ)\n"; } else { print "\n"; }
+ if( $time ) {
+ print " updated: ", POSIX::strftime( "%H:%M, %D", localtime($time) );
+ print "\n";
+ }
+ print " contact: $human ($email)\n";
+ print "\n";
+}
+
+sub display_problem_html {
+ my $self = shift;
+ my $contact = $main::HOSTS{$self->name()}->{'contact'};
+ my $human = $main::HUMANS{$contact}->{'name'};
+ my $email = $main::HUMANS{$contact}->{'email'};
+ my $color = $self->color();
+ my $name = $self->name();
+ my $message = &escape( "Host: $name, " . $self->_problem_message() );
+ my $spacer = "      ";
+ my( $prob, $summ, $time ) = $self->_problem_service();
+
+ if( $main::WWW_USE_IMAGES == 1 ) {
+ print "<img src=\"!!WWWGIFS!!/$color.gif\" alt=$color border=0>";
+ print "<b><a href=\"!!WWWSPONG!!/host/$name\">$name</a></b><br> ";
+ } else {
+ print "<table border=0 cellspacing=0 cellpadding=0><tr>";
+ print "<td width=20 bgcolor=\"" . $main::WWW_COLOR{$color} ;
+ print "\"> </td><td> ";
+ print "<b><a href=\"!!WWWSPONG!!/host/$name\">$name</a></b>";
+ print "</td></tr></table>\n";
+ }
+
+ if( $prob eq "multiple problems" ) {
+ print "$spacer problem: $prob<br>\n";
+ } else {
+ print "$spacer problem: <a href=\"!!WWWSPONG!!/service/$name/";
+ print "$prob\">$prob</a><br>";
+ }
+
+ # if( $summ ) { print "$spacer summary: $summ<br>\n"; }
+ if( $time ) {
+ print "$spacer updated: ";
+ print POSIX::strftime( "%H:%M, %D", localtime($time) ), "<br>\n";
+ }
+
+ print "$spacer contact: ";
+ print "<a href=\"$main::WWWCONTACT?host=$name&message=$message\">";
+ print "$human</a><p>\n";
+}
+
+
+
+# Returns the name (or a string indicating there are multiple problems), the
+# summary information about the service (if only one service is having
+# problems) and the time of the service having a problem on this host.
+
+sub _problem_service {
+ my $self = shift;
+ my( $services, @problist, $probtime, $summary );
+
+ foreach $service ( $self->service_objects() ) {
+ if( $service->has_problem() ) {
+ push( @problist, $service->name() );
+ $summary = $service->summary();
+ if( $probtime == 0 || ($service->rtime() < $probtime) ) {
+ $probtime = $service->rtime();
+ }
+ }
+ }
+
+ if( $#problist == -1 ) {
+ return();
+ } elsif( $#problist == 0 ) {
+ return( $problist[0], $summary, $probtime );
+ } else {
+ return( "multiple problems", "", $probtime );
+ }
+}
+
+# Returns a message that can be sent to the person who is on call for this
+# machine which indicates the problem with this machine.
+
+sub _problem_message {
+ my $self = shift;
+ my( $services, @problist, $probtime, $summary );
+
+ foreach $service ( $self->service_objects() ) {
+ if( $service->has_problem() ) {
+ push( @problist, $service->name() );
+ $summary = $service->summary();
+ if( $probtime == 0 || ($service->rtime() < $probtime) ) {
+ $probtime = $service->rtime();
+ }
+ }
+ }
+
+ if( $#problist == -1 ) {
+ return "No Problem";
+ } elsif( $#problist == 0 ) {
+ return "Problem: " . $problist[0] . ", $summary";
+ } else {
+ my $str = "Multiple Problems: ";
+
+ foreach( @problist ) { $str .= "$_, "; }
+
+ chop( $str ); chop( $str );
+ return $str;
+ }
+}
+
+sub add_action_bar {
+ my( $self ) = shift;
+ my $name = $self->name();
+ my $message = &escape( "Host: $name, " . $self->_problem_message() );
+
+ print "<hr>";
+ print "<a href=\"telnet://$name\">Connect</a> || ";
+ print "<a href=\"$main::WWWACK/$name\">Acknowledge Problem</a> ";
+
+ if( $main::WWWCONTACT ) {
+ print "|| <a href=\"$main::WWWCONTACT?host=$name&message=$message\">";
+ print "Contact Help</a>";
+ }
+
+ if ($main::WWW_ACTIONBAR_CUSTOM) {
+ my($text) = eval '"' . $main::WWW_ACTIONBAR_CUSTOM . '"';
+ print " || " . $text;
+ }
+
+ print "<hr>\n";
+}
+
+sub escape {
+ my($toencode) = @_;
+ $toencode=~s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
+ return $toencode;
+}
+
+1;
+