Пользователи за АТС

Введение

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

То есть, например, в системе есть учетки dep1 (номер 7777), dep2 (номер 8888). Звонит 11 из под dep1. набирает 888815, необходимо этот звонок направить в учетку dep2, передав ему номер 15 в request-uri. При этом From номер должен быть 777711, так чтобы обратный вызов был возможен. А DisplayName должен ходить насквозь, поскольку это не юзер.

Кейс решался в рамках задач #86, #189 в 2017 году.

Особенности

На атску может позвонить и любой другой абонент, в этом случае его обратный номер рассчитывается стандартно. И сама АТСка может позвонить любому другому существующему абоненту системы. То есть не обязательно из АТС в другую АТС. Таким образом разделяется реализация маршрутизации (выбора учетки и номера-назначения), и представления (построения from отправляемого INVITE-запроса).

Решение задачи маршрутизации

Вводится тип action = internalpbx для vectorrule. После модификации правила ролью b2b производится поиск учетной записи по принципу поиска featurecode – по максимальному совпадению префиксов (используется longmatch). Остаток номера считается внутренним номером. B2BUA фактически организует обычный внутренний звонок, пользуясь правилами подмены, там requesturi уже исправлен в ходе поиска и обработки правил маршрутизации.

Решение задачи представления

Подстановка From при звонке с АТС. В этом случае action=internalpbx для vectorrule не используется. Признаком звонка с внутренней АТС считается отличие username в заголовке From входящего INVITE-запроса от реальной учетной записи, зарегистрированной в системе.

Реализуется в модуле r_sip_representative. Однако b2bua_router_utils используют альтернативную точку входа в representative, передавая Request. Это нужно чтобы найти реальную учетную запись sipuser. Стандартный интерфейсный метод не дает информации о прочих полях запроса, поэтому для B2BUA делается специальный метод. В нем идет сравнение username из заголовка AUTH и номера(username) из заголовка FROM.

Если заголовок AUTH не обнаружен, то это означает, что во FROM всё хорошо, система пропустила запрос, посчитав его авторизованным, и, значит, FROM.username совпадает с AUTH.username. Представление действует как обычно.

Если AUTH.username = FROM.username, то представление действует как обычно.

Если же AUTH.username отличается от FROM.username, то реальная учетка, от имени которой идет звонок, ищется исходя из AUTH.username (взамен FROM.username), вычисляется её номер и уходит в любом случае на поиск представления, даже если звонок из того же домена. В поиск представления в доменный центр отправляется from-номер = SipUserNum + FromNum. То есть в примере выше – 888811. Правила представлений могут модифицировать по своему усмотрению этот номер. А если не обнаружены или не изменили, то он в таком виде подставляется во FROM отправляемого инвайта.

Значение displayname при этом (если From.username не обнаруживает учетки) пробрасывается насквозь.

Модификация DisplayName

При обслуживании звонка с устройства, зарегистрированное под учетной записью sipuser, значение ее поля name подставляется в качестве displayname в поле From отправляемого запроса получателю. Поле name поддерживает указание модификаторов.

  • {D} – подставить исходный DisplayName из входящего запроса.

  • {d} – то же в lowercase.

  • {U} – подставить исходный UserName из входящего запроса.

  • {u} – то же в lowercase.

  • {N} и {n} - подставить сформированный полный номер инициатора запроса (склеенные номера sipuser и extension).

  • {A} - подставлять displayname из учетной записи контакта адресной книги, найденного по полному номеру инициатора с extension. Если контакт не найден, то подставляется пустота. Реализовано по задаче #366.

  • {a} - то же в lowercase.

  • {E} – подставить пустоту.

  • любой другой символ захватывается в результат в соответствующую ему позицию.

Например, значение может указано таким: "Peter - {D} - {N}", соответственно вместо модификаторов подставятся указанные выше значения из контекста текущего звонка.

Модификаторы поля displayname применяются при пробросе INVITE-запроса на второе плечо, при пробросе ответа на инициатора, а также при обслуживании re-INVITE.

Подмена значений from/extension

