350 lines
13 KiB
Perl
350 lines
13 KiB
Perl
#!/usr/bin/perl
|
|
#
|
|
# AST_send_action_child.pl version 2.14
|
|
#
|
|
# Part of the Asterisk Central Queue System (ACQS)
|
|
#
|
|
# DESCRIPTION:
|
|
# This script is spawned every time an action is to be executed by the main
|
|
# AST_manager_send.pl script and sends actions blindly to the Asterisk manager
|
|
#
|
|
# SUMMARY:
|
|
# This program was designed as the blind-send part of the ACQS. It's job is to
|
|
# be spawned by the AST_manager_send.pl script lookup the record in the MySQL DB
|
|
# to be executed. connect to the manager interface, send the action and logoff
|
|
# then exit.
|
|
#
|
|
# Copyright (C) 2018 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
|
#
|
|
# CHANGES
|
|
# 50810-1547 - Added database server variable definitions lookup
|
|
# 50823-1527 - Altered commandline debug options with debug printouts
|
|
# 50902-1032 - Changed default logging to fulllog
|
|
# 60718-0909 - Changed to DBI by Marin Blu
|
|
# 60718-1024 - Changed to use /etc/astguiclient.conf for configs
|
|
# 60814-1720 - Added option for no logging to file
|
|
# 60817-1244 - Removed all DB calls and config file open to reduce footprint
|
|
# 61004-1728 - Added ability to parse volume control and lookup meetme IDs
|
|
# 61220-1720 - Optimize and clean code <LottC>
|
|
# 61221-1942 - Additional modification to structure <LottC>
|
|
# 80418-0927 - Added man_id to logging output for better tracking, raised sleep times
|
|
# 100625-1141 - Added waitfors after orginate and logout to fix broken pipe errors in asterisk <MikeC>
|
|
# 100625-1206 - Use strict is a performance hit and should only be uncommented for debugging <MikeC>
|
|
# 130108-1714 - Changes for Asterisk 1.8 compatibility
|
|
# 150610-1200 - Added support for AMI version 1.3
|
|
# 180403-1544 - Updated telnet login process to work with newer Asterisk versions
|
|
#
|
|
|
|
$|++;
|
|
|
|
# use strict is a performance hit and should only be uncommented for debugging
|
|
#use strict;
|
|
#
|
|
|
|
use Getopt::Long;
|
|
use Net::Telnet;
|
|
|
|
### Initialize date/time vars ###
|
|
my $secX = time(); #Start time
|
|
|
|
### Initialize run-time variables ###
|
|
my ($CLOhelp, $SYSLOG, $PATHlogs, $telnet_host, $telnet_port, $ASTmgrUSERNAME);
|
|
my ($ASTmgrSECRET, $ASTmgrUSERNAMEsend, $man_id, $action, $cmd_line_b, $cmd_line_c);
|
|
my ($cmd_line_d, $cmd_line_e, $cmd_line_f, $cmd_line_g, $cmd_line_h);
|
|
my ($cmd_line_i, $cmd_line_j, $cmd_line_k, $DB, $DBX);
|
|
my $FULL_LOG = 1;
|
|
|
|
### begin parsing run-time options ###
|
|
if (scalar @ARGV) {
|
|
GetOptions('help!' => \$CLOhelp,
|
|
'SYSLOG!' => \$SYSLOG,
|
|
'PATHlogs=s' => \$PATHlogs,
|
|
'telnet_host=s' => \$telnet_host,
|
|
'telnet_port=s' => \$telnet_port,
|
|
'ASTmgrUSERNAME=s' => \$ASTmgrUSERNAME,
|
|
'ASTmgrSECRET=s' => \$ASTmgrSECRET,
|
|
'ASTmgrUSERNAMEsend=s' => \$ASTmgrUSERNAMEsend,
|
|
'man_id=s' => \$man_id,
|
|
'action=s' => \$action,
|
|
'cmd_line_b=s' => \$cmd_line_b,
|
|
'cmd_line_c=s' => \$cmd_line_c,
|
|
'cmd_line_d=s' => \$cmd_line_d,
|
|
'cmd_line_e=s' => \$cmd_line_e,
|
|
'cmd_line_f=s' => \$cmd_line_f,
|
|
'cmd_line_g=s' => \$cmd_line_g,
|
|
'cmd_line_h=s' => \$cmd_line_h,
|
|
'cmd_line_i=s' => \$cmd_line_i,
|
|
'cmd_line_j=s' => \$cmd_line_j,
|
|
'cmd_line_k=s' => \$cmd_line_k,
|
|
'debug!' => \$DB,
|
|
'debugX!' => \$DBX,
|
|
'fulllog!' => \$FULL_LOG);
|
|
|
|
$DB = 1 if ($DBX);
|
|
if ($DB) {
|
|
print "\n----- DEBUGGING -----\n\n";
|
|
print "\n----- SUPER-DUPER DEBUGGING -----\n\n" if ($DBX);
|
|
print " SYSLOG: $SYSLOG\n" if ($SYSLOG);
|
|
print " telnet_host: $telnet_host\n" if ($telnet_host);
|
|
print " telnet_port: $telnet_port\n" if ($telnet_port);
|
|
print " ASTmgrUSERNAME: $ASTmgrUSERNAME\n" if ($ASTmgrUSERNAME);
|
|
print " ASTmgrSECRET: $ASTmgrSECRET\n" if ($ASTmgrSECRET);
|
|
print " ASTmgrUSERNAMEsend: $ASTmgrUSERNAMEsend\n" if ($ASTmgrUSERNAMEsend);
|
|
print " man_id: $man_id\n" if ($man_id);
|
|
print " cmd_line_b: $cmd_line_b\n" if ($cmd_line_b);
|
|
print " cmd_line_c: $cmd_line_c\n" if ($cmd_line_c);
|
|
print " cmd_line_d: $cmd_line_d\n" if ($cmd_line_d);
|
|
print " cmd_line_e: $cmd_line_e\n" if ($cmd_line_e);
|
|
print " cmd_line_f: $cmd_line_f\n" if ($cmd_line_f);
|
|
print " cmd_line_g: $cmd_line_g\n" if ($cmd_line_g);
|
|
print " cmd_line_h: $cmd_line_h\n" if ($cmd_line_h);
|
|
print " cmd_line_i: $cmd_line_i\n" if ($cmd_line_i);
|
|
print " cmd_line_j: $cmd_line_j\n" if ($cmd_line_j);
|
|
print " cmd_line_k: $cmd_line_k\n" if ($cmd_line_k);
|
|
print "\n";
|
|
}
|
|
if ($CLOhelp) {
|
|
print "allowed run time options:\n";
|
|
print " [--help] = this help screen\n";
|
|
print " [--SYSLOG] = whether to log actions or not\n";
|
|
print "required flags:\n";
|
|
print " [--PATHlogs] = logs directory path\n";
|
|
print " [--telnet_host] = IP address to connect to Asterisk Manager\n";
|
|
print " [--telnet_port] = port to connect to Asterisk Manager\n";
|
|
print " [--ASTmgrUSERNAME] = username for Asterisk Manager login\n";
|
|
print " [--ASTmgrSECRET] = secret or password for Asterisk Manager login\n";
|
|
print " [--ASTmgrUSERNAMEsend] = username specific for sending actions for Asterisk Manager login\n";
|
|
print " [--man_id] = ID of the action in the vicidial_manager table\n";
|
|
print " [--action] = type of manager action to send\n";
|
|
print " [--cmd_line_X] = lines to send to Manager after action\n";
|
|
print " X replaced with b-k (10 lines)\n";
|
|
print "\n";
|
|
print "You may prefix an option with 'no' to disable it.\n";
|
|
print " ie. --noSYSLOG or --noFULLLOG\n";
|
|
|
|
exit 0;
|
|
}
|
|
}
|
|
|
|
if ($action) {
|
|
$PATHlogs =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_b =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_c =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_d =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_e =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_f =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_g =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_h =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_i =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_j =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
$cmd_line_k =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
|
|
if ($DB) {
|
|
print " SYSLOG: $SYSLOG\n" if ($SYSLOG);
|
|
print " telnet_host: $telnet_host\n" if ($telnet_host);
|
|
print " telnet_port: $telnet_port\n" if ($telnet_port);
|
|
print " ASTmgrUSERNAME: $ASTmgrUSERNAME\n" if ($ASTmgrUSERNAME);
|
|
print " ASTmgrSECRET: $ASTmgrSECRET\n" if ($ASTmgrSECRET);
|
|
print " ASTmgrUSERNAMEsend: $ASTmgrUSERNAMEsend\n" if ($ASTmgrUSERNAMEsend);
|
|
print " man_id: $man_id\n" if ($man_id);
|
|
print " cmd_line_b: $cmd_line_b\n" if ($cmd_line_b);
|
|
print " cmd_line_c: $cmd_line_c\n" if ($cmd_line_c);
|
|
print " cmd_line_d: $cmd_line_d\n" if ($cmd_line_d);
|
|
print " cmd_line_e: $cmd_line_e\n" if ($cmd_line_e);
|
|
print " cmd_line_f: $cmd_line_f\n" if ($cmd_line_f);
|
|
print " cmd_line_g: $cmd_line_g\n" if ($cmd_line_g);
|
|
print " cmd_line_h: $cmd_line_h\n" if ($cmd_line_h);
|
|
print " cmd_line_i: $cmd_line_i\n" if ($cmd_line_i);
|
|
print " cmd_line_j: $cmd_line_j\n" if ($cmd_line_j);
|
|
print " cmd_line_k: $cmd_line_k\n" if ($cmd_line_k);
|
|
}
|
|
|
|
$telnet_port = '5038' if (!$telnet_port);
|
|
|
|
### connect to asterisk manager through telnet
|
|
my $tn = new Net::Telnet (Port => $telnet_port,
|
|
Prompt => '/\r\n/',
|
|
Output_record_separator => '',
|
|
Errmode => "return");
|
|
|
|
##### uncomment both lines below for telnet log
|
|
# $LItelnetlog = "$PATHlogs/send_child_telnet_log.txt";
|
|
# $fh = $tn->dump_log("$LItelnetlog");
|
|
|
|
if (length($ASTmgrUSERNAMEsend) > 3) {$telnet_login = $ASTmgrUSERNAMEsend;}
|
|
else {$telnet_login = $ASTmgrUSERNAME;}
|
|
$tn->open("$telnet_host");
|
|
$tn->waitfor('/Asterisk Call Manager\//');
|
|
|
|
# get the AMI version number
|
|
$ami_version = $tn->getline(Errmode => Return, Timeout => 1,);
|
|
$ami_version =~ s/\n//gi;
|
|
if ($DB) {print "----- AMI Version $ami_version -----\n";}
|
|
|
|
# Login
|
|
$tn->print("Action: Login\nUsername: $telnet_login\nSecret: $ASTmgrSECRET\n\n");
|
|
$tn->waitfor('/Authentication accepted/'); # waitfor auth accepted
|
|
|
|
$tn->buffer_empty;
|
|
|
|
if ($cmd_line_b =~ /XXYYXXYYXXYYXX/) {
|
|
# Action: Command
|
|
# Command: meetme list 8600051
|
|
#
|
|
# Response: Follows
|
|
# Privilege: Command
|
|
# User #: 03 261 261iax Channel: IAX2/261iax-13 (unmonitored)
|
|
# 1 users in that conference.
|
|
# --END COMMAND--
|
|
my $meetme_command = "Action: Command\nCommand: meetme list $cmd_line_k\n\n";
|
|
print nowDate() . "|$SYSLOG|\n$meetme_command";
|
|
|
|
my $participant;
|
|
my @list_meetme = $tn->cmd(String => $meetme_command,
|
|
Prompt => '/--END COMMAND-.*/');
|
|
foreach my $meetme (@list_meetme) {
|
|
if ($meetme =~ /$cmd_line_j /i) {
|
|
$meetme =~ s/User \#: //gi;
|
|
my @participants = split(/ /, $meetme);
|
|
$participant = ($participants[0] + 0);
|
|
}
|
|
# print "$participant|$cmd_line_j|$meetme";
|
|
}
|
|
$cmd_line_b =~ s/XXYYXXYYXXYYXX/$participant/gi if ($participant > 0);
|
|
$cmd_line_j = '';
|
|
$cmd_line_k = '';
|
|
}
|
|
|
|
my $originate_command;
|
|
$originate_command .= "Action: $action\n";
|
|
#if (length($cmd_line_b)>3) {$originate_command .= "$cmd_line_b\n";}
|
|
$originate_command .= $cmd_line_b . "\n" if ($cmd_line_b);
|
|
$originate_command .= $cmd_line_c . "\n" if ($cmd_line_c);
|
|
$originate_command .= $cmd_line_d . "\n" if ($cmd_line_d);
|
|
$originate_command .= $cmd_line_e . "\n" if ($cmd_line_e);
|
|
$originate_command .= $cmd_line_f . "\n" if ($cmd_line_f);
|
|
$originate_command .= $cmd_line_g . "\n" if ($cmd_line_g);
|
|
$originate_command .= $cmd_line_h . "\n" if ($cmd_line_h);
|
|
$originate_command .= $cmd_line_i . "\n" if ($cmd_line_i);
|
|
$originate_command .= $cmd_line_j . "\n" if ($cmd_line_j);
|
|
$originate_command .= $cmd_line_k . "\n" if ($cmd_line_k);
|
|
$originate_command .= "\n";
|
|
|
|
|
|
print nowDate() . "|$SYSLOG|$man_id|\n$originate_command";
|
|
my $event_string = $man_id . "|0|" . $SYSLOG . "|";
|
|
$event_string .= "\n" . $originate_command;
|
|
|
|
eventLogger($PATHlogs,'full',$event_string) if ($FULL_LOG and $SYSLOG);
|
|
|
|
my @list_channels = $tn->cmd(String => $originate_command,
|
|
Prompt => '/.*/');
|
|
|
|
$tn->waitfor(Match => '/Response:.*\n/', Timeout => 10);
|
|
$tn->waitfor(Match => '/Message:.*\n\n/', Timeout => 10);
|
|
|
|
my $data1; # ? Useless ?
|
|
if ($FULL_LOG and $SYSLOG) {
|
|
my $event_string = $man_id . "|1|" . $data1 . "|";
|
|
foreach my $channel (@list_channels) {
|
|
$event_string .= $channel;
|
|
}
|
|
my $read_input_buf = $tn->get(Errmode => "return",
|
|
Timeout => 1);
|
|
$event_string .= $read_input_buf;
|
|
eventLogger($PATHlogs,'full',$event_string);
|
|
}
|
|
|
|
$tn->buffer_empty;
|
|
#@hangup = $tn->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/");
|
|
$tn->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/");
|
|
$tn->buffer_empty;
|
|
|
|
$tn->waitfor(Match => '/Message:.*\n\n/', Timeout => 15);
|
|
|
|
if ($FULL_LOG and $SYSLOG) {
|
|
my $event_string = $man_id . "|2|" . $data1 . "|";
|
|
foreach my $channel (@list_channels) {
|
|
$event_string .= $channel;
|
|
}
|
|
my $read_input_buf = $tn->get(Errmode => "return",
|
|
Timeout => 1);
|
|
$event_string .= $read_input_buf;
|
|
eventLogger($PATHlogs,'full',$event_string);
|
|
}
|
|
|
|
$tn->buffer_empty;
|
|
$tn->close;
|
|
}
|
|
|
|
my $secZ = time();
|
|
my $script_time = ($secZ - $secX);
|
|
if ($DB) {print "DONE execute time: $script_time seconds\n";}
|
|
|
|
exit 0;
|
|
# Program ends.
|
|
|
|
|
|
### Start of subs.
|
|
|
|
# eventLogger usage:
|
|
# eventLgger($LogFileDir, $LogType, $EventString);
|
|
# Requires:
|
|
# $LogFilePath : Directory where log files are.
|
|
# $LogType : Type of log, ie process, send, launch, full
|
|
# $EventString : String to record in log.
|
|
sub eventLogger {
|
|
my ($path,$type,$string) = @_;
|
|
open(LOG, ">>" . $path . "/action_" . $type . "." . logDate())
|
|
|| die "Can't open " . $path . "/action_" . $type . "." .
|
|
logDate() . ": " . $! . "\n";
|
|
print LOG nowDate() . "|" . $string . "|\n";
|
|
close(LOG);
|
|
}
|
|
|
|
# getTime usage:
|
|
# getTime($SecondsSinceEpoch);
|
|
# Options:
|
|
# $SecondsSinceEpoch : Request time in seconds, defaults to current date/time.
|
|
# Returns:
|
|
# ($sec, $min, $hour. $day, $mon, $year)
|
|
sub getTime {
|
|
my ($tms) = @_;
|
|
$tms = time unless ($tms);
|
|
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($tms);
|
|
$year += 1900;
|
|
$mon++;
|
|
$mon = "0" . $mon if ($mon < 10);
|
|
$mday = "0" . $mday if ($mday < 10);
|
|
$min = "0" . $min if ($min < 10);
|
|
$sec = "0" . $sec if ($sec < 10);
|
|
return ($sec,$min,$hour,$mday,$mon,$year);
|
|
}
|
|
|
|
# nowDate usage:
|
|
# nowDate($SecondsSinceEpoch);
|
|
# Options:
|
|
# $SecondsSinceEpoch : Request time in seconds, defaults to current date/time.
|
|
# Returns:
|
|
# scalar date/time string (MySQL formatted) ie "2007-01-01 00:00:00"
|
|
sub nowDate {
|
|
my ($tms) = @_;
|
|
my($sec,$min,$hour,$mday,$mon,$year) = getTime($tms);
|
|
return $year.'-'.$mon.'-'.$mday.' '.$hour.':'.$min.':'.$sec;
|
|
}
|
|
|
|
# logDate usage:
|
|
# logDate($SecondsSinceEpoch);
|
|
# Options:
|
|
# $SecondsSinceEpoch : Request time in seconds, defaults to current date/time.
|
|
# Returns:
|
|
# scalar date string ie "2007-01-01"
|
|
sub logDate {
|
|
my ($tms) = @_;
|
|
my($sec,$min,$hour,$mday,$mon,$year) = getTime($tms);
|
|
return $year . '-' . $mon . '-' . $mday;
|
|
}
|
|
|
|
### End of subs
|
|
|
|
|