#!/usr/bin/perl
#######################################################################
#
#  UptimeNotifier Perl Client
#  --------------------------
#
#  A client for UptimeNotifier.
#
#  02-15-2001
#
#   Copyright (C) 2001  uptimenotifier
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the
#          Free Software Foundation, Inc.,
#          59 Temple Place,
#          Suite 330,
#          Boston, MA  02111-1307  USA
#
# 
#  Before running this script you may have to install the LWP package
#  available via CPAN as follows (might not be necessary with a Windows
#  version of Perl  http://www.activestate.com):
#
#  perl -MCPAN -e shell;
#      then, after you've configured it, you'll need to
#  cpan>install LWP
#      you also might want to do this:
#  cpan>install Bundle::libnet 
#
########################################################################

use Getopt::Std;
use LWP::UserAgent;
use HTTP::Request::Common qw(POST);

########################################################################
#
#  Script variables
#
########################################################################

my %properties;				
my $configfile = "notifier.properties";
my $AGENTNAME = "NotifierClient/1.5";
my $VERBOSE = "N";

$progname = $0;
$progname =~ s,.*/,,;  # use basename only
$progname =~ s/\.\w*$//; # strip extension, if any 

########################################################################
#
#  Get each parameter, exit if request type is invalid.
#  requestType, accountID, and password are always present.  eventID,
#  userID, referenceID, recipientID, serviceID,
#  and message are present depending on requestType.
#
########################################################################

#getopts('hf:e:a:u:r:m:p:s:n:t:A:T:U:P:X:z:D:S:v');
getopts('hf:a:u:r:m:p:t:A:T:U:P:X:z:D:S:v');

&printUsage if $opt_h;

$VERBOSE = "Y" if $opt_v;

$configfile = qq($opt_f) if ($opt_f);
$properties{"useProxy"} = "N";

########################################################################
#
#  Process the configuration file first, then apply command-line
#     arguments
#
########################################################################

if (open( PROPERTIES, $configfile)) {
  while ( <PROPERTIES>) {
    chomp;
    if ( ! /^\#/ && ! /^ *$/) {
      my ( $key, $value) = split /=/;
      $properties{$key} = $value;
    }
  }
  close PROPERTIES or warn "Error closing $configfile - $!"; 
#  warn "\nUnable to open properties file $configfile - $!\n\n";
}

# Set up the common arguments
$properties{"request"}              = qq{$opt_r} if ($opt_r);
$properties{"accountID"}            = qq{$opt_a} if ($opt_a);
$properties{"password"}             = qq{$opt_p} if ($opt_p);
$properties{"eventID"}              = qq{$opt_t} if ($opt_t);
$properties{"userID"}               = qq{$opt_u} if ($opt_u);
$properties{"message"}              = qq{$opt_m} if ($opt_m);
#$properties{"recipientID"}          = qq{$opt_e} if ($opt_e);
#$properties{"serviceID"}            = qq{$opt_s} if ($opt_s);
#$properties{"referenceID"}          = qq{$opt_n} if ($opt_n);
$properties{"proxyAddress"}         = qq{$opt_A} if ($opt_A);
$properties{"proxyPort"}            = qq{$opt_T} if ($opt_T);
$properties{"proxyUserID"}          = qq{$opt_U} if ($opt_U);
$properties{"proxyPassword"}        = qq{$opt_P} if ($opt_P);
$properties{"useProxy"}             = qq{$opt_X} if ($opt_X);
$properties{"useProxyAuth"}         = qq{$opt_z} if ($opt_z);
$properties{"directoryAddress"}     = qq{$opt_D} if ($opt_D);
$properties{"defaultServerAddress"} = qq{$opt_S} if ($opt_S);

if ( $VERBOSE eq "Y") {
  while ( ($key, $value) = each %properties) {
       printf "%-20s: %s\n",$key, $value;
  }
}


########################################################################
#
#   Create a UserAgent object for our directory GET and name it
#
########################################################################

$ua = new LWP::UserAgent;
$ua->agent( $AGENTNAME . $ua->agent);


########################################################################
#
#    Assign the proxy server URL by concatenating (address:port)
#    if requested in properties file.  We are only proxying http.
#
########################################################################

if ( $properties{"useProxy"} eq "Y" ) {
  $proxyServer = $properties{"proxyAddress"}. "\:". $properties{"proxyPort"};
  $ua->proxy( 'http', $proxyServer);
}


