#
# 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: Globals.pm 3 2007-10-18 16:20:19Z guillaume $
#

package A2P::Globals ;

use strict ;
use Time::HiRes qw( gettimeofday ) ;
use A2P::Init ;

BEGIN {
    use Exporter ();

    our ( $VERSION, $SERVICE, @ISA, @EXPORT, @EXPORT_OK, @SHARED );

    $VERSION = sprintf "%s", q$Rev: 1162 $ =~ /(\d[0-9.]+)\s+/ ;
    $SERVICE = defined($ENV{'LOCKID'}) ? 1 : 0 ;

    @ISA = qw(Exporter);

    # Export every constants
    @EXPORT = qw(
        %means &QUIT &PING &_INIT &NOMOREFILE $Progname $StdoutFile
        &DONE $MUSTQUIT $LISTENER &TODO $maintid $do_file $A2P_SYS_CONF
        &A2P_RPM_VERSION %STATS &UPSTAT @SHARED &_UPDATE $SYSLOG &TIMESTAT
        &MAXSTAT &MAXMINSTAT @AbortTime $AFPNAME_REGEX &DOWNSTAT
        );

    # List of thread shared and updatable variables to export
# DEV2
    @SHARED = qw(
        $NO_SYSLOG_DEBUG $AFPSPOOL $USLEEP $AFP2PRINT_PATH $ARCH_DEBUG
        $SHMDIR $ERRORSPOOL $DONESPOOL $LOGOPATH $ARCH_SCENARIO $PCL_RESOLUTION
        $MAXTASK $DESTIDFILE $COMPRESSFILES $DONTZIPPDF $PURGEFILES $DO_PING
        $PARALLELE_VALIDATION $DVILJ $ZIPOPTIONS $LOCKID $NODEBUG_MOD_LIST
        $MINFOLDERCOUNT $MAXFOLDERCOUNT $ARCH_REMHOST_TEST $ARCH_REMPORT_TEST
        $ARCH_REMHOST_TLOG $ARCH_REMPORT_TLOG $ARCH_REMHOST_PROD $PNGCOMPRESSION
        $MAIL_BIN $ALERT_MAILS $ERROR_MAILS $LOGFILENAME $SPOOL_PREFIX
        $LOGFILE_VS_SYSLOG $ARCH_ENABLED $USE_PCLCMD $LOGFILE_PURGE $KEEP_AFPJOB
        $COM_BURST $SCAN_SPOOL $MAX_BACKLOG $WAIT_ON_PREFIX $MAXRETRYTIMER
        $CLIENT_TIMEOUT $START_LOGGER $NODEBUG_SUB_LIST $CONV_STATUS_TIMING
        $KEEP_STATS $STATS_FOLDER $MAXFILES_BY_ZIPCMD $SYSLOG_PATH
        $KEEP_JOBSTATUS $DONT_PRINT $FORCE_DESTID $SPOOL_TIMER $GIFTOPCL
        $AGREGATE_PRINT $BACKEND_FACTOR $SERVICE_TMP $COM_LOCKING $MAXJOBS
        $SERVICE_DEBUG $STDOUT_DEBUG $MAX_BUFFER_SIZE $DEBUG_IN_FILE
        $ADDTEX_DEBUG $TEX_PAGEDEF_DEBUG $TEX_OVERLAY_DEBUG $TEX_SEGMENT_DEBUG
        $TEX_SHOW_SEGMENT $ADVANCED_DEBUGGING $ARCH_REMPORT_PROD
        $KEEP_DYNAMIC_JOB_LOG $JOB_DUMP_ON_ERROR $JOIN_ZIP_ON_ERROR
        $CLEAN_OPTIMIZATION $DYNAMIC_USLEEP $MAX_DYNAMIC_USLEEP $MAX_CONV_RATE
        $ADDTEX_DOCINFO $ADDPCL_JOBNAME $ADDPCL_USERNAME $ONLY_DO_PDF
        $MAXCONNECTIONS $USE_TCPIP_SOCKET $USE_TCPIP_PORT $USE_ONLY_LOOPBACK
        $AUTHORIZED_HOST $ESERVICE_ENABLED $ESERVICE_CONF $CONVERT_CONTENT_FILE
        $CLOSE_CONNECTIONS $ENABLE_DTD_VALIDATION $DOCSFILE $STATUS_DB_MAXAGE
        $DOCUMENTS_CORRECTION_ENABLED $DBI_DSN $DBI_USER $DBI_PASSWD
        $A2PDB_TABLE_PREFIX $STATSFILE_MAXAGE $STATUS_MAXAGE $DO_CONVERT
        $FROM_CONVERT $TO_CONVERT $STATS_COMMIT_SKIP $MAX_CACHED_DB $MAX_LINES
        $RECONNECT_TIMER $STATUS_CACHE_MAXAGE $MAX_CACHED_STATUS $JOBS_COUNTDOWN
        $ENABLE_SPLITTER $BACKEND_RETRY $BACKEND_RETRYTIMEOUT $AUTO_SPLIT_MAX
        $DO_DB_OPTIMIZATION
        );

    # Add here to @SHARED some parameters only used in init script not to
    # initialize
    push @SHARED , qw(
        $AFP2PRINT_USER $PERL $A2P_SYS_CONF $NICE $SERVICE_PROG $PRINTLIB_PATH
        $TEXSPOOL
        );

    # Add shared to export list
    push @EXPORT , @SHARED ;

    @EXPORT_OK = qw( &UpdateSharedEnv &get_default_lockid );
}
our @SHARED ;
our $SYSLOG ;
our $SERVICE;

