#!/usr/bin/perl 
##########################################################################
#                                                                        #
# Perl Script for Radius Accounting                                      #
# Switzernet(c)2011                                                      #
#                                                                        #
##########################################################################
# my modules
use strict;
use warnings;
use Asterisk::Manager;
use Sys::Syslog;
use POSIX;
use Config::IniFiles;
use Authen::Radius;
use DBI;
use Switch;
use threads;
use threads::shared;

#Enable debug
use constant DEBUG => 0;
use Data::Dumper;
local $Data::Dumper::Indent = 0;

#WARNING Variables set by AGI are not correctly read from this script

##########################################################################
# Setting
my $lock_file = '/var/run/ast-rad-acc.pid';
my $lock_control = '/var/run/ast-control.pid';
my $runas_user = 'root';
my $monitor_dir = '/var/spool/asterisk/monitor';
my $config_dir = '/etc/astrad/config';
##########################################################################
# Globals
my %channels;
my ($ast_hostname,$ast_username,$ast_password);
my ($rad_serv, $rad_sec, $nas_ip);
my ($DB_NAME_Rad,$DB_HOST_Rad,$DB_USER_Rad,$DB_PASS_Rad,$dbh_Rad,$Rad_connected);
my ($CustomerType,$lconf,$astman,$ast_connected,$thr);
my $t_event : shared;
my @event_list;
##########################################################################
#                             Initialization                             #
##########################################################################
# Check if already running
#
if( -e $lock_file ) {
	open(PID,$lock_file);
	my $pid=<PID>;
	close PID;
	chomp $pid;
	if( !-e "/proc/$pid" ) {
		print STDERR "Lock file present, but no process with pid=$pid.\n";
		die "Can't delete lock file $lock_file\n" if !unlink $lock_file;
		print STDERR "Lock file has been removed.\n";
	} else {
		die "Lockfile present, another copy is punning pid=$pid\n";
	}
}

load_config();
my ($name, $passwd, $uid, $gid) = getpwnam($runas_user) or die "$runas_user not in passwd file";;
##########################################################################
# set C locale
POSIX::setlocale(LC_ALL, "C");
##########################################################################
# Become daemon
my $pid;
if( !defined($pid = fork()) ) {
	die "cannot fork: $!";
} elsif ($pid) {
# Create lockfile, and finish parent process
#
	open(PID, "> $lock_file") || die "ast-rad-acc.pl: Unable to create lockfile $lock_file\n";
	print PID "$pid";
	close PID;
	chown $uid, $gid, $lock_file;
	exit;
} else {
# daemon
	setpgrp();
	select(STDERR); $| = 1;
	select(STDOUT); $| = 1;
	openlog('ast-rad-acc', 'cons,pid', 'daemon');
	syslog('notice', "Ast-Rad ast-rad-acc: accounting for Asterisk started");
}

##########################################################################
# Install signall handler
$SIG{INT} = \&safe_exit;
$SIG{QUIT} = \&safe_exit;
$SIG{TERM} = \&safe_exit;
$SIG{HUP} = \&load_config;
##########################################################################
# Drop privileges
setuid($uid);
$< = $uid;
$> = $uid;
##########################################################################
# Signal Handlers
sub safe_exit {
    my($sig) = @_;
    syslog('crit', "Ast-Rad: Caught a SIG$sig - shutting down");
    $astman->disconnect if $ast_connected;  
    $dbh_Rad->disconnect if $Rad_connected;    
    unlink $lock_file or syslog('crit', "Ast-Rad: Unable to create lockfile $lock_file\n");
    closelog();     
    exit;
}
##########################################################################
#                                FUNCTION                                #
##########################################################################
# Load config
sub load_config {
    my $conf=Config::IniFiles->new(-file => "$config_dir/switzer.conf");
    return 0 if !defined $conf ;
    $rad_serv     = $conf->val('MASTER_RD','RADIUS_SERVER');
    $rad_sec      = $conf->val('MASTER_RD','RADIUS_SECRET');
    $nas_ip       = $conf->val('GLOBAL','NAS_IP');    
    $DB_NAME_Rad  = $conf->val('ASTER_DB','DB_NAME');
    $DB_HOST_Rad  = $conf->val('ASTER_DB','DB_HOST');
    $DB_USER_Rad  = $conf->val('ASTER_DB','DB_USER');
    $DB_PASS_Rad  = $conf->val('ASTER_DB','DB_PASS');      
    $ast_hostname = $conf->val('Manager','AMI_PERMIT');
    $ast_username = $conf->val('Manager','AMI_USER2');
    $ast_password = $conf->val('Manager','AMI_SECRET2');
return 1;
}
##########################################################################
# sample '09:16:05 GMT Sat Dec 11 2004'
sub format_date_gmt {
    my ($date) = @_;
    return strftime "%H:%M:%S GMT %a %b %e %Y", gmtime($date);
}

