Курсы по использованию Asterisk

IP-телефония — технология будущего. Обучитесь работе с IP-АТС Asterisk для того чтобы внедрить и профессионально использовать при решении коммуникационных задач.

Работайте с Asterisk профессионально!

Многоуровневая защита IP-АТС Asterisk

Телефонные станции очень часто становятся объектами хакерских атак. Узнайте, каким образом необходимо строить многоуровневую защиту для Вашей IP-АТС.

Не оставьте хакерам шансов. Защитите свой Asterisk от атак.

Используйте Веб-Интерфейс для удобства настройки

Панель управление FreePBX позволяет легко и удобно управлять всей системой. Научитесь эффективно использовать FreePBX для решения своих задач.

Управление станцией и статистика в окне браузера.

Научитесь работать с Asterisk из консоли

Для понимания работы с Asterisk необходимо уметь настраивать его вручную с конфигурационными файлами и командной строкой CLI Asterisk.

Научитесь «тонкой» настройке Asterisk

Цель курсов - максимум практики.

Обучение нацелено на практическую работу с IP-оборудованием: платы потоков E1, VoIP-телефонные аппараты, голосовые шлюзы FXS и прочее.

Обучение на реальном оборудовании — залог успеха.

Asterisk - имитация нахождения вызова в очереди для системы статистики

База знаний Настройка Asterisk

В этой статье будет описан способ имитации нахождения вызова в очереди с помощью диалплана Asterisk - это может понадобится для того, чтобы система статистики, работающая с очередями (например Asternic Call Center Stats Pro), учитывала вызовы, которые на самом деле не попадали в очередь. Например, можно учитывать вызовы, пришедшие на операторов колл-центра в результате донабора и/или маршрутизации входящего вызова на ответственного, как вызовы, прошедшие через очередь.
(приведённые настройки верны для FreePBX 13)

Контексты для имитации нахождения вызова в очереди


Для имитации нахождения вызова в очереди, в лог очереди будут добавляться записи с помощью приложения диалплана QueueLog. На различных этапах вызова будут вызываться различные контексты, все они приведены ниже (контексты нужно добавить в файл /etc/asterisk/extensions_custom.conf)

 

[app-fake-queue-enter]
exten => s,1,ExecIf($["${ARG1}" = ""]?Return)
 
same  => n,Set(__FAKEQ_${ARG1}_ENTERTIME=${EPOCH})
same  => n,Set(__FAKEQ_${ARG1}_STATUS=IN QUEUE)
same  => n,Set(__FAKEQ_${ARG1}_ANSWERTIME=)
same  => n,Set(__FAKEQ_${ARG1}_UID=${UNIQUEID})
same  => n,Set(__FAKEQ_${ARG1}_CALLER=${CALLERID(num)})
same  => n,Set(__FAKEQ_${ARG1}_HOLDTIME=)
same  => n,Set(__FAKEQ_${ARG1}_RINGSTART=)
 
same  => n,QueueLog(${ARG1},${FAKEQ_${ARG1}_UID},NONE,DID,${CDR(did)})
same  => n,QueueLog(${ARG1},${FAKEQ_${ARG1}_UID},NONE,ENTERQUEUE,,${FAKEQ_${ARG1}_CALLER},1)
same  => n,Return

Контекст app-fake-queue-enter добавляет в лог очереди записи DID и ENTERQUEUE (запись DID не является стандартной и используется в FreePBX). Единственный аргумент - имя очереди.

[app-fake-queue-connect]
exten => s,1,ExecIf($["${ARG1}" = "" | "${ARG2}" = "" | "${FAKEQ_${ARG1}_STATUS}" != "IN QUEUE" | "${FAKEQ_${ARG1}_ENTERTIME}" = "" | "${FAKEQ_${ARG1}_UID}" = "" ]?Return)
same  => n,GotoIf($["${ARG3}" = "callee"]?callee)
same  => n,Set(__FAKEQ_${ARG1}_ANSWERTIME=${EPOCH})
same  => n,Set(__FAKEQ_${ARG1}_HOLDTIME=$[${FAKEQ_${ARG1}_ANSWERTIME} - ${FAKEQ_${ARG1}_ENTERTIME}])
same  => n,ExecIf($[${FAKEQ_${ARG1}_HOLDTIME} < 0]?Set(__FAKEQ_${ARG1}_HOLDTIME=0))
same  => n,Set(__FAKEQ_${ARG1}_STATUS=ANSWERED)
same  => n,Goto(cont1)
 