# Defaults only used in bash scripts
our $AFP2PRINT_USER = 'afp2print' ;
our $PERL           = '/usr/bin/perl' ;
our $NICE           = 'nice --5' ;
our $SERVICE_PROG   = '$AFP2PRINT_PATH/a2p.pl' ;
our $PRINTLIB_PATH  = '$AFP2PRINT_PATH/printlib' ;
our $TEXSPOOL       = '' ;

################################################################################
##            Threads shared variables                                        ##
##            Each one would be re-initialized by Init function as needed     ##
################################################################################
# DEV: When adding shared variable, dev lines must be added at:
#   DEV1: its 'our' definition with eventually its default value
#   DEV2: and also, it must be inserted in SHARED list (see BEGIN block)

# DEV1

# This is a constant to be update during rpm packaging
sub A2P_RPM_VERSION () { '1.024' }

# NO_LOGFILE is to be greater than 0 to output log to a file and to syslog
# Default to 0 to not have logfile
our $LOGFILE_VS_SYSLOG    = 0 ;
our $LOGFILE_PURGE        = 0 ;
our $LOGFILENAME          = "/var/log/a2p.debug" ;

# NO_SYSLOG_DEBUG is to be greater than 0 to not send any Debug to syslog
# Default to 0 to always debug service start (not critical)
our $NO_SYSLOG_DEBUG      = 0 ;

# SERVICE_DEBUG can be disabled to avoid debugging when service is shutting down
our $SERVICE_DEBUG        = 1 ;

# SYSLOG_PATH is the standard socket where to send syslog message to system
our $SYSLOG_PATH          = "/dev/log" ; # Unix dfault
our $STDOUT_DEBUG         = 0 ; # Send debug to standard console output if set
our $DEBUG_IN_FILE        = 0 ; # To avoid sending debugging to syslog
# ADVANCED_DEBUGGING should not be used in configuration but can be dynamically
# be set by sending signal 12 (USR2) to a thread, see details in A2P::Signal
our $ADVANCED_DEBUGGING   = 0 ; # To activate some online debugging

