Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,197 changes: 538 additions & 659 deletions LICENSE

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions UPGRADE
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,29 @@ OTHER CHANGES:
setting. This can send a URL request when new leads are added to the
system through the "add_lead" Non-Agent API function.

249. Added agc/dispo_move_listSC.php script, allowing for multiple more complex
Dispo Move List functions after an agent dispositions a call.

250. Added "hopper_bulk_insert" Non-Agent API function.

251. Added Stereo Call Recording, allowing for additional call recordings with
the customer on one side(the Right channel) and the agent on the other
side(the Left channel), as well as optional parallel stereo call
recordings. For more information, read the doc:
STEREO_CALL_RECORDINGS.txt

252. Added "Talk Seconds URLs" Campaign and In-Group features. Allows for URLs
to be sent out from the Agent Screen while the agent is talking to the
customer, based on the number of seconds they have been talking.

253. Added Recording DTMF Muting, allowing for the muting of call recordings
for X seconds if any DTMF signal is detected on the call. Configurable
in Campaigns, In-Groups and system-wide.

254. Added Database crashed table auto-check, with display on Admin Web screens
for level 9 users if crashed tables are found. Enabled by default,
configurable in the System Settings.




Expand Down
59 changes: 49 additions & 10 deletions agi/VD_amd.agi
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# exten => _91NXXNXXXXXX,n,Set(__AMDMINLEN=7)
# NOTE: the above variable setting will ensure that this script has run for a minimum of 7 seconds before ending and hanging up
#
# Copyright (C) 2024 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
# Copyright (C) 2025 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
#
# changes:
# 60206-1434 - first build
Expand Down Expand Up @@ -69,16 +69,19 @@
# 220411-0833 - Added FHG(file-http-get) message playback option to download file from website
# 230412-1023 - Added Code to dispo NOAUDIODATA as ADAIR (Dead Air Auto) with Settings Container option, Issue #1459
# 230726-0932 - Added manual_vm_status_updates campaign option
# 250906-2228 - Added AMD minimum length handling to increase short call durations
# 240906-2228 - Added AMD minimum length handling to increase short call durations
# 250924-2152 - Added code for deprecation of "Monitor" application after Asterisk 20
# 251006-0903 - If recording_dtmf_muting enabled, force use of MixMonitor for recording
#

$script = 'VD_amd.agi';
$build = '230726-0932';
$build = '251006-0903';

$A = 1; # set to 1 for AMD output messages mode
$AMD_LOG = 3; # set to 1 for logfile and 2 forDB log, 3 for both
$wav='.wav';
$US='_';
$recording_dtmf_muting=0;

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year = ($year + 1900);
Expand Down Expand Up @@ -147,7 +150,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,recording_dtmf_muting,recording_dtmf_detection FROM system_settings;";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
Expand All @@ -156,6 +159,8 @@ if ($sthArows > 0)
@aryA = $sthA->fetchrow_array;
$SSsip_event_logging = $aryA[0];
$SScall_quota_lead_ranking = $aryA[1];
$SSrecording_dtmf_muting = $aryA[2];
$SSrecording_dtmf_detection = $aryA[3];
}
$sthA->finish();
###########################################
Expand Down Expand Up @@ -533,7 +538,7 @@ else

