# # Copyright (c) 2004-2007 - Consultas, PKG.fr # # This file is part of A2P. # # A2P is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # A2P is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with A2P; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # $Id: Infos.pm 3 2007-10-18 16:20:19Z guillaume $ # # Class to report any usefull information # package A2P::Infos ; use strict; use A2P::Globals ; use A2P::Globals qw( get_default_lockid ); use A2P::Syslog ; use A2P::Init ; use A2P::Init qw( ResetInit ); BEGIN { our $VERSION = sprintf "%s", q$Rev: 1185 $ =~ /(\d[0-9.]+)\s+/ ; } our $VERSION ; sub new { my $class = shift ; my $self = { LOCKID_LIST => [] } ; bless $self , $class ; &Debug("new ".__PACKAGE__." object v$VERSION created"); return $self ; } my $default_lockid = &get_default_lockid() ; my $config ; sub _get_local_servicename { my $lockid = shift ; my $service = shift ; my @confs ; my @found = () ; # If one more argument, it's directly the local service name if (defined($service)) { @confs = ( '/etc/afp2print/' . $service . '.conf' ) ; } else { # Get all local configuration files @confs = glob( '/etc/afp2print/*.conf' ) ; } foreach my $conf (@confs) { my ( $name ) = $conf =~ m|^/etc/afp2print/([^/]+)\.conf$| ; # Skip other configurations next if ( $name =~ /^destid|documents|afpds2tex|stat|e-service/ ); &Debug("Checking '$conf' configuration") if ($ADVANCED_DEBUGGING); # Initialize Init module &ResetInit ; &Init( "$A2P_SYS_CONF" , $conf ); # Requested values must be specified here my @env = &Init( '$TEXSPOOL' => '', '$AFPSPOOL' => '', '$ERRORSPOOL' => '', '$DONESPOOL' => '', '$LOCKID' => $default_lockid, '$SCAN_SPOOL' => 0, '$KEEP_JOBSTATUS' => 0 ); my %env = () ; foreach my $env ( @env ) { $env =~ s|ENV\{(\w+)\}|env{$1}| ; eval $env ; } next unless ( $env{LOCKID} eq $lockid and $env{SCAN_SPOOL} and $env{KEEP_JOBSTATUS}); &Debug("Service '$name' uses '$env{LOCKID}' LOCKID") if ($ADVANCED_DEBUGGING); # Keep config for other API $config = \%env ; push @found, $name ; } return @found ; } sub _recursive_serviceid_table_check { my $ref = shift ; my $depth = shift || 0 ; return &Error("Not a hash ref at depth $depth in services id list") unless (ref($ref) =~ /^HASH/); if ($depth<2) { map { unless(&_recursive_serviceid_table_check($ref->{$_},$depth+1)) { delete $ref->{$_} ; &Error("Key '$_' deleted at depth $depth in services id list"); } } keys(%{$ref}) ; } elsif (!exists($ref->{serviceid}) or !defined($ref->{serviceid}) or !$ref->{serviceid}) { return &Error("'serviceid' key not found"); } return scalar(keys(%{$ref})) ; } sub get_lockid_list { return @{$_[0]->{LOCKID_LIST}} ; } sub get_serviceid_of { my $self = shift ; my $object = shift ; my $lockids = $self->{LOCKID} ; $lockids = $self->{LOCKID} = {} unless (defined($lockids)); # Services table is transmitted by A2P::DB as hash to initialize our list if (ref($object) =~ /^HASH/) { if (&_recursive_serviceid_table_check($object)) { my @services = () ; $self->{LOCKID_ERROR} = 0 ; # Scan hash to get any (lockid,serviceid) pair foreach my $name (keys(%{$object})) { foreach my $lockid (keys(%{$object->{$name}})) { my $serviceid = exists($object->{$name}->{$lockid}->{serviceid}) ? $object->{$name}->{$lockid}->{serviceid} : &Error("No serviceid found for '$name-$lockid'") ; #&Debug("Keeping serviceid $serviceid for '$name-$lockid'"); push @services, [ $lockid , $serviceid , $name ] ; } } # Scan each pair to get conflicting ones while (@services) { my ( $lockid, $serviceid, $name ) = @{ shift @services } ; my @match = () ; if (@match = grep { $_->[0] eq $lockid } @services) { &Debug("Found services with same LOCKID for this server"); # 0. Still strip conflicting from list @services = grep { $_->[0] ne $lockid } @services ; # 1. Search available LOCKID in local configurations my @localname = &_get_local_servicename($lockid); if (!@localname) { &Debug("No local service with $lockid LOCKID found, skipping it"); next ; } elsif (@localname == 1 and $localname[0] eq $name) { # This lockid is in fact the only one used today, so # just remove the others &Debug("Found '$lockid' is managed by service '$name'"); } elsif (@localname == 1) { # Only local service really use this lockid but it should # be in @match others list my @realone = grep { $_->[2] eq $localname[0] } @match ; &Debug("Not installed locally"),next unless (@realone); &Debug("Found '$lockid' is managed by service '$localname[0]'"); &Warn("Found many local service '$name-$lockid', please update your confs") if (@realone>1); ( $lockid, $serviceid, $name ) = @{$realone[0]} ; } else { # Found many local running service with the same LOCKID, we need to # say something is bad in configurations &Warn("Bad server configuration found: ". "many service seems to have the same LOCKID", "So I will associating serviceid $serviceid to only service $name", "You should check configuration files, and set different LOCKID for each one", map { "'$_' service configuration is to check"} @localname ); } } if ( ! defined($lockids->{$lockid}) or $lockids->{$lockid} != $serviceid ) { &Debug("Setting serviceid to $serviceid for lockid $lockid as service $name"); $lockids->{$lockid} = $serviceid ; } } # Update lockid list $self->{LOCKID_LIST} = [ keys(%{$lockids}) ] ; # And return ourself return $self ; } else { return &Error("No serviceid table found in '$object'"); } } return (defined($lockids->{$object}) and $lockids->{$object}) ? $lockids->{$object} : 0 ; } sub get_servicename_of { my $self = shift ; my @name = &_get_local_servicename(@_) ; my $name = shift @name ; return '' unless ( defined($name) and $name ); #&Debug("Servicename of '@_' is '$name'"); return $name ; } sub get_afpspool_of { my $self = shift ; my $lockid = shift ; my $service = shift || 'afpds2tex' ; my @name = &_get_local_servicename($lockid,$service) ; my $name = shift @name ; return &Error("No conf found for $service service (Got '$name')") unless ( $name eq $service ); #&Debug("Servicename of '@_' is '$name'"); return exists($config->{'AFPSPOOL'}) ? $config->{'AFPSPOOL'} : &Error("AFPSPOOL not found for $service service") ; } sub get_spools_of { my $self = shift ; my $lockid = shift ; my $service = shift || 'afpds2tex' ; my @name = &_get_local_servicename($lockid,$service) ; my $name = shift @name ; return &Error("No conf found for $service service (Got '$name')") unless ( $name eq $service ); #&Debug("Servicename of '@_' is '$name'"); return map { exists($config->{$_}) ? $config->{$_} : '' } qw( DONESPOOL ERRORSPOOL ) ; } &Debug("Module " . __PACKAGE__ . " v$VERSION loaded"); 1;