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

package A2P::Signal;

use strict ;
use integer ;
use Carp qw(longmess);
use sigtrap qw(any normal-signals error-signals old-interface-signals IO URG CLD CHLD);
use A2P::Globals ;
use A2P::Syslog ;

BEGIN {
    use Exporter ();

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

    $VERSION = sprintf "%s", q$Rev: 1029 $ =~ /(\d[0-9.]+)\s+/ ;

    @ISA = qw(Exporter);
    @EXPORT    = qw(  $do_init   $do_check  $do_quit  $do_ping  $do_test
        $Childquit    @SigDebug  @SigInfo   @SigWarn  @PIPE     );
    @EXPORT_OK = qw(&LogSigMessage);
}
our $VERSION ;

#############################################################################
##          Signal handling vars                                           ##
#############################################################################
our @SigDebug  = ();
our @SigInfo   = ();
our @SigWarn   = ();

# Socket list to be checked when receiving a SIGPIPE
our @PIPE ;

# Some used flags
our $do_init   = 1 ;
our $do_check  = 1 ;
our $do_quit   = 0 ;
our $do_ping   = 0 ;
our $do_test   = 0 ;
our $Childquit = 0 ;

#############################################################################
##          Signal handling code                                           ##
#############################################################################
sub SigABRT {
    $do_quit += 5 ;
    push @SigWarn , "SIGABRT: Notified to abort ($do_quit)";
    $MUSTQUIT ++ ;
    exit(1) if ( $do_quit > 9 );
    $NO_SYSLOG_DEBUG = 0 if $SERVICE_DEBUG ;
}

sub SigQUIT {
    push @SigDebug , "Notified to quit by 'SIG$_[0]' signal";
    exit(1) if ( ++ $do_quit > 3 );
}

sub SigHUP {
    push @SigDebug , "SIGHUP received";
    $do_init ++ ;
    my $touch_file = $SERVICE_TMP . '/init_' . $Progname ;
    if ( -d $SERVICE_TMP and -e $touch_file ) {
        my $now = time ;
        utime $now, $now, $touch_file ;

    } else {
        push @SigWarn  , "Can't touch file '$touch_file' on SIGHUP" ;
    }
}

sub SigALRM {
    $do_check ++ if $DO_PING ;
    push @SigDebug , "SIGALRM received";
}

sub SigDIE {
    my $info = $_[0] || "" ;
    my $sub ;
    chomp $info ;

    # Forget DIE signal when loading Storable.pm and Log/Agent.pm not present
    return if ( $info =~ /Log\/Agent.pm/ );

    my ($package, $filename, $line) = caller();

    # Forget Encoding integration signal...
    return if ( $filename =~ /Encode.pm/ );

    # As a thread should has shutdown, we should check our services
    ++ $do_check ;

    push @SigWarn  , "Got '__DIE__' signal", &longmess(@_) ;
}

sub SigPIPE {
    my ($package, $filename, $line) = caller();
    push @SigDebug , "SIG@_ received at L. $line in $filename: $! $?" ;
    unless ( grep { defined($_) } @PIPE ) {
        push @SigWarn  , "Got '$_[0]' signal" ;
        $MUSTQUIT ++ ;
    }
}

sub SigINT {
    # Just print info in log about where we were called
    &Info("debug: SIG" . &longmess(@_));
}

sub SigWARN {
    push @SigWarn  , "Got '__WARN__' signal", &longmess(@_) ;
}

sub SigUSR1 {
    $do_test ++ ;
}

my $templogger = 0 ;
my $temp_NO_SYSLOG_DEBUG = $NO_SYSLOG_DEBUG ;
sub SigUSR2 {
    push @SigInfo  , "Got 'USR2' signal", &longmess(@_) ;
    $templogger = $loggertid if $loggertid ;
    $loggertid = $loggertid ? 0 : $templogger ;
    # Switch advanced debugging mode
    if ( $ADVANCED_DEBUGGING = $ADVANCED_DEBUGGING ? 0 : 1 ) {
        $temp_NO_SYSLOG_DEBUG = $NO_SYSLOG_DEBUG ;
        $NO_SYSLOG_DEBUG = 0 ;
    } else {
        $NO_SYSLOG_DEBUG = $temp_NO_SYSLOG_DEBUG ;
    }
    &debugdev("ADVANCED_DEBUGGING=$ADVANCED_DEBUGGING NO_SYSLOG_DEBUG=$NO_SYSLOG_DEBUG");
}

map {
    eval q|$SIG{'| . $_ . q|'} = \&Sig| . $_
} qw( PIPE ABRT QUIT HUP ALRM USR1 USR2 );

$SIG{'INT'}      = \&SigINT  ;
$SIG{'SEGV'}     = \&SigPIPE ;
$SIG{'TERM'}     = \&SigQUIT ;
$SIG{'__DIE__'}  = \&SigDIE  ;
$SIG{'__WARN__'} = \&SigWARN ;
$SIG{'CHLD'}     = sub { $Childquit ++ } ;

sub _log_list {
    my $callback = shift ;
    my $list = shift ;
    my %mesg = () ;
    while (@{$list}) {
        my $message = shift @{$list} ;
        next unless (defined($message) and $message);
        $mesg{$message} = 0 unless (exists($mesg{$message}));
        &$callback($message.
            (($mesg{$message}++) ?" ($mesg{$message} times)" : "" ));
    }
}

sub LogSigMessage {
    &_log_list( \&Warn,  \@SigWarn  );
    &_log_list( \&Info,  \@SigInfo  );
    &_log_list( \&Debug, \@SigDebug );
}

&Debug("Module " . __PACKAGE__ . " v$VERSION loaded");

1;
