hello.

i have edited the accounting.pl file comes with LPRng. for the last few lines in the 
script, it
says 
# you should put your make update record stuff here. 

the parts i added does user quota check, error report etc. 


my question is - is it the right place to add it ? since i got mysterious errors by 
doing that.
different jobs from diff users overlap each other and in term cause the error of the 
update user
quota database.  

eventually i move the part i added to the end of the accounting script. it seems all 
okay now. 

but did i do it right ?

i have the sample portion listed below and also the accounting.pl attached. please 
take a look.

many thanks!


Qiang.


for( my $i = @stack -1; $i >= 0 ; --$i ){
    $_ = $stack[$i];
    print STDERR "stack [$i] '$_'\n" if $debug;
    if( /^[a-z]*end .*-p(\d+)/ ){
        $end_counter = $1;
    } elsif( /^[a-z]*start .*-p(\d+)/ ){
        $start_counter = $1;
    } elsif( /^START/ ){
        # we now update the accounting information
        ($start_time) = /D=(\d+)/;
        s/D=(\d+)/S=$1/;
        $count = $end_counter - $start_counter;
        $elapsed = $time - $start_time;

        # you should put your make update record stuff here
        s/^START/END 't=$elapsed' 'p=$count' 's=$start_counter' 'q=$end_counter' 
'D=$time'/;
        $out = $_ . "\n" . $out;
        $end_counter = $start_counter;
        $time = $start_time;

## everything else go here ??
## such as check user quota, report error base on the checking ??
    }
}

# update the file and the database at this point
print STDERR "APPEND $out" if $debug;
print $acct_h $out;


## now i have everything here - the end of the script.

______________________________________________________________________ 
Post your free ad now! http://personals.yahoo.ca
#!/usr/bin/perl -w

#@ new features added: quota control
#@      windows popup error message

#eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
#    if $running_under_some_shell;
            # this emulates #! processing on NIH machines.
            # (remove #! line above if indigestible)


# accounting.pl.in,v 5.5 2000/06/09 21:55:12 papowell Exp
# LPRng based accounting script.
#  Version Thu Apr 13 21:00:20 PDT 2000
# LPRng 3.6.14
#
# stdin = /dev/null
# stdout = accounting file
# stderr = log file
#  
#  command line format:
#   accounting [start|end] [-options] [accounting file]
#     -Tdebug will turn on debugging
#     start - at start of job; scan accounting file, fix up,
#         put in START entry
#     end  - at end of job; scan accounting file, fix up,
#         put in END entry
#
# Accounting File has format:
# start '-ppagecounter' '-Athis' -P'that'  <- startpage
# ...
# end   '-ppagecounter'                    <- lastpage
# END 't=$elapsed' 'p=$pages' 'q=$lastpage' 's=$startpage' 'A=$opt{A}' 'P=$opt{P}' 
'n=$opt{n}' 'H=$opt{H}' 'D=$time' 'S=$starttime'
#               --- end of a job
# START 'A=$opt{A}' 'P=$opt{P}' 'n=$opt{n}' 'H=$opt{H}' 'D=$time'
# start '-ppagecounter' '-Athis' -P'that'    <- startpage
# ...
# end   '-ppagecounter'                        <- lastpage
# END 't=$elapsed' 'p=$pages' 'q=$lastpage' 's=$startpage' 'A=$opt{A}' 'P=$opt{P}' 
'n=$opt{n}' 'H=$opt{H}' 'D=$time' 'S=$starttime'
#
# We implement a stack based FSM to do the following:
# Stack = NULL, state = FIND_START
#   
#  FIND_START - find the first START
#   START -> push START line
#         -> FIND_start
#
#  FIND_start - find the first 'start' entry with page
#   start -> push start
#         -> FIND_end
#
#  FIND_end   - find the first 'end' entry for this job
#   end   -> push end line
#         -> FOUND_end
#   START -> push START line
#         -> FIND_start
#
#  FOUND_end  - keep looking for 'end' entries
#   end   -> pop stack
#         -> push end line
#   START -> push START line
#         -> FIND_start
#
# All states:
#
#   END   -> clear stack
#         -> FIND_START
#   START -> push START line
#         -> FIND_start
#
#
#  At end, if you do not have state FOUND_end you do not have a
#  valid accounting file so you have to wait.
#  Stack will have contents:
#      ((START*  start )* end) *
#                ^ start page count
#                         ^ end page count
#   we start from the bottom of the stack;
#    - end entry sets end page count for job
#    - start entry sets start page count for job
#    - START assigns pagecount as difference between start and end
#            end page count = start page count
#
# seq   START START START start end
# pages   0     0      end - start       
#
# seq   START START start1         START START start2 end2
# pages   0     start2-start1       0      start2-end2
#

