package printer::main;
# $Id$
use strict;
use common;
use run_program;
use printer::data;
use printer::services;
use printer::default;
use printer::cups;
use printer::detect;
use handle_configs;
use services;
use lang;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw(%printer_type %printer_type_inv);
#-Did we already read the subroutines of /usr/sbin/ptal-init?
my $ptalinitread = 0;
our %printer_type = (
N("Local printer") => "LOCAL",
N("Remote printer") => "REMOTE",
N("Printer on remote CUPS server") => "CUPS",
N("Printer on remote lpd server") => "LPD",
N("Network printer (TCP/Socket)") => "SOCKET",
N("Printer on SMB/Windows 95/98/NT server") => "SMB",
N("Printer on NetWare server") => "NCP",
N("Enter a printer device URI") => "URI",
N("Pipe job into a command") => "POSTPIPE"
);
our %printer_type_inv = reverse %printer_type;
our %thedb;
our $hplipdevicesdb;
# Translation of the "(recommended)" in printer driver entries
our $recstr = N("recommended");
our $precstr = "($recstr)";
our $sprecstr = quotemeta($precstr);
#------------------------------------------------------------------------------
sub spooler() {
# LPD is taken from the menu for the moment because the classic LPD is
# highly unsecure. Depending on how the GNU lpr development is going on
# LPD support can be reactivated by uncommenting the following line.
#return @spooler_inv{qw(cups lpd lprng pdq)};
# LPRng is not officially supported any more since version 9.0 of
# this distribution, so show it only in the spooler menu when it
# was manually installed.
# PDQ is not officially supported any more since version 9.1, so
# show it only in the spooler menu when it was manually installed.
return map { $spoolers{$_}{long_name} } ('cups', 'rcups' ,
if_(files_exist(qw(/usr/bin/pdq)), 'pdq'),
if_(files_exist(qw(/usr/lib/filters/lpf /usr/sbin/lpd)), 'lprng'));
}
sub printer_type($) {
my ($printer) = @_;
for ($printer->{SPOOLER}) {
/cups/ and return @printer_type_inv{qw(LOCAL LPD SOCKET SMB), if_($printer->{expert}, qw(URI))};
/lpd/ and return @printer_type_inv{qw(LOCAL LPD SOCKET SMB NCP), if_($printer->{expert}, qw(POSTPIPE URI))};
/lprng/ and return @printer_type_inv{qw(LOCAL LPD SOCKET SMB NCP), if_($printer->{expert}, qw(POSTPIPE URI))};
/pdq/ and return @printer_type_inv{qw(LOCAL LPD SOCKET), if_($printer->{expert}, qw(URI))};
/rcups/ and return ();
}
}
sub SIGHUP_daemon {
my ($service) = @_;
if ($service eq "cupsd") { $service = "cups" };
# PDQ and remote CUPS have no daemons, exit.
if (($service eq "pdq") || ($service eq "rcups")) { return 1 };
# CUPS needs auto-correction for its configuration
run_program::rooted($::prefix, "/usr/sbin/correctcupsconfig") if $service eq "cups";
# Name of the daemon
my %daemons = (
"lpr" => "lpd",
"lpd" => "lpd",
"lprng" => "lpd",
"cups" => "cupsd",
"devfs" => "devfsd",
);
my $daemon = $daemons{$service};
$daemon = $service unless defined $daemon;
# if ($service eq "cups") {
# # The current CUPS (1.1.13) dies on SIGHUP, do the normal restart.
# printer::services::restart($service);
# # CUPS needs some time to come up.
# printer::services::wait_for_cups();
# } else {
# Send the SIGHUP
run_program::rooted($::prefix, "/usr/bin/killall", "-HUP", $daemon);
if ($service eq "cups") {
# CUPS needs some time to come up.
printer::services::wait_for_cups();
}
return 1;
}
sub assure_device_is_available_for_cups {
# Checks whether CUPS already "knows" a certain port, it does not
# know it usually when the appropriate kernel module is loaded
# after CUPS was started or when the printer is turned on after
# CUPS was started. CUPS 1.1.12 and newer refuses to set up queues
# on devices which it does not know, it points these queues to
# file:/dev/null instead. Restart CUPS if necessary to assure that
# CUPS knows the device.
my ($device) = @_;
my $sdevice = handle_configs::searchstr($device);
my ($result, $i);
# USB printers get special model-dependent URLs in "lpinfo -v" here
# checking is complicated, so we simply restart CUPS then and ready.
if ($device =~ /usb/) {
$result = printer::services::restart("cups");
return 1;
}
my $maxattempts = 3;
for ($i = 0; $i < $maxattempts; $i++) {
open(my $F, ($::testing ? $::prefix : "chroot $::prefix/ ") .
'/bin/sh -c "export LC_ALL=C; /usr/sbin/lpinfo -v" |') or
die 'Could not run "lpinfo"!';
while (my $line = <$F>) {
if ($line =~ /$sdevice/) { # Found a line containing the device
# name, so CUPS knows it.
close $F;
return 1;
}
}
close $F;
$result = printer::services::restart("cups");
}
return $result;
}
sub spooler_in_security_level {
# Was the current spooler already added to the current security level?
my ($spooler, $level) = @_;
my $sp;
$sp = $spooler eq "lpr" || $spooler eq "lprng" ? "lpd" : $spooler;
my $file = "$::prefix/etc/security/msec/server.$level";
if (-f $file) {
open(my $F, "< $file") or return 0;
while (my $line = <$F>) {
if ($line =~ /^\s*$sp\s*$/) {
close $F;
return 1;
}
}
close $F;
}
return 0;
}
sub add_spooler_to_security_level {
my ($spooler, $level) = @_;
my $sp;
$sp = $spooler eq "lpr" || $spooler eq "lprng" ? "lpd" : $spooler;
my $file = "$::prefix/etc/security/msec/server.$level";
if (-f $file) {
eval { append_to_file($file, "$sp\n") } or return 0;
}
return 1;
}
sub pdq_panic_button {
my $setting = $_[0];
if (-f "$::prefix/usr/sbin/pdqpanicbutton") {
run_program::rooted($::prefix, "/usr/sbin/pdqpanicbutton", "--$setting")
or die "Could not $setting PDQ panic buttons!";
}
}
sub copy_printer_params($$) {
my ($from, $to) = @_;
map { $to->{$_} = $from->{$_} } grep { $_ ne 'configured' } keys %$from;
#- avoid cycles-----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
sub getinfo($) {
my ($prefix) = @_;
my $printer = {};
$::prefix = $prefix;
# Initialize $printer data structure
resetinfo($printer);
return $printer;
}
#------------------------------------------------------------------------------
sub resetinfo($) {
my ($printer) = @_;
$printer->{QUEUE} = "";
$printer->{OLD_QUEUE} = "";
$printer->{OLD_CHOICE} = "";
$printer->{ARGS} = {};
$printer->{DBENTRY} = "";
$printer->{DEFAULT} = "";
$printer->{currentqueue} = {};
# -check which printing system was used previously and load the information
# -about its queues
read_configured_queues($printer);
}
sub read_configured_queues($) {
my ($printer) = @_;
my @QUEUES;
# Get the default spooler choice from the config file
$printer->{SPOOLER} ||= printer::default::get_spooler();
if (!$printer->{SPOOLER}) {
#- Find the first spooler where there are queues
foreach my $spooler (qw(rcups cups pdq lprng lpd)) {
#- Is the spooler's daemon running?
my $service = $spooler;
if ($service eq "lprng") {
$service = "lpd";
}
if (($service ne "pdq") && ($service ne "rcups")) {
next unless services::is_service_running($service);
# daemon is running, spooler found
$printer->{SPOOLER} = $spooler;
}
#- poll queue info
if ($service ne "rcups") {
open(my $F, ($::testing ?
$::prefix : "chroot $::prefix/ ") .
"foomatic-configure -P -q -s $spooler |") or
die "Could not run foomatic-configure";
eval join('', <$F>);
close $F;
}
if ($service eq "pdq") {
#- Have we found queues? PDQ has no damon, so we consider
#- it in use when there are defined printer queues
if ($#QUEUES != -1) {
$printer->{SPOOLER} = $spooler;
last;
}
} elsif ($service eq "rcups") {
#- In daemon-less CUPS mode there are no local queues,
#- we can only recognize it by a server entry in
#- /etc/cups/client.conf
my ($daemonless_cups, $remote_cups_server) =
printer::main::read_client_conf();
if ($daemonless_cups) {
$printer->{SPOOLER} = $spooler;
$printer->{remote_cups_server} = $remote_cups_server;
last;
}
} else {
#- For other spoolers we have already found a running
#- daemon when we have arrived here
last;
}
}
} else {
if ($printer->{SPOOLER} ne "rcups") {
#- Poll the queues of the current default spooler
open(my $F, ($::testing ? $::prefix : "chroot $::prefix/ ") .
"foomatic-configure -P -q -s $printer->{SPOOLER} -r |") or
die "Could not run foomatic-configure";
eval join('', <$F>);
close $F;
} else {
my ($_daemonless_cups, $remote_cups_server) =
printer::main::read_client_conf();
$printer->{remote_cups_server} = $remote_cups_server;
}
}
$printer->{configured} = {};
my $i;
my $N = $#QUEUES + 1;
for ($i = 0; $i < $N; $i++) {
# Set the default printer
$printer->{DEFAULT} = $QUEUES[$i]{queuedata}{queue} if
$QUEUES[$i]{queuedata}{default};
# Advance to the next entry if the current is a remotely defined
# printer
|