diff options
Diffstat (limited to 'perl-install/printer.pm')
-rw-r--r-- | perl-install/printer.pm | 1069 |
1 files changed, 612 insertions, 457 deletions
diff --git a/perl-install/printer.pm b/perl-install/printer.pm index 0ece8d811..e3ce0f7fa 100644 --- a/perl-install/printer.pm +++ b/perl-install/printer.pm @@ -1,537 +1,692 @@ -package printer; +package printer; # $Id$ use diagnostics; use strict; -use vars qw(%thedb %printer_type %printer_type_inv); +use vars qw(%thedb %thedb_gsdriver %printer_type %printer_type_inv @papersize_type %fields @entries_db_short @entry_db_description %descr_to_help %descr_to_db %db_to_descr %descr_to_ppd); -######################################################################################## -# misc imports -######################################################################################## -use Data::Dumper; -use File::Copy; +use common qw(:common :system :file); +use commands; -######################################################################################## -# pixel imports -######################################################################################## -# -######################################################################################## -# EXAMPLES AND TYPES -######################################################################################## - -# An entry in the 'printerdb' file, which describes each type of -# supported printer - -#ex: -#StartEntry: DeskJet550 -# GSDriver: cdj550 -# Description: {HP DeskJet 550C/560C/6xxC series} -# About: { \ -# This driver supports the HP inkjet printers which have \ -# color capability using both black and color cartridges \ -# simultaneously. Known to work with the 682C and the 694C. \ -# Other 600 and 800 series printers may work \ -# if they have this feature. \ -# If your printer seems to be saturating the paper with ink, \ -# try added an extra GS option of '-dDepletion=2'. \ -# Ghostscript supports several optional parameters for \ -# this driver: see the document 'devices.doc' \ -# in the ghostscript directory under /usr/doc. \ -# } -# Resolution: {300} {300} {} -# BitsPerPixel: {3} {Normal color printing with color cartridge} -# BitsPerPixel: {8} {Floyd-Steinberg B&W printing for better greys} -# BitsPerPixel: {24} {Floyd-Steinberg Color printing (best, but slow)} -# BitsPerPixel: {32} {Sometimes provides better output than 24} -#EndEntry - -my %ex_printerdb_entry = - ( - ENTRY => "DeskJet550", #Human-readable name of the entry - GSDRIVER => "cdj550", #gs driver used by this printer - DESCR => "HP DeskJet 550C/560C/6xxC series", #Single line description of printer - ABOUT => " - This driver supports the HP inkjet printers which have - color capability using both black and color cartridges - ...", #Lengthy description of printer - RESOLUTION => [ #List of resolutions supported - { - XDPI => 300, - YDPI => 300, - DESCR => "commentaire", - }, - ], - BITSPERPIXEL => [ #List of color depths supported - { - DEPTH => 3, - DESCR => "Normal color printing with color cartridge", - }, - ], - ) -; - - - -# A printcap entry -# Only represents a subset of possible options available -# Sufficient for the simple configuration we are interested in - -# there is also some text in the template (.in) file in the spooldir - -#ex: -## /etc/printcap -## -## Please don't edit this file directly unless you know what you are doing! -## Be warned that the control-panel printtool requires a very strict format! -## Look at the printcap(5) man page for more info. -## -## This file can be edited with the printtool in the control-panel. -# -###PRINTTOOL3## LOCAL uniprint NAxNA letter {} U_NECPrinwriter2X necp2x6 1 -#lpname:\ -# :sd=/var/spool/lpd/lpnamespool:\ -# :mx#45:\ -# :sh:\ -# :lp=/dev/device:\ -# :if=/var/spool/lpd/lpnamespool/filter: -###PRINTTOOL3## REMOTE st800 360x180 a4 {} EpsonStylus800 Default 1 -#remote:\ -# :sd=/var/spool/lpd/remotespool:\ -# :mx#47:\ -# :sh:\ -# :rm=remotehost:\ -# :rp=remotequeue:\ -# :if=/var/spool/lpd/remotespool/filter: -###PRINTTOOL3## SMB la75plus 180x180 letter {} DECLA75P Default {} -#smb:\ -# :sd=/var/spool/lpd/smbspool:\ -# :mx#46:\ -# :sh:\ -# :if=/var/spool/lpd/smbspool/filter:\ -# :af=/var/spool/lpd/smbspool/acct:\ -# :lp=/dev/null: -###PRINTTOOL3## NCP ap3250 180x180 letter {} EpsonAP3250 Default {} -#ncp:\ -# :sd=/var/spool/lpd/ncpspool:\ -# :mx#46:\ -# :sh:\ -# :if=/var/spool/lpd/ncpspool/filter:\ -# :af=/var/spool/lpd/ncpspool/acct:\ -# :lp=/dev/null: - - -my %ex_printcap_entry = - ( - QUEUE => "lpname", #Queue name, can have multi separated by '|' - - #if you want something different from the default - SPOOLDIR => "/var/spool/lpd/lpnamespool/", #Spool directory - IF => "/var/spool/lpd/lpnamespool/filter", #input filter - - # commentaire inserer dans le printcap pour que printtool retrouve ses petits - DBENTRY => "DeskJet670", #entry in printer database for this printer - - RESOLUTION => "NAxNA", #ghostscript resolution to use - PAPERSIZE => "letter", #Papersize - BITSPERPIXEL => "necp2x6", #ghostscript color option - CRLF => "YES" , #Whether or not to do CR/LF xlation - - TYPE => "LOCAL", - - # LOCAL - DEVICE => "/dev/device", #Print device - - # REMOTE (lpd) printers only - REMOTEHOST => "remotehost", #Remote host (not used for all entries) - REMOTEQUEUE => "remotequeue", #Queue on the remote machine - - - #SMB (LAN Manager) only - # in spooldir/.config - #share='\\hostname\printername' - #hostip=1.2.3.4 - #user='user' - #password='passowrd' - #workgroup='AS3' - SMBHOST => "hostname", #Server name (NMB name, can have spaces) - SMBHOSTIP => "1.2.3.4", #Can optional specify and IP address for host - SMBSHARE => "printername", #Name of share on the SMB server - SMBUSER => "user", #User to log in as on SMB server - SMBPASSWD => "passowrd", #Corresponding password - SMBWORKGROUP => "AS3", #SMB workgroup name - AF => "/var/spool/lpd/smbspool/acct", #accounting filter (needed for smbprint) - - # NCP (NetWare) only - # in spooldir/.config - #server=printerservername - #queue=queuename - #user=user - #password=pass - NCPHOST => "printerservername", #Server name (NCP name) - NCPQUEUE => "queuename", #Queue on server - NCPUSER => "user", #User to log in as on NCP server - NCPPASSWD => "pass", #Corresponding password - - ) -; - -######################################################################################## -# INTERN CONSTANT -######################################################################################## -my $PRINTER_NONE = "NONE"; -my $PRINTER_LOCAL = "LOCAL"; -my $PRINTER_LPRREM = "REMOTE"; -my $PRINTER_SMB = "SMB"; -my $PRINTER_NCP = "NCP"; - -######################################################################################## -# EXPORTED CONSTANT -######################################################################################## - - -%printer_type = ("local" => $PRINTER_LOCAL, - "Remote lpd" => $PRINTER_LPRREM, - "SMB/Windows 95/NT" => $PRINTER_SMB, - "NetWare" => $PRINTER_NCP, - ); +#-if we are in an DrakX config +my $prefix = ""; +#-location of the printer database in an installed system +my $PRINTER_DB_FILE = "/usr/lib/rhs/rhs-printfilters/printerdb"; +my $PRINTER_FILTER_DIR = "/usr/lib/rhs/rhs-printfilters"; + +%printer_type = ( + __("Local printer") => "LOCAL", + __("Remote printer") => "REMOTE", + __("Remote CUPS server") => "CUPS", + __("Remote lpd server") => "LPD", + __("Network printer (socket)") => "SOCKET", + __("SMB/Windows 95/98/NT") => "SMB", + __("NetWare") => "NCP", + __("Printer Device URI") => "URI", +); %printer_type_inv = reverse %printer_type; +%fields = ( + STANDARD => [qw(QUEUE SPOOLDIR IF)], + SPEC => [qw(DBENTRY RESOLUTION PAPERSIZE BITSPERPIXEL CRLF)], + LOCAL => [qw(DEVICE)], + REMOTE => [qw(REMOTEHOST REMOTEQUEUE)], + SMB => [qw(SMBHOST SMBHOSTIP SMBSHARE SMBUSER SMBPASSWD SMBWORKGROUP AF)], + NCP => [qw(NCPHOST NCPQUEUE NCPUSER NCPPASSWD)], +); +@papersize_type = qw(letter legal ledger a3 a4); -######################################################################################## -# GLOBALS -######################################################################################## - -#db of all entries in the printerdb file +#------------------------------------------------------------------------------ +sub set_prefix($) { $prefix = $_[0]; } -#if we are in an panoramix config -my $prefix = ""; +sub default_queue($) { (split '\|', $_[0]{QUEUE})[0] } +sub default_spooldir($) { "/var/spool/lpd/" . default_queue($_[0]) } -# location of the printer database in an installed system -my $PRINTER_DB_FILE = "/usr/lib/rhs/rhs-printfilters/printerdb"; -my $PRINTER_FILTER_DIR = "/usr/lib/rhs/rhs-printfilters/"; -my $SPOOLDIR = "/var/spool/lpd/"; +sub default_printer_type($) { "LOCAL" } +sub printer_type($) { + for ($_[0]{mode}) { + /CUPS/ && return @printer_type_inv{qw(LOCAL REMOTE SMB), $::expert ? qw(URI) : ()}; + /lpr/ && return @printer_type_inv{qw(LOCAL LPD SMB NCP)}; + } +} -######################################################################################## -# FUNCTIONS -######################################################################################## +sub copy_printer_params($$) { + my ($from, $to) = @_; + map { $to->{$_} = $from->{$_} } grep { $_ ne 'configured' } keys %$from; #- avoid cycles. +} -sub set_prefix($) { - $prefix = shift; +sub getinfo($) { + my ($prefix) = @_; + my $printer = {}; + + set_prefix($prefix); + + #- try to detect which printing system has been previously installed. + #- the first detected is the default. + read_printers_conf($printer); #- try to read existing cups (local only) queues. + read_configured_queue($printer); #- try to read existing lpr queues. + + add2hash($printer, { + #- global parameters. + want => 0, + complete => 0, + str_type => undef, + QUEUE => "lp", + + #- lpr parameters. + SPOOLDIR => "/var/spool/lpd/lp", + DBENTRY => "PostScript", + PAPERSIZE => "", + ASCII_TO_PS => undef, + CRLF => undef, + NUP => 1, + RTLFTMAR => 18, + TOPBOTMAR => 18, + AUTOSENDEOF => 1, + + DEVICE => "/dev/lp0", + + REMOTEHOST => "", + REMOTEQUEUE => "", + + NCPHOST => "", #-"printerservername", + NCPQUEUE => "", #-"queuename", + NCPUSER => "", #-"user", + NCPPASSWD => "", #-"pass", + + SMBHOST => "", #-"hostname", + SMBHOSTIP => "", #-"1.2.3.4", + SMBSHARE => "", #-"printername", + SMBUSER => "", #-"user", + SMBPASSWD => "", #-"passowrd", + SMBWORKGROUP => "", #-"AS3", + + #- cups parameters. + DeviceURI => "parallel:/dev/lp0", + Info => "", + Location => "", + State => "Idle", + Accepting => "Yes", + }); + $printer; } -#****************************************************************************** -# read function -#****************************************************************************** -#------------------------------------------------------------------------------ -#Read the printer database from dbpath into memory + #------------------------------------------------------------------------------ +sub read_configured_queue($) { + my ($printer) = @_; + my $current = undef; + my $flush_current = sub { + if ($current) { + add2hash($printer->{configured}{$current->{QUEUE}} ||= {}, $current); + $current = undef; + } + }; + + #- read /etc/printcap file. + local *PRINTCAP; open PRINTCAP, "$prefix/etc/printcap" or return; + local $_; + while (<PRINTCAP>) { + chomp; + my $p = '(?:\{(.*?)\}|(\S+))'; + if (/^##PRINTTOOL3##\s+$p\s+$p\s+$p\s+$p\s+$p\s+$p\s+$p(?:\s+$p)?/) { + &$flush_current; + $current = { + mode => 'lpr', + TYPE => $1 || $2, + GSDRIVER => $3 || $4, + RESOLUTION => $5 || $6, + PAPERSIZE => $7 || $8, + #- ignored $9 || $10, + DBENTRY => $11 || $12, + BITSPERPIXEL => $13 || $14, + CRLF => $15 || $16, + }; + } elsif (/^\s*$/) { &$flush_current } + elsif (/^([^:]*):\\/) { $current->{QUEUE} = $1 } + if (/^\s+:(?:[^:]*:)*sd=([^:]*):/) { $current->{SPOOLDIR} = $1 } + if (/^\s+:(?:[^:]*:)*lp=([^:]*):\\/) { $current->{DEVICE} = $1 } + if (/^\s+:(?:[^:]*:)*rm=([^:]*):\\/) { $current->{REMOTEHOST} = $1 } + if (/^\s+:(?:[^:]*:)*rp=([^:]*):\\/) { $current->{REMOTEQUEUE} = $1 } + if (/^\s+:(?:[^:]*:)*af=([^:]*):\\/) { $current->{AF} = $1 } + if (/^\s+:(?:[^:]*:)*if=([^:]*):\\/) { $current->{IF} = $1 } + } + close PRINTCAP; + &$flush_current; + + #- parse general.cfg for any configured queue. + foreach (values %{$printer->{configured}}) { + my $entry = $_; + local *F; open F, "$prefix$entry->{SPOOLDIR}/general.cfg" or next; + local $_; + while (<F>) { + chomp; + if (/^\s*(?:export\s+)?PRINTER_TYPE=(.*?)\s*$/) { $entry->{TYPE} = $1 unless defined $entry->{TYPE} } + elsif (/^\s*(?:export\s+)?ASCII_TO_PS=(.*?)\s*$/) { $entry->{ASCII_TO_PS} = $1 eq 'YES' unless defined $entry->{ASCII_TO_PS} } + elsif (/^\s*(?:export\s+)?PAPER_SIZE=(.*?)\s*$/) { $entry->{PAPERSIZE} = $1 unless defined $entry->{PAPERSIZE} } + } + close F; + } + + #- parse postscript.cfg for any configured queue. + foreach (values %{$printer->{configured}}) { + my $entry = $_; + local *F; open F, "$prefix$entry->{SPOOLDIR}/postscript.cfg" or next; + local $_; + while (<F>) { + chomp; + if (/^\s*(?:export\s+)?GSDEVICE=(.*?)\s*$/) { $entry->{GSDRIVER} = $1 unless defined $entry->{GSDRIVER} } + elsif (/^\s*(?:export\s+)?RESOLUTION=(.*?)\s*$/) { $entry->{RESOLUTION} = $1 unless defined $entry->{RESOLUTION} } + elsif (/^\s*(?:export\s+)?COLOR=-dBitsPerPixel=(.*?)\s*$/) { $entry->{COLOR} = $1 unless defined $entry->{COLOR} } + elsif (/^\s*(?:export\s+)?COLOR=(.*?)\s*$/) { $entry->{COLOR} = $1 ? $1 : 'Default' unless defined $entry->{COLOR} } + elsif (/^\s*(?:export\s+)?PAPERSIZE=(.*?)\s*$/) { $entry->{PAPERSIZE} = $1 unless defined $entry->{PAPERSIZE} } + elsif (/^\s*(?:export\s+)?EXTRA_GS_OPTIONS=(.*?)\s*$/) { $entry->{EXTRA_GS_OPTIONS} = $1 unless defined $entry->{EXTRA_GS_OPTIONS}; $entry->{EXTRA_GS_OPTIONS} =~ s/^\"(.*)\"/$1/ } + elsif (/^\s*(?:export\s+)?REVERSE_ORDER=(.*?)\s*$/) { $entry->{REVERSE_ORDER} = $1 unless defined $entry->{REVERSE_ORDER} } + elsif (/^\s*(?:export\s+)?PS_SEND_EOF=(.*?)\s*$/) { $entry->{AUTOSENDEOF} = $1 eq 'YES' && $entry->{DBENTRY} eq 'PostScript' unless defined $entry->{AUTOSENDEOF} } + elsif (/^\s*(?:export\s+)?NUP=(.*?)\s*$/) { $entry->{NUP} = $1 unless defined $entry->{NUP} } + elsif (/^\s*(?:export\s+)?RTLFTMAR=(.*?)\s*$/) { $entry->{RTLFTMAR} = $1 unless defined $entry->{RTLFTMAR} } + elsif (/^\s*(?:export\s+)?TOPBOTMAR=(.*?)\s*$/) { $entry->{TOPBOTMAR} = $1 unless defined $entry->{TOPBOTMAR} } + } + close F; + } + + #- parse textonly.cfg for any configured queue. + foreach (values %{$printer->{configured}}) { + my $entry = $_; + local *F; open F, "$prefix$entry->{SPOOLDIR}/textonly.cfg" or next; + local $_; + while (<F>) { + chomp; + if (/^\s*(?:export\s+)?TEXTONLYOPTIONS=(.*?)\s*$/) { $entry->{TEXTONLYOPTIONS} = $1 unless defined $entry->{TEXTONLYOPTIONS}; $entry->{TEXTONLYOPTIONS} =~ s/^\"(.*)\"/$1/ } + elsif (/^\s*(?:export\s+)?CRLFTRANS=(.*?)\s*$/) { $entry->{CRLF} = $1 eq 'YES' unless defined $entry->{CRLF} } + elsif (/^\s*(?:export\s+)?TEXT_SEND_EOF=(.*?)\s*$/) { $entry->{AUTOSENDEOF} = $1 eq 'YES' && $entry->{DBENTRY} ne 'PostScript' unless defined $entry->{AUTOSENDEOF} } + } + close F; + } + + #- get extra parameters for SMB or NCP type queue. + foreach (values %{$printer->{configured}}) { + my $entry = $_; + if ($entry->{TYPE} eq 'SMB') { + my $config_file = "$prefix$entry->{SPOOLDIR}/.config"; + local *F; open F, "$config_file" or next; #die "Can't open $config_file $!"; + local $_; + while (<F>) { + chomp; + if (/^\s*share='\\\\(.*?)\\(.*?)'/) { + $entry->{SMBHOST} = $1; + $entry->{SMBSHARE} = $2; + } elsif (/^\s*hostip=(.*)/) { + $entry->{SMBHOSTIP} = $1; + } elsif (/^\s*user='(.*)'/) { + $entry->{SMBUSER} = $1; + } elsif (/^\s*password='(.*)'/) { + $entry->{SMBPASSWD} = $1; + } elsif (/^\s*workgroup='(.*)'/) { + $entry->{SMBWORKGROUP} = $1; + } + } + close F; + } elsif ($entry->{TYPE} eq 'NCP') { + my $config_file = "$prefix$entry->{SPOOLDIR}/.config"; + local *F; open F, "$config_file" or next; #die "Can't open $config_file $!"; + local $_; + while (<F>) { + chomp; + if (/^\s*server=(.*)/) { + $entry->{NCPHOST} = $1; + } elsif (/^\s*user='(.*)'/) { + $entry->{NCPUSER} = $1; + } elsif (/^\s*password='(.*)'/) { + $entry->{NCPPASSWD} = $1; + } elsif (/^\s*queue='(.*)'/) { + $entry->{NCPQUEUE} = $1; + } + } + close F; + } + } + + #- assume this printing system, but only if some queue are defined. + scalar(keys %{$printer->{configured}}) > 0 and $printer->{mode} ||= 'lpr'; +} + sub read_printer_db(;$) { - my ($dbpath) = @_; - - #$dbpath = $dbpath ? $dbpath : $DB_PRINTER_FILTER; - $dbpath ||= $PRINTER_DB_FILE; - $dbpath = "${prefix}$dbpath"; - - - %thedb and return; - - local *DBPATH; #don't have to do close - open DBPATH, "<$dbpath" or die "An error has occurred on $dbpath : $!"; - + my $dbpath = $prefix . ($_[0] || $PRINTER_DB_FILE); + + scalar(keys %thedb) > 4 and return; #- try reparse if using only ppa, POSTSCRIPT, TEXT. + + my %available_devices; #- keep only available devices in our database. + local $_; #- use of while (<... + local *AVAIL; open AVAIL, ($::testing ? "$prefix" : "chroot $prefix/ ") . "/usr/bin/gs --help |"; + while (<AVAIL>) { + if (/^Available devices:/ ... /^\S/) { + @available_devices{split /\s+/, $_} = () if /^\s+/; + } + } + close AVAIL; + $available_devices{ppa} = undef; #- if -x "$prefix/usr/bin/pbm2ppa" && -x "$prefix/usr/bin/pnm2ppa"; + delete $available_devices{''}; + @available_devices{qw/POSTSCRIPT TEXT/} = (); #- these are always available. + + local *DBPATH; #- don't have to do close ... and don't modify globals at least + open DBPATH, $dbpath or die "An error has occurred on $dbpath : $!"; + while (<DBPATH>) { if (/^StartEntry:\s(\w*)/) { - my $entryname = $1; - my $entry = {}; - - $entry->{ENTRY} = $entryname; - - WHILE : + my $entry = { ENTRY => $1 }; + + WHILE : while (<DBPATH>) { SWITCH: { - /GSDriver:\s*(\w*)/ and do { $entry->{GSDRIVER} = $1; last SWITCH}; - /Description:\s*{(.*)}/ and do { $entry->{DESCR} = $1; last SWITCH}; - /About:\s*{(.*)}/ and do { $entry->{ABOUT} = $1; last SWITCH}; - /About:\s*{(.*)/ - and do - { - my $string = "$1\n"; - while (<DBPATH>) { - /(.*)}/ and do { $entry->{ABOUT} = $string; last SWITCH}; - $string .= $_; - } - }; - /Resolution:\s*{(.*)}\s*{(.*)}\s*{(.*)}/ - and do { push @{$entry->{RESOLUTION}}, {XDPI => $1, YDPI => $2, DESCR => $3}; last SWITCH}; - /BitsPerPixel:\s*{(.*)}\s*{(.*)}/ - and do { push @{$entry->{BITSPERPIXEL}}, {DEPTH => $1, DESCR => $2};last SWITCH;}; - /EndEntry/ and do { last WHILE;}; + /GSDriver:\s*(\w*)/ and do { $entry->{GSDRIVER} = $1; last SWITCH }; + /Description:\s*{(.*)}/ and do { $entry->{DESCR} = $1; last SWITCH }; + /About:\s*{\s*(.*?)\s*}/ and do { $entry->{ABOUT} = $1; last SWITCH }; + /About:\s*{\s*(.*?)\s*\\\s*$/ + and do { + my $string = $1; + while (<DBPATH>) { + $string =~ /\S$/ and $string .= ' '; + /^\s*(.*?)\s*\\\s*$/ and $string .= $1; + /^\s*(.*?)\s*}\s*$/ and do { $entry->{ABOUT} = $string . $1; last SWITCH }; + } + }; + /Resolution:\s*{(.*)}\s*{(.*)}\s*{(.*)}/ + and do { push @{$entry->{RESOLUTION} ||= []}, { XDPI => $1, YDPI => $2, DESCR => $3 }; last SWITCH }; + /BitsPerPixel:\s*{(.*)}\s*{(.*)}/ + and do { push @{$entry->{BITSPERPIXEL} ||= []}, {DEPTH => $1, DESCR => $2}; last SWITCH }; + + /EndEntry/ and last WHILE; } } - $thedb{$entryname} = $entry; + if (exists $available_devices{$entry->{GSDRIVER}}) { + $thedb{$entry->{ENTRY}} = $entry; + $thedb_gsdriver{$entry->{GSDRIVER}} = $entry; + } } } + + @entries_db_short = sort keys %printer::thedb; + %descr_to_db = map { $printer::thedb{$_}{DESCR}, $_ } @entries_db_short; + %descr_to_help = map { $printer::thedb{$_}{DESCR}, $printer::thedb{$_}{ABOUT} } @entries_db_short; + @entry_db_description = keys %descr_to_db; + %db_to_descr = reverse %descr_to_db; +} + +#------------------------------------------------------------------------------ +sub read_cupsd_conf { + my @cupsd_conf; + local *F; + + open F, "$prefix/etc/cups/cupsd.conf"; + @cupsd_conf = <F>; + close F; + + @cupsd_conf; +} +sub write_cupsd_conf { + my (@cupsd_conf) = @_; + local *F; + + open F, ">$prefix/etc/cups/cupsd.conf"; + print F @cupsd_conf; + close F; + + #- restart cups after updating configuration. + require run_program; + run_program::rooted($prefix, "/etc/rc.d/init.d/cups restart"); sleep 1; +} + +sub read_printers_conf { + my ($printer) = @_; + my $current = undef; + + #- read /etc/cups/printers.conf file. + #- according to this code, we are now using the following keys for each queues. + #- DeviceURI > lpd://printer6/lp + #- Info > Info Text + #- Location > Location Text + #- State > Idle|Stopped + #- Accepting > Yes|No + local *PRINTERS; open PRINTERS, "$prefix/etc/cups/printers.conf" or return; + local $_; + while (<PRINTERS>) { + chomp; + /^\s*#/ and next; + if (/^\s*<(?:DefaultPrinter|Printer)\s+([^>]*)>/) { $current = { mode => 'CUPS', QUEUE => $1, } } + elsif (/\s*<\/Printer>/) { $current->{QUEUE} && $current->{DeviceURI} or next; #- minimal check of synthax. + add2hash($printer->{configured}{$current->{QUEUE}} ||= {}, $current); $current = undef } + elsif (/\s*(\S*)\s+(.*)/) { $current->{$1} = $2 } + } + close PRINTERS; + + #- assume this printing system. + $printer->{mode} ||= 'CUPS'; +} + +sub get_direct_uri { + #- get the local printer to access via a Device URI. + my @direct_uri; + local *F; open F, ($::testing ? "$prefix" : "chroot $prefix/ ") . "/usr/sbin/lpinfo -v |"; + local $_; + while (<F>) { + /^(direct|usb|serial)\s+(\S*)/ and push @direct_uri, $2; + } + close F; + @direct_uri; +} + +sub get_descr_from_ppd { + my ($printer) = @_; + my %ppd; + + #- if there is no ppd, this means this is the PostScript generic filter. + local *F; open F, "$prefix/etc/cups/ppd/$printer->{QUEUE}.ppd" or return "Generic PostScript"; + local $_; + while (<F>) { + /^\*([^\s:]*)\s*:\s*\"([^\"]*)\"/ and do { $ppd{$1} = $2; next }; + /^\*([^\s:]*)\s*:\s*([^\s\"]*)/ and do { $ppd{$1} = $2; next }; + } + close F; + + $ppd{Manufacturer} . '|' . ($ppd{NickName} || $ppd{ShortNickName} || $ppd{ModelName}) . + ($ppd{LanguageVersion} && (" (" . lc(substr($ppd{LanguageVersion}, 0, 2)) . ")")); } +sub poll_ppd_base { + #- before trying to poll the ppd database available to cups, we have to make sure + #- the file /etc/cups/ppds.dat is no more modified. + #- if cups continue to modify it (because it reads the ppd files available), the + #- poll_ppd_base program simply cores :-) + run_program::rooted($prefix, "ifup lo"); #- else cups will not be happy! + run_program::rooted($prefix, "/etc/rc.d/init.d/cups start"); + + foreach (1..60) { + local *PPDS; open PPDS, ($::testing ? "$prefix" : "chroot $prefix/ ") . "/usr/bin/poll_ppd_base -a |"; + local $_; + while (<PPDS>) { + chomp; + my ($ppd, $mf, $descr, $lang) = split /\|/; + $ppd && $mf && $descr and $descr_to_ppd{"$mf|$descr" . ($lang && " ($lang)")} = $ppd; + } + close PPDS; + scalar(keys %descr_to_ppd) > 5 and last; + sleep 1; #- we have to try again running the program, wait here a little before. + } + + scalar(keys %descr_to_ppd) > 5 or die "unable to connect to cups server"; -#****************************************************************************** -# write functions -#****************************************************************************** + #- assume a default printer not using any ppd at all. + $descr_to_ppd{"Generic PostScript"} = ''; +} + +#-****************************************************************************** +#- write functions +#-****************************************************************************** #------------------------------------------------------------------------------ -# given the path queue_path, we create all the required spool directory +#- given the path queue_path, we create all the required spool directory #------------------------------------------------------------------------------ sub create_spool_dir($) { my ($queue_path) = @_; - my $complete_path = "${prefix}$queue_path"; + my $complete_path = "$prefix/$queue_path"; + + commands::mkdir_("-p", $complete_path); unless ($::testing) { - mkdir "$complete_path", 0755 - or die "An error has occurred - can't create $complete_path : $!"; - - #redhat want that "drwxr-xr-x root lp" + #-redhat want that "drwxr-xr-x root lp" my $gid_lp = (getpwnam("lp"))[3]; - chown 0, $gid_lp, $complete_path + chown 0, $gid_lp, $complete_path or die "An error has occurred - can't chgrp $complete_path to lp $!"; } } #------------------------------------------------------------------------------ -#given the input spec file 'input', and the target output file 'output' -#we set the fields specified by fieldname to the values in fieldval -#nval is the number of fields to set -#Doesnt currently catch error exec'ing sed yet +#-given the input spec file 'input', and the target output file 'output' +#-we set the fields specified by fieldname to the values in fieldval +#-nval is the number of fields to set +#-Doesnt currently catch error exec'ing sed yet #------------------------------------------------------------------------------ sub create_config_file($$%) { - my ($inputfile, $outpufile, %toreplace) = @_; - my ($in, $out) = ("${prefix}$inputfile", "${prefix}$outpufile"); - local *OUT; - local *IN; - - #TODO my $oldmask = umask 0755; - - open IN , "<$in" or die "Can't open $in $!"; - if ($::testing) { - open OUT, ">$out" or die "Can't open $out $!"; - } else { - *OUT = *STDOUT - } - - while ((<IN>)) { - if (/@@@(.*)@@@/) { - my $chaine = $1; - if (!defined($toreplace{$chaine})) { - die "I can't replace $chaine"; - } - s/@@@(.*)@@@/$toreplace{$1}/g; - } - print OUT; - } - - + my ($inputfile, $outputfile, %toreplace) = @_; + template2file("$prefix/$inputfile", "$prefix/$outputfile", %toreplace); + eval { commands::chown_("root.lp", "$prefix/$outputfile") }; } #------------------------------------------------------------------------------ -#copy master filter to the spool dir +#-copy master filter to the spool dir #------------------------------------------------------------------------------ sub copy_master_filter($) { my ($queue_path) = @_; - my $complete_path = "${prefix}${queue_path}filter"; - my $master_filter = "${prefix}${PRINTER_FILTER_DIR}master-filter"; - + my $complete_path = "$prefix/$queue_path/filter"; + my $master_filter = "$prefix/$PRINTER_FILTER_DIR/master-filter"; - unless ($::testing) { - copy($master_filter, $complete_path) or die "Can't copy $master_filter to $complete_path $!"; - } - - + eval { commands::cp('-f', $master_filter, $complete_path) }; + $@ and die "Can't copy $master_filter to $complete_path $!"; + eval { commands::chown_("root.lp", $complete_path); }; } #------------------------------------------------------------------------------ -# given a PrintCap Entry, create the spool dir and special -# rhs-printfilters related config files which are required +#- given a PrintCap Entry, create the spool dir and special +#- rhs-printfilters related config files which are required #------------------------------------------------------------------------------ -my $intro_printcap_test=" +my $intro_printcap_test = " # # Please don't edit this file directly unless you know what you are doing! # Look at the printcap(5) man page for more info. # Be warned that the control-panel printtool requires a very strict format! -# Look at the printcap(5) man page for more info. # -# This file can be edited with the printtool in the control-panel. +# This file can be edited with printerdrake or printtool. # "; - sub configure_queue($) { my ($entry) = @_; - $entry->{SPOOLDIR} ||= "$SPOOLDIR"; - $entry->{IF} ||= "$SPOOLDIR$entry->{QUEUE}/filter"; - $entry->{AF} ||= "$SPOOLDIR$entry->{QUEUE}/acct"; - - my $queue_path = "$entry->{SPOOLDIR}"; - create_spool_dir($queue_path); + for ($entry->{mode}) { + /CUPS/ && do { + #- at this level, we are using lpadmin to create a local printer (only local + #- printer are supported with printerdrake). + require run_program; + run_program::rooted($prefix, "lpadmin", + "-p", $entry->{QUEUE}, + $entry->{State} eq 'Idle' && $entry->{Accepting} eq 'Yes' ? ("-E") : (), + "-v", $entry->{DeviceURI}, + $entry->{cupsPPD} ? ("-m", $entry->{cupsPPD}) : (), + $entry->{Info} ? ("-D", $entry->{Info}) : (), + $entry->{Location} ? ("-L", $entry->{Location}) : (), + ); + last }; + /lpr/ && do { + #- old style configuration scheme for lpr. + my $queue_path = "$entry->{SPOOLDIR}"; + create_spool_dir($queue_path); + + my $get_name_file = sub { + my ($name) = @_; + ("$PRINTER_FILTER_DIR/$name.in", "$entry->{SPOOLDIR}/$name") + }; + my ($filein, $file); + my %fieldname = (); + my $dbentry = $thedb{($entry->{DBENTRY})} or die "no dbentry"; + + #- make general.cfg + ($filein, $file) = &$get_name_file("general.cfg"); + $fieldname{ascps_trans} = $entry->{ASCII_TO_PS} || $dbentry->{GSDRIVER} eq 'ppa' ? "YES" : "NO"; + $fieldname{desiredto} = $dbentry->{GSDRIVER} ne "TEXT" ? "ps" : "asc"; + $fieldname{papersize} = $entry->{PAPERSIZE} ? $entry->{PAPERSIZE} : "letter"; + $fieldname{printertype} = $entry->{TYPE}; + create_config_file($filein, $file, %fieldname); + + #- now do postscript.cfg + ($filein, $file) = &$get_name_file("postscript.cfg"); + %fieldname = (); + $fieldname{gsdevice} = $dbentry->{GSDRIVER}; + $fieldname{papersize} = $entry->{PAPERSIZE} ? $entry->{PAPERSIZE} : "letter"; + $fieldname{resolution} = $entry->{RESOLUTION}; + $fieldname{color} = $entry->{BITSPERPIXEL} ne "Default" && + (($dbentry->{GSDRIVER} ne "uniprint" && "-dBitsPerPixel=") . $entry->{BITSPERPIXEL}); + $fieldname{reversepages} = $entry->{REVERSE_ORDER} ? "YES" : ""; + $fieldname{extragsoptions} = "\"$entry->{EXTRA_GS_OPTIONS}\""; + $fieldname{pssendeof} = $entry->{AUTOSENDEOF} ? ($dbentry->{GSDRIVER} eq "POSTSCRIPT" ? "YES" : "NO") : "NO"; + $fieldname{nup} = $entry->{NUP}; + $fieldname{rtlftmar} = $entry->{RTLFTMAR}; + $fieldname{topbotmar} = $entry->{TOPBOTMAR}; + create_config_file($filein, $file, %fieldname); + + #- finally, make textonly.cfg + ($filein, $file) = &$get_name_file("textonly.cfg"); + %fieldname = (); + $fieldname{textonlyoptions} = "\"$entry->{TEXTONLYOPTIONS}\""; + $fieldname{crlftrans} = $entry->{CRLF} ? "YES" : ""; + $fieldname{textsendeof} = $entry->{AUTOSENDEOF} ? ($dbentry->{GSDRIVER} eq "POSTSCRIPT" ? "NO" : "YES") : "NO"; + create_config_file($filein, $file, %fieldname); + + if ($entry->{TYPE} eq "SMB") { + #- simple config file required if SMB printer + my $config_file = "$prefix$queue_path/.config"; + local *F; + open F, ">$config_file" or die "Can't create $config_file $!"; + print F "share='\\\\$entry->{SMBHOST}\\$entry->{SMBSHARE}'\n"; + print F "hostip=$entry->{SMBHOSTIP}\n"; + print F "user='$entry->{SMBUSER}'\n"; + print F "password='$entry->{SMBPASSWD}'\n"; + print F "workgroup='$entry->{SMBWORKGROUP}'\n"; + close F; + eval { chmod 0640, $config_file; commands::chown_("root.lp", $config_file) }; + } elsif ($entry->{TYPE} eq "NCP") { + #- same for NCP printer + my $config_file = "$prefix$queue_path/.config"; + local *F; + open F, ">$config_file" or die "Can't create $config_file $!"; + print F "server=$entry->{NCPHOST}\n"; + print F "queue=$entry->{NCPQUEUE}\n"; + print F "user=$entry->{NCPUSER}\n"; + print F "password=$entry->{NCPPASSWD}\n"; + close F; + eval { chmod 0640, $config_file; commands::chown_("root.lp", $config_file) }; + } - my $get_name_file = sub { - my ($name) = @_; - ("${PRINTER_FILTER_DIR}$name.in)", "$entry->{SPOOLDIR}$name") - }; - my ($filein, $file); - my %fieldname = (); - my $dbentry = $thedb{($entry->{DBENTRY})} or die "no dbentry"; - - - ($filein, $file) = &$get_name_file("general.cfg"); - $fieldname{desiredto} = ($entry->{GSDRIVER} eq "TEXT") ? "ps" : "asc"; - $fieldname{papersize} = ($entry->{PAPERSIZES}) ? $entry->{PAPERSIZES} : "letter"; - $fieldname{printertype} = ($entry)->{TYPE}; - $fieldname{ascps_trans} = ($dbentry->{GSDRIVER} eq "POSTSCRIPT") ? - "NO" : "YES"; - create_config_file($filein,$file, %fieldname); - - # successfully created general.cfg, now do postscript.cfg - ($filein, $file) = &$get_name_file("postscript.cfg"); - %fieldname = (); - $fieldname{gsdevice} = $dbentry->{GSDRIVER}; - $fieldname{papersize} = ($entry->{PAPERSIZES}) ? $entry->{PAPERSIZES} : "letter"; - $fieldname{resolution} = ($entry->{RESOLUTION} eq "Default") ? "Default" : ""; - $fieldname{color} = - do { - if ($dbentry->{GSDRIVER} eq "uniprint") { - ($entry->{BITSPERPIXEL} eq "Default") ? "-dBitsPerPixel=Default" : ""; - } else { - $entry->{BITSPERPIXEL}; - } - }; - $fieldname{reversepages} = "NO"; - $fieldname{extragsoptions} = ""; - $fieldname{pssendeof} = ($dbentry->{GSDRIVER} eq "POSTSCRIPT") ? - "NO" : "YES"; - $fieldname{nup} = "1"; - $fieldname{rtlftmar} = "18"; - $fieldname{topbotmar} = "18"; - create_config_file($filein, $file, %fieldname); - - # finally, make textonly.cfg - ($filein, $file) = &$get_name_file("textonly.cfg"); - %fieldname = (); - $fieldname{textonlyoptions} = ""; - $fieldname{crlftrans} = $entry->{CRLF}; - $fieldname{textsendeof} = "1"; - create_config_file($filein, $file, %fieldname); - - - unless ($::testing) { - if ($entry->{TYPE} eq $PRINTER_SMB) { - # simple config file required if SMB printer - my $config_file = "${prefix}${queue_path}.config"; - local *CONFFILE; - open CONFFILE, ">$config_file" or die "Can't create $config_file $!"; - print CONFFILE "share='\\\\$entry->{SMBHOST}\\$entry->{SMBSHARE}'\n"; - print CONFFILE "hostip='$entry->{SMBHOSTIP}'\n"; - print CONFFILE "user='$entry->{SMBUSER}'\n"; - print CONFFILE "password='$entry->{SMBPASSWD}'\n"; - print CONFFILE "workgroup='$entry->{SMBWORKGROUP}'\n"; - } elsif ($entry->{TYPE} eq $PRINTER_NCP) { - # same for NCP printer - my $config_file = "${prefix}${queue_path}.config"; - local *CONFFILE; - open CONFFILE, ">$config_file" or die "Can't create $config_file $!"; - print CONFFILE "server=$entry->{NCPHOST}\n"; - print CONFFILE "queue=$entry->{NCPQUEUE}\n"; - print CONFFILE "user=$entry->{NCPUSER}\n"; - print CONFFILE "password=$entry->{NCPPASSWD}\n"; - } + copy_master_filter($queue_path); + + #-now the printcap file, note this one contains all the printer (use configured for that). + local *PRINTCAP; + open PRINTCAP, ">$prefix/etc/printcap" or die "Can't open printcap file $!"; + print PRINTCAP $intro_printcap_test; + foreach (values %{$entry->{configured}}) { + $_->{DBENTRY} = $thedb_gsdriver{$_->{GSDRIVER}}{ENTRY} unless defined $_->{DBENTRY}; + my $db_ = $thedb{$_->{DBENTRY}} or next; #die "no dbentry"; + + $_->{SPOOLDIR} ||= default_spooldir($_); + $_->{IF} ||= "$_->{SPOOLDIR}/filter"; + $_->{AF} ||= "$_->{SPOOLDIR}/acct"; + + printf PRINTCAP "##PRINTTOOL3## %s %s %s %s %s %s %s%s\n", + $_->{TYPE} || '{}', + $db_->{GSDRIVER} || '{}', + $_->{RESOLUTION} || '{}', + $_->{PAPERSIZE} || '{}', + '{}', + $db_->{ENTRY} || '{}', + $_->{BITSPERPIXEL} || '{}', + $_->{CRLF} ? " 1" : ""; + + print PRINTCAP "$_->{QUEUE}:\\\n"; + print PRINTCAP "\t:sd=$_->{SPOOLDIR}:\\\n"; + print PRINTCAP "\t:mx#0:\\\n\t:sh:\\\n"; + + if ($_->{TYPE} eq "LOCAL") { + print PRINTCAP "\t:lp=$_->{DEVICE}:\\\n"; + } elsif ($_->{TYPE} eq "REMOTE") { + print PRINTCAP "\t:rm=$_->{REMOTEHOST}:\\\n"; + print PRINTCAP "\t:rp=$_->{REMOTEQUEUE}:\\\n"; + } else { + #- (pcentry->Type == (PRINTER_SMB | PRINTER_NCP)) + print PRINTCAP "\t:lp=/dev/null:\\\n"; + print PRINTCAP "\t:af=$_->{AF}\\\n"; + } + + #- cheating to get the input filter! + print PRINTCAP "\t:if=$_->{IF}:\n"; + print PRINTCAP "\n"; + } + eval { commands::chown_("root.lp", "$prefix/etc/printcap") }; + last }; } - copy_master_filter($queue_path); - - #now the printcap file - local *PRINTCAP; - if ($::testing) { - open PRINTCAP, ">${prefix}etc/printcap" or die "Can't open printcap file $!"; - } else { - *PRINTCAP = *STDOUT; + my $useUSB = 0; + foreach (values %{$entry->{configured}}) { + $useUSB ||= $_->{DEVICE} =~ /usb/ || $_->{DeviceURI} =~ /usb/; } - - print PRINTCAP $intro_printcap_test; - printf PRINTCAP "##PRINTTOOL3## %s %s %s %s %s %s %s \n", - $entry->{TYPE}, - $dbentry->{GSDRIVER}, - $entry->{RESOLUTION}, - $entry->{PAPERSIZE}, - "{}", - $dbentry->{ENTRY}, - $entry->{BITSPERPIXEL}, - ($entry->{CRLF} eq "YES") ? "1" : ""; - - - print PRINTCAP "$entry->{QUEUE}:\\\n"; - print PRINTCAP "\t:sd=$entry->{SPOOLDIR}:\\\n"; - print PRINTCAP "\t:mx#0:\\\n\t:sh:\\\n"; - - if ($entry->{TYPE} eq $PRINTER_LOCAL) { - print PRINTCAP "\t:lp=$entry->{DEVICE}:\\\n"; - } elsif ($entry->{TYPE} eq $PRINTER_LPRREM) { - print PRINTCAP "\t:rm=$entry->{REMOTEHOST}:\\\n"; - print PRINTCAP "\t:rp=$entry->{REMOTEQUEUE}:\\\n"; - } else { - # (pcentry->Type == (PRINTER_SMB | PRINTER_NCP)) - print PRINTCAP "\t:lp=/dev/null:\\\n"; - print PRINTCAP "\t:af=$entry->{SPOOLDIR}acct\\\n"; + if ($useUSB) { + my $f = "$prefix/etc/sysconfig/usb"; + my %usb = getVarsFromSh($f); + $usb{PRINTER} = "yes"; + setVarsInSh($f, \%usb); } +} - # cheating to get the input filter! - print PRINTCAP "\t:if=$entry->{SPOOLDIR}filter:\n"; - +#- use the queue currently configured at the top of printer hash. +sub remove_queue($) { + my ($printer) = @_; + $printer->{configured}{$printer->{QUEUE}} or return; #- something strange at this point. + + if ($printer->{mode} eq 'CUPS') { + require run_program; + run_program::rooted($prefix, "lpadmin", "-x", $printer->{QUEUE}); + } + delete $printer->{configured}{$printer->{QUEUE}}; } +sub restart_queue($) { + my ($printer) = @_; + my $queue = default_queue($printer); + + for ($printer->{mode}) { + /CUPS/ && do { + #- restart cups before cleaning the queue. + require run_program; + run_program::rooted($prefix, "/etc/rc.d/init.d/cups start"); sleep 1; + run_program::rooted($prefix, "lprm-cups", "-P$queue", "-"); + last }; + /lpr/ && do { + #- restart lpd after cleaning the queue. + foreach (("/var/spool/lpd/$queue/lock", "/var/spool/lpd/lpd.lock")) { + my $pidlpd = (cat_("$prefix$_"))[0]; + kill 'TERM', $pidlpd if $pidlpd; + unlink "$prefix$_"; + } + require run_program; + run_program::rooted($prefix, "lprm-lpd", "-P$queue", "-"); sleep 1; + run_program::rooted($prefix, "lpd"); sleep 1; + last }; + } +} -#------------------------------------------------------------------------------ -#interface function -#------------------------------------------------------------------------------ +sub print_pages($@) { + my ($printer, @pages) = @_; + my $queue = default_queue($printer); + my ($lpr, $lpq); -sub -#pixel stuff -my ($o, $in); - + for ($printer->{mode}) { + /CUPS/ and ($lpr, $lpq) = ("/usr/bin/lpr-cups", "/usr/bin/lpq-cups"); + /lpr/ and ($lpr, $lpq) = ("/usr/bin/lpq-lpd", "/usr/bin/lpq-lpd"); + } -#------------------------------------------------------------------------------ -#fonction de test -#------------------------------------------------------------------------------ -sub test { - $::testing = 1; - $printer::prefix=""; - - read_printer_db(); - - print "the dump\n"; - print Dumper(%thedb); - - - # - #eval { printer::create_spool_dir("/tmp/titi/", ".") }; - #print $@; - #eval { printer::copy_master_filter("/tmp/titi/", ".") }; - #print $@; - # - # - #eval { printer::create_config_file("files/postscript.cfg.in", "files/postscript.cfg","./", - # ( - # gsdevice => "titi", - # resolution => "tata", - # )); - # }; - #print $@; - # - # - # - #printer::configure_queue(\%printer::ex_printcap_entry, "/"); + require run_program; + foreach (@pages) { + run_program::rooted($prefix, $lpr, "-P$queue", $_); + } + sleep 5; #- allow lpr to send pages. + local *F; open F, ($::testing ? "$prefix" : "chroot $prefix/ ") . "$lpq -P$queue |"; + my @lpq_output = grep { !/^no entries/ && !(/^Rank\s+Owner/ .. /^\s*$/) } <F>; + close F; + @lpq_output; } -######################################################################################## -# Wonderful perl :( -######################################################################################## -1; # +#-###################################################################################### +#- Wonderful perl :( +#-###################################################################################### +1; |