
IP ATC Asterisk — това е мощен комбайн в областта на IP телефонията. Уеб интерфейсът FreePBX, създаден за Asterisk, значително улеснява настройките и намалява прага на влизане в системата.
Ако можете да измислите каквато и да е задача, свързана с IP телефонията, почти със сигурност може да бъде реализирана в Asterisk. Но бъдете уверени, че ще е необходимо упорство и търпение.
Пред нас стоеше задачата да настроим e-mail известия за пропуснати повиквания. По-точно казано, да уведомяваме по e-mail за случаите, когато входящо повикване е преминало в опашка, но никой (от агентите) не е отговорил на това входящо повикване.
Научихме, че няма стандартни средства за решаване на тази задача във FreePBX. Ще разкажа как решихме тази задача по-долу.
Предговор
Преди да решим задачата "направо", разбира се, потърсихме информация в интернет, но не намерихме готово решение (може би търсехме лошо, но какво да се прави...).
Не разполагаме с много опит в работа с Asterisk, затова предлаганото , не беше до край осмислено и беше отхвърлено.
Необходимото решение, което предложи , ни хареса, въпреки че не сработи. Оттук подчертахме, че работата с Asterisk трябва да се извършва в контекста на опашките [ext-queues]. И тъй като работим с FreePBX, трябва да действаме в конфигурационния файл "extensions_override_freepbx.conf". Обърнахме внимание, че "уловът на пропуснати повиквания" е удобен преди събитието hangupcall (край на повикването).
След като прочетохме обсъждането на , се появи идеята, че трябва да филтрираме в CDR променливата "Disposition" по всички агенти в опашката. След прочитането на информацията, се очертаха напълно конкретни стъпки за решаване на поставената задача.
Какво имаме:
Имаме FreePBX 13.0.197, който използва Asterisk 13.12.1. Версия на ОС SHMZ release 6.6 (Краен). Дистрибутивът е базиран на CentOS.
В Asterisk е настроен IVR (гласово меню), който разпределя входящите повиквания на различни опашки (queues). На всяка опашка са назначени агенти, т.е. оператори.
Теория
Какво се случва в Asterisk
Когато в Asterisk постъпи входящо повикване, това повикване попада на IVR. Звонящият прави избор, натискайки определена цифра на телефона, и попада в определена опашка. След това на всички свободни агенти на опашката едновременно постъпва повикване.
За да разберем по-добре какво се случва в този момент и какво следва, ще обърнем внимание на Report CDR (Рис.1).

