package Voip_aaa;

# VoIP AAA functions
#

use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION
);

use Exporter;
$VERSION     = 2.01;
@ISA         = ('Exporter');
@EXPORT      = qw();
@EXPORT_OK   = ();
%EXPORT_TAGS = ();

# User name expration
use main;
use Billing;
use Auth;

@ISA = ("main");
my ($db, $conf, $Billing);

my %RAD_PAIRS = ();
my %ACCT_TYPES = ('Start', 1, 'Stop', 2, 'Alive', 3, 'Accounting-On', 7, 'Accounting-Off', 8);

#**********************************************************
# Init
#**********************************************************
sub new {
  my $class = shift;
  ($db, $conf) = @_;
  my $self = {};
  bless($self, $class);

  my $Auth = Auth->new($db, $conf);
  $Billing = Billing->new($db, $conf);

  return $self;
}

#**********************************************************
# Pre_auth
#**********************************************************
sub pre_auth {
  my ($self, $RAD, $attr) = @_;

  $self->{'RAD_CHECK'}{'Auth-Type'} = "Accept";
  return 0;
}

#**********************************************************
# Preproces
#**********************************************************
sub preproces {
  my ($RAD) = @_;

  my %CALLS_ORIGIN = (
    answer    => 0,
    originate => 1,
    proxy     => 2
  );

  (undef, $RAD->{H323_CONF_ID}) = split(/=/, $RAD->{H323_CONF_ID}, 2) if ($RAD->{H323_CONF_ID} =~ /=/);
  $RAD->{H323_CONF_ID} =~ s/ //g;

  if ($RAD->{H323_CALL_ORIGIN}) {
    (undef, $RAD->{H323_CALL_ORIGIN}) = split(/=/, $RAD->{H323_CALL_ORIGIN}, 2) if ($RAD->{H323_CALL_ORIGIN} =~ /=/);
    $RAD->{H323_CALL_ORIGIN} = $CALLS_ORIGIN{ $RAD->{H323_CALL_ORIGIN} } if ($RAD->{H323_CALL_ORIGIN} ne 1);
  }

  (undef, $RAD->{H323_DISCONNECT_CAUSE}) = split(/=/, $RAD->{H323_DISCONNECT_CAUSE}, 2) if (defined($RAD->{H323_DISCONNECT_CAUSE}));

  $RAD->{CLIENT_IP_ADDRESS} = $RAD->{FRAMED_IP_ADDRESS} if ($RAD->{FRAMED_IP_ADDRESS});
}

#**********************************************************
# user_info
#**********************************************************
sub user_info {
  my $self = shift;
  my ($RAD, $NAS) = @_;

  my $WHERE = '';
  if (defined($RAD->{H323_CALL_ORIGIN}) && $RAD->{H323_CALL_ORIGIN} == 0) {
    $WHERE = " and number='$RAD->{CALLED_STATION_ID}'";
    $RAD->{USER_NAME} = $RAD->{CALLED_STATION_ID};
  }
  else {
    $WHERE = " and number='$RAD->{USER_NAME}'";
  }

  $self->query(
    $db, "SELECT 
   voip.uid, 
   voip.number,
   voip.tp_id, 
   INET_NTOA(voip.ip),
   DECODE(password, '$conf->{secretkey}'),
   0,
   voip.allow_answer,
   voip.allow_calls,
   voip.disable,
   u.disable,
   u.reduction,
   u.bill_id,
   u.company_id,
   u.credit,
  UNIX_TIMESTAMP(),
  UNIX_TIMESTAMP(DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP()), '%Y-%m-%d')),
  DAYOFWEEK(FROM_UNIXTIME(UNIX_TIMESTAMP())),
  DAYOFYEAR(FROM_UNIXTIME(UNIX_TIMESTAMP()))

   FROM voip_main voip, 
        users u
   WHERE 
    u.uid=voip.uid
   $WHERE;"
  );

  if ($self->{TOTAL} < 1) {
    return $self;
  }

  (
    $self->{UID},
    $self->{NUMBER},
    $self->{TP_ID},
    $self->{IP},
    $self->{PASSWORD},
    $self->{SIMULTANEOUSLY},
    $self->{ALLOW_ANSWER},
    $self->{ALLOW_CALLS},
    $self->{VOIP_DISABLE},
    $self->{USER_DISABLE},
    $self->{REDUCTION},
    $self->{BILL_ID},
    $self->{COMPANY_ID},
    $self->{CREDIT},

    $self->{SESSION_START},
    $self->{DAY_BEGIN},
    $self->{DAY_OF_WEEK},
    $self->{DAY_OF_YEAR}

  ) = @{ $self->{list}->[0] };

  $self->{SIMULTANEOUSLY} = 0;

  #Chack Company account if ACCOUNT_ID > 0
  $self->check_company_account() if ($self->{COMPANY_ID} > 0);

  $self->check_bill_account();
  if ($self->{errno}) {
    $RAD_PAIRS{'Reply-Message'} = $self->{errstr};
    return 1, \%RAD_PAIRS;
  }

  return $self;
}

