#  PagerDaemon.pl
#  Example 8.9:
#  ----------------------------------------
#  From "Win32 Perl Scripting: Administrators Handbook" by Dave Roth
#  Published by New Riders Publishing.
#  ISBN # 1-57870-215-1
#
#  This script is a Win32 service that acts as a pager server.
#
print "From the book 'Win32 Perl Scripting: The Administrator's Handbook' by Dave Roth\n\n";


use Win32::Daemon;
use Win32::Console;
use Win32::Pipe;
use Win32::Perms;
use Net::Pager;

if( scalar @ARGV )
{
    if( $ARGV[0] =~ /install/i )
    {
        InstallService();
        exit();
    }
    elsif( $ARGV[0] =~ /remove/i)
    {
        RemoveService();
        exit();
    }
}

# How much time do we sleep between polling?
$SERVICE_SLEEP_TIME = 1;
$PIPE_NAME = "PagerService";

my ( $DB_FILE ) = ( Win32::GetFullPathName( $0 ) =~ /(.*?)\..*?$/ )[0] . ".log";
if( open( LOG, "> $DB_FILE" ) )
{
    my $Handle = select( LOG );
    $| = 1;
    select( $Handle );
    print LOG "Started: " . localtime() . "\n\n";
}

# Start the service...
if( ! Win32::Daemon::StartService() )
{
    exit();
}
# Register the service
Win32::Daemon::ShowService();

$Buffer = new Win32::Console();
$Buffer->Display();
$Buffer->Title( "Perl based Pager service" );
Write( "Service started\n" );

while( SERVICE_STOPPED != ( $State = Win32::Daemon::State() ) )
{
    if( SERVICE_START_PENDING == $State )
    {
        # Initialization code
        my $Perm;
        if( $Perm = new Win32::Perms() )
        {
            $Perm->Allow( "administrators", FULL );
        }
        
        # Now create the pipe and specify to use the permissions above
        if( $Pipe = new Win32::Pipe( $PIPE_NAME, 1000, PIPE_NOWAIT | PIPE_READMODE_BYTE, $Perm ) )
        {
            Win32::Daemon::State( SERVICE_RUNNING );
            Win32::Daemon::SetServiceBits( USER_SERVICE_BITS_1 );
            Write( "Service is running\n" );
        }
        else
        {
            Win32::Daemon::State( SERVICE_STOPPED );
            Write( "Service stopping\n" );
        }
    }
    elsif( SERVICE_PAUSE_PENDING == $State )
    {
        # "Pausing...";
        if( $Connected )
        {
            $Pipe->Disconnect();
            $Connected = 0;
        }
        Win32::Daemon::State( SERVICE_PAUSED );
        Write( "Paused\n" );
        next;
    }
    elsif( SERVICE_CONTINUE_PENDING == $State )
    {
        # "Resuming...";
        Win32::Daemon::State( SERVICE_RUNNING );
        Write( "Resumed\n" );
        next;
    }
    elsif( SERVICE_STOP_PENDING == $State )
    {
        # "Stopping...";
        if( $Connected )
        {
            $Pipe->Disconnect();
            $Connected = 0;
        }
        Win32::Daemon::State( SERVICE_STOPPED );
        Write( "Stopped\n" );
        next;
    }
    elsif( SERVICE_RUNNING == $State )
    {
        # The service is running as normal...
        if( ! $Connected )
        {
            $Connected = Connect( $Pipe );
        }
        if( $Connected )
        {
            if( $Pipe->Peek() )
            {
                my $Result = 0;
                my $Data = $Pipe->Read();
                if( my $Pager = new Net::Pager )
                {
                    my( $To, $Message ) = split( /\t/, $Data );
                    # AT&T PCS services has a service number of 7.
                    # Check with the Net::Pager documentation to 
                    # discover other paging service values.
                    # This script assumes everyone uses AT&T PCS 
                    # services.
                    my $SERVICE = 7;
                    my $FROM = "Perl Pager";
                    Write( "Sending page to $To...\n" );
                    if( $Pager->sendPage( $SERVICE, $To, $FROM, $Message, undef ) )
                    {
                        Write( "Page was sent\n" );
                    }
                    else
                    {
                        Write( "Page failed to send\n" );
                    }
                }
                else
                {
                    Write( "Unable create a pager object\n" );
                }
                $Pipe->Disconnect();
                Write( "Waiting for connection\n" );
                $Connected = 0;
            }
        }
    }
    else
    {
    # Got an unhandled control message
        Win32::Daemon::State( SERVICE_RUNNING );
    }
    sleep( $SERVICE_SLEEP_TIME );
}

sub Connect
{
    my( $Pipe ) = @_;
    my $Connected  = 0;
    if( $Pipe->Connect() )
    {
        $Connected = 1;
        Write( "Connected by " . ( $Pipe->GetInfo() )[2] . "\n" );
    }
    return( $Connected );
}

sub GetServiceConfig
{
    my $ScriptPath = join( "", Win32::GetFullPathName( $0 ) );
    my %Hash = (
        name    =>  'Pager',
        display =>  'Pager Service',
        path    =>      $^X,
        user    =>  '',
        pwd     =>  '',
        parameters =>  "$ScriptPath",
    );
    return( \%Hash );
}

sub InstallService
{
    my $ServiceConfig = GetServiceConfig();
    if( Win32::Daemon::CreateService( $ServiceConfig ) )
    {
        print "The $ServiceConfig->{display} was successfully installed.\n";
    }
    else
    {
        print "Failed to add the $ServiceConfig->{display} service.\nError: " . GetError() . "\n";
    }
}

sub RemoveService
{
    my $ServiceConfig = GetServiceConfig();
    if( Win32::Daemon::DeleteService( $ServiceConfig->{name} ) )
    {
        print "The $ServiceConfig->{display} was successfully removed.\n";
    }
    else
    {
        print "Failed to remove the $ServiceConfig->{display} service.\nError: " . GetError() . "\n";
    }
}

sub GetError
{
    return( Win32::FormatMessage( Win32::Daemon::GetLastError() ) );
}

sub Write
{
    my( $Message ) = @_;
    $Message = "[" . scalar( localtime() ) . "] $Message";
    if( defined $Buffer )
    {
        $Buffer->Write( $Message );
    }
    else
    {
        print $Message;
    }
    if( fileno( LOG ) )
    {
        print LOG $Message;
    }
}