same  => n(callee),Set(MASTER_CHANNEL(__FAKEQ_${ARG1}_ANSWERTIME)=${EPOCH})
same  => n,Set(FAKEQ_${ARG1}_HOLDTIME=$[${FAKEQ_${ARG1}_ANSWERTIME} - ${FAKEQ_${ARG1}_ENTERTIME}])
same  => n,ExecIf($[${FAKEQ_${ARG1}_HOLDTIME} < 0]?Set(FAKEQ_${ARG1}_HOLDTIME=0))
same  => n,Set(MASTER_CHANNEL(__FAKEQ_${ARG1}_HOLDTIME)=${FAKEQ_${ARG1}_HOLDTIME})
same  => n,Set(MASTER_CHANNEL(__FAKEQ_${ARG1}_STATUS)=ANSWERED)
 
same  => n(cont1),QueueLog(${ARG1},${FAKEQ_${ARG1}_UID},${ARG2},CONNECT,${FAKEQ_${ARG1}_HOLDTIME},,1)
same  => n,Return

Контекст app-fake-queue-connect добавляет в лог очереди запись CONNECT. Аргументы контекста:
ARG1 - имя очереди
ARG2 - имя ответившего оператора
ARG3 - должен иметь значение callee, если Gosub в контекст app-fake-queue-connect был выполнен на канале вызванного абонента (например с помощью опции U приложения Dial). Если Gosub был выполнен на канале звонящего, ARG3 должен иметь любое другое значение (в том числе пустое)

 

[app-fake-queue-noanswer]
exten => s,1,ExecIf($["${ARG1}" = "" | "${ARG2}" = "" | "${FAKEQ_${ARG1}_STATUS}" != "IN QUEUE" | "${FAKEQ_${ARG1}_ENTERTIME}" = "" | "${FAKEQ_${ARG1}_UID}" = "" | "${FAKEQ_${ARG1}_RINGSTART}" = "" ]?Return)
same  => n,Set(RINGNOANSWER_TIME=$[(${EPOCH} - ${FAKEQ_${ARG1}_RINGSTART})*1000])
same  => n,ExecIf($[${RINGNOANSWER_TIME} < 0]?Set(RINGNOANSWER_TIME=0))
same  => n,QueueLog(${ARG1},${FAKEQ_${ARG1}_UID},${ARG2},RINGNOANSWER,${RINGNOANSWER_TIME})
same  => n,Return

Контекст app-fake-queue-noanswer добавляет в лог очереди запись RINGNOANSWER. Аргументы контекста:
ARG1 - имя очереди
ARG2 - имя оператора, пропустившего звонок

 

[app-fake-queue-leave]
exten => s,1,ExecIf($["${ARG1}" = "" | "${FAKEQ_${ARG1}_ENTERTIME}" = "" | "${FAKEQ_${ARG1}_UID}" = ""]?Return)
same  => n,Set(NOW=${EPOCH})
same  => n,GotoIf($["${FAKEQ_${ARG1}_STATUS}" = "ANSWERED"]?answered)
; no answer
same  => n,GotoIf($["${ARG2}" = "" | "${FAKEQ_${ARG1}_RINGSTART}" = ""]?no-ring)
same  => n,Gosub(app-fake-queue-noanswer,s,1(${ARG1},${ARG2}))
same  => n(no-ring),Set(ABANDON_TIME=$[${NOW} - ${FAKEQ_${ARG1}_ENTERTIME}])
same  => n,ExecIf($[${ABANDON_TIME} < 0]?Set(ABANDON_TIME=0))
same  => n,QueueLog(${ARG1},${FAKEQ_${ARG1}_UID},NONE,ABANDON,1,1,${ABANDON_TIME})
same  => n,Goto(cont1)
; answered
same  => n(answered),ExecIf($["${ARG2}" = "" | "${FAKEQ_${ARG1}_ANSWERTIME}" = "" | "${FAKEQ_${ARG1}_HOLDTIME}" = ""]?Return)
same  => n,Set(QUEUE_EVENT=${IF($["${ARG3}" = "COMPLETEAGENT"]?${ARG3}:COMPLETECALLER)})
same  => n,Set(CALL_TIME=$[${NOW} - ${FAKEQ_${ARG1}_ANSWERTIME}])
same  => n,ExecIf($[${CALL_TIME} < 0]?Set(CALL_TIME=0))
same  => n,QueueLog(${ARG1},${FAKEQ_${ARG1}_UID},${ARG2},${QUEUE_EVENT},${FAKEQ_${ARG1}_HOLDTIME},${CALL_TIME},1)
 
same  => n(cont1),Set(__FAKEQ_${ARG1}_ENTERTIME=)
same  => n,Set(__FAKEQ_${ARG1}_STATUS=)
same  => n,Set(__FAKEQ_${ARG1}_ANSWERTIME=)
same  => n,Set(__FAKEQ_${ARG1}_UID=)
same  => n,Set(__FAKEQ_${ARG1}_CALLER=)
same  => n,Set(__FAKEQ_${ARG1}_HOLDTIME=)
same  => n,Set(__FAKEQ_${ARG1}_RINGSTART=)
same  => n,Return