##########################################################################
# sample '2004-12-11 09:16:05'
sub format_date_sql {
    my ($date) = @_;
    
    if ($date eq 0) {
        return "NULL";
    } else {
        return strftime("%Y-%m-%d %H:%M:%S", localtime($date));
    }
}
##########################################################################
# Astrad Rad. DB connect 
sub Rad_connect {
my $cop=0;
$Rad_connected = 1;
while( 1 ) {
    $cop++;
    $dbh_Rad = DBI->connect_cached("DBI:mysql:$DB_NAME_Rad;host=$DB_HOST_Rad", $DB_USER_Rad, $DB_PASS_Rad);
    if( $dbh_Rad ) {
        $Rad_connected = 1;
        $cop=0;
        syslog('info', 'Ast-Rad: Connected to Astrad Rad. DB!') if (DEBUG);
        return 1;
        } else {
            if ($Rad_connected) {
                syslog('err', 'Ast-Rad: Could not connect to Astrad Rad. DB!');
                $cop=1;
                }
            $Rad_connected = 0;
            syslog('info', "Ast-Rad: Connection to Astrad Rad. DB -> SLEEP $cop");
            $cop++ if $cop;
            return 0 if ($cop>=3);
            }
        sleep 1;
    }
}
##########################################################################
# Insert into the Failed radius packets Table 
sub Failed_radius_packet {
  my (%data) = @_;
  return 0 if (!Rad_connect());
  $data{'CDR(CustomerType)'}="" if (!defined($data{'CDR(CustomerType)'}));    
  my $request="INSERT INTO radius_packets_Failed ("
                ."h323_connect_time, h323_disconnect_time, acct_session_time, h323_disconnect_cause, nas_ip_address, user_name, calling_station_id, "
                ."called_station_id, call_id, h323_setup_time, h323_conf_id, h323_remote_address, call_profile, creation_date, reception_date, "
                ."last_send, send_counter, status) "
                ."VALUES "
                ."('".$data{'H323_connect_time'}."','".$data{'H323_disconnect_time'}."','".$data{'Acct_Session_Time'}."','".$data{'H323_disconnect_cause'}
                ."','".$data{'nas_ip_address'}."','".$data{'user_name'}."','".$data{'Calling-Station-Id'}."','".$data{'Called-Station-Id'}
                ."','".$data{'call_id'}."','".$data{'H323_setup_time'}."','".$data{'H323_conf_id'}."','".$data{'H323_remote_address'}."','".$data{'call_profile'}
                ."','".$data{'creation_date'}."','".$data{'reception_date'}."','".$data{'last_send'}."','".$data{'send_counter'}."','".$data{'status'}."')";
    my $sth = $dbh_Rad->prepare($request);
    if ($sth->execute()) {
        $sth->finish;
        syslog('info', "Ast-Rad: Request = $request") if (DEBUG);
        return 1;
        }
return 0;
}
##########################################################################
# thread control
sub AMI_control {
syslog('info', 'Ast-Rad: Thread: Start AMI Control') if (DEBUG);
my ($l_event,$cop) = (0,0);
while ( 1 ) {
    $l_event = time();
    syslog('info', "Ast-Rad: Thread: Time Events -> Last = $t_event | Now = $l_event") if (DEBUG);
    #TODO if connection to asterisk is lost the script should not exit
    if ($l_event - $t_event > 400) {
        syslog('crit', "Ast-Rad: Thread: Asterisk PBX is probably restarted !");
        safe_exit();
        }
    $cop=0 if ($l_event - $t_event < 4);
    $cop++;
    syslog('info', "Ast-Rad: Thread: AMI Control sleep $cop") if (DEBUG);
    sleep 2;
    }
}
##########################################################################
# AMI connect
sub AMI_connect {
$astman = new Asterisk::Manager;
$astman->user($ast_username);
$astman->secret($ast_password);
$astman->host($ast_hostname);
$t_event = time();
my $cop=0;
$ast_connected = 1;
while( 1 ) {
    $cop++;
    if( $astman->connect ) {
        $ast_connected = 1;
        $cop=0;
        syslog('info', 'Ast-Rad: Connected to Asterisk!') if (DEBUG);
        $thr = threads->new(\&AMI_control);
        $astman->setcallback('DEFAULT', \&status_callback);
        eval { $astman->eventloop; };
        } 
    else { 
        if ($ast_connected) {
            syslog('err', 'Ast-Rad: Could not connect to Asterisk!');
            $cop=1;
            }
        $ast_connected = 0;
        syslog('info', "Ast-Rad: SLEEP $cop");
        $cop++ if $cop;
        return 0 if ($cop>=3);
        }
    sleep 1;
    }
}
##########################################################################
# 
sub status_callback {
  my (%unfiltered_event) = @_;
  my $status = 0;
  return if not (%unfiltered_event);
  $t_event = time();
  foreach (keys %unfiltered_event) {
    next if ($_ eq '');
    push(@event_list, [$_, $unfiltered_event{$_}]);
  }
  my @event_pos;
  for my $i ( 0 .. $#event_list) {
    push(@event_pos, $i) if ($event_list[$i][0] eq 'Event');
  }
  #Remove lines prior to first event
  my $offset=0;
  if ($event_pos[0] != 0) {
    shift(@event_list);
    $offset++;
  }
  while ($#event_pos > 0) {
    my @filtered_event;
    print "\n" if (DEBUG);
    for (my $i = 0; $i < ($event_pos[1]-$offset) ; $i++) {
      my $addtolist = 1;
      $addtolist = 0 if ($event_list[0][1] eq 'PeerStatus');
      push(@filtered_event, [$event_list[0][0],$event_list[0][1]]) if ($addtolist == 1);
      print "['".$event_list[0][0]."','".$event_list[0][1]."']\n" if (DEBUG);
      shift(@event_list);
    }
    if ($filtered_event[0][0] eq 'Event') {
      print "Executing event in filtered_event ".$filtered_event[0][1]."\n" if (DEBUG);
      switch ($filtered_event[0][1]) {
        case "Newchannel" {
#['Event','Newchannel']
#['Privilege','call,all']
#['Channel','SIP/41215500331-00000013']
#['Context','fromaccount']
#['CallerIDName','41215500331']
#['Uniqueid','91.121.122.64-1324372616.19']
#['ChannelState','']
#['ChannelStateDesc','Down']
#['CallerIDNum','41215500331']
#['Value','sip:41215500331@192.168.1.121:5060']
          $channels{$filtered_event[2][1]} = { 
            'CALLERID' => $filtered_event[8][1],
            'UNIQUEID' => $filtered_event[5][1],
            'CALL_START' => time(),
            'LINK_START' => time(),
            'LINK_END' => time(),
            'CALL_TYPE' => 'VoIP',
            'CALL_PROTOCOL' => 'sipv2',
            'CALL_ID' => $filtered_event[5][1],
            'RADIUS_Server' => $rad_serv,
            'RADIUS_Secret' => $rad_sec,
            'NAS_IP_Address' => $nas_ip,
            'NAS-Port' => '5060',
            'Remoteip' => $nas_ip
          };
          $channels{$filtered_event[2][1]}{'Remoteip'} = $1 if ($filtered_event[2][1] =~ /^SIP\/(\d+\.\d+\.\d+\.\d+)-/i);
        }
        case "Newstate" {
#['Event','Newstate']
#['Privilege','call,all']
#['Channel','SIP/41215500331-00000013']
#['CallerIDName','41215500331']
#['Uniqueid','91.121.122.64-1324372616.19']
#['ChannelStateDesc','Up']
#['ChannelState','6']
#['CallerIDNum','41215500331']
        }
        case "Newexten" {
#['Event','Newexten']
#['Privilege','dialplan,all']
#['Channel','SIP/41215500331-00000011']
#['Context','fromaccount']
#['Extension','0215502419']
#['Uniqueid','91.121.122.64-1324369709.17']
#['Application','Set']
#['AppData','CDR(CustomerType)=SipAuth']
#['Priority','2']
          if (defined $filtered_event[7][1] && $filtered_event[6][1] eq 'Set') {
            my $channel = $filtered_event[2][1];
            $channels{$channel}{'DNID'} = $1 if (defined $filtered_event[4][1] && $filtered_event[4][1] =~ /^(\d+)$/);
            my ( $_var, $_val ) = split(/=/, $filtered_event[7][1]);
            if ( $_val ne '') {
              if($_var eq 'CDR(accountcode)') {
                $channels{$channel}{'ACCOUNTCODE'} = $_val;
                print '$channels{'.$channel.'}{ACCOUNTCODE} = '.$_val."\n" if (DEBUG);
              } else {
                $channels{$channel}{$_var} = $_val;
                print '$channels{'.$channel.'}{'.$_var.'} = '.$_val."\n" if (DEBUG);
                if ( $_var eq 'H323_ID') {
                  syslog('debug', "H323 dec: ".$channels{$channel}{'H323_ID'}) if (DEBUG);
                  $channels{$channel}{'H323_ID'}=sprintf("%08X %08X %08X %08X",$1,$2,$3,$4) if $channels{$channel}{'H323_ID'} =~ /(\d+)-(\d+)-(\d+)-(\d+)/;
                  syslog('debug', "H323 hex: ".$channels{$channel}{'H323_ID'}) if (DEBUG);
                }
              }
            }
          }
        }
        case "NewAccountCode" {
#['Event','NewAccountCode']
#['Privilege','call,all']
#['Channel','SIP/91.121.151.75-00000014']
#['Uniqueid','91.121.122.64-1324372618.20']
#['Channel2','SIP/91.121.151.75-00000014']
#['Bridgestate','Link']
        }
        case "Link" {
#Link does not seem to appear in the new version of asterisk
#			my $channel1 = $event{'Channel1'};
#			my $channel2 = $event{'Channel2'};
#			return unless $channels{$channel1};
#			$channels{$channel1}{'LINK_START'} = time();
#			$channels{$channel2}{'LINK_START'} = time();
#
#			syslog('info', 'Link without uniqueid') unless $channels{$channel1}{'UNIQUEID'};
#			syslog('info', 'Link without channeld') unless $channel1;
#			syslog('info', 'Link on undefined channel') unless $channels{$channel1};
#
#			return unless($channel1 && $channels{$channel1} && $channels{$channel1}{'UNIQUEID'});
        }
        case "VarSet" {
#['Event','VarSet']
#['Privilege','dialplan,all']
#['Channel','SIP/41215500331-00000011']
#['Uniqueid','91.121.122.64-1324369709.17']
#['Variable','SIPURI']
#['Value','astrad.switzernet.com']
          if (defined $filtered_event[5][0] && defined $filtered_event[4][0] && defined $channels{$filtered_event[2][1]}) {
             $channels{$filtered_event[2][1]}{$filtered_event[4][1]} = $filtered_event[5][1];
             print '$channels{'.$filtered_event[2][1].'}{'.$filtered_event[4][1].'} = '.$filtered_event[5][1]."\n" if (DEBUG);
          }
        }
        case "Bridge" {
#['Event','Bridge']
#['Privilege','call,all']
#['Uniqueid2','91.121.122.64-1324372618.20']
#['Channel1','SIP/41215500331-00000013']
#['Bridgetype','core']
#['Uniqueid1','91.121.122.64-1324372616.19']
#['CallerID1','41215500331']
#['CallerID2','0215502419']
#['Value','SIP/91.121.151.75-00000014']
          if (defined $filtered_event[8][1]) {
            my $channel1 = $filtered_event[3][1];
            my $channel2 = $filtered_event[8][1];
            $channels{$channel1}{'LINK_START'} = time();
            $channels{$channel1}{'CHANNEL2'} = $channel2;
            $channels{$channel2}{'CHANNEL1'} = $channel1;
            $channels{$channel2}{'LINK_START'} = time();
		    $channels{$channel1}{'CALL_ORIGIN'} = 'answer';
		    print 'Call '.$channel1." answered. Sending ".$channels{$channel1}{'CALL_ORIGIN'}."-START Radius packet.\n" if (DEBUG);
            send_acc('Start',%{$channels{$channel1}});
          }
        }
        case "Unlink" {
#['Event','Unlink']
#['Privilege','call,all']
#['Uniqueid2','91.121.122.64-1324372618.20']
#['Channel1','SIP/41215500331-00000013']
#['Uniqueid1','91.121.122.64-1324372616.19']
#['CallerID1','41215500331']
#['CallerID2','0215502419']
#['Value','9']
          my $channel = $filtered_event[3][1];
          last unless $channels{$channel};
          $channels{$channel}{'LINK_END'} = time();
          $channels{$channels{$channel}{'CHANNEL2'}}{'LINK_END'} = time() if defined $channels{$channel}{'CHANNEL2'};
        }
        case "Hangup" {
#['Event','Hangup'];
#['Privilege','call,all'];
#['Channel','SIP/91.121.117.76-00000060'];
#['Cause','16'];
#['ConnectedLineName','41215500331'];
#['ConnectedLineNum','41215500331'];
#['CallerIDName','<unknown>'];
#['Uniqueid','91.121.122.64-1324045271.96'];
#['CallerIDNum','0215502419'];
#['Cause-txt','Normal Clearing'];
          my $channel = $filtered_event[2][1];
          $channel = $channels{$channel}{'CHANNEL1'} if (defined $channels{$channel}{'CHANNEL1'});
          last if !defined $channels{$channel};
          last if !defined $channels{$channel}{'H323_ID'};
          $channels{$channel}{'CALL_END'} = time();
          $channels{$channel}{'CAUSE'} = 0;
          $channels{$channel}{'CAUSE'} = $filtered_event[3][1] if $filtered_event[3][1] ne '';
          if (defined($channels{$channel}{'CALL_ORIGIN'}) && $channels{$channel}{'CALL_ORIGIN'} eq 'answer') {
            if (defined $channels{$channel}{'CHANNEL2'}) { 
              print 'Call '.$channel."->".$channels{$channel}{'CHANNEL2'}." disconnected. Sending ".$channels{$channel}{'CALL_ORIGIN'}."-STOP Radius packet.\n" if (DEBUG);
              delete $channels{$channels{$channel}{'CHANNEL2'}}{'CHANNEL1'};
              delete $channels{$channels{$channel}{'CHANNEL2'}};
            } else {
              print 'Call '.$channel." disconnected. Sending ".$channels{$channel}{'CALL_ORIGIN'}."-STOP Radius packet.\n" if (DEBUG);
            }
            send_acc('Stop',%{$channels{$channel}});
          }
          $channels{$channel}{'CALL_ORIGIN'} = 'originate';
          print 'Call '.$channel." disconnected. Sending ".$channels{$channel}{'CALL_ORIGIN'}."-STOP Radius packet.\n" if (DEBUG);
          send_acc('Stop',%{$channels{$channel}});
          delete $channels{$channel}{'CHANNEL2'};
          delete $channels{$channel};
        }
        case "Dial" {
#['Event','Dial'];
#['DestUniqueID','91.121.122.64-1324045271.96'];
#['Privilege','call,all'];
#['Destination','SIP/91.121.117.76-00000060'];
#['Channel','SIP/41215500331-0000005f'];
#['SubEvent','Begin'];
#['Dialstring','41215502419@91.121.117.76'];
#['ConnectedLineName','<unknown>'];
#['ConnectedLineNum','<unknown>'];
#['CallerIDName','41215500331'];
#['UniqueID','91.121.122.64-1324045269.95'];
#['CallerIDNum','41215500331'];
          if ($filtered_event[3][0] ne 'Destination' || $filtered_event[4][0] ne 'Channel' || $filtered_event[5][1] ne 'Begin') {
            print "End dial\n" if (DEBUG);
            last;
          }
          my $channel1 = $filtered_event[4][1];
          my $channel2 = $filtered_event[3][1];
          syslog('debug', "DIAL: $channel1 -> $channel2") if (DEBUG);
          $channels{$channel1}{'VLEG'} = $channel2;
          $channels{$channel1}{'CALL_ORIGIN'} = 'originate';
          $channels{$channel1}{'ACCOUNTCODE'} = $channels{$channel1}{'CALLERID'} if !defined $channels{$channel1}{'ACCOUNTCODE'};
          $channels{$channel2}{'ACCOUNTCODE'} = $channels{$channel1}{'ACCOUNTCODE'};
          $channels{$channel1}{'CALL_ID'}     = $filtered_event[10][1] if !defined $channels{$channel1}{'CALL_ID'};
          $channels{$channel2}{'CALL_ID'}     = $channels{$channel1}{'CALL_ID'};
          $channels{$channel2}{'CALLERID'}    = $channels{$channel1}{'CALLERID'};
          $channels{$channel2}{'DNID'}        = $channels{$channel1}{'VDNID'};
          $channels{$channel2}{'H323_ID'}     = $channels{$channel1}{'H323_ID'};
          $channels{$channel1}{'LINK_START2'} = time();
          $channels{$channel2}{'LINK_START2'} = time();
          print "Sending ".$channels{$channel1}{'CALL_ORIGIN'}."-START Radius packet.\n" if (DEBUG);
          send_acc('Start',%{$channels{$channel1}});
        }
        case "Shutdown" {
          syslog('info', "Asterisk Shutdown");
          safe_exit();
        }
        case "Reload" {
          syslog('info', "Asterisk Reload");
          load_config();
        }
      }
    }
    undef @filtered_event;
    shift(@event_pos);
  }
  return;
}
##########################################################################
# 
sub send_acc {
	my ($acc_type,%cdr) = @_;
	my $cause="null";
	my $remote;
	my $duration=0;
	my $date=0;

        return if $cdr{'H323_ID'} =~ /(\d+)-(\d+)-(\d+)-(\d+)/;
        return if !defined $cdr{'CDR(CustomerType)'};
        $cdr{'CALL_ORIGIN'} = 'originate' if( !defined $cdr{'CALL_ORIGIN'} );
	my $r = new Authen::Radius(Host => $cdr{'RADIUS_Server'}, Secret => $cdr{'RADIUS_Secret'}, TimeOut => 10, Service => 'radius-acct');

	if( !defined $r ) {
		syslog('crit', "RADIUS host $cdr{'RADIUS_Server'} ERROR");
                print "RADIUS host ".$cdr{'RADIUS_Server'}." ERROR\n" if (DEBUG);
		return;
	}

	$r->clear_attributes();
        return if ($acc_type ne 'Start' && $acc_type ne 'Stop');
        print ("Sending Radius ".$cdr{'CALL_ORIGIN'}."->".$acc_type."\n") if (DEBUG);
        my $CSI = $cdr{'DNID'};
#        $CSI = $cdr{'PBCLD'} if ($cdr{'CALL_ORIGIN'} eq "originate");
        $CSI = $cdr{'VDNID'} if ($cdr{'CALL_ORIGIN'} eq "originate");
	$r->add_attributes (
          { Name => 'Acct-Status-Type',   Value => $acc_type },
          { Name => 'h323-call-origin',   Value => $cdr{'CALL_ORIGIN'} },
          { Name => 'h323-call-type',     Value => $cdr{'CALL_TYPE'} },
          { Name => 'Cisco-AVPair',       Value => "h323-session-protocol=".$cdr{'CALL_PROTOCOL'} },
          { Name => 'NAS-IP-Address',     Value => $cdr{'NAS_IP_Address'} },
          { Name => 'NAS-Port',           Value => $cdr{'NAS-Port'} },
          { Name => 'User-Name',          Value => $cdr{'ACCOUNTCODE'} },
          { Name => 'Calling-Station-Id', Value => $cdr{'CALLERID'} },
          { Name => 'Called-Station-Id',  Value => $CSI },
          { Name => 'Cisco-AVPair',       Value => "call-id=".$cdr{'CALL_ID'} },
          { Name => 'Cisco-AVPair',       Value => "Acct-Session-Id=".$cdr{'CALL_ID'} },
          { Name => 'Cisco-AVPair',       Value => "Acct-Delay-Time=0" },
          { Name => 'h323-setup-time',    Value => format_date_gmt($cdr{'CALL_START'}) },
          { Name => 'Cisco-AVPair',       Value => "h323-conf-id=".$cdr{'H323_ID'} }
	);
        if ($acc_type eq 'Stop') {
#           TODO why?
            $cause = $cdr{'CAUSE'}-6;
            $cause = 0 if $cause<0;
            $r->add_attributes (
              { Name => 'h323-disconnect-time', Value => format_date_gmt($cdr{'LINK_END'}) },
              { Name => 'Acct-Session-Time', Value => $cdr{'LINK_END'} - $cdr{'LINK_START'} },
              { Name => 'h323-disconnect-cause', Value => $cause }
#TODO h323-voice-quality
            );
            $r->add_attributes ( { Name => 'h323-ivr-out', Value => 'PortaBilling_Session:unlock' } ) if ($cdr{'CALL_ORIGIN'} eq "answer");
            $duration=$cdr{'LINK_END'} - $cdr{'LINK_START'};
        }

        $remote = $cdr{'NAS_IP_Address'};
        if ($cdr{'CALL_ORIGIN'} eq "originate") {
          if ($cdr{'ROUTEIP'} eq $cdr{'NAS_IP_Address'}) {
            $remote = 'sip-ua';
          } else {
            $remote = $cdr{'ROUTEIP'};
          }
          $r->add_attributes ( { Name => 'h323-ivr-out', Value => 'PortaBilling_Auth_CLD:'. $cdr{'PBCLD'}} ) if (defined $cdr{'PBCLD'} && $cdr{'PBCLD'} ne '');
          $cdr{'Dial_Info'} =~ m/L\((\d+):/;
#The maximum duration of the call is on the wrong field to an Asterisk bug which writes the value of a variable on the previous event when the variable is set from an AGI
          $r->add_attributes ( { Name => 'h323-ivr-out',      Value => 'DURATION:'. substr($1, 0, -3) } ) if defined $1; 
          $r->add_attributes ( { Name => 'h323-connect-time', Value => format_date_gmt($cdr{'LINK_START2'}) } );
#TODO alert-timepoint when call starts ringing if start
        } else {
          $remote = $cdr{'RECVIP'};
          $r->add_attributes ( { Name => 'h323-connect-time', Value => format_date_gmt($cdr{'LINK_START'}) } );
          $r->add_attributes ( { Name => 'Cisco-AVPair',   Value => "alert-timepoint=".format_date_gmt($cdr{'LINK_START'}) } );
        }
        $r->add_attributes ( { Name => 'h323-remote-address', Value => $remote } );
	$date=time;

	if ($acc_type eq 'Start') {
          $r->send_packet (ACCOUNTING_REQUEST);
	} else {
          $r->send_packet (ACCOUNTING_REQUEST) and my $type = $r->recv_packet;
          if (!defined $type) {
            my %data;
            $data{'H323_setup_time'}       = format_date_sql($cdr{'CALL_START'});
            $data{'H323_connect_time'}     = format_date_sql($cdr{'LINK_START2'});
            $data{'H323_disconnect_time'}  = format_date_sql($cdr{'LINK_END'});
            $data{'Acct_Session_Time'}     = $cdr{'LINK_END'} - $cdr{'LINK_START'};
            $data{'H323_disconnect_cause'} = $cause;
            $data{'nas_ip_address'}        = $cdr{'NAS_IP_Address'};
            $data{'user_name'}             = $cdr{'ACCOUNTCODE'};
            $data{'call_id'}               = $cdr{'CALL_ID'};
            $data{'H323_conf_id'}          = $cdr{'H323_ID'};
            $data{'H323_remote_address'}   = $remote;
            $data{'call_profile'}          = "";
            $data{'call_profile'}          = $cdr{'CDR(CustomerType)'} if defined($data{'CDR(CustomerType)'});
            $data{'creation_date'}         = format_date_sql($date);
            $data{'reception_date'}        = format_date_sql(0);
            $data{'last_send'}             = format_date_sql(time+1);
            $data{'send_counter'}          = 1;
            $data{'status'}                = 0;
            $data{'Calling-Station-Id'}    = $cdr{'CALLERID'};
            $data{'Called-Station-Id'}     = $CSI;
            $data{'reception_date'}=0;
            $data{'STATUS'}=0;
            syslog('crit', "Ast-Rad: No response from RADIUS server !");
            print "Ast-Rad: No response from RADIUS server!\n" if DEBUG;
#TODO sometimes it adds several times the same call
            Failed_radius_packet(%data);
          } else {
            print "Ast-Rad: Ast-Rad: Good response from RADIUS server!\n" if DEBUG;
            syslog('crit', "Ast-Rad: Good response from RADIUS server");
          }
	}
}
##########################################################################
#                                 main()                                 #
##########################################################################
# Load Radius dictionary
Authen::Radius->load_dictionary;
$lconf=0;
while ( 1 ) {
    if (!$lconf && !load_config()) {
        syslog('crit', "Ast-Rad: Config file error!");
        next;
        }
    $lconf=1;
    if (!AMI_connect()) {
        syslog('crit', "Ast-Rad: Error in Astrerisk Manager connection");
        $lconf=0;
        sleep 1; 
        }
}
##########################################################################
#                                  END                                   #
##########################################################################
