#!@PERL@ # -*- perl -*- # Foomatic PPD file generator for manual PPD generation (via "-p", # "-d", "-A", and "-P" command line options) or for automatic # on-the-fly PPD generation by CUPS 1.2 or newer (via "cat" and "list" # command line options). use Foomatic::Defaults; use Foomatic::DB; use Getopt::Std; use Data::Dumper; #use strict; my $debug = 0; # Use program name as the first part of the PPD URI for CUPS (should be # "foomatic"). $0 =~ m!/([^/]+)\s*$!; my $progname = ($1 || $0); # Default settings for listing PPDs by cups-driverd # List only the PPD file with the reconmmended driver for each printer # and do not show "(recommended)" in the CUPS web interface. This mode # makes CUPS setup with the web interface very easy for beginners. # This can be set by "OnlyRecommended Yes" or "OnlyRecommended No" in # /etc/cups/foomatic.conf my $onlyrecommended = 0; # The Foomatic database does not only generate PPD files from Foomatic # XML data but also of ready-made PPDs mainly from printer manufacturers # for their PostScript printers. As these PPDs are often also linked to # the directories in which CUPS links directly to PPD files, duplicate # listing of these PPDs by CUPS would result. Therefore we suppress # listing the ready-made PPDs. This behaviour can be changed by using # "ListReadyMadePPDs Yes" or "ListReadyMadePPDs No" in # /etc/cups/foomatic.conf my $listreadymadeppds = 0; help() if !@ARGV; #my ($opt_h, $opt_d, $opt_p, $opt_A, $opt_P, $opt_w); getopts("AP:d:p:hwt:"); help() if $opt_h; my $drv = $opt_d; my $poid = $opt_p; my $showall = $opt_A; my $showmatch = $opt_P; help() if ($#ARGV > 1) && !($poid); if ($ARGV[0] =~ /^list$/i) { # List all available PPD files (format for cups-driverd) cupslistppds(); } elsif ($ARGV[0] =~ /^cat$/i) { # Generate and return the selected PPD file (cups-driverd command line) generateppd($ARGV[1]); } elsif ($showall or $showmatch) { # List all PPD files or files matching regexp (manual operation) foomaticlistppds($showmatch); } elsif ($poid) { # Generate and return the selected PPD file (manual operation) generateppd($poid, $drv); } else { help(); } exit(0); sub cupslistppds { # Read configuration in /etc/cups/foomatic.conf my $conffilename; if (my $cupsserverroot = $ENV{CUPS_SERVERROOT}) { $conffilename = "$cupsserverroot/foomatic.conf"; } else { $conffilename = "/etc/cups/foomatic.conf"; } my $onlyrecommended = 0; my $listreadymadeppds = 0; if (-r $conffilename and open CONF, "< $conffilename") { while (my $line = ) { chomp $line; if ($line =~ /^\s*OnlyRecommended\s+(Yes|On|True|1)\s*$/i) { $onlyrecommended = 1; } elsif ($line =~ /^\s*OnlyRecommended\s+(No|Off|False|0)\s*$/i) { $onlyrecommended = 0; } if ($line =~ /^\s*ListReadyMadePPDs\s+(Yes|On|True|1)\s*$/i) { $listreadymadeppds = 1; } elsif ($line =~ /^\s*ListReadyMadePPDs\s+(No|Off|False|0)\s*$/i) { $listreadymadeppds = 0; } } close CONF; } my $db = Foomatic::DB->new(); $db->get_overview(1, 1 + $listreadymadeppds); for my $printer (@{$db->{'overview'}}) { my $poid = $printer->{'id'}; my $make = $printer->{'make'}; my $model = $printer->{'model'}; my $recdriver = $printer->{'driver'}; my @drivers = @{$printer->{'drivers'}}; my $id = $printer->{'ieee'}; # No drivers => No PPDs next if $#drivers < 0; # Put the reconmmended driver to the beginning of list, as CUPS # probably will take the first PPD which matches the printer model my @sorteddrivers; if (Foomatic::DB::member($recdriver, @drivers)) { # Valid entry for the recommended driver push(@sorteddrivers, $recdriver); if (!$onlyrecommended) { foreach my $driver (@drivers) { push(@sorteddrivers, $driver) if $driver ne $recdriver; } } } else { # Invalid entry for the recommended driver next if $onlyrecommended; undef $recdriver; @sorteddrivers = @drivers; } # Go through all the drivers and list the PPD entries foreach my $driver (@sorteddrivers) { # Get PPD header data from the PPD file generator my ($ieee1284,$pnpmake,$pnpmodel,$filename,$longname, $drivername,$nickname,$modelname) = Foomatic::DB::getppdheaderdata($printer, $driver, ($onlyrecommended ? '' : $printer->{'driver'})); print "\"$progname:$printer->{'id'}-$driver.ppd\" en \"$make\" \"$nickname\" \"$ieee1284\"\n"; } } } sub foomaticlistppds { my ($match) = @_; my $db = Foomatic::DB->new(); $db->get_overview(); my @drivers = $db->get_driverlist(); for my $printer (@{$db->{'overview'}}) { my $pr = $printer->{'make'}; my $model = $printer->{'model'}; my $name = "$pr $model"; my $driver = ($printer->{'driver'} || "No Default Driver"); my $dlist = ""; my $dcount = 0; if( $printer->{'drivers'} ){ $dcount = @{$printer->{'drivers'}}; for my $d (@{$printer->{'drivers'}}) { $dlist .= "$d "; } } if (not $match or "$name" =~ m{$match}o) { print "$name Id='$printer->{'id'}' Driver='$driver'"; if ($dcount > 1){ print " CompatibleDrivers='$dlist'"; } print "\n"; } } } sub generateppd { my ($ppduri, $driver) = @_; my $poid; my $db = Foomatic::DB->new(); my $printer; my @drivers = $db->get_driverlist(); if ($ppduri =~ /^$progname:(.*)\.ppd$/) { # cups-driverd operation # We try to split between printer name and driver name at all # dashes in the PPD file name, as some drivers (ex. hpijs-pcl3) # have dashes in their names. my $ppdname = $1; my @poidcomponents = split(/-/, $ppdname); my @drivercomponents = (); my @printers = $db->get_printerlist(); while ($#poidcomponents > 1) { unshift(@drivercomponents, pop(@poidcomponents)); $driver = join('-', @drivercomponents); $printer = join('-', @poidcomponents); my @driver_printers = $db->get_printers_for_driver ($driver); next if ((!Foomatic::DB::member($driver, @drivers) or !Foomatic::DB::member($printer, @printers)) and !Foomatic::DB::member($printer, @driver_printers)); $poid = $printer; last; } die "ERROR: Could not determine driver name for $ppdname.ppd!\n" if( !$poid ); } else { # manual operation $poid = $ppduri; } # If the user supplies an old numerical printer ID, translate it to # a new clear-text ID $poid = Foomatic::DB::translate_printer_id($poid); my $lcname = lc( $poid ); my $pentry = $db->get_printer($poid); if (!$pentry || ($pentry->{'noxmlentry'} != 0)) { $pentry = undef; $db->get_overview(); for $printer (@{$db->{'overview'}}) { my $name = lc( $printer->{'id'} ); print STDERR "DEBUG2: $progname: compare '$lcname' to '$name'\n" if $debug; if( $name eq $lcname ){ $pentry = $printer; $poid = $pentry->{'id'}; print STDERR "DEBUG: $progname: Using printer entry '$poid'\n" if $debug; last; } } } print STDERR "DEBUG: Printer '$poid' not found!\n" if ($debug && not defined $pentry ); print STDERR "DEBUG: $progname: Found $pentry->{id}\nDEBUG2: $progname: " . join ("\nDEBUG2: $progname: ", split(/\n/, Dumper($pentry))) . "\n" if $debug; if (!$driver || ($driver =~ /(default|recommended)/i)) { $driver = $pentry->{'driver'}; if( not defined( $driver ) ){ die "ERROR: $progname: Printer '$poid' does not have default driver!\n"; } } my @drvlist = $db->get_drivers_for_printer($poid); my $found = 0; for my $d (@drvlist) { last if ($found = ($driver eq $d)); } if ( not $found ) { warn "ERROR: $progname: Printer '$poid' and driver '$driver' are not compatible\n"; } $found = 0; for my $d (@drivers) { last if ($found = ($driver eq $d)); } if ( not $found ) { print STDERR "DEBUG: $progname: Driver '$driver' not in database!\n" if $debug; } # Get all the data about this driver/printer pair my $possible = $db->getdat($driver, $poid); # Stop if the printer is not supported by the given driver die "ERROR: $progname: That printer and driver combination is not possible.\n" if (!$possible); # Stop if the driver entry has an empty command line prototype or if there # is no custom PPD file die "ERROR: $progname: There is neither a custom PPD file nor the driver database entry contains sufficient data to build a PPD file.\n" if (!$db->{'dat'}{'cmd'}) && (!$db->{'dat'}{'ppdfile'}); my @data; @data = $db->getppd($opt_w); die "ERROR: $progname: No PPD file for printer '$poid' and driver '$driver'!\n" if not @data; print @data; } sub help { print < $progname -p [-d ] [-w] $progname list $progname cat [-w] $progname -h -A : show all Printer ID's and compatible drivers -P : show all Printer ID's whose names and model matched by the RE. For example: -P HP will match all names with HP in them -p : Printer ID -d : Driver name If the driver is not specified then the default driver for the is used. list : List all possible PPDs in the format needed by the cups-driverd cat : Generate PPD file appropriate to the . Available CUPS PPD URIs are listed by "$progname list". -w : Generate PPD which is compatible with the CUPS PostScript driver for Windows (GUI strings are limited to 39 characters). -h : show help information HELP exit 1; }