Меню переадресации для Asterisk

Администратор, 24.11.2015

Asterisk - IP-АТС с крайне широкими возможностями. Однако, это скорее "двигатель для постройки любого автомобиля", нежели мощнейший суперкар, в смысле того, что все функции, которые в нее заложены, администратор вынужден настраивать с нуля на каждой новой инсталяции, то есть мы не имеем никакого pre-defined кода, как это сделано, скажем, во FreePBX.

С одной стороны - это крайне удобно, потому что вы не завязаны на использование диалплана, который придуман разработчиками и имеете полнейшую свободу выбора в настройке, тем самым пользуетесь всеми преимуществами настоящего open source решения. Однако с другой стороны, процесс первичного развертывания АТС затягивается из-за того, что вы вынуждены писать диалплан с нуля в каждой новой системе.

Что же делать? Наиболее верным решением является использование некоторых функциональных блоков, которые перетекают у вас от инсталляции к инсталляции. Одной из такой фич несомненно является опция установки переадресации абонентом, ведь не принципиально, какие внешние условия наложены на вашу систему (DAHDI, SIP и тд), этот функционал будет использоваться везде.

Нами были сделаны два варианта реализации:

Вариант 1. Реализация установки переадресации с помощью интерактивного голосового меню и взаимодействия с пользователем:

extensions.conf

exten => 4567,1,Answer() ;абонент набирает номер 4567
same  => n,Playback(/var/lib/asterisk/sounds/redir/4) ; приветствие системы
same  => n,Set(ACTNUM=${DB(tempred/${CALLERID(num)})}) ; кладем в переменную ACTNUM номер, введенный пользователем при условии его существования
same  => n,NoOp(${ACTNUM})
same  => n,GotoIf(${DB_EXISTS(tempred/${CALLERID(num)})}?yes:no) ;если есть уже номер для переадресации - идем к метке (yes), нет - (no)
same  => n(no),Playback(/var/lib/asterisk/sounds/redir/5) ; просим пользователя ввести номер
same  => n,Read(TMPNUM) ; читаем этот номер
same  => n,Set(DB(tempred/${CALLERID(num)})=${TMPNUM}) ; кладем в базу
same  => n,Set(ACTNUM=${DB(tempred/${CALLERID(num)})}) ; кладет в переменную ACTNUM номер, введенный пользователем
same  => n,Playback(/var/lib/asterisk/sounds/redir/6) ; говорим, что номер установлен
same  => n,SayDigits(${ACTNUM}) ;проговариваем номер
same  => n,Wait(1)
same  => n,Playback(vm-goodbye) ; прощаемся с абонентом
same  => n,Hangup()
same  => n(yes),GoTo(redir-yes,s,1) ; идем в другой контекст

exten => _4567XXX,1,Answer() ; проверка статуса перадресация для внутренних абонентов, в моем случае используются трехзначные номера ХХХ
same  => n,Set(ACTNUM=${DB(tempred/${CALLERID(num)})}) ;см выше
same  => n,Set(EXIST=${ISNULL(${ACTNUM})}) ;Проверяем существование номера
same  => n,GotoIf($["${EXIST}"="1"]?null:notnull) ;условный переход по существованию номера для переадресации
same  => n(null),Playback(/var/lib/asterisk/sounds/redir/7);;Переадресация не установлена
same  => n,Hangup()
same  => n(notnull),Playback(/var/lib/asterisk/sounds/redir/8);Установлена переадресация на номер
same  => n,SayDigits(${ACTNUM}) ; проговариваем номер, на который установлена переадресация
same  => n,Hangup()


[redir-yes]

exten => s,1,Answer()
same  => n,Playback(/var/lib/asterisk/sounds/redir/1);;У вас установлена переадресация на номер
same  => n,SayDigits(${ACTNUM}) ; проговариваем номер
same  => n,Background(/var/lib/asterisk/sounds/redir/2);; Для удаления переадресации нажмите один
same  => n,WaitExten(5) ;ждем пока абонент введет цифру один
same  => n,Hangup()

exten => 1,1,Playback(/var/lib/asterisk/sounds/redir/3) ;;переадресация удалена. до свидания
same  => n,NoOp(${DB_DELETE(tempred/${CALLERID(num)})}) ;удаляем номер из базы
same  => n,Hangup()


И непосредственно диалплан для вызова внутреннего номера:

