FreePBX. Configuración de Asterisk para notificaciones por correo electrónico sobre llamadas entrantes perdidas en la cola

FreePBX. Configuración de Asterisk para notificaciones por correo electrónico sobre llamadas entrantes perdidas en la cola
IP ATC Asterisk es un potente sistema en el ámbito de la telefonía IP. La interfaz web FreePBX, diseñada para Asterisk, simplifica enormemente la configuración y reduce la barrera de entrada al sistema.
Si puedes imaginar alguna tarea relacionada con la telefonía IP, casi seguramente se puede implementar en Asterisk. Pero asegúrate de que se requerirá perseverancia y paciencia de tu parte.

Se nos presentó la tarea de configurar notificaciones por correo electrónico sobre llamadas perdidas. Más concretamente, notificar por correo electrónico en aquellos casos en que una llamada entrante pasara a la cola, pero nadie (de los agentes) respondiera a esa llamada entrante.

Sorprendentemente, no encontramos medios estándar para resolver esta tarea en FreePBX. Cómo resolvimos esta tarea lo contaré a continuación.

Prólogo

Antes de abordar la tarea directamente, por supuesto, buscamos información en Internet, pero no encontramos una solución lista para usar (quizás no buscáramos lo suficiente, pero así es…).

No hay muchas habilidades para trabajar directamente en Asterisk, como nos gustaría, por lo que la solución propuesta aquí, no se pensó completamente y fue descartada.

Nos gustó la solución propuesta por aquí, aunque no funcionó. De aquí se destacó que se debe trabajar en Asterisk en el contexto de las colas [ext-queues]. Y dado que trabajamos en FreePBX, es necesario trabajar en el archivo de configuración "extensions_override_freepbx.conf". Se destacó que "capturar llamadas perdidas" es conveniente antes del evento hangupcall (fin de la llamada).
Al leer la discusión aquí, surgió la idea de que era necesario filtrar en CDR la variable "Disposition" por todos los agentes en la cola. Después de leer esta la información, se formaron pasos bastante concretos para resolver la tarea planteada.

Lo que tenemos:

Tenemos FreePBX 13.0.197, que utiliza Asterisk 13.12.1. La versión del SO es SHMZ release 6.6 (Final). La distribución se basa en CentOS.

En Asterisk se ha configurado un IVR (menú de voz) que distribuye las llamadas entrantes a diferentes colas. A cada cola se le han asignado agentes, es decir, operadores.

Teoría

Lo que sucede en Asterisk

Cuando Asterisk recibe una llamada entrante, esta llamada pasa al IVR. El llamante hace una selección presionando un número específico en el teléfono y entra en una cola específica. Después de eso, todos los agentes libres de la cola reciben simultáneamente la llamada.

Para entender mejor lo que sucede en ese momento y qué sucede después, consultemos el Reporte CDR (Fig. 1).

FreePBX. Configuración de Asterisk para notificaciones por correo electrónico sobre llamadas entrantes perdidas en la cola
Fig. 1

Cuando una llamada entrante entra en la cola, el valor de la variable «Disposition» de todos los agentes se establece en «NO ANSWER», si los agentes no estaban ocupados en ese momento. La variable «Disposition» también puede tener otros valores (ver https://asterisk-pbx.ru/wiki/asterisk/cf/cdr), excepto el valor «ANSWERED». En el momento en que uno de los agentes responde a la llamada entrante, el valor de la variable «Disposition» de ese agente se convierte en «ANSWERED».
En el Report CDR se puede observar que cuando la llamada entra en la cola (en la columna App el valor se convierte en «Queue»), todos los eventos aparecen con el mismo «uniqueid» (columna System).

Breve sobre CDR

Es importante entender qué es CDR y en qué momento se registran los datos que observamos en el Report CDR. CDR, en relación con el sistema operativo, es una base de datos en la que Asterisk registra un informe detallado de las llamadas (ver https://asterisk-pbx.ru/wiki/asterisk/cf/cdr). En nuestro caso, esta base de datos se llama asteriskcdrdb y se encuentra en mysql. A través de la experiencia, hemos comprobado que los datos de la llamada con un «uniqueid» específico no se registran en asteriskcdrdb inmediatamente después de que ocurre algún evento, sino después del evento hangupcall (finalización de la llamada).

Principio de funcionamiento de la solución creada

Dado que tenemos más conocimientos en bash que en Asterisk, la idea principal resultó ser la siguiente. Antes del evento hangupcall, se debe llamar a un script de bash. A este script se le deben pasar 3 parámetros. El primer parámetro es «uniqueid», para filtrar los datos obtenidos de CDR. El segundo parámetro es «CALLERID(num)» (número del que llama), para saber a quién devolver la llamada. El tercer parámetro es «NODEST» (número de la cola), en la que se recibió la llamada, para saber sobre qué asunto fue la llamada y a quién enviar una notificación por correo electrónico sobre la llamada perdida.
El script de bash debe conectarse a la base de datos asteriskcdrdb en mysql y obtener todos los valores de la variable «Disposition» con un «uniqueid» específico. De los datos obtenidos, deben excluirse los valores: «NO ANSWER», «BUSY», «FAILED», «UNKNOWN». Como resultado, quedarán ya sea «ANSWERED» — la llamada entrante fue respondida, o nada en absoluto — llamada perdida.

A continuación, si la llamada resultó ser perdida, el script debe enviar una notificación por correo electrónico.
Asterisco ejecuta los comandos secuencialmente, esperando a que se completen (lo cual tiene mucho sentido). Llamaremos al script bash antes de que se ejecute el comando hangupcall. Así, en el momento exacto de la ejecución del script, la información sobre el «uniqueid» que buscamos aún no se habrá agregado al CDR. Para solucionar este problema, llamaremos al script bash con el parámetro «&», para que Asterisco pase inmediatamente a ejecutar el siguiente paso, es decir, hangupcall. Y dentro del script bash, al principio, estableceremos un pequeño retraso, para dar tiempo a que Asterisco registre los datos del «uniqueid» que nos interesa en el CDR.

Práctica

Antes de configurar Asterisco y crear el script bash, necesitamos configurar el envío de notificaciones por e-mail. Para esto utilizaremos la utilidad postfix.

Configuración de postfix

Tenemos un dominio de correo «lucky.ru», alojado en Yandex. Configuraremos postfix en modo cliente SMTP y estaremos enviando correos desde la cuenta asterisk@lucky.ru.
Se tomó como base la solución de aquí: https://www.dmosk.ru/miniinstruktions.php?mini=postfix-over-yandex.

Primero instalaremos/actualizaremos/verificaremos la disponibilidad de los paquetes:

yum install postfix
yum install mailx
yum install cyrus-sasl cyrus-sasl-lib cyrus-sasl-plain

No vamos a sobrescribir el archivo de configuración principal de postfix «/etc/postfix/main.cf», sino que crearemos una copia de seguridad:

cp /etc/postfix/main.cf /etc/postfix/main.cf.sav

Editamos el archivo «/etc/postfix/main.cf» y lo llevamos al siguiente formato:

nano /etc/postfix/main.cf
#####################
relayhost =
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/private/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_type = cyrus
smtp_sasl_mechanism_filter = login
smtp_sender_dependent_authentication = yes
sender_dependent_relayhost_maps = hash:/etc/postfix/private/sender_relay
smtp_generic_maps = hash:/etc/postfix/generic
smtp_tls_CAfile = /etc/postfix/ca.pem
smtp_use_tls = yes
smtputf8_autodetect_classes = all
#####################

No cada línea de «/etc/postfix/main.cf» se puede comentar. Los comentarios en algunas líneas no son identificados por el parser y se envían a procesamiento, lo que lleva a errores. Es mejor prescindir de los comentarios dentro de este archivo. Puedes experimentar con esto ejecutando en la ventana adyacente «tail -f /var/log/messages».

Destacaré la línea «smtputf8_autodetect_classes = all». Esta entrada habilita utf-8 por defecto, lo que permite el uso de caracteres cirílicos tanto en el cuerpo del correo como en el asunto sin manipulaciones adicionales (Ver. http://www.postfix.org/SMTPUTF8_README.html).

Crearemos un directorio para los archivos de configuración:

mkdir /etc/postfix/private

Editamos el archivo «/etc/postfix/private/sender_relay». En él debemos especificar a qué servidor smtp referirnos al utilizar nuestro dominio de correo:

nano /etc/postfix/private/sender_relay
#####################
@lucky.ru smtp.yandex.ru
#####################

Editamos el archivo «/etc/postfix/private/sasl_passwd». En él especificaremos la dirección de correo electrónico que utilizaremos para enviar mensajes, así como el nombre de usuario y la contraseña de esta cuenta (especificamos el nombre de usuario y la contraseña a través de dos puntos):

nano /etc/postfix/private/sasl_passwd
#####################
asterisk@lucky.ru asterisk@lucky.ru:password_asterisk
#####################

Editamos el archivo «/etc/postfix/generic». En él estableceremos las reglas para reemplazar la dirección de origen (ver: https://wiki.merionet.ru/ip-telephoniya/30/postfix-nastrojka-otpravki-pochty-v-asterisk/):

nano /etc/postfix/generic
#####################
root asterisk@lucky.ru
root@localhost asterisk@lucky.ru
root@localhost.localdomain asterisk@lucky.ru
root@freepbx asterisk@lucky.ru
root@freepbx.localdomain asterisk@lucky.ru
root@asterisk asterisk@lucky.ru
root@asterisk.localdomain asterisk@lucky.ru
asterisk asterisk@lucky.ru
asterisk@localhost asterisk@lucky.ru
asterisk@localhost.localdomain asterisk@lucky.ru
asterisk@freepbx asterisk@lucky.ru
asterisk@freepbx.localdomain asterisk@lucky.ru
asterisk@asterisk asterisk@lucky.ru
asterisk@asterisk.localdomain asterisk@lucky.ru
root@localdomain.localdomain asterisk@lucky.ru
#####################

La dirección de envío original depende del contenido de «/etc/hosts» y «/etc/hostname», así como del nombre de usuario que enviará el mensaje. Es decir, aunque utilicemos un cliente smtp y enviemos correos desde asterisk@lucky.ru, postfix inicialmente reemplazará la dirección del remitente con «algo propio» y esto necesita ser corregido con las reglas de este archivo de configuración.

Aquí está el contenido de mi archivo «/etc/hosts»:

cat /etc/hosts
#####################
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 asterisk.localdomain
127.0.0.1 localhost.localdomain localhost
::1 asterisk localhost localhost6
#####################

Es importante que el servidor tenga algún dominio (el valor después del punto), porque la herramienta mail "busca" el nombre del dominio en "etc/hosts" y si no lo "encuentra" de inmediato, seguirá buscándolo durante algunos minutos y solo luego enviará el mensaje. Es decir, si el dominio no está configurado, el mensaje se enviará con un retraso de varios minutos.

Aquí está el contenido de mi archivo «/etc/hostname»:

cat /etc/hostname
#####################
asterisk
#####################

A continuación, es necesario transformar los archivos de configuración creados en bases de datos indexadas, para ello ejecutaremos el siguiente comando:

postmap /etc/postfix/generic && postmap /etc/postfix/private/{sasl_passwd,sender_relay}

Luego debemos descargar y colocar en el servidor el certificado smtp.yandex.ru, para ello ejecutaremos el siguiente comando:

openssl s_client -starttls smtp -crlf -connect smtp.yandex.ru:25 > /etc/postfix/ca.pem

Pero después de que la información técnica aparezca en la pantalla, el equipo seguirá "congelado". Presione Ctrl+C para interrumpirlo.

Ahora eliminaremos manualmente de el archivo resultante todo el desecho y dejaremos solo el certificado. Debería parecer algo así:

nano /etc/postfix/ca.pem
#####################
-----BEGIN CERTIFICATE-----
MIIGazCCBVOgAwIBAgIQcUU9mJXW4OUs5Gf0JfLtsjANBgkqhkiG9w0BAQsFADBf
...
nRG0DfdqYIuPGApFORYe
-----END CERTIFICATE-----
#####################

Y finalmente reiniciaremos postfix:

service postfix restart

Enviamos un correo electrónico de prueba:

echo "Este es el cuerpo del correo" | mail -s "Este es el asunto" admin@lucky.ru

admin@lucky.ru — dirección de destino

Así termina la configuración de postfix.

Escribimos un script bash

Creamos un directorio para almacenar el script bash (donde más les guste):

mkdir /home/asterisk/scripts

Creamos el archivo del script bash:

touch /home/asterisk/scripts/noanswer.sh

Otorgamos permisos de ejecución al archivo del script:

chmod +x /home/asterisk/scripts/noanswer.sh

Si hay dudas sobre los permisos del archivo, se puede otorgar acceso total al archivo temporalmente para depuración. Pero esto "no es seguro".

chmod 777 /home/asterisk/scripts/noanswer.sh

Texto del script bash:

nano /home/asterisk/scripts/noanswer.sh
#####################
#! /bin /bash

sleep 7

res_sql="SELECT disposition FROM cdr WHERE uniqueid = '$1'"

answer=`mysql -u freepbxuser -pPassword_freepbxuser -D asteriskcdrdb -B -N -e "$res_sql" | grep -E -v "NO ANSWER|BUSY|FAILED|UNKNOWN" | head -n 1`

error_kod=0
if [ "$answer" != "ANSWERED" ]
then

 case $3 in
 68800)
 address="big_boss@lucky.ru"
 subject="sobre un asunto importante"
 ;;
 63100)
 address="debian@lucky.ru"
 subject="sobre cuestiones de linux debian"
 ;;
 63200)
 address="windows@lucky.ru"
 subject="sobre cuestiones de windows"
 ;;
 63300)
 address="freebsd@lucky.ru"
 subject="sobre cuestiones de freebsd"
 ;;
 63400)
 address="ubuntu@lucky.ru"
 subject="sobre cuestiones de linux ubuntu"
 ;;
 63500)
 address="centos@lucky.ru"
 subject="sobre cuestiones de linux centos"
 ;;
 *)
 address="admin@lucky.ru"
 error_kod=1
 ;;
 esac

 case $error_kod in
 0)
 echo "Llamada perdida del abonado $2, que llamaba $subject." | mail -s "Llamada perdida de $2" $address
 echo "Llamada perdida para $address de abonado $2, que llamaba $subject. uid=$1" | mail -s "Llamada perdida de $2" admin@lucky.ru
 ;;
 1)
 echo "Llamada perdida de $2. Cola desconocida. uid=$1" | mail -s "Llamada perdida de $2" admin@lucky.ru
 ;;
 esac

fi
#####################

Análisis breve del script:
«sleep 7»:

Esta es la misma demora de tiempo de la que hablé anteriormente. Hemos establecido una espera de 7 segundos. Aunque creo que con un segundo es suficiente.

«res_sql="SELECT disposition FROM cdr WHERE uniqueid = '$1'"»:

Hemos trasladado la consulta en mysql a una variable separada para mayor comodidad.

A continuación, hacemos una consulta en mysql y filtramos la salida obtenida. Eliminamos todas las opciones excepto «ANSWERED», si es que existe. Si hay múltiples valores «ANSWERED», entonces solo debemos conservar uno. Al final, en la variable «answer» obtendremos ya sea «ANSWERED» o «».
Si el valor de la variable «answer» no es igual a «ANSWERED», se trata de una llamada perdida. Dependiendo del número de la cola, usaremos el operador case para establecer la dirección a la que se debe enviar la notificación por correo electrónico y qué escribir en ese mensaje (parte modificable del mensaje).

A continuación, se presenta el caso en el que la cola está definida en Asterisk, pero no está descrita en el script. En este caso, admin@lucky.ru recibirá un correo informando que la cola no es conocida por el script.

Sin embargo, si la cola está descrita, se enviará un correo al destino y un correo duplicado a admin@lucky.ru indicando el «uniqueid», para poder rastrear los eventos de esta llamada en caso de ser necesario.

