[Astpp-commit] SF.net SVN: astpp:[2220] trunk
Brought to you by:
darrenkw
From: <dar...@us...> - 2009-01-17 17:13:27
|
Revision: 2220 http://astpp.svn.sourceforge.net/astpp/?rev=2220&view=rev Author: darrenkw Date: 2009-01-17 17:13:20 +0000 (Sat, 17 Jan 2009) Log Message: ----------- Moved the agi files into the asterisk_apps directory. Modified Paths: -------------- trunk/Makefile Added Paths: ----------- trunk/asterisk_apps/astpp-ani-map.agi trunk/asterisk_apps/astpp-authorize.agi trunk/asterisk_apps/astpp-callback-register.agi trunk/asterisk_apps/astpp-callback.agi trunk/asterisk_apps/astpp-callingcards.agi trunk/asterisk_apps/astpp-did-map.agi trunk/asterisk_apps/astpp-ip-map.agi trunk/asterisk_apps/astpp-lcr.agi trunk/asterisk_apps/astpp-manager-variables.agi trunk/asterisk_apps/astpp-refill.agi Removed Paths: ------------- trunk/astpp-ani-map.agi trunk/astpp-authorize.agi trunk/astpp-callback-register.agi trunk/astpp-callback.agi trunk/astpp-callingcards.agi trunk/astpp-did-map.agi trunk/astpp-ip-map.agi trunk/astpp-lcr.agi trunk/astpp-manager-variables.agi trunk/astpp-refill.agi Modified: trunk/Makefile =================================================================== --- trunk/Makefile 2009-01-17 02:19:55 UTC (rev 2219) +++ trunk/Makefile 2009-01-17 17:13:20 UTC (rev 2220) @@ -63,7 +63,7 @@ install_agi: - for x in *.agi; do \ + for x in asterisk_apps/*.agi; do \ echo $$x; \ install -m 755 -o $(OWNER) -g $(GROUP) $$x $(PREFIX)$(AGIDIR); \ done Copied: trunk/asterisk_apps/astpp-ani-map.agi (from rev 2218, trunk/astpp-ani-map.agi) =================================================================== --- trunk/asterisk_apps/astpp-ani-map.agi (rev 0) +++ trunk/asterisk_apps/astpp-ani-map.agi 2009-01-17 17:13:20 UTC (rev 2220) @@ -0,0 +1,90 @@ +#!/usr/bin/perl +# +# ASTPP - Open Source Voip Billing +# +# Copyright (C) 2004, Aleph Communications +# +# Darren Wiebe (da...@al...) +# +# This program is Free Software and is distributed under the +# terms of the GNU General Public License version 2. +# +# This script is used to authenticate calls to ASTPP accounts based on pin codes in the Dialplan. +# It can be used to do wholesale SIP termination which is authenticated by a pin code that is dialed +# in front of the number to be called. +# + +use DBI; +use Asterisk::AGI; +use POSIX qw(ceil floor); +use POSIX qw(strftime); +use strict; +use vars qw(@output $verbose $SIG $astpp_db $config $AGI); +@output = ( "STDERR", "LOGFILE" ); +$verbose = 2; +require "/usr/local/astpp/astpp-common.pl"; +$AGI = new Asterisk::AGI; + +sub initialize() { + $SIG{HUP} = 'ignore_hup'; + $config = &load_config(); + $astpp_db = &connect_db( $config, @output ); + $config = &load_config_db($astpp_db,$config); +} + +sub ignore_hup { + foreach my $handle (@output) { + print $handle "HUP received\n"; + $AGI->verbose( "HUP received!\n", $verbose ); + } +} + +sub get_ani() { + my ($number) = @_; + my ($sql); + $sql = + $astpp_db->prepare( + "SELECT * FROM ani_map WHERE number = " . $astpp_db->quote($number) . " AND status IN (0,1)" ); + $sql->execute; + $AGI->verbose( "$sql\n", $verbose ); + my $anidata = $sql->fetchrow_hashref; + $sql->finish; + return $anidata; +} + +sub get_cc() { + my ($number) = @_; + my ($sql); + $sql = + $astpp_db->prepare( + "SELECT * FROM accounts WHERE cc = " . $astpp_db->quote($number) ); + $sql->execute; + $AGI->verbose( "$sql\n", $verbose ); + my $anidata = $sql->fetchrow_hashref; + $sql->finish; + return $anidata; +} +################# Program Starts Here ################################# +my ( $number, $type,$variablename ) = @ARGV; +my ( $sql, $anidata ); +&initialize; +if ( $type eq "ANI" || $type eq "PREFIX" ) { + $anidata = &get_ani($number); + $AGI->set_variable( "$variablename", "\"$anidata->{account}\"" ); + $AGI->exec( 'Set', "$variablename=$anidata->{account}" ); + if ($anidata->{context} ne "" ) { + $AGI->set_variable( 'DEST_CONTEXT', "\"$anidata->{context}\"" ); + $AGI->exec( 'Set', "DEST_CONTEXT=$anidata->{context}" ); + } else { + $AGI->set_variable( 'DEST_CONTEXT', "\"$config->{lcrcontext}\"" ); + $AGI->exec( 'Set', "DEST_CONTEXT=$config->{lcrcontext}" ); + } +} +elsif ($type eq "CC") { + $anidata = &get_cc($number); + $AGI->set_variable( "$variablename", "\"$anidata->{cc}\"" ); + $AGI->exec( 'Set', "$variablename=$anidata->{cc}" ); + $AGI->set_variable( 'DEST_CONTEXT', "\"$config->{lcrcontext}\"" ); + $AGI->exec( 'Set', "DEST_CONTEXT=$config->{lcrcontext}" ); + +} Property changes on: trunk/asterisk_apps/astpp-ani-map.agi ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:mergeinfo + Added: svn:eol-style + native Copied: trunk/asterisk_apps/astpp-authorize.agi (from rev 2218, trunk/astpp-authorize.agi) =================================================================== --- trunk/asterisk_apps/astpp-authorize.agi (rev 0) +++ trunk/asterisk_apps/astpp-authorize.agi 2009-01-17 17:13:20 UTC (rev 2220) @@ -0,0 +1,197 @@ +#!/usr/bin/perl +# +# ASTPP - Open Source Voip Billing +# +# Copyright (C) 2004, DNW Consulting +# +# Darren Wiebe (da...@dn...) +# +# This program is Free Software and is distributed under the +# terms of the GNU General Public License version 2. +############################################################ +# +# Usage-example: +# +# ; +# ; Card-number and number to dial derived from command-line. +# ; Call script with the card-number as first arg and the number +# ; to dial as the second arg. astpp-authorize will return a line containing info +# ; that will cut the call off before it goes over the users credit limit. The +# ; user can get over credit limit if they have multiple calls going at once. +# ; Presently the only way to stop that is to limit them to one call which is not +# ; a nice solution. +# ; +# ; The following variables must be set: +# ; USER1 = Username at IAX2 Provider #1 +# ; PASS1 = Password for User1 +# ; PROVIDER1 = IP address of IAX2 Provider #1 or else associate name from +# ; iax.conf +# ; +# With LCR +# [astpp] +# +# exten => _1XXXXXXXXXX,1,Set(GROUP()=${ACCOUNTCODE}) +# exten => _1XXXXXXXXXX,2,AGI(astpp-authorize.agi,${ACCOUNTCODE},${EXTEN}) +# exten => _1XXXXXXXXXX,3,GotoIf($["${CALLSTATUS}" = "0"]?60) ; Checks if account has sufficient funds +# exten => _1XXXXXXXXXX,4,GotoIf($["${CALLSTATUS}" = "1"]?70) ; Checks if the phone number exists +# exten => _1XXXXXXXXXX,5,GotoIf($["${CALLSTATUS}" = "2"]?80) ; Check if account exists +# exten => _1XXXXXXXXXX,6,GotoIf($["${GROUP_COUNT()}" > "${MAXCHANNELS}"]?90) ; Verify number of outgoing channels +# ; assigned to account. +# exten => _1XXXXXXXXXX,7,Set(GROUP(${TRUNK1}-OUTBOUND)=OUTBOUND) +# exten => _1XXXXXXXXXX,8,GotoIf($["${GROUP_COUNT(OUTBOUND@${TRUNK1}-OUTBOUND)}" > "${TRUNK1_MAXCHANNELS}"]?10) +# exten => _1XXXXXXXXXX,9,Dial(${LCRSTRING1}||${TIMELIMIT}|${OPTIONS}) +# exten => _1XXXXXXXXXX,110,Busy +# exten => _1XXXXXXXXXX,10,Set(GROUP(${TRUNK2}-OUTBOUND)=OUTBOUND) +# exten => _1XXXXXXXXXX,11,GotoIf($["${GROUP_COUNT(OUTBOUND@${TRUNK2}-OUTBOUND)}" > "${TRUNK2_MAXCHANNELS}"]?13) +# exten => _1XXXXXXXXXX,12,Dial(${LCRSTRING2}||${TIMELIMIT}|${OPTIONS}) +# exten => _1XXXXXXXXXX,113,Busy +# exten => _1XXXXXXXXXX,13,Set(GROUP(${TRUNK2}-OUTBOUND)=OUTBOUND) +# exten => _1XXXXXXXXXX,14,GotoIf($["${GROUP_COUNT(OUTBOUND@${TRUNK3}-OUTBOUND)}" > "${TRUNK3_MAXCHANNELS}"]?16) +# exten => _1XXXXXXXXXX,15,Dial(${LCRSTRING3}||${TIMELIMIT}|${OPTIONS}) +# exten => _1XXXXXXXXXX,116,Busy +# exten => _1XXXXXXXXXX,16,Set(GROUP(${TRUNK4}-OUTBOUND)=OUTBOUND) +# exten => _1XXXXXXXXXX,17,GotoIf($["${GROUP_COUNT(OUTBOUND@${TRUNK4}-OUTBOUND)}" > "${TRUNK4_MAXCHANNELS}"]?19) +# exten => _1XXXXXXXXXX,18,Dial(${LCRSTRING4}||${TIMELIMIT}|${OPTIONS}) +# exten => _1XXXXXXXXXX,119,Busy +# exten => _1XXXXXXXXXX,19,Set(GROUP(${TRUNK5}-OUTBOUND)=OUTBOUND) +# exten => _1XXXXXXXXXX,20,GotoIf($["${GROUP_COUNT(OUTBOUND@${TRUNK5})-OUTBOUND}" > "${TRUNK5_MAXCHANNELS}"]?22) +# exten => _1XXXXXXXXXX,21,Dial(${LCRSTRING5}||${TIMELIMIT}|${OPTIONS}) +# exten => _1XXXXXXXXXX,122,Busy +# exten => _1XXXXXXXXXX,22,Goto(100) +# exten => _1XXXXXXXXXX,60,Congestion ; '0' Tells them they do not have enough money +# exten => _1XXXXXXXXXX,61,Hangup +# exten => _1XXXXXXXXXX,70,Congestion '1' Bad Phone Number +# exten => _1XXXXXXXXXX,71,Hangup +# exten => _1XXXXXXXXXX,80,Congestion +# exten => _1XXXXXXXXXX,81,Hangup +# exten => _1XXXXXXXXXX,90,Congestion ; Their outgoing channel limit is full already +# exten => _1XXXXXXXXXX,91,Hangup +# exten => _1XXXXXXXXXX,100,Congestion ; No Route Available +# exten => _1XXXXXXXXXX,101,Hangup +# ; This lines are optional and would forward users to a help desk if the call did not go through. +# exten => _1XXXXXXXXXX,60,Dial(SIP/HELPDESK) ; '0' Tells them they do not have enough money +# exten => _1XXXXXXXXXX,61,Hangup +# exten => _1XXXXXXXXXX,70,Dial(SIP/HELPDESK) ; '1' Bad Phone Number +# exten => _1XXXXXXXXXX,71,Hangup +# exten => _1XXXXXXXXXX,80,Dial(SIP/HELPDESK) +# exten => _1XXXXXXXXXX,81,Hangup + +use DBI; +use Asterisk::AGI; +use strict; +use vars qw(@output $config $astpp_db $verbosity $AGI); +use Locale::gettext_pp qw(:locale_h); +require "/usr/local/astpp/astpp-common.pl"; +$ENV{LANGUAGE} = "en"; # de, es, br - whatever +print STDERR "Interface language is set to: " . $ENV{LANGUAGE} . "\n"; +bindtextdomain( "astpp", "/usr/local/share/locale" ); +textdomain("astpp"); +$verbosity = 2; +@output = ("STDERR"); +$AGI = new Asterisk::AGI; + +################# Programs start here ####################################### +my ( $accountcode, $phoneno ) = @ARGV; +my ( $maxlength, $maxmins,$callstatus ); +$AGI->set_variable( 'ASTPP', '1' ); +$AGI->verbose( "$accountcode, $phoneno", $verbosity ); +$config = &load_config(); +$astpp_db = &connect_db( $config, @output ); +$config = &load_config_db($astpp_db,$config); +my $carddata = &get_account( $astpp_db, $accountcode ); # Fetch all the account info from the db. + +if ( !$carddata->{number} ) { # Check to see if the account exists. If not then exit. + $AGI->verbose( "CALLSTATUS 2\n", $verbosity ); + $AGI->verbose( "CANNOT RETRIEVE CARD\n", $verbosity ); + $AGI->set_variable( 'CALLSTATUS', "\"2\"" ); + $AGI->exec( 'Set', "CALLSTATUS=2" ); + exit(0); +} + +if ($carddata->{dialed_modify}) { + my @regexs = split(m/,/m, $carddata->{dialed_modify}); + foreach my $regex (@regexs) { + $regex =~ s/"//g; #Strip off quotation marks + my ($grab,$replace) = split(m!/!i, $regex); # This will split the variable into a "grab" and "replace" as needed + $AGI->verbose( "Grab: $grab\n", $verbosity ) if $config->{debug} == 1; + $AGI->verbose( "Replacement: $replace\n", $verbosity ) if $config->{debug} == 1; + $AGI->verbose( "Phone Before: $phoneno\n", $verbosity ) if $config->{debug} == 1; + $phoneno =~ s/$grab/$replace/is; + $AGI->verbose( "Phone After: $phoneno\n", $verbosity ) if $config->{debug} == 1 + } + } + +print STDERR "\nFINDING LIMIT FOR: $carddata->{number}\n" if $config->{debug} == 1; +($callstatus, $maxlength) = &max_length($astpp_db, $config, $carddata, $phoneno); +my $routeinfo = &get_route( $astpp_db, $config, $phoneno, $carddata->{pricelist},$carddata ); +print STDERR "Minimum Charge on call = $routeinfo->{cost}" if $config->{debug} == 1; +my $minimumcharge = $routeinfo->{cost}; +my @reseller_list; +print STDERR "\nCALLSTATUS: $callstatus MAX_LENGTH: $maxlength\n" if $config->{debug} == 1; +while ( $carddata->{reseller} && $maxlength > 1 && $callstatus == 1) { + print STDERR "\nFINDING LIMIT FOR: $carddata->{reseller}\n" if $config->{debug} == 1; + $carddata = &get_account( $astpp_db, $carddata->{reseller} ); + push @reseller_list, $carddata->{number}; + print STDERR "ADDING $carddata->{number} to the list of resellers for this account\n" if $config->{debug} == 1; + my ($resellercallstatus, $resellermaxlength) = &max_length($astpp_db, $config, $carddata, $phoneno); + my $routeinfo = &get_route( $astpp_db, $config, $phoneno, $carddata->{pricelist},$carddata ); + if ($resellercallstatus != 1) { + $carddata->{reseller} = ""; + $callstatus = $resellercallstatus; + } elsif ($resellermaxlength < $maxlength) { + $maxlength = $resellermaxlength; + } + print STDERR "Reseller cost = $routeinfo->{cost} and minimum charge is $minimumcharge\n" if $config->{debug} == 1; + if ($resellermaxlength < 1 || $routeinfo->{cost} > $minimumcharge ) { + $AGI->verbose("Reseller call is priced too cheap! Call being barred!", $verbosity ) if $config->{debug} == 1; + $callstatus = 0; + $maxlength = 0; + } + print STDERR "\nRESELLER Max Length: $resellermaxlength\n" if $config->{debug} == 1; + print STDERR "RESELLER Call Status: $resellercallstatus\n" if $config->{debug} == 1; +} + +if ($config->{debug} == 1) { + $AGI->verbose( "PRINTING LIST OF RESELLERS FOR THIS ACCOUNT\n", $verbosity ); + foreach my $reseller (@reseller_list) { + $AGI->verbose( "RESELLER: $reseller", $verbosity ); + } +} + +$AGI->verbose( "Max Call Length: $maxlength minutes\n", $verbosity ); +$AGI->verbose( "Call Status: $callstatus\n", $verbosity ); + +if ( $maxlength <= 1 ) { + $AGI->verbose( "NOT ENOUGH CREDIT\n", $verbosity ); + $AGI->set_variable( 'CALLSTATUS', "\"0\"" ); + exit(0); +} + +# Set the timelimit as well as other variables which are needed in the dialplan. +my $timelimit = "L(" . sprintf( "%.0f", $maxlength * 60 * 1000 ) . ":60000:30000)"; +$AGI->set_variable( "\"TIMELIMIT\"", "\"$timelimit\"" ); +$AGI->set_variable( "\"OPTIONS\"", "\"Hj\"" ); +$AGI->set_variable( 'CALLSTATUS', "\"3\"" ); +$AGI->set_variable( 'MAXCHANNELS', "\"$carddata->{maxchannels}\"" ); +if ( $config->{enablelcr} == 1 ) { # Do we do LCR on our outgoing calls? If so then carry on. + $AGI->verbose( "Looking for outbound Route\n", $verbosity ); + my $routeinfo = &get_route($astpp_db,$config,$phoneno,$carddata->{pricelist},$carddata); + # Get the list of routes for the phone number. + my @outboundroutes = &get_outbound_routes( $astpp_db, $phoneno,$carddata,$routeinfo, @reseller_list ); + my $count = 1; + foreach my $route (@outboundroutes) { + $AGI->verbose( "$route->{trunk}: cost $route->{cost}\t $route->{pattern}", $verbosity ); + if ($route->{cost} > $routeinfo->{cost}) { + $AGI->verbose( "$route->{trunk}: $route->{cost} > $routeinfo->{cost}, skipping\n", $verbosity ); + } else { + my $trunkdata = &get_trunk($astpp_db, $route->{trunk}); + my $dialstring = &get_dial_string( $astpp_db, $route, $phoneno ); + $AGI->set_variable( "\"LCRTRUNKS\"", "\"$count\"" ); + $AGI->set_variable( "\"LCRSTRING$count\"", "\"$dialstring\"" ); + $AGI->set_variable( "\"TRUNK$count\"", "\"$route->{trunk}\"" ); + $AGI->set_variable( "\"TRUNK" . $count . "_MAXCHANNELS\"", "\"$trunkdata->{maxchannels}\"" ); + $count++; + } + } +} +exit(0); Property changes on: trunk/asterisk_apps/astpp-authorize.agi ___________________________________________________________________ Added: svn:executable + * Added: svn:keywords + Author Date Id Revision Added: svn:mergeinfo + Added: svn:eol-style + native Copied: trunk/asterisk_apps/astpp-callback-register.agi (from rev 2218, trunk/astpp-callback-register.agi) =================================================================== --- trunk/asterisk_apps/astpp-callback-register.agi (rev 0) +++ trunk/asterisk_apps/astpp-callback-register.agi 2009-01-17 17:13:20 UTC (rev 2220) @@ -0,0 +1,272 @@ +#!/usr/bin/perl +# +# ASTPP callfile creation +# +# Copyright (C) 2006, DNW Consulting +# +# Darren Wiebe <da...@dn...> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Contact information can be found @ www.dnwconsulting.net +# +# ANI Map Info +# Status 0 is for regular ASTPP accounts and status 1 is for calling cards +# that are ok. Status 2 is a blocked number. +# This program is used to request callbacks from ASTPP for calling cards. It's +# also used to register telephone numbers in the "ani_map" table. You can set it +# to register only by passing along "REGISTER" in the ${DESTINATION} field. Here's an +# example on how to call it. +# +# ${CARDNUMBER} = The calling card number we wish to register to. +# ${PIN} = The pin for ${CARDNUMBER} if appropriate. +# ${CALLERIDNUM} = Is the number we are calling from and will use for ANI authentication. +# This is also the number we will be called back at. +# ${DESTINATION} = The number we wish the system to call once we are authenticated. +# +# +# exten => 2,2,DeadAGI(astpp-register-card.agi,${CALLERIDNUM},${DESTINATION},${CARDNUMBER},${PIN}) +# +# +###########################################################################` + +use POSIX qw(ceil floor); +use POSIX qw(strftime); +use DBI; +use Asterisk::AGI; +use strict; +require "/usr/local/astpp/astpp-common.pl"; +use vars qw($vars $verbose $astpp_db $AGI $config @output $sound); +$verbose = 2; +@output = ("STDERR"); +$AGI = new Asterisk::AGI; +$config = &load_config(); +$astpp_db = &connect_db( $config, @output ); +$config = &load_config_db( $astpp_db, $config ); +my $brand = $AGI->get_variable("BRAND"); +if ($brand) { + my $brandinfo = &get_cc_brand($astpp_db, $brand); + if ($brandinfo->{reseller}) { + $config = &load_config_db_reseller($astpp_db,$config,$brandinfo->{reseller}); + } + $config = &load_config_db_brand($astpp_db,$config,$brand); +} +$sound = &define_sounds($astpp_db); +$SIG{HUP} = 'ignore_hup'; +my $verbosity = 2; +my $input_timeout = 15000; #How long do we wait for input? Specified in MS + +sub ignore_hup { + foreach my $handle (@output) { + print $handle "HUP received\n"; + } +} + +sub get_ani() { + my ($number) = @_; + my ($sql); + $sql = + $astpp_db->prepare( + "SELECT * FROM ani_map WHERE number = " . $astpp_db->quote($number) ); + $sql->execute; + $AGI->verbose( "$sql\n", $verbose ); + my $anidata = $sql->fetchrow_hashref; + $sql->finish; + return $anidata; +} + +###################################################################### +# Beginning of Program +###################################################################### +my ( $callerid, $destination, $cardnumber, $pin ) = @ARGV; +$AGI->answer(); +my ( $clidnumber, $retries ); +while ( !$clidnumber && $retries < $config->{card_retries} ) { + my $answer = $AGI->get_data( $sound->{number_to_register}, $input_timeout ); + if ( $answer == 1 ) { + $clidnumber = $callerid; + } elsif ( $answer > 1 ) { + $clidnumber = $answer; + } else { + $retries++; + } +} +if ( $retries > $config->{card_retries} ) { + $AGI->stream_file($sound->{goodbye}); + exit(0); +} + +my $numberdata = &get_ani($clidnumber); + +if ( $numberdata->{status} == 2 ) { #This number is in our "blocked" list. + $AGI->stream_file($sound->{badnumber}); + $AGI->stream_file($sound->{goodbye}); + exit(0); +} elsif ( !$numberdata ) { + my $cardinfo; + $cardinfo = &get_callingcard( $astpp_db, $cardnumber, $config ) if $cardnumber; + my $retries = 0; + while ( $cardinfo->{status} != 1 && $retries < $config->{card_retries} ) { + my $cardnum = $AGI->get_data( $sound->{cardnumber}, $input_timeout ); + $cardinfo = &get_callingcard( $astpp_db, $cardnum, $config ); + $AGI->verbose( "ASTPP Number: $cardnum ", $verbosity ) + if $config->{debug} == 1; + $AGI->verbose( "ASTPP Number Status: $cardinfo->{status}", $verbosity ) + if $config->{debug} == 1; + if ( $cardinfo->{status} != 1 ) { + $AGI->stream_file($sound->{cardnumber_incorrect}); + } + $retries++; + } + if ( !$cardinfo->{status} ) { + my $sql = + "INSERT INTO ani_map (number,status) VALUES (" + . $astpp_db->quote($clidnumber) . ", 0)"; + $AGI->verbose( "SQL $sql", $verbosity ) + if $config->{debug} == 1; + $astpp_db->do($sql); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); + } elsif ( $cardinfo->{status} != 1 ) { + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); + } + if ( $pin != $cardinfo->{pin} ) { + $retries = 0; + while ( $cardinfo->{pin} != $pin && $retries < $config->{pin_retries} ) { + $pin = $AGI->get_data( $sound->{pin}, $input_timeout ); + if ( $cardinfo->{pin} != $pin ) { + $AGI->stream_file($sound->{pin_incorrect}); + } + $retries++; + } + } + if ( $pin != $cardinfo->{pin} ) { + my $sql = + "INSERT INTO ani_map (number,status) VALUES (" + . $astpp_db->quote($clidnumber) . ", 0)"; + $AGI->verbose( "SQL $sql", $verbosity ) + if $config->{debug} == 1; + $astpp_db->do($sql); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); + } + my $cardstatus = &check_card_status( $astpp_db, $cardinfo ); + # This subroutine returns the status of the card: + if ( $cardstatus == 1 ) { + $AGI->stream_file($sound->{card_inuse}); + $AGI->stream_file($sound->{goodbye}); + } elsif ( $cardstatus == 2 ) { + $AGI->stream_file($sound->{card_has_expired}); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + } elsif ( $cardstatus == 3 ) { + $AGI->stream_file($sound->{card_is_empty}); + $AGI->hangup(); + } + my $register = $AGI->get_data( $sound->{register_ani}, $input_timeout ); + if ( $register == 1 ) { + my $sql = + "INSERT INTO ani_map (number,account,status) VALUES (" + . $astpp_db->quote($clidnumber) . ", " + . $astpp_db->quote( $cardinfo->{cardnumber} ) . ", 0)"; + $AGI->verbose( "SQL $sql", $verbosity ) + if $config->{debug} == 1; + $astpp_db->do($sql); + } +} else { + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); +} + +$numberdata = &get_ani($clidnumber); +if ( $numberdata->{status} == 1 && $destination ne "REGISTER" ) +{ #This number is registered to a calling card. + my $cardinfo = &get_callingcard( $astpp_db, $numberdata->{account}, $config ); + my $cardstatus = &check_card_status( $astpp_db, $cardinfo ); + # This subroutine returns the status of the card: + if ( $cardstatus == 1 ) { + $AGI->stream_file($sound->{card_inuse}); + $AGI->stream_file($sound->{goodbye}); + } elsif ( $cardstatus == 2 ) { + $AGI->stream_file($sound->{card_has_expired}); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + } elsif ( $cardstatus == 3 ) { + $AGI->stream_file($sound->{card_is_empty}); + $AGI->hangup(); + } elsif ( $cardstatus == 0 ) { + my $retries = 0; + my $desination; + while ( !$destination && $retries < $config->{number_retries} ) { + my $answer = $AGI->get_data( $sound->{where_to_call}, $input_timeout ); + if ( $answer == 1 ) { + $destination = $clidnumber; + } elsif ( $answer > 1 ) { + $destination = $answer; + } else { + $retries++; + } + } + if ( $retries > $config->{number_retries} ) { + $AGI->stream_file($sound->{goodbye}); + exit(0); + } + + # If we get this far then it means that the account is good to go. + my @variables; + my $brandinfo = &get_cc_brand( $astpp_db, $cardinfo->{brand} ); + if ($brandinfo->{reseller}) { + $config = &load_config_db_reseller($astpp_db,$config,$brandinfo->{reseller}); + } + $config = &load_config_db_brand($astpp_db,$config,$cardinfo->{brand}); + my $rateinfo = + &get_route( $astpp_db, $config, $destination, $brandinfo->{pricelist}, + $cardinfo ); + my $connectsurcharge->{name} = "CONNECTSURCHARGE"; + $connectsurcharge->{value} = $rateinfo->{connectcost}; + my $perminutesurcharge->{name} = "PERMINUTESURCHARGE"; + $perminutesurcharge->{value} = $rateinfo->{cost}; + $destination->{name} = "DESTINATION"; + $destination->{value} = $destination; + $pin->{name} = "PIN"; + $pin->{value} = $pin; + push @variables, $connectsurcharge; + push @variables, $perminutesurcharge; + push @variables, $destination; + push @variables, $pin; + &perform_callout( + $destination, + $config->{lcrcontext}, + $config->{callout_accountcode}, + $config->{maxretries}, + $config->{waittime}, + $config->{retrytime}, + $config->{clidname}, + $config->{clidnumber}, + $config->{callingcards_callback_context}, + $config->{callingcards_callback_extension}, + @variables + ); + $AGI->stream_file($sound->{callback_performed}); + $AGI->stream_file($sound->{goodbye}); + exit(0); + } +} + +exit(0); Property changes on: trunk/asterisk_apps/astpp-callback-register.agi ___________________________________________________________________ Added: svn:executable + * Added: svn:mergeinfo + Copied: trunk/asterisk_apps/astpp-callback.agi (from rev 2218, trunk/astpp-callback.agi) =================================================================== --- trunk/asterisk_apps/astpp-callback.agi (rev 0) +++ trunk/asterisk_apps/astpp-callback.agi 2009-01-17 17:13:20 UTC (rev 2220) @@ -0,0 +1,278 @@ +#!/usr/bin/perl +# +# ASTPP callfile creation +# +# Copyright (C) 2006, DNW Consulting +# +# Darren Wiebe <da...@dn...> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Contact information can be found @ www.dnwconsulting.net +# +# ANI Map Info +# Status 0 is for regular ASTPP accounts and status 1 is for calling cards +# that are ok. Status 2 is a blocked number. +# This program is used to request callbacks from ASTPP for calling cards. It's +# also used to register telephone numbers in the "ani_map" table. You can set it +# to register only by passing along "REGISTER" in the ${DESTINATION} field. Here's an +# example on how to call it. +# +# ${CARDNUMBER} = The calling card number we wish to register to. +# ${PIN} = The pin for ${CARDNUMBER} if appropriate. +# ${CALLERIDNUM} = Is the number we are calling from and will use for ANI authentication. +# This is also the number we will be called back at. +# ${DESTINATION} = The number we wish the system to call once we are authenticated. +# +# +# exten => 2,2,DeadAGI(astpp-register-card.agi,${CALLERIDNUM},${DESTINATION},${CARDNUMBER},${PIN}) +# +# +###########################################################################` + +use POSIX qw(ceil floor); +use POSIX qw(strftime); +use DBI; +use Asterisk::AGI; +use strict; +require "/usr/local/astpp/astpp-common.pl"; +use vars qw($vars $verbose $brandinfo $astpp_db $AGI $config @output $sound); +$verbose = 2; +@output = ("STDERR"); +$AGI = new Asterisk::AGI; + +sub initialize() { +$config = &load_config(); +$astpp_db = &connect_db( $config, @output ); +$config = &load_config_db( $astpp_db, $config ); +my $brand = $AGI->get_variable("BRAND"); +if ($brand) { + $brandinfo = &get_cc_brand($astpp_db, $brand); + if ($brandinfo->{reseller}) { + $config = &load_config_db_reseller($astpp_db,$config,$brandinfo->{reseller}); + } + $config = &load_config_db_brand($astpp_db,$config,$brand); +} +} +$sound = &define_sounds($astpp_db); +$SIG{HUP} = 'ignore_hup'; +my $verbosity = 2; +my $input_timeout = 15000; #How long do we wait for input? Specified in MS + +sub ignore_hup { + foreach my $handle (@output) { + print $handle "HUP received\n"; + } +} + +sub get_ani() { + my ($number) = @_; + my ($sql); + my $tmp = "SELECT * FROM ani_map WHERE number = " . $astpp_db->quote($number); + $sql = + $astpp_db->prepare($tmp); + $sql->execute; + $AGI->verbose( "$tmp\n", $verbose ); + my $anidata = $sql->fetchrow_hashref; + $sql->finish; + return $anidata; +} + +###################################################################### +# Beginning of Program +###################################################################### +my ( $callerid, $destination, $cardnumber, $pin ) = @ARGV; +$AGI->answer(); +my ( $clidnumber, $retries ); +&initialize(); +$retries = 0; +$clidnumber = $callerid if $destination ne "REGISTER"; +while ( !$clidnumber && $retries < $config->{card_retries} ) { + my $answer = $AGI->get_data( $sound->{number_to_register}, $input_timeout ); + if ( $answer == 1 ) { + $clidnumber = $callerid; + } elsif ( $answer > 1 ) { + $clidnumber = $answer; + } else { + $retries++; + } +} +if ( $retries > $config->{card_retries} ) { + $AGI->stream_file($sound->{goodbye}); + exit(0); +} + +my $numberdata = &get_ani($clidnumber); + +if ( $numberdata->{status} == 2 ) { #This number is in our "blocked" list. + $AGI->stream_file($sound->{badnumber}); + $AGI->stream_file($sound->{goodbye}); + exit(0); +} elsif ( !$numberdata->{number} ) { + my $cardinfo; + $cardinfo = &get_callingcard( $astpp_db, $cardnumber, $config ) if $cardnumber; + my $retries = 0; + while ( $cardinfo->{status} != 1 && $retries < $config->{card_retries} ) { + my $cardnum = $AGI->get_data( $sound->{cardnumber}, $input_timeout ); + $cardinfo = &get_callingcard( $astpp_db, $cardnum, $config ); + $AGI->verbose( "ASTPP Number: $cardnum ", $verbosity ) + if $config->{debug} == 1; + $AGI->verbose( "ASTPP Number Status: $cardinfo->{status}", $verbosity ) + if $config->{debug} == 1; + if ( $cardinfo->{status} != 1 ) { + $AGI->stream_file($sound->{cardnumber_incorrect}); + } + $retries++; + } + if ( !$cardinfo->{status} ) { + my $sql = + "INSERT INTO ani_map (number,status) VALUES (" + . $astpp_db->quote($clidnumber) . ", 2)"; + $AGI->verbose( "SQL $sql", $verbosity ) + if $config->{debug} == 1; + $astpp_db->do($sql); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); + } elsif ( $cardinfo->{status} != 1 ) { + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); + } + if ( $pin != $cardinfo->{pin} ) { + $retries = 0; + while ( $cardinfo->{pin} != $pin && $retries < $config->{pin_retries} ) { + $pin = $AGI->get_data( $sound->{pin}, $input_timeout ); + if ( $cardinfo->{pin} != $pin ) { + $AGI->stream_file($sound->{pin_incorrect}); + } + $retries++; + } + } + if ( $pin != $cardinfo->{pin} ) { + my $sql = + "INSERT INTO ani_map (number,status) VALUES (" + . $astpp_db->quote($clidnumber) . ", 2)"; + $AGI->verbose( "SQL $sql", $verbosity ) + if $config->{debug} == 1; + $astpp_db->do($sql); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); + } + my $cardstatus = &check_card_status( $astpp_db, $cardinfo ); + # This subroutine returns the status of the card: + if ( $cardstatus == 1 ) { + $AGI->stream_file($sound->{card_inuse}); + $AGI->stream_file($sound->{goodbye}); + } elsif ( $cardstatus == 2 ) { + $AGI->stream_file($sound->{card_has_expired}); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + } elsif ( $cardstatus == 3 ) { + $AGI->stream_file($sound->{card_is_empty}); + $AGI->hangup(); + } + my $register = $AGI->get_data( $sound->{register_ani}, $input_timeout ); + if ( $register == 1 ) { + my $sql = + "INSERT INTO ani_map (number,account,status) VALUES (" + . $astpp_db->quote($clidnumber) . ", " + . $astpp_db->quote( $cardinfo->{cardnumber} ) . ", 1)"; + $AGI->verbose( "SQL $sql", $verbosity ) + if $config->{debug} == 1; + $astpp_db->do($sql); + } +} else { + if ($destination eq "REGISTER") { + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + exit(0); + } +} + +$numberdata = &get_ani($clidnumber); +if ( $numberdata->{status} == 1 && $destination ne "REGISTER" ) +{ #This number is registered to a calling card. + my $cardinfo = &get_callingcard( $astpp_db, $numberdata->{account}, $config ); + my $cardstatus = &check_card_status( $astpp_db, $cardinfo ); + # This subroutine returns the status of the card: + if ( $cardstatus == 1 ) { + $AGI->stream_file($sound->{card_inuse}); + $AGI->stream_file($sound->{goodbye}); + } elsif ( $cardstatus == 2 ) { + $AGI->stream_file($sound->{card_has_expired}); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + } elsif ( $cardstatus == 3 ) { + $AGI->stream_file($sound->{card_is_empty}); + $AGI->hangup(); + } elsif ( $cardstatus == 0 ) { + my $retries = 0; + my $destination; + while ( !$destination && $retries < $config->{number_retries} ) { + my $answer = $AGI->get_data( $sound->{where_to_call}, $input_timeout ); + if ( $answer == 1 ) { + $destination = $clidnumber; + } elsif ( $answer > 1 ) { + $destination = $answer; + } else { + $retries++; + } + } + if ( $retries > $config->{number_retries} ) { + $AGI->stream_file($sound->{goodbye}); + exit(0); + } + + # If we get this far then it means that the account is good to go. + my @variables; + my $brandinfo = &get_cc_brand( $astpp_db, $cardinfo->{brand} ); + if ($brandinfo->{reseller}) { + $config = &load_config_db_reseller($astpp_db,$config,$brandinfo->{reseller}); + } + $config = &load_config_db_brand($astpp_db,$config,$cardinfo->{brand}); + if ($destination =~ m/\d\d\d\d\d\d\d\d\d\d/) { + $destination = "1" . $destination; + } + my $rateinfo = + &get_route( $astpp_db, $config, $destination, $brandinfo->{pricelist}, + $cardinfo ); + $AGI->stream_file($sound->{callback_performed}); + $AGI->stream_file($sound->{goodbye}); + $AGI->hangup(); + sleep 15; # This is to give the customer time to hang their phone up. + my %variables = ( CONNECTSURCHARGE => $rateinfo->{connectcost}, + PERMINUTESURCHARGE => $rateinfo->{cost}, + CARDNUMBER => $cardinfo->{cardnumber}, + PIN => $cardinfo->{pin}); + my $ActionID = &perform_callout( + $astpp_db, $config, + $destination, + $config->{lcrcontext}, + $config->{callout_accountcode}, + $config->{maxretries}, + $config->{waittime}, + $config->{retrytime}, + $config->{clidname}, + $config->{clidnumber}, + $config->{callingcards_callback_context}, + $config->{callingcards_callback_extension}, + %variables + ); + exit(0); + } +} + +exit(0); Property changes on: trunk/asterisk_apps/astpp-callback.agi ___________________________________________________________________ Added: svn:executable + * Added: svn:mergeinfo + Copied: trunk/asterisk_apps/astpp-callingcards.agi (from rev 2218, trunk/astpp-callingcards.agi) =================================================================== --- trunk/asterisk_apps/astpp-callingcards.agi (rev 0) +++ trunk/asterisk_apps/astpp-callingcards.agi 2009-01-17 17:13:20 UTC (rev 2220) @@ -0,0 +1,774 @@ +#!/usr/bin/perl +# +# ASTPP - Open Source Voip Billing +# +# Copyright (C) 2004, Aleph Communications +# +# Darren Wiebe (da...@al...) +# +# This program is Free Software and is distributed under the +# terms of the GNU General Public License version 2. +# +# Sample Configuration +# [astpp-callingcards] +# exten => s,1,Answer +# exten => s,n,DeadAGI(astpp-callingcards.agi) +# exten => s,n,GotoIf($["${NEWCALL}" = "1"]?60) +# exten => s,n,GotoIf($["${BALANCE}" = "1"]?70) +# exten => s,n,Hangup +# exten => s,60,DeadAGI(astpp-callingcards.agi,${CARDNUMBER}) +# exten => s,n,Hangup +# exten => s,70,DeadAGI(astpp-callingcards.agi,${CARDNUMBER},BALANCE) +# +############################################################################# +use DBI; +use Asterisk::AGI; +use POSIX qw(ceil floor); +use POSIX qw(strftime); +use Time::HiRes qw( gettimeofday tv_interval ); +use ASTPP; +#use strict; + +use vars qw(@output $verbosity $AGI $config $astpp_db $cdr_db + $ASTPP %stats %input $cc $pricelistinfo $brandinfo $sound @resellerlist $brand); +$stats{start_time} = [gettimeofday]; +$cc = 0; +$verbosity = 1; +require "/usr/local/astpp/astpp-common.pl"; + +$AGI = new Asterisk::AGI; +$AGI->set_variable( 'ASTPP', '1' ); +$ASTPP = ASTPP->new; +$ASTPP->set_verbosity($verbosity); #Tell ASTPP debugging how verbose we want to be. +#$ASTPP->set_asterisk_agi($AGI); + +sub initialize() { + $SIG{HUP} = 'ignore_hup'; # We ignore the HUP command that Asterisk sends on a call hangup. + $config = &load_config(); # Load /var/lib/astpp/astpp-config.conf + $astpp_db = &connect_db( $config, @output ); + $ASTPP->set_astpp_db($astpp_db); + $config = &load_config_db($astpp_db,$config); + $brand = $AGI->get_variable("BRAND"); + if ($brand && $brand ne "") { + my $brandinfo = &get_cc_brand($astpp_db, $brand); + if ($brandinfo->{reseller}) { + $config = &load_config_db_reseller($astpp_db,$config,$brandinfo->{reseller}); + } + $config = &load_config_db_brand($astpp_db,$config,$brand); + } + $cdr_db = &cdr_connect_db( $config, @output ); + $ASTPP->set_cdr_db($cdr_db); + $sound = &define_sounds($astpp_db); +} + +=over 4 + +=item bgplay([$filename1, $filename2, ..., $filenameN], $timeout, $maxdigit) + +Executes Asterisk Command "Background filename1&filename2...filenameN" And +Asterisk AGI Command "Get Data filename timeout, maxdigit". + +This command instructs Asterisk to play the given list of sound files and wait for user input in form of DTMF, +upto 'maxdigit' (optional) till timeout (optional) happens. Files extension must not be used in the filename +because Asterisk will find the most appropriate file type. + +Example: bgplay(["demo-echotest", "echo-test"], 10, 4); +Plays files "demo-echotest" and "echo-test" and waits for 10 seconds for user to enter 4 dight DTMF. + +Returns: -1 on error or hangup, +0 if timeout for user input happens, +or user input upto maxdigit value (default 1) + +=cut + +sub bgplay(\@;$$) +{ + my $files = shift; + my $timeout = shift||1; + my $maxdigit= shift||1; + + my $x = shift(@{$files}); + foreach (@{$files}) { + $x .= '&' . $_; + } + + my $res = $AGI->exec("Background $x"); + + if($res > 0) { + $res -= 48; + } + + if($maxdigit > 1) { + $res .= $AGI->get_data("silence/1", ($timeout * 1000), ($maxdigit - 1)); + } + + return $res; +} + +sub ignore_hup { + $ASTPP->debug( debug => "HUP received", + verbosity => $verbosity); +} + +sub set_in_use() { # Set the "inuse" flag on the calling cards. This prevents multiple people from +# using the same card. + my ( $cardinfo, $status ) = @_; + my $sql; + $sql = + "UPDATE callingcards SET inuse = " + . $astpp_db->quote($status) + . " WHERE cardnumber = " + . $astpp_db->quote( $cardinfo->{cardnumber} ); + $astpp_db->do($sql); +} + +sub check_card() { # Check a few things before saying the card is ok. + my ($cardinfo) = @_; + my $now = $astpp_db->selectall_arrayref("SELECT NOW() + 0")->[0][0]; + $ASTPP->debug( debug => "Present Time: $now", + verbosity => $verbosity ); + $ASTPP->debug( debug => "Expiration Date: $cardinfo->{expiry}", + verbosity => $verbosity ); + $ASTPP->debug( debug => "Valid for Days: $cardinfo->{validfordays}", + verbosity => $verbosity ); + $ASTPP->debug( debug => "First Use: $cardinfo->{firstused}", + verbosity => $verbosity ); + if ( $cardinfo->{inuse} != 0 ) { # If the card is in use then say so and leave. + $AGI->stream_file($sound->{card_inuse}); + $AGI->stream_file($sound->{goodbye}); + &leave($cardinfo); + } + &set_in_use( $cardinfo, 1 ); # Now the card is in use and nobody else can use it. + if ( $cardinfo->{firstused} eq "00000000000000" || $cardinfo->{firstused} eq "0000-00-00 00:00:00" ) { # If "firstused" has not been set, we will set it now. + # At the same time we will update the "maint_day" field. + my $sql = + "UPDATE callingcards SET firstused = NOW() WHERE cardnumber = " + . $astpp_db->quote( $cardinfo->{cardnumber} ); + $ASTPP->debug( debug => $sql, + verbosity => $verbosity ); + $astpp_db->do($sql); + $sql = + "UPDATE callingcards SET maint_day = DATE_ADD(NOW(), INTERVAL " + . "$cardinfo->{maint_fee_days} day) WHERE cardnumber = " + . $astpp_db->quote( $cardinfo->{cardnumber} ); + $ASTPP->debug( debug => $sql, + verbosity => $verbosity ); + if ( $cardinfo->{maint_fee_days} > 0 ) { + $astpp_db->do($sql); + } +# $cardinfo = &get_callingcard( $astpp_db, $cardinfo->{cardnumber} ); + if ( $cardinfo->{validfordays} > 0 ) { #Check if the card is set to expire and deal with that as appropriate. + my $sql = +"UPDATE callingcards SET expiry = DATE_ADD(NOW(), INTERVAL " + . " $cardinfo->{validfordays} day) WHERE cardnumber = " + . $astpp_db->quote( $cardinfo->{cardnumber} ); + $ASTPP->debug( debug => $sql, + verbosity => $verbosity ); + $astpp_db->do($sql); + $cardinfo = &get_callingcard( $astpp_db, $cardinfo->{cardnumber}, $config ); + } + } + elsif ( $cardinfo->{validfordays} > 0 ) { + my $now = $astpp_db->selectall_arrayref("SELECT NOW() + 0")->[0][0]; + $cardinfo->{expiry} = $astpp_db->selectall_arrayref("SELECT DATE_FORMAT('$cardinfo->{expiry}' , '\%Y\%m\%d\%H\%i\%s')")->[0][0]; + if ( $now >= $cardinfo->{expiry} ) { + my $sql = + "UPDATE callingcards SET status = 2 WHERE cardnumber = " + . $astpp_db->quote( $cardinfo->{cardnumber} ); + $ASTPP->debug( debug => $sql, + verbosity => $verbosity ); + $astpp_db->do($sql); + $sql = + "DELETE FROM ani_map WHERE account = " + . $astpp_db->quote( $cardinfo->{cardnumber} ); + $ASTPP->debug( debug => $sql, + verbosity => $verbosity ); + $astpp_db->do($sql); + $AGI->stream_file($sound->{card_has_expired}); + $AGI->stream_file($sound->{goodbye}); + &leave($cardinfo); + } + } + $ASTPP->debug( debug => "Present Time: $now", + verbosity => $verbosity ); + $ASTPP->debug( debug => "Expiration Date: $cardinfo->{expiry}", + verbosity => $verbosity ); + $ASTPP->debug( debug => "Valid for Days: $cardinfo->{validfordays}", + verbosity => $verbosity ); + $ASTPP->debug( debug => "First Use: $cardinfo->{firstused}", + verbosity => $verbosity ); +} + +sub tell_cost() { #Say how much the call will cost. + my ( $numberinfo, $pricelistinfo, $cardinfo ) = @_; + if ( $pricelistinfo->{markup} ne "" && $pricelistinfo->{markup} != 0 ) { + $ASTPP->debug( debug => "Adding Markup of $pricelistinfo->{markup}", + verbosity => $verbosity); + $numberinfo->{connectcost} = + $numberinfo->{connectcost} * + ( ( $pricelistinfo->{markup} / 10000 ) + 1 ); + $numberinfo->{cost} = + $numberinfo->{cost} * ( ( $pricelistinfo->{markup} / 10000 ) + 1 ); + } + if ($config->{calling_cards_rate_announce} == 1) { + if ( $numberinfo->{cost} > 0 ) { + $AGI->stream_file($sound->{call_will_cost}); +# $AGI->say_number(ceil($numberinfo->{cost} / 100)); +# $AGI->stream_file($sound->{currency}); + my @call_cost = split(/\./, ($numberinfo->{cost} / 100)); + $AGI->say_number(@call_cost[0]); + if (@call_cost[1]) { + $AGI->stream_file($sound->{point}); + $AGI->say_number(@call_cost[1]); + $AGI->stream_file($sound->{sub_currency}); + } + $AGI->stream_file($sound->{per}); + $AGI->stream_file($sound->{minute}); + } + if ( $numberinfo->{connectcost} > 0 ) { + $AGI->stream_file($sound->{a_connect_charge}); + $AGI->say_number(ceil($numberinfo->{connectcost} / 100)); + $AGI->stream_file($sound->{sub_currency}); + $AGI->stream_file($sound->{will_apply}); + } + } +} + +sub timelimit() { #Calculate and say the time limit. + my ( $numberinfo, $pricelistinfo, $cardinfo, $phoneno ) = @_; + my ( $connectfee, $cost, $timelimit, $available, $maxtime, $balance ); +# if ( $numberinfo->{connectfee} > 0 ) { +# $connectfee = $numberinfo->{connectfee} / 100; +# } +# if ( $numberinfo->{cost} > 0 ) { +# $cost = $numberinfo->{cost} / 100; +# } + # Timelimit is in seconds + if ($cc == 0) { +# $available = +# ( ( $cardinfo->{value} - $cardinfo->{used} ) / 100 ) - $numberinfo->{connectfee}; + $available = + ( $cardinfo->{value} - $cardinfo->{used} ) - $numberinfo->{connectfee}; + $ASTPP->debug( debug => "FUNDS AVAILABLE: $available", + verbosity => $verbosity); + } elsif ( $cc == 1 ) { + $balance = &accountbalance( $astpp_db, $cardinfo->{number} ); + $balance = ($balance * -1) + ( $cardinfo->{credit_limit}); + $available = ($balance - $numberinfo->{connectfee}) / 100; + } + if ( $available > 0 && $numberinfo->{cost} > 0 ) { + $timelimit = ( ( $available / $numberinfo->{cost} ) * 60 ); + } + elsif ( $available >= 0 && $numberinfo->{cost} <= 0 ) { + $timelimit = $config->{callingcards_max_length}; + } + if ( $timelimit > $config->{callingcards_max_length} ) { + $timelimit = $config->{callingcards_max_length}; + } + $ASTPP->debug( debug => "TIMELIMIT: $timelimit", + verbosity => $verbosity); + if ($brandinfo->{reseller} ne "") { + ASTPP->debug( debug => "THIS BRAND BELONGS TO $brandinfo->{reseller}!", + verbosity => $verbosity); + my $carddata = &get_account( $astpp_db, $brandinfo->{reseller} ); +# ($callstatus, $maxlength) = &max_length($astpp_db, $config, $carddata, $phoneno); +# my $routeinfo = &get_route( $astpp_db, $config, $phoneno, $carddata->{pricelist},$carddata ); + my $minimumcharge = $numberinfo->{cost}; + my $belongs_to_reseller = 1; + while ( $belongs_to_reseller == 1 ) { + $ASTPP->debug( debug => "FINDING LIMIT FOR: $carddata->{reseller}", + verbosity => $verbosity); + push @resellerlist, $carddata->{number}; + $ASTPP->debug( debug => "PUSHING $carddata->{number} ONTO THE LIST OF RESELLERS", + verbosity => $verbosity); + my ($resellercallstatus, $resellermaxlength) = &max_length($astpp_db, $config, $carddata, $phoneno); + my $routeinfo = &get_route( $astpp_db, $config, $phoneno, $carddata->{pricelist}, $carddata, "CC" ); + if ($resellercallstatus != 1) { + $carddata->{reseller} = ""; + $timelimit = 0; + } elsif ($resellermaxlength < $timelimit / 60) { + $timelimit = $resellermaxlength * 60; + } + if ($resellermaxlength < 1 || $routeinfo->{cost} > $minimumcharge ) { + $carddata->{reseller} = ""; + $timelimit = 0; + } + $ASTPP->debug( debug => "RESELLER Max Length: $resellermaxlength", + verbosity => $verbosity); + $ASTPP->debug( debug => "RESELLER Call Status: $resellercallstatus", + verbosity => $verbosity); + if ($carddata->{reseller} && $carddata->{reseller} ne "") { + $carddata = &get_account( $astpp_db, $carddata->{reseller} ); + } else { + $belongs_to_reseller = 0; + } + } + } else { + $ASTPP->debug( debug => "THIS BRAND DOES NOT BELONG TO A RESELLER!", + verbosity => $verbosity); + } + $ASTPP->debug( debug =>"TIMELIMIT: $timelimit", verbosity => $verbosity); + my $minutes = $timelimit / 60; + $ASTPP->debug( debug => "MINUTES: $minutes", verbosity => $verbosity); + if ($minutes > 0 && $config->{calling_cards_timelimit_announce} == 1) { + my $minutes = $timelimit / 60; + $minutes = sprintf( "%.0f", $minutes ); + $AGI->stream_file($sound->{call_will_last}); + if ( $minutes == 1 ) { + $AGI->say_number($minutes); + $AGI->stream_file($sound->{minute}); + } + elsif ( $minutes > 1 ) { + $AGI->say_number($minutes); + $AGI->stream_file($sound->{minutes}); + } + } + elsif ($minutes < 1) { + $AGI->stream_file($sound->{not_enough_credit}); + $AGI->stream_file($sound->{goodbye}); + &leave($cardinfo); + } + $maxtime = $timelimit * 1000; + + + $timelimit = "\|30\|HL($maxtime:60000:30000)\|Hgj"; + $ASTPP->debug( debug => "Available: $available", + verbosity => $verbosity ); + $ASTPP->debug( debug => "Balance: $balance", verbosity => $verbosity ); + $ASTPP->debug( debug => "Max Time: $maxtime", verbosity => $verbosity ); + return $timelimit; +} + +sub say_balance() { #Calculate and say the card balance. + my ($cardinfo) = @_; + my ( $connectfee, $cost, $included, $sub_balance, $balance, $main_balance ); + if ($cc == 0 ) { + $balance = $cardinfo->{value} - $cardinfo->{used}; + } elsif ($cc ==1) { + $balance = &accountbalance( $astpp_db, $cardinfo->{number} ); + $balance = ($balance * -1) + ( $cardinfo->{credit_limit} ); + } + if ( $balance > 0 ) { + $balance = $balance / 10000; + $balance = sprintf( "%.2f", $balance ); + $sub_balance = substr( $balance, -2, 2 ); + $main_balance = substr( $balance, 0, -2 ); + my $interrupt = &bgplay([$sound->{card_has_balance_of}], 0, 1); +# my $interrupt = $AGI->get_data($sound->{card_has_balance_of},0,1); + if (!$interrupt || $interrupt eq "" || $interrupt == 0) { + if ( $main_balance == 1 ) { + $AGI->say_number($main_balance); + $AGI->stream_file($sound->{main_currency}); + } + elsif ( $main_balance > 1 ) { + $AGI->say_number($main_balance); + $AGI->stream_file($sound->{main_currency_plural}); + } + if ( $sub_balance == 1 ) { + $AGI->say_number($sub_balance); + $AGI->stream_file($sound->{sub_currency}); + } + elsif ( $sub_balance > 1 ) { + $AGI->say_number($sub_balance); + $AGI->stream_file($sound->{sub_currency_plural}); + } + } + } + else { + $AGI->stream_file($sound->{card_is_empty}); + $AGI->stream_file($sound->{goodbye}); + &leave($cardinfo); + } + return $balance; +} + +sub update_balance() { #Update the available credit on the calling card. + my ( $cardinfo, $charge ) = @_; + my $sql = + "UPDATE callingcards SET used = " + . $astpp_db->quote( ($charge) + $cardinfo->{used} ) + . " WHERE cardnumber = " + . $astpp_db->quote( $cardinfo->{cardnumber} ); + $astpp_db->do($sql); +} + +sub write_asterisk_cdr() { #Write the cdr record to the asterisk cdr db. This is done so we get a record of the call the callingcard user placed. + # This is especially important for resellers and calling cards. + my ( + $reseller, $clid, $destination, $status, + $callstart, $answeredtime, $dstchannel, $lastapp, $dialedtime, $uniqueid, $asterisk_time, $cdr_db + ) + = @_; + my ($sql); + if (!$status) {$status = gettext("N/A"); } + $sql = "INSERT INTO cdr (calldate,dst,clid,dstchannel,lastapp,duration,billsec,disposition,accountcode,uniqueid) VALUES(" + . $astpp_db->quote($asterisk_time) . ", " + . $astpp_db->quote($destination) . ", " + . $astpp_db->quote($clid) . ", " + . $astpp_db->quote($dstchannel) . ", " + . $astpp_db->quote($lastapp) . ", " + . $astpp_db->quote($dialedtime) . ", " + . $astpp_db->quote($answeredtime) . ", " + . $astpp_db->quote($status) . ", " + . $astpp_db->quote( $reseller ) . ", " + . $astpp_db->quote( $uniqueid ) . ")"; + $cdr_db->do($sql); + $AGI->set_variable( "\"ANSWEREDTIME\"", "0" ); + $AGI->set_variable( "\"DIALEDTIME\"", "0" ); + $AGI->set_variable( "\"DIALSTATUS\"", "NO ANSWER" ); +} + + +sub write_cdr() { # Write the callingcardcdr record if this is a calling card. + my ( + $cardinfo, $clid, $destination, $status, + $callstart, $charge, $answeredtime + ) + = @_; + my ($sql); + if (!$status) {$status = gettext("N/A"); } + $sql = +"INSERT INTO callingcardcdrs (cardnumber,clid,destination,disposition,callstart,seconds," + . "debit) VALUES (" + . $astpp_db->quote( $cardinfo->{cardnumber} ) . ", " + . $astpp_db->quote($clid) . ", " + . $astpp_db->quote($destination) . ", " + . $astpp_db->quote($status) . ", " + . $astpp_db->quote($callstart) . ", " + . $astpp_db->quote($answeredtime) . ", " + . $astpp_db->quote($charge) . ")"; + $astpp_db->do($sql); + $ASTPP->debug( debug => "$sql", verbosity => $verbosity ); + $ASTPP->debug( debug => "Resetting CDR Variables", verbosity => $verbosity ); + $AGI->set_variable( "\"ANSWEREDTIME\"", "0" ); + $AGI->set_variable( "\"DIALEDTIME\"", "0" ); + $AGI->set_variable( "\"DIALSTATUS\"", "NO ANSWER" ); +} + +sub dialout() { # Rig up the LCR stuff and do the outbound dialing. + # If a call does not go through we give the user the option + # of trying again. + my ( $destination, $timelimit, $numberinfo, $pricelistinfo, $cardinfo, $brandinfo ) = + @_; + my ( $status, $count, $increment ); + $ASTPP->debug( debug => "Looking for outbound Route", verbosity => $verbosity ); + my @outboundroutes = &get_outbound_routes( $astpp_db, $destination,$cardinfo,$numberinfo, @resellerlist ); + $count = @outboundroutes; + if ( $count == 0 ) { + $ASTPP->debug(debug => "NO OUTBOUND ROUTES FOUND!", verbosity => $verbosity ); + my $order = $AGI->get_data( $sound->{noanswer}, $config->{calling_cards_general_input_timeout}, 1 ); + if ( $order != 1 ) { + &write_cdr( $cardinfo, "", $destination, gettext("NO Route Found"), "", 0, 0 ); + &leave($cardinfo); + } + } + $count = 0; + foreach my $route (@outboundroutes) { + my $trunk = &get_dial_string( $astpp_db, $route, $destination ); + my $dialstring = $trunk . $timelimit; + my $callstart = localtime(); + my ($accountcode); + $callstart = &prettytimestamp if $cc == 1; + $AGI->set_variable( "\"LCRSTRING$count\"", + "\"$config->{callingcardowner}\"" ); + $AGI->exec( 'Set', "TRUNK_NAME$count=$route->{trunk}" ); + if ($brandinfo->{reseller} ne "" ) { + $AGI->exec( 'Set', "accountcode=$brandinfo->{reseller}" ); + $accountcode = $brandinfo->{reseller}; + + } else { + $AGI->exec( 'Set', "accountcode=$config->{callingcardowner}" ); + $accountcode = $config->{callingcardowner}; + } + my $res = $AGI->exec("DIAL $dialstring"); + my $status = $AGI->get_variable("DIALSTATUS"); + my $answeredtime = $AGI->get_variable("ANSWEREDTIME"); + $stats{answered_time} = $AGI->get_variable("ANSWEREDTIME"); + my $dialedtime = $AGI->get_variable("DIALEDTIME"); + my $uniqueid = $AGI->get_variable("UNIQUEID"); + $stats{uniqueid} = $AGI->get_variable("UNIQUEID"); + my $clid = $AGI->get_variable("CALLERID(all)"); + my $asterisk_time = &prettytimestamp; + $ASTPP->debug( debug => "CALL STATUS $status", verbosity => 1); + $ASTPP->debug( debug => "ANSWERED TIME $answeredtime", verbosity => $verbosity); + $ASTPP->debug( debug => "Account CC?: $cc", verbosity => $verbosity); + + if ( ( $status != ~/CHANUNAVAIL/ ) && ( $status != ~/CONGESTION/ ) ) { + if ( $status =~ /BUSY/ ) { + $ASTPP->debug( debug => "CALL BUSY", verbosity => $verbosity ); + my $order = $AGI->get_data( $sound->{busy}, $config->{calling_cards_general_input_timeout},1 ); + if ( $order != 1 ) { + &write_cdr( $cardinfo, $clid, $destination, $status, + $callstart, 0, 0, $uniqueid ) + if $cc == 0; + &write_account_cdr( $astpp_db, $cardinfo->{number}, 0, + $destination, $callstart, 0, $uniqueid, $clid ) + if $cc == 1; + &write_asterisk_cdr( $accountcode, $clid, $destination, $status, + $callstart, $answeredtime, $trunk, "CallingCards", $dialedtime, $uniqueid . "a", $asterisk_time, $cdr_db); + &leave($cardinfo); + } else { + push @outboundroutes, $route; + } + } + elsif ( $status =~ /NOANSWER/ ) { + $ASTPP->debug(debug=> "NO ANSWER", verbosity => $verbosity ); + my $order = $AGI->get_data( $sound->{noanswer}, $config->{calling_cards_general_input_timeout},1 ); + if ( $order != 1 ) { + &write_cdr( $cardinfo, $clid, $destination, $status, + $callstart, 0, 0, $uniqueid ) + if $cc == 0; + &write_account_cdr( $astpp_db, $cardinfo->{number}, 0, + $destination, $callstart, 0, $uniqueid, $clid ) + if $cc == 1; + &write_asterisk_cdr( $accountcode, $clid, $destination, $status, + $callstart, $answeredtime, $trunk, "CallingCards", $dialedtime, $uniqueid . "a", $asterisk_time, $cdr_db); + &leave($cardinfo); + } else { + push @outboundroutes, $route; + } + } + elsif ( $status =~ /ANSWER/ || $answeredtime > 0) { + $ASTPP->debug( debug => "CALL ANSWERED", verbosity => $verbosity ); + my $increment; + if ( $numberinfo->{inc} > 0 ) { + $increment = $numberinfo->{inc}; + } + else { + $increment = $pricelistinfo->{inc}; + } + $ASTPP->debug( debug => "$numberinfo->{connectcost}, $numberinfo->{cost}, $answeredtime, $increment, $numberinfo->{includedseconds}", + verbosity => $verbosity); + my $charge = &calc_call_cost( + $numberinfo->{connectcost}, $numberinfo->{cost}, + $answeredtime, $increment, + $numberinfo->{includedseconds} + ); + $ASTPP->debug( debug => "Cost $charge ", verbosity => $verbosity ); + if ($cardinfo->{minute_fee_pennies} > 0) { + $charge = (($cardinfo->{minute_fee_pennies} * 100) + $charge) if $cardinfo->{timeused} + $answeredtime => $cardinfo->{minute_fee_minutes}; + } + if ($cardinfo->{min_length_pennies} > 0 && ($cardinfo->{min_length_minutes}*60) > $answeredtime) { + $charge = (($cardinfo->{min_length_pennies} * 100) + $charge); + } + if ( $cc == 0 ) { + &write_cdr( + $cardinfo, $clid, $destination, $status, + $callstart, $charge, $answeredtime, $uniqueid + ); + &write_asterisk_cdr( $accountcode, $clid, $destination, "ANSWERED", + $callstart, $answeredtime, $trunk, "CallingCards", $dialedtime, $uniqueid . "a", $asterisk_time, $cdr_db); + &update_balance( $cardinfo, $charge ); + $astpp_db->do("UPDATE callingcards SET timeused = " + . $astpp_db->quote($cardinfo->{timeused} + $answeredtime) + . " WHERE cardnumber = " + . $astpp_db->quote($cardinfo->{cardnumber})); + } + elsif ( $cc == 1 ) { + my $status = + &write_account_cdr( $astpp_db, $cardinfo->{number}, + $charge, $destination, $callstart, $answeredtime, $uniqueid, $clid ); + &write_asterisk_cdr( $accountcode, $clid, $destination, $status, + $callstart, $answeredtime, $trunk, "CallingCards", $dialedtime, $uniqueid . "a", $asterisk_time, $cdr_db); + $ASTPP->debug( debug => $status, verbosity => $verbosity ); + } + $AGI->stream_file($sound->{call_completed}); + &leave($cardinfo); + } + elsif ( $status =~ /CANCEL/ ) { + $ASTPP->debug( debug => "CALL CANCELLED", verbosity => $verbosity ); + $AGI->stream_file($sound->{cancelled}) if $config->{calling_cards_cancelled_prompt} == 1; + &write_cdr( $cardinfo, $clid, $destination, $status, $callstart, 0, + 0, $uniqueid ) + if $cc == 0; + &write_account_cdr( $astpp_db, $cardinfo->{number}, 0, + $destination, $callstart, 0, $uniqueid, $clid ) + if $cc == 1; + &write_asterisk_cdr( $accountcode, $clid, $destination, $status, + $callstart, $answeredtime, $trunk, "CallingCards", $dialedtime, $uniqueid . "a", $asterisk_time, $cdr_db); + &leave($cardinfo); + } + else { + $ASTPP->debug( debug => "ERROR - ERROR - ERROR", verbosity => $verbosity ); + my $order = $AGI->get_data( $sound->{noanswer}, $config->{calling_cards_general_input_timeout},1 ); + if ( $order != 1 ) { + &write_cdr( $cardinfo, $clid, $destination, $status, + $callstart, 0, 0, $uniqueid ) + if $cc == 0; + &write_account_cdr( $astpp_db, $cardinfo->{number}, 0, + $destination, $callstart, 0, $uniqueid, $clid ) + if $cc == 1; + &write_asterisk_cdr( $accountcode, $clid, $destination, $status, + $callstart, $answeredtime, $trunk, "CallingCards", $dialedtime, $uniqueid . "a", $asterisk_time, $cdr_db); + &leave($cardinfo); + } + } + } + } +} + +sub leave() { # Prepare everything and then leave the calling card app. + my ($cardinfo) = @_; + my ($whatnow); + my $retries = 0; + &set_in_use( $cardinfo, 0 ) if $cc == 0; + while ($retries < ... [truncated message content] |