Рис.1
Когато входящият повик се премести в опашката, стойността на променливата «Disposition» за всички агенти стана равна на «NO ANSWER», ако агенти не бяха заети в този момент. Променливата «Disposition» можеше да приеме и други стойности (вж. ), освен стойността «ANSWERED». А в момента, когато един от агентите отговори на входящото повикване, стойността на променливата «Disposition» за този агент става равна на «ANSWERED».
От Report CDR може да се забележи, че когато повикването премине в опашка (в колоната App стойността става равна на «Queue»), всички събития се появяват с едно и също «uniqueid» (колонка System).
Кратко за CDR
Важно е да разберете какво е CDR и в кой именно момент данните, които наблюдаваме в Report CDR, се записват. CDR, относно операционната система — е база данни, в която Asterisk записва подробен отчет за повикванията (вж. ). В нашия случай това е база с името asteriskcdrdb, която се намира в mysql. Опитно установихме, че данните за повикването с определено «uniqueid» се вписват в asteriskcdrdb не веднага след възникването на каквото и да било събитие, а след събитието hangupcall (приключване на повикването).
Принцип на работа на създаденото решение
Тъй като имаме повече познания по bash, отколкото по Asterisk, основната идея се оказа следната. Преди събитието hangupcall да се извика bash-скрипт. В този скрипт да се предадат 3 параметъра. Първият параметър е «uniqueid», за филтриране на данните, получени от CDR. Вторият параметър е «CALLERID(num)» (номер на обаждащия), за да знаем на кого да се обадим обратно. Третият параметър е «NODEST» (номер на опашката), в която е влязло повикването, за да знаем по какъв въпрос е било повикването и на кого да изпратим имейл уведомление за пропуснато повикване.
Bash-скриптът трябва да се свърже с базата asteriskcdrdb в mysql и да вземе всички стойности на променливата «Disposition» с определено «uniqueid». От получените данни трябва да се изключат стойности: «NO ANSWER», «BUSY», «FAILED», «UNKNOWN». В резултат ще останат или «ANSWERED» — на входящото повикване е отговорено, или нищо — пропуснато повикване.
След това, ако повикването е пропуснато, скриптът трябва да изпрати имейл уведомление.
Предварително ще подчертая важен момент. Asterisk изпълнява командите последователно, изчаквайки тяхното изпълнение (което в общи линии е логично). А ние ще извикаме bash-скрипта преди да бъде изпълнена командата hangupcall. По този начин в момента на непосредственото изпълнение на скрипта, в CDR все още няма да бъде внесена информация за желаното от нас «uniqueid». За да решим този проблем, ще извикаме bash-скрипта с параметъра «&», за да прехвърли Asterisk веднага на изпълнението на следващата стъпка, т.е. hangupcall. А в самото начало на bash-скрипта, ще зададем малко закъснение във времето, за да дадем възможност на Asterisk да вмени данните с интересуващия ни «uniqueid» в CDR.
Практика
Преди да преминем към настройка на Asterisk и създаване на bash-скрипт, трябва да настроим изпращането на уведомления по e-mail. За целта ще използваме утилитата postfix.
Настройка на postfix
Имаме пощенски домейн «lucky.ru», разположен в Яндекс. Ще настроим postfix в режим smtp-клиент и ще изпращаме писма от акаунта asterisk@lucky.ru.
За основа е взето решението оттук: .
Първо ще инсталираме/обновим/проверим наличието на пакетите:
yum install postfix
yum install mailx
yum install cyrus-sasl cyrus-sasl-lib cyrus-sasl-plainНе ще изтриваме основния конфигурационен файл на postfix «/etc/postfix/main.cf», а ще създадем негова резервна копия:
cp /etc/postfix/main.cf /etc/postfix/main.cf.savРедактираме файла «/etc/postfix/main.cf» и го приведем в следния вид:
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
#####################Не всяка линия в «/etc/postfix/main.cf» може да бъде коментирана. Коментарите в някои редове не се разпознават от парсера и се предават за обработка, което води до грешки. По-добре е да се откажете от коментарите в този файл. Можете да експериментирате с това, като стартирате в съседния прозорец «tail -f /var/log/messages».
Подчертавам реда «smtputf8_autodetect_classes = all». Тази записва включва utf-8 по подразбиране, което позволява използването на кирилица както в тялото на писмото, така и в темата на писмото без допълнителни манипулации (Вж. ).
Да създадем каталог за конфигурационните файлове:
mkdir /etc/postfix/privateРедактиране на файла «/etc/postfix/private/sender_relay». В него трябва да посочим на кой smtp-сървър да се отнасяме при използване на нашия пощенски домейн:
nano /etc/postfix/private/sender_relay
#####################
@lucky.ru smtp.yandex.ru
#####################Редактиране на файла «/etc/postfix/private/sasl_passwd». В него ще посочим имейл адреса, който ще използваме за изпращане на писма, а също така логин и парола за тази акаунт (логин и парола се посочват с двоеточие):
nano /etc/postfix/private/sasl_passwd
#####################
asterisk@lucky.ru asterisk@lucky.ru:password_asterisk
#####################Редактиране на файла «/etc/postfix/generic». В него ще запишем правилата за замяна на изходящия адрес (вж. ):
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
#####################Първоначалният изходящ адрес зависи от съдържанието на «/etc/hosts» и «/etc/hostname», както и от името на потребителя, който ще изпраща писмото. И така, въпреки че използваме smtp-клиент и изпращаме писма от asterisk@lucky.ru, все пак в адреса на изпращача postfix първоначално ще вмъкне «нещо свое» и това трябва да се коригира с правилата от този конфигурационен файл.
Ще покажа съдържанието на моя файл «/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
#####################Важно е серивърът да има домейн (стойността след точката), тъй като утилитата mail «търси» името на домейна в «/etc/hosts» и ако «не го намери» веднага, ще продължи да прави това още няколко минути и едва след това ще изпрати писмото. Т.е. ако домейнът не е посочен, писмото ще бъде изпратено със закъснение от няколко минути.
Ще покажа съдържанието на моя файл «/etc/hostname»:
cat /etc/hostname
#####################
asterisk
#####################Следва да преобразуваме създадените конфигурационни файлове в индексни бази данни, за което ще изпълним следната команда:
postmap /etc/postfix/generic && postmap /etc/postfix/private/{sasl_passwd,sender_relay}Следва да изтеглим и поставим на сървъра сертификата smtp.yandex.ru, за което ще изпълним следната команда:
openssl s_client -starttls smtp -crlf -connect smtp.yandex.ru:25 > /etc/postfix/ca.pemНо след като на екрана излезе техническата информация, екипът ще продължи да стои на линия. Натиснете Ctrl+C, за да го прекратите.
Сега ръчно ще изтрием всичките ненужни данни от получената файла и ще оставим само сертификата. Трябва да изглежда нещо подобно:
nano /etc/postfix/ca.pem
#####################
-----BEGIN CERTIFICATE-----
MIIGazCCBVOgAwIBAgIQcUU9mJXW4OUs5Gf0JfLtsjANBgkqhkiG9w0BAQsFADBf
...
nRG0DfdqYIuPGApFORYe
-----END CERTIFICATE-----
#####################И накрая ще рестартираме postfix:
service postfix restartИзпращаме тестово писмо:
echo "Това е телото на писмото" | mail -s "Това е темата" admin@lucky.ruadmin@lucky.ru — адрес на получателя
Тук настройката на postfix приключва.
Пишем bash-скрипт
Създаваме директория за съхранение на bash-скрипта (тук, където всеки предпочита):
mkdir /home/asterisk/scriptsСъздаваме файла на bash-скрипта:
touch /home/asterisk/scripts/noanswer.shДаваме права за изпълнение на файла на скрипта:
chmod +x /home/asterisk/scripts/noanswer.shАко имате съмнения относно правата на файла, временно можете да дадете пълен достъп до файла. Но това е "не безопасно".
chmod 777 /home/asterisk/scripts/noanswer.shТекст на 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="по важен въпрос"
;;
63100)
address="debian@lucky.ru"
subject="по въпросите на linux debian"
;;
63200)
address="windows@lucky.ru"
subject="по въпросите на windows"
;;
63300)
address="freebsd@lucky.ru"
subject="по въпросите на freebsd"
;;
63400)
address="ubuntu@lucky.ru"
subject="по въпросите на linux ubuntu"
;;
63500)
address="centos@lucky.ru"
subject="по въпросите на linux centos"
;;
*)
address="admin@lucky.ru"
error_kod=1
;;
esac
case $error_kod in
0)
echo "Пропуснато обаждане от абонат $2, извикал $subject." | mail -s "Пропуснато обаждане от $2" $address
echo "Пропуснато обаждане за $address от абонат $2, извикал $subject. uid=$1" | mail -s "Пропуснато обаждане от $2" admin@lucky.ru
;;
1)
echo "Пропуснато обаждане от $2. Опашката е неизвестна. uid=$1" | mail -s "Пропуснато обаждане от $2" admin@lucky.ru
;;
esac
fi
#####################Кратко обяснение на скрипта:
«sleep 7»:
Това е забавянето, за което споменах по-рано. Имаме установено забавяне от 7 секунди. Въпреки че, мисля, че и една секунда е напълно достатъчна.
«res_sql="SELECT disposition FROM cdr WHERE uniqueid = '$1'"»:Заявката в mysql сме изнесли в отделна променлива за удобство.
След това правим заявка към mysql и филтрираме полученото изходно. Премахваме всички варианти, освен «ANSWERED», ако изобщо има такъв. Ако все пак има няколко стойности «ANSWERED», оставяме само една. Накрая в променливата «answer» ще получим или «ANSWERED», или «».
Ако стойността на променливата «answer» не е равна на «ANSWERED», то това е пропуснато обаждане. В зависимост от номера на опашката, с помощта на оператора case задаваме адреса, на когото точно трябва да изпратим e-mail уведомление и какво да напишем в това съобщение (променливата част на съобщението).
Следва вариант, когато опашката е зададена в Asterisk, но не е описана в скрипта. В този случай admin@lucky.ru ще получи писмо, че опашката не е известна на скрипта.
Ако опашката е описана, писмото ще бъде изпратено на адреса и дублиращо писмо на admin@lucky.ru с указание «uniqueid», за да може да се проследят събитията за това обаждане, ако е необходимо.
Тук скриптът завършва.
Ще отбележа, че за свързване с mysql използвахме потребителско име и парола, които предварително узнахме. В FreePBX, за да разберете потребителското име на Asterisk в mysql, изпълнете следната команда:
cat /etc/amportal.conf | grep AMPDBUSERА за да разберете паролата на потребителя Asterisk в mysql, изпълнете следната команда:
cat /etc/amportal.conf | grep AMPDBPASSНастройка на Asterisk
Използваме FreePBX. В FreePBX има различни типове конфигурационни файлове (виж. ), някои от тях FreePBX презаписва при рестартиране, а някои не (наричат се custom), тъй като са специално предназначени за потребителя.
Ще работим с конфигурационния файл «extensions_override_freepbx.conf», тъй като той попада в категорията custom.
Първо ще се уверим, че файлът «/etc/asterisk/extensions.conf» е свързан с файла «extensions_override_freepbx.conf». За целта изпълняваме следната команда:
cat /etc/asterisk/extensions.conf | grep extensions_override_freepbx.conf
#####################
#include extensions_override_freepbx.conf
#####################Редактираме файла «/etc/asterisk/extensions_override_freepbx.conf» и го довеждаме до следния вид:
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,)
#####################Както писах по-рано, символът «&» в края е задължителен. Тъй като ще работим в bash-скрипт с данни CDR директно от базата mysql, а тези данни се записват в mysql само след изпълнението на „exten => h,2,Macro(hangupcall,)“, е необходимо да не чакаме завършването на bash-скрипта, а да преминем към изпълнението на следващата стъпка в Asterisk. А самият bash-скрипт трябва да съдържа времево забавяне, преди да изпълни основната си част.
За да влязат в сила промените в конфигурационния файл «/etc/asterisk/extensions_override_freepbx.conf», е необходимо да се рестартира ядрото на Asterisk с следната команда:
/usr/sbin/asterisk -rx "core restart now"Това трябва да се направи след като bash-скриптът бъде създаден.
Заключение
Вероятно, това е 1001-ят начин за „улов на пропуснати повиквания“ в Asterisk. Споделете в коментарите как решавате тази задача вие. И какво, според вас, може да се подобри/преработи/opтимизира. Ще бъдем благодарни за конструктивни идеи.
Източник: habr.com
