#!/usr/bin/perl
#^^^^^^^^^^^^^^^^^^^^ Update pathname appropriately to where you have Perl installed
# And update the path below of the configuration file as appropriate.

$lpinfo_ph = "/usr/local/lprng/info/lpinfo.ph";


#-------------- Should be fairly boilerplate from here on out --------------
# lpinfo - a Web/command line "printtool" for LPRng
# Copyright 1997, 1998, 1999, 2000  by Alek Komarnitsky, 
# Use and distribution of this software is covered by the GNU GPL license.  
# Please see the LICENSE file and http://www.gnu.org/
# Script to provide misc. info on LPRng from the Web and command line.
# Perhaps more bloated than we need ... 

$version="2.63";

$updatetime = 5 ; # Number of seconds between autoupdates
$testpageupdatetime = 3;   # Number of seconds betwen auto-update on printing test page
$timeout = 35;    # Number of seconds for lpq's and other system stuff to timeout
$| = 1;           # This seems to be needed so system calls don't write "too fast" to STDOUT

require 5.002;
use Socket;

# These are how I color code what is returned from the lpq status
# It is used in both the "middle" and "bottom" displays, so I put it here.
@orange = ("spooling disabled" , "who knows - NT Q" , "who knows - A-T Q" , "who knows - forward" , "appears busy" , "appears waiting" );
@red = ("WARNING" , "not in printcap","printing disabled","cannot open conn", "Connection refused" , "No Access" ,"unknown printer" , "paper jam" , "P-S does not know" , "No AppleTalk printer status", "queue not enabled" , "bad queue name" , "Stopped  - NT Q" , "queue is turned off" , "ink low" , "cannot chdir" , "remove media" , "lpq timed out" , "out of ink" , "(Paused)" ); 
@green = ("0 jobs", "no printable jobs" , "Ready" , "No Status" );
@blue = ("job" );

# Grab stuff from lpinfo.ph ...
if ( -r "$lpinfo_ph" ) { 
   require "$lpinfo_ph";
} else {
   print "could not open $lpinfo_ph - serious error ... \n";
   exit(2);
}

if ( ! ( ($lpq_all_dir) and ( -r "$lpq_all_dir/current" ) and ( ! -z "$lpq_all_dir/current") ) ) {
   $lpq_all_dir = 0 ;
}
   
# See if we are running in a command line or as a CGI
$html = 1 if (length($ENV{GATEWAY_INTERFACE}));
$lookup_info = 1  if ( -d $info_dir ); 
$locations_file = 0 if ( ! -r $locations_file ); 

# Here we determine if hacks are allowed ...   ;-)
if (( -r "/etc/resolv.conf" ) && (`cat /etc/resolv.conf` =~ "SITE.com" )) {
   $site_hacks = 1;
} 