use strict;
use Getopt::Std;
use DBI;
use FileHandle;
use Socket;

my($JFAIL, $JABORT, $JREMOVE, $JHOLD) = ( 32, 33, 34, 37);
my(%opt, $action, $acct_h, $debug,$state,@stack);
my($FIND_START,$FIND_start,$FIND_end,$FOUND_end)=(0,1,2,3,4,5);

$debug = 0;

# print STDERR "$0: '" . join("' '",@ARGV) . "'\n" if $debug;
$action = "";
if( @ARGV ){
    if( $ARGV[0] !~ /^-/ ){
        $action = shift @ARGV;
    }
    print STDERR "action $action\n" if $debug;
}
if( $action ne "start" and $action ne "end" ){
    print STDERR "$0: invalid action '$action'\n";
    exit $JABORT;
}

# pull out the options

getopts( 'A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:T:S:U:V:W:X:Y:Z:'
. 'a:b:cd:e:f:g:h:i:j:k:l:m:n:o:p:q:r:t:s:u:v:w:x:y:z:', \%opt );

my($acct_file) = "";
if( @ARGV ){
    $acct_file = shift @ARGV;
} else {
    $acct_file = $opt{'a'};
}
if( exists( $opt{T} ) && $opt{T} =~ m/debug/ ){
    $debug = 1;
}
if( !$acct_file ){
    print STDERR "$0: no accounting file\n";
    exit( $JABORT );
}

my($time) = time;
print STDERR "$0: $action 'A=$opt{A}' 'P=$opt{P}' 'n=$opt{n}' 'H=$opt{H}' 'D=$time'\n" 
if $debug;

print STDERR "accounting file '$acct_file'\n" if $debug;

#################################@@
## define global variable
#################################@@

my ($dbh, $sth, $pages, $uname, $host, $space, $jobhistory, $max_h, $remote_ip 
,$remain, $rmssh);

$host=$opt{H};
$uname = $opt{n};
$jobhistory = "/usr/local/quotasrv/jobs.history"; # file to record print history.
$max_h = 20;  # max history to keep
# parse ip and convert it to real remote host name.
$host =  scalar gethostbyaddr(inet_aton($remote_ip),AF_INET)
        if (($remote_ip) = $opt{C}=~ /REMOTEIP=(.*)/);
$rmssh = "/usr/local/quotasrv/rmssh";
$space = '&nbsp;';

###################################

if( $action eq "start" ){

        ##@@ connect and check user paper count. 
        ##@@ abort if with insufficient paper
        connect_db();
        check_page_count();
        $dbh->disconnect() if $dbh; 
        ##@@ user quota check succeed at this point.

    $acct_h = new FileHandle ">>$acct_file" ;
    print $acct_h "START 'A=$opt{A}' 'P=$opt{P}' 'n=$opt{n}' 'H=$opt{H}' 'D=$time'\n";
    print STDERR "START 'A=$opt{A}' 'P=$opt{P}' 'n=$opt{n}' 'H=$opt{H}' 'D=$time'\n" 
if $debug;
    $acct_h->close();

    exit 0;
}

$acct_h = new FileHandle "+<$acct_file" ;
if( ! defined($acct_h) ){
    print STDERR "$0: cannot open $acct_file r/w - $!\n";
    exit( $JABORT );
}

# now we read the last line from the accounting file
my($size) = -s $acct_file;
my($max_seek) = 2048;
my($read_all) = 0;

if( $size > $max_seek  && not $acct_h->seek( -$max_seek, 2 )
){
    print STDERR "$0: lseek $acct_file failed - $!\n";
    exit( $JABORT );
}

again:

@stack = ();
$state = $FIND_START;


while( <$acct_h> ){
    chomp;
    print STDERR "STATE '$state' LINE '$_'\n" if $debug;
    print STDERR "STACK\n " . join("\n ",@stack) . "\n" if $debug;
    if( /^END / ){
        $state = $FIND_START;
        @stack = ();
        next;
    }
    if( /^START / ){
        push @stack, $_;
        $state = $FIND_start;
        next;
    }
    if( $state == $FIND_start ){
        if( /^(file)?start .*-p\d+/ ){
            push @stack, $_;
            $state = $FIND_end;
        }
    } elsif( $state == $FIND_end ){
        if( /^(file)?end .*-p\d+/ ){
            push @stack, $_;
            $state = $FOUND_end;
        }
    } elsif( $state == $FOUND_end ){
        if( /^(file)?end .*-p\d+/ ){
            pop @stack;
            push @stack, $_;
            $state = $FOUND_end;
        }
    }
}

