Asterisk. Dialplan Askozia 6. Исходящие звонки +7


В статье пойдет речь о бесплатной АТС Askozia версии 6. При разработке телефонной станции одной из первых задач была организация исходящих звонков.

Как это было


В старой версии Askozia использовались стандартные “шаблоны” dialplan.

  • X! — все номера телефонов
  • XXX — трехзначные цифровые номера
  • .! — абсолютно все номера телефонов

Схематично можно описать пример контекста:

[outgoing]
exten => _XXXXXX!,1,NoOp(Start outgoing calling...) 
	same => n,Dial…

Нам показался такой подход недостаточно гибким. Нет возможности описать следующее правило:

  • Номер начинается с 79
  • Далее следует либо 35 либо 26
  • Остальная часть номера состоит из 7 цифр

Под катом описан выбранный нами подход и итог разработки.

Текущая реализация


Мы решили реализовать этот функционал по другому, с использованием REGEX.

Пример шаблона:

79(25|26)[1-9]{7}

  • (25|26) — это 25 ИЛИ 26
  • [0-9] — цифра от 0 до 9ти, вхождение от 1ого и более раз
  • {7} — кол-во вхождений предыдущего символа

Синтаксис функции REGEX:

REGEX("regular expression" string)
Return '1' on regular expression match or '0' otherwise

Пример использования в Askozia 6:

[outgoing]
exten => _X!,1,NoOp(Start outgoing calling...) 
  same => n,Ringing() 
  same => n,ExecIf($["${REGEX("^[0-9]{6}$" ${EXTEN})}" == "1"]?Gosub(SIP-PR-1-out,${EXTEN},1)) 
  same => n,ExecIf($["${REGEX("^(7|8)[0-9]{10}$" ${EXTEN})}" == "1"]?Gosub(SIP-PR-2-out,${EXTEN},1)) 
  same => n,Hangup()

Для исходящих звонков организована одна точка входа — контекст “outgoing”, в нем происходит вызов функции “ExecIf”:

ExecIf($["${REGEX("^[0-9]{6}$" ${EXTEN})}" == "1"]

Если номер телефона, указанный в переменной “${EXTEN}”, соответствует шаблону, то вызов направляется в sub-контекст средствами функции “Gosub”.

Если в sub-контекст вызов не был прерван, то набор пойдет по следующему подходящему правилу.

Мы таким образом решили проблему с одноканальными линиями. Если линия занята, то вызов идет через следующую, пока не будет отвечен.

Примеры контекстов:

[SIP-PR-1]
exten => _X!,1,ExecIf($["${number}x" == "x"]?Hangup())
	same => n,Dial(SIP/PR-1/${EXTEN},600,TeK))
	same => n,ExecIf($["${DIALSTATUS}" = "ANSWER"]?Hangup())
	same => n,return

[SIP-PR-2]
exten => _X!,1,ExecIf($["${number}x" == "x"]?Hangup())
	same => n,Dial(SIP/PR-2/${EXTEN},600,TeK))
	same => n,ExecIf($["${DIALSTATUS}" = "ANSWER"]?Hangup())
	same => n,return

Обязательно в “sub” — контекст производится проверка “DIALSTATUS”. Если вызов отвечен, то после разговора канал будет завершен средствами функции “Hangup()”. Если этого не сделать, то при завершении звонка клиентом, может произойти повторный набор номера клиента.

Одна важная тонкость, при использовании “Gosub” или “Goto” мы намеренно не меняем ${EXTEN}. Даже если необходимо модифицировать номер телефона (добавить / удалить префикс).

Дело в том, что при модификации EXTEN Asterisk будет модифицировать значение переменной CDR(dst), что приведет к слабо прогнозируемому результату в таблице истории звонков CDR. Считаю, в истории важно сохранять тот номер, который был набран сотрудником.

Будьте аккуратны при описании регулярного выражения. Используйте символы “^”, начало строки и “$” — конец строки, иначе можно получить неожиданный результат.

К примеру шаблон “[0-9]{6}” будет соответствовать всем номерам, где есть 6 и более цифр. Шаблон “^[0-9]{6}$” соответствует только 6ти значным номерам.

Итоги


Мы получили гибкую подсистему, для описания исходящей маршрутизации на АТС.
Список правил отображаем следующим образом:

image

Пример карточки конкретного “Правила”:

image




К сожалению, не доступен сервер mySQL