# KEEP_DYNAMIC_JOB_LOG keeps job info that will be only available in the mail
# sent to the ERRORS_MAIL list when an AlertError rises.
our $KEEP_DYNAMIC_JOB_LOG = 1 ;
# Set it to 0 to desactivate
# Set it a greater value than 1 to also keep debugging messages

our $JOB_DUMP_ON_ERROR    = 1 ; # By default make a job dump in the error mail
our $JOIN_ZIP_ON_ERROR    = 1 ; # By default add zip when exist to dumped job

# By default, we could keep some few last log messages,
# used for job debugging on error and mailed report
our $MAX_BACKLOG          = 10 ;

# TeX info insertion enabled mostly for PDF Title and Creator
our $ADDTEX_DOCINFO       = 1 ;

# PCL5 info insertion can be forced for all produced PCL otherwise it should be
# enabled by DESTID in desti configuration file
our $ADDPCL_JOBNAME       = 0 ;
our $ADDPCL_USERNAME      = 0 ;

# TeX debugging for TeX validation only
our $ADDTEX_DEBUG         = 0 ; # Set alone, it outputs font names in TeX output
# ADDTEX_DEBUG must be true to use these following
our $TEX_PAGEDEF_DEBUG    = 0 ; # Show PAGEDEF frame and page off-set used
our $TEX_OVERLAY_DEBUG    = 0 ; # Show OVERLAY frames and page off-set used
our $TEX_SEGMENT_DEBUG    = 0 ; # Show SEGMENT frames and page off-set used
our $TEX_SHOW_SEGMENT     = 1 ; # Remove SEGMENT

# Do we should start a logger thread
our $START_LOGGER         = 1 ;

# KEEP_STATS actives conversion statistics if set to 1
our $KEEP_STATS           = 1 ;
our $STATS_FOLDER         = "/apps/afp2print/stats" ;

# KEEP_JOBSTATUS can be set to 0 to disable keeping job status
our $KEEP_JOBSTATUS       = 1 ;

# This is the max number of com to manage in one loop
our $COM_BURST            = 5 ;
# This set the use of locking feature during communication between processes
# It can be imply a performance issue but also a stability issue if disabled
our $COM_LOCKING          = 0 ; # Not useful with new comm scheme
our $MAX_BUFFER_SIZE      = 65536 ;

# DEBUG_MOD_LIST is to be populated with module or file name to not debug
# DEBUG_SUB_LIST is to be populated with subfunction name to not debug
# This comportement can be inversed by inserting the '!' char at beginning
our $NODEBUG_MOD_LIST     = "" ;
our $NODEBUG_SUB_LIST     = "" ;

# DO_PINGPONG is to be greater than 0 to ping threads periodictly
our $DO_PING              = 1 ;

# AFPSPOOL is the spool directory where AFPDS file will be expected
our $AFPSPOOL             = '/apps/afp2print/afpspool' ;

# SCAN_SPOOL should be disabled for a validation service which don't need
# to scan the spool. It will also disable SpoolManager launch.
our $SCAN_SPOOL           = 1 ;
# SPOOL_TIMER is the number of seconds between 2 checks in spool when idle
our $SPOOL_TIMER          = 5 ;
# SPOOL_PREFIX is to tune de prefix selection in the spool (NOT case sensitive)
our $SPOOL_PREFIX         = "TRANS ARCHI" ;
# WAIT_ON_PREFIX could be set to activate the wait on prefix locking
our $WAIT_ON_PREFIX       = 0 ;

# USLEEP is the time in microsecond to sleep in thread loops
our $USLEEP               = 50000 ;
# DYNAMIC_USLEEP set USLEEP to dynamic mode
our $DYNAMIC_USLEEP       = 1 ;
our $MAX_DYNAMIC_USLEEP   = 1_000_000 ; # Max USLEEP in dynamic mode (in ms)

# CLEAN_OPTIMIZATION can be disable to force new job creation only after
# previous jobs have been cleaned
our $CLEAN_OPTIMIZATION   = 1 ;