$selected_campaign='';
### Grab vmail forward message values from the database
$stmtA = "SELECT am_message_exten,amd_send_to_vmx,waitforsilence_options,survey_recording,campaign_rec_filename,cpd_amd_action,amd_inbound_group,amd_callmenu,cpd_unknown_action,campaign_id,am_message_wildcards,call_quota_lead_ranking,vmm_daily_limit,manual_vm_status_updates FROM vicidial_campaigns where campaign_id = '$VD_campaign_id' limit 1;";
$stmtA = "SELECT am_message_exten,amd_send_to_vmx,waitforsilence_options,survey_recording,campaign_rec_filename,cpd_amd_action,amd_inbound_group,amd_callmenu,cpd_unknown_action,campaign_id,am_message_wildcards,call_quota_lead_ranking,vmm_daily_limit,manual_vm_status_updates,recording_dtmf_muting FROM vicidial_campaigns where campaign_id = '$VD_campaign_id' limit 1;";
if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;}
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
Expand All @@ -555,14 +560,15 @@ else
$VD_call_quota_lead_ranking = $aryA[11];
$vmm_daily_limit = $aryA[12];
$manual_vm_status_updates = $aryA[13];
$recording_dtmf_muting = $aryA[14];
$sthA->finish();
}
else
{
$sthA->finish();
### Grab vmail forward message values from the database
$SQL_group_id=$VD_campaign_id; $SQL_group_id =~ s/_/\\_/gi;
$stmtA = "SELECT am_message_exten,amd_send_to_vmx,waitforsilence_options,survey_recording,campaign_rec_filename,cpd_amd_action,amd_inbound_group,amd_callmenu,cpd_unknown_action,campaign_id,am_message_wildcards,vmm_daily_limit,manual_vm_status_updates FROM vicidial_campaigns where closer_campaigns LIKE \"% $SQL_group_id %\" order by active,campaign_id limit 1;";
$stmtA = "SELECT am_message_exten,amd_send_to_vmx,waitforsilence_options,survey_recording,campaign_rec_filename,cpd_amd_action,amd_inbound_group,amd_callmenu,cpd_unknown_action,campaign_id,am_message_wildcards,vmm_daily_limit,manual_vm_status_updates,recording_dtmf_muting FROM vicidial_campaigns where closer_campaigns LIKE \"% $SQL_group_id %\" order by active,campaign_id limit 1;";
if ($AGILOG) {$agi_string = "|$stmtA|"; &agi_output;}
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
Expand All @@ -584,6 +590,7 @@ else
$VD_call_quota_lead_ranking = 'DISABLED';
$vmm_daily_limit = $aryA[12];
$manual_vm_status_updates = $aryA[13];
$recording_dtmf_muting = $aryA[14];
$sthA->finish();
if ($AGILOG) {$agi_string = "-- Inbound call, settings gathered from: |$selected_campaign|$DB_am_message_exten|$DB_amd_send_to_vmx|$waitforsilence_options"; &agi_output;}
}
Expand Down Expand Up @@ -709,17 +716,49 @@ else
%ast_ver_str = parse_asterisk_version($asterisk_version);
if (( $ast_ver_str{major} = 1 ) && ($ast_ver_str{minor} < 6))
{
$AGI->exec("Monitor wav|/var/spool/asterisk/monitor/MIX/$campaign_rec_filename");
$AGI->exec("Monitor wav|/var/spool/asterisk/monitor/MIX/AMD$campaign_rec_filename");
}
else
{
$AGI->exec("Monitor","wav,/var/spool/asterisk/monitor/MIX/$campaign_rec_filename");
if ( ($ast_ver_str{major} > 20) || ($SSrecording_dtmf_muting > 0) )
{
# Deprecation of "Monitor" application after Asterisk 20
$AGI->exec("MixMonitor",",r($PATHmonitor/MIX/AMD$campaign_rec_filename-in.wav)t($PATHmonitor/MIX/AMD$campaign_rec_filename-out.wav)");
}
else
{
$AGI->exec("Monitor","wav,/var/spool/asterisk/monitor/MIX/AMD$campaign_rec_filename");
}
}

### insert record into recording_log table ###
$stmtA = "INSERT INTO recording_log (channel,server_ip,extension,start_time,start_epoch,length_in_sec,filename,lead_id,user,location,vicidial_id) values('$channel','$VARserver_ip','$VD_phone_number','$now_date','$now_date_epoch','0','$campaign_rec_filename','$VD_lead_id','VDAD','$campaign_rec_filename','$uniqueid');";
$stmtA = "INSERT INTO recording_log (channel,server_ip,extension,start_time,start_epoch,length_in_sec,filename,lead_id,user,location,vicidial_id) values('$channel','$VARserver_ip','$VD_phone_number','$now_date','$now_date_epoch','0','AMD$campaign_rec_filename','$VD_lead_id','VDAD','AMD$campaign_rec_filename','$uniqueid');";
$SRaffected_rows = $dbhA->do($stmtA);
if ($AGILOG) {$agi_string = "-- AMD RECORDING STARTED : |$SRaffected_rows|$campaign_rec_filename|$stmtA|"; &agi_output;}

$stmtB = "SELECT LAST_INSERT_ID() LIMIT 1;";
$sthA = $dbhA->prepare($stmtB) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
if ($sthArows > 0)
{
@aryA = $sthA->fetchrow_array;
$recording_id = $aryA[0];
}
$sthA->finish();

