#! /s/std/bin/perl
#
# usage: 
#    check_printer_status [-v] -m <model> -d <device>
#
#
# Do SNMP query of printer; return PJL-style information for ifhp 
# (must have ifhp-3.5.8a3 or newer)
#
# Originally written to deal with Xerox appsocket printers, but could 
# easily work with other printers, too.
#
# Symlink this printer as 3 separate names.  I've used the following:
#    check_printer_status      (status check)
#    check_printer_waitend     (EOJ check--will spin until EOJ comes back)
#    check_printer_pagecount   (pagecount query)
#


#BEGIN {
#	if ($0 =~ m/^(.*?)[\/\\]([^\/\\]+)$/) {
#		$runtimedir = $1;
#		$PROGNAME = $2;
#	}
#}

use strict;
use Getopt::Std;
use Net::SNMP;
use XML::Simple;
use Data::Dumper;

# XML config file containing printer-specific information
my $xml_config="/s/lprng-3.8/common/sbin/check_printer_status.xml";

# other variables
my $printcap;
my $host;
my $model;
my $ifhp;
my $error;
my $response;
my $status;
my $pagecount;
my $complete=0;
my $verbose=0;
my $pjl_status_code;
my $display;
my %opts;

# parse any args
getopts('vm:d:', \%opts);
if ($opts{v} eq 1 ) {
  $verbose = 1;
}
$host = $opts{d};
$host =~ s/\%\S*\s*//;
$model = $opts{m};

if ((length($host) == 0 ) || length($model) == 0) {
  print "No host or model defined...pulling from \$PRINTCAP_ENTRY\n" if $verbose;
  if (!($ENV{PRINTCAP_ENTRY})) {
    die "Missing host or model info\n";
  }
  $printcap = $ENV{PRINTCAP_ENTRY};
  foreach (split (/:/, $printcap)) {
    if (/^lp=/ && length($host) == 0) { 
      $host = $_;
      $host =~ s/lp=//;
      $host =~ s/\%\S*\s*//;
    }
    if (/^ifhp=/) { 
      $ifhp = $_;
      $ifhp =~ s/ifhp=//;
      foreach (split(/,/, $ifhp)) {
        if (/dev=/ && length($host) == 0) {
          $host = $_;
          $host =~ s/dev=//;
          $host =~ s/\%\S*\s*//;
        }
        if (/model=/ && length($model) == 0) {
          $model = $_;
          $model =~ s/model=//;
          $model =~ s/\s*//g;
        }
      }
    }
  }

}

$error = 0;
if (length($host) eq 0) {
  $error = 1;
  print "No host specified!\n";
}
if (length($model) eq 0) {
  $error = 1;
  print "No model specified!\n";
}
if ($error eq 1) {
  die;
}

print "Host: $host\tModel: $model\n" if $verbose;

# parse XML config file
# slurp in all printer-specific OID info, 
my $ref = XMLin($xml_config, forcearray => 0);

# SNMP parameters
# Not sure why the following line doesn't work...I suspect something 
# strange in XML::Simple...Nate thinks it's in XML::Parser called from
# XML::Simple.
#my $community=$ref->{snmp_params}->{community};
my $community=substr($ref->{snmp_params}->{community}, 0);
my $timeout=$ref->{snmp_params}->{timeout};
my $retries=$ref->{snmp_params}->{retries};
my $session;

if ( $host eq "" ) {
    die "No printer name defined or \$PRINTER set\n";
}

#print "progname: $0\n";

print Dumper($ref) if $verbose;

print "SNMP params: host $host, community $community, timeout $timeout, retries $retries\n" if $verbose;
($session, $error) = Net::SNMP->session(-hostname => $host,
					-community => $community,
					-timeout => $timeout,
					-retries => $retries);

# check status
if ($0 =~ /waitend/) {
  if ($ref->{printerdata}->{$model}->{jobstatus_oid}) {
    my $jobstatus_oid=$ref->{printerdata}->{$model}->{jobstatus_oid};
	    my $status_ok=$ref->{printerdata}->{$model}->{status_ok};
	    my $status_cancelled=$ref->{printerdata}->{$model}->{status_cancelled};
	    do {
	      if ($response) {
		# be nice to the network
		sleep 3;
	      }
	      print "Running get_table ($jobstatus_oid)\n" if $verbose;
	      ($response) = $session->get_table(($jobstatus_oid));
	      print "jobstatus response: $response\n" if $verbose;
	      # if we get an answer back, assume the printer job is complete and change
	      # the flag if it is still printing; otherwise, assume the job is not done
	      my $error_message = $session->error;
	      if ($error_message =~ /Requested.table.is.empty.or.does.not.exist/) {
		# exit with JFAIL if printer was turned off and back on during the job
		exit 32;
	      }
	      if ($response) {
		$complete=1;
		foreach (sort keys (%$response)) {
		  print "response for $_: $response->{$_}\n" if $verbose;
		  # Get "ok" status from XML config file
		  if ($response->{$_} != $status_ok && $response->{$_} != $status_cancelled) {
		    $complete=0;
		  }
		}
	      } 
	    } until ($complete);
	      print "RESULT=OK\n";
	      print "waitend=1\n";
	  }
	} 

# check pagecount
if ($0 =~ /pagecount/) {
  print "Running pagecount\n" if $verbose;
  if ($ref->{printerdata}->{$model}->{pagecount_oid} &&
    $ref->{printerdata}->{$model}->{jobstatus_oid} ) {
  
  my $pagecount_oid=$ref->{printerdata}->{$model}->{pagecount_oid};
  print "Running get_request $pagecount_oid\n" if $verbose;
  ($response) = $session->get_request(($pagecount_oid));
  $pagecount = $response->{$pagecount_oid};
  print "pagecount response: $response\tpagecount: $pagecount\n" if $verbose;
  print "Error: $error\n" if $verbose;
  if ($pagecount) {
    print "PAGECOUNT=$pagecount\n";
  }
}
}

# check display status

if ($0 =~ /status/ && $ref->{printerdata}->{$model}->{display_oid}) {
  my $display_oid=$ref->{printerdata}->{$model}->{display_oid};
  print "Running get_table $display_oid\n" if $verbose;
  $display = $session->get_request($display_oid);
  print "Display status fetched: $display->{$display_oid}" if $verbose;

  my $status = $ref->{printerdata}->{$model}->{status};
  if ($status) {
    foreach (keys %$status) {
      print "Checking for $_\n" if $verbose;
      if ($display->{$display_oid} =~ /$_/) {
	$pjl_status_code = $status->{$_};
	print "CODE=$pjl_status_code\n";
	last;
      }
    }
    print "sync=1\n";
  } else {
    print "sync=0\n";
  }
}

# all done
  $session->close;


# exit with JSUCC
$status = 0;
print "Exit status: 0\n" if $verbose;
exit $status;