# This is the default project path installation
our $AFP2PRINT_PATH       = '/apps/afp2print' ;

# SHMDIR default to "/dev/shm" to optimize throughput as be done in memory
our $SHMDIR               = '/dev/shm' ;

# SERVICE_TMP is the path where to use temporary files
our $SERVICE_TMP          = '/tmp/.a2p' ;

# ERRORSPOOL is the spool directory where failed conversion files will be moved
our $ERRORSPOOL           = '/apps/afp2print/spool/error' ;

# DONESPOOL is the spool directory where done conversion files will be moved
our $DONESPOOL            = '/apps/afp2print/spool/done' ;

# LOGOPATH must point to the segment library
our $LOGOPATH             = '/apps/afp2print/printlib/seglib' ;

# MAXTASK is set to the number of concurrent conversion to process
our $MAXTASK              = 1 ;

# MAXJOBS is set to the maximum AFP jobs we can process at a time
our $MAXJOBS              = 1 ;

# MAXCONNECTIONS is the maximum concurrent connections that we be accepted by
# any Listener
our $MAXCONNECTIONS       = 10 ;

# By default Listener won't listen on TCP/IP socket
our $USE_TCPIP_SOCKET     = 0 ;
our $USE_TCPIP_PORT       = 6400 ;
# By default TCP/IP server will listen only on the localhost (127.0.0.1)
our $USE_ONLY_LOOPBACK    = 1 ;
# Even if listening over internet we only accept connection from just localhost
# by default. Set it to "0.0.0.0" or "any" to accept from any host
our $AUTHORIZED_HOST      = "127.0.0.1" ;

# MAX_CONV_RATE is used to limit the conversion rate on big job. It is the
# maximum number of conversion to do during one second, and it is really used
# only with AFP job with more than this value of sub jobs
# Default MAX_CONV_RATE=20 means AFP jobs with more than 20 sub-jobs will have
# their TeX conversion limited to not exceed 20 sub-jobs created for each second
# This should be used to avoid processes communication saturation
# Remark: - if set to 0, conversion will slow down to reach one conversion by
#           USLEEP interval
#         - it is disabled with negative value
our $MAX_CONV_RATE        = -1 ;

# BACKEND_FACTOR must be greater than 0 and define the numbre of processes
# (multiplied by MAXTASK) that will be used to call command on the system and
# this defined also the number of ARchiver processes
# Exemple:
#  - If MAXTASK = 1 and BACKEND_FACTOR = 3 (this is the default)
#        3 BackEnd processes will be managed
#        3 Archiver will be also managed if ARCH_ENABLED is set
#  - If MAXTASK = 2 and BACKEND_FACTOR = 5
#        10 BackEnd processes will be managed
#        10 Archiver will be also managed if ARCH_ENABLED is set
our $BACKEND_FACTOR       = 3 ;
# Maximum number of retries when command fails
our $BACKEND_RETRY        = 10 ;
# Maximum number of seconds when command fails to really set the command failed
our $BACKEND_RETRYTIMEOUT = 30 ;

# DESTIDFILE is the configuration file for print configuration
our $DESTIDFILE           = '/etc/afp2print/destid.conf' ;

# DOCSFILE is the configuration file for print correction by document
our $DOCSFILE             = '/etc/afp2print/documents.conf' ;

# DOCUMENTS_CORRECTION_ENABLED can be set to 1 to enable automatic by Documents
# scaling and off-set correction. A flag by DestId can be used to enable/disable
# the correction for a specific DestId.
# When set greater than 1, the flag by DestId is ignored and correction is
# forced and only if correction exists for a Document
our $DOCUMENTS_CORRECTION_ENABLED = 0 ;

# DONTZIPPDF must be set to '1' to keep PDF files not compressed in zip file
# Only used if COMPRESSFILES is set to 1
our $DONTZIPPDF           = 0 ;

