FreePBX. Konfigurimi i Asterisk për njoftime me e-mail për thirrjet e humbura të pranuara në radhë

FreePBX. Konfigurimi i Asterisk për njoftime me e-mail për thirrjet e humbura të pranuara në radhë
IP ATC Asterisk — это мощный комбайн в области IP-телефонии. А web-интерфейс FreePBX, созданный для Asterisk, значительно упрощает настройку и снижает порог вхождения в систему.
Если вы можете придумать какую-либо задачу, связанную с IP-телефонией, то почти наверняка это можно реализовать в Asterisk. Но будьте уверены, что от вас потребуется упорство и выдержка.

Перед нами встала задача настроить e-mail уведомления о пропущенных вызовах. Точнее говоря, оповещать через e-mail о тех случаях, когда входящий вызов перешёл в очередь, но никто (из агентов) так и не ответил на этот входящий вызов.

На удивление мы не обнаружили штатных средств для решения этой задачи во FreePBX. О том, как мы решили эту задачу, расскажу под катом.

Parathënie

Перед решением задачи «в лоб» мы конечно поискали информацию в интернете, но решения под ключ не нашли (возможно плохо искали, но что поделаешь… ).

Навыков работы непосредственно в Asterisk не так много, как хотелось бы, поэтому решение, предлагаемое këtu, не было до конца осмыслено и было отброшено.

Понравилось решение, предложенное këtu, хоть оно и не заработало. Отсюда подчеркнули, что работать в Asterisk нужно в контексте очередей [ext-queues]. И так как мы работаем во Freepbx, то работать нужно в файле конфигурации «extensions_override_freepbx.conf». Обратили внимание на то, что «ловить пропущенные вызовы» удобно перед событием hangupcall (окончание вызова).
Прочитав обсуждение këtu, появилась идея о том, что нужно фильтровать в CDR переменную «Disposition» по всем агентам в очереди. А после прочтения këtë информации сформировались вполне конкретные шаги по решению поставленной задачи.

Что у нас есть:

Есть FreePBX 13.0.197, который использует Asterisk 13.12.1. Версия ОС SHMZ release 6.6 (Final). Дистрибутив базируется на CentOS.

В Asterisk настроен IVR (голосовое меню) раскидывающий входящие вызовы на разные Queues (очереди). Каждой очереди назначены Agents (агенты), т. е. операторы.

Teoria

Что происходит в Asterisk

Когда на Asterisk поступает входящий вызов, этот вызов попадает на IVR. Звонящий делает выбор, нажав определенную цифру на телефоне, и попадает в определенную очередь. После этого всем свободным агентам очереди одновременно поступает звонок.

Для того чтобы лучше понять, что происходит в этот момент и что происходит дальше, обратимся к Report CDR (Рис.1).

FreePBX. Konfigurimi i Asterisk për njoftime me e-mail për thirrjet e humbura të pranuara në radhë
Рис.1