exten => _XXX,1,NoOp(Call from ${CALLERID(num)} to ${EXTEN})
same  => n,Set(ACTNUM=${DB(tempred/${EXTEN:-3})})
same  => n,Set(EXIST=${ISNULL(${ACTNUM})})
same  => n,GotoIf($["${EXIST}"="1"]?null:notnull)
same => n(null),Dial(SIP/${EXTEN},40,Tt)
same => n,Hangup()
same => n(notnull),Set(length=${LEN(${ACTNUM})})
same => n,NoOp(${length})
same => n,GotoIf($["${length}" = "3"]?local:long)
same => n(local),Dial(SIP/${ACTNUM},60,Tt)
same => n,Hangup()
same => n(long),GoTo(from-internal-out,${ACTNUM},1)
same => n,Hangup()


Вариант 2. Установка переадресации через кодовые команды (наподобие USSD-запросов мобильных телефонов)

exten =>_*1*1*X.,1,NoOp(CCF activated) ;установка условной переадресации
same  => n,Set(cond=${EXTEN:3:1}) ;кладем переменную условия, 1 - условная, 0 - безусловная
same  => n,Set(tmpnum=${EXTEN:5}) ; номер для переадресации
same  => n,NoOp(${cond})
same  => n,NoOp(${tmpnum})
same  => n,Set(DB(condi/${CALLERID(num)})=${cond}) ; кладем в базу условие
same  => n,Set(DB(tempred/${CALLERID(num)})=${tmpnum}) ; кладем в базу номер
same  => n,Set(ACTNUM=${DB(tempred/${CALLERID(num)})}) ; делаем переменную, в которую кладем номер переадресации
same  => n,Playback(/var/lib/asterisk/sounds/redir/ccf_activated) ; проговариваем, что установлена переадресация
same  => n,SayDigits(${tmpnum}) ; говорим номер переадресации
same  => n,Hangup()

;аналогичная логика для написанного выше
exten =>_*1*0*X.,1,NoOp(UCF activated)
same  => n,Set(cond=${EXTEN:3:1})
same  => n,Set(tmpnum=${EXTEN:5})
same  => n,NoOp(${cond})
same  => n,NoOp(${tmpnum})
same  => n,Set(DB(condi/${CALLERID(num)})=${cond})
same  => n,Set(DB(tempred/${CALLERID(num)})=${tmpnum})
same  => n,Set(ACTNUM=${DB(tempred/${CALLERID(num)})})
same  => n,Playback(/var/lib/asterisk/sounds/redir/ucf_activated)
same  => n,SayDigits(${tmpnum})
same  => n,Hangup()

;убираем переадресацию
exten =>_*0!,1,NoOp(any CF deactivated)
same  => n,NoOp(${DB_DELETE(tempred/${CALLERID(num)})})
same  => n,NoOp(${DB_DELETE(condi/${CALLERID(num)})})
same  => n,Playback(/var/lib/asterisk/sounds/redir/cf_off)
same  => n,Hangup()

;;cf checking
;проверка статуса переадресации
exten => _*2XXX,1,NoOp(CF Checking)
same => n,Answer()
same => n,Set(tellnum=${DB(tempred/${EXTEN:2})})
same  => n,Set(EXIST=${ISNULL(${tellnum})})
same  => n,GotoIf($["${EXIST}"="1"]?null)
same => n,Playback(/var/lib/asterisk/sounds/redir/cf_activated)
same => n,SayDigits(${tellnum})
same => n,Hangup()
same => n(null),Playback(/var/lib/asterisk/sounds/redir/cf_off)
same => n,Hangup()


И непосредственно диалплан для вызова внутреннего номера:

exten => _XXX,1,NoOp(Call from ${CALLERID(num)} to ${EXTEN})
same => n,Set(actcon=${DB(condi/${EXTEN})})
same => n,NoOp(ACTUAL CONDITION = ${actcon})
same => n,Set(actnum=${DB(tempred/${EXTEN})})
same => n,NoOp(ACTUAL NUMBER = ${actnum})
same  => n,GotoIf($["${actcon}"="1"]?ccf)
same  => n,GotoIf($["${actcon}"="0"]?ucf)
same => n,Dial(SIP/${EXTEN},40,Tt)
same => n,Hangup()
same => n(ccf),Dial(SIP/${EXTEN},10,Tt)
same => n,Dial(SIP/${EXTEN}&SIP/provider/${actnum},60,Tt)
same => n,Hangup()
same => n(ucf),GoTo(from-internal-out,${actnum},1)
same => n,Hangup()