# DONT_PRINT is set to 1 to skip lpr command
# FORCE_DESTID can be used as in validation, exemple set it to "LINDEC" in conf
our $DONT_PRINT           = 0 ;
our $FORCE_DESTID         = "" ;

# AGREGATE_PRINT is set to 0 to force print immediatly and not agregate PCL5 to
# only do one PCL5 by DESTID
our $AGREGATE_PRINT       = 1 ;

# PARALLELE_VALIDATION: Set it to:
# - 1 to duplicate AFP incoming flux to validation mode and destinations
# - 2 to only use validation mode and destination printers
our $PARALLELE_VALIDATION = 0 ;

# the dvilj variant to run taken from dvihp script
our $DVILJ                = 'dvipcl5' ;

# the zip option environment for optimizing compression
our $ZIPOPTIONS           = 'DjJqXm' ;
our $MAXFILES_BY_ZIPCMD   = 1 ;
# COMPRESSFILES must be set to compression level desired for backup files in
# DONESPOOL and ERRORSPOOL, value can be 0 to 9 (see 'zip' command man)
our $COMPRESSFILES        = 0 ;

# PURGEFILES is set to 1 when we don't need to keep any file after processing
our $PURGEFILES           = 0 ;

# MINFOLDERCOUNT is the minimum spool file number under which we will repopulate
# the spool file cache
our $MINFOLDERCOUNT       = 10 ;
# MAXFOLDERCOUNT is the maximum spool files to keep in our known file cache
our $MAXFOLDERCOUNT       = 100 ;
# MAXRETRYTIMER is the time in ms to keep a cached available file
# in memory before retrying to lock it
our $MAXRETRYTIMER        = 500 ;

# CONV_STATUS_TIMING is the time in second after which a status conversion must
# be provided to inform clients
our $CONV_STATUS_TIMING   = 30 ;

# KEEP_AFPJOB is set to 1 when PARALLELE_VALIDATION is 0 if we want to keep AFP
# version of each job. In that case, an AFPDS file is splitted in as many job
# that it contains. This is the default if PARALLELE_VALIDATION is set to 1 or 2
our $KEEP_AFPJOB          = 1 ;

# Mailing variables for alerts and errors
our $MAIL_BIN             = "/usr/lib/sendmail" ;
# ALERT_MAILS will receive a short mail with only job in ABTERM in the subject
our $ALERT_MAILS          = "" ;
# ERROR_MAILS will receive a mail with knowns errors in the body
our $ERROR_MAILS          = "" ;

# CLient time-out is the max time we can expect for a response from listener
our $CLIENT_TIMEOUT       = 300 ;

# Some variable used for archivage processing
our $ARCH_REMHOST_TEST    = '127.0.0.1' ;
our $ARCH_REMPORT_TEST    = 2222 ;
our $ARCH_REMHOST_TLOG    = '127.0.0.1' ;
our $ARCH_REMPORT_TLOG    = 2222 ;
our $ARCH_REMHOST_PROD    = '127.0.0.1' ;
our $ARCH_REMPORT_PROD    = 2222 ;
our $ARCH_DEBUG           = 0 ;
# ARCH_ENABLED: Can be set to from 0 to 99
#               to get ARCH_ENABLED * BACKEND_FACTOR Archiver processes
# ARCH_ENABLED: Set to greater than 99 to activate an archivage simulation:
#    - if = 100 than archivage call returns true each time
#    - else greater, it returns randomly false when random(value) > 99
#      (so greater value produces more false case)
our $ARCH_ENABLED         = 2 ;
# ARCH_SCENARIO: 1 = separate binary file, 3 = xml embedded
our $ARCH_SCENARIO        = 1 ;

# ESERVICE designs Electronic Service it can only be activated with AFP flux
# telling about RC 200,201,202 and replaces the ARCH step when enabled
our $ESERVICE_ENABLED     = 0 ;
# ESERVICE_ENABLED: Can be set to from 0 to 99
#                   to get ESERVICE_ENABLED * BACKEND_FACTOR EService processes
# ESERVICE_ENABLED: Set to greater than 99 to activate an e-service simulation:
#    - if = 100 than e-service call returns true each time
#    - else greater, it returns randomly false when random(value) > 99
#      (so greater value produces more false case)
our $ESERVICE_CONF        = '/etc/afp2print/e-service.conf' ;

