#!/usr/bin/perl -Tw

use strict;
use vars qw( $log_file $sigterm $sigint );
use subs qw( _die _logmsg );
use Fcntl qw(:flock);
use POSIX qw(setsid);
use Date::Format;
use IO::File;
use FS::UID qw(adminsuidsetup);
#use FS::Record qw(qsearch qsearchs);
#use FS::part_export;
#use FS::svc_acct;
#use FS::cust_svc;

#lots of false laziness w/freeside-queued

my $user = shift or die &usage;

#my $pid_file = "/var/run/freeside-sqlradius-radacctd.$user.pid";
my $pid_file = "/var/run/freeside-sqlradius-radacctd.pid";

&daemonize1;

#sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; }
#$SIG{CHLD} =  \&REAPER;

$sigterm = 0;
$sigint = 0;
$SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $sigint++; };
$SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $sigterm++; };

my $freeside_gid = scalar(getgrnam('freeside'))
  or die "can't setgid to freeside group\n";
$) = $freeside_gid;
$( = $freeside_gid;
#if freebsd can't setuid(), presumably it can't setgid() either.  grr fleabsd
($(,$)) = ($),$();
$) = $freeside_gid;

$> = $FS::UID::freeside_uid;
$< = $FS::UID::freeside_uid;
#freebsd is sofa king broken, won't setuid()
($<,$>) = ($>,$<);
$> = $FS::UID::freeside_uid;

#$ENV{HOME} = (getpwuid($>))[7]; #for ssh
adminsuidsetup $user;

$log_file= "/usr/local/etc/freeside/sqlradius-radacctd-log.". $FS::UID::datasrc;

&daemonize2;

$SIG{__DIE__} = \&_die;
$SIG{__WARN__} = \&_logmsg;

warn "freeside-sqlradius-radacctd starting\n";

#eslaf

#my $machine = shift or die &usage; #would need to be up higher for real
my @exports = qsearch('part_export', { 'exporttype' => 'sqlradius' } );

while (1) {

  my %seen = ();
  foreach my $export ( @exports ) {
    next if $seen{$export->option('datasrc')}++;
    my $dbh = DBI->connect(
      map { $export->option($_) } qw( datasrc username password )
    ) or do {
      warn "can't connect to ". $export->option('datasrc'). ": ". $DBI::errstr;
      next;
    }

    # find old radacct position
    #$lastid = 0;

    # get new radacct records
    my $sth = $dbh->prepare('SELECT * FROM radacct WHERE radacctid > ?') or do {
      warn "can't select in radacct table from ". $export->option('datasrc').
           ": ". $dbh->errstr;
      next;
    };

    while ( my $radacct = $sth->fetchrow_arrayref({}) ) {

      my $session = new FS::session {
        portnum =>
        svcnum  => 
        login   =>
        #logout  =>
      };

    }

    # look for updated radacct records & replace them

  }

  sleep 5;

}

#more false laziness w/freeside-queued

sub usage {
  die "Usage:\n\n  freeside-sqlradius-radacctd user\n";
}

sub _die {
  my $msg = shift;
  unlink $pid_file if -e $pid_file;
  _logmsg($msg);
}

sub _logmsg {
  chomp( my $msg = shift );
  my $log = new IO::File ">>$log_file";
  flock($log, LOCK_EX);
  seek($log, 0, 2);
  print $log "[". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n";
  flock($log, LOCK_UN);
  close $log;
}

sub daemonize1 {

  chdir "/" or die "Can't chdir to /: $!";
  open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";
  defined(my $pid = fork) or die "Can't fork: $!";
  if ( $pid ) {
    print "freeside-sqlradius-radacctd started with pid $pid\n";
          #logging to $log_file\n";
    exit unless $pid_file;
    my $pidfh = new IO::File ">$pid_file" or exit;
    print $pidfh "$pid\n";
    exit;
  }
  #open STDOUT, '>/dev/null'
  #                          or die "Can't write to /dev/null: $!";
  #setsid                  or die "Can't start a new session: $!";
  #open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";

}

sub daemonize2 {
  open STDOUT, '>/dev/null'
                            or die "Can't write to /dev/null: $!";
  setsid                  or die "Can't start a new session: $!";
  open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
}


#eslaf

=head1 NAME

freeside-sqlradius-radacctd - Real-time radacct import daemon

=head1 SYNOPSIS

  freeside-sqlradius-radacctd username

=head1 DESCRIPTION

Imports records from an SQL radacct table in real-time into the session
monitor.

This enables per-minute or per-hour charges as well as the
"View active NAS ports" function.

B<username> is a username added by freeside-adduser.

=head1 SEE ALSO

session.html from the base documentation.

=cut