diff --git a/agc_2-X/trunk/agi/agi-VDAD_ALL_outbound.agi b/agc_2-X/trunk/agi/agi-VDAD_ALL_outbound.agi index 0dc5c5f9..76f7446e 100644 --- a/agc_2-X/trunk/agi/agi-VDAD_ALL_outbound.agi +++ b/agc_2-X/trunk/agi/agi-VDAD_ALL_outbound.agi @@ -125,6 +125,7 @@ # 191120-2235 - Added DYN multi-prompt survey prompts functionality # 200825-2342 - Added option for auto-only sip actions # 200915-2218 - Fixes for surveys with hash-star +# 210907-1254 - Added KHOMP code (install JSON::PP Perl module and remove '#UC#' in the code to enable) # $script = 'agi-VDAD_ALL_outbound.agi'; @@ -134,9 +135,32 @@ $mysql_log_count=147; $one_mysql_log=0; use Time::Local; -use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Time::HiRes ('tv_interval','gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second ($START_s_hires, $START_usec) = gettimeofday(); +# Needed for Khomp Integration +#UC# use JSON::PP qw(encode_json decode_json); + + +### find curl binary for KHOMP +$curlbin = ''; +$khomp_enabled = 1; +if ( -e ('/bin/curl')) {$curlbin = '/bin/curl';} +else + { + if ( -e ('/usr/bin/curl')) {$curlbin = '/usr/bin/curl';} + else + { + if ( -e ('/usr/local/bin/curl')) {$curlbin = '/usr/local/bin/curl';} + else + { + if ($AGILOG) {$agi_string = "ERROR: curl binary not found, KHOMP disabled"; &agi_output;} + $khomp_enabled = 0; + } + } + } + + $DROP_TIME = 9; ### default number of seconds to wait until you drop a waiting call $at='@'; $US='_'; @@ -843,6 +867,144 @@ if ($VDACaffected_rows > 0) } $sthA->finish(); + ### if using KHOMP Analytics get relavant system settings + if ( $amd_type eq "KHOMP" ) + { + $khomp_api_url = ''; + $khomp_api_proxied = 'false'; + $khomp_api_login_url = ''; + $khomp_api_user = ''; + $khomp_api_pass = ''; + $khomp_header = ''; + $khomp_id_format = ''; + + $stmtA = "SELECT container_entry FROM vicidial_settings_containers WHERE container_id = 'KHOMPSETTINGS';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $container_entry = $aryA[0]; + + my @lines = split ( /\n/, $container_entry ); + foreach my $line (@lines) + { + # remove comments and blank lines + $line =~ /^\s*$/ and next; # skip blank lines + $line =~ /^\s*#/ and next; # skip line that begin with # + if ( $line =~ /#/ ) # check for comments midway through the line + { + # remove them + @split_line = split( /#/ , $line ); + $line = $split_line[0]; + } + + if ( $line =~ /=>/ ) + { + @setting = split( /=>/ , $line ); + $key = $setting[0]; + $key =~ s/^\s+|\s+$//g; + $value = $setting[1]; + $value =~ s/^\s+|\s+$//g; + + if ( $key eq 'khomp_api_url' ) { $khomp_api_url = $value; } + if ( $key eq 'khomp_api_proxied' ) { $khomp_api_proxied = $value; } + if ( $key eq 'khomp_api_user' ) { $khomp_api_user = $value; } + if ( $key eq 'khomp_api_pass' ) { $khomp_api_pass = $value; } + if ( $key eq 'khomp_header' ) { $khomp_header = $value; } + if ( $key eq 'khomp_id_format' ) { $khomp_id_format = $value; } + if ( $key eq 'khomp_api_login_url' ) { $khomp_api_login_url = $value; } + if ( $key eq 'khomp_api_token' ) { $khomp_api_token = $value; } + if ( $key eq 'khomp_api_token_expire' ) { $khomp_api_token_expire = $value; } + } + + } + $agi_string = "KHOMP Settings: url-$khomp_api_url|proxied-$khomp_api_proxied|login_url-$khomp_api_login_url|user-$khomp_api_user|pass-$khomp_api_pass|header-$khomp_header|format-$khomp_id_format"; + &agi_output; + } + + ### load the Khomp status map + %conclusion_map = {}; + + $stmtA = "SELECT container_entry FROM vicidial_settings_containers WHERE container_id = 'KHOMPSTATUSMAP';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $container_entry = $aryA[0]; + + my @lines = split ( /\n/, $container_entry ); + foreach my $line (@lines) + { + # remove comments and blank lines + $line =~ /^\s*$/ and next; # skip blank lines + $line =~ /^\s*#/ and next; # skip line that begin with # + if ( $line =~ /#/ ) # check for comments midway through the line + { + # remove them + @split_line = split( /#/ , $line ); + $line = $split_line[0]; + } + + if ( $line =~ /=>/ ) + { + @setting = split( /=>/ , $line ); + $conclusion_pattern = $setting[0]; + $conclusion_pattern =~ s/^\s+|\s+$//g; + + $action_status = $setting[1]; + $action_status =~ s/^\s+|\s+$//g; + + # check if the conclusion_pattern looks like "blah"."blahblah" or just "blah" + if ( $conclusion_pattern =~ /\./ ) + { + # if "blah"."blahblah" break it up + + @rsr = split( /\./ , $conclusion_pattern ); + $conclusion = $rsr[0]; + $conclusion =~ s/^\s+|\s+$//g; + $conclusion =~ s/^"|"$//g; + + $pattern = $rsr[1]; + $pattern =~ s/^\s+|\s+$//g; + $pattern =~ s/^"|"$//g; + } + else + { + # otherwise conclusion is the string and pattern is blank + + $conclusion = $conclusion_pattern; + $conclusion =~ s/^\s+|\s+$//g; + $conclusion =~ s/^"|"$//g; + $pattern = ""; + } + + @as = split( /\./ , $action_status ); + $action = @as[0]; + $action =~ s/^\s+|\s+$//g; + $action =~ s/^"|"$//g; + + $status = @as[1]; + $status =~ s/^\s+|\s+$//g; + $status =~ s/^"|"$//g; + + $dial_status = @as[2]; + $dial_status =~ s/^\s+|\s+$//g; + $dial_status =~ s/^"|"$//g; + + + # load the result map hash with the values + $conclusion_map{"$conclusion"}{"$pattern"}{'action'} = $action; + $conclusion_map{"$conclusion"}{"$pattern"}{'status'} = $status; + $conclusion_map{"$conclusion"}{"$pattern"}{'dial_status'} = $dial_status; + } + } + + } + } ##### BEGIN SIP Action check ##### if ( ($SIP_event_recent_inserted > 0) && ($SIP_event_action_checked < 1) && (length($CAMPsip_event_logging) > 0) and ($CAMPsip_event_logging !~ /^DISABLED$/i) ) @@ -1409,51 +1571,75 @@ if ($call_handle_method =~ /REMIND/) { $AGI->stream_file('sip-silence'); - ############# BEGIN CPD AMD SECTION ############################ - if ($cpd_amd_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) + ### Using Sangoma CPD + if ( $amd_type eq 'CPD' ) { - $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') and status='NEW';"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; - $dbhP=$dbhA; $mysql_count='01054'; $MEL_aff_rows=$sthArows; &mysql_error_logging; - if ($sthArows > 0) + ############# BEGIN CPD AMD SECTION ############################ + if ($cpd_amd_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) { - @aryA = $sthA->fetchrow_array; - $cpd_amd = $aryA[0]; + $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') and status='NEW';"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $dbhP=$dbhA; $mysql_count='01054'; $MEL_aff_rows=$sthArows; &mysql_error_logging; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $cpd_amd = $aryA[0]; + } + $sthA->finish(); + + if ($cpd_amd > 0) + { + &cpd_end_call; + } } - $sthA->finish(); - - if ($cpd_amd > 0) + ############# END CPD AMD SECTION ############################ + + ############# BEGIN CPD Unknown SECTION ############################ + if ($cpd_unknown_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) { - &cpd_end_call; + $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result IN('Unknown','???') and status='NEW';"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $dbhP=$dbhA; $mysql_count='01109'; $MEL_aff_rows=$sthArows; &mysql_error_logging; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $cpd_unknown = $aryA[0]; + } + $sthA->finish(); + + if ($cpd_unknown > 0) + { + &cpd_end_call; + } } + ############# END CPD Unknown SECTION ############################ } - ############# END CPD AMD SECTION ############################ - ############# BEGIN CPD Unknown SECTION ############################ - if ($cpd_unknown_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) + ### Using KHOMP call analytics + if (( $amd_type eq 'KHOMP' ) && ( $khomp_enabled ) ) { - $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result IN('Unknown','???') and status='NEW';"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; - $dbhP=$dbhA; $mysql_count='01109'; $MEL_aff_rows=$sthArows; &mysql_error_logging; - if ($sthArows > 0) - { - @aryA = $sthA->fetchrow_array; - $cpd_unknown = $aryA[0]; - } - $sthA->finish(); - - if ($cpd_unknown > 0) - { - &cpd_end_call; - } + process_khomp_analytics( + $khomp_api_url, + $khomp_api_proxied, + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass, + $khomp_header, + $khomp_id_format, + $external_server_ip, + $VDADcampaign, + $callerid, + $cpd_amd_action, + $cpd_unknown_action, + $CIDlead_id + ); } - ############# END CPD Unknown SECTION ############################ $stmtA = "UPDATE vicidial_auto_calls set last_update_time='$FDtsSQLdate',stage='REMIND-0' where callerid='$callerid' order by call_time desc limit 1;"; $affected_rows = $dbhA->do($stmtA); @@ -1490,51 +1676,75 @@ if ($call_handle_method =~ /SURVEY/) { $AGI->stream_file('sip-silence'); - ############# BEGIN CPD AMD SECTION ############################ - if ($cpd_amd_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) + ### Using Sangoma CPD + if ( $amd_type eq 'CPD' ) { - $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') and status='NEW';"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; - $dbhP=$dbhA; $mysql_count='01110'; $MEL_aff_rows=$sthArows; &mysql_error_logging; - if ($sthArows > 0) + ############# BEGIN CPD AMD SECTION ############################ + if ($cpd_amd_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) { - @aryA = $sthA->fetchrow_array; - $cpd_amd = $aryA[0]; + $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') and status='NEW';"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $dbhP=$dbhA; $mysql_count='01110'; $MEL_aff_rows=$sthArows; &mysql_error_logging; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $cpd_amd = $aryA[0]; + } + $sthA->finish(); + + if ($cpd_amd > 0) + { + &cpd_end_call; + } } - $sthA->finish(); + ############# END CPD AMD SECTION ############################ + + ############# BEGIN CPD Unknown SECTION ############################ + if ($cpd_unknown_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) + { + $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result IN('Unknown','???') and status='NEW';"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $dbhP=$dbhA; $mysql_count='01111'; $MEL_aff_rows=$sthArows; &mysql_error_logging; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $cpd_unknown = $aryA[0]; + } + $sthA->finish(); - if ($cpd_amd > 0) - { - &cpd_end_call; + if ($cpd_unknown > 0) + { + &cpd_end_call; + } } + ############# END CPD Unknown SECTION ############################ } - ############# END CPD AMD SECTION ############################ - ############# BEGIN CPD Unknown SECTION ############################ - if ($cpd_unknown_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) + ### Using KHOMP call analytics + if (( $amd_type eq 'KHOMP' ) && ( $khomp_enabled ) ) { - $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result IN('Unknown','???') and status='NEW';"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; - $dbhP=$dbhA; $mysql_count='01111'; $MEL_aff_rows=$sthArows; &mysql_error_logging; - if ($sthArows > 0) - { - @aryA = $sthA->fetchrow_array; - $cpd_unknown = $aryA[0]; - } - $sthA->finish(); - - if ($cpd_unknown > 0) - { - &cpd_end_call; - } - } - ############# END CPD Unknown SECTION ############################ + process_khomp_analytics( + $khomp_api_url, + $khomp_api_proxied, + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass, + $khomp_header, + $khomp_id_format, + $external_server_ip, + $VDADcampaign, + $callerid, + $cpd_amd_action, + $cpd_unknown_action, + $CIDlead_id + ); + } $stmtA = "UPDATE vicidial_auto_calls set last_update_time='$FDtsSQLdate',stage='SURVEY-0' where callerid='$callerid' order by call_time desc limit 1;"; $affected_rows = $dbhA->do($stmtA); @@ -2400,6 +2610,26 @@ $drop_seconds=0; $hold_message_counter=25; $hold_tone_counter=0; +#### Using KHOMP analytics +if (( $amd_type eq 'KHOMP' ) && ( $khomp_enabled ) ) + { + process_khomp_analytics( + $khomp_api_url, + $khomp_api_proxied, + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass, + $khomp_header, + $khomp_id_format, + $external_server_ip, + $VDADcampaign, + $callerid, + $cpd_amd_action, + $cpd_unknown_action, + $CIDlead_id + ); + } + while ($drop_timer <= $DROP_TIME) { $channel_status = $AGI->channel_status("$channel"); @@ -2418,52 +2648,55 @@ while ($drop_timer <= $DROP_TIME) $drop_timer = ($drop_timer + $DROP_TIME); } } - - ############# BEGIN CPD AMD SECTION ############################ - if ($cpd_amd_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) + ### Using Sangoma CPD + if ( $amd_type eq 'CPD' ) { - $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') and status='NEW';"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; - $dbhP=$dbhA; $mysql_count='01117'; $MEL_aff_rows=$sthArows; &mysql_error_logging; - if ($sthArows > 0) + ############# BEGIN CPD AMD SECTION ############################ + if ($cpd_amd_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) { - @aryA = $sthA->fetchrow_array; - $cpd_amd = $aryA[0]; + $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') and status='NEW';"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $dbhP=$dbhA; $mysql_count='01117'; $MEL_aff_rows=$sthArows; &mysql_error_logging; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $cpd_amd = $aryA[0]; + } + $sthA->finish(); + + if ($cpd_amd > 0) + { + &cpd_end_call; + } } - $sthA->finish(); + ############# END CPD AMD SECTION ############################ - if ($cpd_amd > 0) + ############# BEGIN CPD Unknown SECTION ############################ + if ($cpd_unknown_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) { - &cpd_end_call; - } - } - ############# END CPD AMD SECTION ############################ - - ############# BEGIN CPD Unknown SECTION ############################ - if ($cpd_unknown_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/) - { - $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result IN('Unknown','???') and status='NEW';"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; + $stmtA = "SELECT count(*) FROM vicidial_cpd_log where callerid='$callerid' and result IN('Unknown','???') and status='NEW';"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; $dbhP=$dbhA; $mysql_count='01118'; $MEL_aff_rows=$sthArows; &mysql_error_logging; - if ($sthArows > 0) - { - @aryA = $sthA->fetchrow_array; - $cpd_unknown = $aryA[0]; - } - $sthA->finish(); - - if ($cpd_unknown > 0) - { - &cpd_end_call; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $cpd_unknown = $aryA[0]; + } + $sthA->finish(); + + if ($cpd_unknown > 0) + { + &cpd_end_call; + } } } - ############# END CPD Unknown SECTION ############################ + ############# END CPD Unknown SECTION ############################ @@ -4977,3 +5210,489 @@ sub validate_cid_name } } + +### code for processing KHOMP analytics +sub process_khomp_analytics + { + ( + $khomp_api_url, + $khomp_api_proxied, + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass, + $khomp_header, + $khomp_id_format, + $external_server_ip, + $campaign_id, + $callerid, + $cpd_amd_action, + $cpd_unknown_action, + $CIDlead_id + ) = @_; + + ### Extra SIP Headers begin with an X + $khomp_header = "X-" . $khomp_header; + + # determin khomp id format to use + if ($khomp_id_format eq 'CALLERCODE') + { $khomp_id = $callerid; } + elsif ($khomp_id_format eq 'CALLERCODE_EXTERNIP') + { $khomp_id = $callerid . '_' . $external_server_ip; } + elsif ($khomp_id_format eq 'CALLERCODE_CAMP_EXTERNIP') + { $khomp_id = $callerid . '_' . $campaign_id . '_' . $external_server_ip; } + + my $api_auth_time = 0; + if ( ($khomp_api_token_expire < time() ) or ( $khomp_api_token eq 'TOKENTOKENTOKEN' )) + { + if ($AGILOG) {$agi_string = "-- KHOMP API Token $khomp_api_token has expired at $khomp_api_token_expire"; &agi_output;} + + # get a new API token + my $new_khomp_api_token = ''; + if ( $khomp_api_proxied eq 'false' ) + { + ($new_khomp_api_token, $api_auth_time) = khomp_api_login( $khomp_api_login_url, $khomp_api_user, $khomp_api_pass ); + } + + # update the settings container + my $old_token_string = "khomp_api_token => $khomp_api_token"; + my $new_token_string = "khomp_api_token => $new_khomp_api_token"; + my $new_token_expire_time = time() + 3600; + my $old_token_expire_string = "khomp_api_token_expire => $khomp_api_token_expire"; + my $new_token_expire_string = "khomp_api_token_expire => $new_token_expire_time"; + + # LOCK vicidial_settings_containers + $stmtA = "LOCK TABLES vicidial_settings_containers WRITE"; + $dbhA->do($stmtA); + # UPDATE the Token + $stmtToken = "UPDATE vicidial_settings_containers SET container_entry = REGEXP_REPLACE(container_entry, '$old_token_string', '$new_token_string') WHERE container_id = 'KHOMPSETTINGS';"; + $affected_rows = $dbhA->do($stmtToken); + # UPDATE the Expire time + $stmtExpire = "UPDATE vicidial_settings_containers SET container_entry = REGEXP_REPLACE(container_entry, '$old_token_expire_string', '$new_token_expire_string') WHERE container_id = 'KHOMPSETTINGS';"; + $affected_rows = $dbhA->do($stmtExpire); + # Unlock vicidial_settings_containers + $stmtA = "UNLOCK TABLES"; + $dbhA->do($stmtA); + + if ($AGILOG) {$agi_string = "-- KHOMP SC TOKEN UPDATE|$affected_rows|$stmtToken|"; &agi_output;} + if ($AGILOG) {$agi_string = "-- KHOMP SC TOKEN EXPIRE UPDATE|$affected_rows|$stmtExpire|"; &agi_output;} + + # over write the old with the new + $khomp_api_token = $new_khomp_api_token; + } + else + { + if ($AGILOG) {$agi_string = "-- KHOMP API Token $khomp_api_token still valid till $khomp_api_token_expire"; &agi_output;} + } + + if ( $khomp_api_token ne 'TOKENTOKENTOKEN' ) + { + # build JSON object + my $khomp_request = { + 'id' => 0, + 'method' => 'CallList', + 'params' => { + 'token' => "$khomp_api_token", + 'query' => { + 'type' => "eq", + 'field' => "sip_header:$khomp_header", + 'values' => ["$khomp_id"], + }, + 'selected_fields' => ["sip_header:call-id", "start_stamp", "audio_stamp", "answer_stamp", "end_stamp", "analyzer_stamp", "analyzer_conclusion", "analyzer_pattern", "analyzer_action", "hangup_origin", "hangup_cause", "hangup_cause_sent"] + }, + 'jsonrpc' => '2.0', + }; + + # encode it as JSON +#UC# $khomp_json = encode_json( $khomp_request ); + + # call the API + ($result, $api_query_time) = khomp_json_api( $khomp_json, $khomp_api_url ); + + # check the result + if ( $result =~ /^ERROR/ ) + { + # we got an error so log it + if ($AGILOG) { $agi_string = "--KHOMP: $result"; &agi_output; } + } + else + { + # we got a result + + if ( defined $result->{'result'}->{'calls'}[0]->{'fields'} ) + { + my $khomp_call_data = $result->{'result'}->{'calls'}[0]->{'fields'}; + + %parsed_data = khomp_parse_call_data( $khomp_header, $khomp_id, $callerid, $CIDlead_id, $khomp_id_format, $khomp_call_data ); + $parsed_data{'api_auth_time'} = $api_auth_time; + $parsed_data{'api_query_time'} = $api_query_time; + + $conclusion = $parsed_data{'conclusion'}; + $pattern = $parsed_data{'pattern'}; + + #$agi_string = Dumper( \%conclusion_map ); + #&agi_output; + + my $action = ''; + my $status = ''; + + if ( defined ( $conclusion_map{"$conclusion"}{"$pattern"}{'action'} ) ) + { + $action = $conclusion_map{"$conclusion"}{"$pattern"}{'action'}; + $status = $conclusion_map{"$conclusion"}{"$pattern"}{'status'}; + } + elsif ( defined( $conclusion_map{"$conclusion"}{''}{'action'} ) ) + { + $action = $conclusion_map{"$conclusion"}{''}{'action'}; + $status = $conclusion_map{"$conclusion"}{''}{'status'}; + } + else + { + $action = 'route'; + $status = 'KPEROR'; + } + + if ($AGILOG) { $agi_string = "--KHOMP: conclusion = $conclusion|pattern = $pattern|action = $action|status = $status"; &agi_output; } + + if ( $action ne '' ) { $parsed_data{'vici_action'} = "$action"; } + if ( $status ne '' ) { $parsed_data{'vici_status'} = "$status"; } + + # log the khomp data in the vicidial_khomp_log + log_khomp_call_data( %parsed_data ); + + # handle the AMD action + if ( + (( $action eq 'amdaction' ) && ($cpd_amd_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/)) || + (( $action eq 'cpdunknown' ) && ($cpd_unknown_action =~ /DISPO|MESSAGE|CALLMENU|INGROUP/)) || + ( $action eq 'status' ) + ) + { + khomp_end_call( %parsed_data ); + } + if ( $action eq 'route' ) + { + if ($AGILOG) { $agi_string = "--KHOMP: Routing Call"; &agi_output; } + } + if ( $action eq '' ) + { + if ($AGILOG) { $agi_string = "--KHOMP: No Action Defined. Routing Call"; &agi_output; } + } + } + else + { + if ($AGILOG) { $agi_string = "--KHOMP: No Call Record Found"; &agi_output; } + } + } + } + else + { + if ($AGILOG) { $agi_string = "--KHOMP: Login Failed"; &agi_output; } + } + + } + +# code to log the khomp data in vicidial_khomp_log +sub log_khomp_call_data + { + %khomp_call_data = @_; + + $stmtA = "UPDATE vicidial_khomp_log SET caller_code = '$khomp_call_data{'caller_code'}', lead_id = '$khomp_call_data{'lead_id'}', server_ip = '$VARserver_ip', khomp_header = '$khomp_call_data{'khomp_header'}', khomp_id = '$khomp_call_data{'khomp_id'}', khomp_id_format = '$khomp_call_data{'khomp_id_format'}', route_auth_time = '$khomp_call_data{'api_auth_time'}', route_query_time = '$khomp_call_data{'api_query_time'}'"; + + if ( defined( $khomp_call_data{'sip_call_id'} ) ) { $stmtA .= ", sip_call_id = '$khomp_call_data{'sip_call_id'}'"; } + if ( defined( $khomp_call_data{'start_epoch'} ) ) { $stmtA .= ", start_date = FROM_UNIXTIME($khomp_call_data{'start_epoch'})"; } + if ( defined( $khomp_call_data{'audio_epoch'} ) ) { $stmtA .= ", audio_date = FROM_UNIXTIME($khomp_call_data{'audio_epoch'})"; } + if ( defined( $khomp_call_data{'answer_epoch'} ) ) { $stmtA .= ", answer_date = FROM_UNIXTIME($khomp_call_data{'answer_epoch'})"; } + if ( defined( $khomp_call_data{'end_epoch'} ) ) { $stmtA .= ", end_date = FROM_UNIXTIME($khomp_call_data{'end_epoch'})"; } + if ( defined( $khomp_call_data{'analyzer_epoch'} ) ) { $stmtA .= ", analyzer_date = FROM_UNIXTIME($khomp_call_data{'analyzer_epoch'})"; } + if ( defined( $khomp_call_data{'conclusion'} ) ) { $stmtA .= ", conclusion = '$khomp_call_data{'conclusion'}'"; } + if ( defined( $khomp_call_data{'pattern'} ) ) { $stmtA .= ", pattern = '$khomp_call_data{'pattern'}'"; } + if ( defined( $khomp_call_data{'action'} ) ) { $stmtA .= ", action = '$khomp_call_data{'action'}'"; } + if ( defined( $khomp_call_data{'hangup_origin'} ) ) { $stmtA .= ", hangup_origin = '$khomp_call_data{'hangup_origin'}'"; } + if ( defined( $khomp_call_data{'hangup_cause_recv'} ) ) { $stmtA .= ", hangup_cause_recv = '$khomp_call_data{'hangup_cause_recv'}'"; } + if ( defined( $khomp_call_data{'hangup_cause_sent'} ) ) { $stmtA .= ", hangup_cause_sent = '$khomp_call_data{'hangup_cause_sent'}'"; } + if ( defined( $khomp_call_data{'vici_action'} ) ) { $stmtA .= ", vici_action = '$khomp_call_data{'vici_action'}'"; } + if ( defined( $khomp_call_data{'vici_status'} ) ) { $stmtA .= ", vici_status = '$khomp_call_data{'vici_status'}'"; } + + $stmtA .= " WHERE khomp_id = '$khomp_call_data{'khomp_id'}'"; + + $affected_rows = $dbhA->do($stmtA); + + if ($AGILOG) {$agi_string = "-- KHOMP Log Update: |$stmtA|$affected_rows|"; &agi_output;} + + } + +sub khomp_end_call + { + %khomp_call_data = @_; + + $vdad_action = $khomp_call_data{'vici_action'}; + $vdad_result = $khomp_call_data{'vici_status'}; + + if ($AGILOG) {$agi_string = "-- VDAD KHOMP End Call |a:$vdad_action|s:$vdad_result|"; &agi_output;} + + my $conclusion = $khomp_call_data{'conclusion'}; + my $pattern = $khomp_call_data{'pattern'}; + + ($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"; + $CIDdate = "$mon$mday$hour$min$sec"; + $tsSQLdate = "$year$mon$mday$hour$min$sec"; + $SQLdate = "$year-$mon-$mday $hour:$min:$sec"; + + if ($enable_queuemetrics_logging > 0) + { + $dbhB = DBI->connect("DBI:mysql:$queuemetrics_dbname:$queuemetrics_server_ip:3306", "$queuemetrics_login", "$queuemetrics_pass") + or die "Couldn't connect to database: " . DBI->errstr; + + if ($DBX) {print "CONNECTED TO DATABASE: $queuemetrics_server_ip|$queuemetrics_dbname\n";} + + $stmtB = "INSERT INTO queue_log SET `partition`='P01',time_id='$now_date_epoch',call_id='$callerid',queue='$VDADcampaign',agent='NONE',verb='EXITWITHTIMEOUT',data1='1',serverid='$queuemetrics_log_id';"; + $Baffected_rows = $dbhB->do($stmtB); + $dbhP=$dbhB; $stmtA=$stmtB; $mysql_count='01048'; $MEL_aff_rows=$Baffected_rows; &mysql_error_logging; + + $stmtB = "INSERT INTO queue_log SET `partition`='P01',time_id='$now_date_epoch',call_id='$callerid',queue='$VDADcampaign',agent='NONE',verb='CALLSTATUS',data1='$vdad_result',serverid='$queuemetrics_log_id';"; + $Baffected_rows = $dbhB->do($stmtB); + $dbhP=$dbhB; $stmtA=$stmtB; $mysql_count='01049'; $MEL_aff_rows=$Baffected_rows; &mysql_error_logging; + + $dbhB->disconnect(); + } + + if ($drop_seconds < 1) + { + $drop_seconds = $DROP_TIME; + } + + if ( + ( ($cpd_amd_action =~ /MESSAGE|CALLMENU|INGROUP/) && ($vdad_action eq 'amdaction') ) || + ( ($cpd_unknown_action =~ /MESSAGE|CALLMENU|INGROUP/) && ($vdad_action eq 'cpdunknown' ) ) + ) + { + $DROPexten = "8320"; + $AMDSTATUS_set = $AGI->set_variable('AMDSTATUS', "CPDMACHINE"); + $AMDCAUSE_set = $AGI->set_variable('AMDCAUSE', "$conclusion-$pattern"); + } + else + { + $stmtA = "DELETE FROM vicidial_auto_calls where callerid='$callerid' order by call_time desc limit 1;"; + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01052'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- VDAD KHOMP vac record deleted: |$affected_rows|$VDADcampaign|$callerid|"; &agi_output;} + } + + $Euniqueid=$uniqueid; + $Euniqueid =~ s/\.\d+//gi; + $stmtA = "UPDATE vicidial_log FORCE INDEX(lead_id) set status='$vdad_result',end_epoch='$now_date_epoch',length_in_sec='$drop_seconds',term_reason='AGENT' where lead_id = '$CIDlead_id' and uniqueid LIKE \"$Euniqueid%\";"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01050'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- VDAD KHOMP vicidial_log update: |$affected_rows|$uniqueid"; &agi_output;} + + $stmtA = "UPDATE vicidial_list set status='$vdad_result' where lead_id = '$CIDlead_id';"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01051'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- VDAD KHOMP vicidial_list update: |$affected_rows|$CIDlead_id"; &agi_output;} + + ### use STDOUT to send call to proper DROP location + $VHqueryCID = "VH$CIDdate$VDADconf_exten"; + + if (length($DROPexten)>0) + { ### if DROP extension is defined then send the dropped call there instead of hangup + $AGI->stream_file('sip-silence'); + $AGI->stream_file('sip-silence'); + $AGI->stream_file('sip-silence'); + + if ($AGILOG) {$agi_string = "exiting the VDAD app, KHOMP transferring call to $DROPexten"; &agi_output;} + print "SET CONTEXT $ext_context\n"; + $result = ; + checkresult($result); + print "SET EXTENSION $DROPexten\n"; + $result = ; + checkresult($result); + print "SET PRIORITY 1\n"; + $result = ; + checkresult($result); + + exit; + } + else + { + ### insert a NEW record to the vicidial_manager table to be processed + $stmtA = "INSERT INTO vicidial_manager values('','','$SQLdate','NEW','N','$VARserver_ip','','Hangup','$VHqueryCID','Channel: $channel','','','','','','','','','')"; + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01053'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- VDAD call_hungup KHOMP timout: |$CIDlead_id|$VHqueryCID|$VDADconf_exten|$channel|insert to vicidial_manager"; &agi_output;} + + $AGI->hangup(); + + exit; + } + } + + +### code for parsing the call data into a useful data structure +sub khomp_parse_call_data + { + ( $khomp_header, $khomp_id, $callerid, $lead_id, $khomp_id_format, $khomp_call_data ) = @_; + + my %new_khomp_call_data; + + + #KHOMP Field Names - Meaning: + # sip_header:call-id - leg A - SIP Call-ID + # start_stamp - unix timestamp of the call start (first INVITE) + # audio_stamp - unix timestamp of the audio start (183) + # answer_stamp - unix timestamp of the call answer (200 OK) + # end_stamp - unix timestamp of call end + # analyzer_stamp - unix timestamp of Analytics conclusion + # analyzer_conclusion - the Analytics conclusion + # analyzer_pattern - The specific pattern that was detected (if any) + # analyzer_action - the action taken for the analytics conclusion + # hangup_origin - which leg hangup the call: leg a or leg b + # hangup_cause - hangup cause received + # hangup_cause_sent - the cause code that was sent + # + + $new_khomp_call_data{'caller_code'} = $callerid; + $new_khomp_call_data{'lead_id'} = $lead_id; + $new_khomp_call_data{'khomp_header'} = $khomp_header; + $new_khomp_call_data{'khomp_id'} = $khomp_id; + $new_khomp_call_data{'khomp_id_format'} = $khomp_id_format; + $new_khomp_call_data{'sip_call_id'} = $khomp_call_data->{'sip_header:call-id'}; + $new_khomp_call_data{'start_epoch'} = $khomp_call_data->{'start_stamp'}; + $new_khomp_call_data{'audio_epoch'} = $khomp_call_data->{'audio_stamp'}; + $new_khomp_call_data{'answer_epoch'} = $khomp_call_data->{'answer_stamp'}; + $new_khomp_call_data{'end_epoch'} = $khomp_call_data->{'end_stamp'}; + $new_khomp_call_data{'analyzer_epoch'} = $khomp_call_data->{'analyzer_stamp'}; + $new_khomp_call_data{'conclusion'} = $khomp_call_data->{'analyzer_conclusion'}; + $new_khomp_call_data{'pattern'} = $khomp_call_data->{'analyzer_pattern'}; + $new_khomp_call_data{'action'} = $khomp_call_data->{'analyzer_action'}; + $new_khomp_call_data{'hangup_origin'} = $khomp_call_data->{'hangup_origin'}; + $new_khomp_call_data{'hangup_cause_recv'} = $khomp_call_data->{'hangup_cause'}; + $new_khomp_call_data{'hangup_cause_sent'} = $khomp_call_data->{'hangup_cause_sent'}; + + # handle blank times + if ($new_khomp_call_data{'start_epoch'} eq '') { $new_khomp_call_data{'start_epoch'} = 0; } + if ($new_khomp_call_data{'audio_epoch'} eq '') { $new_khomp_call_data{'audio_epoch'} = 0; } + if ($new_khomp_call_data{'answer_epoch'} eq '') { $new_khomp_call_data{'answer_epoch'} = 0; } + if ($new_khomp_call_data{'end_epoch'} eq '') { $new_khomp_call_data{'end_epoch'} = 0; } + if ($new_khomp_call_data{'analyzer_epoch'} eq '') { $new_khomp_call_data{'analyzer_epoch'} = 0; } + + # time is returned in milliseconds since 1970 we need seconds + if ($new_khomp_call_data{'start_epoch'} > 0) { $new_khomp_call_data{'start_epoch'} = $new_khomp_call_data{'start_epoch'} / 1000; } + if ($new_khomp_call_data{'audio_epoch'} > 0) { $new_khomp_call_data{'audio_epoch'} = $new_khomp_call_data{'audio_epoch'} / 1000; } + if ($new_khomp_call_data{'answer_epoch'} > 0) { $new_khomp_call_data{'answer_epoch'} = $new_khomp_call_data{'answer_epoch'} / 1000; } + if ($new_khomp_call_data{'end_epoch'} > 0) { $new_khomp_call_data{'end_epoch'} = $new_khomp_call_data{'end_epoch'} / 1000; } + if ($new_khomp_call_data{'analyzer_epoch'} > 0) { $new_khomp_call_data{'analyzer_epoch'} = $new_khomp_call_data{'analyzer_epoch'} / 1000; } + + return %new_khomp_call_data; + } + +### code for logging into KHOMP api +sub khomp_api_login + { + ( + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass + ) = @_; + + my $token = 'login'; + my $auth_start_sec; + my $auth_start_usec; + my $auth_end_sec; + my $auth_end_usec; + my $auth_sec; + my $auth_usec; + my $api_auth_time; + + ($auth_start_sec, $auth_start_usec) = gettimeofday(); + + # build JSON object + my $login_json = { + 'id' => 0, + 'method' => 'SessionLogin', + 'params' => { + 'username' => "$khomp_api_user", + 'password' => "$khomp_api_pass", + }, + 'jsonrpc' => '2.0', + }; + + # encode it as JSON +#UC# $login_json = encode_json( $login_json ); + + my $curl_cmd = "$curlbin -sS --data \'$login_json\' $khomp_api_login_url"; + + $agi_string = "-- KHOMP CURL COMMAND: $curl_cmd"; &agi_output; + + $message = `$curl_cmd`; + + chomp($message); + + if ($AGILOG) + { + $agi_string = "-- KHOMP LOGIN URL: |$khomp_api_login_url|"; &agi_output; + $agi_string = "-- KHOMP LOGIN JSON : |$login_json|"; &agi_output; + $agi_string = "-- KHOMP LOGIN RESPONSE JSON: |$message|"; &agi_output; + } + +#UC# $json = JSON::PP->new->ascii->pretty->allow_nonref; +#UC# $result = $json->decode($message); + + $token = $result->{'result'}->{'token'}; + + ($auth_end_sec, $auth_end_usec) = gettimeofday(); + + $api_auth_time = tv_interval ( [$auth_start_sec, $auth_start_usec], [$auth_end_sec, $auth_end_usec]); + + return ($token, $api_auth_time); + } + +### code for connecting to KHOMP api and passing JSON +sub khomp_json_api + { + ( $khomp_json, $khomp_api_url ) = @_; + + my $query_start_sec; + my $query_start_usec; + my $query_end_sec; + my $query_end_usec; + my $query_sec; + my $query_usec; + my $api_query_time; + + ($query_start_sec, $query_start_usec) = gettimeofday(); + + my $curl_cmd = "$curlbin -sS --data \'$khomp_json\' $khomp_api_url"; + + $agi_string = "-- KHOMP CURL COMMAND: $curl_cmd"; &agi_output; + + $message = `$curl_cmd`; + + chomp($message); + + if ($AGILOG) + { + $agi_string = "-- KHOMP URL: |$khomp_api_url|"; &agi_output; + $agi_string = "-- KHOMP JSON : |$khomp_json|"; &agi_output; + $agi_string = "-- KHOMP RESPONSE JSON: |$message|"; &agi_output; + } + +#UC# $json = JSON::PP->new->ascii->pretty->allow_nonref; +#UC# $result = $json->decode($message); + + ($query_end_sec, $query_end_usec) = gettimeofday(); + + $api_query_time = tv_interval ( [$query_start_sec, $query_start_usec], [$query_end_sec, $query_end_usec]); + + return ($result, $api_query_time); + } diff --git a/agc_2-X/trunk/bin/FastAGI_log.pl b/agc_2-X/trunk/bin/FastAGI_log.pl index 26673838..a4abf7b7 100644 --- a/agc_2-X/trunk/bin/FastAGI_log.pl +++ b/agc_2-X/trunk/bin/FastAGI_log.pl @@ -91,6 +91,7 @@ # 210718-0358 - Fixes for 24-Hour Call Count Limits with standard Auto-Alt-Dialing # 210719-1521 - Added additional state override methods for call_limit_24hour # 210827-0936 - Added PJSIP compatibility +# 210907-0841 - Added KHOMP code (install JSON::PP Perl module and remove '#UC#' in the code to enable) # # defaults for PreFork @@ -189,10 +190,29 @@ use Net::Server; use vars qw(@ISA); use Net::Server::PreFork; # any personality will do @ISA = qw(Net::Server::PreFork); -use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Time::HiRes ('tv_interval','gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second use Time::Local; +# Needed for Khomp Integration +#UC# use JSON::PP qw(encode_json decode_json); +### find curl binary for KHOMP +$curlbin = ''; +$khomp_enabled = 1; +if ( -e ('/bin/curl')) {$curlbin = '/bin/curl';} +else + { + if ( -e ('/usr/bin/curl')) {$curlbin = '/usr/bin/curl';} + else + { + if ( -e ('/usr/local/bin/curl')) {$curlbin = '/usr/local/bin/curl';} + else + { + if ($AGILOG) {$agi_string = "ERROR: curl binary not found, KHOMP disabled"; &agi_output;} + $khomp_enabled = 0; + } + } + } sub process_request @@ -265,7 +285,7 @@ sub process_request or die "Couldn't connect to database: " . DBI->errstr; ### Grab Server values from the database - $stmtA = "SELECT agi_output,asterisk_version FROM servers where server_ip = '$VARserver_ip';"; + $stmtA = "SELECT agi_output,asterisk_version,external_server_ip 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; @@ -275,6 +295,7 @@ sub process_request @aryA = $sthA->fetchrow_array; $DBagi_output = $aryA[0]; $asterisk_version = $aryA[1]; + $external_server_ip = $aryA[2]; if ($DBagi_output =~ /STDERR/) {$AGILOG = '1';} if ($DBagi_output =~ /FILE/) {$AGILOG = '2';} if ($DBagi_output =~ /BOTH/) {$AGILOG = '3';} @@ -286,6 +307,144 @@ sub process_request if (( $ast_ver_str{major} = 1 ) && ($ast_ver_str{minor} >= 12)) {$h_exten_reason=1;} + ### Grab KHOMP settings from the KHOMPSETTINGS settings container + $khomp_api_url = ''; + $khomp_api_proxied = 'false'; + $khomp_api_login_url = ''; + $khomp_api_user = ''; + $khomp_api_pass = ''; + $khomp_header = ''; + $khomp_id_format = ''; + $khomp_sub_account_header = ''; + + $stmtA = "SELECT container_entry FROM vicidial_settings_containers WHERE container_id = 'KHOMPSETTINGS';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $container_entry = $aryA[0]; + + my @lines = split ( /\n/, $container_entry ); + foreach my $line (@lines) + { + # remove comments and blank lines + $line =~ /^\s*$/ and next; # skip blank lines + $line =~ /^\s*#/ and next; # skip line that begin with # + if ( $line =~ /#/ ) # check for comments midway through the line + { + # remove them + @split_line = split( /#/ , $line ); + $line = $split_line[0]; + } + + if ( $line =~ /=>/ ) + { + @setting = split( /=>/ , $line ); + $key = $setting[0]; + $key =~ s/^\s+|\s+$//g; + $value = $setting[1]; + $value =~ s/^\s+|\s+$//g; + + if ( $key eq 'khomp_api_url' ) { $khomp_api_url = $value; } + if ( $key eq 'khomp_api_proxied' ) { $khomp_api_proxied = $value; } + if ( $key eq 'khomp_api_user' ) { $khomp_api_user = $value; } + if ( $key eq 'khomp_api_pass' ) { $khomp_api_pass = $value; } + if ( $key eq 'khomp_header' ) { $khomp_header = $value; } + if ( $key eq 'khomp_id_format' ) { $khomp_id_format = $value; } + if ( $key eq 'khomp_api_login_url' ) { $khomp_api_login_url = $value; } + if ( $key eq 'khomp_sub_account_header' ) { $khomp_sub_account_header = $value; } + if ( $key eq 'khomp_api_token' ) { $khomp_api_token = $value; } + if ( $key eq 'khomp_api_token_expire' ) { $khomp_api_token_expire = $value; } + } + + } + $agi_string = "KHOMP Settings: url-$khomp_api_url|user-$khomp_api_user|pass-$khomp_api_pass|header-$khomp_header|format-$khomp_id_format|sub-account-$khomp_sub_account_header"; + #&agi_output; + } + + ### load the Khomp status map + %conclusion_map = {}; + + $stmtA = "SELECT container_entry FROM vicidial_settings_containers WHERE container_id = 'KHOMPSTATUSMAP';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $container_entry = $aryA[0]; + + my @lines = split ( /\n/, $container_entry ); + foreach my $line (@lines) + { + # remove comments and blank lines + $line =~ /^\s*$/ and next; # skip blank lines + $line =~ /^\s*#/ and next; # skip line that begin with # + if ( $line =~ /#/ ) # check for comments midway through the line + { + # remove them + @split_line = split( /#/ , $line ); + $line = $split_line[0]; + } + + if ( $line =~ /=>/ ) + { + @setting = split( /=>/ , $line ); + $conclusion_pattern = $setting[0]; + $conclusion_pattern =~ s/^\s+|\s+$//g; + + $action_status = $setting[1]; + $action_status =~ s/^\s+|\s+$//g; + + # check if the conclusion_pattern looks like "blah"."blahblah" or just "blah" + if ( $conclusion_pattern =~ /"\."/ ) + { + # if "blah"."blahblah" break it up + + @rsr = split( /"\."/ , $conclusion_pattern ); + $conclusion = $rsr[0]; + $conclusion =~ s/^\s+|\s+$//g; + $conclusion =~ s/^"|"$//g; + + $pattern = $rsr[1]; + $pattern =~ s/^\s+|\s+$//g; + $pattern =~ s/^"|"$//g; + } + else + { + # otherwise result is the string and pattern is blank + + $conclusion = $conclusion_pattern; + $conclusion =~ s/^\s+|\s+$//g; + $conclusion =~ s/^"|"$//g; + $pattern = ""; + } + + @as = split( /\./ , $action_status ); + $action = @as[0]; + $action =~ s/^\s+|\s+$//g; + $action =~ s/^"|"$//g; + + $status = @as[1]; + $status =~ s/^\s+|\s+$//g; + $status =~ s/^"|"$//g; + + $dial_status = @as[2]; + $dial_status =~ s/^\s+|\s+$//g; + $dial_status =~ s/^"|"$//g; + + # load the result map hash with the values + $conclusion_map{"$conclusion"}{"$pattern"}{'action'} = $action; + $conclusion_map{"$conclusion"}{"$pattern"}{'status'} = $status; + $conclusion_map{"$conclusion"}{"$pattern"}{'dial_status'} = $dial_status; + + } + } + + } + if ($AGILOG) { $agi_string = "+++++++++++++++++ FastAGI Start ++++ Asterisk version: $ast_ver_str{major} $ast_ver_str{minor} ++++++ hER: $h_exten_reason ++++++"; @@ -392,6 +551,7 @@ sub process_request $callerid =~ s/\'|\\\\|\\\|\\|\\;|\\\;|\;|;//gi; $calleridname =~ s/\'|\\\\|\\\|\\|\\;|\\\;|\;|;//gi; $extension =~ s/\'|\"|\\\\|\\\|\\|\\;|\\\;|\;|;//gi; + $agi_called_ext = $extension; if ($AGILOG) { @@ -550,14 +710,31 @@ sub process_request { @aryA = $sthA->fetchrow_array; $CAMPCUST = $aryA[0]; + $campaign = $aryA[0]; } $sthA->finish(); + + ### get campaign settings + $stmtA = "SELECT amd_type,campaign_vdad_exten FROM vicidial_campaigns where campaign_id = '$campaign';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $amd_type = $aryA[0]; + $campaign_vdad_exten = $aryA[1]; + } + $sthA->finish(); + + ### set dialplan variable CAMPCUST to the campaign_id of the outbound auto-dial or manual dial call if (length($CAMPCUST) > 0) { $AGI->exec("EXEC Set(_CAMPCUST=$CAMPCUST)"); if ($AGILOG) {$agi_string = "|CAMPCUST: $CAMPCUST|$callerid|"; &agi_output;} } + ### BEGIN OpenSIPs CallerIDname code ### ### get system_settings $stmtA = "SELECT opensips_cid_name FROM system_settings"; @@ -597,6 +774,36 @@ sub process_request } } ### END OpenSIPs CallerIDname code ### + + if ($AGILOG) {$agi_string = "|KHOMP $amd_type|$HVcauses|$extension|$campaign_vdad_exten"; &agi_output;} + + ### Add the KHOMP SIP X header to the outbound call + if (( $amd_type eq 'KHOMP' ) && ($agi_called_ext!= $campaign_vdad_exten)) + { + # determin header format + if ($khomp_id_format eq 'CALLERCODE') + { $khomp_id = $callerid; } + elsif ($khomp_id_format eq 'CALLERCODE_EXTERNIP') + { $khomp_id = $callerid . '_' . $external_server_ip; } + elsif ($khomp_id_format eq 'CALLERCODE_CAMP_EXTERNIP') + { $khomp_id = $callerid . '_' . $campaign . '_' . $external_server_ip; } + + $stmtA = "INSERT INTO vicidial_khomp_log SET caller_code = '$callerid', lead_id = '$lead_id', server_ip = '$VARserver_ip', khomp_header = '$khomp_header', khomp_id = '$khomp_id', khomp_id_format = '$khomp_id_format', start_date=NOW()"; + if ($AGILOG) {$agi_string = "-- KHOMP Log Insert: |$stmtA|"; &agi_output;} + $dbhA->do($stmtA); + + # add the SIP tracking header + $header = "X-" . $khomp_header . ": " . $khomp_id; + $AGI->exec("EXEC SIPAddHeader(\"$header\")"); + if ($AGILOG) {$agi_string = "|KHOMP SIP Header= $header|$khomp_id_format|"; &agi_output;} + + if ( $khomp_sub_account_header ne '' ) + { + $sub_header = "X-KHOMP-Sub-Account:" . $khomp_sub_account_header; + $AGI->exec("EXEC SIPAddHeader(\"$sub_header\")"); + if ($AGILOG) {$agi_string = "|KHOMP Sub Account Header= $sub_header|"; &agi_output;} + } + } } $stmtA = "INSERT INTO call_log (uniqueid,channel,channel_group,type,server_ip,extension,number_dialed,start_time,start_epoch,end_time,end_epoch,length_in_sec,length_in_min,caller_code) values('$unique_id','$channel','$channel_group','$type','$VARserver_ip','$extension','$number_dialed','$now_date','$now_date_epoch','','','','','$callerid')"; @@ -960,6 +1167,72 @@ sub process_request if ($AGILOG) {$agi_string = "VD_hangup : $callerid $channel $priority $CIDlead_id"; &agi_output;} + if ($callerid =~ /^V\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) + { + $campaign=''; + + # check vac for the call to get the campaign id + $stmtA = "SELECT campaign_id FROM vicidial_auto_calls where uniqueid = '$unique_id' or callerid = '$callerid' limit 1;"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $campaign = $aryA[0]; + } + $sthA->finish(); + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + + # vac does not have a record of the call check the vl + if ( $campaign eq '' ) + { + $stmtA = "SELECT campaign_id FROM vicidial_log where uniqueid = '$unique_id' limit 1;"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $campaign = $aryA[0]; + } + $sthA->finish(); + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + } + + ### get campaign settings + $stmtA = "SELECT amd_type FROM vicidial_campaigns where campaign_id = '$campaign';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $amd_type = $aryA[0]; + } + $sthA->finish(); + + if (( $amd_type eq 'KHOMP' ) && ( $khomp_enabled ) ) + { + if ($AGILOG) {$agi_string = "-- KHOMP process call for campaign $campaign callerid $callerid"; &agi_output;} + ( $khomp_action, $khomp_VDL_status, $khomp_VDAC_status ) = process_khomp_analytics( + $khomp_api_url, + $khomp_api_proxied, + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass, + $khomp_header, + $khomp_id_format, + $external_server_ip, + $campaign, + $callerid, + $cpd_amd_action, + $cpd_unknown_action, + $CIDlead_id + ); + } + } + if ($channel =~ /^Local/) { $enhanced_disconnect_logging=0; @@ -998,43 +1271,67 @@ sub process_request # # if ($AGILOG) {$agi_string = "HiRes Time: $callerid|$channel|$priority|$CIDlead_id|$uniqueid|$HRnow_date|$now_date"; &agi_output;} - - ############################################################## - ### BEGIN - CPD Look for result for B/DC calls - ############################################################## - sleep(1); - - $stmtA = "SELECT result FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') order by cpd_id desc limit 1;"; - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; - if ($sthArows > 0) + if ( $amd_type eq 'CPD' ) { - @aryA = $sthA->fetchrow_array; - $cpd_result = $aryA[0]; + ############################################################## + ### BEGIN - CPD Look for result for B/DC calls + ############################################################## + sleep(1); + + $stmtA = "SELECT result FROM vicidial_cpd_log where callerid='$callerid' and result NOT IN('Voice','Unknown','???','') order by cpd_id desc limit 1;"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $cpd_result = $aryA[0]; + $sthA->finish(); + if ($cpd_result =~ /Busy/i) {$VDL_status='CPDB'; $VDAC_status='BUSY'; $CPDfound++;} + if ($cpd_result =~ /Unknown/i) {$VDL_status='CPDUK'; $VDAC_status='NA'; $CPDfound++;} + if ($cpd_result =~ /All-Trunks-Busy/i) {$VDL_status='CPDATB'; $VDAC_status='CONGESTION'; $CPDfound++;} + if ($cpd_result =~ /No-Answer/i) {$VDL_status='CPDNA'; $VDAC_status='NA'; $CPDfound++;} + if ($cpd_result =~ /Reject/i) {$VDL_status='CPDREJ'; $VDAC_status='DISCONNECT'; $CPDfound++;} + if ($cpd_result =~ /Invalid-Number/i) {$VDL_status='CPDINV'; $VDAC_status='DISCONNECT'; $CPDfound++;} + if ($cpd_result =~ /Service-Unavailable/i) {$VDL_status='CPDSUA'; $VDAC_status='CONGESTION'; $CPDfound++;} + if ($cpd_result =~ /Sit-Intercept/i) {$VDL_status='CPDSI'; $VDAC_status='DISCONNECT'; $CPDfound++;} + if ($cpd_result =~ /Sit-No-Circuit/i) {$VDL_status='CPDSNC'; $VDAC_status='CONGESTION'; $CPDfound++;} + if ($cpd_result =~ /Sit-Reorder/i) {$VDL_status='CPDSR'; $VDAC_status='CONGESTION'; $CPDfound++;} + if ($cpd_result =~ /Sit-Unknown/i) {$VDL_status='CPDSUK'; $VDAC_status='CONGESTION'; $CPDfound++;} + if ($cpd_result =~ /Sit-Vacant/i) {$VDL_status='CPDSV'; $VDAC_status='CONGESTION'; $CPDfound++;} + if ($cpd_result =~ /\?\?\?/i) {$VDL_status='CPDERR'; $VDAC_status='NA'; $CPDfound++;} + if ($cpd_result =~ /Fax|Modem/i) {$VDL_status='AFAX'; $VDAC_status='FAX'; $CPDfound++;} + if ($cpd_result =~ /Answering-Machine/i) {$VDL_status='AA'; $VDAC_status='AMD'; $CPDfound++;} + } $sthA->finish(); - if ($cpd_result =~ /Busy/i) {$VDL_status='CPDB'; $VDAC_status='BUSY'; $CPDfound++;} - if ($cpd_result =~ /Unknown/i) {$VDL_status='CPDUK'; $VDAC_status='NA'; $CPDfound++;} - if ($cpd_result =~ /All-Trunks-Busy/i) {$VDL_status='CPDATB'; $VDAC_status='CONGESTION'; $CPDfound++;} - if ($cpd_result =~ /No-Answer/i) {$VDL_status='CPDNA'; $VDAC_status='NA'; $CPDfound++;} - if ($cpd_result =~ /Reject/i) {$VDL_status='CPDREJ'; $VDAC_status='DISCONNECT'; $CPDfound++;} - if ($cpd_result =~ /Invalid-Number/i) {$VDL_status='CPDINV'; $VDAC_status='DISCONNECT'; $CPDfound++;} - if ($cpd_result =~ /Service-Unavailable/i) {$VDL_status='CPDSUA'; $VDAC_status='CONGESTION'; $CPDfound++;} - if ($cpd_result =~ /Sit-Intercept/i) {$VDL_status='CPDSI'; $VDAC_status='DISCONNECT'; $CPDfound++;} - if ($cpd_result =~ /Sit-No-Circuit/i) {$VDL_status='CPDSNC'; $VDAC_status='CONGESTION'; $CPDfound++;} - if ($cpd_result =~ /Sit-Reorder/i) {$VDL_status='CPDSR'; $VDAC_status='CONGESTION'; $CPDfound++;} - if ($cpd_result =~ /Sit-Unknown/i) {$VDL_status='CPDSUK'; $VDAC_status='CONGESTION'; $CPDfound++;} - if ($cpd_result =~ /Sit-Vacant/i) {$VDL_status='CPDSV'; $VDAC_status='CONGESTION'; $CPDfound++;} - if ($cpd_result =~ /\?\?\?/i) {$VDL_status='CPDERR'; $VDAC_status='NA'; $CPDfound++;} - if ($cpd_result =~ /Fax|Modem/i) {$VDL_status='AFAX'; $VDAC_status='FAX'; $CPDfound++;} - if ($cpd_result =~ /Answering-Machine/i) {$VDL_status='AA'; $VDAC_status='AMD'; $CPDfound++;} + if ($AGILOG) {$agi_string = "$sthArows|$cpd_result|$stmtA|"; &agi_output;} + ############################################################## + ### END - CPD Look for result for B/DC calls + ############################################################## } - $sthA->finish(); - if ($AGILOG) {$agi_string = "$sthArows|$cpd_result|$stmtA|"; &agi_output;} + ############################################################## - ### END - CPD Look for result for B/DC calls + ### BEGIN - KHOMP status B/DC calls based off result + ############################################################## + if (( $amd_type eq 'KHOMP' ) && ( $khomp_VDL_status ne 'ERROR' ) && ( $khomp_VDAC_status ne 'ERROR' )) + { + $VDL_status = $khomp_VDL_status; + $VDAC_status = $khomp_VDAC_status; + if ($AGILOG) {$agi_string = "-- KHOMP CPDfound=$CPDfound|khomp_action=$khomp_action|$callerid"; &agi_output;} + if ( + ( ( $khomp_action eq 'cpdunknown') && (( $cpd_unknown_action eq 'MESSAGE' ) || ( $cpd_unknown_action eq 'DISPO' ))) || + ( ( $khomp_action eq 'amdaction') && (( $cpd_amd_action eq 'MESSAGE' ) || ( $cpd_amd_action eq 'DISPO' ))) || + ( $khomp_action eq 'status') + ) + { $CPDfound = 1; } + + if ($AGILOG) {$agi_string = "-- KHOMP setting VDL_status = $VDL_status | VDAC_status = $VDAC_status"; &agi_output;} + } + ############################################################## + ### END - KHOMP status B/DC calls based off result ############################################################## } + if ( ($PRI =~ /^PRI$/) && ($callerid =~ /\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) && ( ( ($dialstatus =~ /BUSY/) || ( ($dialstatus =~ /CHANUNAVAIL/) && ($hangup_cause =~ /^1$|^28$/) ) || ( ($enhanced_disconnect_logging > 0) && ( ( ($dialstatus =~ /CONGESTION/) && ($hangup_cause =~ /^1$|^19$|^21$|^34$|^38$|^102$/) ) || ( ($dialstatus =~ /CHANUNAVAIL/) && ($hangup_cause =~ /^18$/) ) || ($dialstatus =~ /DNC|DISCONNECT/) ) ) || ($CPDfound > 0) && ($callerid !~ /^S\d\d\d\d\d\d\d\d\d\d\d\d/) ) ) ) { if ($CPDfound < 1) @@ -1167,7 +1464,7 @@ sub process_request if ( ($CPDfound > 0) && ($VDL_status !~ /AA/) ) { $stmtA = "DELETE FROM vicidial_auto_calls where callerid = '$callerid';"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} $VDACDELaffected_rows = $dbhA->do($stmtA); if ($AGILOG) {$agi_string = "-- CPD VDAC deleted: |$VDACDELaffected_rows|$callerid"; &agi_output;} } @@ -2760,3 +3057,444 @@ sub parse_asterisk_version return ( %ast_ver_hash ); } + +### code for processing KHOMP analytics +sub process_khomp_analytics + { + ( + $khomp_api_url, + $khomp_api_proxied, + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass, + $khomp_header, + $khomp_id_format, + $external_server_ip, + $campaign_id, + $callerid, + $cpd_amd_action, + $cpd_unknown_action, + $CIDlead_id + ) = @_; + + ### Extra SIP Headers begin with an X + $khomp_header = "X-" . $khomp_header; + + # determin khomp id format to use + if ($khomp_id_format eq 'CALLERCODE') + { $khomp_id = $callerid; } + elsif ($khomp_id_format eq 'CALLERCODE_EXTERNIP') + { $khomp_id = $callerid . '_' . $external_server_ip; } + elsif ($khomp_id_format eq 'CALLERCODE_CAMP_EXTERNIP') + { $khomp_id = $callerid . '_' . $campaign_id . '_' . $external_server_ip; } + + my $api_auth_time = 0; + if ( ($khomp_api_token_expire < time() ) or ( $khomp_api_token eq 'TOKENTOKENTOKEN' )) + { + if ($AGILOG) {$agi_string = "-- KHOMP API Token $khomp_api_token has expired at $khomp_api_token_expire"; &agi_output;} + + # get a new API token + my $new_khomp_api_token = ''; + if ( $khomp_api_proxied eq 'false' ) + { + ($new_khomp_api_token, $api_auth_time) = khomp_api_login( $khomp_api_login_url, $khomp_api_user, $khomp_api_pass ); + } + + # update the settings container + my $old_token_string = "khomp_api_token => $khomp_api_token"; + my $new_token_string = "khomp_api_token => $new_khomp_api_token"; + my $new_token_expire_time = time() + 3600; + my $old_token_expire_string = "khomp_api_token_expire => $khomp_api_token_expire"; + my $new_token_expire_string = "khomp_api_token_expire => $new_token_expire_time"; + + # LOCK vicidial_settings_containers + $stmtA = "LOCK TABLES vicidial_settings_containers WRITE"; + $dbhA->do($stmtA); + # UPDATE the Token + $stmtToken = "UPDATE vicidial_settings_containers SET container_entry = REGEXP_REPLACE(container_entry, '$old_token_string', '$new_token_string') WHERE container_id = 'KHOMPSETTINGS';"; + $affected_rows = $dbhA->do($stmtToken); + # UPDATE the Expire time + $stmtExpire = "UPDATE vicidial_settings_containers SET container_entry = REGEXP_REPLACE(container_entry, '$old_token_expire_string', '$new_token_expire_string') WHERE container_id = 'KHOMPSETTINGS';"; + $affected_rows = $dbhA->do($stmtExpire); + # Unlock vicidial_settings_containers + $stmtA = "UNLOCK TABLES"; + $dbhA->do($stmtA); + + if ($AGILOG) {$agi_string = "-- KHOMP SC TOKEN UPDATE|$affected_rows|$stmtToken|"; &agi_output;} + if ($AGILOG) {$agi_string = "-- KHOMP SC TOKEN EXPIRE UPDATE|$affected_rows|$stmtExpire|"; &agi_output;} + + # over write the old with the new + $khomp_api_token = $new_khomp_api_token; + } + else + { + if ($AGILOG) {$agi_string = "-- KHOMP API Token $khomp_api_token still valid till $khomp_api_token_expire"; &agi_output;} + } + + if ( $khomp_api_token ne 'TOKENTOKENTOKEN' ) + { + # build JSON object + my $khomp_request = { + 'id' => 0, + 'method' => 'CallList', + 'params' => { + 'token' => "$khomp_api_token", + 'query' => { + 'type' => "eq", + 'field' => "sip_header:$khomp_header", + 'values' => ["$khomp_id"], + }, + 'selected_fields' => ["sip_header:call-id", "start_stamp", "audio_stamp", "answer_stamp", "end_stamp", "analyzer_stamp", "analyzer_conclusion", "analyzer_pattern", "analyzer_action", "hangup_origin", "hangup_cause", "hangup_cause_sent"] + }, + 'jsonrpc' => '2.0', + }; + + # encode it as JSON +#UC# $khomp_json = encode_json( $khomp_request ); + + # call the API +#UC# ($result, $api_query_time) = khomp_json_api( $khomp_json, $khomp_api_url ); + + # check the result + if ( $result =~ /^ERROR/ ) + { + # we got an error so log it + if ($AGILOG) { $agi_string = "-- KHOMP: $result"; &agi_output; } + } + else + { + # we got a result + if ( defined $result->{'result'}->{'calls'}[0]->{'fields'} ) + { + my $khomp_call_data = $result->{'result'}->{'calls'}[0]->{'fields'}; + %parsed_data = khomp_parse_call_data( $khomp_header, $khomp_id, $callerid, $CIDlead_id, $khomp_id_format, $khomp_call_data ); + + $parsed_data{'api_auth_time'} = $api_auth_time; + $parsed_data{'api_query_time'} = $api_query_time; + + $conclusion = $parsed_data{'conclusion'}; + $pattern = $parsed_data{'pattern'}; + + my $khomp_VDL_status = ''; + my $khomp_VDAC_status = ''; + my $khomp_action = ''; + + if ( $conclusion ne "" ) + { + # we got a conclusion + if ( defined ( $conclusion_map{"$conclusion"}{"$pattern"}{'status'} ) ) + { + # see if there is a conclusion and pattern for it + $khomp_action = $conclusion_map{"$conclusion"}{"$pattern"}{'action'}; + $khomp_VDL_status = $conclusion_map{"$conclusion"}{"$pattern"}{'status'}; + $khomp_VDAC_status = $conclusion_map{"$conclusion"}{"$pattern"}{'dial_status'}; + } + elsif ( defined( $conclusion_map{"$conclusion"}{''}{'status'} ) ) + { + # there is no known pattern for it + $khomp_action = $conclusion_map{"$conclusion"}{""}{'action'}; + $khomp_VDL_status = $conclusion_map{"$conclusion"}{''}{'status'}; + $khomp_VDAC_status = $conclusion_map{"$conclusion"}{""}{'dial_status'}; + } + else + { + # there isnt even a known conclusion for it + $khomp_action = 'error'; + $khomp_VDL_status = 'KPEROR'; + $khomp_VDAC_status = 'NA'; + } + } + else + { + # no conclusion was made + if ( $parsed_data{'hangup_origin'} eq 'leg a' ) + { + # Vicidial Hung Up + # Not sure what to do here + } + elsif ( $parsed_data{'hangup_origin'} eq 'leg b' ) + { + # Khomp or Carrier Did Not Answer + if ( $parsed_data{'hangup_cause_recv'} eq '20003' ) + { + # No Channels Available on KHOMP equipment + $khomp_action = 'status'; + $khomp_VDL_status = 'KPNOCH'; + $khomp_VDAC_status = 'CONGESTION'; + } + elsif ( $parsed_data{'hangup_cause_recv'} eq '30000' ) + { + # No sip response was recieved for KHOMP's INVITE + $khomp_action = 'status'; + $khomp_VDL_status = 'KPTMOT'; + $khomp_VDAC_status = 'CONGESTION'; + } + elsif ( $parsed_data{'hangup_cause_recv'} eq '486' ) + { + # Carrier returned "Busy Here" + $khomp_action = 'status'; + $khomp_VDL_status = 'KPBUSY'; + $khomp_VDAC_status = 'BUSY'; + } + elsif ( + ( $parsed_data{'hangup_cause_recv'} eq '487' ) && + ( $parsed_data{'answer_epoch'} > 0 ) + ) + { + # Call hung up before Khomp had a conclusion + $khomp_action = 'status'; + $khomp_VDL_status = 'KPDROP'; + $khomp_VDAC_status = 'ANSWER'; + } + elsif ( $parsed_data{'hangup_cause_recv'} eq '488' ) + { + # Carrier returned "Not Acceptable Here" + # Normally an audio codec issue, but could be other things + $khomp_action = 'status'; + $khomp_VDL_status = 'KPCONG'; + $khomp_VDAC_status = 'CONGESTION'; + } + elsif ( $parsed_data{'hangup_cause_recv'} eq '500' ) + { + # Carrier returned "Internal Server Error" + $khomp_action = 'status'; + $khomp_VDL_status = 'KPCONG'; + $khomp_VDAC_status = 'CONGESTION'; + } + elsif ( $parsed_data{'hangup_cause_recv'} eq '503' ) + { + # Carrier returned "Service Unavailable" + $khomp_action = 'status'; + $khomp_VDL_status = 'KPCONG'; + $khomp_VDAC_status = 'CONGESTION'; + } + elsif ( $parsed_data{'hangup_cause_recv'} eq '603' ) + { + # Carrier returned "Decline" + $khomp_action = 'status'; + $khomp_VDL_status = 'KPCONG'; + $khomp_VDAC_status = 'CONGESTION'; + } + else + { + $khomp_action = 'error'; + $khomp_VDL_status = 'KPEROR'; + $khomp_VDAC_status = 'NA'; + } + } + } + + if ( $khomp_action ne '' ) { $parsed_data{'vici_action'} = "$khomp_action"; } + if ( $khomp_VDL_status ne '' ) { $parsed_data{'vici_status'} = "$khomp_VDL_status"; } + + # log the khomp data in the vicidial_khomp_log + log_khomp_call_data( %parsed_data); + + if ($AGILOG) { $agi_string = "--KHOMP: conclusion = $conclusion|pattern = $pattern|status = $khomp_VDL_status"; &agi_output; } + + return ( $khomp_action, $khomp_VDL_status, $khomp_VDAC_status ); + + } + else + { + if ($AGILOG) { $agi_string = "-- KHOMP: No Call Record Found"; &agi_output; } + return ( 'error', 'ERROR', 'ERROR' ); + } + + } + } + else + { + if ($AGILOG) { $agi_string = "--KHOMP: Login Failed"; &agi_output; } + return ( 'error', 'ERROR', 'ERROR'); + } + } + +# code to log the khomp data in vicidial_khomp_log +sub log_khomp_call_data + { + (%khomp_call_data) = @_; + + $stmtA = "UPDATE vicidial_khomp_log SET caller_code = '$khomp_call_data{'caller_code'}', lead_id = '$khomp_call_data{'lead_id'}', server_ip = '$VARserver_ip', khomp_header = '$khomp_call_data{'khomp_header'}', khomp_id = '$khomp_call_data{'khomp_id'}', khomp_id_format = '$khomp_call_data{'khomp_id_format'}', hangup_auth_time = '$khomp_call_data{'api_auth_time'}', hangup_query_time = '$khomp_call_data{'api_query_time'}'"; + + if ( defined( $khomp_call_data{'sip_call_id'} ) ) { $stmtA .= ", sip_call_id = '$khomp_call_data{'sip_call_id'}'"; } + if ( defined( $khomp_call_data{'start_epoch'} ) ) { $stmtA .= ", start_date = FROM_UNIXTIME($khomp_call_data{'start_epoch'})"; } + if ( defined( $khomp_call_data{'audio_epoch'} ) ) { $stmtA .= ", audio_date = FROM_UNIXTIME($khomp_call_data{'audio_epoch'})"; } + if ( defined( $khomp_call_data{'answer_epoch'} ) ) { $stmtA .= ", answer_date = FROM_UNIXTIME($khomp_call_data{'answer_epoch'})"; } + if ( defined( $khomp_call_data{'end_epoch'} ) ) { $stmtA .= ", end_date = FROM_UNIXTIME($khomp_call_data{'end_epoch'})"; } + if ( defined( $khomp_call_data{'analyzer_epoch'} ) ) { $stmtA .= ", analyzer_date = FROM_UNIXTIME($khomp_call_data{'analyzer_epoch'})"; } + if ( defined( $khomp_call_data{'conclusion'} ) ) { $stmtA .= ", conclusion = '$khomp_call_data{'conclusion'}'"; } + if ( defined( $khomp_call_data{'pattern'} ) ) { $stmtA .= ", pattern = '$khomp_call_data{'pattern'}'"; } + if ( defined( $khomp_call_data{'action'} ) ) { $stmtA .= ", action = '$khomp_call_data{'action'}'"; } + if ( defined( $khomp_call_data{'hangup_origin'} ) ) { $stmtA .= ", hangup_origin = '$khomp_call_data{'hangup_origin'}'"; } + if ( defined( $khomp_call_data{'hangup_cause_recv'} ) ) { $stmtA .= ", hangup_cause_recv = '$khomp_call_data{'hangup_cause_recv'}'"; } + if ( defined( $khomp_call_data{'hangup_cause_sent'} ) ) { $stmtA .= ", hangup_cause_sent = '$khomp_call_data{'hangup_cause_sent'}'"; } + if ( defined( $khomp_call_data{'vici_action'} ) ) { $stmtA .= ", vici_action = '$khomp_call_data{'vici_action'}'"; } + if ( defined( $khomp_call_data{'vici_status'} ) ) { $stmtA .= ", vici_status = '$khomp_call_data{'vici_status'}'"; } + + $stmtA .= " WHERE khomp_id = '$khomp_call_data{'khomp_id'}'"; + + $affected_rows = $dbhA->do($stmtA); + + if ($AGILOG) {$agi_string = "-- KHOMP Log Update: |$stmtA|$affected_rows|"; &agi_output;} + + } + +### code for parsing the call data into a useful data structure +sub khomp_parse_call_data + { + ( $khomp_header, $khomp_id, $callerid, $lead_id, $khomp_id_format, $khomp_call_data ) = @_; + + my %new_khomp_call_data; + + + #KHOMP Field Names - Meaning: + # sip_header:call-id - leg A - SIP Call-ID + # start_stamp - unix timestamp of the call start (first INVITE) + # audio_stamp - unix timestamp of the audio start (183) + # answer_stamp - unix timestamp of the call answer (200 OK) + # end_stamp - unix timestamp of call end + # analyzer_stamp - unix timestamp of Analytics conclusion + # analyzer_conclusion - the Analytics conclusion + # analyzer_pattern - The specific pattern that was detected (if any) + # analyzer_action - the action taken for the analytics conclusion + # hangup_origin - which leg hangup the call: leg a or leg b + # hangup_cause - hangup cause received + # hangup_cause_sent - the cause code that was sent + # + + $new_khomp_call_data{'caller_code'} = $callerid; + $new_khomp_call_data{'lead_id'} = $lead_id; + $new_khomp_call_data{'khomp_header'} = $khomp_header; + $new_khomp_call_data{'khomp_id'} = $khomp_id; + $new_khomp_call_data{'khomp_id_format'} = $khomp_id_format; + $new_khomp_call_data{'sip_call_id'} = $khomp_call_data->{'sip_header:call-id'}; + $new_khomp_call_data{'start_epoch'} = $khomp_call_data->{'start_stamp'}; + $new_khomp_call_data{'audio_epoch'} = $khomp_call_data->{'audio_stamp'}; + $new_khomp_call_data{'answer_epoch'} = $khomp_call_data->{'answer_stamp'}; + $new_khomp_call_data{'end_epoch'} = $khomp_call_data->{'end_stamp'}; + $new_khomp_call_data{'analyzer_epoch'} = $khomp_call_data->{'analyzer_stamp'}; + $new_khomp_call_data{'conclusion'} = $khomp_call_data->{'analyzer_conclusion'}; + $new_khomp_call_data{'pattern'} = $khomp_call_data->{'analyzer_pattern'}; + $new_khomp_call_data{'action'} = $khomp_call_data->{'analyzer_action'}; + $new_khomp_call_data{'hangup_origin'} = $khomp_call_data->{'hangup_origin'}; + $new_khomp_call_data{'hangup_cause_recv'} = $khomp_call_data->{'hangup_cause'}; + $new_khomp_call_data{'hangup_cause_sent'} = $khomp_call_data->{'hangup_cause_sent'}; + + # handle blank times + if ($new_khomp_call_data{'start_epoch'} eq '') { $new_khomp_call_data{'start_epoch'} = 0; } + if ($new_khomp_call_data{'audio_epoch'} eq '') { $new_khomp_call_data{'audio_epoch'} = 0; } + if ($new_khomp_call_data{'answer_epoch'} eq '') { $new_khomp_call_data{'answer_epoch'} = 0; } + if ($new_khomp_call_data{'end_epoch'} eq '') { $new_khomp_call_data{'end_epoch'} = 0; } + if ($new_khomp_call_data{'analyzer_epoch'} eq '') { $new_khomp_call_data{'analyzer_epoch'} = 0; } + + # time is returned in milliseconds since 1970 we need seconds + if ($new_khomp_call_data{'start_epoch'} > 0) { $new_khomp_call_data{'start_epoch'} = $new_khomp_call_data{'start_epoch'} / 1000; } + if ($new_khomp_call_data{'audio_epoch'} > 0) { $new_khomp_call_data{'audio_epoch'} = $new_khomp_call_data{'audio_epoch'} / 1000; } + if ($new_khomp_call_data{'answer_epoch'} > 0) { $new_khomp_call_data{'answer_epoch'} = $new_khomp_call_data{'answer_epoch'} / 1000; } + if ($new_khomp_call_data{'end_epoch'} > 0) { $new_khomp_call_data{'end_epoch'} = $new_khomp_call_data{'end_epoch'} / 1000; } + if ($new_khomp_call_data{'analyzer_epoch'} > 0) { $new_khomp_call_data{'analyzer_epoch'} = $new_khomp_call_data{'analyzer_epoch'} / 1000; } + + return %new_khomp_call_data; + } + +### code for logging into KHOMP api +sub khomp_api_login + { + ( + $khomp_api_login_url, + $khomp_api_user, + $khomp_api_pass + ) = @_; + + my $token = 'login'; + my $auth_start_sec; + my $auth_start_usec; + my $auth_end_sec; + my $auth_end_usec; + my $auth_sec; + my $auth_usec; + my $api_auth_time; + + ($auth_start_sec, $auth_start_usec) = gettimeofday(); + + # build JSON object + my $login_json = { + 'id' => 0, + 'method' => 'SessionLogin', + 'params' => { + 'username' => "$khomp_api_user", + 'password' => "$khomp_api_pass", + }, + 'jsonrpc' => '2.0', + }; + + # encode it as JSON +#UC# $login_json = encode_json( $login_json ); + + my $curl_cmd = "$curlbin -sS --data \'$login_json\' $khomp_api_login_url"; + + $agi_string = "-- KHOMP CURL COMMAND: $curl_cmd"; &agi_output; + + $message = `$curl_cmd`; + + chomp($message); + + if ($AGILOG) + { + $agi_string = "-- KHOMP LOGIN URL: |$khomp_api_login_url|"; &agi_output; + $agi_string = "-- KHOMP LOGIN JSON : |$login_json|"; &agi_output; + $agi_string = "-- KHOMP LOGIN RESPONSE JSON: |$message|"; &agi_output; + } + +#UC# $json = JSON::PP->new->ascii->pretty->allow_nonref; +#UC# $result = $json->decode($message); + + $token = $result->{'result'}->{'token'}; + + ($auth_end_sec, $auth_end_usec) = gettimeofday(); + + $api_auth_time = tv_interval ( [$auth_start_sec, $auth_start_usec], [$auth_end_sec, $auth_end_usec]); + + return ($token, $api_auth_time); + } + +### code for connecting to KHOMP api and passing JSON +sub khomp_json_api + { + ( $khomp_json, $khomp_api_url ) = @_; + + my $query_start_sec; + my $query_start_usec; + my $query_end_sec; + my $query_end_usec; + my $query_sec; + my $query_usec; + my $api_query_time; + + ($query_start_sec, $query_start_usec) = gettimeofday(); + + my $curl_cmd = "$curlbin -sS --data \'$khomp_json\' $khomp_api_url"; + + $agi_string = "-- KHOMP CURL COMMAND: $curl_cmd"; &agi_output; + + $message = `$curl_cmd`; + + chomp($message); + + if ($AGILOG) + { + $agi_string = "-- KHOMP URL: |$khomp_api_url|"; &agi_output; + $agi_string = "-- KHOMP JSON : |$khomp_json|"; &agi_output; + $agi_string = "-- KHOMP RESPONSE JSON: |$message|"; &agi_output; + } + +#UC# $json = JSON::PP->new->ascii->pretty->allow_nonref; +#UC# $result = $json->decode($message); + + ($query_end_sec, $query_end_usec) = gettimeofday(); + + $api_query_time = tv_interval ( [$query_start_sec, $query_start_usec], [$query_end_sec, $query_end_usec]); + + return ($result, $api_query_time); + } diff --git a/agc_2-X/trunk/docs/KHOMP_CPD_INTEGRATION.txt b/agc_2-X/trunk/docs/KHOMP_CPD_INTEGRATION.txt index 06f2d3f9..c7dfdc38 100644 --- a/agc_2-X/trunk/docs/KHOMP_CPD_INTEGRATION.txt +++ b/agc_2-X/trunk/docs/KHOMP_CPD_INTEGRATION.txt @@ -1,4 +1,4 @@ -KHOMP Answering Machine Detection Started: 2018-09-29 Update: 2021-07-20 +KHOMP Answering Machine Detection Started: 2018-09-29 Update: 2021-09-07 The KHOMP Analytics Integration code, installation and configuration information @@ -21,6 +21,7 @@ Here are a few basic things to check with KHOMP if you are experiencing issues, c. Make sure campaign's "AMD Type" is set to 'KHOMP' d. Make sure the campaign's "Routing Extension" is set to '8368'. e. If you want to leave answering machine messages make sure the "CPD AMD Action" and "CPD Unknown Actions" are setup to do so. + 2. "Why did this call do this thing?" a. Do a lead search for the phone number. b. Bring up the lead. @@ -29,6 +30,7 @@ Here are a few basic things to check with KHOMP if you are experiencing issues, e. Note the 'Conclusion' and 'Pattern' KHOMP returned. f. Go to "Reports -> Admin Utilities -> Dialer KHOMP Admin Tool". g. Search for the Conclusion / Pattern in the list and verify that it is configured to do what you expect. + 3. "Something is clearly wrong. Every call is coming back as *SOME WEIRD CONCLUSION*" a. Recommend they reboot the KHOMP server. b. Disable KHOMP in the campaign. @@ -37,3 +39,7 @@ Here are a few basic things to check with KHOMP if you are experiencing issues, III. If they want to use Asterisk AMD set the "Campaign Routing Extension" appropriately. c. Have the manager wait until all their existing calls from before the change have ended. d. Reboot the Khomp Server by going into Administration -> "Reboot The Gateway" in the Khomp interface. + +4. "All of my answered calls are being set as PU, what's going on?" + a. The KHOMP server itself needs to either have a valid SSL certificate from a valid certificate authority, or HTTPS needs to be disabled on the KHOMP server. + If you don't do this, curl will refuse to connect to the API and all answered calls will end up as PU. diff --git a/agc_2-X/trunk/extras/KHOMP/FastAGI_log.pl b/agc_2-X/trunk/extras/KHOMP/FastAGI_log.pl index ee1ddf32..04161c1d 100644 --- a/agc_2-X/trunk/extras/KHOMP/FastAGI_log.pl +++ b/agc_2-X/trunk/extras/KHOMP/FastAGI_log.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl # -# FastAGI_log.pl version 2.14 (KHOMP VERSION as of svn/trunk rev 3198) +# FastAGI_log.pl version 2.14 (KHOMP VERSION as of svn/trunk rev 3524) # # Experimental Deamon using perl Net::Server that runs as FastAGI to reduce load # replaces the following AGI scripts: @@ -25,7 +25,7 @@ # exten => h,1,DeadAGI(agi://127.0.0.1:4577/call_log--HVcauses--PRI-----NODEBUG-----${HANGUPCAUSE}-----${DIALSTATUS}-----${DIALEDTIME}-----${ANSWEREDTIME}) # # -# Copyright (C) 2020 Matt Florell LICENSE: AGPLv2 +# Copyright (C) 2021 Matt Florell LICENSE: AGPLv2 # # CHANGELOG: # 61010-1007 - First test build @@ -85,7 +85,13 @@ # 190626-1100 - Added more logging for Auto-Alt-Dial debug # 190709-2240 - Added Call Quota logging # 191001-1509 - Small fix for monitoring issue -# 200210-1644 - Added KHOMP code +# 200318-1054 - Added code for OpenSIPs CallerIDname +# 210314-1015 - Added enhanced_disconnect_logging=2 option +# 210606-1007 - Added TILTX features for pre-carrier call filtering +# 210718-0358 - Fixes for 24-Hour Call Count Limits with standard Auto-Alt-Dialing +# 210719-1521 - Added additional state override methods for call_limit_24hour +# 210827-0936 - Added PJSIP compatibility +# 210907-0841 - Added KHOMP code (install JSON::PP Perl module and remove '#UC#' in the code to enable) # # defaults for PreFork @@ -188,7 +194,7 @@ use Time::HiRes ('tv_interval','gettimeofday','usleep','sleep'); # necessary to use Time::Local; # Needed for Khomp Integration -use JSON::PP qw(encode_json decode_json); + use JSON::PP qw(encode_json decode_json); ### find curl binary for KHOMP $curlbin = ''; @@ -273,6 +279,7 @@ sub process_request if (!$VARDB_port) {$VARDB_port='3306';} if (!$AGILOGfile) {$AGILOGfile = "$PATHlogs/FASTagiout.$year-$mon-$mday";} + if (!$AADLOGfile) {$AADLOGfile = "$PATHlogs/auto-alt-dial.$year-$mon-$mday";} $dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_user", "$VARDB_pass") or die "Couldn't connect to database: " . DBI->errstr; @@ -288,7 +295,7 @@ sub process_request @aryA = $sthA->fetchrow_array; $DBagi_output = $aryA[0]; $asterisk_version = $aryA[1]; - $external_server_ip = $aryA[2]; + $external_server_ip = $aryA[2]; if ($DBagi_output =~ /STDERR/) {$AGILOG = '1';} if ($DBagi_output =~ /FILE/) {$AGILOG = '2';} if ($DBagi_output =~ /BOTH/) {$AGILOG = '3';} @@ -511,9 +518,9 @@ sub process_request $dial_time = $ARGV_vars[4]; $answered_time = $ARGV_vars[5]; $tech_hangup_cause = $ARGV_vars[6]; - if( $dial_time > $answered_time ) + if( $dial_time > $answered_time ) {$ring_time = $dial_time - $answered_time;} - else + else {$ring_time = 0;} $agi_string = "URL HVcauses: |$PRI|$DEBUG|$hangup_cause|$dialstatus|$dial_time|$ring_time|$tech_hangup_cause|"; &agi_output; @@ -594,7 +601,7 @@ sub process_request if ($AGILOG) {$agi_string = "+++++ CALL LOG START : $now_date"; &agi_output;} - if ($channel =~ /^SIP/) {$channel =~ s/-.*//gi;} + if ($channel =~ /^SIP|^PJSIP/) {$channel =~ s/-.*//gi;} if ($channel =~ /^IAX2/) {$channel =~ s/\/\d+$//gi;} if ($channel =~ /^Zap\/|^DAHDI\//) { @@ -645,7 +652,7 @@ sub process_request if ($AGILOG) {$agi_string = $channel_group . ": $aryA[0]|$channel_line|"; &agi_output;} } ### This section breaks the outbound dialed number down(or builds it up) to a 10 digit number and gives it a description - if ( ($channel =~ /^SIP|^IAX2/) || ( ($is_client_phone > 0) && (length($channel_group) < 1) ) ) + if ( ($channel =~ /^SIP|^PJSIP|^IAX2/) || ( ($is_client_phone > 0) && (length($channel_group) < 1) ) ) { if ( ($extension =~ /^901144/) && (length($extension)==16) ) #test 207 608 6400 {$extension =~ s/^9//gi; $channel_group = 'Outbound Intl UK';} @@ -662,7 +669,7 @@ sub process_request if ($is_client_phone > 0) {$channel_group = 'Client Phone';} - $SIP_ext = $channel; $SIP_ext =~ s/SIP\/|IAX2\/|Zap\/|DAHDI\/|Local\///gi; + $SIP_ext = $channel; $SIP_ext =~ s/PJSIP\/|SIP\/|IAX2\/|Zap\/|DAHDI\/|Local\///gi; $number_dialed = $extension; $extension = $SIP_ext; @@ -702,7 +709,7 @@ sub process_request if ($sthArows > 0) { @aryA = $sthA->fetchrow_array; - $CAMPCUST = $aryA[0]; + $CAMPCUST = $aryA[0]; $campaign = $aryA[0]; } $sthA->finish(); @@ -721,12 +728,53 @@ sub process_request $sthA->finish(); ### set dialplan variable CAMPCUST to the campaign_id of the outbound auto-dial or manual dial call - if ((length($CAMPCUST) > 0) && ($DP_variables_enabled > 0) ) + if (length($CAMPCUST) > 0) { $AGI->exec("EXEC Set(_CAMPCUST=$CAMPCUST)"); if ($AGILOG) {$agi_string = "|CAMPCUST: $CAMPCUST|$callerid|"; &agi_output;} } + + ### BEGIN OpenSIPs CallerIDname code ### + ### get system_settings + $stmtA = "SELECT opensips_cid_name FROM system_settings"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $opensips_cid_name = $aryA[0]; + } + $sthA->finish(); + if ($AGILOG) {$agi_string = "$stmtA|$opensips_cid_name"; &agi_output;} + + ### opensips_cid_name is active + if ( $opensips_cid_name == 1) + { + ### get the Campaign CID Name + $stmtA = "SELECT opensips_cid_name FROM vicidial_campaigns where campaign_id = '$CAMPCUST';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $camp_opensips_cid_name = $aryA[0]; + } + $sthA->finish(); + if ($AGILOG) {$agi_string = "$stmtA|$camp_opensips_cid_name"; &agi_output;} + + ### check that the campaign has a CID Name set + if ( $camp_opensips_cid_name ne "" ) + { + if ($AGILOG) {$agi_string = "Adding \"X-CIDNAME: $camp_opensips_cid_name\" header to INVITE"; &agi_output;} + $header = "X-CIDNAME: " . $camp_opensips_cid_name; + $AGI->exec("EXEC SIPAddHeader(\"$header\")"); + } + } + ### END OpenSIPs CallerIDname code ### + if ($AGILOG) {$agi_string = "|KHOMP $amd_type|$HVcauses|$extension|$campaign_vdad_exten"; &agi_output;} ### Add the KHOMP SIP X header to the outbound call @@ -755,10 +803,7 @@ sub process_request $AGI->exec("EXEC SIPAddHeader(\"$sub_header\")"); if ($AGILOG) {$agi_string = "|KHOMP Sub Account Header= $sub_header|"; &agi_output;} } - - } - } $stmtA = "INSERT INTO call_log (uniqueid,channel,channel_group,type,server_ip,extension,number_dialed,start_time,start_epoch,end_time,end_epoch,length_in_sec,length_in_min,caller_code) values('$unique_id','$channel','$channel_group','$type','$VARserver_ip','$extension','$number_dialed','$now_date','$now_date_epoch','','','','','$callerid')"; @@ -941,6 +986,7 @@ sub process_request if ( ( ($callerid =~ /^BM\d\d\d\d\d\d\d\d/) && ($channel =~ /ASTblind/) ) || ($callerid =~ /^BB\d\d\d\d\d\d\d\d/) || ($callerid =~ /^BW\d\d\d\d\d\d\d\d/) ) { $stmtA = "SELECT monitor_start_time,UNIX_TIMESTAMP(monitor_start_time) from vicidial_rt_monitor_log where caller_code='$callerid' and ( (monitor_end_time is NULL) or (monitor_start_time=monitor_end_time) );"; + # if ($AGILOG) {$agi_string = "|JCJ|$stmtA|$monitor_start_time|$EPOCHmonitor_start_time|"; &agi_output;} $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; $sthArows=$sthA->rows; @@ -1265,8 +1311,8 @@ sub process_request } ############################################################## - ### BEGIN - KHOMP status B/DC calls based off result - ############################################################## + ### BEGIN - KHOMP status B/DC calls based off result + ############################################################## if (( $amd_type eq 'KHOMP' ) && ( $khomp_VDL_status ne 'ERROR' ) && ( $khomp_VDAC_status ne 'ERROR' )) { $VDL_status = $khomp_VDL_status; @@ -1276,26 +1322,44 @@ sub process_request ( ( $khomp_action eq 'cpdunknown') && (( $cpd_unknown_action eq 'MESSAGE' ) || ( $cpd_unknown_action eq 'DISPO' ))) || ( ( $khomp_action eq 'amdaction') && (( $cpd_amd_action eq 'MESSAGE' ) || ( $cpd_amd_action eq 'DISPO' ))) || ( $khomp_action eq 'status') - ) + ) { $CPDfound = 1; } if ($AGILOG) {$agi_string = "-- KHOMP setting VDL_status = $VDL_status | VDAC_status = $VDAC_status"; &agi_output;} } ############################################################## - ### END - KHOMP status B/DC calls based off result - ############################################################## - + ### END - KHOMP status B/DC calls based off result + ############################################################## } - if ( ($PRI =~ /^PRI$/) && ($callerid =~ /\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) && ( ( ($dialstatus =~ /BUSY/) || ( ($dialstatus =~ /CHANUNAVAIL/) && ($hangup_cause =~ /^1$|^28$/) ) || ( ($enhanced_disconnect_logging > 0) && ( ($dialstatus =~ /CONGESTION/) && ($hangup_cause =~ /^1$|^19$|^21$|^34$|^38$/) ) ) ) || ($CPDfound > 0) ) && ($callerid !~ /^S\d\d\d\d\d\d\d\d\d\d\d\d/) ) + + if ( ($PRI =~ /^PRI$/) && ($callerid =~ /\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) && ( ( ($dialstatus =~ /BUSY/) || ( ($dialstatus =~ /CHANUNAVAIL/) && ($hangup_cause =~ /^1$|^28$/) ) || ( ($enhanced_disconnect_logging > 0) && ( ( ($dialstatus =~ /CONGESTION/) && ($hangup_cause =~ /^1$|^19$|^21$|^34$|^38$|^102$/) ) || ( ($dialstatus =~ /CHANUNAVAIL/) && ($hangup_cause =~ /^18$/) ) || ($dialstatus =~ /DNC|DISCONNECT/) ) ) || ($CPDfound > 0) && ($callerid !~ /^S\d\d\d\d\d\d\d\d\d\d\d\d/) ) ) ) { if ($CPDfound < 1) { - if ($dialstatus =~ /BUSY/) {$VDL_status = 'AB'; $VDAC_status = 'BUSY';} - if ($dialstatus =~ /CHANUNAVAIL/) {$VDL_status = 'ADC'; $VDAC_status = 'DISCONNECT';} - if ($enhanced_disconnect_logging > 0) + if ($enhanced_disconnect_logging == '2') { - if ($dialstatus =~ /CONGESTION/ && $hangup_cause =~ /^1$/) {$VDL_status = 'ADC'; $VDAC_status = 'DISCONNECT';} - if ($dialstatus =~ /CONGESTION/ && $hangup_cause =~ /^19$|^21$|^34$|^38$/) {$VDL_status = 'ADCT'; $VDAC_status = 'DISCONNECT';} + if ($dialstatus =~ /BUSY/) {$VDL_status = 'AB'; $VDAC_status = 'BUSY';} + if ($dialstatus =~ /CHANUNAVAIL/) {$VDL_status = 'ADC'; $VDAC_status = 'DISCONNECT';} + if ($enhanced_disconnect_logging > 0) + { + if ($dialstatus =~ /CHANUNAVAIL/ && $hangup_cause =~/^18/) {$VDL_status = 'ADCT'; $VDAC_status = 'DISCONNECT';} + if ($dialstatus =~ /CONGESTION/ && $hangup_cause =~ /^1$/) {$VDL_status = 'ADC'; $VDAC_status = 'DISCONNECT';} + if (($dialstatus =~ /CONGESTION/ && $hangup_cause =~ /^21$|^34$|^38$|^102$/) || ($dialstatus =~ /BUSY/ && $hangup_cause =~ /^19$/)) {$VDL_status = 'ADCT'; $VDAC_status = 'DISCONNECT';} + if ($dialstatus =~ /DISCONNECT/) {$VDL_status = 'ADCCAR'; $VDAC_status = 'ADCCAR';} # pre-carrier disconnect filter + if ($dialstatus =~ /DNC/) {$VDL_status = 'DNCCAR'; $VDAC_status = 'DNCCAR';} # pre-carrier DNC filter + } + } + else + { + if ($dialstatus =~ /BUSY/) {$VDL_status = 'AB'; $VDAC_status = 'BUSY';} + if ($dialstatus =~ /CHANUNAVAIL/) {$VDL_status = 'ADC'; $VDAC_status = 'DISCONNECT';} + if ($enhanced_disconnect_logging > 0) + { + if ($dialstatus =~ /CONGESTION/ && $hangup_cause =~ /^1$/) {$VDL_status = 'ADC'; $VDAC_status = 'DISCONNECT';} + if ($dialstatus =~ /CONGESTION/ && $hangup_cause =~ /^19$|^21$|^34$|^38$/) {$VDL_status = 'ADCT'; $VDAC_status = 'DISCONNECT';} + if ($dialstatus =~ /DISCONNECT/) {$VDL_status = 'ADCCAR'; $VDAC_status = 'ADCCAR';} # pre-carrier disconnect filter + if ($dialstatus =~ /DNC/) {$VDL_status = 'DNCCAR'; $VDAC_status = 'DNCCAR';} # pre-carrier DNC filter + } } } @@ -1724,7 +1788,7 @@ sub process_request ############################################# ##### SYSTEM SETTINGS LOOKUP ##### - $stmtA = "SELECT enable_drop_lists,call_quota_lead_ranking,timeclock_end_of_day FROM system_settings;"; + $stmtA = "SELECT enable_drop_lists,call_quota_lead_ranking,timeclock_end_of_day,call_limit_24hour FROM system_settings;"; $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; $sthArows=$sthA->rows; @@ -1734,6 +1798,7 @@ sub process_request $enable_drop_lists = $aryA[0]; $SScall_quota_lead_ranking = $aryA[1]; $timeclock_end_of_day = $aryA[2]; + $SScall_limit_24hour = $aryA[3]; } $sthA->finish(); ##### END SYSTEM SETTINGS LOOKUP ##### @@ -1971,7 +2036,7 @@ sub process_request $VD_auto_alt_dial = 'NONE'; $VD_auto_alt_dial_statuses=''; $VD_call_quota_lead_ranking='DISABLED'; - $stmtA="SELECT auto_alt_dial,auto_alt_dial_statuses,use_internal_dnc,use_campaign_dnc,use_other_campaign_dnc,call_quota_lead_ranking FROM vicidial_campaigns where campaign_id='$VD_campaign_id';"; + $stmtA="SELECT auto_alt_dial,auto_alt_dial_statuses,use_internal_dnc,use_campaign_dnc,use_other_campaign_dnc,call_quota_lead_ranking,call_limit_24hour_method,call_limit_24hour_scope,call_limit_24hour,call_limit_24hour_override FROM vicidial_campaigns where campaign_id='$VD_campaign_id';"; if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; @@ -1980,12 +2045,16 @@ sub process_request while ($sthArows > $epc_countCAMPDATA) { @aryA = $sthA->fetchrow_array; - $VD_auto_alt_dial = $aryA[0]; - $VD_auto_alt_dial_statuses = $aryA[1]; - $VD_use_internal_dnc = $aryA[2]; - $VD_use_campaign_dnc = $aryA[3]; - $VD_use_other_campaign_dnc = $aryA[4]; - $VD_call_quota_lead_ranking = $aryA[5]; + $VD_auto_alt_dial = $aryA[0]; + $VD_auto_alt_dial_statuses = $aryA[1]; + $VD_use_internal_dnc = $aryA[2]; + $VD_use_campaign_dnc = $aryA[3]; + $VD_use_other_campaign_dnc = $aryA[4]; + $VD_call_quota_lead_ranking = $aryA[5]; + $VD_call_limit_24hour_method = $aryA[6]; + $VD_call_limit_24hour_scope = $aryA[7]; + $VD_call_limit_24hour = $aryA[8]; + $VD_call_limit_24hour_override = $aryA[9]; $epc_countCAMPDATA++; } @@ -2005,12 +2074,13 @@ sub process_request # if ($AGILOG) {$agi_string = "AUTO-ALT TEST: |$VD_status|$VDL_status|$VD_auto_alt_dial_statuses|$VD_auto_alt_dial|"; &agi_output;} if ($VD_auto_alt_dial_statuses =~ / $VD_status | $VDL_status /) { + $alt_skip_reason=''; $addr3_skip_reason=''; if ($AGILOG) {$agi_string = "AUTO-ALT MATCH: |$VD_status|$VDL_status|$VD_auto_alt_dial_statuses|$VD_auto_alt_dial|$VD_alt_dial|$VD_alt_dial_log|"; &agi_output;} if ( ($VD_auto_alt_dial =~ /(ALT_ONLY|ALT_AND_ADDR3|ALT_AND_EXTENDED)/) && ($VD_alt_dial =~ /NONE|MAIN/) ) { $alt_dial_skip=0; $VD_alt_phone=''; - $stmtA="SELECT alt_phone,gmt_offset_now,state,list_id FROM vicidial_list where lead_id='$VD_lead_id';"; + $stmtA="SELECT alt_phone,gmt_offset_now,state,list_id,phone_code,postal_code FROM vicidial_list where lead_id='$VD_lead_id';"; if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; @@ -2024,6 +2094,8 @@ sub process_request $VD_gmt_offset_now = $aryA[1]; $VD_state = $aryA[2]; $VD_list_id = $aryA[3]; + $VD_phone_code = $aryA[4]; + $VD_postal_code = $aryA[5]; $epc_countCAMPDATA++; } $sthA->finish(); @@ -2076,23 +2148,42 @@ sub process_request } if ($VD_alt_dnc_count < 1) { - $stmtA = "INSERT INTO vicidial_hopper SET lead_id='$VD_lead_id',campaign_id='$VD_campaign_id',status='READY',list_id='$VD_list_id',gmt_offset_now='$VD_gmt_offset_now',state='$VD_state',alt_dial='ALT',user='',priority='25',source='A';"; - $affected_rows = $dbhA->do($stmtA); - if ($AGILOG) {$agi_string = "-- VDH record inserted: |$affected_rows| |$stmtA|"; &agi_output;} + $passed_24hour_call_count=1; + if ( ($SScall_limit_24hour > 0) && ($VD_call_limit_24hour_method =~ /PHONE_NUMBER|LEAD/) ) + { + $temp_24hour_phone = $VD_alt_phone; + $temp_24hour_phone_code = $VD_phone_code; + $temp_24hour_state = $VD_state; + $temp_24hour_postal_code = $VD_postal_code; + if ($DB > 0) {print "24-Hour Call Count Check: $SScall_limit_24hour|$VD_call_limit_24hour_method|$VD_lead_id|\n";} + &check_24hour_call_count; + } + if ($passed_24hour_call_count > 0) + { + $stmtA = "INSERT INTO vicidial_hopper SET lead_id='$VD_lead_id',campaign_id='$VD_campaign_id',status='READY',list_id='$VD_list_id',gmt_offset_now='$VD_gmt_offset_now',state='$VD_state',alt_dial='ALT',user='',priority='25',source='A';"; + $affected_rows = $dbhA->do($stmtA); + if ($AGILOG) {$agi_string = "-- VDH record inserted: |$affected_rows| |$stmtA|"; &agi_output;} + if ($AGILOG) {$aad_string = "$VD_lead_id|$VD_alt_phone|$VD_campaign_id|ALT|25|hopper insert|"; &aad_output;} + } + else + {$alt_dial_skip=1; $alt_skip_reason='24-hour call count limit failed';} } else - {$alt_dial_skip=1;} + {$alt_dial_skip=1; $alt_skip_reason='DNC check failed';} } else - {$alt_dial_skip=1;} + {$alt_dial_skip=1; $alt_skip_reason='ALT phone invalid';} if ($alt_dial_skip > 0) - {$VD_alt_dial='ALT';} + { + $VD_alt_dial='ALT'; + if ($AGILOG) {$aad_string = "$VD_lead_id|$VD_alt_phone|$VD_campaign_id|ALT|0|hopper skip|$alt_skip_reason|"; &aad_output;} + } } if ( ( ($VD_auto_alt_dial =~ /(ADDR3_ONLY)/) && ($VD_alt_dial =~ /NONE|MAIN/) ) || ( ($VD_auto_alt_dial =~ /(ALT_AND_ADDR3)/) && ($VD_alt_dial =~ /ALT/) ) ) { $addr3_dial_skip=0; $VD_address3=''; - $stmtA="SELECT address3,gmt_offset_now,state,list_id FROM vicidial_list where lead_id='$VD_lead_id';"; + $stmtA="SELECT address3,gmt_offset_now,state,list_id,phone_code,postal_code FROM vicidial_list where lead_id='$VD_lead_id';"; if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; @@ -2106,6 +2197,8 @@ sub process_request $VD_gmt_offset_now = $aryA[1]; $VD_state = $aryA[2]; $VD_list_id = $aryA[3]; + $VD_phone_code = $aryA[4]; + $VD_postal_code = $aryA[5]; $epc_countCAMPDATA++; } $sthA->finish(); @@ -2158,17 +2251,36 @@ sub process_request } if ($VD_alt_dnc_count < 1) { - $stmtA = "INSERT INTO vicidial_hopper SET lead_id='$VD_lead_id',campaign_id='$VD_campaign_id',status='READY',list_id='$VD_list_id',gmt_offset_now='$VD_gmt_offset_now',state='$VD_state',alt_dial='ADDR3',user='',priority='20',source='A';"; - $affected_rows = $dbhA->do($stmtA); - if ($AGILOG) {$agi_string = "-- VDH record inserted: |$affected_rows| |$stmtA|"; &agi_output;} + $passed_24hour_call_count=1; + if ( ($SScall_limit_24hour > 0) && ($VD_call_limit_24hour_method =~ /PHONE_NUMBER|LEAD/) ) + { + $temp_24hour_phone = $VD_address3; + $temp_24hour_phone_code = $VD_phone_code; + $temp_24hour_state = $VD_state; + $temp_24hour_postal_code = $VD_postal_code; + if ($DB > 0) {print "24-Hour Call Count Check: $SScall_limit_24hour|$VD_call_limit_24hour_method|$VD_lead_id|\n";} + &check_24hour_call_count; + } + if ($passed_24hour_call_count > 0) + { + $stmtA = "INSERT INTO vicidial_hopper SET lead_id='$VD_lead_id',campaign_id='$VD_campaign_id',status='READY',list_id='$VD_list_id',gmt_offset_now='$VD_gmt_offset_now',state='$VD_state',alt_dial='ADDR3',user='',priority='20',source='A';"; + $affected_rows = $dbhA->do($stmtA); + if ($AGILOG) {$agi_string = "-- VDH record inserted: |$affected_rows| |$stmtA|"; &agi_output;} + if ($AGILOG) {$aad_string = "$VD_lead_id|$VD_address3|$VD_campaign_id|ADDR3|20|hopper insert|"; &aad_output;} + } + else + {$addr3_dial_skip=1; $addr3_skip_reason='24-hour call count limit failed';} } else - {$addr3_dial_skip=1;} + {$addr3_dial_skip=1; $addr3_skip_reason='DNC check failed';} } else - {$addr3_dial_skip=1;} + {$addr3_dial_skip=1; $addr3_skip_reason='ADDR3 phone invalid';} if ($addr3_dial_skip > 0) - {$VD_alt_dial='ADDR3';} + { + $VD_alt_dial='ADDR3'; + if ($AGILOG) {$aad_string = "$VD_lead_id|$VD_address3|$VD_campaign_id|ADDR3|0|hopper skip|$addr3_skip_reason|"; &aad_output;} + } } if ( ( ($VD_auto_alt_dial =~ /(EXTENDED_ONLY)/) && ($VD_alt_dial =~ /NONE|MAIN/) ) || ( ($VD_auto_alt_dial =~ /(ALT_AND_EXTENDED)/) && ($VD_alt_dial =~ /ALT/) ) || ( ($VD_auto_alt_dial =~ /ADDR3_AND_EXTENDED|ALT_AND_ADDR3_AND_EXTENDED/) && ($VD_alt_dial =~ /ADDR3/) ) || ( ($VD_auto_alt_dial =~ /(EXTENDED)/) && ($VD_alt_dial =~ /X/) && ($VD_alt_dial !~ /XLAST/) ) ) { @@ -2179,7 +2291,7 @@ sub process_request if (length($Xlast)<1) {$Xlast=0;} $VD_altdialx=''; - $stmtA="SELECT gmt_offset_now,state,list_id FROM vicidial_list where lead_id='$VD_lead_id';"; + $stmtA="SELECT gmt_offset_now,state,list_id,postal_code FROM vicidial_list where lead_id='$VD_lead_id';"; if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; @@ -2191,6 +2303,7 @@ sub process_request $VD_gmt_offset_now = $aryA[0]; $VD_state = $aryA[1]; $VD_list_id = $aryA[2]; + $VD_postal_code = $aryA[3]; $epc_countCAMPDATA++; } $sthA->finish(); @@ -2210,7 +2323,7 @@ sub process_request while ( ($alt_dial_phones_count > 0) && ($alt_dial_phones_count > $Xlast) ) { $Xlast++; - $stmtA="SELECT alt_phone_id,phone_number,active FROM vicidial_list_alt_phones where lead_id='$VD_lead_id' and alt_phone_count='$Xlast';"; + $stmtA="SELECT alt_phone_id,phone_number,active,phone_code FROM vicidial_list_alt_phones where lead_id='$VD_lead_id' and alt_phone_count='$Xlast';"; if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; @@ -2218,9 +2331,10 @@ sub process_request if ($sthArows > 0) { @aryA = $sthA->fetchrow_array; - $VD_altdial_id = $aryA[0]; - $VD_altdial_phone = $aryA[1]; - $VD_altdial_active = $aryA[2]; + $VD_altdial_id = $aryA[0]; + $VD_altdial_phone = $aryA[1]; + $VD_altdial_active = $aryA[2]; + $VD_altdial_phone_code = $aryA[3]; } else {$Xlast=9999999999;} @@ -2281,14 +2395,33 @@ sub process_request { if ($alt_dial_phones_count eq '$Xlast') {$Xlast = 'LAST';} - $stmtA = "INSERT INTO vicidial_hopper SET lead_id='$VD_lead_id',campaign_id='$VD_campaign_id',status='READY',list_id='$VD_list_id',gmt_offset_now='$VD_gmt_offset_now',state='$VD_state',alt_dial='X$Xlast',user='',priority='15',source='A';"; - $affected_rows = $dbhA->do($stmtA); - if ($AGILOG) {$agi_string = "-- VDH record inserted: |$affected_rows| |$stmtA|X$Xlast|$VD_altdial_id|"; &agi_output;} - $Xlast=9999999999; + $passed_24hour_call_count=1; + if ( ($SScall_limit_24hour > 0) && ($VD_call_limit_24hour_method =~ /PHONE_NUMBER|LEAD/) ) + { + $temp_24hour_phone = $VD_altdial_phone; + $temp_24hour_phone_code = $VD_altdial_phone_code; + $temp_24hour_state = $VD_state; + $temp_24hour_postal_code = $VD_postal_code; + if ($DB > 0) {print "24-Hour Call Count Check: $SScall_limit_24hour|$VD_call_limit_24hour_method|$VD_lead_id|\n";} + &check_24hour_call_count; + } + if ($passed_24hour_call_count > 0) + { + $stmtA = "INSERT INTO vicidial_hopper SET lead_id='$VD_lead_id',campaign_id='$VD_campaign_id',status='READY',list_id='$VD_list_id',gmt_offset_now='$VD_gmt_offset_now',state='$VD_state',alt_dial='X$Xlast',user='',priority='15',source='A';"; + $affected_rows = $dbhA->do($stmtA); + if ($AGILOG) {$agi_string = "-- VDH record inserted: |$affected_rows| |$stmtA|X$Xlast|$VD_altdial_id|"; &agi_output;} + if ($AGILOG) {$aad_string = "$VD_lead_id|$VD_altdial_phone|$VD_campaign_id|X$Xlast|15|hopper insert|"; &aad_output;} + $Xlast=9999999999; + $DNC_hopper_trigger=0; + } + else + {$DNC_hopper_trigger=1;} } else + {$DNC_hopper_trigger=1;} + if ($DNC_hopper_trigger > 0) { - if ( ( ($VD_auto_alt_dial_statuses =~ / DNCC /) && ($DNCC > 0) ) || ( ($VD_auto_alt_dial_statuses =~ / DNCL /) && ($DNCL > 0) ) ) + if ( ( ($VD_auto_alt_dial_statuses =~ / DNCC /) && ($DNCC > 0) ) || ( ($VD_auto_alt_dial_statuses =~ / DNCL /) && ($DNCL > 0) ) || ( ($auto_alt_dial_statuses[$i] =~ / TFHCCL /) && ($TFHCCL > 0) ) ) { if ($alt_dial_phones_count eq '$Xlast') {$Xlast = 'LAST';} @@ -2297,10 +2430,12 @@ sub process_request if ($AGILOG) {$agi_string = "-- VDH record DNC inserted: |$affected_rows| |$stmtA|X$Xlast|$VD_altdial_id|"; &agi_output;} $Xlast=9999999999; if ($AGILOG) {$agi_string = "-- VDH alt dial inserting DNC|X$Xlast|$VD_altdial_phone|"; &agi_output;} + if ($AGILOG) {$aad_string = "$VD_lead_id|$VD_altdial_phone|$VD_campaign_id|X$Xlast|15|hopper DNC insert|"; &aad_output;} } else { if ($AGILOG) {$agi_string = "-- VDH alt dial not-inserting DNC|X$Xlast|$VD_altdial_phone|"; &agi_output;} + if ($AGILOG) {$aad_string = "$VD_lead_id|$VD_altdial_phone|$VD_campaign_id|X$Xlast|15|hopper DNC skip|"; &aad_output;} } } } @@ -2670,6 +2805,186 @@ sub call_quota_logging } } +sub check_24hour_call_count + { + $passed_24hour_call_count=0; + $limit_scopeSQL=''; + if ($VD_call_limit_24hour_scope =~ /CAMPAIGN_LISTS/) + { + $limit_scopeCAMP=''; + $stmtY = "SELECT list_id FROM vicidial_lists where campaign_id='$VD_campaign_id';"; + $sthY = $dbhA->prepare($stmtY) or die "preparing: ",$dbhA->errstr; + $sthY->execute or die "executing: $stmtY", $dbhA->errstr; + $sthYrows=$sthY->rows; + $rec_campLISTS=0; + while ($sthYrows > $rec_campLISTS) + { + @aryY = $sthY->fetchrow_array; + $limit_scopeCAMP .= "'$aryY[0]',"; + $rec_campLISTS++; + } + if (length($limit_scopeCAMP) < 2) {$limit_scopeCAMP="'1'";} + else {chop($limit_scopeCAMP);} + $limit_scopeSQL = "and list_id IN($limit_scopeCAMP)"; + } + if ($VD_call_limit_24hour_method =~ /PHONE_NUMBER/) + { + $stmtA="SELECT count(*) FROM vicidial_lead_24hour_calls where phone_number='$temp_24hour_phone' and phone_code='$temp_24hour_phone_code' and (call_date >= NOW() - INTERVAL 1 DAY) $limit_scopeSQL;"; + } + else + { + $stmtA="SELECT count(*) FROM vicidial_lead_24hour_calls where lead_id='$VD_lead_id' and (call_date >= NOW() - INTERVAL 1 DAY) $limit_scopeSQL;"; + } + if ($DB) {print " Doing 24-Hour Call Count Check: $VD_lead_id|$temp_24hour_phone_code|$temp_24hour_phone|$temp_24hour_state|$temp_24hour_postal_code - $VD_call_limit_24hour_method|$VD_call_limit_24hour_scope|$VD_call_limit_24hour\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $TFhourCOUNT=0; + $TFhourSTATE=''; + $TFhourCOUNTRY=''; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $TFhourCOUNT = ($TFhourCOUNT + $aryA[0]); + } + $sthA->finish(); + $TEMPcall_limit_24hour = $VD_call_limit_24hour; + if ($DBX) {print " 24-Hour Call Limit Count DEBUG: $TFhourCOUNT|$stmtA|\n";} + + if ( ($VD_call_limit_24hour_override !~ /^DISABLED$/) && (length($VD_call_limit_24hour_override) > 0) ) + { + $TFH_areacode = substr($temp_24hour_phone, 0, 3); + $stmtY = "SELECT state,country FROM vicidial_phone_codes where country_code='$temp_24hour_phone_code' and areacode='$TFH_areacode';"; + $sthY = $dbhA->prepare($stmtY) or die "preparing: ",$dbhA->errstr; + $sthY->execute or die "executing: $stmtY", $dbhA->errstr; + $sthYrows=$sthY->rows; + if ($sthYrows > 0) + { + @aryY = $sthY->fetchrow_array; + $TFhourSTATE = $aryY[0]; + $TFhourCOUNTRY = $aryY[1]; + } + $sthA->finish(); + + $TEMP_TFhour_OR_entry=''; + $TFH_OR_method='state_areacode'; + $TFH_OR_postcode_field_match=0; + $TFH_OR_state_field_match=0; + $TFH_OR_postcode_state=''; + $stmtA = "SELECT container_entry FROM vicidial_settings_containers where container_id='$VD_call_limit_24hour_override';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($DBX) {print "$sthArows|$stmtA\n";} + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $TEMP_TFhour_OR_entry = $aryA[0]; + } + $sthA->finish(); + + if (length($TEMP_TFhour_OR_entry) > 2) + { + @container_lines = split(/\n/,$TEMP_TFhour_OR_entry); + $c=0; + foreach(@container_lines) + { + $container_lines[$c] =~ s/;.*|\r|\t//gi; + $container_lines[$c] =~ s/ => |=> | =>/=>/gi; + if (length($container_lines[$c]) > 3) + { + # define core settings + if ($container_lines[$c] =~ /^method/i) + { + #$container_lines[$c] =~ s/method=>//gi; + $TFH_OR_method = $container_lines[$c]; + if ( ($TFH_OR_method =~ /state$/) && ($TFhourSTATE ne $temp_24hour_state) ) + { + $TFH_OR_state_field_match=1; + } + if ( ($TFH_OR_method =~ /postcode/) && (length($temp_24hour_postal_code) > 0) ) + { + if ($TFhourCOUNTRY == 'USA') + { + $temp_24hour_postal_code =~ s/\D//gi; + $temp_24hour_postal_code = substr($temp_24hour_postal_code,0,5); + } + if ($TFhourCOUNTRY == 'CAN') + { + $temp_24hour_postal_code =~ s/[^a-zA-Z0-9]//gi; + $temp_24hour_postal_code = substr($temp_24hour_postal_code,0,6); + } + $stmtA = "SELECT state FROM vicidial_postal_codes where postal_code='$temp_24hour_postal_code';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($DBX) {print "$sthArows|$stmtA\n";} + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $TFH_OR_postcode_state = $aryA[0]; + $TFH_OR_postcode_field_match=1; + } + $sthA->finish(); + } + } + else + { + if ($container_lines[$c] =~ /^state/i) + { + $container_lines[$c] =~ s/state=>//gi; # USA,GA,4 + @TEMP_state_ARY = split(/,/,$container_lines[$c]); + + if ($TFhourCOUNTRY eq $TEMP_state_ARY[0]) + { + $TEMP_state_ARY[2] =~ s/\D//gi; + if ( ($TFhourSTATE eq $TEMP_state_ARY[1]) && (length($TEMP_state_ARY[2]) > 0) ) + { + if ($DB) {print " 24-Hour Call Count State Override Triggered: $TEMPcall_limit_24hour|$container_lines[$c]\n";} + $TEMPcall_limit_24hour = $TEMP_state_ARY[2]; + } + if ( ($TFH_OR_postcode_state eq $TEMP_state_ARY[1]) && (length($TEMP_state_ARY[2]) > 0) && ($TFH_OR_postcode_field_match > 0) ) + { + if ($DBX) {print " 24-Hour Call Count State Override Match(postcode $TFH_OR_postcode_state): $TEMPcall_limit_24hour|$container_lines[$c]\n";} + if ($TEMP_state_ARY[2] < $TEMPcall_limit_24hour) + { + if ($DBX) {print " POSTCODE field override of override triggered: ($TEMP_state_ARY[2] < $TEMPcall_limit_24hour)\n";} + $TEMPcall_limit_24hour = $TEMP_state_ARY[2]; + } + } + if ( ($temp_24hour_state eq $TEMP_state_ARY[1]) && (length($TEMP_state_ARY[2]) > 0) && ($TFH_OR_state_field_match > 0) ) + { + if ($DBX) {print " 24-Hour Call Count State Override Match(state $temp_24hour_state): $TEMPcall_limit_24hour|$container_lines[$c]\n";} + if ($TEMP_state_ARY[2] < $TEMPcall_limit_24hour) + { + if ($DBX) {print " STATE field override of override triggered: ($TEMP_state_ARY[2] < $TEMPcall_limit_24hour)\n";} + $TEMPcall_limit_24hour = $TEMP_state_ARY[2]; + } + } + } + } + } + } + if ($DBX) {print " 24-Hour Call Count State Override DEBUG: |$container_lines[$c]|\n";} + $c++; + } + } + } + + if ( ($TFhourCOUNT > 0) && ($TFhourCOUNT >= $TEMPcall_limit_24hour) ) + { + $TFHCCLlead=1; + $TFHCCL++; + $passed_24hour_call_count=0; + if ($DBX) {print "Flagging 24-Hour Call Limit lead: $VD_lead_id ($TFhourCOUNT >= $TEMPcall_limit_24hour) $passed_24hour_call_count\n";} + } + else + { + $passed_24hour_call_count=1; + if ($DBX) {print " 24-Hour Call Limit check passed: $VD_lead_id ($TFhourCOUNT < $TEMPcall_limit_24hour) $passed_24hour_call_count\n";} + } + } + sub agi_output { if ($AGILOG >=2) @@ -2688,6 +3003,18 @@ sub agi_output $agi_string=''; } +sub aad_output + { + if ($AGILOG > 0) + { + ### open the log file for writing ### + open(Aout, ">>$AADLOGfile") || die "Can't open $AADLOGfile: $!\n"; + print Aout "$now_date|$script|$aad_string\n"; + close(Aout); + } + $aad_string=''; + } + # subroutine to parse the asterisk version # and return a hash with the various part sub parse_asterisk_version @@ -3170,4 +3497,4 @@ sub khomp_json_api $api_query_time = tv_interval ( [$query_start_sec, $query_start_usec], [$query_end_sec, $query_end_usec]); return ($result, $api_query_time); - } \ No newline at end of file + } diff --git a/agc_2-X/trunk/extras/KHOMP/agi-VDAD_ALL_outbound.agi b/agc_2-X/trunk/extras/KHOMP/agi-VDAD_ALL_outbound.agi index b82e3d70..ee4dea28 100644 --- a/agc_2-X/trunk/extras/KHOMP/agi-VDAD_ALL_outbound.agi +++ b/agc_2-X/trunk/extras/KHOMP/agi-VDAD_ALL_outbound.agi @@ -1,6 +1,6 @@ #!/usr/bin/perl # -# agi-VDAD_ALL_outbound.agi version 2.14 (KHOMP VERSION as of svn/trunk rev 3198) +# agi-VDAD_ALL_outbound.agi version 2.14 (KHOMP VERSION as of svn/trunk rev 3524) # # runs when an outbound call is answered. This script will # send the calls out to the agents that are logged in. @@ -18,7 +18,7 @@ # ; - SURVEYCAMPCEP - Survery question, campaign settings, cepstral name # ; - REMINDER - Reminder campaign # ; - REMINDX - Reminder with transfer to agent -# ; 2. the method of searching for an available agent: +# ; 2. the method of searching for an available agent: (agent_search_method) # ; - LB - Load Balance total system # ; - LO - Load Balance Overflow only (priority to home server) # ; - SO - Home server only @@ -123,7 +123,9 @@ # 190925-1348 - Added campaign SIP Actions processing # 191104-2026 - Added code for Khomp version compatibility # 191120-2235 - Added DYN multi-prompt survey prompts functionality -# 200210-1645 - Added KHOMP code +# 200825-2342 - Added option for auto-only sip actions +# 200915-2218 - Fixes for surveys with hash-star +# 210907-1254 - Added KHOMP code (install JSON::PP Perl module and remove '#UC#' in the code to enable) # $script = 'agi-VDAD_ALL_outbound.agi'; @@ -137,9 +139,8 @@ use Time::HiRes ('tv_interval','gettimeofday','usleep','sleep'); # necessary to ($START_s_hires, $START_usec) = gettimeofday(); # Needed for Khomp Integration -#use Cpanel::JSON::XS qw(encode_json decode_json); -use JSON::PP qw(encode_json decode_json); -#use Data::Dumper; + use JSON::PP qw(encode_json decode_json); + ### find curl binary for KHOMP $curlbin = ''; @@ -267,7 +268,7 @@ $dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VA ############################################# ##### Gather system_settings ##### -$stmtA = "SELECT sip_event_logging,call_quota_lead_ranking FROM system_settings;"; +$stmtA = "SELECT sip_event_logging,call_quota_lead_ranking,agent_search_method FROM system_settings;"; $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; $sthArows=$sthA->rows; @@ -276,6 +277,7 @@ if ($sthArows > 0) @aryA = $sthA->fetchrow_array; $SSsip_event_logging = $aryA[0]; $SScall_quota_lead_ranking = $aryA[1]; + $SSagent_search_method = $aryA[2]; } $sthA->finish(); ########################################### @@ -291,15 +293,15 @@ $sthArows=$sthA->rows; while ($sthArows > $rec_count) { @aryA = $sthA->fetchrow_array; - $DBvoicemail_dump_exten = $aryA[0]; - $DBext_context = $aryA[1]; - $DBanswer_transfer_agent = $aryA[2]; - $DBSERVER_GMT = $aryA[3]; - $asterisk_version = $aryA[4]; - $DBmax_vicidial_trunks = $aryA[5]; - $DBagi_output = $aryA[6]; + $DBvoicemail_dump_exten = $aryA[0]; + $DBext_context = $aryA[1]; + $DBanswer_transfer_agent = $aryA[2]; + $DBSERVER_GMT = $aryA[3]; + $asterisk_version = $aryA[4]; + $DBmax_vicidial_trunks = $aryA[5]; + $DBagi_output = $aryA[6]; $voicemail_dump_exten_no_inst = $aryA[7]; - $external_server_ip = $aryA[8]; + $external_server_ip = $aryA[8]; if ($DBvoicemail_dump_exten) {$voicemail_dump_exten = $DBvoicemail_dump_exten;} if ($DBext_context) {$ext_context = $DBext_context;} if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} @@ -808,7 +810,7 @@ if ($VDACaffected_rows > 0) ##### END - Max call stats ### Grab campaign values from the database - $stmtA = "SELECT drop_call_seconds,drop_action,safe_harbor_exten,concurrent_transfers,next_agent_call,voicemail_ext,drop_inbound_group,use_internal_dnc,use_campaign_dnc,cpd_amd_action,am_message_exten,three_way_call_cid,campaign_cid,survey_first_audio_file,survey_opt_in_audio_file,survey_ni_audio_file,survey_third_audio_file,survey_fourth_audio_file,extension_appended_cidname,queue_priority,closer_campaigns,queuemetrics_phone_environment,campaign_recording,campaign_rec_filename,safe_harbor_audio,safe_harbor_menu_id,survey_recording,safe_harbor_audio_field,use_other_campaign_dnc,cpd_unknown_action,routing_initiated_recordings,campaign_rec_exten,call_quota_lead_ranking,sip_event_logging,amd_type FROM vicidial_campaigns where campaign_id = '$VDADcampaign';"; + $stmtA = "SELECT drop_call_seconds,drop_action,safe_harbor_exten,concurrent_transfers,next_agent_call,voicemail_ext,drop_inbound_group,use_internal_dnc,use_campaign_dnc,cpd_amd_action,am_message_exten,three_way_call_cid,campaign_cid,survey_first_audio_file,survey_opt_in_audio_file,survey_ni_audio_file,survey_third_audio_file,survey_fourth_audio_file,extension_appended_cidname,queue_priority,closer_campaigns,queuemetrics_phone_environment,campaign_recording,campaign_rec_filename,safe_harbor_audio,safe_harbor_menu_id,survey_recording,safe_harbor_audio_field,use_other_campaign_dnc,cpd_unknown_action,routing_initiated_recordings,campaign_rec_exten,call_quota_lead_ranking,sip_event_logging,amd_type,agent_search_method FROM vicidial_campaigns where campaign_id = '$VDADcampaign';"; $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; $sthArows=$sthA->rows; @@ -854,6 +856,7 @@ if ($VDACaffected_rows > 0) $VD_call_quota_lead_ranking = $aryA[32]; $CAMPsip_event_logging = $aryA[33]; $amd_type = $aryA[34]; + $agent_search_method_OVERRIDE = $aryA[35]; if (length($closer_campaigns) > 2) { $closer_campaigns =~ s/^ | -$//gi; @@ -875,119 +878,6 @@ if ($VDACaffected_rows > 0) $khomp_header = ''; $khomp_id_format = ''; - - ##### BEGIN SIP Action check ##### - if ( ($SIP_event_recent_inserted > 0) && ($SIP_event_action_checked < 1) && (length($CAMPsip_event_logging) > 0) and ($CAMPsip_event_logging !~ /^DISABLED$/i) ) - { - # Gather settings container for SIP Event Actions - $CQcontainer_entry=''; - $stmtA = "SELECT container_entry FROM vicidial_settings_containers where container_id='$CAMPsip_event_logging';"; - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArows=$sthA->rows; - if ( ($AGILOG > 0) && ($sthArows > 0) ) {$agi_string = "-- SIP ACTION check: |$sthArows|$invite_to_final|$CAMPsip_event_logging|"; &agi_output;} - $dbhP=$dbhA; $mysql_count='01141'; $MEL_aff_rows=$sthArows; &mysql_error_logging; - if ($sthArows > 0) - { - @aryA = $sthA->fetchrow_array; - $SAcontainer_entry = $aryA[0]; - $SAcontainer_entry =~ s/\r|\t|\'|\"//gi; - @sip_action_settings = split(/\n/,$SAcontainer_entry); - $sea=0; - foreach (@sip_action_settings) - { - if ($sip_action_settings[$sea] =~ /^invite_to_final => /) - { - # invite_to_final => 0.0,1.0,hangup-dispo-message,FAS,Auto Hangup and Dispo of False Answer Call - $sip_action_settings[$sea] =~ s/invite_to_final => //gi; - @invite_to_finalARY = split(/,/,$sip_action_settings[$sea]); - $T_dial_time = ($invite_to_final + 0); - $itf_begin = ($invite_to_finalARY[0] + 0); - $itf_end = ($invite_to_finalARY[1] + 0); - $itf_actions = $invite_to_finalARY[2]; - $itf_dispo = $invite_to_finalARY[3]; - $itf_message = $invite_to_finalARY[4]; - if ( ($T_dial_time >= $itf_begin) && ($T_dial_time <= $itf_end) && (length($itf_actions) > 4) ) - { - if ($itf_actions =~ /logtable/i) - { - ##### insert record into vicidial_sip_action_log - $stmtA="INSERT INTO vicidial_sip_action_log set call_date='$invite_date',caller_code='$callerid',lead_id='$CIDlead_id',phone_number='$VDADphone',user='VDAD',result='$itf_dispo';"; - $SAaffected_rows = $dbhA->do($stmtA); - $dbhP=$dbhA; $mysql_count='01142'; $MEL_aff_rows=$SAaffected_rows; &mysql_error_logging; - if ($AGILOG) {$agi_string = "-- SIP ACTION logtable inserted : |$SAaffected_rows|($T_dial_time <> $itf_begin -> $itf_end)|$itf_actions|$stmtA|"; &agi_output;} - } - if ($itf_actions =~ /hangup/i) - { - if (length($itf_dispo) < 1) - {$itf_dispo='SIPACT';} - $xCLlist_id=0; - $called_count=0; - $stmtA = "SELECT list_id,security_phrase,called_count from vicidial_list where lead_id='$CIDlead_id' limit 1;"; - $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; - $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; - $sthArowsLI=$sthA->rows; - $dbhP=$dbhA; $mysql_count='01143'; $MEL_aff_rows=$sthArowsLI; &mysql_error_logging; - if ($sthArowsLI > 0) - { - @aryA = $sthA->fetchrow_array; - $xCLlist_id = $aryA[0]; - $security_phrase = $aryA[1]; - $called_count = $aryA[2]; - } - $sthA->finish(); - - ($END_s_hires, $END_usec) = gettimeofday(); - $START_time = $START_s_hires . '.' . sprintf("%06s", $START_usec); - $END_time = $END_s_hires . '.' . sprintf("%06s", $END_usec); - $RUN_time = ($END_time - $START_time); - $RUN_time = sprintf("%.3f", $RUN_time); - if ($AGILOG) {$agi_string = "Preprocess time: |$RUN_time ($END_time - $START_time)|"; &agi_output;} - - $stmtA = "INSERT INTO vicidial_log (uniqueid,lead_id,campaign_id,call_date,start_epoch,end_epoch,length_in_sec,status,phone_code,phone_number,user,processed,alt_dial,list_id,comments,called_count,term_reason) values('$uniqueid','$CIDlead_id','$VDADcampaign','$SQLdate','$now_date_epoch','$now_date_epoch','0','$itf_dispo','$VDADphone_code','$VDADphone','VDAD','N','$VDADalt_dial','$xCLlist_id','$RUN_time','$called_count','SYSTEM')"; - if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} - $affected_rows = $dbhA->do($stmtA); - $dbhP=$dbhA; $mysql_count='01144'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; - - if ($AGILOG) {$agi_string = "-- SIP ACTION VDAD : |$VDADlead_id|$CIDlead_id|($T_dial_time <> $itf_begin -> $itf_end)|$itf_actions|insert to vicidial_log: $uniqueid"; &agi_output;} - - $stmtA = "INSERT INTO vicidial_log_extended set uniqueid='$uniqueid',server_ip='$VARserver_ip',call_date='$SQLdate',lead_id = '$CIDlead_id',caller_code='$callerid',custom_call_id='';"; - $affected_rows = $dbhA->do($stmtA); - $dbhP=$dbhA; $mysql_count='01145'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; - if ($AGILOG) {$agi_string = "-- SIP ACTION VDAD VLE insert: |$affected_rows|\n|$stmtA|"; &agi_output;} - - $stmtA = "UPDATE vicidial_list set status='$itf_dispo' where lead_id='$CIDlead_id';"; - if ($AGILOG) { $agi_string = "|$stmtA|"; &agi_output; } - $affected_rows = $dbhA->do($stmtA); - $dbhP=$dbhA; $mysql_count='01146'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; - if ($AGILOG) - {$agi_string = "-- SIP ACTION VDAD vicidial_list update: $itf_dispo|$affected_rows|$CIDlead_id"; &agi_output;} - - $stmtA = "DELETE FROM vicidial_auto_calls where callerid='$callerid' order by call_time desc limit 1;"; - $affected_rows = $dbhA->do($stmtA); - $dbhP=$dbhA; $mysql_count='01147'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; - if ($AGILOG) {$agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|"; &agi_output;} - - if ( ($SScall_quota_lead_ranking > 0) && ($VD_call_quota_lead_ranking !~ /^DISABLED$/i) ) - { - $temp_status = $itf_dispo; - &call_quota_logging; - } - $AGI->hangup(); - - exit; - } - } - } - $sea++; - } - } - $sthA->finish(); - $SIP_event_action_checked++; - } - ##### END SIP Action check ##### - - $stmtA = "SELECT container_entry FROM vicidial_settings_containers WHERE container_id = 'KHOMPSETTINGS';"; $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; @@ -1116,6 +1006,118 @@ if ($VDACaffected_rows > 0) } } + ##### BEGIN SIP Action check ##### + if ( ($SIP_event_recent_inserted > 0) && ($SIP_event_action_checked < 1) && (length($CAMPsip_event_logging) > 0) and ($CAMPsip_event_logging !~ /^DISABLED$/i) ) + { + # Gather settings container for SIP Event Actions + $CQcontainer_entry=''; + $stmtA = "SELECT container_entry FROM vicidial_settings_containers where container_id='$CAMPsip_event_logging';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ( ($AGILOG > 0) && ($sthArows > 0) ) {$agi_string = "-- SIP ACTION check: |$sthArows|$invite_to_final|$CAMPsip_event_logging|"; &agi_output;} + $dbhP=$dbhA; $mysql_count='01141'; $MEL_aff_rows=$sthArows; &mysql_error_logging; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $SAcontainer_entry = $aryA[0]; + $SAcontainer_entry =~ s/\r|\t|\'|\"//gi; + @sip_action_settings = split(/\n/,$SAcontainer_entry); + $sea=0; + foreach (@sip_action_settings) + { + if ( ($sip_action_settings[$sea] =~ /^invite_to_final => /) && ($sip_action_settings[$sea] !~ /manual-only/i) ) + { + # invite_to_final => 0.0,1.0,hangup-dispo-message,FAS,Auto Hangup and Dispo of False Answer Call,auto-only + $sip_action_settings[$sea] =~ s/invite_to_final => //gi; + @invite_to_finalARY = split(/,/,$sip_action_settings[$sea]); + $T_dial_time = ($invite_to_final + 0); + $itf_begin = ($invite_to_finalARY[0] + 0); + $itf_end = ($invite_to_finalARY[1] + 0); + $itf_actions = $invite_to_finalARY[2]; + $itf_dispo = $invite_to_finalARY[3]; + $itf_message = $invite_to_finalARY[4]; + if ( ($T_dial_time >= $itf_begin) && ($T_dial_time <= $itf_end) && (length($itf_actions) > 4) ) + { + if ($itf_actions =~ /logtable/i) + { + ##### insert record into vicidial_sip_action_log + $stmtA="INSERT INTO vicidial_sip_action_log set call_date='$invite_date',caller_code='$callerid',lead_id='$CIDlead_id',phone_number='$VDADphone',user='VDAD',result='$itf_dispo';"; + $SAaffected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01142'; $MEL_aff_rows=$SAaffected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- SIP ACTION logtable inserted : |$SAaffected_rows|($T_dial_time <> $itf_begin -> $itf_end)|$itf_actions|$stmtA|"; &agi_output;} + } + if ($itf_actions =~ /hangup/i) + { + if (length($itf_dispo) < 1) + {$itf_dispo='SIPACT';} + $xCLlist_id=0; + $called_count=0; + $stmtA = "SELECT list_id,security_phrase,called_count from vicidial_list where lead_id='$CIDlead_id' limit 1;"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArowsLI=$sthA->rows; + $dbhP=$dbhA; $mysql_count='01143'; $MEL_aff_rows=$sthArowsLI; &mysql_error_logging; + if ($sthArowsLI > 0) + { + @aryA = $sthA->fetchrow_array; + $xCLlist_id = $aryA[0]; + $security_phrase = $aryA[1]; + $called_count = $aryA[2]; + } + $sthA->finish(); + + ($END_s_hires, $END_usec) = gettimeofday(); + $START_time = $START_s_hires . '.' . sprintf("%06s", $START_usec); + $END_time = $END_s_hires . '.' . sprintf("%06s", $END_usec); + $RUN_time = ($END_time - $START_time); + $RUN_time = sprintf("%.3f", $RUN_time); + if ($AGILOG) {$agi_string = "Preprocess time: |$RUN_time ($END_time - $START_time)|"; &agi_output;} + + $stmtA = "INSERT INTO vicidial_log (uniqueid,lead_id,campaign_id,call_date,start_epoch,end_epoch,length_in_sec,status,phone_code,phone_number,user,processed,alt_dial,list_id,comments,called_count,term_reason) values('$uniqueid','$CIDlead_id','$VDADcampaign','$SQLdate','$now_date_epoch','$now_date_epoch','0','$itf_dispo','$VDADphone_code','$VDADphone','VDAD','N','$VDADalt_dial','$xCLlist_id','$RUN_time','$called_count','SYSTEM')"; + if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;} + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01144'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + + if ($AGILOG) {$agi_string = "-- SIP ACTION VDAD : |$VDADlead_id|$CIDlead_id|($T_dial_time <> $itf_begin -> $itf_end)|$itf_actions|insert to vicidial_log: $uniqueid"; &agi_output;} + + $stmtA = "INSERT INTO vicidial_log_extended set uniqueid='$uniqueid',server_ip='$VARserver_ip',call_date='$SQLdate',lead_id = '$CIDlead_id',caller_code='$callerid',custom_call_id='';"; + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01145'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- SIP ACTION VDAD VLE insert: |$affected_rows|\n|$stmtA|"; &agi_output;} + + $stmtA = "UPDATE vicidial_list set status='$itf_dispo' where lead_id='$CIDlead_id';"; + if ($AGILOG) { $agi_string = "|$stmtA|"; &agi_output; } + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01146'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) + {$agi_string = "-- SIP ACTION VDAD vicidial_list update: $itf_dispo|$affected_rows|$CIDlead_id"; &agi_output;} + + $stmtA = "DELETE FROM vicidial_auto_calls where callerid='$callerid' order by call_time desc limit 1;"; + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01147'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|"; &agi_output;} + + if ( ($SScall_quota_lead_ranking > 0) && ($VD_call_quota_lead_ranking !~ /^DISABLED$/i) ) + { + $temp_status = $itf_dispo; + &call_quota_logging; + } + $AGI->hangup(); + + exit; + } + } + } + $sea++; + } + } + $sthA->finish(); + $SIP_event_action_checked++; + } + ##### END SIP Action check ##### + + ### start recording if survey recording is enabled if ( ($call_handle_method =~ /SURVEY/) && ($survey_recording =~ /Y/) ) @@ -1812,7 +1814,7 @@ if ($call_handle_method =~ /SURVEY/) } # they opted out - if ($opt_code =~ /$survey_ni_digit/) + if ($opt_code eq $survey_ni_digit) { if ( $survey_ni_audio_file ne "") { @@ -1838,15 +1840,15 @@ if ($call_handle_method =~ /SURVEY/) $dbhP=$dbhA; $mysql_count='01017'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; if ($AGILOG) { - $agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|$callerid"; + $agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|"; &agi_output; } $Euniqueid=$uniqueid; - $Euniqueid =~ s/\.\d+//gi; + $Euniqueid =~ s/\.\d+//gi; $now_date_epoch = time(); $drop_seconds = $now_date_epoch - $start_time_epoch; - $stmtA = "UPDATE vicidial_log FORCE INDEX(lead_id) set status='$survey_ni_status', end_epoch='$now_date_epoch', length_in_sec='$drop_seconds', term_reason='CALLER' where lead_id = '$CIDlead_id' and uniqueid LIKE \"$Euniqueid%\";"; + $stmtA = "UPDATE vicidial_log FORCE INDEX(lead_id) set status='$survey_ni_status', end_epoch='$now_date_epoch', length_in_sec='$drop_seconds', term_reason='CALLER' where lead_id = '$CIDlead_id' and uniqueid LIKE \"$Euniqueid%\";"; if ($AGILOG) { $agi_string = "|$stmtA|"; &agi_output; } $affected_rows = $dbhA->do($stmtA); $dbhP=$dbhA; $mysql_count='01018'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; @@ -1926,7 +1928,7 @@ if ($call_handle_method =~ /SURVEY/) } ### third digit option - if ($opt_code =~ /$survey_third_digit/) + if ($opt_code eq $survey_third_digit) { if ( $survey_third_audio_file ne "") { @@ -1952,15 +1954,15 @@ if ($call_handle_method =~ /SURVEY/) $dbhP=$dbhA; $mysql_count='01017'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; if ($AGILOG) { - $agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|$callerid"; + $agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|"; &agi_output; } $Euniqueid=$uniqueid; - $Euniqueid =~ s/\.\d+//gi; + $Euniqueid =~ s/\.\d+//gi; $now_date_epoch = time(); $drop_seconds = $now_date_epoch - $start_time_epoch; - $stmtA = "UPDATE vicidial_log FORCE INDEX(lead_id) set status='$survey_third_status', end_epoch='$now_date_epoch', length_in_sec='$drop_seconds', term_reason='CALLER' where lead_id = '$CIDlead_id' and uniqueid LIKE \"$Euniqueid%\";"; + $stmtA = "UPDATE vicidial_log FORCE INDEX(lead_id) set status='$survey_third_status', end_epoch='$now_date_epoch', length_in_sec='$drop_seconds', term_reason='CALLER' where lead_id = '$CIDlead_id' and uniqueid LIKE \"$Euniqueid%\";"; if ($AGILOG) { $agi_string = "|$stmtA|"; &agi_output; } $affected_rows = $dbhA->do($stmtA); $dbhP=$dbhA; $mysql_count='01018'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; @@ -2055,7 +2057,7 @@ if ($call_handle_method =~ /SURVEY/) ### fourth digit option - if ($opt_code =~ /$survey_fourth_digit/) + if ($opt_code eq $survey_fourth_digit) { if ( $survey_fourth_audio_file ne "") { @@ -2081,15 +2083,15 @@ if ($call_handle_method =~ /SURVEY/) $dbhP=$dbhA; $mysql_count='01017'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; if ($AGILOG) { - $agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|$callerid"; + $agi_string = "-- VDAD vac record deleted: |$affected_rows|$VDADcampaign|"; &agi_output; } $Euniqueid=$uniqueid; - $Euniqueid =~ s/\.\d+//gi; + $Euniqueid =~ s/\.\d+//gi; $now_date_epoch = time(); $drop_seconds = $now_date_epoch - $start_time_epoch; - $stmtA = "UPDATE vicidial_log FORCE INDEX(lead_id) set status='$survey_fourth_status', end_epoch='$now_date_epoch', length_in_sec='$drop_seconds', term_reason='CALLER' where lead_id = '$CIDlead_id' and uniqueid LIKE \"$Euniqueid%\";"; + $stmtA = "UPDATE vicidial_log FORCE INDEX(lead_id) set status='$survey_fourth_status', end_epoch='$now_date_epoch', length_in_sec='$drop_seconds', term_reason='CALLER' where lead_id = '$CIDlead_id' and uniqueid LIKE \"$Euniqueid%\";"; if ($AGILOG) { $agi_string = "|$stmtA|"; &agi_output; } $affected_rows = $dbhA->do($stmtA); $dbhP=$dbhA; $mysql_count='01018'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; @@ -2183,7 +2185,7 @@ if ($call_handle_method =~ /SURVEY/) } # they opted in - if ( ($opt_code =~ /\d/) || ($survey_no_response_action =~ /OPTOUT/) ) + if ( ($opt_code =~ /\d|\*|\#/) || ($survey_no_response_action =~ /OPTOUT/) ) { $now_date_epoch = time(); $FDtarget = ($now_date_epoch + 60); @@ -2721,10 +2723,15 @@ while ($drop_timer <= $DROP_TIME) ##### Attempt to send call to an agent on this server only ##### - if ($agent_search_method =~ /^SO|^LO/) + if ( ($agent_search_method =~ /^SO|^LO/) || ( ( ($SSagent_search_method == 1) || ($SSagent_search_method == 3) ) && ($agent_search_method_OVERRIDE =~ /^SO|^LO/) ) ) { if ($agent_search_method =~ /^SO/) {$agent_search_method = 'LO';} + if ( ( ($SSagent_search_method == 1) || ($SSagent_search_method == 3) ) && ($agent_search_method_OVERRIDE =~ /^SO/) ) + { + if ($AGILOG) {$agi_string = "|Agent Search Method Campaign Override: $agent_search_method_OVERRIDE ($SSagent_search_method)$agent_search_method|"; &agi_output;} + $agent_search_method = 'SO'; + } if ($DBconcurrent_transfers =~ /AUTO/) { @@ -3988,7 +3995,7 @@ while ($drop_timer <= $DROP_TIME) ### END routing-initiated agent call recording for ALLCALLS/ALLFORCE ### } - if ($extension_appended_cidname =~ /Y/) + if ($extension_appended_cidname =~ /Y|USER/) { $eac_extension=''; $stmtA = "SELECT extension,campaign_id FROM vicidial_live_agents where user='$VDADuser' order by last_call_time limit 1;"; @@ -4340,6 +4347,14 @@ if ($drop_timer > $DROP_TIME) $dbhP=$dbhA; $mysql_count='01051'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; if ($AGILOG) {$agi_string = "-- VDAD vicidial_list update: |$affected_rows|$CIDlead_id"; &agi_output;} + if ( ($DBdrop_call_seconds < 0) && ($drop_action =~ /IN_GROUP/) ) + { + $stmtA = "INSERT IGNORE INTO vicidial_shared_drops (callerid,server_ip,campaign_id,status,lead_id,uniqueid,channel,phone_code,phone_number,call_time,call_type,stage,last_update_time,alt_dial,drop_time) SELECT callerid,server_ip,campaign_id,status,lead_id,uniqueid,channel,phone_code,phone_number,call_time,call_type,stage,last_update_time,alt_dial,now() from vicidial_auto_calls where callerid='$callerid' order by call_time desc limit 1;"; + $affected_rows = $dbhA->do($stmtA); + $dbhP=$dbhA; $mysql_count='01XXX'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; + if ($AGILOG) {$agi_string = "-- SHARED drop record inserted: |$affected_rows|$VDADcampaign|"; &agi_output;} + } + $stmtA = "DELETE FROM vicidial_auto_calls where callerid='$callerid' order by call_time desc limit 1;"; $affected_rows = $dbhA->do($stmtA); $dbhP=$dbhA; $mysql_count='01052'; $MEL_aff_rows=$affected_rows; &mysql_error_logging; @@ -4491,7 +4506,10 @@ sub enter_pin_number $totalDTMF=''; if ($interrupt_digit > 1) { - $interrupt_digit = $interrupt_digit - 48; + if ($interrupt_digit == 35) {$interrupt_digit='#';} + if ($interrupt_digit == 42) {$interrupt_digit='*';} + if ($interrupt_digit >= 48) + {$interrupt_digit = $interrupt_digit - 48;} $totalDTMF=$interrupt_digit; } @@ -4519,7 +4537,7 @@ sub enter_pin_number } } - $totalDTMF =~ s/\D//gi; + #$totalDTMF =~ s/\D//gi; $pin = $totalDTMF; if ($totalDTMF) {if ($AGILOG) {$agi_string = "digit |$digit| TotalDTMF |$totalDTMF|"; &agi_output;}} @@ -5285,7 +5303,7 @@ sub process_khomp_analytics }; # encode it as JSON - $khomp_json = encode_json( $khomp_request ); + $khomp_json = encode_json( $khomp_request ); # call the API ($result, $api_query_time) = khomp_json_api( $khomp_json, $khomp_api_url );