# By default client request sockets are closed when processed
our $CLOSE_CONNECTIONS    = 1 ;

# CONVERT_CONTENT_FILE must be true to convert RC201-RC202 content from EBCDIC
our $CONVERT_CONTENT_FILE = 1 ;

# DO_CONVERT is set or not to activate AFP conversion with from_to perl API
our $DO_CONVERT           = 1 ;
# The following defines which encoding to use with from_to perl API
our $FROM_CONVERT         = 'cp1047' ;
our $TO_CONVERT           = 'latin1' ;

# ENABLE_DTD_VALIDATION can be set to 0 or 1 to disable
# or activate DTD validation on XML requests
our $ENABLE_DTD_VALIDATION= 0 ;

# ONLY_DO_PDF can be set to avoid the steps 4 to 10 only used with printing and
# online archivage. This is used essentialy to only handle PDF generation and
# get better performance in this case.
our $ONLY_DO_PDF          = 0 ;

# DBI variables with default connection on local mysql serveur and db a2p
our $DBI_DSN              = 'DBI:mysql:database=a2p;host=localhost;port=3306' ;
our $DBI_USER             = '' ; # Set to Progname (a2p-stat,...) if not set
our $DBI_PASSWD           = '' ; # Connection should failed if not configured

# Time to force reconnection to DB for a2p-stat and a2p-status services
our $RECONNECT_TIMER      = 3600 ;

# A2PDB_PREFIX can be set if you need to install stats or/and status tables in
# a database with conflicting table names
our $A2PDB_TABLE_PREFIX   = '' ;

# Set maximum amount of values that can be cached in memory during DB usage
our $MAX_CACHED_DB        = 10000 ;
# Set maximum lines to read by a2p-stat in each statistics file at each loop
our $MAX_LINES            = 100 ;

# By default don't do DBA job by ourself
our $DO_DB_OPTIMIZATION   = 0 ;

# STATSFILE_MAXAGE is only used by statistics service to delete statistics file
# for which the age in DAYs is greater than this value
our $STATSFILE_MAXAGE     = 70 ;
# Default value keeps at least 2 months of statistics files

# STATUS_MAXAGE is used as peremption timer for status information in DBM files
# By default it should be disabled, and only activated in a2p-status service
# Only DONE status can be deleted automatically as it is redondant
# with statistics informations. Unit is milli-second.
our $STATUS_MAXAGE        = 3600000 ; # Clean after one hour
# But we are checking Progname later below and set it to 1h on *-status name
our $STATUS_CACHE_MAXAGE  = 60000 ; # 1 minute
# Default value keeps 1 hour of status
# MAX_CACHED_STATUS set the max number of status we can keep in cache. If this
# maximum is reached, the older DONE status will be released
our $MAX_CACHED_STATUS    = 1000 ;
# STATUS_DB_MAXAGE represents the max time to keep a status in jobs_status table
our $STATUS_DB_MAXAGE     = 24 ; # Time in hours

# A boolean to enable/disable the AFPDS splitting code
our $ENABLE_SPLITTER      = 1 ;
# A number of jobs on which use an auto-split
our $AUTO_SPLIT_MAX       = 100 ;

# A value to force a2p to quit when this number of jobs has been processed
our $JOBS_COUNTDOWN       = 0 ;

# STATS_COMMIT_SKIP is only used by statistics to skip some commit, when loading
# statistics files to get better performance
our $STATS_COMMIT_SKIP    = 100 ;
# But commit will be forced if none has been done since 10 seconds

