#!/usr/bin/perl -w
# getdial.pl
# Copyright (C) 2006 Bernardo Vieira bernardo.vieira@terra.com.br
#
# Script para iniciar uma chamda no Asterisk através de uma 
# URL. Recebe parâmetros atraves do metodo get, permitindo 
# que seja utilizado em uma tag <a href...>Discar</a>.
#
# Baseado no script TACI - Trivial Asterisk Call Interface v.02
# de Tony Wasson wasson@azxws.com
#
# Certifique-se que ha um handler para extensões inválidas no
# contexto [default] do extensions.conf:
#       exten => s,1,Playback(invalid)
use Net::Telnet ();
use Net::Netmask();
use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);

#
# Configuracoes:
#

$managerHost='127.0.0.1';		# endereco do servidor rodando o Asterisk
$managerPort=5038;			# porta da interface de gerenciamento do Asterisk

$managerUser='ususario';		# nome do usuario manager do Asterisk

# TODO: proteger esta senha
$managerSecret='senha';			# senha do manager

$defaultContext='from-internal'; 	# contexto padrao para a ligacao, pode ser especificado
					# na query string, senao este valor e utilizado

$defaultCID='callerid';			# Caller Id padrao pode ser especificado na query string

@allowedNetworks= ('192.168.1.0/24');	# lista de redes (clientes) que podem usar este script	

@allwedReferers=('http://192.168.1.1/teste/teste.html'); # lista de paginas que podem usar este script


#
# Prototipos
#
sub isInNetwork;
sub testIp;
sub testReferer;

# verifica se o cliente esta na lista de clientes autorizados
&testReferer($ENV{HTTP_REFERER},@allwedReferers) or die "Pagina nao autorizada a user este script: ", $ENV{HTTP_REFERER};
&testIp($ENV{REMOTE_ADDR},@allowedNetworks) or die "Cliente nao autorizado a usar este script: ", $ENV{REMOTE_ADDR};

#
# Parametros
#
my $phonetype = param('type') ||  "" ;
my $account = param('account') || "";
my $callerid = param('callerid') || $defaultCID;
my $context = param('context') || $defaultContext;
my $exten = param('exten') || "";
my $callid = param('callid') || 0;


# Limpar parametros
if ($exten)   {$exten =~   s/([^A-Z0-9a-z\/@\.])//g;}
else {$exten="";}

if ($context) {$context =~   s/([^A-Z0-9a-z\-])//g;}
else {$context="";}

if ($account) {$account =~  s/([^A-Z0-9a-z])//g;}
else {$account="";}

# Testa se a extensao e valida (mais de dois digitos)
# TODO: melhorar o teste

if (not $exten =~ /[0-9][0-9]/) { die "Destino invalido, deve conter pelo menos 2 numeros!"; };

#print header;

# Abre a conexao ao asterisk...
$tn = new Net::Telnet (	Port => $managerPort,
			Prompt => '/.*[\$%#>] $/',
			Output_record_separator => '',
			Errmode    => 'return'
			);

$tn->open("$managerHost");
$tn->waitfor('/0\n$/');                  	
$tn->print("ACTION: LOGIN\nUSERNAME: $managerUser\nSECRET: $managerSecret\n\n");
$tn->waitfor('/Authentication accept*/')
    or die "Nao foi possivel conectar ao asterisk: ", $tn->lastline;

# Abre a chamada
$tn->print("ACTION: ORIGINATE\nExten: $exten\nContext: $context\nChannel: $phonetype/$account\nPriority: 1\nCallerid: $callerid\n\n");
$tn->waitfor('/Event: Newchannel.*/') or die "Nao foi possivel deteminar o status da chamada: ", $tn>lastline;
$tn->print("Action: LOGOFF\n\n");

# Chamada aceita
# TODO: monitorar melhor a ligacao, mesmo que o numero for invalido o programa chega aqui.
print "Location:  $ENV{HTTP_REFERER}?callid=$callid&status=0\n\n";
exit 0;



sub isInNetwork {
	my ($cidr,$ipaddress) = @_;
	local $network = new Net::Netmask($cidr);
	return $network->match($ipaddress);
}

sub testIp {
	my($ip,@allowedNetworks) = @_;
	my($matchFound) = 0;
	foreach my $network (@allowedNetworks) {
	    $matchFound = isInNetwork($network,$ip);
	    if ($matchFound) {
		last;
            }
	}
	return $matchFound;
}

sub testReferer{
	my($referer,@allowedReferers) = @_;
	return scalar(grep(/$referrer/,@allowedReferers));
}