if ( ( exists($properties{"directoryAddress"}) && 
       length($properties{"directoryAddress"}) != 0)){

  ########################################################################
  #
  #    Create a request object to perform HTTP GET to retrieve
  #    Notification Server addresses from the directory server.
  #    If using a proxy, set the proxyUserID and proxyPassword.
  #    It then sets the content type and performs the HTTP GET.
  #
  ########################################################################

  my $req = new HTTP::Request GET => $properties{"directoryAddress"};
  if ( $properties{"useProxy"} eq "Y" &&
       $properties{"useProxyAuth"} eq "Y") {

    $req->proxy_authorization_basic( $properties{"proxyUserID"},
                                     $properties{"proxyPassword"});
  }
  my $res = $ua->simple_request( $req);

  ########################################################################
  #
  #   Check the result of the HTTP GET.
  #
  #   If it was successful, store the Notification Server URIs in
  #   @ServerURI.  It then tries each URI in sequence.  Stop at the first
  #   success.  Or continue as long as we fail or run out of URIs.
  #
  #   If the directory server HTTP GET fails, report the failure and
  #   perform a HTTP POST of the default Notification Server. 
  #
  ########################################################################

  if ( $res->is_success) {
    use Text::ParseWords;
    @ServerURI = quotewords( "\n", 0, $res->content);

    # Attempt a post to each server returned.  Stop on first success.
    foreach $item  ( @ServerURI) {
      printf "Trying: %s\n", $item;
      my $ret = doPost( $item);
      exit 0 if ( $ret eq 0 )
    }
  }
  else {
    printf "\n==>  Unable to reach Servers Directory: \n",
           $properties{"directoryAddress"} if ( $VERBOSE eq "Y");
  }
}
else {

  printf "Trying: %s\n",
         $properties{"defaultServerAddress"} if ( $VERBOSE eq "Y");
  $return = doPost($properties{"defaultServerAddress"});
  exit 0 if ( $return eq 0)
}

########################################################################
#
#    Function printUsage()
#
#    Displays proper parameter syntax for the client.
#
########################################################################

sub printUsage() {
    warn "@_\n" if @_;
    die <<"ENDUSG";
$progname - sends UptimeNotifier notifications, $AGENTNAME

  usage: $PN  <-r -a -p> [options]

  -r:  the UptimeNotifier request type
  -a:  the UptimeNotifier accountID
  -p:  the account password
       
  where options are:

  -f <properties file>:  location of properties file
  -u <user ID>        :  the UptimeNotifier userID
  -t <event ID>       :  the UptimeNotifier event id
  -m <message>        :  a notification message, e.g., \" Notify"
  -v                  :  display more verbose output

  -X <useProxy>       :  tells the client to use a proxy server
  -z <useProxyAuth>   :  tells the client to send proxy id/password
  -A <proxyAddress>   :  the URI of the proxy server
  -T <proxyPort>      :  the proxy port to use
  -U <proxy user id>  :  the id to negotiate the proxy
  -P <proxy password> :  the password for the proxy user
  -D <directory>      :  the URI of the server directory
  -S <server>         :  the URI of the server to use

ENDUSG
}


##########################################################################
#
#  function doPost()
#
#  Does the work of POSTing messages to a Notification server.
#  Constructs a LWP::UserAgent object, sets up to use a proxy
#  server if required, and POSTs all names available.  The
#  Notification server will disregard names that do not match
#  with the request type.  The response from the Notification
#  server is checked for 200 or 201.  Either response will
#  signal success and the send process will stop.
#
##########################################################################

sub doPost {

  # Initialize the UserAgent
  my $postua = LWP::UserAgent->new();
  $postua->agent( $AGENTNAME . $postua->agent);

  # Set up to use the proxy server if required
  $postua->proxy('http' => $proxyServer) 
                        if ( $properties{"useProxy"} eq "Y" );
 
  # Format all name/value pairs.  The server will sort things out. 
  # Some of these values will be empty.
  my $postreq = POST $_[0],
        [ request     => $properties{"request"},
          accountID   => $properties{"accountID"},
          password    => $properties{"password"},
          eventID     => $properties{"eventID"},
          userID      => $properties{"userID"},
#          recipientID => $properties{"recipientID"},
#          serviceID   => $properties{"serviceID"},
#          referenceID => $properties{"referenceID"},
          message     => $properties{"message"}
        ];
  $postreq->content_type('application/x-www-form-urlencoded');

  # Prime the proxy server with our 'id:password'
  if ( $properties{"useProxy"} eq "Y" &&
       $properties{"useProxyAuth"} eq "Y") { 
    $postreq->proxy_authorization_basic( $properties{"proxyUserID"},
                                         $properties{"proxyPassword"});
  }

  # POST the message
  my $postresponse = $postua->request( $postreq);

  # Check the response and react accordingly
  if ($postresponse->is_error()) {
    warn " $postresponse->status_line, $_[0]"; # if ( $VERBOSE eq "Y");
    return 13;
  }
  else {
    my $content = $postresponse->content();
    printf "%s", $content;
    # Look for a 2xx code returned from Notification server.
    if ( $content =~ /^[24]0/) {
      return 0;
    }
    else {
      print "No reasonable status code returned.\n";
      return 15;
    }
  }
}
