Files
ViciDialSVN/agc_2-X/trunk/agi/cm_dnc.agi
T
mattf 446b80719a Added filtering to AGI processes to help prevent DID SQL injection attacks
Added nanpa filtering log viewing to new NANPA updating process
Fixed span order in vicidial.php
Fixed issue with list webform overrides in agent interface
other small variable filtering fixes

git-svn-id: svn://192.168.202.10@2023 3d104415-ff17-0410-8863-d5cf3c621b8a
2013-09-26 01:27:15 +00:00

363 lines
11 KiB
Perl

#!/usr/bin/perl
#
# cm_dnc.agi version 2.8
#
# Designed to work with Cell Menus to allow setting of a number as DNC or NI
# This script is meant as a replacecment for the agi-VDADinbound_NI_DNC_CIDlookup.agi
# script. It is designed to work easily in the Call Menu framework, it plays no
# audio itself, and it has more options.
#
# Flag Options:
# 1- run as DNC status or NI status (Default=NI)
# 2- default to insert into the vicidial_dnc table for DNC selections (Default=YES)
# 3- campaign to take dnc settings from(overrides option 2)
# 4- call menu option to send the call to after executing (Default=B)
# 5- if option 3 is used, search for lead in campaign lists or whole system(CAMP or SYS) (Default=SYS)
#
# example of what to put in the AGI entry for a Call Menu AGI route:
# cm_dnc.agi,DNC---YES---TESTCAMP---B---CAMP
#
# Copyright (C) 2013 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
#
# changes:
# 121109-1623 - First draft
# 130108-1817 - Changes for Asterisk 1.8 compatibility
# 130925-1825 - Added variable filter to prevent DID SQL injection attack
#
$script = 'cm_dnc.agi';
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year = ($year + 1900);
$mon++;
if ($mon < 10) {$mon = "0$mon";}
if ($mday < 10) {$mday = "0$mday";}
if ($hour < 10) {$hour = "0$hour";}
if ($min < 10) {$min = "0$min";}
if ($sec < 10) {$sec = "0$sec";}
$now_date_epoch = time();
$now_date = "$year-$mon-$mday $hour:$min:$sec";
$start_time=$now_date;
$CIDdate = "$mon$mday$hour$min$sec";
$tsSQLdate = "$year$mon$mday$hour$min$sec";
$SQLdate = "$year-$mon-$mday $hour:$min:$sec";
$SQLdateBEGIN = $SQLdate;
# default path to astguiclient configuration file:
$PATHconf = '/etc/astguiclient.conf';
open(conf, "$PATHconf") || die "can't open $PATHconf: $!\n";
@conf = <conf>;
close(conf);
$i=0;
foreach(@conf)
{
$line = $conf[$i];
$line =~ s/ |>|\n|\r|\t|\#.*|;.*//gi;
if ( ($line =~ /^PATHhome/) && ($CLIhome < 1) )
{$PATHhome = $line; $PATHhome =~ s/.*=//gi;}
if ( ($line =~ /^PATHlogs/) && ($CLIlogs < 1) )
{$PATHlogs = $line; $PATHlogs =~ s/.*=//gi;}
if ( ($line =~ /^PATHagi/) && ($CLIagi < 1) )
{$PATHagi = $line; $PATHagi =~ s/.*=//gi;}
if ( ($line =~ /^PATHweb/) && ($CLIweb < 1) )
{$PATHweb = $line; $PATHweb =~ s/.*=//gi;}
if ( ($line =~ /^PATHsounds/) && ($CLIsounds < 1) )
{$PATHsounds = $line; $PATHsounds =~ s/.*=//gi;}
if ( ($line =~ /^PATHmonitor/) && ($CLImonitor < 1) )
{$PATHmonitor = $line; $PATHmonitor =~ s/.*=//gi;}
if ( ($line =~ /^VARserver_ip/) && ($CLIserver_ip < 1) )
{$VARserver_ip = $line; $VARserver_ip =~ s/.*=//gi;}
if ( ($line =~ /^VARDB_server/) && ($CLIDB_server < 1) )
{$VARDB_server = $line; $VARDB_server =~ s/.*=//gi;}
if ( ($line =~ /^VARDB_database/) && ($CLIDB_database < 1) )
{$VARDB_database = $line; $VARDB_database =~ s/.*=//gi;}
if ( ($line =~ /^VARDB_user/) && ($CLIDB_user < 1) )
{$VARDB_user = $line; $VARDB_user =~ s/.*=//gi;}
if ( ($line =~ /^VARDB_pass/) && ($CLIDB_pass < 1) )
{$VARDB_pass = $line; $VARDB_pass =~ s/.*=//gi;}
if ( ($line =~ /^VARDB_port/) && ($CLIDB_port < 1) )
{$VARDB_port = $line; $VARDB_port =~ s/.*=//gi;}
$i++;
}
if (!$VARDB_port) {$VARDB_port='3306';}
if (!$AGILOGfile) {$AGILOGfile = "$PATHlogs/agiout.$year-$mon-$mday";}
use DBI;
use Asterisk::AGI;
$AGI = new Asterisk::AGI;
$dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_user", "$VARDB_pass")
or die "Couldn't connect to database: " . DBI->errstr;
### Grab Server values from the database
$stmtA = "SELECT agi_output FROM servers where server_ip = '$VARserver_ip';";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
$rec_count=0;
while ($sthArows > $rec_count)
{
$AGILOG = '0';
@aryA = $sthA->fetchrow_array;
$DBagi_output = $aryA[0];
if ($DBagi_output =~ /STDERR/) {$AGILOG = '1';}
if ($DBagi_output =~ /FILE/) {$AGILOG = '2';}
if ($DBagi_output =~ /BOTH/) {$AGILOG = '3';}
$rec_count++;
}
$sthA->finish();
### begin parsing run-time options ###
if (length($ARGV[0])>1)
{
if ($AGILOG) {$agi_string = "Perl Environment Dump:"; &agi_output;}
$i=0;
while ($#ARGV >= $i)
{
$args = "$args $ARGV[$i]";
if ($AGILOG) {$agi_string = "$i|$ARGV[$i]"; &agi_output;}
$i++;
}
### list of command-line array arguments:
@ARGV_vars = split(/---/, $ARGV[0]);
$new_status = $ARGV_vars[0];
$dnc_default = $ARGV_vars[1];
$campaign_id = $ARGV_vars[2];
$next_step = $ARGV_vars[3];
$camp_sys = $ARGV_vars[4];
}
if (length($new_status) < 1)
{$new_status = 'NI';}
if (length($dnc_default) < 2)
{$dnc_default = 'YES';}
if (length($next_step) < 1)
{$next_step = 'B';}
if (length($camp_sys) < 2)
{$camp_sys = 'SYS';}
$|=1;
while(<STDIN>)
{
chomp;
last unless length($_);
if ($AGILOG)
{
if (/^agi_(\w+)\:\s+(.*)$/)
{
$AGI{$1} = $2;
}
}
if (/^agi_context\:\s+(.*)$/) {$context = $1;}
if (/^agi_uniqueid\:\s+(.*)$/) {$unique_id = $1; $uniqueid = $unique_id;}
if (/^agi_channel\:\s+(.*)$/) {$channel = $1;}
if (/^agi_extension\:\s+(.*)$/) {$extension = $1;}
if (/^agi_type\:\s+(.*)$/) {$type = $1;}
if (/^agi_callerid\:\s+(.*)$/) {$callerid = $1;}
if (/^agi_calleridname\:\s+(.*)$/) {$calleridname = $1;}
$callerid =~ s/\'|\\\\|\\\|\\|\\;|\\\;|\;|;//gi;
$calleridname =~ s/\'|\\\\|\\\|\\|\\;|\\\;|\;|;//gi;
$extension =~ s/\'|\"|\\\\|\\\|\\|\\;|\\\;|\;|;//gi;
if ( ($callerid =~ /\".*\"/) && ( (!$calleridname) or ($calleridname =~ /unknown/) ) )
{
$calleridname = $callerid;
$calleridname =~ s/\<\d\d\d\d\d\d\d\d\d\d\>//gi;
$calleridname =~ s/\"|\" //gi;
}
$callerid =~ s/\D//gi;
$calleridname =~ s/unknown//gi;
if ( (!$callerid) or ($callerid =~ /unknown/) )
{$callerid = $calleridname;}
if (length($callerid)>0) {$phone_number = $callerid;}
else {$phone_number = '';}
if (length($calleridname)>0) {$VLcomments = $calleridname;}
else {$VLcomments = '';}
if (length($callerid)<10) {$callerid = $parked_by;}
if (length($pin)>0) {$callerid = $pin;}
}
foreach $i (sort keys %AGI)
{
if ($AGILOG) {$agi_string = " -- $i = $AGI{$i}"; &agi_output;}
}
if ($AGILOG) {$agi_string = "AGI Variables: |$unique_id|$channel|$extension|$type|$callerid|"; &agi_output;}
# if campaign is used and selected for search, find the lists in the campaign
$listSQL='';
if ( (length($campaign_id) > 0) && ($camp_sys =~ /CAMP/) )
{
$cbc=0;
$SlistsSQL='';
$stmtA = "SELECT list_id FROM vicidial_lists where campaign_id='$campaign_id' limit 1000;";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
if ($AGILOG) {$agi_string = "$sthArows|$stmtA|"; &agi_output;}
while ($sthArows > $cbc)
{
@aryA = $sthA->fetchrow_array;
$SlistsSQL .= "'$aryA[0]',";
$cbc++;
}
$sthA->finish();
chop($SlistsSQL);
if (length($SlistsSQL)<3)
{$SlistsSQL = "''";}
if (length($SlistsSQL)>1)
{$listSQL = "and list_id IN($SlistsSQL)";}
}
### Gather the lead IDs of the leads with this phone number ###
$stmtA= "SELECT lead_id from vicidial_list where phone_number='$phone_number' $listSQL;";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
if ($AGILOG) {$agi_string = "$sthArows|$stmtA|"; &agi_output;}
$g=0;
$SleadsSQL='';
while ($sthArows > $g)
{
@aryA = $sthA->fetchrow_array;
$SleadsSQL .= "'$aryA[0]',";
$g++;
}
$sthA->finish();
chop($SleadsSQL);
### process for NI path
if ($new_status =~ /NI/) # set the phone_number to NI
{
if ($g > 0)
{
### update all records for the phone_number in vicidial_list to NI (Not Interested)
$stmtA = "UPDATE vicidial_list SET status='NI' where lead_id IN($SleadsSQL);";
$affected_rows = $dbhA->do($stmtA);
if ($AGILOG) {$agi_string = "$affected_rows|$stmtA|"; &agi_output;}
}
}
### process for DNC path
if ($new_status =~ /DNC/) # set the phone_number to DNC
{
if ($g > 0)
{
### update all records for the phone_number in vicidial_list to NI (Not Interested)
$stmtA = "UPDATE vicidial_list SET status='DNC' where lead_id IN($SleadsSQL);";
$affected_rows = $dbhA->do($stmtA);
if ($AGILOG) {$agi_string = "$affected_rows|$stmtA|"; &agi_output;}
}
if (length($campaign_id)>1)
{
### Grab DNC settings from campaign
$stmtA = "SELECT use_internal_dnc,use_campaign_dnc FROM vicidial_campaigns where campaign_id = '$campaign_id';";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
@aryA = $sthA->fetchrow_array;
$use_internal_dnc = $aryA[0];
$use_campaign_dnc = $aryA[1];
$sthA->finish();
if ( ($use_internal_dnc =~ /Y|AREACODE/) && ($dnc_default =~ /YES/) )
{
### add the number to the vicidial_dnc table
$stmtA = "INSERT IGNORE INTO vicidial_dnc SET phone_number='$phone_number';";
$affected_rows = $dbhA->do($stmtA);
if ($AGILOG) {$agi_string = "$affected_rows|$stmtA|"; &agi_output;}
}
if ($use_campaign_dnc =~ /Y|AREACODE/)
{
### add the number to the vicidial_campaign_dnc table
$stmtA = "INSERT IGNORE INTO vicidial_campaign_dnc SET phone_number='$phone_number',campaign_id='$campaign_id';";
$affected_rows = $dbhA->do($stmtA);
if ($AGILOG) {$agi_string = "$affected_rows|$stmtA|"; &agi_output;}
}
}
else
{
if ($dnc_default =~ /YES/)
{
### add the number to the vicidial_dnc table
$stmtA = "INSERT INTO vicidial_dnc SET phone_number='$phone_number';";
$affected_rows = $dbhA->do($stmtA);
if ($AGILOG) {$agi_string = "$affected_rows|$stmtA|"; &agi_output;}
}
}
}
$dbhA->disconnect();
if ($AGILOG) {$agi_string = "exiting the cm_dnc app, transferring call to $next_step:$context |$phone_number|"; &agi_output;}
print "SET CONTEXT $context\n";
$result = <STDIN>;
checkresult($result);
print "SET EXTENSION $next_step\n";
$result = <STDIN>;
checkresult($result);
print "SET PRIORITY 1\n";
$result = <STDIN>;
checkresult($result);
exit;
sub agi_output
{
if ($AGILOG >=2)
{
### open the log file for writing ###
open(Lout, ">>$AGILOGfile")
|| die "Can't open $AGILOGfile: $!\n";
print Lout "$now_date|$script|$agi_string\n";
close(Lout);
}
### send to STDERR writing ###
if ( ($AGILOG == '1') || ($AGILOG == '3') )
{print STDERR "$now_date|$script|$agi_string\n";}
$agi_string='';
}
sub checkresult
{
my ($res) = @_;
my $retval;
$tests++;
chomp $res;
if ($res =~ /^200/)
{
$res =~ /result=(-?\d+)/;
if (!length($1))
{
# print STDERR "FAIL ($res)\n";
$fail++;
}
else
{
# print STDERR "PASS ($1)\n";
$pass++;
}
}
else
{
# print STDERR "FAIL (unexpected result '$res')\n";
$fail++;
}
}