#**********************************************************
#
#**********************************************************
sub number_expr {
  my ($RAD) = @_;
  my @num_expr = split(/;/, $conf->{VOIP_NUMBER_EXPR});

  my $number = $RAD->{CALLED_STATION_ID};
  for (my $i = 0 ; $i <= $#num_expr ; $i++) {
    my ($left, $right) = split(/\//, $num_expr[$i]);
    my $r = eval "\"$right\"";
    if ($RAD->{CALLED_STATION_ID} =~ s/$left/$r/) {

      #    print "$i\n";
      last;
    }
  }

  return 0;
}

#**********************************************************
# Accounting Work_
#**********************************************************
sub auth {
  my $self = shift;
  my ($RAD, $NAS) = @_;

  if (defined($RAD->{H323_CONF_ID})) {
    preproces($RAD);
  }

  # For Cisco
  if ($RAD->{USER_NAME} =~ /(\S+):(\d+)/) {
    $RAD->{USER_NAME} = $2;
  }

  if ($conf->{VOIP_NUMBER_EXPR}) {
    number_expr($RAD);
  }

  %RAD_PAIRS = ();
  $self->user_info($RAD, $NAS);

  if ($self->{errno}) {
    $RAD_PAIRS{'Reply-Message'} = $self->{errstr};
    return 1, \%RAD_PAIRS;
  }
  elsif ($self->{TOTAL} < 1) {
    $self->{errno}  = 2;
    $self->{errstr} = 'ERROR_NOT_EXIST';
    if (!$RAD->{H323_CALL_ORIGIN}) {
      $RAD_PAIRS{'Reply-Message'} = "Answer Number Not Exist '$RAD->{USER_NAME}'";
    }
    else {
      $RAD_PAIRS{'Reply-Message'} = "Caller Number Not Exist '$RAD->{USER_NAME}'";
    }
    return 1, \%RAD_PAIRS;
  }

  if (defined($RAD->{CHAP_PASSWORD}) && defined($RAD->{CHAP_CHALLENGE})) {
    if (check_chap("$RAD->{CHAP_PASSWORD}", "$self->{PASSWORD}", "$RAD->{CHAP_CHALLENGE}", 0) == 0) {
      $RAD_PAIRS{'Reply-Message'} = "Wrong CHAP password '$self->{PASSWORD}'";
      return 1, \%RAD_PAIRS;
    }
  }
  else {
    if ($self->{IP} ne '0.0.0.0' && $self->{IP} ne $RAD->{FRAMED_IP_ADDRESS}) {
      $RAD_PAIRS{'Reply-Message'} = "Not allow IP '$RAD->{FRAMED_IP_ADDRESS}' / $self->{IP} ";
      return 1, \%RAD_PAIRS;
    }
  }

  #DIsable
  if ($self->{VOIP_DISABLE}) {
    if ($self->{VOIP_DISABLE} == 2 && $RAD->{H323_CALL_ORIGIN} == 1) {
      $RAD_PAIRS{'Reply-Message'} = "Incoming only";
      return 1, \%RAD_PAIRS;
    }
    else {
      $RAD_PAIRS{'Reply-Message'} = "Service Disable";
      return 1, \%RAD_PAIRS;
    }
  }
  elsif ($self->{USER_DISABLE}) {

    #$RAD_PAIRS{'h323-return-code'}=7;
    $RAD_PAIRS{'Reply-Message'} = "Account Disable";
    return 1, \%RAD_PAIRS;
  }

  $self->{PAYMENT_TYPE} = 0;
  if ($self->{PAYMENT_TYPE} == 0) {
    $self->{DEPOSIT}           = $self->{DEPOSIT} + $self->{CREDIT};    #-$self->{CREDIT_TRESSHOLD};
    $RAD->{H323_CREDIT_AMOUNT} = $self->{DEPOSIT};

    #Check deposit
    if ($self->{DEPOSIT} <= 0) {
      $RAD_PAIRS{'Reply-Message'} = "Negativ deposit '$self->{DEPOSIT}'. Rejected!";
      return 1, \%RAD_PAIRS;
    }
  }
  else {
    $self->{DEPOSIT} = 0;
  }

  #  $self->check_bill_account();
  # if call
  if (defined($RAD->{H323_CONF_ID})) {
    if ($self->{ALLOW_ANSWER} < 1 && $RAD->{H323_CALL_ORIGIN} == 0) {
      $RAD_PAIRS{'Reply-Message'} = "Not allow answer";
      return 1, \%RAD_PAIRS;
    }
    elsif ($self->{ALLOW_CALLS} < 1 && $RAD->{H323_CALL_ORIGIN} == 1) {
      $RAD_PAIRS{'Reply-Message'} = "Not allow calls";
      return 1, \%RAD_PAIRS;
    }

    $self->get_route_prefix($RAD);
    if ($self->{TOTAL} < 1) {
      $RAD_PAIRS{'Reply-Message'} = "No route '" . $RAD->{'CALLED_STATION_ID'} . "'";
      return 1, \%RAD_PAIRS;
    }
    elsif ($self->{ROUTE_DISABLE} == 1) {
      $RAD_PAIRS{'Reply-Message'} = "Route disabled '" . $RAD->{'CALLED_STATION_ID'} . "'";
      return 1, \%RAD_PAIRS;
    }

    #Get intervals and prices
    #originate
    if ($RAD->{H323_CALL_ORIGIN} == 1) {
      $self->{INFO} = "$RAD->{'CALLED_STATION_ID'}";
      $self->get_intervals();

      if ($self->{TOTAL} < 1) {
        $RAD_PAIRS{'Reply-Message'} = "No price for route prefix '$self->{PREFIX}' number '" . $RAD->{'CALLED_STATION_ID'} . "'";
        return 1, \%RAD_PAIRS;
      }

      my ($session_timeout, $ATTR) = $Billing->remaining_time(
        $self->{DEPOSIT},
        {
          TIME_INTERVALS      => $self->{TIME_PERIODS},
          INTERVAL_TIME_TARIF => $self->{PERIODS_TIME_TARIF},
          SESSION_START       => $self->{SESSION_START},
          DAY_BEGIN           => $self->{DAY_BEGIN},
          DAY_OF_WEEK         => $self->{DAY_OF_WEEK},
          DAY_OF_YEAR         => $self->{DAY_OF_YEAR},
          REDUCTION           => $self->{REDUCTION},
          POSTPAID            => $self->{PAYMENT_TYPE},
          PRICE_UNIT          => 'Min'
        }
      );

      if ($session_timeout > 0) {
        $RAD_PAIRS{'Session-Timeout'} = $session_timeout;

        #$RAD_PAIRS{'h323-credit-time'}=$session_timeout;
      }
      elsif ($self->{PAYMENT_TYPE} == 0 && $session_timeout == 0) {
        $RAD_PAIRS{'Reply-Message'} = "Too small deposit for call'";
        return 1, \%RAD_PAIRS;
      }

      #Make trunk data for asterisk
      if ($NAS->{NAS_TYPE} eq 'asterisk' and $self->{TRUNK_PROTOCOL}) {
        $self->{prepend} = '';

        my $number = $RAD->{'CALLED_STATION_ID'};
        if (defined($self->{REMOVE_PREFIX})) {
          $number =~ s/^$self->{REMOVE_PREFIX}//;
        }

        if (defined($self->{ADDPREFIX})) {
          $number = $self->{ADDPREFIX} . $number;
        }

        if ($self->{TRUNK_PROTOCOL} eq "Local") {
          $RAD_PAIRS{'next-hop-ip'} = "Local/" . $self->{prepend} . $number . "\@" . $self->{TRUNK_PROVIDER} . "/n";
        }
        elsif ($self->{TRUNK_PROTOCOL} eq "IAX2") {
          $RAD_PAIRS{'next-hop-ip'} = "IAX2/" . $self->{TRUNK_PROVIDER} . "/" . $self->{prepend} . $number;
        }
        elsif ($self->{TRUNK_PROTOCOL} eq "Zap") {
          $RAD_PAIRS{'next-hop-ip'} = "Zap/" . $self->{TRUNK_PROVIDER} . "/" . $self->{prepend} . $number;
        }
        elsif ($self->{TRUNK_PROTOCOL} eq "SIP") {
          $RAD_PAIRS{'next-hop-ip'} = "SIP/" . $self->{prepend} . $number . "\@" . $self->{TRUNK_PROVIDER};
        }
        elsif ($self->{TRUNK_PROTOCOL} eq "OH323") {
          $RAD_PAIRS{'next-hop-ip'} = "OH323/" . $self->{TRUNK_PROVIDER} . "/" . $self->{prepend} . $number;
        }
        elsif ($self->{TRUNK_PROTOCOL} eq "OOH323C") {
          $RAD_PAIRS{'next-hop-ip'} = "OOH323C/" . $self->{prepend} . $number . "\@" . $self->{TRUNK_PROVIDER};
        }
        elsif ($self->{TRUNK_PROTOCOL} eq "H323") {
          $RAD_PAIRS{'next-hop-ip'} = "H323/" . $self->{prepend} . $number . "\@" . $self->{TRUNK_PROVIDER};
        }

        $RAD_PAIRS{'session-protocol'} = $self->{TRUNK_PROTOCOL};

      }
    }
    else {
      $RAD->{USER_NAME} = "$RAD->{CALLED_STATION_ID}";
    }

    #Make start record in voip_calls
    my $SESSION_START = 'now()';
    $self->query(
      $db, "INSERT INTO voip_calls 
   (  status,
      user_name,
      started,
      lupdated,
      calling_station_id,
      called_station_id,
      nas_id,
      client_ip_address,
      conf_id,
      call_origin,
      uid,
      bill_id,
      tp_id,
      route_id,
      reduction
   )
   values ('0', \"$RAD->{USER_NAME}\", $SESSION_START, UNIX_TIMESTAMP(), 
      '$RAD->{CALLING_STATION_ID}', '$RAD->{CALLED_STATION_ID}', '$NAS->{NAS_ID}',
      INET_ATON('$RAD->{CLIENT_IP_ADDRESS}'),
      '$RAD->{H323_CONF_ID}',
      '$RAD->{H323_CALL_ORIGIN}',
      '$self->{UID}',
      '$self->{BILL_ID}',
      '$self->{TP_ID}',
      '$self->{ROUTE_ID}',
      '$self->{REDUCTION}');", 'do'
    );

    #   }
  }

  return 0, \%RAD_PAIRS;
}

#**********************************************************
#
#**********************************************************
sub get_route_prefix {
  my $self = shift;
  my ($RAD) = @_;

  # Get route
  my $query_params = '';

  for (my $i = 1 ; $i <= length($RAD->{'CALLED_STATION_ID'}) ; $i++) {
    $query_params .= '\'' . substr($RAD->{'CALLED_STATION_ID'}, 0, $i) . '\',';
  }
  chop($query_params);

  $self->query($db, "SELECT r.id AS route_id,
      r.prefix AS prefix,
      r.gateway_id AS gateway_id,
      r.disable AS route_disable
     FROM voip_routes r
      WHERE r.prefix in ($query_params)
      ORDER BY 2 DESC LIMIT 1;",
      undef,
      {INFO => 1}
  );

  #if ($self->{TOTAL} < 1) {
  #  return $self;
  #}
  #($self->{ROUTE_ID}, $self->{PREFIX}, $self->{GATEWAY_ID}, $self->{ROUTE_DISABLE}, $self->{TRUNK_PROTOCOL}, $self->{TRUNK_PATH}) = @{ $self->{list}->[0] };

  return $self;
}

#**********************************************************
#
#**********************************************************
 sub get_intervals {
  my $self = shift;
  my ($attr) = @_;

  $self->query(
    $db, "SELECT i.day, TIME_TO_SEC(i.begin), TIME_TO_SEC(i.end), 
    rp.price, i.id, rp.route_id,
    if (t.protocol IS NULL, '', t.protocol),
    if (t.protocol IS NULL, '', t.provider_ip),
    if (t.protocol IS NULL, '', t.addparameter),
    if (t.protocol IS NULL, '', t.removeprefix),
    if (t.protocol IS NULL, '', t.addprefix),
    if (t.protocol IS NULL, '', t.failover_trunk),
    rp.extra_tarification
      from intervals i, voip_route_prices rp
      LEFT JOIN voip_trunks t ON (rp.trunk=t.id)       
      where
         i.id=rp.interval_id 
         and i.tp_id  = '$self->{TP_ID}'
         and rp.route_id = '$self->{ROUTE_ID}';"
  );

  my $list                = $self->{list};
  my %time_periods        = ();
  my %periods_time_tarif  = ();
  $self->{TRUNK_PATH}     = '';
  $self->{TRUNK_PROVIDER} = '';

  foreach my $line (@$list) {
    #$time_periods{INTERVAL_DAY}{INTERVAL_START}="INTERVAL_ID:INTERVAL_END";
    $time_periods{ $line->[0] }{ $line->[1] } = "$line->[4]:$line->[2]";

    #$periods_time_tarif{INTERVAL_ID} = "INTERVAL_PRICE";
    $periods_time_tarif{ $line->[4] } = $line->[3];
    $self->{TRUNK_PROTOCOL}           = $line->[6];
    $self->{TRUNK_PROVIDER}           = $line->[7];
    $self->{ADDPARAMETER}             = $line->[8];
    $self->{REMOVE_PREFIX}            = $line->[9];
    $self->{ADDPREFIX}                = $line->[10];
    $self->{FAILOVER_TRUNK}           = $line->[11];
    $self->{EXTRA_TARIFICATION}       = $line->[12];
  }
  $self->{TIME_PERIODS}       = \%time_periods;
  $self->{PERIODS_TIME_TARIF} = \%periods_time_tarif;

  return $self;
}

#**********************************************************
# Accounting Work_
#**********************************************************
sub accounting {
  my $self = shift;
  my ($RAD, $NAS) = @_;

  my $acct_status_type = $ACCT_TYPES{ $RAD->{ACCT_STATUS_TYPE} };
  my $SESSION_START    = (defined($RAD->{SESSION_START}) && $RAD->{SESSION_START} > 0) ? "FROM_UNIXTIME($RAD->{SESSION_START})" : 'now()';
  my $sesssion_sum     = 0;
  $RAD->{CLIENT_IP_ADDRESS} = '0.0.0.0' if (!$RAD->{CLIENT_IP_ADDRESS});

  preproces($RAD);

  if ($NAS->{NAS_TYPE} eq 'cisco_voip') {
    if ($RAD->{USER_NAME} =~ /(\S+):(\d+)/) {
      $RAD->{USER_NAME} = $2;
    }

    #   if ($RAD->{H323_CALL_ORIGIN}==0) {
    # 	   $RAD->{H323_CALL_ORIGIN} = 1;
    # 	   $RAD->{USER_NAME}=$RAD->{CALLING_STATION_ID};
    #    }
    #   else {
    #   	 $RAD->{H323_CALL_ORIGIN} = 0;
    #   	 $RAD->{USER_NAME}=$RAD->{CALLED_STATION_ID};
    #    }
  }

  if ($conf->{VOIP_NUMBER_EXPR}) {
    number_expr($RAD);
  }

  #Start
  if ($acct_status_type == 1) {
    if ($NAS->{NAS_TYPE} eq 'cisco_voip') {

      # For Cisco
      $self->user_info($RAD, $NAS);

      my $sql = "INSERT INTO voip_calls 
     (  status,
      user_name,
      started,
      lupdated,
      calling_station_id,
      called_station_id,
      nas_id,
      conf_id,
      call_origin,
      uid,
      bill_id,
      tp_id,
      reduction,
      acct_session_id,
      route_id
     )
    values ($acct_status_type, '$RAD->{USER_NAME}', $SESSION_START, UNIX_TIMESTAMP(), 
      '$RAD->{CALLING_STATION_ID}', '$RAD->{CALLED_STATION_ID}', '$NAS->{NAS_ID}',
      '$RAD->{H323_CONF_ID}',
      '$RAD->{H323_CALL_ORIGIN}',
      '$self->{UID}',
      '$self->{BILL_ID}',
      '$self->{TP_ID}',
      '$self->{REDUCTION}',
      '$RAD->{ACCT_SESSION_ID}',
      ''
      );";

      $self->query($db, $sql, 'do');
    }
    else {
      $self->query(
        $db, "UPDATE voip_calls SET
      status='$acct_status_type',
      acct_session_id='$RAD->{ACCT_SESSION_ID}'
      WHERE conf_id='$RAD->{H323_CONF_ID}';", 'do'
      );
    }
  }

  # Stop status
  elsif ($acct_status_type == 2) {
    if ($RAD->{ACCT_SESSION_TIME} > 0) {
      $self->query($db, "SELECT 
      UNIX_TIMESTAMP(started),
      lupdated,
      acct_session_id,
      calling_station_id,
      called_station_id,
      nas_id,
      client_ip_address,
      conf_id,
      call_origin,
      uid,
      reduction,
      bill_id,
      c.tp_id,
      route_id,
      tp.time_division,
      UNIX_TIMESTAMP(),
      UNIX_TIMESTAMP(DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP()), '%Y-%m-%d')),
      DAYOFWEEK(FROM_UNIXTIME(UNIX_TIMESTAMP())),
      DAYOFYEAR(FROM_UNIXTIME(UNIX_TIMESTAMP()))
    FROM voip_calls c, voip_tps tp
      WHERE  c.tp_id=tp.id
      and conf_id='$RAD->{H323_CONF_ID}'
      and call_origin='$RAD->{H323_CALL_ORIGIN}';"
      );

      if ($self->{TOTAL} < 1) {
        $self->{errno}  = 1;
        $self->{errstr} = "Call not exists";
        $self->{Q}->finish();
        return $self;
      }
      elsif ($self->{errno}) {
        $self->{errno}  = 1;
        $self->{errstr} = "SQL error";
        return $self;
      }

      (
        $self->{SESSION_START},
        $self->{LAST_UPDATE},
        $self->{ACCT_SESSION_ID},
        $self->{CALLING_STATION_ID},
        $self->{CALLED_STATION_ID},
        $self->{NAS_ID},
        $self->{CLIENT_IP_ADDRESS},
        $self->{CONF_ID},
        $self->{CALL_ORIGIN},
        $self->{UID},
        $self->{REDUCTION},
        $self->{BILL_ID},
        $self->{TP_ID},
        $self->{ROUTE_ID},
        $self->{TIME_DIVISION},

        $self->{SESSION_STOP},
        $self->{DAY_BEGIN},
        $self->{DAY_OF_WEEK},
        $self->{DAY_OF_YEAR}

      ) = @{ $self->{list}->[0] };

      if ($self->{UID} == 0) {
        $self->{errno}  = 110;
        $self->{errstr} = "Number not found '" . $RAD->{'USER_NAME'} . "'";
        return $self;
      }
      elsif ($RAD->{H323_CALL_ORIGIN} == 1) {
        if (!$self->{ROUTE_ID}) {
          $self->get_route_prefix($RAD);
        }

        $self->get_intervals();
        if ($self->{TOTAL} < 1) {
          $self->{errno}  = 111;
          $self->{errstr} = "No price for route prefix '$self->{PREFIX}' number '" . $RAD->{'CALLED_STATION_ID'} . "'";
          return $self;
        }

        # Extra tarification
        if ($self->{EXTRA_TARIFICATION}) {
          $self->query($db, "SELECT prepaid_time FROM voip_route_extra_tarification WHERE id='$self->{EXTRA_TARIFICATION}';");
          $self->{PREPAID_TIME} = $self->{list}->[0]->[0];
          if ($self->{PREPAID_TIME} > 0) {
            $self->{LOG_DURATION} = 0;
            my $sql = "SELECT sum(duration) FROM voip_log l, voip_route_prices rp WHERE l.route_id=rp.route_id
       	 	   AND uid='$self->{UID}' AND rp.extra_tarification='$self->{EXTRA_TARIFICATION}'";
            $self->query($db, "$sql");
            $self->{LOG_DURATION} = 0;
            if ($self->{TOTAL} > 0) {
              $self->{LOG_DURATION} = $self->{list}->[0]->[0];
            }
            if ($RAD->{ACCT_SESSION_TIME} + $self->{LOG_DURATION} < $self->{PREPAID_TIME}) {
              $self->{PERIODS_TIME_TARIF} = undef;
            }
            elsif ($self->{LOG_DURATION} < $self->{PREPAID_TIME} && $RAD->{ACCT_SESSION_TIME} + $self->{LOG_DURATION} > $self->{PREPAID_TIME}) {
              $self->{PAID_SESSION_TIME} = $RAD->{ACCT_SESSION_TIME};
            }
          }
        }

        #Id defined time tarif
        if ($self->{PERIODS_TIME_TARIF}) {
          my $duration = $self->{PAID_SESSION_TIME} || $RAD->{ACCT_SESSION_TIME};

          if ($self->{TIME_DIVISION}) {
            my $periods = $duration / $self->{TIME_DIVISION};
            if ($periods != int($periods)) {
              $duration = $self->{TIME_DIVISION} * (int($periods) + 1);
            }
          }

          $Billing->time_calculation(
            {
              REDUCTION          => $self->{REDUCTION},
              TIME_INTERVALS     => $self->{TIME_PERIODS},
              PERIODS_TIME_TARIF => $self->{PERIODS_TIME_TARIF},
              SESSION_START      => $self->{SESSION_STOP} - $RAD->{ACCT_SESSION_TIME},
              ACCT_SESSION_TIME  => $duration,
              DAY_BEGIN          => $self->{DAY_BEGIN},
              DAY_OF_WEEK        => $self->{DAY_OF_WEEK},
              DAY_OF_YEAR        => $self->{DAY_OF_YEAR},
              PRICE_UNIT         => 'Min',
            }
          );

          $sesssion_sum = $Billing->{SUM};
          if ($Billing->{errno}) {
            $self->{errno}  = $Billing->{errno};
            $self->{errstr} = $Billing->{errstr};
            return $self;
          }
        }
      }

      my $filename;
      $self->query(
        $db, "INSERT INTO voip_log (uid, start, duration, calling_station_id, called_station_id,
              nas_id, client_ip_address, acct_session_id, 
              tp_id, bill_id, sum,
              terminate_cause, route_id) 
        VALUES ('$self->{UID}', FROM_UNIXTIME($RAD->{SESSION_START}),  '$RAD->{ACCT_SESSION_TIME}', 
        '$RAD->{CALLING_STATION_ID}', '$RAD->{CALLED_STATION_ID}', 
        '$NAS->{NAS_ID}', INET_ATON('$RAD->{CLIENT_IP_ADDRESS}'), '$RAD->{ACCT_SESSION_ID}', 
        '$self->{TP_ID}', '$self->{BILL_ID}', '$sesssion_sum',
        '$RAD->{ACCT_TERMINATE_CAUSE}', '$self->{ROUTE_ID}');", 'do'
      );

      if ($self->{errno}) {
        $filename = "$RAD->{USER_NAME}.$RAD->{ACCT_SESSION_ID}";
        $self->{LOG_WARNING} = "ACCT [$RAD->{USER_NAME}] Making accounting file '$filename'";
        $Billing->mk_session_log($RAD);
      }

      # If SQL query filed
      else {
        if ($Billing->{SUM} > 0) {
          $self->query($db, "UPDATE bills SET deposit=deposit-$Billing->{SUM} WHERE id='$self->{BILL_ID}';", 'do');
        }
      }
    }
    else {

    }

    # Delete from session wtmp
    $self->query(
      $db, "DELETE FROM voip_calls 
     WHERE acct_session_id='$RAD->{ACCT_SESSION_ID}' 
     and nas_id='$NAS->{NAS_ID}'
     and conf_id='$RAD->{H323_CONF_ID}';", 'do'
    );
  }

  #Alive status 3
  elsif ($acct_status_type eq 3) {
    $self->query(
      $db, "UPDATE voip_calls SET
    status='$acct_status_type',
    client_ip_address=INET_ATON('$RAD->{FRAMED_IP_ADDRESS}'),
    lupdated=UNIX_TIMESTAMP()
   WHERE
    acct_session_id='$RAD->{ACCT_SESSION_ID}' and 
    user_name='$RAD->{USER_NAME}'
    );", 'do'
    );
  }
  else {
    $self->{errno}  = 1;
    $self->{errstr} = "ACCT [$RAD->{USER_NAME}] Unknown accounting status: $RAD->{ACCT_STATUS_TYPE} ($RAD->{ACCT_SESSION_ID})";
  }

  if ($self->{errno}) {
    $self->{errno}  = 1;
    $self->{errstr} = "ACCT $RAD->{ACCT_STATUS_TYPE} SQL Error";
  }

  return $self;
}

1