if ( $html ) { 
   print "Content-type: text/html\n\n\n" ;
   print $meta_tags if (defined($meta_tags)); 
   &ReadParse;
   # Turn on admin mode as appropriate ...
   $adminmode = 1; 
   $_ = &get_env_variable("^SCRIPT_NAME");
   if ( $_ eq $thisURLadmin ) {
      $thisURL = $thisURLadmin;
      $_ = &get_env_variable("^REMOTE_USER");
      $adminmode = $_; 
      $adminmode = "nobody" if ($adminmode eq ""); 
   }
   $counter2 = &Increment_Accumulator($count_file2) if (($count_file2) && (-w $count_file2));
   $lpqlevel = -1; 
   $lpqlevel = $in{'lpqlevel'} if (defined($in{'lpqlevel'})); 

   # Generate some JavaScript to fire up new mode of operation ...
   if (( defined($in{'poweruseron'}) ) || ( defined($in{'normaluseron'})) || ( defined($in{'adminmodeon'})) ) {
      print "<script language=JavaScript>";
      if ( defined($in{'poweruseron'}) ) {
         print "windowclear=window.open('$thisURL?poweruser=true','main');";
      } elsif ( defined($in{'normaluseron'}) ) {
         print "windowclear=window.open('$thisURL?normaluseruser=true','main');";
      } elsif ( defined($in{'adminmodeon'}) ) {
         print "windowclear=window.open('$thisURLadmin?adminmode=true','main');";
      } else {
         print "OOOPS ... got into JavaScript power/normal/admin area, but nothing started up ...";
      }
      print "windowclear.close();"; 
      print "</script>";
      exit();
   }

   #  Show the middle frame at startup ...
   if ( defined($in{'show_middle_frame'}) ) {
      if ( $webservers_subnets_file) { 
         print "<a href=\"$thisURL?show_web_servers=true\" target=\"bottom\">Other Web Servers </a>";
###         print "<a href=\"$thisURL?show_web_servers=true&alek_special=true\" target=\"bottom\">debug</a>";
      }
      $counter0 = &Get_Accumulator($count_file0) if (($count_file0) && (-r $count_file0));
      $counter1 = &Increment_Accumulator($count_file1) if (($count_file1) && ( -w $count_file1));
      $tempvar = "$counter1-$counter2" if (($counter1) && ($counter2)); 
      $tempvar = "$counter0-$counter1-$counter2" if (( $counter0) && ($counter1) && ($counter2)); 
      $_ = `uname -n`;
      $tempvar = "($version: $tempvar - $_)";
      print "<p>Questions/suggestions on this web page can be directed to <a href=mailto:$email_address> $email_address</a> $tempvar";
      exit(); 
   }


   # show initial page
   if ( (!defined($in{'location'})) && ( !defined($in{'showqueue'})) && ( !defined($in{'printer'} )) && ( !defined($in{'auto'})) && ( !defined($in{'show_web_servers'})) &&  ( !defined($in{'getinfo'}))  ) {
      $counter0 = &Increment_Accumulator($count_file0) if (($count_file0) && (-w $count_file0) && ($adminmode));
      print "<form method=\"post\" action=\"$thisURL\" target=\"middle\">";
      print "&nbsp; &nbsp;";
      print "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;";
      print "<strong><input type=\"submit\" value=\"Show\"></strong>";
      print "&nbsp;";
      if ( $locations_file ) { 
         if ( -r $locations_subnets_file) { 
            $_ = &get_env_variable("^REMOTE_ADDR");
            if ( $_ ne "" ) { 
               @iplist = split(/\./,$_);
               $browser_subnet = "$iplist[0]\.$iplist[1]\.$iplist[2]";
               @_ = `cat $locations_subnets_file`;
               foreach $_ (@_) {
                  chomp();
                  next if ( /^#/ );
                  next if ( /^\s*$/ );
                  ($subnet,$bldg) = split();
                  $SUBNET_BLDG{$subnet} = $bldg;
               }
               $SUBNET_BLDG{$browser_subnet} = "NOT-FOUND" if ( ! defined ($SUBNET_BLDG{$browser_subnet}) );
            }
         }
         @_ = `cat $locations_file`;
         @locations = (); 
         foreach $_ (@_) {
            chomp();
            next if ( /^#/ );
            next if ( /^\s*$/ );
            ($location) = split();
            if ( $location eq $SUBNET_BLDG{$browser_subnet} ) {
               $browser_building = $SUBNET_BLDG{$browser_subnet};
            } else {
               push (@locations,$location);
            }
         }

         print "printers in ";
         print "<select name=\"location\">";
         print "<option>$browser_building" if ($browser_building);
         foreach $_ ( @locations ) { 
            print "<option>$_"; 
         }
         print "</select>";
         print " location";
         if (( $adminmode) || ( defined($in{'poweruser'}))) {
            print "&nbsp; &nbsp;";
            print "or enter optional override substring: <input type=\"input\" name=\"keyword\" size=\"9\" value=\"$in{'keyword'}\">";
         }
      } else {
         print "Enter optional string to reduce number of printers displayed: <input type=\"input\" size=\"9\" name=\"keyword\" value=\"$in{'keyword'}\">";
      }
      if ( ($adminmode) || (defined($in{'poweruser'}))) {
         print "<table cols=5 border=0 width=95%><tr>";     
         print "<td></td>";
         print "<td><input type=\"radio\" name=\"showqueue\" value=\"0\" checked> List only (fast!)</td>";
         print "<td><input type=\"radio\" name=\"showqueue\" value=\"1\"> queue status</td>";
         print "<td><input type=\"radio\" name=\"showqueue\" value=\"2\"> active/broke</td>";
         print "</tr></table>";
      }
      print "</form>";
      &clear_window("bottom");

   # Generate admin table of contents in middle frame
   } elsif ( defined($in{'adminsetup'})) {
      print "<frameset cols=\"30%,*\">";
      if ( $adminmode ) { 
         print "<frame src=\"$lpinfo_web_dir/admin/admintoc.html\" name=\"admintoc\">";
         print "<frame src=\"$lpinfo_web_dir/admin/middle.html\" name=\"adminout\">";
      } else {
         print "<frame src=\"$lpinfo_web_dir/admintoc.html\" name=\"admintoc\">";
         print "<frame src=\"$lpinfo_web_dir/middle.html\" name=\"adminout\">";
      }
      print "</frameset>";
      &clear_window("bottom");

   # Various lpc commands ...
   } elsif ( (defined($in{'lpc_restart'})) ||  (defined($in{'lpc_release'})) || (defined($in{'lpc_enable'})) ||  (defined($in{'lpc_disable'})) || (defined($in{'lpc_pause'})) || (defined($in{'lpc_resume'})) ) {
      if ($adminmode ) {
         $_ = &get_env_variable("^REMOTE_ADDR");
         if ( $_ ne "" ) { 
           @iplist = split(/\./,$_);
           $ip = pack('C4',@iplist);
           $browserhost = gethostbyaddr($ip,AF_INET);
         }
         $browserhost = &get_env_variable("^REMOTE_ADDR") if ( $browserhost eq "" ); 
         if (defined($in{'lpc_restart'})) {
            $lpc_options = "kill";
         } elsif (defined($in{'lpc_release'})) {
            $lpc_options = "release";
         } elsif (defined($in{'lpc_enable'})) {
            $lpc_options = "enable";
         } elsif (defined($in{'lpc_disable'})) {
            $lpc_options = "disable";
         } elsif (defined($in{'lpc_pause'})) {
            $lpc_options = "PA";
         } elsif (defined($in{'lpc_resume'})) {
            $lpc_options = "RE";
         } else {
            print "Could not figure out option to pass to lpc ...";
            exit(2);
         }
         $printserver = "unix";
         $queue_is_nt = &check_if_nt_queue($in{'printer'});
         if ( $queue_is_nt) {
            $printserver = &get_printserver($in{'printer'});
         }
         $_ = `$lpc_suid $adminmode $browserhost $in{'printer'} $printserver $lpc_options`;
         print "$_ ";
      } else {
         print "You have not enabled adminmode ...";
      }

   # Misc. Admin fucntions/documentation ...
   } elsif ( defined($in{'showactivebroke'})) {
      if ( $lpq_all_dir ) {
         $days = -M "$lpq_all_dir/current";
         $minutes = int (60 * 24 * $days); 
         print "<pre><b>";
         print "\"active/broke\" printers from an \"lpq-all\" run $minutes minutes ago <br>";
         print "Transient Network and/or Print Server outages may result in reds<br>";
         print "Queue Status          Printer Name        Description<br>";
         print "<hr></b>";
         open (LPQALL,"<$lpq_all_dir/current") || ( print "Can't open $lpq_all_dir/current: $!" || die() ) ; 
         while (<LPQALL>) {
            chomp ();
            ($color,$results,$printer) = split("  +");
            printf "%s%-22s%s%s%-24s" ,"<font color=$color>" , $results , "</font>" ,"<a href=\"$thisURL?printer=$printer\" target=\"bottom\">", "$printer</a>";
           if ( $lookup_info ) {
               $description = &get_shortinfo($printer);
            }
            print "<br>";
         }
         close (LPQALL);
      } else {
         print "<pre><b>Does not appear to be active/broke queue data available<br>";
      }

   # Show mis-configured queues ...
   } elsif ( defined($in{'misconfigured'})) {
      print "<pre><b><center>";
      print "List of queues that are mis-configured";
      print "</center><hr></b>";
      open (MISCONFIGURED,"<$misconfigured") || ( print "Can't open $misconfigured: $!" || die() ) ; 
      while (<MISCONFIGURED>) {
         print $_; 
      }
      close (MISCONFIGURED);

   # Check LPRng print servers
   } elsif ( defined($in{'checkprintservers'})) {
      print "<center><pre><b>Checking status of LPRng print servers</center><hr>"; 
      printf "Print Server    Status<br>";
      open (SERVERS,"<$lprng_print_servers") ||  print "Can't open $lprng_print_servers: $!" ;
      while (<SERVERS>) {
         chomp($printer = $_ );
         $results = `$lpc -Plp\@$printer lpd`; 
         chomp ($results); 
         if (( "$results" =~ "Server PID" ) || ( "$results" =~ "lpd server pid") ) { 
            printf "%s%-16s%s" ,"<font color=green>" , "$printer" , "OK - $results";
         } else {
            printf "%s%-16s%s" ,"<font color=red>" , "$printer", "$results";
         }
         print "<br>";
      }
      close (SERVERS);

   # Print a test page ...
   } elsif ( defined($in{'testpage'})) {
      print "Printing test page to $in{'printer'} <br>\n";
      $banner = "echo" if ( ! -x $banner );
      $testpage = "/tmp/lp-testpage-$$"; 
      open(TESTPAGE,">$testpage") || print "Can't open $testpage: $!" ;
      $_ = `$banner -w40 "lpinfo"`;
      print TESTPAGE "$_ \n\n";
      $_ = `$banner -w40"test\ page"`;
      print TESTPAGE "$_ \n\n\n\n\n";
      $_ = `date`;
      print TESTPAGE "printed to queue $in{'printer'} on $_ \n\n\014";
      close(TESTPAGE); 
      system ("$lpr -h -P$in{'printer'} $testpage");
      system ("rm $testpage");
      print "<meta http-equiv=\"Refresh\" content=\"0 ; URL=$thisURL?printer=$in{'printer'}&auto=$testpageupdatetime\"></html>";

   # Display help file
   } elsif ( defined($in{'show_help_'})) {
      open (HELP,"<$helpfile") ||  ( print "Can't open $helpfile: $!" || die() ); 
      while (<HELP>) {
         print $_;
      }
      close (HELP);
      &clear_window("bottom");

   # Update middle window (with or without (selective) queue status)
   } elsif ( (defined($in{'location'})) || (defined($in{'showqueue'}))) {
      @printers = &parse_printcap();
      if ( $#printers == -1 ) {
         print "ZERO printers returned ... something is amiss ... maybe 'cause @printers \n";
         exit(2);
      }
      if ( (! defined($in{'keyword'})) || (( $in{'keyword'} eq "" ))) { 
         if ( $in{'location'} eq "ALL" ) { 
            @print_printers = &grep_printers("");
            $num_printers = $#print_printers + 1;
            print "<center>ALL Printers ($num_printers total)</center>";
         } else {
            open(LOCATION,"<$locations_file") || die "Can't open $locations_file: $!";  
            while (<LOCATION>) {
               chomp();
               @locations = split(); 
               if ($in{'location'} eq $locations[0]) {
                  $keyword = "";
                  foreach $_ (@locations[1 .. $#locations]) { 
                     if ($keyword eq "" ) {
                        $keyword = "$_";
                     } else {
                        $keyword = "$keyword $_";
                     }
                  }
               }
            }
            close (LOCATION); 
            @print_printers = &grep_printers($keyword);
            $num_printers = $#print_printers + 1;
            print "<center>$num_printers printers located in \"$in{'location'}\"</center>";
         }
      } else {
         @print_printers = &grep_printers($in{'keyword'});
         $num_printers = $#print_printers + 1;
         print "<center>$num_printers printers have the string \"$in{'keyword'}\" in the printer name</center>";
      }
      &show_printers;
      &clear_window("bottom");

   # Display other web servers that are available in bottom window
   } elsif ( defined($in{'show_web_servers_'}) ) {
      if (( $webservers_subnets_file) && ( -r $webservers_subnets_file)) { 
         $_ = &get_env_variable("^REMOTE_ADDR");
         if ( $_ ne "" ) { 
            @iplist = split(/\./,$_);
            $browser_subnet = "$iplist[0]\.$iplist[1]\.$iplist[2]";
            open(SUBNETS,"<$webservers_subnets_file") || die "Can't open $webservers_subnets_file: $!";  
            while (<SUBNETS>) {
               chomp();
               @list = split();
               push (@web_servers,$list[0]);
               push (@web_server_locations,$list[1]);
               foreach $entry (@list[2 .. $#list]) {
                  if ( $entry eq $browser_subnet ) {
                     $web_server = $list[0];
                     $web_server_location = $list[1];
                     last;
                  }
               }
            }
            close (SUBNETS); 
         }
         chomp($_ = `uname -n`);
         print "You are browsing from $browser_subnet.$iplist[3] and connecting to the Web Server on $_<br><br>\n";
         if (( $web_server ) || ( defined($in{'alek_special'})))  { 
            print "<strong>The nearest Print Web Server to you appears to be <a href=\"http://$web_server\" target=_parent>$web_server_location (http://$web_server)</a></strong><br><br>\n";
         }
         if (defined($in{'alek_special'}))  { 
            print "<blink>WARNING:</blink> you are in some debug code here ...<br>";
         }
         print "Or you can click on one of the links below for other Print Web Servers:<br>\n";
         print "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;";
         print "<a href=\"$default_web_server\" target=_parent>$default_web_server_location ($default_web_server)</a> &nbsp; (DEFAULT)<br>\n";
         foreach $web_server (@web_servers) {
            $web_server_location = $web_server_locations[0];
            shift @web_server_locations;
            print "&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;";
            print "<a href=\"http://$web_server\" target=_parent>$web_server_location (http://$web_server)</a><br>\n";
         }
      } else {
         print "Could not find webservers_subnets_file at $webservers_subnets_file ... DOOPPP";
      }
   

   # show info (bottom window) of selected printer
   } elsif ( defined($in{'getinfo'}) ) {
      &get_longinfo($in{'getinfo'});

   # Show queue status in bottom window
   } else {
      if ( ( defined($in{'changelpqless'})) || ( defined ($in{'changelpqmore'}) ) ) {
            # Should be a more clever way to do this than this extra re-direct ...
            $lpqlevel = $in{'lpqlevel'} if ( defined($in{'lpqlevel'}));
            $lpqlevel--  if ( defined($in{'changelpqless'}));
            $lpqlevel++  if ( defined($in{'changelpqmore'}));
            $lpqlevel = -1 if ( $lpqlevel < -1 ) ; 
            print "<meta http-equiv=\"Refresh\" content=\"0 ; URL=$thisURL?printer=$in{'printer'}&auto=0&lpqlevel=$lpqlevel\"></html>";
            exit(); 
       }
      if ( ( !defined($in{'auto'})) || ($in{'auto'} eq 0)) {
         # Show long queue status (bottom window) of selected printer and setup for STOP/START
         $lpqlevel = $in{'lpqlevel'} if ( defined($in{'lpqlevel'}));
         print "<center><strong><b>$in{'printer'} Print Queue";

         # Allow direct access to printers with a web interface
         if (( $adminmode ) && ($printers_with_web) && ( -r $printers_with_web) ) { 
            open(WEB_PRINTERS,"<$printers_with_web") || die "Can't open $printers_with_web: $!";  
            while (<WEB_PRINTERS>) {
               chomp();
               if ( $in{'printer'} =~ /$_/ ) {
                  print " <a href=\"http://$in{'printer'}\" target=\"new\">(Direct Web Interface)</a>";
               }
            }
            close (WEB_PRINTERS); 
         }

         print "</center></strong></b>";
         print "<form method=\"post\" action=\"$thisURL?printer=$in{'printer'}&auto=$updatetime&lpqlevel=$lpqlevel\" target=bottom>";
         print "<input type=\"hidden\" name=\"printer\" value=\"$in{'printer'}\">";
         print "<input type=\"hidden\" name=\"auto\" value=\"$updatetime\">";
         print "<input type=\"hidden\" name = \"lpqlevel\" value = \"$lpqlevel\">";
         if ($no_over_ride_updatetime) { 
            print "<input type=\"submit\" value=\"Check Queue every $updatetime seconds\" name=\"autostop\">";
         } else { 
            print "<input type=\"submit\" value=\"Check Queue\" name=\"autostop\">every <input type=\"input\" name=\"changeupdatetime\" size=\"2\" value=\"$updatetime\"> seconds";
         }
         $queue_is_lprng = &check_if_lprng_queue($in{'printer'});
         if ( $queue_is_lprng ) { 
            print " &nbsp; &nbsp; &nbsp;";
            print "<input type=\"submit\" value=\"More\" name=\"changelpqmore\">";
            print "<input type=\"submit\" value=\"Less\" name=\"changelpqless\">" if ( $lpqlevel > -1 );
            print " Queue Info";
         }
         print " &nbsp; &nbsp; &nbsp;";
         print "<input type=\"submit\" name=\"testpage\" value=\"Print Test Page\">";
         if ( $adminmode ) { 
            print " &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ";
            if ( $queue_is_lprng ) { 
               print "<input type=\"submit\" name=\"lpc_restart\" value=\"RestartQ\">";
               print " &nbsp; &nbsp; &nbsp;";
               print "<input type=\"submit\" name=\"lpc_release\" value=\"ReleaseQ\">";
               print " &nbsp; &nbsp; &nbsp;";
               print "<input type=\"submit\" name=\"lpc_enable\" value=\"EnableQ\">";
               print " &nbsp; &nbsp; &nbsp;";
               print "<input type=\"submit\" name=\"lpc_disable\" value=\"DisableQ\">";
            } else {
               $queue_is_nt = &check_if_nt_queue($in{'printer'});
               if ( $queue_is_nt ) { 
                  print " &nbsp; &nbsp; &nbsp;";
                  print "<input type=\"submit\" name=\"lpc_pause\" value=\"PauseQ\">";
                  print " &nbsp; &nbsp; &nbsp;";
                  print "<input type=\"submit\" name=\"lpc_resume\" value=\"ResumeQ\">";
               } else {
                  print "Not a LPRng print queue - no admin commands available";
               }
            }
         }
         print "</form>";
      } else {
         if ( (defined($in{'changeupdatetime'})) && ( $in{'changeupdatetime'} >= 1 )) { 
            # Should be a more clever way to do this than this extra re-direct ...
            print "<meta http-equiv=\"Refresh\" content=\"0 ; URL=$thisURL?printer=$in{'printer'}&auto=$in{'changeupdatetime'}&lpqlevel=$in{'lpqlevel'}\"></html>";
            exit(); 
         } else { 
            print "<center><strong><b>$in{'printer'} Print Queue</center></strong></b>";
            print <<"EndofTEXT";
             <meta http-equiv="Refresh" content="$in{'auto'}">
             <form method="post" action="$thisURL?printer=$in{'printer'}&auto=0&$lpqlevel=$in{'lpqlevel'}" target=bottom>
             <input type="submit" value = "STOP" name="autostop"> Auto update of $in{'printer'} queue status every $in{'auto'} seconds
             <input type="hidden" name = "printer" value = "$in{'printer'}">
             <input type="hidden" name = "auto" value = "0">
             <input type="hidden" name = "lpqlevel" value = "$lpqlevel">
             </form>
EndofTEXT
         }
      }
      # Show queue status of selected printer
      &check_queue($in{'printer'});
   }
   print "</html>";
   exit();


#Command line output ... 
} else { 
   # Big hack to enable continued use of SunOS printtool at ...
   # You can ignore this ... since you are using lpinfo because you *are* using LPRng!  ;-)
   if ( $site_hacks ) { 
      if ( ! ( ( -e "/etc/init.d/lprng") or ( -e "/sbin/init.d/lprng" ) or ( -e "/etc/rc.lprng" ) ) ) {
         $_ = `uname`;
         if ( ( "$_" =~ "SunOS" ) and ( -x "/usr/local/share/bin/printtool.SunOS4.x" ) ){ 
            $SIG{'HUP'} = 'IGNORE';
            exec "/usr/local/share/bin/printtool.SunOS4.x &";
         } else {
            print "command line lpinfo not available here - use the Web interface at: \n";
            print "   $url_address \n";
         }
         exit(2);
      }
   }

   # How 'bout this for a nice little hack to get access to things via the command line!
   if ( $ARGV[0] eq "special" ) { 
      $special = $ARGV[1]; 
      $keyword = ".";
      if (defined($ARGV[2])) {
         shift @ARGV ; shift @ARGV; 
         $keyword = "@ARGV"; 
      }
      if (( $special eq 1 ) or ( $special eq 2 )) { 
         @printers = &parse_printcap();
         if ( $#printers == -1 ) {
            print "ZERO printers returned ... something is amiss ... maybe 'cause";
            print @printers;
            exit(2);
         }
         @print_printers = &grep_printers($keyword);
         &show_printers;
      } else {
         print "you passed in >>> @ARGV <<< and what was special about that ...\n";
      }
      exit();
   }

   print "Command line version $version of lpinfo\n";
   print "The Web version is at $url_address\n"; 
   print "Pls send comments/questions/suggestions/etc. to $email_address\n\n";
   TOP:
   print "\nPls select one of the following options\n";
   print "1   Show all printers\n";
   print "2   Search (by keyword) for particular printers\n";
   print "3   Check queue status of a particular printer\n";
   print "9   Exit\n";
   print "Enter choice ===> ";
   chomp($_ = <STDIN>);
   $selection = &sanitize($_);

   if ( $selection eq 1 ) {
      @printers = &parse_printcap();
      if ( $#printers == -1 ) {
         print "ZERO printers returned ... something is amiss ... maybe 'cause @printers \n";
         exit(2);
      }
      @print_printers = @printers;
      &show_printers;
   } elsif ( $selection eq 2 ) {
      print "Enter keyword to search for (multiple entries seperated by whitespace) ===> ";
      chomp($_ = <STDIN>);
      $keyword = &sanitize($_);
      @printers = &parse_printcap();
      if ( $#printers == -1 ) {
         print "ZERO printers returned ... something is amiss ... maybe 'cause @printers \n";
         exit(2);
      }
      @print_printers = &grep_printers($keyword);
      &show_printers;
   } elsif ( $selection eq 3 ) { 
      print "Enter name of queue to check status on ===> ";
      chomp($_ = <STDIN>);
      $queue = &sanitize($_);
      &check_queue($queue); 
   } elsif ( $selection eq 9 ) { 
      print "Exiting lpinfo\n";
      exit();
   } else {
      print "Got an illegal value of $_ ... pls pick one of the selections\n\n";
   } 
   goto TOP;
   print "Should never reach here ... \n";
}
exit();



# HTML parsing ...
sub ReadParse {
   if (@_) { local (*in) = @_; }
   local ($i, $loc, $key, $val);
   # Read in text
   if ($ENV{'REQUEST_METHOD'} eq "GET") {
      $in = $ENV{'QUERY_STRING'};
   } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
      for ($i = 0; $i < $ENV{'CONTENT_LENGTH'}; $i++) {
         $in .= getc;  }
   }
   @in = split(/&/,$in);
   foreach $i (0 .. $#in) {
      # Convert plus's to spaces
      $_ = $in[$i];
      $in[$i] = &sanitize($_);
      $in[$i] =~ s/\+/ /g;
      # Convert %XX from hex numbers to alphanumeric
      $in[$i] =~ s/%(..)/pack("c",hex($1))/ge;
      # Split into key and value.
      $loc = index($in[$i],"=");
      $key = substr($in[$i],0,$loc);
      $val = substr($in[$i],$loc+1);
      $in{$key} .= '\0' if (defined($in{$key})); # \0 is the multiple separator
      $in{$key} .= $val;
  }
}


# Grope through printcap file (or NIS) to generate list of printers
sub parse_printcap {
   @printers = ();
   if ( $printcap ne "NIS" ) {                                        
      if ( !open (PRINTCAP,"<$printcap" )) {                        
         $printers[1] = "could not open $printcap";
      } else {   
         while (<PRINTCAP>) {
            if  ( ! ( ( $_ =~ '^\s.*$' ) or ( $_ =~ '^#.*$' ) or ( $_ =~ '^$' )))  {
               s/\s*\:\\$//;
               chomp();                                                      
               push (@printers,$_);
            }
         }
         close PRINTCAP;
      }
   } else {
      # because the YP map may contain some identical entries for one
      # printer (each keyed by another name) we must check for duplicates.
      my(%printers, $printer);
      open (PRINTCAP,"ypcat printcap|");        # return code is meaningless
                                                # we check $? later
      while (<PRINTCAP>) {
         next unless /^[a-z]/i;                 # skip prototype entries
         next if /:ss=/;                        # skip queue servers
         s/:.*//;
         chomp();
         next if /all/;
         ($printer = $_) =~ s/\|.*//;
         next if $printers{$printer};
         $printers{$printer}++;
         push(@printers,$_);
      }
      close(PRINTCAP);
      $printers[1] = "could not open $printcap" if $?;
   }
   return (@printers);
}


# Show table of printers and possible associated queue status
sub show_printers{
   $num_printers = $#print_printers + 1;
   if ( $html ) { 
      if (defined($in{'showqueue'})) {
         $showqueue = $in{'showqueue'};
         $showbadones = 1 if ($showqueue eq 2 ) ;
      }
      print "<TABLE FRAME=\"border\" RULES=\"rows\" CELLPADDING=0 CELLSPACING=0 BORDER=0><TR>";
   }
   if ( $special ) {
      $showqueue = 1;
      $showbadones = 1 if ( $special eq 2 ) ;
   }
   if ( ! $special) { 
      if ( $showqueue ) {
         print "<TD><B>Queue Status &nbsp; &nbsp; &nbsp;</B>" if ( $html );
         print "Queue Status          " if ( ! $html) ; 
      }
      print "<td><b>Printer Name &nbsp; &nbsp; &nbsp;</b>" if ($html);
      print "Printer             " if ( ! $html);
      if ( $lookup_info ) {
         print "<TD><B>Description &nbsp; &nbsp; &nbsp;</B>" if ($html);
         print "Description                      " if ( ! $html ); 
      }
      print "<TD><B>Aliases &nbsp; &nbsp; &nbsp;</B>" if ($html); 
      print "Aliases       " if ( ! $html ) ; 
      print "\n";
      print "</TR>" if ( $html );
   }
   print "No printers matched\n" if ( $num_printers eq 0 ); 
   foreach $printer (@print_printers) {
      @printer_names = split(/\|/,$printer);
      if ( $html or $special) { 
         print "<TR>"                        if ( $html );
         if ( $showqueue ) { 
            ($color,$results)=&check_queue_short($printer_names[0]);
            if ( $results =~ "job" ) {
               $results =~ s/^.* (\d* jobs?).*$/$1/s;               
               $results =~ /^(.*)\s.*$/;
               $results = " $results" if ($1 < 10 ); 
            }
            if ((( $showbadones ) and ($color ne "green")) or ( ! $showbadones) ){
               if ( $special) {
                  $color = "purple" if ( "$color" =~ "purple" );
                  printf "%-9s%-22s%-24s" , "$color" , "$results" , "$printer_names[0]";
               } else {
                  print "<TD><font color=$color>$results</font></TD><TD><a href=\"$thisURL?printer=$printer_names[0]\" target=\"bottom\">$printer_names[0]</a> </TD>";
               }
            }
         } else { 
            print "<TD><a href=\"$thisURL?printer=$printer_names[0]\" target=\"bottom\">$printer_names[0]</a> </TD>";
         }
         if (( $showbadones ) and (($color ne "green" ) ) or ( ! $showbadones)){
            if ( $lookup_info ) {
               $description = &get_shortinfo($printer_names[0]);
            }
            if ( ! $special ) { 
               shift @printer_names; 
               print "<TD>" if ($html);
               foreach (@printer_names) {
                  print "$_";
                  print ", " if ( $_ ne $printer_names[$#printer_names] );
               }
               print "</TD>" if ($html);
            }
            print "ERROR CODE AMISS on $printer - TELL ALEK</blink>" if ( ($showqueue) && ("$color" =~ "purple"));
         }
         print "</TR>"                        if ( $html );
      } else {
         printf "%-20s" ,$printer_names[0];
         if ( $lookup_info ) {
            $description = &get_shortinfo($printer_names[0]);
         }
         shift @printer_names; 
         foreach (@printer_names) {
            print "$_   ";
         }
      }
      if ((( $showbadones ) and ($color ne "green")) or ( ! $showbadones) ){
         print "\n";
      } 
   } 
   print "</TABLE>" if ( $html ) ; 
}


# grep out this printers we are interested. 
# Note that multiple words and regular expressions are allowed.
sub grep_printers{ 
   my($keywords) = @_;
   @print_printers = ();
   if ($keywords eq "" ) { 
      @print_printers = @printers;
   } else { 
      foreach $printer_full (@printers) {
         NEXT_PRINTER: foreach $printer (split(/\|/,$printer_full)) {
            foreach $key (split(/\s+/,$keywords)) {
               if ( $printer =~ /$key/i ) { 
                  push(@print_printers,$printer_full);
                  last NEXT_PRINTER;
               }
            }
         }
      }
   }
   return(@print_printers);
}


# Show (optional) short information available from "info" database in middle window
sub get_shortinfo{
   if ( ! $special) { 
      if ( $lookup_info ) { 
         if ( -r "$info_dir/short/@_" ) {
            open (INFO,"<$info_dir/short/@_") || (  print "Can't open $info_dir/short/@_: $!" || die() ) ; 
            chomp($_ = <INFO>);
            close (INFO);
            if ( $html ) { 
               print "<TD><a href=\"$thisURL?getinfo=@_\" target=\"bottom\">$_</a> </TD>";
            } else {
               printf "%-30s   ", "$_";
            }
         } else {
            if ( $html ) { 
               print "<TD>No data available </TD>";
            } else {
               printf "%-30s   ", "No data available";
            }
         }
      } else {
         if ( $html ) { 
            printf "%-30s   ", "<TD>No printer info dir</TD>";
         } else {
            printf "%-30s   ", "No printer info dir";
         }
      }
   }
}


# Show extended info in bottom window
sub get_longinfo{
   if ( -r "$info_dir/long/@_" ) {
      print "<center><u>Information on printer @_ </center></u>";
      print "<pre>";
      open (INFO,"<$info_dir/long/@_") ||  ( print "Can't open $info_dir/long/@_: $!" || die() ) ; 
      while (<INFO>) {
         print $_;
      }
      close (INFO);
      print "</pre>";
   } else {
      print "No long information available for printer @_"; 
   }
}


# This is misc. counter stuff ... better ways to do this, but this is pretty portable ...
sub Increment_Accumulator {
   local ($Accumulator) =@_;local ($accum);
   open (LOG,$Accumulator) || return "-111";
   while (<LOG>) { chomp($accum=$_); ++$accum;}
   close LOG;
   # Reset the accumulator file
   open (LOG,">$Accumulator") || return "-222";
   print LOG "$accum\n";
   close LOG;
   $accum;
}


sub Get_Accumulator {
   local ($Accumulator) =@_;local ($accum);
   open (LOG,$Accumulator) || die " Problem opening the accumulator file $Accumulator\n";
   while (<LOG>) { $accum=$_; chomp($accum); }
   close LOG;
   $accum;
}


# Added per CERT advistory - send Alek EMail if you want changes here ...
sub sanitize {
   # This is opened up a bit 'cause we want to allow Perl regular expressions ...
   local ($OK_CHARS);
   $OK_CHARS='-a-zA-Z0-9_.@=/?+[]* \s';
   s/[^$OK_CHARS]/_/go;
   return $_;
}


sub clear_window {
      $frame = $_[0];
      print "<script language=JavaScript>";
      print "window.open('about:blank','$frame');";
      print "</script>";
}


# Returns long queue status for bottom window
sub check_queue{
   $printer = $_[0]; 
   $number_ls = ""; 
   for  ($i = 1; $i <= $lpqlevel ; $i++ ) { 
      $number_ls = "l$number_ls";
   } 
   $number_ls = "\-$number_ls" if ($number_ls ne "") ; 
   print "<pre>" if ( $html ) ; 
   if ( defined($in{'check_via_nt'})) { 
      $printserver = &get_printserver($printer);
      $command = "$lpq_nt $printer $printserver" ;
   } else {
      $command = "$lpq -P$printer $number_ls" ;
   }

   # Here's some mildly trick code to insure we never loose the lpq ... gives it $timeout seconds max
   $SIG{ALRM} = \&timed_out;
   eval {
      alarm ($timeout);
      @results = `$command` ;
      alarm(0);
   };
   if ($@ =~ /timed out/ ) { 
      @results = "lpq timed out";
   }
   if ( $html ) { 
      $_ = &get_env_variable("^REMOTE_ADDR");
      if (defined($in{'check_via_nt'})) {
         $browserhost = $_;
      } else { 
         if ( $_ ne "" ) { 
            @iplist = split(/\./,$_);
            $ip = pack('C4',@iplist);
            $browserhost = gethostbyaddr($ip,AF_INET);
         }
      }
      @results_mod = ();
      @results_status = ();
      $foundsomething = "no" ; 

      foreach $line (@results) { 
         next if ( $line =~ /^$/); 
         if (($foundrank ) || ( ( defined($in{'check_via_nt'})) && ($foundsomething eq "yes") )) { 
            ($rank,$owner,$class,$job,$misc) = split(/\s+/,$line);
            $_ = $owner;
            s/^.*@(.*)\+.*$/$1/s;
            tr/A-Z/a-z/;
            if (( "$rank" =~ /stalled\(/ ) || ( "$rank" =~ /error/) ) {
               $line = "<font color=red>$line</font>";
            }
            if (( $lprmURL ) && (("$class" eq "A" ) || ($queue_is_nt)) && (($_ eq $browserhost ) || ( $adminmode)) ){
               if (($queue_is_nt) && ( ! (defined($in{'check_via_nt'})))) {
                  $job = substr($line,42,6); $job =~ s/^\s+//; $job =~ s/(\S)\s+/$1_/g;
               }
               if (( $lprmURLadmin) && ($adminmode )) {
                  push (@results_mod,"<a href=\"$lprmURLadmin?printer=$printer&jobnumber=$job$queue_is_nt\" target=\"bottom\">REMOVE</a>  $line"); 
               } else {
                  push(@results_mod,"<a href=\"$lprmURL?printer=$printer&jobnumber=$job$queue_is_nt\" target=\"bottom\">REMOVE</a>  $line");
               }
            } else { 
               push(@results_mod,"        $line");
            } 
            $foundsomething = "yes";
         } else { 
            push (@results_mod,"        $line"); 
            foreach $_ (@red) { 
               if ( $line =~ $_ ) {
                  push(@results_status,"       <font color=\"red\">$line</font>"); 
                  $print_results = 1;
               }
            }
            foreach $_ (@orange) { 
               if ( $line =~ $_ ) {
                  push(@results_status,"       <font color=\"orange\">$line</font>"); 
                  $print_results = 1;
               }
            }
            if (( $line =~ "printable job") && ( ! ($line =~ "no printable job"))) { 
               push(@results_status,"       $line"); 
               $print_results = 1;
            }
         }
         if ( $line =~ "Rank   Owner/ID") { 
            $foundrank = 1; 
            @results_mod = ("        $line") if ($lpqlevel eq -1); 
         }
         if ( $line =~ "Windows NT LPD Server") { 
            if (! defined($in{'check_via_nt'})) { 
               $printserver = &get_printserver($printer);
            }
            $queue_is_nt = "&queue_is_nt=yes&printserver=$printserver";
         }
         if ( ($queue_is_nt) && ($foundsomething eq "hyphens")) { 
            $foundsomething = "yes"; 
         }
         if ( ($queue_is_nt) && ($line =~ "------------------")) { 
            $foundrank = 1; 
            $foundsomething = "hyphens"; 
         }
         if ( $line =~ "Queue: no printable jobs in queue") { 
            $foundsomething = "no" ; 
         }
      }
      if ( ( ($foundsomething eq "no")) && ( $lpqlevel eq -1) ) {
         @results_mod = ("        Queue is empty"); 
      }
      print @results_status if (( ($print_results) || ($foundrank)) && ($lpqlevel eq -1));
      print @results_mod;
      print "</pre>" if ( $html ) ; 
      if (($foundsomething eq "yes") && ( $lprmURLadmin) && ($adminmode ) && ($foundrank) && ( $html)) {
         print "<a href=\"$lprmURLadmin?printer=$printer&jobnumber=all$queue_is_nt\" target=\"bottom\">REMOVE 'em ALL!</a>";
      }
      if (( $lpq_nt ) && (! defined($in{'check_via_nt'})) && ( ! $adminmode ) && ($foundsomething eq "yes") && ($queue_is_nt) ) {
         print "This is an NT Print Server Queue: <a href=\"$thisURL?printer=$printer&check_via_nt=yes\">Click here to see which jobs you may delete</a> - takes a few seconds to determine";
      }
   } else {
      print "@results\n";
   } 
}


sub timed_out{
   die "timed out";
}


sub get_env_variable{
   $env_variable = $_[0]; 
   @env = `env`;
   @array=();
   push(@array,grep(/$env_variable/,@env));
   chomp($_ = $array[0]); 
   $_ = &sanitize($_);
   s/^.*=//s;
   return $_;
}


sub check_if_lprng_queue{
   $printer = $_[0];
   $printer = "zip-nada" if ($printer eq "");
   # Here's some mildly trick code to insure we never loose the lpq ... gives it $timeout seconds max
   $SIG{ALRM} = \&timed_out;
   eval {
      alarm ($timeout);
      chomp($_ = `$lpc -V -P$printer status`);
      alarm(0);
   };
   if (( /Status\/Debug/ ) && ( ! /not in printcap/ ) ) {
      return 1;
    } elsif (( /Status\/\(Debug/ ) && ( ! /not in printcap/ ) ) {
      return 1;
   } else {
      return 0;
   }
}


sub check_if_nt_queue{
   $printer = $_[0];
   $printer = "zip-nada" if ($printer eq "");
   # Here's some mildly trick code to insure we never loose the lpq ... gives it $timeout seconds max
   $SIG{ALRM} = \&timed_out;
   eval {
      alarm ($timeout);
      chomp($_ = `$lpq -P$printer`);
      alarm(0);
   };
   if (( /Windows NT LPD Server/ ) && ( ! /not in printcap/ ) ) {
      return 1;
   } else {
      return 0;
   }
}



sub get_printserver {
   $printer = $_[0];
   $printserver = "not_found";
   if ( $printcap ne "NIS" ) {                                        
      if ( !open (PRINTCAP,"<$printcap" )) {                        
         $printserver = "could_not_open_$printcap";
      } else {   
         while (<PRINTCAP>) {
            $found = 1 if (/^$printer/);
            if ($found) {
               if (/:lp=\S+@(\S+?):/) {
                  $printserver = $1;
                  last;
               }
            }
         }
      }
      close PRINTCAP;
   } else {
      # because the YP map may contain some identical entries for one
      # printer (each keyed by another name) we must check for duplicates.
      # We don't distribute via NIS, so this is not tested ...
      my(%printers, $printer);
      open (PRINTCAP,"ypcat printcap|");        # return code is meaningless
                                                # we check $? later
      while (<PRINTCAP>) {
         next unless /^[a-z]/i;                 # skip prototype entries
         next if /:ss=/;                        # skip queue servers
         s/:.*//;
         chomp();
         next if /all/;
         ($printerentry = $_) =~ s/\|.*//;
         $found = 1 if ($printerentry =~ /^$printer/);
         if ($found) {
            if (/:lp=\S+@(\S+?):/) {
               $printserver = $1;
               last;
            }
         }
      }
      close(PRINTCAP);
      $printserver= "could_not_open_$printcap" if $?;
   }
   return ("$printserver");
}



# Return short queue status for middle window (and color coding as appropriate)
sub check_queue_short{
   # Here's some mildly trick code to insure we never loose the lpq ... gives it $timeout seconds max
   $SIG{ALRM} = \&timed_out;
   eval {
      alarm ($timeout);
      chomp($_ = `$lpq -s -P@_`);
      alarm(0);
   };
   if ($@ =~ /timed out/ ) { 
      $_ = "bogus lpq timed out";
   }

   # Handle bounce queues
   if ( /bounce to/ ) { 
      @array = split();
      $jobs = 0 ;
      foreach $_ (@array) { 
         $jobs = $jobs + $job if ( /^job/ );
         $job = $_
      }
      $_ = "bogus $jobs jobs";
   }

   # Here come the hacks to deal with remove non-LPRng printers ...

   if ( /No entries/ ) { 
      $_ = "bugus 0 jobs";
   }
   if ( /no entries/ ) { 
      $_ = "bugus 0 jobs";
   }
   if ( /Rank   Owner/ ) { 
      $count = s/\n/\n/g; 
      $count = $count - 1;
      $_ = "bogus $count jobs";
   }
   if ( /No job currently printing/ )  {
      $_ = "bogus 0 jobs";
   }
   if ( /No such file or directory/ )  {
      $_ = "bogus cannot chdir";
   }
   if ( /unknown printer/ )  {
      $_ = "bogus unknown printer";
   }
   if ( /forwarding to/ )  {
      $_ = "bogus who knows - forward";
   }
   if  (/status: busy; source: LPR/ )  {
      $_ = "bogus appears busy";
   }
   if ( /status: waiting; source: LPR/ )  {
      $_ = "bogus appears waiting";
   }
   if  (/Active: .* printing via TCP\/IP/ )  {
      $_ = "bogus appears busy";
   }
   if ( /Couldn\'t get AppleTalk printer status/ )  {
      $_ = "No AppleTalk printer status";
   }
   if ( /Host name for your address.*unknown/ )  {
      $_ = "bogus P-S does not know";
   }
   if ( /status: busy; source: EtherTalk/ )  {
      $_ = "bogus who knows - A-T Q";
   }
   if ( /status: waiting; source: EtherTalk/ )  {
      $_ = "bogus who knows - A-T Q";
   }


   # For wierd stuff
   if ( /Ready$/ )  {
      $_ = "bogus Ready";
   }
   if ( /^$/ )  {
      $_ = "bogus No Status";
   }

   # Some misc. conditions we want to shorten
   if ( /Your host does not have line printer access/ ) {
      $_ = "bogus No Access";
   }

   # For NT Print Servers
   if ( /Server Queue .* is Processing/ )  {
      $_ = "bogus who knows - NT Q";
   }
   if ( /Server Queue .* is Stopped/ )  {
      $_ = "bogus Stopped - NT Q";
   }

   if (/Windows NT LPD Server/) {
      $jobcount = 0;
      @lpqout = split(/\n/,$_);
      foreach $line (@lpqout) {
         if ( ($line =~ /Windows NT LPD Server/) || ($line =~ /^Owner/) || ($line =~ /--------------------/) || ($line =~ /^\s*$/)) {
            next;
         } elsif ($line =~ /Printer $printer/) {
            $queuestatus = $line;
            $queuestatus =~ s/^\s*Printer $printer\s*(\S*)\s*/$1/;
         } else {
            $jobcount++;
         }
      }
      if ( $queuestatus =~ /^\s*$/ ) { 
         $_ = "bogus 0 jobs" if ($jobcount == 0);
         $_ = "bogus 1 job" if ($jobcount == 1);
         $_ = "bogus $jobcount jobs" if ($jobcount > 0);
      } else { 
         $_ = "bogus $queuestatus";
      }
   }


   ($printer,$results) = split(/\s/,$_,2);
   foreach $_ (@orange) { if ( $results =~ $_ ) { return("orange","$_")} };
   foreach $_ (@red) { if ( $results =~ $_ ) { return("red","$_")} };
   foreach $_ (@green) { if ( $results =~ $_ ) { return("green","$_")} };
   foreach $_ (@blue) { if ( $results =~ $_ ) { return("blue","$results")} };
   return("purple><blink","$results");
}