if( $state != $FOUND_end ){
    if( $read_all ){
        print STDERR "$0: did not find end record in file";
        exit 0;
    }
    $acct_h->close();
    $acct_h = new FileHandle "+<$acct_file" ;
    if( ! defined($acct_h) ){
        print STDERR "$0: cannot open $acct_file r/w - $!\n";
        exit( $JABORT );
    }
    $read_all = 1;
}

print STDERR "FINAL STATE '$state'\n" if $debug;
print STDERR "FINAL STACK\n " . join("\n ",@stack) . "\n" if $debug;
my($end_counter,$start_counter,$start_time,$count,$out,$elapsed);

$end_counter = $start_counter = 0;
$out = "";

for( my $i = @stack -1; $i >= 0 ; --$i ){
    $_ = $stack[$i];
    print STDERR "stack [$i] '$_'\n" if $debug;
    if( /^[a-z]*end .*-p(\d+)/ ){
        $end_counter = $1;
    } elsif( /^[a-z]*start .*-p(\d+)/ ){
        $start_counter = $1;
    } elsif( /^START/ ){
        # we now update the accounting information
        ($start_time) = /D=(\d+)/;
        s/D=(\d+)/S=$1/;
        $count = $end_counter - $start_counter;
        $elapsed = $time - $start_time;
        # you should put your make update record stuff here
        s/^START/END 't=$elapsed' 'p=$count' 's=$start_counter' 'q=$end_counter' 
'D=$time'/;
        $out = $_ . "\n" . $out;
        $end_counter = $start_counter;
        $time = $start_time;
    }
}

# update the file and the database at this point
print STDERR "APPEND $out" if $debug;
print $acct_h $out;


print STDERR "$0: +++++++ $count pages printed ++++++\n";

#@@ count is negative. something fishy.
handle_error("Printing Halted.") if ($count=~/-/);

#######################@@
## update db
#######################@@
connect_db();
$pages = check_page_count();
$remain = $pages-$count;
update_db($remain);
## @@ write job history
write_history('');
$dbh->disconnect() if $dbh;


#------- the rest is the helper function -------#

#################################@@
# write job.history. err msg is passed as first argument
#################################@@
sub write_history {
        my $err = shift;

        # create history file if it doesn't exist.
        unless (-e $jobhistory) {
                open F,">$jobhistory";
                close F ;
        }

        # read job history
        open F,$jobhistory or warn "$?: read file error\n" and return;
        my @history = <F>;
        close F;

        $count = 0 if $count !~ /\d/;

        # set empty filed to html space for pretty printing ;)
        # append current job into history
        my $current = join '%', map {($_ eq "")?$space:$_}
                ($uname,$count,$remain,$host,scalar localtime($time),$err);
        push @history,$current."\n";

        # save history
        # keep limited history records.
        open F,">$jobhistory" or warn "$?:\n" and return;
        if ($#history > $max_h) { 
            print F splice(@history,$#history-$max_h,$max_h);
        } else {
            print F @history;
        }
        close F;
}

#################################@@
# connect db and keep a handle around
#################################@@

sub connect_db {

        # abort if user name not present.
        handle_error("what is your name?")
                unless( defined $uname );

        # Perform db connection. abort on connection fail.
        $dbh = DBI->connect( "dbi:mysql:dbname", "user", "password" , {
                  PrintError => 0,
              RaiseError => 0 
        } );
        handle_error("database connection failed") 
                unless ($dbh);
}
#################################@@
## return user quota from database
#################################@@

sub check_page_count {

        # Prepare a SQL statement
        $sth = $dbh->prepare( "SELECT quota FROM printquota WHERE username=?" );
  
        # Execute the statement
        handle_error("User Name Not Found") 
                unless $sth->execute($uname);

        # Retrieve the page record
        ($pages) = $sth->fetchrow_array();
        $sth->finish;
        if ( $DBI::err ) {
                handle_error("Error getting your quota");
        } elsif ( !(defined $pages) ) {
                handle_error("Error getting your quota") 
        } elsif ( $pages <= 0 ) {
                handle_error("You have insufficient page quota");
        } else {
                return $pages;
        }
}

##@@ update quota record.

sub update_db {
        ## page left after print.
        my $pages = shift;
        $sth = $dbh->prepare("UPDATE printquota set quota=? WHERE username=?");
        handle_error("Update quota failed")
                unless $sth->execute($pages,$uname);
}

##@@ handle database error and quota error.
##@@ send windows pop up message to user.

sub handle_error {
        my ($msg) = @_;
        # Disconnect from the database
        $dbh->disconnect() if $dbh;
        # send windows popup message to win user.
        $msg = "'Error - ".$msg." '";
        print STDERR "$0: sending popup msg to $uname\n$msg\n";
        `$rmssh $uname $msg`;
        write_history($msg);
        exit( $JABORT );
}

Reply via email to