Контекст app-fake-queue-leave добавляет в лог очереди запись COMPLETECALLER/COMPLETEAGENT, если был ответ на вызов, или ABANDON, если ответа не было (также вызывает app-fake-queue-noanswer при необходимости). Аргументы контекста:
ARG1 - имя очереди
ARG2 - имя оператора, принявшего или пропустившего звонок
ARG3 - должен иметь значение COMPLETEAGENT, если вызов завершил оператор (иначе в лог будет записано COMPLETECALLER)

 

Применение сценария на примере прямого донабора в IVR


Ниже приведены параметры тестового меню IVR.

Параметры текстового меню IVR

Вызовы из IVR идут в очередь 10000, сделаем так, чтобы при наборе в IVR номера оператора очереди 10000, в лог очереди добавились все необходимые сообщения для системы статистики (для этого опция Enable Direct Dial должна быть отключена).
Порядок вызова контекстов следующий:
1) app-fake-queue-enter для записи ENTERQUEUE
2) app-fake-queue-connect для записи CONNECT (если был ответ)
3) app-fake-queue-leave для записи COMPLETECALLER/COMPLETEAGENT или RINGNOANSWER и ABANDON
(app-fake-queue-noanswer в данном сценарии вызывается только из app-fake-queue-leave)

Донабор для IVR лучше реализовать в виде отдельного контекста, чтобы можно было включать его в различные IVR (если в IVR используются разные очереди, нужно устанавливать переменную CUR_QUEUE до входа в IVR, например, через Custom Destination).

[ext-direct-dial-fakeq]
exten => _XXX,1,Set(DIAL_STR=${DB(DEVICE/${EXTEN}/dial)})
same  => n,GotoIf($[${DIALPLAN_EXISTS(ext-local,${EXTEN},1)} = 0]?invalid)
same  => n,GotoIf($["${DIAL_STR}" = ""]?invalid)
same  => n,GotoIf($["${EXTENSION_STATE(${EXTEN}@ext-local)}" != "NOT_INUSE"]?continue)
same  => n,Set(CUR_QUEUE=10000)
same  => n,GotoIf($[${REGEX("(^|,)Local/${EXTEN}@from-queue/n($|,)" ${QUEUE_MEMBER_LIST(${CUR_QUEUE})})} = 0]?skip_fake_queue)
same  => n,Set(FAKEQ_NUM=${CUR_QUEUE})
same  => n,Set(FAKEQ_AGENT_NUM=${EXTEN})
same  => n,Set(FAKEQ_AGENT_NAME=${DB(AMPUSER/${FAKEQ_AGENT_NUM}/cidname)})
same  => n,Set(FAKEQ_RESULT=COMPLETECALLER)
same  => n,ExecIf($["${FAKEQ_AGENT_NAME}" = ""]?Set(FAKEQ_AGENT_NAME=${FAKEQ_AGENT_NUM}))
same  => n,ExecIf($["${FAKEQ_${FAKEQ_NUM}_STATUS}" = ""]?Gosub(app-fake-queue-enter,s,1(${FAKEQ_NUM})))
same  => n,Set(CHANNEL(hangup_handler_push)=app-fake-queue-leave,s,1(${FAKEQ_NUM},${FAKEQ_AGENT_NAME},${FAKEQ_RESULT}))
same  => n,Set(__FAKEQ_${FAKEQ_NUM}_RINGSTART=${EPOCH})
same  => n(skip_fake_queue),Gosub(sub-record-check,s,1(exten,${EXTEN},yes))
same  => n,Set(DIALSTATUS=)
same  => n,Dial(${DIAL_STR},15,tgU(app-fake-queue-connect^${FAKEQ_NUM}^${FAKEQ_AGENT_NAME}^callee))
same  => n,Set(FAKEQ_RESULT=COMPLETEAGENT)
same  => n,ExecIf($["${DIALSTATUS}" = "ANSWER"]?Hangup)
same  => n(continue),Gosub(app-fake-queue-leave,s,1(${FAKEQ_NUM},${FAKEQ_AGENT_NAME}))
same  => n,Goto(t,1)
same  => n(invalid),Set(INVALID_EXTEN=${EXTEN})
same  => n,Goto(i,1)
 

Теперь нужно найти в файле /etc/asterisk/extensions_additional.conf имя контекста созданного IVR, в данном примере это контекст ivr-2. В файле /etc/asterisk/extensions_override_freepbx.conf нужно включить контекст ext-ivr-direct-dial в ivr-2.

[ivr-2]
include => ext-direct-dial-fakeq 

Настройка завершена.

 

asterisk, настройка, Call-файл, FreePBX, Channel, Event, Time, call, asternic, callerid, IVR