# GIFTOPCL is the command chain to use for GIF to PCL conversion
# The first %d will be replaced by the width of the image to scale to
# The second %d will be replaced by the resolution to be used for PCL format
our $GIFTOPCL             = 'giftopnm | pnmscalefixed -width=%d | ppmtopgm ' .
    '| pgmtopbm -d8 | pbmtolj -resolution %d -packbits -float -noreset' ;
# Dont't use delta compression with pbmtolj as the result is wrong with texts

# PNGCOMPRESSION could be from 0 for no compression to 9 for maximum compression
# of included PNG resources in PDF generated files
our $PNGCOMPRESSION       = 9 ;

# PCL_RESOLUTION is the default resolution to use for PCL resource conversion
our $PCL_RESOLUTION       = 600 ;

# LOCKID is just an identifier to be able to run the service on the same spool
our $LOCKID               = &get_default_lockid() ;

sub get_default_lockid {
    my $lockid = "a2p-service" ;
    if ( -e '/proc/sys/kernel/hostname' and ! $SERVICE ) {
        open *HOSTNAME , '<', "/proc/sys/kernel/hostname"
            or die "Can't read hostname from kernel: $!";
        $lockid = <HOSTNAME> ;
        close HOSTNAME ;
    } else {
        $lockid = $SERVICE ? $ENV{'LOCKID'} : qx/hostname -s/ ;
    }
    chomp $lockid ;
    $lockid = $1 if ( $lockid =~ /^([^.]+)/ );
    $lockid = uc( $lockid );
    return $lockid ;
}

our $MUSTQUIT             = 0 ; # Shared flagged to stop immediatly

# Should we use \special command specific to dvipcl5 instead of
# Integrating files containing PCL5 commands
our $USE_PCLCMD           = 1 ;

################################################################################
##                      Optimized shared constants                            ##
################################################################################
# These common constants are arbitrary values
sub QUIT       () { 0xEFEF }; # Constant passed in request queues
sub PING       () { 0x0FF0 }; # Constant passed to ping a thread
sub _INIT      () { 0xF000 }; # Constant passed to update thread env
sub _UPDATE    () { 0xF001 }; # Constant passed to directly update shared var
sub TODO       () { 0x8888 }; # Constant passed to ask job to a thread
sub DONE       () { 0xFFF0 }; # Constant to say job is done
sub NOMOREFILE () {   99   }; # Constant to say when no file are found in spool

our %means = (
    QUIT        ,   "QUIT",
    PING        ,   "PING",
    _INIT       ,   "INIT",
    _UPDATE     ,   "Direct UPDATE",
    TODO        ,   "TODO",
    DONE        ,   "DONE",
    NOMOREFILE  ,   "NO MORE FILE"
    );

# Regex used in SpoolManager and Converter to compute AFPNAME
our $AFPNAME_REGEX =
    qr/(?i:LINUX\.|TEMP\.)*([-0-9a-zA-Z_.]+)(?i:\.afp|\.afpds)?$/ ;

################################################################################
##                            System shared values                            ##
################################################################################
# Prepare process short name, extracting basename without extension
our $Progname ;
if (!defined($Progname)) {
    ( $Progname ) = $ARGV[0] =~ m|.*/([^/.]+)(\.[^/.]+)?$|
        if (defined($ARGV[0]));
    ( $Progname ) = $0 =~ m|.*/([^/.]+)(\.[^/.]+)?$|
        unless (defined($Progname));
    $Progname = "a2p" unless (defined($Progname));
}

die "Can't starting process without Progname defined"
    unless (defined($Progname));

our $maintid = 0 ;
our $do_file = 0 ;
our %STATS  = () ;
our @AbortTime = () ;

sub DOWNSTAT {
    my $what = shift ;
    my $down = @_ ? shift : 1 ;
    unless (defined($STATS{$what})) { $STATS{$what} = 0 }
    $STATS{$what} -= $down ;
}