if ( ($SSrecording_dtmf_detection > 0) && ($SSrecording_dtmf_muting > 0) )
{
if ($SSrecording_dtmf_muting > 1)
{
$recording_dtmf_muting = $SSrecording_dtmf_muting;
}
}

### insert record into recording_live table ###
$stmtD = "INSERT INTO recording_live (recording_id,recording_type,server_ip,start_time,channel,filename,lead_id,user,dtmf_muting_end_time,recording_status,dtmf_muting_seconds) values('$recording_id','MONO_LEGACY_AMD','$VARserver_ip','$now_date','$channel','AMD$campaign_rec_filename','$VD_lead_id','VDAD','2020-12-31 23:59:59','STARTED','$recording_dtmf_muting');";
$rLIVEaffected_rows = $dbhA->do($stmtD);

if ($AGILOG) {$agi_string = "-- AMD RECORDING STARTED : |$SRaffected_rows|$rLIVEaffected_rows|$recording_id|AMD$campaign_rec_filename|$stmtA|"; &agi_output;}
}
}

Expand Down
33 changes: 29 additions & 4 deletions agi/agi-DID_route.agi
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# ;inbound DID catch-all:
#exten => _X.,1,AGI(agi-DID_route.agi)
#
# Copyright (C) 2024 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
# Copyright (C) 2025 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
#
# changes:
# 81007-0324 - First Build
Expand Down Expand Up @@ -51,6 +51,8 @@
# 220507-0811 - Added pre_filter_recent_call function
# 230124-1228 - Added logging of VICIrecGatewayID channel variable, and vicidial_did_gateway_log table
# 241208-1748 - Changed DID filter_phone_group_id & pre_filter_phone_group_id to multi-selects
# 250924-2156 - Added code for deprecation of "Monitor" application after Asterisk 20
# 251006-0905 - If recording_dtmf_muting enabled, force use of MixMonitor for recording
#


Expand Down Expand Up @@ -153,7 +155,7 @@ $sthA->finish();

#############################################
##### START SYSTEM SETTINGS LOOKUP #####
$stmtA = "SELECT enable_queuemetrics_logging,queuemetrics_server_ip,queuemetrics_dbname,queuemetrics_login,queuemetrics_pass,queuemetrics_log_id,queuemetrics_eq_prepend,did_agent_log,alt_log_server_ip,alt_log_dbname,alt_log_login,alt_log_pass,tables_use_alt_log_db,did_system_filter,inbound_answer_config FROM system_settings;";
$stmtA = "SELECT enable_queuemetrics_logging,queuemetrics_server_ip,queuemetrics_dbname,queuemetrics_login,queuemetrics_pass,queuemetrics_log_id,queuemetrics_eq_prepend,did_agent_log,alt_log_server_ip,alt_log_dbname,alt_log_login,alt_log_pass,tables_use_alt_log_db,did_system_filter,inbound_answer_config,recording_dtmf_muting,recording_dtmf_detection FROM system_settings;";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
Expand All @@ -175,6 +177,8 @@ if ($sthArows > 0)
$tables_use_alt_log_db = $aryA[12];
$SSdid_system_filter = $aryA[13];
$SSinbound_answer_config = $aryA[14];
$SSrecording_dtmf_muting = $aryA[15];
$SSrecording_dtmf_detection = $aryA[16];
}
$sthA->finish();
##### END SYSTEM SETTINGS LOOKUP #####
Expand Down Expand Up @@ -879,7 +883,15 @@ if ($record_call =~ /Y/)
}
else
{
$AGI->exec("Monitor","wav,/var/spool/asterisk/monitor/MIX/$filename");
if ( ($ast_ver_str{major} > 20) || ($SSrecording_dtmf_muting > 0) )
{
# Deprecation of "Monitor" application after Asterisk 20
$AGI->exec("MixMonitor",",r($PATHmonitor/MIX/$filename-in.wav)t($PATHmonitor/MIX/$filename-out.wav)");
}
else
{
$AGI->exec("Monitor","wav,/var/spool/asterisk/monitor/MIX/$filename");
}
}

### insert record into recording_log table ###
Expand All @@ -899,7 +911,20 @@ if ($record_call =~ /Y/)
$sthA->finish();
}