Нижестоящая АТС (Б) подключена по описанной выше схеме к учетной записи с номером 1234567, при этом ее нужно вызывать как 1234567X, то есть добавляя к номеру учетки набранный номер. Однако, сама АТС шлет звонки от 1234567X.

При применении в чистом виде вышеописанной модели склейки номера и extension, АТС будет вызываться по номеру X, а от нее приходящие звонки будут поступать на анализ в систему с номером 12345671234567X.

В реализацию поступила концепция, когда сохраняется принцип "Номер учетки" + "номер extension", однако extension подвергается модификации. В sipuser вставляются поля

  • opts.modextin, применяемое при входящем звонке с учетки в любом случае;

  • opts.modextout, применяемое к вычисленному extension при звонке internalpbx.

По умолчанию modextin содержит пустую строку, так что мимо модификатора идет отказ от использования extension. А modextout по умолчанию содержит "*", то есть звонок уходит на вычисленный extension по остатку после long hunting.

Если же в modextin указано нечто, то оно применяется к тому полю, которое отличается от учетной записи (может быть From username или Contact username, включая пустое значение), либо к From username, если они оба совпадают. В модификаторе допускается использование X/X, *, {U} – логин sipuser, {N} – номер sipuser, {F} – from username, {C} – contact username, regex-последовательностей.

Итого для modextin (входящие звонки с учетки в систему):

  • Чтобы входящий работал без extension как обычный sipuser телефон, не нужно указывать modextin, или указывать пустым (""). From подставится номером учетной записи.

  • Чтобы работать по прежней схеме (доклейка extension к username) – нужно указывать modextin = "*". Однако есть два отличия от прежней схемы: (а) не будет проверки на числовое значение расширения, (б) если contact username и from username совпадают с username учетки, то на выходе получится From = конкатенации sipuser phonenumber и значения из From username. Итого From подставится склейкой номера учетной записи и преимущественно отличающегося от sipuser логина значения из From или Contact. Если не отличаются, то к номеру учетной записи добавится From из текущего запроса. Такое поведение в частности позволит нормально обслуживать extension номера, совпадающие с логином самой учетки системы «Era».

  • Чтобы отработать схему c нижестоящей АТС (Б), необходимо в качестве modextin указать "/XXXXXXX/X". При этом поскольку From username (12345678) фактически отличается от учетки (1234567), то взяв его за основу и вырезав первые семь символов, после склейки с номером учетки sipuser получится желанная комбинация 12345678.

  • Если про подключаемое устройство (АТС) известно, где именно оно размещает информацию об extension номере, то ее можно указать в modextin явно, например {C} – к номеру учетки sipuser доклеится значение username из заголовка Contact INVITE-запроса.

Доступны и последовательности регулярок для модификации преимущественно отличающего значения. Даже если это значение пустое (в частности в заголовке Contact username пусто), то серией применяемых regex replace можно обработать эту ситуацию. А если не пустое и совпадает с номером учетки, то это тоже легко описывается регулярным выражением. Первая обрабатывает пустоту, вторая обрабатывает номер.

Итого для modextout (исходящие с учетки):

  • Чтобы internalpbx вызывать на само имя sipuser и банить extension, нужно в modextout указать пустоту. Но тогда зачем internalpbx? Лучше использовать классический internal. Этот режим оставлен для общности модификаторов, но результат модификации обрабатывается особо.

  • Чтобы пробросить вычисленный extension после long hunting - нужно оставить дефолт (установить) – "*". То есть пробросит 123, если учетка с номером 13 и набрано 13123.

  • Чтобы решить проблему вызовов нижестоящей АТС (Б) – при звонке на 12345678 (учетка 1234567, вычисленный extension 8), нужно в качестве modextout указать 1234567X или 567X. Возможна последовательность регулярок.

  • Если представить проблему, обратную описанной нижестоящей АТС (Б), (учетка 1234, набирается 12345678, а он ждет 8), то /XXX/X. То есть от вычисленного 5678 вырежет 8.

При этом всем к каждому URI после разрешения в номерном плане и регистраре применится свой модификатор в соответствии с той учеткой sipuser, которой он соответствует.