#!/usr/bin/perl # # park_call_IVR_example.agi version 2.4 # # NOTE: this script is an example of how you can use a custom AGI script with # the new Park Call IVR feature in campaigns. You will most likely need to # significantly alter this script to suit your specific needs # # Defined in the Park Call AGI IVR field of a campaign, this script will ask # customer for their ID and then populate it in the vicidial_list table and then # send the call back to the agent. If the customer enters nothing X number of # times then the call can be kicked out to a separate in-group # # Here is a list of the variables that you can set: # 1. Language - default: en (English), other options are es-Spanish, fr-French # 2. First prompt - default: please_enter_id_number # 3. You-Entered prompt - default: you-entered # 4. Confirmation prompt - default: confirm_id_number # 5. Thank you prompt - default: auth-thankyou # 6. Invalid prompt - default: buzz # 7. Attempts before kick-out - default: 2 # 8. Kick-out prompt - default: outside-transfer # 9. Kick-out In-Group # # Example Park Call AGI IVR field: # park_call_IVR_example.agi|en---please_enter_id_number---you-entered---confirm_id_number---auth-thankyou---buzz---2---outside-transfer---TEST_IN # # NOTE: For Asterisk 1.8 and higher, use a comma instead of a pipe in the Park Call AGI IVR field # # Copyright (C) 2010 Matt Florell LICENSE: AGPLv2 # # changes: # 101004-1132 - First build # $script = 'park_call_IVR_example.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"; $S='*'; # default path to astguiclient configuration file: $PATHconf = '/etc/astguiclient.conf'; open(conf, "$PATHconf") || die "can't open $PATHconf: $!\n"; @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,ext_context 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]; $ext_context = $aryA[1]; 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]); $language = $ARGV_vars[0]; $first_prompt = $ARGV_vars[1]; $you_entered_prompt = $ARGV_vars[2]; $confirmation_prompt = $ARGV_vars[3]; $thank_you_prompt = $ARGV_vars[4]; $invalid_prompt = $ARGV_vars[5]; $kickout_attempts = $ARGV_vars[6]; $kickout_prompt = $ARGV_vars[7]; $kickout_ingroup = $ARGV_vars[8]; } if (length($language)<1) {$language='en';} if (length($first_prompt)<1) {$first_prompt='please_enter_id_number';} if (length($you_entered_prompt)<1) {$you_entered_prompt='you-entered';} if (length($confirmation_prompt)<1) {$confirmation_prompt='confirm_id_number';} if (length($thank_you_prompt)<1) {$thank_you_prompt='auth-thankyou';} if (length($invalid_prompt)<1) {$invalid_prompt='buzz';} if (length($kickout_attempts)<1) {$kickout_attempts='2';} if (length($kickout_prompt)<1) {$kickout_prompt='outside-transfer';} $|=1; while() { chomp; last unless length($_); if ($AGILOG) { if (/^agi_(\w+)\:\s+(.*)$/) { $AGI{$1} = $2; } } if (/^agi_uniqueid\:\s+(.*)$/) {$unique_id = $1;} if (/^agi_channel\:\s+(.*)$/) {$channel = $1;} if (/^agi_extension\:\s+(.*)$/) {$extension = $1;} if (/^agi_type\:\s+(.*)$/) {$type = $1;} if (!$fullCID) # if no fullCID sent { if (/^agi_callerid\:\s+(.*)$/) {$callerid = $1;} if (/^agi_calleridname\:\s+(.*)$/) {$calleridname = $1;} if ( $calleridname =~ /\"/) {$calleridname =~ s/\"//gi;} if ( (!$callerid) or ($callerid =~ /unknown/) or ( ($calleridname =~ /\d\d\d\d\d\d\d\d\d/) && (length($calleridname) > 16) ) ) {$callerid = $calleridname;} if ( ($callerid =~ / /) && (length($callerid) > 20) ) {$callerid =~ s/ .*//gi;} ### allow for ANI being sent with the DNIS "*3125551212*9999*" if ($extension =~ /^\*\d\d\d\d\d\d\d\d\d\d\*/) { $callerid = $extension; $callerid =~ s/\*\d\d\d\d\*$//gi; $callerid =~ s/^\*//gi; $extension =~ s/^\*\d\d\d\d\d\d\d\d\d\d\*//gi; $extension =~ s/\*$//gi; } $calleridname = $callerid; } } if ($AGILOG) {$agi_string = "AGI Environment Dump:"; &agi_output;} 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 ($AGILOG) {$agi_string = "PARKED CALL IVR STARTED"; &agi_output;} $stmtA = "UPDATE parked_channels set channel_group='$callerid' where server_ip='$VARserver_ip' and channel='$channel';"; if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} $affected_rows = $dbhA->do($stmtA); if ($AGILOG) {$agi_string = "-- Park record updated: |$affected_rows| |$callerid|$channel|$VARserver_ip"; &agi_output;} $VACcount=0; $VAC_campaign_id=''; $VAC_call_type=''; $VAC_extension=''; $VLAcount=0; $VLA_user=''; $VLA_campaign_id=''; $VCcount=0; $MOHfiles=0; $stmtA = "SELECT campaign_id,call_type,extension,phone_number,lead_id FROM vicidial_auto_calls where callerid='$callerid';"; $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; $VACcount=$sthA->rows; if ($VACcount > 0) { @aryA = $sthA->fetchrow_array; $VAC_campaign_id = $aryA[0]; $VAC_call_type = $aryA[1]; $VAC_extension = $aryA[2]; $VAC_phone_number = $aryA[3]; $VAC_lead_id = $aryA[4]; if ($AGILOG) {$agi_string = "-- VAC Call Found: |$callerid|$VAC_campaign_id|$VAC_call_type|$VAC_extension|$VAC_phone_number|$VAC_lead_id|"; &agi_output;} } $sthA->finish(); if ($VACcount > 0) { $stmtA = "SELECT user,campaign_id,server_ip,conf_exten FROM vicidial_live_agents where callerid='$callerid';"; $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; $VLAcount=$sthA->rows; if ($VLAcount > 0) { @aryA = $sthA->fetchrow_array; $VLA_user = $aryA[0]; $VLA_campaign_id = $aryA[1]; $VLA_server_ip = $aryA[2]; $VLA_conf_exten = $aryA[3]; } $sthA->finish(); if ($VLAcount > 0) { if ($AGILOG) {$agi_string = "-- Starting Gather Data: |$VLA_user|$VLA_campaign_id|$kickout_attempts| |$callerid|"; &agi_output;} ### BEGIN prompt for customer ID number ($customer_id_number) ### $customer_id_number=''; $variable=''; $confirmation=0; $confirmation_chances=0; $collect_digits='20'; $ms_delay='8000'; $variable_entry_prompt = $first_prompt; $confirm_entry_prompt = $you_entered_prompt; while ( ($confirmation_chances < $kickout_attempts) && ($confirmation < 1) ) { $entry_chances=0; while ( ($entry_chances < $kickout_attempts) && (length($variable) < 1) ) { $entry_chances++; &customer_variable_gather; $customer_id_number = $variable; if ( (length($customer_id_number) < 1) || (length($customer_id_number) > 20) ) { if ($AGILOG) {$agi_string = "-- CUSTOMER ID GATHER FAIL : |$customer_id_number|"; &agi_output;} $audio_file = $invalid_prompt; &play_audio; $variable=''; } } $confirmation_chances++; if ( (length($customer_id_number) > 0) || (length($customer_id_number) <= 20) ) { $audio_file = $confirm_entry_prompt; &play_audio; $AGI->say_digits("$variable"); &confirm_entry; if ($ANSWER_confirm > 1) {$variable='';} if ( ($ANSWER_confirm > 0) && ($ANSWER_confirm < 2) ) {$confirmation=1;} } else { if ($entry_chances >= $kickout_attempts) {$confirmation_chances=$kickout_attempts;} } } ### customer ID confirmed, update in vicidial_list and tag agent for update if ($confirmation > 0) { $stmtA = "UPDATE vicidial_list set vendor_lead_code='$customer_id_number' where lead_id='$VAC_lead_id';"; $affected_rows = $dbhA->do($stmtA); if ($AGILOG) {$agi_string = "-- Lead record updated: |$affected_rows| |$callerid|$stmtA|"; &agi_output;} $stmtA = "UPDATE vicidial_live_agents set external_update_fields='1',external_update_fields_data='vendor_lead_code' where user='$VLA_user';"; $affected_rows = $dbhA->do($stmtA); if ($AGILOG) {$agi_string = "-- Agent data update triggered: |$affected_rows| |$callerid|$stmtA|"; &agi_output;} } ### no valid customer ID received, send customer to kickout in-group if defined if ( ($confirmation < 1) && (length($kickout_ingroup)>0) ) { $audio_file = $kickout_prompt; &play_audio; sleep(1); $stmtA = "UPDATE vicidial_live_agents set external_transferconf='LOCAL_CLOSER---$kickout_ingroup' where user='$VLA_user';"; $affected_rows = $dbhA->do($stmtA); if ($AGILOG) {$agi_string = "-- AGI Done, kick-out, sending call to kickout ingroup: |$affected_rows| |$callerid|$kickout_ingroup|$stmtA"; &agi_output;} } ### END prompt for customer ID number ($customer_id_number) ### else { ### send API command to have agent grab call back $AGI->stream_file('sip-silence'); $AGI->stream_file('sip-silence'); $AGI->stream_file('sip-silence'); $AGI->stream_file('sip-silence'); $stmtA = "UPDATE vicidial_live_agents set external_park='GRAB_IVR_CUSTOMER' where user='$VLA_user';"; $affected_rows = $dbhA->do($stmtA); if ($AGILOG) {$agi_string = "-- AGI Done, sending call back to agent: |$affected_rows| |$callerid|$stmtA|$VLA_user|"; &agi_output;} } } } else { if ($AGILOG) {$agi_string = "-- Call Not Found in vicidial_auto_calls: |$callerid|"; &agi_output;} } $dbhA->disconnect(); $AGI->stream_file('sip-silence'); if ($AGILOG) {$agi_string = "-- Exiting Park Call IVR: |$callerid|"; &agi_output;} 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++; } } sub leading_zero($) { $_ = $_[0]; s/^(\d)$/0$1/; s/^(\d\d)$/0$1/; return $_; } # End of the leading_zero() routine. ### play audio, check for existing other language if defined ### sub play_audio { if ($language =~ /es/) { $file_extension_gsm='.gsm'; $file_extension_wav='.wav'; $audio_suffix='_es'; if ( (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_gsm")) || (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_wav")) ) {$donothing=1;} else {$audio_suffix='';} } elsif ($language =~ /fr/) { $file_extension_gsm='.gsm'; $file_extension_wav='.wav'; $audio_suffix='_fr'; if ( (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_gsm")) || (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_wav")) ) {$donothing=1;} else {$audio_suffix='';} } else {$audio_suffix='';} $AGI->stream_file("$audio_file$audio_suffix"); } ##### BEGIN collect the customer variable ############################################### sub customer_variable_gather { $interrupt_digit=''; $audio_file = "$variable_entry_prompt"; if ($language =~ /es/) { $file_extension_gsm='.gsm'; $file_extension_wav='.wav'; $audio_suffix='_es'; if ( (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_gsm")) || (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_wav")) ) {$donothing=1;} else {$audio_suffix='';} } elsif ($language =~ /fr/) { $file_extension_gsm='.gsm'; $file_extension_wav='.wav'; $audio_suffix='_fr'; if ( (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_gsm")) || (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_wav")) ) {$donothing=1;} else {$audio_suffix='';} } else {$audio_suffix='';} $interrupt_digit = $AGI->stream_file("$audio_file$audio_suffix",'0123456789'); print STDERR "interrupt_digit |$interrupt_digit|\n"; $digits_being_entered=1; $PASS_word=''; if ($interrupt_digit > 0) { # if ($interrupt_digit == 35) {$interrupt_digit='#';} # if ($interrupt_digit == 42) {$interrupt_digit='*';} if ($interrupt_digit == 48) {$interrupt_digit=0;} if ($interrupt_digit == 49) {$interrupt_digit=1;} if ($interrupt_digit == 50) {$interrupt_digit=2;} if ($interrupt_digit == 51) {$interrupt_digit=3;} if ($interrupt_digit == 52) {$interrupt_digit=4;} if ($interrupt_digit == 53) {$interrupt_digit=5;} if ($interrupt_digit == 54) {$interrupt_digit=6;} if ($interrupt_digit == 55) {$interrupt_digit=7;} if ($interrupt_digit == 56) {$interrupt_digit=8;} if ($interrupt_digit == 57) {$interrupt_digit=9;} $PASS_word=$interrupt_digit; } $digit_loop_counter=0; while ($digits_being_entered > 0) { $digit = chr($AGI->wait_for_digit('8000')); # wait 8 seconds for input or until the pound key is pressed if ($digit =~ /\d/) { $PASS_word = "$PASS_word$digit"; print STDERR "digit |$digit| PASS_word |$PASS_word|\n"; # $AGI->say_digits("$digit"); undef $digit; } else { $digits_being_entered=0; } if ( (length($PASS_word)) >= $collect_digits) { $digits_being_entered=0; } $digit_loop_counter++; } $PASS_word =~ s/\D//gi; $variable = $PASS_word; if ($PASS_word) {print STDERR "digit |$digit| PASS_word |$PASS_word| variable |$variable|\n";} $collect_digits='99'; } ##### END collect the customer variable ############################################### ##### BEGIN confirm entry ###################################### sub confirm_entry { $interrupt_digit=''; $audio_file = "$confirmation_prompt"; if ($language =~ /es/) { $file_extension_gsm='.gsm'; $file_extension_wav='.wav'; $audio_suffix='_es'; if ( (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_gsm")) || (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_wav")) ) {$donothing=1;} else {$audio_suffix='';} } elsif ($language =~ /fr/) { $file_extension_gsm='.gsm'; $file_extension_wav='.wav'; $audio_suffix='_fr'; if ( (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_gsm")) || (-e ("$PATHsounds/$audio_file$audio_suffix$file_extension_wav")) ) {$donothing=1;} else {$audio_suffix='';} } else {$audio_suffix='';} $interrupt_digit = $AGI->stream_file("$audio_file$audio_suffix",'12'); print STDERR "interrupt_digit |$interrupt_digit|\n"; $digits_being_entered=1; $ANSWER_confirm=''; if ($interrupt_digit > 0) { # if ($interrupt_digit == 35) {$interrupt_digit='#';} # if ($interrupt_digit == 42) {$interrupt_digit='*';} if ($interrupt_digit == 48) {$interrupt_digit=0;} if ($interrupt_digit == 49) {$interrupt_digit=1;} if ($interrupt_digit == 50) {$interrupt_digit=2;} if ($interrupt_digit == 51) {$interrupt_digit=3;} if ($interrupt_digit == 52) {$interrupt_digit=4;} if ($interrupt_digit == 53) {$interrupt_digit=5;} if ($interrupt_digit == 54) {$interrupt_digit=6;} if ($interrupt_digit == 55) {$interrupt_digit=7;} if ($interrupt_digit == 56) {$interrupt_digit=8;} if ($interrupt_digit == 57) {$interrupt_digit=9;} $ANSWER_confirm=$interrupt_digit; } if (length($ANSWER_confirm) < 1) { $digit_loop_counter=0; while ( ($digits_being_entered > 0) && ($digit_loop_counter < 1) ) { $digit = chr($AGI->wait_for_digit("$ms_delay")); # wait 10 seconds for input or until the pound key is pressed if ($digit =~ /\d/) { $ANSWER_confirm = "$ANSWER_confirm$digit"; print STDERR "digit |$digit| ANSWER_confirm |$ANSWER_confirm|\n"; # $AGI->say_digits("$digit"); undef $digit; } else { $digits_being_entered=0; } $digit_loop_counter++; } } $ANSWER_confirm =~ s/\D//gi; if ($ANSWER_confirm) {print STDERR "digit |$digit| ANSWER_confirm |$ANSWER_confirm|\n";} } ##### END confirm entry ######################################