Added --call-log-only flag to archive log script
Added FastAGIServer code git-svn-id: svn://192.168.202.10@4015 3d104415-ff17-0410-8863-d5cf3c621b8a
This commit is contained in:
@@ -78,6 +78,7 @@
|
|||||||
# 251024-1518 - Added --vicidial-dial-log-only flag
|
# 251024-1518 - Added --vicidial-dial-log-only flag
|
||||||
# 260111-2138 - Added --agent-log-only flag
|
# 260111-2138 - Added --agent-log-only flag
|
||||||
# 260516-2149 - Added internal logging
|
# 260516-2149 - Added internal logging
|
||||||
|
# 260826-2206 - Added --call-log-only flag
|
||||||
#
|
#
|
||||||
|
|
||||||
$CALC_TEST=0;
|
$CALC_TEST=0;
|
||||||
@@ -132,6 +133,8 @@ if (length($ARGV[0])>1)
|
|||||||
print " [--vicidial-dial-log-days=XX] = REQUIRED FOR --vicidial-dial-log-only, number of days to archive vicidial_dial_log table only past\n";
|
print " [--vicidial-dial-log-days=XX] = REQUIRED FOR --vicidial-dial-log-only, number of days to archive vicidial_dial_log table only past\n";
|
||||||
print " [--extended-log-only] = OPTIONAL, only archive vicidial_log_extended table then exit\n";
|
print " [--extended-log-only] = OPTIONAL, only archive vicidial_log_extended table then exit\n";
|
||||||
print " [--extended-log-days=XX] = REQUIRED FOR --extended-log-only, number of days to archive vicidial_log_extended table only past\n";
|
print " [--extended-log-days=XX] = REQUIRED FOR --extended-log-only, number of days to archive vicidial_log_extended table only past\n";
|
||||||
|
print " [--call-log-only] = OPTIONAL, only archive call_log table then exit\n";
|
||||||
|
print " [--call-log-days=XX] = REQUIRED FOR --call-log-only, number of days to archive call_log table only past\n";
|
||||||
print " [--agent-log-only] = OPTIONAL, only archive vicidial_agent_log table then exit\n";
|
print " [--agent-log-only] = OPTIONAL, only archive vicidial_agent_log table then exit\n";
|
||||||
print " [--api-archive-only] = OPTIONAL, only purge vicidial_api_log_archive table then exit\n";
|
print " [--api-archive-only] = OPTIONAL, only purge vicidial_api_log_archive table then exit\n";
|
||||||
print " [--api-archive-days=XX] = REQUIRED FOR --api-archive-only, number of days to purge vicidial_api_log_archive table only past\n";
|
print " [--api-archive-days=XX] = REQUIRED FOR --api-archive-only, number of days to purge vicidial_api_log_archive table only past\n";
|
||||||
@@ -354,6 +357,25 @@ if (length($ARGV[0])>1)
|
|||||||
{print "\n----- EXTENDED LOG ARCHIVE ACTIVE, DAYS: $extendeddays -----\n\n";}
|
{print "\n----- EXTENDED LOG ARCHIVE ACTIVE, DAYS: $extendeddays -----\n\n";}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($args =~ /--call-log-only/i)
|
||||||
|
{
|
||||||
|
$call_log_only++;
|
||||||
|
if ($Q < 1)
|
||||||
|
{print "\n----- CALL LOG ARCHIVE ONLY $call_log_only -----\n\n";}
|
||||||
|
}
|
||||||
|
if ($args =~ /--call-log-days=/i)
|
||||||
|
{
|
||||||
|
$call_log_only++;
|
||||||
|
@data_in = split(/--call-log-days=/,$args);
|
||||||
|
$extendeddays = $data_in[1];
|
||||||
|
$extendeddays =~ s/ .*$//gi;
|
||||||
|
$extendeddays =~ s/\D//gi;
|
||||||
|
if ($extendeddays > 999999)
|
||||||
|
{$extendeddays=1825;}
|
||||||
|
if ($Q < 1)
|
||||||
|
{print "\n----- CALL LOG ARCHIVE ACTIVE, DAYS: $extendeddays -----\n\n";}
|
||||||
|
}
|
||||||
|
|
||||||
if ($args =~ /--api-archive-only/i)
|
if ($args =~ /--api-archive-only/i)
|
||||||
{
|
{
|
||||||
$api_archive_only++;
|
$api_archive_only++;
|
||||||
@@ -536,7 +558,7 @@ if ($url_log_only > 0)
|
|||||||
if ($URLsec < 10) {$URLsec = "0$URLsec";}
|
if ($URLsec < 10) {$URLsec = "0$URLsec";}
|
||||||
$URLdel_time = "$URLyear-$URLmon-$URLmday $URLhour:$URLmin:$URLsec";
|
$URLdel_time = "$URLyear-$URLmon-$URLmday $URLhour:$URLmin:$URLsec";
|
||||||
}
|
}
|
||||||
if ( ($extended_log_only > 0) || ($vicidial_log_only > 0) || ($vicidial_dial_log_only > 0) )
|
if ( ($extended_log_only > 0) || ($call_log_only > 0) || ($vicidial_log_only > 0) || ($vicidial_dial_log_only > 0) )
|
||||||
{
|
{
|
||||||
$EXTENDEDdel_epoch = ($secX - (86400 * $extendeddays)); # X days ago
|
$EXTENDEDdel_epoch = ($secX - (86400 * $extendeddays)); # X days ago
|
||||||
($EXTENDEDsec,$EXTENDEDmin,$EXTENDEDhour,$EXTENDEDmday,$EXTENDEDmon,$EXTENDEDyear,$EXTENDEDwday,$EXTENDEDyday,$EXTENDEDisdst) = localtime($EXTENDEDdel_epoch);
|
($EXTENDEDsec,$EXTENDEDmin,$EXTENDEDhour,$EXTENDEDmday,$EXTENDEDmon,$EXTENDEDyear,$EXTENDEDwday,$EXTENDEDyday,$EXTENDEDisdst) = localtime($EXTENDEDdel_epoch);
|
||||||
@@ -2058,6 +2080,65 @@ if (!$T)
|
|||||||
########## END --extended-log-only flag processing ##########
|
########## END --extended-log-only flag processing ##########
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
########## BEGIN --call-log-only flag processing ##########
|
||||||
|
if ($call_log_only > 0)
|
||||||
|
{
|
||||||
|
##### call_log
|
||||||
|
$stmtA = "SELECT count(*) from call_log;";
|
||||||
|
$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;
|
||||||
|
$call_log_count = $aryA[0];
|
||||||
|
}
|
||||||
|
$sthA->finish();
|
||||||
|
|
||||||
|
$stmtA = "SELECT count(*) from call_log_archive;";
|
||||||
|
$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;
|
||||||
|
$call_log_archive_count = $aryA[0];
|
||||||
|
}
|
||||||
|
$sthA->finish();
|
||||||
|
|
||||||
|
if (!$Q) {print "\nProcessing call_log table... ($call_log_count|$call_log_archive_count)\n";}
|
||||||
|
$stmtA = "INSERT IGNORE INTO call_log_archive SELECT * from call_log;";
|
||||||
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||||
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||||
|
|
||||||
|
$sthArows = $sthA->rows;
|
||||||
|
if (!$Q) {print "$sthArows rows inserted into call_log_archive table \n";}
|
||||||
|
|
||||||
|
$rv = $sthA->err();
|
||||||
|
if (!$rv)
|
||||||
|
{
|
||||||
|
if ($wipe_all > 0)
|
||||||
|
{$stmtA = "DELETE FROM call_log;";}
|
||||||
|
else
|
||||||
|
{$stmtA = "DELETE FROM call_log WHERE start_time < '$EXTENDEDdel_time';";}
|
||||||
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||||
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||||
|
$sthArows = $sthA->rows;
|
||||||
|
if (!$Q) {print "$sthArows rows deleted from call_log table \n";}
|
||||||
|
|
||||||
|
$stmtA = "optimize table call_log;";
|
||||||
|
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||||
|
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$Q) {print "\nProcessing call_log table finished: ($sthArows rows deleted) \n";}
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
########## END --call-log-only flag processing ##########
|
||||||
|
|
||||||
|
|
||||||
########## BEGIN --vicidial-log-only flag processing ##########
|
########## BEGIN --vicidial-log-only flag processing ##########
|
||||||
if ($vicidial_log_only > 0)
|
if ($vicidial_log_only > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -185,9 +185,10 @@
|
|||||||
# 260515-2121 - Added truncating of vicidial_internal_log entries after 7 days, updating of some records
|
# 260515-2121 - Added truncating of vicidial_internal_log entries after 7 days, updating of some records
|
||||||
# 260527-0142 - Added dialplan filtering
|
# 260527-0142 - Added dialplan filtering
|
||||||
# 260605-1002 - Added end-of-day log processing log entry for the vicidial_internal_log
|
# 260605-1002 - Added end-of-day log processing log entry for the vicidial_internal_log
|
||||||
|
# 260826-1814 - Added FastAGIServer code
|
||||||
#
|
#
|
||||||
|
|
||||||
$build = '260605-1002';
|
$build = '260826-1814';
|
||||||
|
|
||||||
$DB=0; # Debug flag
|
$DB=0; # Debug flag
|
||||||
$teodDB=0; # flag to log Timeclock End of Day processes to log file
|
$teodDB=0; # flag to log Timeclock End of Day processes to log file
|
||||||
@@ -598,6 +599,7 @@ else
|
|||||||
$AST_VDremote_agents=0;
|
$AST_VDremote_agents=0;
|
||||||
$AST_VDadapt=0;
|
$AST_VDadapt=0;
|
||||||
$FastAGI_log=0;
|
$FastAGI_log=0;
|
||||||
|
$FastAGIServer=0;
|
||||||
$email_inbound=0;
|
$email_inbound=0;
|
||||||
$AST_VDauto_dial_FILL=0;
|
$AST_VDauto_dial_FILL=0;
|
||||||
$ip_relay=0;
|
$ip_relay=0;
|
||||||
@@ -619,6 +621,7 @@ else
|
|||||||
$runningsip_logger=0;
|
$runningsip_logger=0;
|
||||||
$runningconf_updater=0;
|
$runningconf_updater=0;
|
||||||
$runningcrash_test=0;
|
$runningcrash_test=0;
|
||||||
|
$runningFastAGIServer=0;
|
||||||
$AST_conf_3way=0;
|
$AST_conf_3way=0;
|
||||||
$AST_rec_monitor=0;
|
$AST_rec_monitor=0;
|
||||||
|
|
||||||
@@ -682,6 +685,11 @@ else
|
|||||||
$conf_updater=1;
|
$conf_updater=1;
|
||||||
if ($DB) {print "Check to see if conference updater should run\n";}
|
if ($DB) {print "Check to see if conference updater should run\n";}
|
||||||
}
|
}
|
||||||
|
if ($VARactive_keepalives =~ /F/)
|
||||||
|
{
|
||||||
|
$FastAGIServer=1;
|
||||||
|
if ($DB) {print "FastAGIServer set to keepalive\n";}
|
||||||
|
}
|
||||||
if ($cu3way > 0)
|
if ($cu3way > 0)
|
||||||
{
|
{
|
||||||
$AST_conf_3way=1;
|
$AST_conf_3way=1;
|
||||||
@@ -800,6 +808,11 @@ else
|
|||||||
$runningcrash_test++;
|
$runningcrash_test++;
|
||||||
if ($DB) {print "AST_table_status RUNNING: |$psline[1]|\n";}
|
if ($DB) {print "AST_table_status RUNNING: |$psline[1]|\n";}
|
||||||
}
|
}
|
||||||
|
if ($psoutput[$i] =~ /$REGhome\/FastAGIServer\/FastAGIServer\.pl/)
|
||||||
|
{
|
||||||
|
$runningFastAGIServer++;
|
||||||
|
if ($DB) {print "FastAGIServer Running: |$psoutput[$i]|\n";}
|
||||||
|
}
|
||||||
|
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
@@ -813,7 +826,14 @@ else
|
|||||||
if($DB){print STDERR "$affected_rows|\n";}
|
if($DB){print STDERR "$affected_rows|\n";}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# if $runningFastAGIServer running, update internal process log
|
||||||
|
if ( ($runningFastAGIServer > 0) && ($reset_test =~ /0$|5$/) )
|
||||||
|
{
|
||||||
|
$stmtA = "UPDATE vicidial_internal_log SET up_time=NOW(), action='running', stage=CONCAT((UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(db_time)),' seconds runtime') WHERE process='FastAGIServer.pl' and server_ip='$server_ip' order by db_time desc limit 1;";
|
||||||
|
if($DB){print STDERR "|$stmtA|";}
|
||||||
|
my $affected_rows = $dbhA->do($stmtA);
|
||||||
|
if($DB){print STDERR "$affected_rows|\n";}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
##### Second, IF MORE THAN ONE LISTEN INSTANCE IS RUNNING, KILL THE SECOND ONE #####
|
##### Second, IF MORE THAN ONE LISTEN INSTANCE IS RUNNING, KILL THE SECOND ONE #####
|
||||||
@@ -889,6 +909,7 @@ else
|
|||||||
( ($AST_VDremote_agents > 0) && ($runningAST_VDremote_agents < 1) ) ||
|
( ($AST_VDremote_agents > 0) && ($runningAST_VDremote_agents < 1) ) ||
|
||||||
( ($AST_VDadapt > 0) && ($runningAST_VDadapt < 1) ) ||
|
( ($AST_VDadapt > 0) && ($runningAST_VDadapt < 1) ) ||
|
||||||
( ($FastAGI_log > 0) && ($runningFastAGI_log < 1) ) ||
|
( ($FastAGI_log > 0) && ($runningFastAGI_log < 1) ) ||
|
||||||
|
( ($FastAGIServer > 0) && ($runningFastAGIServer < 1) ) ||
|
||||||
( ($AST_VDauto_dial_FILL > 0) && ($runningAST_VDauto_dial_FILL < 1) ) ||
|
( ($AST_VDauto_dial_FILL > 0) && ($runningAST_VDauto_dial_FILL < 1) ) ||
|
||||||
( ($ip_relay > 0) && ($runningip_relay < 1) ) ||
|
( ($ip_relay > 0) && ($runningip_relay < 1) ) ||
|
||||||
( ($AST_conf_3way > 0) && ($runningAST_conf_3way < 1) ) ||
|
( ($AST_conf_3way > 0) && ($runningAST_conf_3way < 1) ) ||
|
||||||
@@ -998,6 +1019,11 @@ else
|
|||||||
$runningcrash_test++;
|
$runningcrash_test++;
|
||||||
if ($DB) {print "AST_table_status RUNNING: |$psline[1]|\n";}
|
if ($DB) {print "AST_table_status RUNNING: |$psline[1]|\n";}
|
||||||
}
|
}
|
||||||
|
if ($psoutput2[$i] =~ /$REGhome\/FastAGIServer\/FastAGIServer\.pl/)
|
||||||
|
{
|
||||||
|
$runningFastAGIServer++;
|
||||||
|
if ($DB) {print "FastAGIServer Running: |$psoutput2[$i]|\n";}
|
||||||
|
}
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1167,6 +1193,13 @@ else
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( ($FastAGIServer > 0) && ($runningFastAGIServer < 1) )
|
||||||
|
{
|
||||||
|
# FastAGIServer does not run in a Screen session
|
||||||
|
if ($DB) {print "starting FastAGIServer...\n";}
|
||||||
|
`/usr/bin/screen -d -m -S FastAGIServer $PATHhome/FastAGIServer/FastAGIServer.pl --nofork --loglevel 4`;
|
||||||
|
# `/usr/bin/perl $PATHhome/FastAGIServer/FastAGIServer.pl &`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
# Compiler settings
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -O2 -Wall -Wextra -static
|
||||||
|
|
||||||
|
# Installation directory
|
||||||
|
AGI_BIN_DIR = /var/lib/asterisk/agi-bin
|
||||||
|
|
||||||
|
# Target binaries
|
||||||
|
TARGETS = agi-VDAD_ALL_outbound.agi agi-VDAD_ALL_inbound.agi VD_amd.agi
|
||||||
|
|
||||||
|
# Default rule (runs when you type 'make')
|
||||||
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
# Compilation rules
|
||||||
|
agi-VDAD_ALL_outbound.agi: VDAD_ALL_outbound_redir.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
agi-VDAD_ALL_inbound.agi: VDAD_ALL_inbound_redir.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
VD_amd.agi: VD_amd_redir.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
# Installation rule (runs when you type 'sudo make install')
|
||||||
|
install: all
|
||||||
|
mkdir -p $(AGI_BIN_DIR)
|
||||||
|
cp $(TARGETS) $(AGI_BIN_DIR)/
|
||||||
|
chmod +x $(TARGETS:%=$(AGI_BIN_DIR)/%)
|
||||||
|
@echo "AGI scripts installed successfully to $(AGI_BIN_DIR)"
|
||||||
|
|
||||||
|
# Cleanup rule (runs when you type 'make clean')
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGETS)
|
||||||
|
|
||||||
|
.PHONY: all install clean
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DELIMITER "-----"
|
||||||
|
#define BUFFER_SIZE 4096
|
||||||
|
#define FAGI_CMD "EXEC AGI agi://127.0.0.1:4573/VDAD_ALL_inbound"
|
||||||
|
#define MOVED_MSG "ATTENTION! agi-VDAD_ALL_inbound.agi has replaced by a FastAGI at agi://127.0.0.1:4573/VDAD_ALL_inbound. You need to update your dialplan. Redirecting to the FastAGI.\n"
|
||||||
|
|
||||||
|
// Helper function to send commands to Asterisk and read the response
|
||||||
|
void send_agi_command(const char *cmd) {
|
||||||
|
char response[BUFFER_SIZE];
|
||||||
|
printf("%s\n", cmd);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// Read response to keep communication synchronized
|
||||||
|
if (fgets(response, sizeof(response), stdin) != NULL) {
|
||||||
|
response[strcspn(response, "\r\n")] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char env_buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
// Read the environment block from Asterisk
|
||||||
|
while (fgets(env_buffer, sizeof(env_buffer), stdin) != NULL) {
|
||||||
|
if (strcmp(env_buffer, "\n") == 0 || strcmp(env_buffer, "\r\n") == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to let an Admin know of the changes
|
||||||
|
fprintf(stderr, MOVED_MSG);
|
||||||
|
|
||||||
|
// 2. Parse the argument string if it exists
|
||||||
|
if (argc > 1 && argv != NULL && argv[1] != NULL) {
|
||||||
|
char var_buf[BUFFER_SIZE] = "";
|
||||||
|
char cmd_buf[BUFFER_SIZE];
|
||||||
|
|
||||||
|
char *src = argv[1]; // Safely assigned now that we've checked argv[1] != NULL
|
||||||
|
char *next_delim;
|
||||||
|
size_t delim_len = strlen(DELIMITER);
|
||||||
|
size_t var_len = 0;
|
||||||
|
int need_comma = 0;
|
||||||
|
|
||||||
|
// Find each occurrence of "-----"
|
||||||
|
while ((next_delim = strstr(src, DELIMITER)) != NULL) {
|
||||||
|
size_t segment_len = next_delim - src;
|
||||||
|
|
||||||
|
if (segment_len > 0) {
|
||||||
|
int written = snprintf(var_buf + var_len, sizeof(var_buf) - var_len,
|
||||||
|
"%s%.*s", need_comma ? "," : "", (int)segment_len, src);
|
||||||
|
|
||||||
|
if (written < 0 || (size_t)written >= sizeof(var_buf) - var_len) break;
|
||||||
|
var_len += written;
|
||||||
|
need_comma = 1;
|
||||||
|
}
|
||||||
|
src = next_delim + delim_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the final remaining part of the string if it contains data
|
||||||
|
if (strlen(src) > 0 && var_len < sizeof(var_buf)) {
|
||||||
|
snprintf(var_buf + var_len, sizeof(var_buf) - var_len,
|
||||||
|
"%s%s", need_comma ? "," : "", src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ONLY send to Asterisk if we actually captured an argument string
|
||||||
|
if (strlen(var_buf) > 0) {
|
||||||
|
int cmd_written = snprintf(cmd_buf, sizeof(cmd_buf), "SET VARIABLE AGIARGS \"%s\"", var_buf);
|
||||||
|
if (cmd_written >= 0 && (size_t)cmd_written < sizeof(cmd_buf)) {
|
||||||
|
send_agi_command(cmd_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hand off the call to the FastAGI server
|
||||||
|
send_agi_command(FAGI_CMD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DELIMITER "-----"
|
||||||
|
#define BUFFER_SIZE 4096
|
||||||
|
#define FAGI_CMD "EXEC AGI agi://127.0.0.1:4573/VDAD_ALL_outbound"
|
||||||
|
#define MOVED_MSG "ATTENTION! agi-VDAD_ALL_outbound.agi has replaced by a FastAGI at agi://127.0.0.1:4573/VDAD_ALL_outbound. You need to update your dialplan. Redirecting to the FastAGI.\n"
|
||||||
|
|
||||||
|
// Helper function to send commands to Asterisk and read the response
|
||||||
|
void send_agi_command(const char *cmd) {
|
||||||
|
char response[BUFFER_SIZE];
|
||||||
|
printf("%s\n", cmd);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// Read response to keep communication synchronized
|
||||||
|
if (fgets(response, sizeof(response), stdin) != NULL) {
|
||||||
|
response[strcspn(response, "\r\n")] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char env_buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
// Read the environment block from Asterisk
|
||||||
|
while (fgets(env_buffer, sizeof(env_buffer), stdin) != NULL) {
|
||||||
|
if (strcmp(env_buffer, "\n") == 0 || strcmp(env_buffer, "\r\n") == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to let an Admin know of the changes
|
||||||
|
fprintf(stderr, MOVED_MSG);
|
||||||
|
|
||||||
|
// 2. Parse the argument string if it exists
|
||||||
|
if (argc > 1 && argv != NULL && argv[1] != NULL) {
|
||||||
|
char var_buf[BUFFER_SIZE] = "";
|
||||||
|
char cmd_buf[BUFFER_SIZE];
|
||||||
|
|
||||||
|
char *src = argv[1]; // Safely assigned now that we've checked argv[1] != NULL
|
||||||
|
char *next_delim;
|
||||||
|
size_t delim_len = strlen(DELIMITER);
|
||||||
|
size_t var_len = 0;
|
||||||
|
int need_comma = 0;
|
||||||
|
|
||||||
|
// Find each occurrence of "-----"
|
||||||
|
while ((next_delim = strstr(src, DELIMITER)) != NULL) {
|
||||||
|
size_t segment_len = next_delim - src;
|
||||||
|
|
||||||
|
if (segment_len > 0) {
|
||||||
|
int written = snprintf(var_buf + var_len, sizeof(var_buf) - var_len,
|
||||||
|
"%s%.*s", need_comma ? "," : "", (int)segment_len, src);
|
||||||
|
|
||||||
|
if (written < 0 || (size_t)written >= sizeof(var_buf) - var_len) break;
|
||||||
|
var_len += written;
|
||||||
|
need_comma = 1;
|
||||||
|
}
|
||||||
|
src = next_delim + delim_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the final remaining part of the string if it contains data
|
||||||
|
if (strlen(src) > 0 && var_len < sizeof(var_buf)) {
|
||||||
|
snprintf(var_buf + var_len, sizeof(var_buf) - var_len,
|
||||||
|
"%s%s", need_comma ? "," : "", src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ONLY send to Asterisk if we actually captured an argument string
|
||||||
|
if (strlen(var_buf) > 0) {
|
||||||
|
int cmd_written = snprintf(cmd_buf, sizeof(cmd_buf), "SET VARIABLE AGIARGS \"%s\"", var_buf);
|
||||||
|
if (cmd_written >= 0 && (size_t)cmd_written < sizeof(cmd_buf)) {
|
||||||
|
send_agi_command(cmd_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hand off the call to the FastAGI server
|
||||||
|
send_agi_command(FAGI_CMD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,81 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DELIMITER "-----"
|
||||||
|
#define BUFFER_SIZE 4096
|
||||||
|
#define FAGI_CMD "EXEC AGI agi://127.0.0.1:4573/VD_amd"
|
||||||
|
#define MOVED_MSG "ATTENTION! VD_amd.agi has replaced by a FastAGI at agi://127.0.0.1:4573/VD_amd. You need to update your dialplan. Redirecting to the FastAGI.\n"
|
||||||
|
|
||||||
|
// Helper function to send commands to Asterisk and read the response
|
||||||
|
void send_agi_command(const char *cmd) {
|
||||||
|
char response[BUFFER_SIZE];
|
||||||
|
printf("%s\n", cmd);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// Read response to keep communication synchronized
|
||||||
|
if (fgets(response, sizeof(response), stdin) != NULL) {
|
||||||
|
response[strcspn(response, "\r\n")] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char env_buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
// Read the environment block from Asterisk
|
||||||
|
while (fgets(env_buffer, sizeof(env_buffer), stdin) != NULL) {
|
||||||
|
if (strcmp(env_buffer, "\n") == 0 || strcmp(env_buffer, "\r\n") == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to let an Admin know of the changes
|
||||||
|
fprintf(stderr, MOVED_MSG);
|
||||||
|
|
||||||
|
// 2. Parse the argument string if it exists
|
||||||
|
if (argc > 1 && argv != NULL && argv[1] != NULL) {
|
||||||
|
char var_buf[BUFFER_SIZE] = "";
|
||||||
|
char cmd_buf[BUFFER_SIZE];
|
||||||
|
|
||||||
|
char *src = argv[1]; // Safely assigned now that we've checked argv[1] != NULL
|
||||||
|
char *next_delim;
|
||||||
|
size_t delim_len = strlen(DELIMITER);
|
||||||
|
size_t var_len = 0;
|
||||||
|
int need_comma = 0;
|
||||||
|
|
||||||
|
// Find each occurrence of "-----"
|
||||||
|
while ((next_delim = strstr(src, DELIMITER)) != NULL) {
|
||||||
|
size_t segment_len = next_delim - src;
|
||||||
|
|
||||||
|
if (segment_len > 0) {
|
||||||
|
int written = snprintf(var_buf + var_len, sizeof(var_buf) - var_len,
|
||||||
|
"%s%.*s", need_comma ? "," : "", (int)segment_len, src);
|
||||||
|
|
||||||
|
if (written < 0 || (size_t)written >= sizeof(var_buf) - var_len) break;
|
||||||
|
var_len += written;
|
||||||
|
need_comma = 1;
|
||||||
|
}
|
||||||
|
src = next_delim + delim_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the final remaining part of the string if it contains data
|
||||||
|
if (strlen(src) > 0 && var_len < sizeof(var_buf)) {
|
||||||
|
snprintf(var_buf + var_len, sizeof(var_buf) - var_len,
|
||||||
|
"%s%s", need_comma ? "," : "", src);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ONLY send to Asterisk if we actually captured an argument string
|
||||||
|
if (strlen(var_buf) > 0) {
|
||||||
|
int cmd_written = snprintf(cmd_buf, sizeof(cmd_buf), "SET VARIABLE AGIARGS \"%s\"", var_buf);
|
||||||
|
if (cmd_written >= 0 && (size_t)cmd_written < sizeof(cmd_buf)) {
|
||||||
|
send_agi_command(cmd_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hand off the call to the FastAGI server
|
||||||
|
send_agi_command(FAGI_CMD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,340 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
#
|
||||||
|
# FastAGIServer.pl
|
||||||
|
#
|
||||||
|
# Runs Vicidial AGI Modules as a FastAGI server
|
||||||
|
#
|
||||||
|
# Copyright (C) 2026 Matt Florell, Mike Cargile <vicidial@gmail.com> LICENSE: AGPLv2
|
||||||
|
#
|
||||||
|
# ; VICIDIAL_auto_dialer transfer script Load Balanced:
|
||||||
|
# exten => 8380,1,AGI(agi://127.0.0.1:4577/call_log)
|
||||||
|
# exten => 8380,n,Set(AGIARGS=NORMAL,LB,${CONNECTEDLINE(name)})
|
||||||
|
# exten => 8380,n,AGI(agi://127.0.0.1:4573/VDAD_ALL_outbound)
|
||||||
|
# exten => 8380,n,Hangup()
|
||||||
|
#
|
||||||
|
# changes:
|
||||||
|
# 260826-1814 - Initial Build
|
||||||
|
#
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
# tell perl where our modules are
|
||||||
|
use FindBin;
|
||||||
|
use lib "$FindBin::Bin";
|
||||||
|
|
||||||
|
# load standard modules
|
||||||
|
use base qw(Net::Server::PreFork);
|
||||||
|
use Asterisk::AGI;
|
||||||
|
use JSON::PP;
|
||||||
|
use DBI;
|
||||||
|
use Time::HiRes ('gettimeofday');
|
||||||
|
use POSIX qw(strftime);
|
||||||
|
use Cwd qw(abs_path);
|
||||||
|
use Getopt::Long qw(GetOptions);
|
||||||
|
|
||||||
|
BEGIN { $0 = abs_path($0); }
|
||||||
|
|
||||||
|
my $nofork = 0;
|
||||||
|
my $loglevel = 3;
|
||||||
|
my $logfile = '/var/log/astguiclient/FastAGI-server.log';
|
||||||
|
|
||||||
|
# Bind options to variables
|
||||||
|
GetOptions(
|
||||||
|
'nofork' => \$nofork,
|
||||||
|
'loglevel=i' => \$loglevel,
|
||||||
|
'help|h|?' => \&show_help,
|
||||||
|
) or die "Error in command line arguments\n";
|
||||||
|
|
||||||
|
my $agc_config_path = '/etc/astguiclient.conf';
|
||||||
|
|
||||||
|
# load /etc/astguiclient.conf
|
||||||
|
my %agc_config = parse_config( $agc_config_path );
|
||||||
|
|
||||||
|
# connect to vicidial DB
|
||||||
|
my $db_connect_str = "DBI:mysql:$agc_config{'VARDB_database'}:$agc_config{'VARDB_server'}:$agc_config{'VARDB_port'}";
|
||||||
|
my $dbh = DBI->connect(
|
||||||
|
$db_connect_str,
|
||||||
|
$agc_config{'VARDB_user'},
|
||||||
|
$agc_config{'VARDB_pass'}
|
||||||
|
) or die "Couldn't connect to database: " . DBI->errstr;
|
||||||
|
|
||||||
|
# get the FAST_AGI_SERVER_CONFIG settings container
|
||||||
|
my $stmt = "SELECT container_entry FROM vicidial_settings_containers WHERE container_id = 'FAST_AGI_SERVER_CONFIG';";
|
||||||
|
my $sth = $dbh->prepare($stmt) or die "preparing: ",$dbh->errstr;
|
||||||
|
$sth->execute or die "executing: $stmt ", $dbh->errstr;
|
||||||
|
|
||||||
|
if ( $sth->rows == 0 ) { die "FAST_AGI_SERVER_CONFIG Settings Container Not Found!!"; }
|
||||||
|
|
||||||
|
my @fagi_settiongs_ary = $sth->fetchrow_array;
|
||||||
|
my $fagi_config_json = $fagi_settiongs_ary[0];
|
||||||
|
|
||||||
|
$sth->finish();
|
||||||
|
|
||||||
|
# log to the internal_process_log
|
||||||
|
$stmt = "INSERT INTO vicidial_internal_log SET db_time=NOW(), up_time=NOW(), action='launched', stage='Run seconds: 0', process='FastAGIServer.pl', server_ip='$agc_config{'VARserver_ip'}';";
|
||||||
|
$sth = $dbh->prepare($stmt) or die "preparing: ",$dbh->errstr;
|
||||||
|
$sth->execute or die "executing: $stmt ", $dbh->errstr;
|
||||||
|
|
||||||
|
$sth->finish();
|
||||||
|
$dbh->disconnect();
|
||||||
|
|
||||||
|
my $fagi_config = decode_json($fagi_config_json);
|
||||||
|
|
||||||
|
|
||||||
|
if ( $loglevel > 4 ) {
|
||||||
|
$loglevel = 4;
|
||||||
|
}
|
||||||
|
if ( $loglevel < 0 ) {
|
||||||
|
$loglevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Set the server options
|
||||||
|
my $server_opts = $fagi_config->{server} || {};
|
||||||
|
$server_opts->{host} //= '0.0.0.0';
|
||||||
|
$server_opts->{port} //= 4573;
|
||||||
|
$server_opts->{min_servers} //= 5;
|
||||||
|
$server_opts->{max_servers} //= 20;
|
||||||
|
$server_opts->{max_requests} //= 1000;
|
||||||
|
$server_opts->{log_level} = $loglevel;
|
||||||
|
|
||||||
|
if ( $nofork == 1 ) {
|
||||||
|
print( "No Fork active.\n");
|
||||||
|
$server_opts->{background} = 0;
|
||||||
|
$server_opts->{log_file} = undef;
|
||||||
|
} else {
|
||||||
|
$server_opts->{background} = 1;
|
||||||
|
$server_opts->{log_file} //= $logfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my $server = __PACKAGE__->new(%$server_opts);
|
||||||
|
|
||||||
|
$server->{agc_config} = \%agc_config;
|
||||||
|
$server->{fagi_config} = $fagi_config;
|
||||||
|
|
||||||
|
my ($epoch, $usec) = gettimeofday();
|
||||||
|
|
||||||
|
$server->{conf_epoch} = $epoch;
|
||||||
|
$server->{conf_usec} = $usec;
|
||||||
|
|
||||||
|
$server->run();
|
||||||
|
|
||||||
|
sub show_help {
|
||||||
|
print << "EOF";
|
||||||
|
Usage: $0 [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--help Show this help message and exit.
|
||||||
|
--nofork Do not fork a background process and show all log data in the CLI.
|
||||||
|
--loglevel On a scale of 0 to 4 how verbose do you want the logs. (Defaults to 3)
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$0 --nofork --loglevel 4
|
||||||
|
$0 --help
|
||||||
|
$0
|
||||||
|
EOF
|
||||||
|
exit(0); # Exit cleanly since help was explicitly requested
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Overriding the default log writer hook cleanly
|
||||||
|
sub write_to_log_hook {
|
||||||
|
my ($self, $level, $msg) = @_;
|
||||||
|
|
||||||
|
# 1. Strip trailing newlines from the incoming message
|
||||||
|
$msg =~ s/\s+$//;
|
||||||
|
|
||||||
|
# 2. Build your custom timestamp format
|
||||||
|
my ($log_epoch,$log_usec) = gettimeofday();
|
||||||
|
my $log_msec = $log_usec / 1000;
|
||||||
|
my $timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime($log_epoch)) . sprintf(".%03d", $log_msec);
|
||||||
|
|
||||||
|
# 3. Create your custom log format string
|
||||||
|
my $formatted_line = sprintf("[%s] [PID: %d] [LVL: %s] %s\n", $timestamp, $$, $level, $msg);
|
||||||
|
|
||||||
|
# 4. Write it out to the configured file handle
|
||||||
|
if (my $fp = $self->{server}->{log_fp}) {
|
||||||
|
print $fp $formatted_line;
|
||||||
|
} else {
|
||||||
|
print STDERR $formatted_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub idle_loop_hook {
|
||||||
|
my ($self, $readable_fh_ref) = @_;
|
||||||
|
|
||||||
|
$self->SUPER::idle_loop_hook($readable_fh_ref);
|
||||||
|
|
||||||
|
my ($idle_epoch,$idle_usec) = gettimeofday();
|
||||||
|
|
||||||
|
if ($idle_epoch - 30 > $self->{conf_epoch} ) {
|
||||||
|
my $old_fagi_config = $server->{fagi_config};
|
||||||
|
|
||||||
|
# connect to vicidial DB
|
||||||
|
my $db_connect_str = "DBI:mysql:$self->{agc_config}->{'VARDB_database'}:$self->{agc_config}->{'VARDB_server'}:$self->{agc_config}->{'VARDB_port'}";
|
||||||
|
my $dbh = DBI->connect(
|
||||||
|
$db_connect_str,
|
||||||
|
$self->{agc_config}->{'VARDB_user'},
|
||||||
|
$self->{agc_config}->{'VARDB_pass'}
|
||||||
|
) or die "Couldn't connect to database: " . DBI->errstr;
|
||||||
|
|
||||||
|
# get the FAST_AGI_SERVER_CONFIG settings container
|
||||||
|
my $stmt = "SELECT container_entry FROM vicidial_settings_containers WHERE container_id = 'FAST_AGI_SERVER_CONFIG';";
|
||||||
|
my $sth = $dbh->prepare($stmt) or die "preparing: ",$dbh->errstr;
|
||||||
|
$sth->execute or die "executing: $stmt ", $dbh->errstr;
|
||||||
|
|
||||||
|
if ( $sth->rows == 0 ) { die "FAST_AGI_SERVER_CONFIG Settings Container Not Found!!"; }
|
||||||
|
|
||||||
|
my @fagi_settiongs_ary = $sth->fetchrow_array;
|
||||||
|
my $fagi_config_json = $fagi_settiongs_ary[0];
|
||||||
|
|
||||||
|
$sth->finish();
|
||||||
|
$dbh->disconnect();
|
||||||
|
|
||||||
|
my $fagi_config = eval { decode_json($fagi_config_json); };
|
||||||
|
|
||||||
|
if ($@) {
|
||||||
|
$self->log(3, "FAST_AGI_SERVER_CONFIG settings container contains invalid JSON. Keeping old config");
|
||||||
|
} else {
|
||||||
|
my ($epoch, $usec) = gettimeofday();
|
||||||
|
$self->{conf_epoch} = $epoch;
|
||||||
|
$self->{conf_usec} = $usec;
|
||||||
|
|
||||||
|
# Settings are good. update the server
|
||||||
|
my $server_opts = $fagi_config->{server} || {};
|
||||||
|
|
||||||
|
if ($self->_config_has_changed($self->{fagi_config}->{server}, $server_opts)) {
|
||||||
|
$self->{fagi_config} = $fagi_config;
|
||||||
|
|
||||||
|
$self->log(3, "Server config has changed. Reloading." );
|
||||||
|
for my $key ( keys $server_opts->%* ) {
|
||||||
|
# skip keys that cannot be changed
|
||||||
|
next if $key =~ /^(port|host|proto|user|group|chroot|background)$/;
|
||||||
|
|
||||||
|
$self->log( 3, "\t" . $key . "=" . $server_opts->{$key} );
|
||||||
|
$self->{server}->{$key} = $server_opts->{$key};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$self->{server}->{count_servers} = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _config_has_changed {
|
||||||
|
my ($self, $old_hash_ref, $new_hash_ref) = @_;
|
||||||
|
# Check if any keys in the new hash are different or completely missing from old
|
||||||
|
for my $key ( keys $new_hash_ref->%* ) {
|
||||||
|
if (!exists $old_hash_ref->{$key} || $old_hash_ref->{$key} ne $new_hash_ref->{$key}) {
|
||||||
|
return 1; # Change found!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Check if any old keys were deleted in the new database update
|
||||||
|
for my $key ( keys $old_hash_ref->%* ) {
|
||||||
|
if (!exists $new_hash_ref->{$key}) {
|
||||||
|
return 1; # Change found!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; # The two hash references are identical
|
||||||
|
}
|
||||||
|
|
||||||
|
# Net::Server Initialization Function Hook
|
||||||
|
sub post_configure_hook {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
# Save the route mapping globally inside the runtime server object
|
||||||
|
$self->{_agi_routes} = $fagi_config->{routes} || {};
|
||||||
|
|
||||||
|
$self->log(3, "Loading and verifying routing configurations...");
|
||||||
|
|
||||||
|
# Dynamically load the configured call handler modules
|
||||||
|
foreach my $path (keys %{ $self->{_agi_routes} }) {
|
||||||
|
my $package = $self->{_agi_routes}->{$path};
|
||||||
|
|
||||||
|
my $file = $package;
|
||||||
|
$file =~ s/::/\//g;
|
||||||
|
$file .= ".pm";
|
||||||
|
|
||||||
|
$self->log(3, "Dynamically loading module: $package for route $path");
|
||||||
|
|
||||||
|
eval { require $file; };
|
||||||
|
if ($@) {
|
||||||
|
die "Fatal error loading module $package for route $path: $@\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Request Handler
|
||||||
|
sub process_request {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my $AGI = Asterisk::AGI->new(
|
||||||
|
stdin => \*STDIN,
|
||||||
|
stdout => \*STDOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
$AGI->{debug} = 0;
|
||||||
|
|
||||||
|
my %agc_conf = parse_config( $agc_config_path );
|
||||||
|
|
||||||
|
# Parse and extract ALL environment variables into a hash
|
||||||
|
my %input = $AGI->ReadParse();
|
||||||
|
|
||||||
|
my $request_uri = $input{'request'} || '';
|
||||||
|
my $path = '';
|
||||||
|
if ($request_uri =~ m{agi://[^/]+(/[^?#\s]*)}) {
|
||||||
|
$path = $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $handler_class = $self->{_agi_routes}->{$path};
|
||||||
|
|
||||||
|
if ($handler_class) {
|
||||||
|
my $handler_conf = $fagi_config->{handler_settings}->{$handler_class} || {};
|
||||||
|
|
||||||
|
$self->log(3, "Routing $path to handler $handler_class");
|
||||||
|
eval {
|
||||||
|
my $worker = $handler_class->new($self, $AGI, $handler_conf, \%agc_conf, \%input );
|
||||||
|
$worker->run();
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
$self->log(1, "Runtime crash in handler $handler_class: $@");
|
||||||
|
$AGI->verbose("AGI internal server execution error", 1);
|
||||||
|
$AGI->hangup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->log(2, "No configuration route found for path: $path");
|
||||||
|
$AGI->verbose("Unknown route specified: $path", 3);
|
||||||
|
$AGI->hangup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Config Parser
|
||||||
|
sub parse_config {
|
||||||
|
my ($filepath) = @_;
|
||||||
|
my %config;
|
||||||
|
|
||||||
|
open(my $fh, '<', $filepath) or die "Cannot open $filepath: $!";
|
||||||
|
|
||||||
|
while (my $line = <$fh>) {
|
||||||
|
chomp($line);
|
||||||
|
|
||||||
|
$line =~ s/#.*//; # Remove comments
|
||||||
|
$line =~ s/^\s+|\s+$//g; # Trim whitespace
|
||||||
|
next if $line eq ''; # Skip empty lines
|
||||||
|
|
||||||
|
# Match key => value or key = value
|
||||||
|
if ($line =~ /^([^=\s>]+)\s*(?:=>|=)\s*(.+)$/) {
|
||||||
|
my $key = $1;
|
||||||
|
my $val = $2;
|
||||||
|
|
||||||
|
$val =~ s/^['"]|['"]$//g; # Strip quotes
|
||||||
|
$config{$key} = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close($fh);
|
||||||
|
return %config;
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# install.pl version 2.14
|
# install.pl version 2.14
|
||||||
#
|
#
|
||||||
# Copyright (C) 2025 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
# Copyright (C) 2026 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||||
#
|
#
|
||||||
|
|
||||||
# CHANGES
|
# CHANGES
|
||||||
@@ -54,6 +54,7 @@
|
|||||||
# 240704-0830 - Added coldstorage DB entries
|
# 240704-0830 - Added coldstorage DB entries
|
||||||
# 250103-1017 - Added ConfBridge conf files updates
|
# 250103-1017 - Added ConfBridge conf files updates
|
||||||
# 250823-1411 - Added stereo recording directories
|
# 250823-1411 - Added stereo recording directories
|
||||||
|
# 260826-1919 - Added 'F' keepalive option, for FastAGIServer
|
||||||
#
|
#
|
||||||
|
|
||||||
############################################
|
############################################
|
||||||
@@ -236,6 +237,7 @@ if (length($ARGV[0])>1)
|
|||||||
print " 9 - Timeclock auto-logout\n";
|
print " 9 - Timeclock auto-logout\n";
|
||||||
print " C - ConfBridge process, (see the ConfBridge documentation for more info)\n";
|
print " C - ConfBridge process, (see the ConfBridge documentation for more info)\n";
|
||||||
print " E - Email processor, (If multi-server system, this must only be on one server)\n";
|
print " E - Email processor, (If multi-server system, this must only be on one server)\n";
|
||||||
|
print " F - FastAGIServer, for faster routing of calls to agents\n";
|
||||||
print " S - SIP Logger (Patched Asterisk 13 or higher required)\n";
|
print " S - SIP Logger (Patched Asterisk 13 or higher required)\n";
|
||||||
print " [--asterisk_version] = set the asterisk version you want to install for\n";
|
print " [--asterisk_version] = set the asterisk version you want to install for\n";
|
||||||
print " [--copy_sample_conf_files] = copies the sample conf files to /etc/asterisk/\n";
|
print " [--copy_sample_conf_files] = copies the sample conf files to /etc/asterisk/\n";
|
||||||
@@ -2070,6 +2072,7 @@ else
|
|||||||
print " 9 - Timeclock auto logout\n";
|
print " 9 - Timeclock auto logout\n";
|
||||||
print " C - ConfBridge process, (see the ConfBridge documentation for more info)\n";
|
print " C - ConfBridge process, (see the ConfBridge documentation for more info)\n";
|
||||||
print " E - Email processor, (If multi-server system, this must only be on one server)\n";
|
print " E - Email processor, (If multi-server system, this must only be on one server)\n";
|
||||||
|
print " F - FastAGIServer, for faster routing of calls to agents\n";
|
||||||
print " S - SIP Logger (Patched Asterisk 13 or higher required)\n";
|
print " S - SIP Logger (Patched Asterisk 13 or higher required)\n";
|
||||||
print "Enter active keepalives or press enter for default: [$VARactive_keepalives] ";
|
print "Enter active keepalives or press enter for default: [$VARactive_keepalives] ";
|
||||||
$PROMPTactive_keepalives = <STDIN>;
|
$PROMPTactive_keepalives = <STDIN>;
|
||||||
@@ -2711,6 +2714,7 @@ print conf "# 8 - ip_relay (used for blind agent monitoring)\n";
|
|||||||
print conf "# 9 - Timeclock auto logout, (If multi-server system, this must only be on one server)\n";
|
print conf "# 9 - Timeclock auto logout, (If multi-server system, this must only be on one server)\n";
|
||||||
print conf "# C - ConfBridge process, (see the ConfBridge documentation for more info)\n";
|
print conf "# C - ConfBridge process, (see the ConfBridge documentation for more info)\n";
|
||||||
print conf "# E - Email processor, (If multi-server system, this must only be on one server)\n";
|
print conf "# E - Email processor, (If multi-server system, this must only be on one server)\n";
|
||||||
|
print conf "# F - FastAGIServer, for faster routing of calls to agents\n";
|
||||||
print conf "# S - SIP Logger (Patched Asterisk 13 or higher required)\n";
|
print conf "# S - SIP Logger (Patched Asterisk 13 or higher required)\n";
|
||||||
print conf "VARactive_keepalives => $VARactive_keepalives\n";
|
print conf "VARactive_keepalives => $VARactive_keepalives\n";
|
||||||
print conf "\n";
|
print conf "\n";
|
||||||
|
|||||||
Reference in New Issue
Block a user