Когда входящий вызов попал в очередь, у всех агентов значение переменной «Disposition» стало равным «NO ANSWER», если агенты в этот момент были не заняты. Переменная «Disposition» могла принять и другие значения (см. https://asterisk-pbx.ru/wiki/asterisk/cf/cdr), кроме значения «ANSWERED». А в тот момент, когда один из агентов отвечает на входящий вызов, значение переменной «Disposition» этого агента становится равной «ANSWERED».
Из Report CDR можно заметить, что когда вызов перешел в очередь (в колонке App значение становится равным «Queue»), то все события фигурируют с одинаковым «uniqueid» (колонка System).

Коротко о CDR

Важно понимать что такое CDR, и в какой именно момент в CDR заносятся данные, которые мы наблюдаем в Report CDR. CDR, относительно операционной системы — это база данных, в которую Asterisk записывает детализированный отчет вызовов (см. https://asterisk-pbx.ru/wiki/asterisk/cf/cdr). В нашем случае это база под именем asteriskcdrdb, которая находится в mysql. Опытным путем мы установили, что данные о вызове с определенным «uniqueid» заносятся в asteriskcdrdb не сразу после возникновения какого-либо события, а после события hangupcall (окончание вызова).

Принцип работы созданного решения

Так как у нас познаний в bash больше, чем познаний в Asterisk, то основная идея получилась следующей. Перед событием hangupcall вызвать bash-скрипт. В этот скрипт передать 3 параметра. Первый параметр «uniqueid», для фильтрации данных, получаемых из CDR. Второй параметр «CALLERID(num)» (номер звонившего), чтобы знать кому перезвонить. Третий параметр «NODEST» (номер очереди), в которую поступил звонок, для того, чтобы знать по какому вопросу был звонок, и кому отправить e-mail уведомление о пропущенном вызове.
Bash-скрипт должен подключиться к базе asteriskcdrdb в mysql и взять все значения переменной «Disposition» с определенным «uniqueid». Из полученных данных нужно исключить значения: «NO ANSWER», «BUSY», «FAILED», «UNKNOWN». В результате останутся либо «ANSWERED» — на входящий вызов ответили, либо вообще ни чего — пропущенный вызов.

Далее, если вызов оказался пропущенным, то скрипт должен отправить e-mail уведомление.
Duke the foresight, the important point is that Asterisk executes commands sequentially, waiting for their completion (which is generally logical). We will call the bash script before the hangupcall command is executed. Consequently, at the moment of executing the script, the information about the desired "uniqueid" won't yet be recorded in the CDR. To solve this problem, we will call the bash script with the parameter "&", allowing Asterisk to move to the next step immediately, i.e., hangupcall. At the beginning of the bash script, we will set a slight delay to give Asterisk time to record the data with the desired "uniqueid" in the CDR.

Praktika

Before we move to configure Asterisk and create the bash script, we need to set up email notifications. For this, we will use the postfix utility.

Configuration of postfix

We have the email domain "lucky.ru" hosted on Yandex. We will configure postfix in SMTP client mode and send emails from the account asterisk@lucky.ru.
This solution is based on the following: https://www.dmosk.ru/miniinstruktions.php?mini=postfix-over-yandex.

First, we install/update/check for the presence of the packages:

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

We won't overwrite the main configuration file postfix "/etc/postfix/main.cf", but will create a backup of it:

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

We edit the file "/etc/postfix/main.cf" and modify it as follows:

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
#####################

Not every line in "/etc/postfix/main.cf" can have comments. Comments in some lines aren't recognized by the parser and are processed, which leads to errors. It's better to refrain from comments inside this file. You can experiment with this by running "tail -f /var/log/messages" in a neighboring window.

I would like to point out the line "smtputf8_autodetect_classes = all". This entry enables utf-8 by default, allowing the use of Cyrillic in both the body and the subject of the email without additional manipulations (See. http://www.postfix.org/SMTPUTF8_README.html).

Let's create a directory for configuration files:

mkdir /etc/postfix/private

We edit the file "/etc/postfix/private/sender_relay". Here, we need to specify which SMTP server to refer to when using our email domain:

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

We edit the file "/etc/postfix/private/sasl_passwd". In it, we will specify the email address that we will use for sending emails, as well as the login and password for this account (the login and password are separated by a colon):

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

We edit the file "/etc/postfix/generic". In it, we will write rules for replacing the outgoing address (see. 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
#####################

The initial outgoing address depends on the content of "/etc/hosts" and "/etc/hostname", as well as on the username who will send the email. In other words, even though we are using the SMTP client and sending emails from asterisk@lucky.ru, postfix will initially substitute "something of its own" for the sender's address and this must be corrected by the rules in this configuration file.

I will provide the content of my file "/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
#####################

It's important for the server to have some domain (the value after the dot) because the mail utility "searches" for the domain name in "/etc/hosts" and if it does not find it immediately, it will continue to search for several more minutes and only then send the email. In other words, if the domain is not specified, the email will be sent with a delay of several minutes.

I will provide the content of my file "/etc/hostname":

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

Next, we need to convert the created configuration files into indexed databases; for this we will execute the following command:

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

Next, we need to download and place the certificate for smtp.yandex.ru on the server; we will execute the following command:

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

But after the technical information appears on the screen, the command will "keep hanging". Press Ctrl+C to stop it.

Tani tani do të heqim manualisht të gjitha mbeturinat nga skedari i thelluar dhe do të lëmë vetëm certifikatën. Duhet të dalë diçka e tillë:

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

Dhe përfundimisht, riaktivizojmë postfix-in:

service postfix restart

Dërgojmë një email testues:

echo "Ky është trupi i email-it" | mail -s "Kjo është tema" admin@lucky.ru

admin@lucky.ru - adresa e destinacionit

Këtu përfundojmë konfigurimin e postfix.

Shkruajmë një skript bash

Krijojmë një direktorium për storingun e skriptit bash (këtu ku çdo kush preferon):

mkdir /home/asterisk/scripts

Krijojmë skedarin e skriptit bash:

touch /home/asterisk/scripts/noanswer.sh

I japim skedarit të skriptit të drejtat për ekzekutim:

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

Nëse keni dyshime mbi drejtat e skedarit, mund të jepni qasje të plotë në skedar për kohën e debugimit. Por kjo "nuk është e sigurt".

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

Teksti i skriptit 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="për një çështje të rëndësishme"
 ;;
 63100)
 address="debian@lucky.ru"
 subject="për çështje linux debian"
 ;;
 63200)
 address="windows@lucky.ru"
 subject="për çështje windows"
 ;;
 63300)
 address="freebsd@lucky.ru"
 subject="për çështje freebsd"
 ;;
 63400)
 address="ubuntu@lucky.ru"
 subject="për çështje linux ubuntu"
 ;;
 63500)
 address="centos@lucky.ru"
 subject="për çështje linux centos"
 ;;
 *)
 address="admin@lucky.ru"
 error_kod=1
 ;;
 esac

 case $error_kod in
 0)
 echo "Thirrja e humbur nga abonenti $2, që telefonoi $subject." | mail -s "Thirrja e humbur nga $2" $address
 echo "Thirrja e humbur për $address nga abonenti $2, që telefonoi $subject. uid=$1" | mail -s "Thirrja e humbur nga $2" admin@lucky.ru
 ;;
 1)
 echo "Thirrja e humbur nga $2. Rradha është e panjohur. uid=$1" | mail -s "Thirrja e humbur nga $2" admin@lucky.ru
 ;;
 esac

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