Así concluye el script.

Debo señalar que para conectarnos a mysql utilizamos un nombre de usuario y una contraseña que averiguamos de antemano. En FreePBX, para descubrir el nombre de usuario de Asterisk en mysql, ejecuta el siguiente comando:

cat /etc/amportal.conf | grep AMPDBUSER

Y para saber la contraseña del usuario Asterisk en mysql, ejecuta el siguiente comando:

cat /etc/amportal.conf | grep AMPDBPASS

Configuración de Asterisk

Utilizamos FreePBX. En FreePBX hay diferentes tipos de archivos de configuración (ver. https://asterisk-pbx.ru/wiki/freepbx/files), algunos de estos archivos son sobrescritos por FreePBX al reiniciarse, mientras que otros no (se les llama custom), ya que están destinados específicamente al usuario.

Trabajaremos con el archivo de configuración «extensions_override_freepbx.conf», ya que pertenece al tipo custom.

Para empezar, asegúrate de que el archivo «/etc/asterisk/extensions.conf» esté conectado al archivo «extensions_override_freepbx.conf». Para ello, ejecuta el siguiente comando:

cat /etc/asterisk/extensions.conf | grep extensions_override_freepbx.conf
#####################
#include extensions_override_freepbx.conf
#####################

Editamos el archivo «/etc/asterisk/extensions_override_freepbx.conf» y lo modificamos de la siguiente manera:

nano /etc/asterisk/extensions_override_freepbx.conf
#####################
[ext-queues]

exten => h,1,System(/home/asterisk/scripts/noanswer.sh ${CDR(uniqueid)} ${CALLERID(num)} ${NODEST} &)
exten => h,2,Macro(hangupcall,)
#####################

Como mencioné anteriormente, el símbolo «&» al final es obligatorio. Dado que vamos a trabajar en un script bash con datos CDR directamente desde la base de datos mysql, y estos datos se ingresan en mysql solo después de ejecutar «exten => h,2,Macro(hangupcall,)», no debemos esperar a que el script bash termine, sino que debemos proceder a la siguiente etapa en Asterisk. Además, el script bash debe contener una demora antes de ejecutar su parte principal.

Para que los cambios en el archivo de configuración «/etc/asterisk/extensions_override_freepbx.conf» surtan efecto, es necesario reiniciar el núcleo de Asterisk con el siguiente comando:

/usr/sbin/asterisk -rx "core restart now"

Esto debe hacerse después de que se haya creado el script bash.

Conclusión

Probablemente, este es el método 1001 para «captar llamadas perdidas» en Asterisk. Compartan en los comentarios cómo resuelven esta tarea. Y qué, en su opinión, se puede mejorar/reformular/optimizar. Agradeceremos las ideas constructivas.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster