Александр Мисюрин
14.10.2019
2408

Сервисные коды custom переадресаций

В данной статье рассмотрим реализацию своих переадресаций, помимо стандартных переадресаций, существующих во FreePBX. Ниже приведу список рассматриваемых переадресаций: Безусловная переадресация на внутренний номер, Безусловная переадресация на мобильный номер, Параллельная переадресация на мобильный номер, Безусловная переадресация на группу (очередь), А также рассмотрим сервисный код по включению/выключению записей на внутреннем номере. Поскольку во время переадресации через сервисный […]

Сервисные коды custom переадресаций

В данной статье рассмотрим реализацию своих переадресаций, помимо стандартных переадресаций, существующих во FreePBX.

Ниже приведу список рассматриваемых переадресаций:

  1. Безусловная переадресация на внутренний номер,
  2. Безусловная переадресация на мобильный номер,
  3. Параллельная переадресация на мобильный номер,
  4. Безусловная переадресация на группу (очередь),
  5. А также рассмотрим сервисный код по включению/выключению записей на внутреннем номере.

Поскольку во время переадресации через сервисный код во FreePBX, на внутреннем номере устанавливается статус Busy, необходимо переделать встроенный во FreePBX контекст установки/снятия переадресации, который мы можем найти в extensions_additional.conf.

Ниже прописываем контексты, полученные из additional, с некоторыми изменениями.

Установка CF:

;start sub cf
[cf-on-s]
exten => sstate,1,Set(DEVICE_STATE(Custom:CF${fromext})=${STATE})
exten => sstate,n,Set(DEVICES=${DB(AMPUSER/${fromext}/device)})
exten => sstate,n,GotoIf($["${DEVICES}" = "" ]?return)
exten => sstate,n,Set(LOOPCNT=${FIELDQTY(DEVICES,&)})
exten => sstate,n,Set(ITER=1)
exten => sstate,n(begin),Set(DEVICE_STATE(Custom:DEVCF${CUT(DEVICES,&,${ITER})})=${STATE})
exten => sstate,n,Set(ITER=$[${ITER} + 1])
exten => sstate,n,GotoIf($[${ITER} <= ${LOOPCNT}]?begin)
exten => sstate,n(return),Return()
exten => lang-playback,1,GosubIf($[${DIALPLAN_EXISTS(app-cf-on,${CHANNEL(language)})}]?app-cf-on,${CHANNEL(language)},${ARG1}():app-cf-on,en,${ARG1}())
exten => lang-playback,n,Return()
exten => lang-playback-cancel,1,Playback(call-fwd-cancelled&for&extension)
exten => lang-playback-cancel,n,SayDigits(${fromext})
exten => lang-playback-cancel,n,Return()
exten => lang-playback-g,1,Playback(call-fwd-group&for&extension)
exten => lang-playback-g,n,SayDigits(${fromext})
exten => lang-playback-g,n,Playback(is-set-to)
exten => lang-playback-g,n,SayDigits(${toext})
exten => lang-playback-g,n,Return()
exten => lang-playback-m,1,Playback(call-fwd-parallel&for&extension)
exten => lang-playback-m,n,SayDigits(${fromext})
exten => lang-playback-m,n,Playback(is-set-to)
exten => lang-playback-m,n,SayDigits(${toext})
exten => lang-playback-m,n,Return()
;end sub cf

Удаление CF:

;start sub cf off
[cf-off-s]
exten => sstate,1,Set(DEVICE_STATE(Custom:CF${fromext})=${STATE})
exten => sstate,n,Set(DEVICES=${DB(AMPUSER/${fromext}/device)})
exten => sstate,n,GotoIf($["${DEVICES}" = "" ]?return)
exten => sstate,n,Set(LOOPCNT=${FIELDQTY(DEVICES,&)})
exten => sstate,n,Set(ITER=1)
exten => sstate,n(begin),Set(DEVICE_STATE(Custom:DEVCF${CUT(DEVICES,&,${ITER})})=${STATE})
exten => sstate,n,Set(ITER=$[${ITER} + 1])
exten => sstate,n,GotoIf($[${ITER} <= ${LOOPCNT}]?begin)
exten => sstate,n(return),Return()
exten => lang-playback,1,GosubIf($[${DIALPLAN_EXISTS(app-cf-off,${CHANNEL(language)})}]?app-cf-off,${CHANNEL(language)},${ARG1}():app-cf-off,en,${ARG1}())
exten => lang-playback,n,Return()
exten => lang-playback-cancel,1,Playback(call-fwd-cancelled&for&extension)
exten => lang-playback-cancel,n,SayDigits(${fromext})
exten => lang-playback-cancel,n,Return()
exten => lang-playback-g,1,Playback(call-fwd-group&for&extension)
exten => lang-playback-g,n,SayDigits(${fromext})
exten => lang-playback-g,n,Playback(is-set-to)
exten => lang-playback-g,n,SayDigits(${toext})
exten => lang-playback-g,n,Return()
exten => lang-playback-m,1,Playback(call-fwd-parallel&for&extension)
exten => lang-playback-m,n,SayDigits(${fromext})
exten => lang-playback-m,n,Playback(is-set-to)
exten => lang-playback-m,n,SayDigits(${toext})
exten => lang-playback-m,n,Return()
;end sub cf off

И начинаем прописывать сервисные коды:

  1. Установка безусловной переадресации на внутренний:
exten => _*21*XXXX,1,Answer
exten => _*21* XXXX,n,Wait(1)
exten => _*21* XXXX,n,Macro(user-callerid,)
exten => _*21* XXXX,n,Set(fromext=${AMPUSER})
exten => _*21* XXXX,n,Set(toext=${EXTEN:4})
exten => _*21* XXXX,n,Set(DB(CF/${fromext})=${toext})
exten => _*21* XXXX,n,Set(STATE=BUSY)
exten => _*21* XXXX,n,Gosub(cf-on-s,sstate,1())
exten => _*21* XXXX,n,Gosub(cf-on-s,lang-playback,1(hook_3))
exten => _*21* XXXX,n,Macro(hangupcall,)

2. Установка безусловной переадресации на мобильный:

exten => _*21*89.,1,Answer
exten => _*21*89.,n,Wait(1)
exten => _*21*89.,n,Macro(user-callerid,)
exten => _*21*89.,n,Set(fromext=${AMPUSER})
exten => _*21*89.,n,Set(toext=${EXTEN:4})
exten => _*21*89.,n,Set(DB(CF/${fromext})=${toext})
exten => _*21*89.,n,Set(STATE=BUSY)
exten => _*21*89.,n,Gosub(cf-on-s,sstate,1())exte
n => _*21*89.,n,Gosub(cf-on-s,lang-playback,1(hook_3))
exten => _*21*89.,n,Macro(hangupcall,)

3. Установка параллельной переадресации на мобильный, тут имеется в виду, что вызов будет поступать одновременно и на внутренний и на мобильный номер, соответственно статус Busy на внутреннем номере ставить не нужно:

exten => _*22*89.,1,Answer
exten => _*22*89.,n,Wait(1)
exten => _*22*89.,n,Macro(user-callerid,)
exten => _*22*89.,n,Set(fromext=${AMPUSER})
exten => _*22*89.,n,Set(toext=${EXTEN:4})
exten => _*22*89.,n,Set(DB(CFM/${fromext})=${toext})
exten => _*22*89.,n,Gosub(cf-on-s,lang-playback-m,1(hook_3))
exten => _*22*89.,n,Macro(hangupcall,)

4. Установка безусловной переадресации на группу (очередь), в данном сервисном, маской ограничиваем номера пулом номеров очередей или ring group:

exten => _*22*89.,1,Answer
exten => _*22*89.,n,Wait(1)
exten => _*22*89.,n,Macro(user-callerid,)
exten => _*22*89.,n,Set(fromext=${AMPUSER})
exten => _*22*89.,n,Set(toext=${EXTEN:4})
exten => _*22*89.,n,Set(DB(CFM/${fromext})=${toext})
exten => _*22*89.,n,Gosub(cf-on-s,lang-playback-m,1(hook_3))
exten => _*22*89.,n,Macro(hangupcall,)

Также сервисный снятия безусловной переадресации на группу:

exten => *30,1,Answer
exten => *30,n,Wait(1)
exten => *30,n,Macro(user-callerid,)
exten => *30,n,Set(fromext=${AMPUSER})
exten => *30,n,Noop(Deleting: CF/${fromext} ${DB_DELETE(CF/${fromext})})
exten => *30,n,Set(STATE=NOT_INUSE)
exten => *30,n,Gosub(cf-off-s,sstate,1())
exten => *30,n,Gosub(cf-off-s,lang-playback-g,1(hook_0))
exten => *30,n,Macro(hangupcall,)

И сервисный код отключения всех переадресаций:

exten => *20,1,Answer
exten => *20,n,Wait(1)
exten => *20,n,Macro(user-callerid,)
exten => *20,n,Set(fromext=${AMPUSER})
exten => *20,n,Noop(Deleting: CF/${fromext} ${DB_DELETE(CF/${fromext})})
exten => *20,n,Noop(Deleting: CFM/${fromext} ${DB_DELETE(CFM/${fromext})})
exten => *20,n,Set(STATE=NOT_INUSE)
exten => *20,n,Gosub(cf-off-s,sstate,1())
exten => *20,n,Gosub(cf-off-s,lang-playback-cancel,1(hook_0))ex
ten => *20,n,Macro(hangupcall,)
В зависимости от типа переадресации отправляем на свое голосовое сообщение в контексте

(lang-playback/lang-playback-cancel/lang-playback-g/lang-playback-m).

Однако это еще не все, если безусловные переадресации основываются на переадресации FreePBX, то параллельная переадресация работает несколько иначе, следовательно, для нее необходимо переделать вызовы на внутренние номера, через macro-dial-one.

В самом макросе необходимо изменить строку с dial, заменив ее на следующее:

exten => s,n,Set(ring_time=${ARG1});назначаем время дозвона по умолчанию
exten => s,n,ExecIf($[${DB_EXISTS(CFM/${ARG3})}]?Set(ring_time=60));время дозвона 60 секунд, если параллельная переадресация
exten => s,n,ExecIf($[${DB_EXISTS(CFM/${ARG3})} & !${DB_EXISTS(CF/${ARG3})}]?Dial(Local/${DB(CFM/${DEXTEN})}@outbound-allroutes&${DSTRING},${ring_time},${D_OPTIONS}b(func-apply-sipheaders^s^1)));параллельный вызов на внутренний и мобильный номер если установлена переадресация
exten => s,n,ExecIf($[!${DB_EXISTS(CFM/${ARG3})}]?Dial(${DSTRING},${ARG1},${D_OPTIONS}b(func-apply-sipheaders^s^1)))
Также необходимо дополнить строку после:
exten => s,n,GosubIf($["${DB(CF/${DEXTEN})}"!=""]?cf,1())

Добавив:

exten => s,n,GosubIf($["${DB(CF/${DEXTEN})}"="" & "${DB(CFM/${DEXTEN})}"=""]?cfm,1())

и сам exten:

exten => cfm,1,Set(CFAMPUSER=${IF($["${AMPUSER}"=""]?${CALLERID(number)}:${AMPUSER})})
exten => cfm,n,ExecIf($["${DB(CFM/${DEXTEN})}"="${CFAMPUSER}" | "${DB(CFM/${DEXTEN})}"="${REALCALLERIDNUM}" | "${CUT(CUT(BLINDTRANSFER,-,1),/,1)}" = "${DB(CFM/${DEXTEN})}" | "${DEXTEN}"="${DB(CFM/${DEXTEN})}"]?Return())
exten => cfm,n,ExecIf($["${DB(AMPUSER/${DEXTEN}/cfringtimer)}" != "0" & "${DB(AMPUSER/${DEXTEN}/cfringtimer)}" != ""]?Set(ARG1=${IF($["${DB(AMPUSER/${DEXTEN}/cfringtimer)}"="-1"]? : ${DB(AMPUSER/${DEXTEN}/cfringtimer)})}))
exten => cfm,n,ExecIf($["${DB(AMPUSER/${DEXTEN}/cfringtimer)}" == "0"]?Set(ARG1=${IF($["${DB(FREEPBXCONF/CFRINGTIMERDEFAULT)}"="-1"]? : ${DB(FREEPBXCONF/CFRINGTIMERDEFAULT)})}))
exten => cfm,n,Set(DEXTEN=${IF($["${CFIGNORE}"=""]?"${DB(CFM/${DEXTEN})}#": )})
exten => cfm,n,ExecIf($["${DEXTEN}"!=""]?Return())
exten => cfm,n,Set(DIALSTATUS=NOANSWER)
exten => cfm,n,Return()
Примеры установленных переадресаций
Примеры установленных переадресаций
Лог вызова на номер с параллельной переадресацией
Лог вызова на номер с параллельной переадресацией

Соответственно в данном примере переадресация параллельного мобильного номера срабатывает по всем исходящим маршрутам, чтобы это изменить можно изменить строку dial (например вносить ее в базу переадресации).

Переадресации на группу работают по принципу обычной переадресации, соответственно особого смысла в них нет, только если не настраивать строку dial для них отдельно, тогда картина будет аналогична параллельной переадресации.

5. Включение/Выключение записи разговоров на внутреннем номере.

Поскольку запись на внутреннем номере основывается на пункте в AstDB, то изменить ее довольно просто.

Сначала отобразим запись в БД для определенного номера:

Asterisk -rx 'database show AMPUSER/03911'

Нас интересуют пункты: /recording/, в частности in/out internal/external, соответственно входящие внутренние/внешние, исходящие внутренние/внешние. Чтобы отключить запись на внутреннем номере полностью, они должны быть в значении never (поскольку dontcare все равно зависит от предыдущего канала), для включения всех записей соответственно в force.

Установка будет выглядеть следующим образом:

exten => _*41*XXXX,1,GotoIf($[${DIALPLAN_EXISTS(ext-local,${EXTEN:4},1)} = 0]?end)
exten => _*41*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/in/external)=force)
exten => _*41*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/in/internal)=force)
exten => _*41*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/out/external)=force)
exten => _*41*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/out/internal)=force)
exten => _*41*XXXX,n(end),Macro(hangupcall,)

Снятие:

exten => _*40*XXXX,1,GotoIf($[${DIALPLAN_EXISTS(ext-local,${EXTEN:4},1)} = 0]?end)
exten => _*40*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/in/external)=dontcare)
exten => _*40*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/in/internal)=dontcare)
exten => _*40*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/out/external)=dontcare)
exten => _*40*XXXX,n,Set(DB(AMPUSER/${EXTEN:4}/recording/out/internal)=dontcare)
exten => _*40*XXXX,n(end),Macro(hangupcall,)

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

Желательно ограничивать возможность набирать данный сервисный код по маске номеров, например:
_*41*XXXX/_10XX
Отработка включения/выключения записи разговоров.
Отработка включения/выключения записи разговоров.
Подписаться
Уведомление о
guest
0 Комментарий
Inline Feedbacks
View all comments

Остались вопросы?

Я - Компаниец Никита, менеджер компании Voxlink. Хотите уточнить детали или готовы оставить заявку? Укажите номер телефона, я перезвоню в течение 3-х секунд.

VoIP оборудование

ближайшие курсы

ближайшие Вебинары

ONLINE

10 доводов в пользу Asterisk

Распространяется бесплатно.

Asterisk – программное обеспечение с открытым исходным кодом, распространяется по лицензии GPL. Следовательно, установив один раз Asterisk вам не придется дополнительно платить за новых абонентов, подключение новых транков, расширение функционала и прочие лицензии. Это приближает стоимость владения станцией к нулю.

Безопасен в использовании.

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

Надежен в эксплуатации.

Время работы серверов некоторых наших клиентов исчисляется годами. Это значит, что Asterisk работает несколько лет, ему не требуются никакие перезагрузки или принудительные отключения. А еще это говорит о том, что в районе отличная ситуация с электроэнергией, но это уже не заслуга Asterisk.

Гибкий в настройке.

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

Имеет огромный функционал.

Во многом именно Asterisk показал какой должна быть современная телефонная станция. За многие годы развития функциональность Asterisk расширилась, а все основные возможности по-прежнему доступны бесплатно сразу после установки.

Интегрируется с любыми системами.

То, что Asterisk не умеет сам, он позволяет реализовать за счет интеграции. Это могут быть интеграции с коммерческими телефонными станциями, CRM, ERP системами, биллингом, сервисами колл-трекинга, колл-бэка и модулями статистики и аналитики.

Позволяет телефонизировать офис за считанные часы.

В нашей практике были проекты, реализованные за один рабочий день. Это значит, что утром к нам обращался клиент, а уже через несколько часов он пользовался новой IP-АТС. Безусловно, такая скорость редкость, ведь АТС – инструмент зарабатывания денег для многих компаний и спешка во внедрении не уместна. Но в случае острой необходимости Asterisk готов к быстрому старту.

Отличная масштабируемость.

Очень утомительно постоянно возвращаться к одному и тому же вопросу. Такое часто бывает в случае некачественного исполнения работ или выбора заведомо неподходящего бизнес-решения. С Asterisk точно не будет такой проблемы! Телефонная станция, построенная на Asterisk может быть масштабируема до немыслимых размеров. Главное – правильно подобрать оборудование.

Повышает управляемость бизнеса.

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

Снижает расходы на связь.

Связь между внутренними абонентами IP-АТС бесплатна всегда, независимо от их географического расположения. Также к Asterisk можно подключить любых операторов телефонии, в том числе GSM сим-карты и настроить маршрутизацию вызовов по наиболее выгодному тарифу. Всё это позволяет экономить с первых минут пользования станцией.