Shkurtimisht, analiza e skriptit:
«sleep 7»:

Kjo është ajo vonesë kohore për të cilën kam folur më parë. Kemi vendosur një vonesë prej 7 sekondash. Megjithatë, mendoj se një sekondë do të ishte e mjaftueshme.

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

Kërkesa në mysql ne e kemi vendosur në një variabël të veçantë për lehtësi.

Më pas bëjmë një kërkesë në mysql dhe filtrojmë rezultatin e marrë. Heqim të gjitha variantet përveç «ANSWERED», nëse ka të tilla. Nëse ka shumë vlera «ANSWERED», duhet të lëmë vetëm një. Në fund, në variablin «answer» do të marrim ose «ANSWERED» ose «».
Nëse vlera e variablit «answer» nuk është e barabartë me «ANSWERED», atëherë është një thirrje e humbur. Duke u bazuar në numrin e radhës, me operatorin case do të caktojmë adresën, kujt duhet t'i dërgohet njoftimi në email dhe çfarë duhet të shkruhet në këtë mesazh (pjesa e ndryshueshme e mesazhit).

Më pas trajtohet rasti kur radha është caktuar në Asterisk, por nuk është përshkruar në skript. Në këtë rast, admin@lucky.ru do të marrë një email që e informon se radhën nuk e njeh skripti.

Por nëse radhën e njohim, do të dërgohet një email në destinacion dhe një email kopje te admin@lucky.ru me informacionin "uniqueid", për të ndjekur ngjarjet e kësaj thirrjeje në rast nevoje.

Këtu përfundon skripti.

Dua të theksoj se për t'u lidhur me mysql kemi përdorur emrin e përdoruesit dhe fjalëkalimin që i kemi gjetur më parë. Në FreePBX për të gjetur emrin e përdoruesit Asterisk në mysql ekzekutoni komandën e mëposhtme:

cat /etc/amportal.conf | grep AMPDBUSER

Dhe për të gjetur fjalëkalimin e përdoruesit Asterisk në mysql ekzekutoni komandën e mëposhtme:

cat /etc/amportal.conf | grep AMPDBPASS

Konfigurimi i Asterisk

Ne përdorim FreePBX. Në FreePBX ka lloje të ndryshme skedarësh konfigurimi (shih. https://asterisk-pbx.ru/wiki/freepbx/files), disa prej të cilëve FreePBX i ripërpunon gjatë rindezjes, ndërsa disa të tjerë nuk i ripërpunon (ato quhen custom), sepse janë të destinuara posaçërisht për përdoruesin.

Do të punojmë me skedarin e konfigurimit «extensions_override_freepbx.conf», pasi ai i përket tipit custom.

Fillimisht, le të sigurohemi që skedari «/etc/asterisk/extensions.conf» lidhet me skedarin «extensions_override_freepbx.conf». Për këtë ekzekutoni komandën e mëposhtme:

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

E redaktojmë skedarin «/etc/asterisk/extensions_override_freepbx.conf» dhe e çojmë në formatin e mëposhtëm:

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,)
#####################

Ashtu siç kam thënë më parë, simboli «&» në fund është i detyrueshëm. Po punojmë në bash-skript me të dhënat CDR që nuk ruhen në mysql deri pas përfundimit të «exten => h,2,Macro(hangupcall,)», prandaj është e nevojshme të mos presim për përfundimin e bash-skriptit dhe të kalojmë në hapin tjetër në Asterisk. Dhe vetë bash-skripti duhet të ketë një vonesë kohore para përfundimit të pjesës kryesore.

Për që ndryshimet në skedarin e konfigurimit «/etc/asterisk/extensions_override_freepbx.conf» të hynin në fuqi, duhet riaktualizuar bërthama e Asterisk me komandën e mëposhtme:

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

Kjo duhet të bëhet pasi scripti bash të jetë krijuar.

Përfundimi

Ndoshta ky është mënyra e 1001-të për "kapjen e thirrjeve të humbura" në Asterisk. Ndani në komentet se si e zgjidhni ju këtë problem. Dhe çfarë mendoni se mund të përmirësohet/rikonstruohet/optimalizohet. Do të ishim mirënjohës për ide konstruktive.

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster