3 use File::Temp qw(tempfile);
7 #######################################################
9 ######################################################
11 my $arg_job = $ARGV[0];
12 my $arg_user = $ARGV[1];
13 my $arg_title = $ARGV[2];
14 my $arg_copies = $ARGV[3];
15 my $arg_options = $ARGV[4];
17 my $progname = basename( $0 );
19 # Set to 1 to capture the Postscript that you generate to a temp file
20 my $capture_postscript = 0;
22 # Set to 1 to print debug messages to CUPS error log
25 my $capture_fh = undef;
26 my $capture_filename = undef;
29 #----------------------------------------------------
31 ######################################################
32 # Various debug & error subs
33 # Error and debugging messages have to go to STDERR
34 ######################################################
38 print STDERR "ERROR: $progname - $mesg\n";
44 return if( ! $debug );
46 print STDERR "DEBUG: $progname [PID $$] $output\n";
52 print STDERR "INFO: $progname [PID $$] $output\n";
58 print STDERR "WARN: $progname [PID $$] $output\n";
61 ###################################################################
62 # Open a temp file to capture the Postscript that I send to the printer.
64 ###################################################################
67 if( $capture_postscript ) {
68 ( $capture_fh, $capture_filename ) =
69 tempfile( "${progname}-$$-capture-XXXXXX", DIR => "/tmp", SUFFIX => ".ps", UNLINK => 0 );
70 if ( !defined $capture_fh ) {
72 print_warning( "Could not open capture file. Will not save Postscript output." );
73 $capture_filename = undef;
74 $capture_postscript = 0;
77 print_info( "Capturing Postscript to '$capture_filename'" );
82 ###################################################################
83 # Close the debugging capture log
84 ###################################################################
87 if( $capture_postscript && defined $capture_fh ) {
88 close( $capture_fh ) or print_warning( "Could not close capture file '$capture_filename': $!" );
92 ###################################################################
93 # Print out the given line to STDOUT (print data stream)
94 # and optionally capture it for debugging.
95 ###################################################################
101 if( $capture_postscript && $capture_fh ) {
102 print $capture_fh $line;
106 ###################################################################
107 # Get the type of accounting that is used for the printer
108 # by looking at the PPD for specific values.
109 # Currently only support HPAccountingInfo: 1
110 ###################################################################
111 sub GetHPAccountingType
113 my $ppd = $ENV{"PPD"};
114 if( (! $ppd ) || (! -r $ppd ) ) {
115 return( "NONE", "NONE" );
118 open( PPDFILE, "$ppd" ) or return( "NONE", "NONE" );
120 my $accounting_type = "NONE";
121 my $accounting_mode = "NONE";
125 if( $ppdline =~ /^\*HPAccountingInfo:\s*(\d*)\s*$/ ) {
126 $accounting_type = "HPAccountingInfo";
127 $accounting_mode = $1;
128 print_debug("HPAccountingInfo found $accounting_mode");
133 return( $accounting_type, $accounting_mode );
136 ###################################################################
137 # The Postscript code containing the accounting info
138 # has starting and ending snippets.
139 ###################################################################
140 sub InsertFeatureStart
147 emit_line( "} stopped cleartomark\n" );
150 ###################################################################
164 ###################################################################
168 ###################################################################
171 ###################################################################
175 my $options = $arg_options;
176 my @opt_array = split( ' ', $options );
177 foreach my $option ( @opt_array ) {
178 my( $name, $value ) = split( /=/, $option, 2 );
182 print_debug( "Option $name='$value'" );
183 $opt_hash{$name} = $value;
185 return( \%opt_hash );
188 ###################################################################
189 # If a UUID wasn't given to us by CUPS, try a few methods
190 # to create one ourselves.
191 ###################################################################
197 my $ug = new Data::UUID;
198 $uuid_str = $ug->create_str;
201 $uuid_str = `uuidgen`;
202 $uuid_str =~ s/\r?\n?$//;
208 ###################################################################
209 # CUPS passes in an option value that contains a UUID.
210 # If it's there, use that and if not, try to create one ourselves
211 ###################################################################
215 my $r_opt_hash = GetOptions();
216 # job-uuid=urn:uuid:018c1dab-3c0c-3edf-6036-1e87af479038
218 my $job_uuid = $$r_opt_hash{ "job-uuid" };
220 if ( $job_uuid =~ /urn:uuid:(.*)/ ) {
222 print_debug( "UUID in job-uuid=$uuid" );
225 print_debug( "bad job-uuid" );
226 $uuid = CreateUUID();
230 $uuid = CreateUUID();
234 print_debug( "EPIC FAIL: Could not find nor generate UUID" );
240 ###################################################################
241 # Get the system name
242 ###################################################################
245 my $system_name = hostname;
246 if( !$system_name ) {
247 $system_name = "unknown-system_name";
250 return( $system_name );
254 ###################################################################
255 # The domain value is really a Windows domain. Since we're
256 # not using this in the Windows environment, we just
257 # use the hostname. The value is not used for Color Access Control
258 # filtering but it still has to be included in the job accounting info
259 ###################################################################
262 my $domain = hostname;
264 $domain = "unknown-domain";
270 ###################################################################
271 # Gather up all of the information needed for the accounting data
272 # to be included in the print stream
273 ###################################################################
274 sub GetHPAccountingInfo
276 my( $jobname, $user, $system, $domain, $date, $uuid, $app, $appexe, $dept );
280 $system = GetSystem();
281 $domain = GetDomain();
282 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
286 $date = sprintf( "%s%02d%02d%02d%02d%02d", $year, $mon, $mday, $hour, $min, $sec);
289 # There is no way to get the name of the application that generated this PS file.
290 # Set it to this as a fallback.
291 $app = "HP Linux Printing";
292 $appexe = "HP Linux Printing";
296 return( $jobname, $user, $system, $domain, $date, $uuid, $app, $appexe, $dept );
299 ###################################################################
300 # Once the accounting data has been gathered, format it and
301 # include it in the print stream.
302 ###################################################################
303 sub InsertHPAccountingInfo
306 my ( $accounting_type, $accounting_mode ) = GetHPAccountingType();
307 print_debug( "Accounting Type=$accounting_type\tAccounting Mode=$accounting_mode");
309 if( ! ( ($accounting_type eq "HPAccountingInfo") && ($accounting_mode == 1)) ) {
310 print_debug( "Color Access Control not in effect." );
314 InsertFeatureStart();
315 my( $jobname, $user, $system, $domain, $date, $uuid, $app, $appexe, $dept ) = GetHPAccountingInfo();
317 my $accounting_feature = "";
318 $accounting_feature = "%%BeginFeature: *HPAccountingInfo\n" .
319 " currentpagedevice /StringCodeSet known\n" .
321 " << /StringCodeSet (UTF8) >> setpagedevice\n" .
323 " /JobName ($jobname)\n" .
324 " /JobAcct1 ($user)\n" .
325 " /JobAcct2 ($system)\n" .
326 " /JobAcct3 ($domain)\n" .
327 " /JobAcct4 ($date)\n" .
328 " /JobAcct5 ($uuid)\n" .
329 " /JobAcct6 ($app)\n" .
330 " /JobAcct7 ($appexe)\n" .
331 " /JobAcct8 ($dept)\n" .
332 " >> setuserparams\n" .
336 " /JobName ($jobname)\n" .
337 " /JobAcct1 ($user)\n" .
338 " /JobAcct2 ($system)\n" .
339 " /JobAcct3 ($domain)\n" .
340 " /JobAcct4 ($date)\n" .
341 " /JobAcct5 ($uuid)\n" .
342 " /JobAcct6 ($app)\n" .
343 " /JobAcct7 ($appexe)\n" .
344 " /JobAcct8 ($dept)\n" .
345 " >> setuserparams\n" .
349 emit_line( $accounting_feature );
353 ###################################################################
354 # If the print job is from stdin, save a copy
355 ###################################################################
358 my ( $tmp_fh, $tmp_filename ) =
359 tempfile( "${progname}-$$-stdin-XXXXXX", SUFFIX => ".ps", DIR => "/tmp", UNLINK => 0 );
360 if ( !defined $tmp_fh ) {
361 abort_exit( "Cannot create tempfile '$tmp_filename'" );
364 print_debug( "Copying STDIN to $tmp_filename" );
369 close $tmp_fh or abort_exit( "Cannot close tempfile '$tmp_filename': $!" );
370 return( $tmp_filename );
373 ###################################################################
374 # If the print job is contained in a file, make a copy.
375 # A copy is made because the original file could be deleted
376 # before this print job is completed.
377 ###################################################################
382 open (FROM, "<$from" ) or abort_exit( "Cannot read '$from': $!" );
383 my ( $tmp_fh, $tmp_filename ) =
384 tempfile( "${progname}-$$-copy-XXXXXX", SUFFIX => ".ps", DIR => "/tmp", UNLINK => 0 );
385 if ( !defined $tmp_fh ) {
386 abort_exit( "Couldn't create temporary file '$tmp_filename'" );
389 print_debug( "Copying $from to $tmp_filename" );
391 print $tmp_fh $_ or abort_exit( "Can't write to tempfile '$tmp_filename': $!" );
393 close $tmp_fh or abort_exit( "Cannot close tempfile '$tmp_filename': $!" );
395 return $tmp_filename;
398 ###################################################################
399 # Given the print job, look through it for the right place to
400 # insert the accounting info. The document is assumed to be in
401 # the Adobe DSC format already and should contain the BeginProlog
402 # item. Upstream CUPS filters will have converted the Postscript
403 # data into DSC format.
404 ###################################################################
408 open (PSFILE, "<$fn") or abort_exit( "Cannot open '$fn': $!");
412 if( /%%BeginProlog/ ) {
413 InsertHPAccountingInfo();
419 ###################################################################
421 ###################################################################
425 $procfile = stdin2file();
429 $procfile = copy_file($ARGV[5]);
431 abort_exit( "job-id user title copies options [file]");
434 for my $i ( 0 .. $#ARGV ) {
435 print_debug( "ARG $i=$ARGV[$i]")
437 print_debug("job-id=$arg_job user=$arg_user title=$arg_title copies=$arg_copies $arg_options $procfile");
440 foreach $key ( sort keys %ENV) {
441 print_debug("ENV $key=$ENV{$key}");
444 print_debug( "Processing file");
446 processfile($procfile);
449 unlink($procfile) or print STDERR "ERROR: $progname - Couldn't remove '$procfile': $!\n";