sub UPSTAT {
    my $what = shift ;
    my $plus = @_ ? shift : 1 ;
    unless (defined($STATS{$what})) { $STATS{$what} = 0 }
    $STATS{$what} += $plus ;
}

my %chrono = () ;
sub TIMESTAT {
    my @timing = &gettimeofday() ;
    my $what = 'TIMING-' . $_[0] ;
    if (defined($chrono{$what}) and @{$chrono{$what}}) {
        &MAXSTAT($what,( $timing[0] - ${$chrono{$what}}[0] ) * 1_000_000
            + ( $timing[1] - ${$chrono{$what}}[1] ));
        $chrono{$what} = [] ;

    } else {
        $chrono{$what} = [ @timing ] ;
    }
}

sub MAXSTAT {
    my $max = $_[0] . '-MAX' ;
    $STATS{(!defined($STATS{$max}) or $_[1] > $STATS{$max}) ? $max : $_[0]}
        = $_[1] ;
}

sub MAXMINSTAT {
    my $min = $_[0] . '-MIN' ;
    $STATS{(!defined($STATS{$min}) or ! $STATS{$min}
        or ( $_[1] and $_[1] < $STATS{$min})) ? $min : $_[0]} = $_[1]
        if (&MAXSTAT(@_) == $_[1]);
}

# Update LOGFILENAME default
$LOGFILENAME = $SHMDIR . '/' . $Progname . '.log' unless $LOGFILENAME ;

our $LISTENER = $SERVICE_TMP . '/' . $Progname . '-listener' ;

# This authorizes to get thread compilation errors when debugging
our $StdoutFile = "/var/run/$Progname.debug" ;
# But it should be really set to /dev/null for a service
$StdoutFile = "/dev/null" if ( ! -e $StdoutFile );

# A2P_SYS_CONF has its defaults should come from a2p.sh script
our $A2P_SYS_CONF = defined($ENV{'A2P_SYS_CONF'}) ?
    $ENV{'A2P_SYS_CONF'} : "/etc/afp2print/afpds2tex.conf" ;

if ($SERVICE) {
    # Initialize Init module
    &Init( "$A2P_SYS_CONF" , "/etc/afp2print/" . $Progname . ".conf" );

    my @FIRSTENV = &Init( map { $_ => eval $_ } @SHARED );

    # Now we can evaluate our %ENV
    map { eval $_ } @FIRSTENV ;

    my $debugenv = 0 ; # Set to one to got ENV debugging while updating conf
    sub UpdateSharedEnv {
        # Compute shared variable
        map {
            my ( $key ) = $_ =~ /^[\$](.*)$/ ;
            if ($key and defined($ENV{$key})) {
                my $quote = $ENV{$key} =~ /^\d+$/ ? "\"\"" : "\"'\"" ;
                eval "$_ = \$ENV{$key}" ;
            }
        } @SHARED ;

        # Update some other ENV
        $ENV{TEXMFOUTPUT} = $SHMDIR if ( defined($SHMDIR) and -d $SHMDIR );

        # Debug env if needed
        if ($debugenv) {
            my %HASH = %ENV ;
            $debugenv ++ while ( -e "/tmp/$Progname-ENV-$debugenv" );
            open( *LOG, '>', "/tmp/$Progname-ENV-$debugenv" )
                or return ;
            map {
                my ( $key ) = $_ =~ /^[\$](.*)$/ ;
                print LOG scalar(localtime), ", $0: $_ => ",
                    defined($ENV{$key}) ? "ENV='$ENV{$key}'" : "ENV=undef",
                    " vs '", eval $_ , "'\n" ;
                delete $HASH{$key};
            } @SHARED ;
            map {
                print LOG scalar(localtime), ", $0: ENV $_ = $ENV{$_}\n"
                } keys( %HASH );
            map {
                print LOG scalar(localtime), ", $0: FIRSTENV => $_ \n"
                } @FIRSTENV ;
            close(LOG);
        }
    }

    &UpdateSharedEnv ;
}

1;