if ($AGILOG) {$did_string = "-- RECORDING LOG : |$affected_rowsR|$insert_recording_id|$stmtA|"; &did_output;}
$recording_dtmf_muting=0;
if ( ($SSrecording_dtmf_detection > 0) && ($SSrecording_dtmf_muting > 0) )
{
if ($SSrecording_dtmf_muting > 1)
{
$recording_dtmf_muting = $SSrecording_dtmf_muting;
}
}

### insert record into recording_live table ###
$stmtD = "INSERT INTO recording_live (recording_id,recording_type,server_ip,start_time,channel,filename,lead_id,user,dtmf_muting_end_time,recording_status,dtmf_muting_seconds) values('$insert_recording_id','MONO_LEGACY_DID','$VARserver_ip','$now_date','$channel','$filename','$lead_id','$user','2020-12-31 23:59:59','STARTED','$recording_dtmf_muting');";
$rLIVEaffected_rows = $dbhA->do($stmtD);

if ($AGILOG) {$did_string = "-- RECORDING LOG : |$affected_rowsR|$rLIVEaffected_rows|$insert_recording_id|$stmtA|"; &did_output;}
}

### Grab Server values from the database
Expand Down
41 changes: 39 additions & 2 deletions agi/agi-IVR_recording_verification.agi
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
#exten => _83002*.,5,Hangup
#
#
# Copyright (C) 2013 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
# Copyright (C) 2025 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
#
# CHANGELOG
# 70912-1105 - First build, non-functional
Expand All @@ -53,6 +53,8 @@
# 71120-1337 - added playing of recording ID at beginning of session
# 120430-2214 - Converted call to Monitor app to be asterisk 1.8 compatible
# 130108-1816 - Changes for Asterisk 1.8 compatibility
# 250924-2158 - Added code for deprecation of "Monitor" application after Asterisk 20
# 251006-0901 - If recording_dtmf_muting enabled, force use of MixMonitor for recording
#

&get_time_now;
Expand Down Expand Up @@ -118,6 +120,21 @@ $dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VA
or die "Couldn't connect to database: " . DBI->errstr;


#############################################
##### Gather system_settings #####
$stmtA = "SELECT recording_dtmf_muting,recording_dtmf_detection 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;
$SSrecording_dtmf_muting = $aryA[0];
$SSrecording_dtmf_detection = $aryA[1];
}
$sthA->finish();
###########################################

### Grab Server values from the database
$stmtA = "SELECT agi_output,ext_context,asterisk_version FROM servers where server_ip = '$VARserver_ip';";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
Expand Down Expand Up @@ -386,7 +403,15 @@ if ($record_call =~ /Y/)
}
else
{
$AGI->exec("Monitor","wav,/var/spool/asterisk/monitor/MIX/$filename,m");
if ( ($ast_ver_str{major} > 20) || ($SSrecording_dtmf_muting > 0) )
{
# Deprecation of "Monitor" application after Asterisk 20
$AGI->exec("MixMonitor",",r($PATHmonitor/MIX/$filename-in.wav)t($PATHmonitor/MIX/$filename-out.wav)");
}
else
{
$AGI->exec("Monitor","wav,/var/spool/asterisk/monitor/MIX/$filename,m");
}
}

### insert record into recording_log table ###
Expand All @@ -409,6 +434,18 @@ if ($record_call =~ /Y/)
if ($AGILOG) {$agi_string = "RECORDING- $recording_id $ivr_id START filename: $filename"; &agi_output;}
$affected_rows = $dbhA->do($stmtA);

$recording_dtmf_muting=0;
if ( ($SSrecording_dtmf_detection > 0) && ($SSrecording_dtmf_muting > 0) )
{
if ($SSrecording_dtmf_muting > 1)
{
$recording_dtmf_muting = $SSrecording_dtmf_muting;
}
}

### insert record into recording_live table ###
$stmtD = "INSERT INTO recording_live (recording_id,recording_type,server_ip,start_time,channel,filename,lead_id,user,dtmf_muting_end_time,recording_status,dtmf_muting_seconds) values('$recording_id','MONO_LEGACY_VERIF','$server_ip','$now_date','$channel','$filename','$lead_id','$user','2020-12-31 23:59:59','STARTED','$recording_dtmf_muting');";
$rLIVEaffected_rows = $dbhA->do($stmtD);
}


Expand Down
Loading