#!/usr/local/bin/perl

# Asterisk Call Throttling
# keep kid's friends from dialing over-and-over-and[...]
# jkister 20100909.01

use strict;
use Asterisk::AGI;
use DBI;

my $PIN         = CHANGE_ME;   # replace with override pin (as few/many digits as you want)
my $PIN_RETRIES = 3;
my $DBASE       = '/var/sql/agi.db';

my $agi = Asterisk::AGI->new();
my %input = $agi->ReadParse();

exit unless($input{callerid} =~ /^[0-9\-]{3,11}$/);

if( my $desc = $agi->database_get('skipauth', "num:$input{callerid}") ){
	verbose("skipauth found for $input{callerid} - $desc");
	exit;
}

my($dbun,$dbpw);
my $dsn = "DBI:SQLite:dbname=$DBASE";
my $dbh = DBI->connect($dsn, $dbun, $dbpw, {RaiseError => 1});

eval {
    my $h = set_sig_handler('ALRM', sub { die "table check timeout!"; } );
    alarm(3);
    my $res = $dbh->selectrow_arrayref(
                        "SELECT COUNT(*) FROM sqlite_master" .
                        " WHERE type='table'" .
                        " AND name = 'throttle'"
                      );
    alarm(3);
    if( $res ){
        my $tenminago = ( $^T - 600 );
        $dbh->do( "DELETE FROM throttle WHERE time < $tenminago" );
    }else{
        $dbh->do( 'CREATE TABLE throttle ('           ,
                  ' id INTEGER PRIMARY KEY NOT NULL,' ,
                  ' callerid VARCHAR(11) NOT NULL,'   ,
                  ' time INTEGER NOT NULL'            ,
                );
    }
    alarm(0);
};
alarm(0);

die "problem with database at $DBASE: $@\n" if $@;

my $sql = 'INSERT INTO throttle (callerid,time) VALUES (' .
          $dbh->quote($input{callerid}) . ',' .
          "'$^T')";
my $sth = $dbh->prepare($sql);
$sth->execute;

$sql = 'SELECT COUNT(*) FROM throttle where callerid = ' . $dbh->quote($input{callerid});
$sth = $dbh->prepare($sql);
$sth->execute;
my $row = $sth->fetchrow_arrayref;
my $count = $row->[0];

if($count > 2){
	verbose("call throttle for $input{callerid}");
	swift( 'Call throttling activated.' );
	
	my ($pass,$i);
	until($pass eq $PIN){
		$i++;
		if($i == $PIN_RETRIES){
			swift( 'Too many incorrect passwords.  Goodbye.' );
			sleep 1;
			$agi->hangup();
		}
		swift( 'Enter password or call back after ten minutes.  not one minute.  not nine minutes.  but after ten minutes.|5000|5' );
		$pass = $agi->get_variable('SWIFT_DTMF');
	}
}

sub swift {
	my $msg = join(' ', @_);

	$agi->exec('Swift', $msg);
}

sub verbose {
	my $msg = join(' ', @_);
	
	$agi->verbose($msg, 1);
}
