#!/usr/bin/perl # # PrePaid CallingCard IVR Application for Asterisk PBX # Copyright 2003, Brian K. West 2003-08-20 # # All prompts are kludged together.. I would like it to read # "Please enter your calling card number" # "I'm sorry thats an invalid card" # "You have Twenty minutes remaing on this card" # "Please enter the number you wish to call" # # We could be evil and set the initial AbsoluteTimeout when the call is answered # So slower users are cut off thus not wasting time :P Like 60 seconds. # # Also to be on the more evil side you can start the AbsoluteTimeout before we ask for the number # So we would be on the users time at that point and they would have some sort of incentive # to enter a number. As you see I have it set to give them 3 trys for an X number of digits. # # TODO: # Not really sure.... This was more to prove I could do it. # Fix the error checking... its far from graceful now. # Write monthly cron to clean db and remove old pins. # Do a happy dance? # # mad propz to citats for Asterisk::AGI perl modules. # use Asterisk::AGI; use DBI; # Config options %MYSQL = ( hostname => "localhost", username => "asdf", password => "asdf", database => "asteriskdb" ); $dbh = DBI->connect("dbi:mysql:$MYSQL{database}:$MYSQL{hostname}","$MYSQL{username}","$MYSQL{password}") || die("Couldn't connect to database!\n"); # # We should throw an error down the channel and take care of it gracefully # $AGI = new Asterisk::AGI; my %input = $AGI->ReadParse(); my $target = 0; my $try = 0; # Watch out for loops they will make you dizzy. while(length($pin) != 8 || $try < 3) { $pin = $AGI->get_data("card-number", "10000", "8"); $units = check_pin($pin); if($units eq undef) { # $try++; # we could do an invalid pin warning here... :P } else { # reset try because we want to make sure we try to get a valid # X digit number from the user.. its set at 7 now.. but you can # change that to say 11. # $try = 0; $timeout = $units * 60; # use the pin as the account code so we can track this $AGI->exec('SetAccount',$pin); $AGI->stream_file('card-balance-is'); $AGI->exec('SayDigits',$units); $AGI->stream_file('minutes'); $AGI->exec('Wait','1'); while(length($target) != 7) { $target = $AGI->get_data("extension", "10000", "7"); if($try >= 3) { $AGI->stream_file('vm-goodbye'); $AGI->hangup(); exit(0); } $try++; } $AGI->exec('AbsoluteTimeout',$timeout); # maybe a prompt saying "connecing your call" here. # this could be a config option or even dynamic depending on info associated # with the pin. Many Many options here. $AGI->exec('Dial',"ZAP/1/$target"); $AGI->hangup(); exit(0); } $try++; } # user screwed up so lets just say goodbye and let them try again later. $AGI->stream_file('vm-goodbye'); $AGI->hangup(); exit(0); sub check_pin($pin) { my $query = "SELECT units FROM pins WHERE pin='$pin' LIMIT 1"; my $sth = $dbh->prepare($query); $sth->execute || die("Couldn't exec sth2!"); # need to be graceful here also my $units = $sth->fetchrow_hashref; # # Now we subtract usage from this pin. # Lets ditch all calls under 6 seconds.. you can change this. # Also when you clean the database you need to be sure that you remove the pin from # pins database. Check TODO list above. # my $query = "SELECT SUM(CEILING(billsec/60)) AS used FROM cdr WHERE accountcode='$pin' and billsec > 6;"; my $sth = $dbh->prepare($query); $sth->execute || die("Couldn't exec sth2!"); # need to be graceful here also my $used = $sth->fetchrow_hashref; $units->{units} = $units->{units} - $used->{used}; $sth->finish; if($units->{units} > 0) { return $units->{units}; } else { return undef; } }