feat(inbound): add CID name prefix support per trunk and per inbound route
This commit is contained in:
1 parent
9518e10616
commit
8804501c42
5 files changed
+188
-12
No files matched your search
+143
-8
@@ -1309,16 +1309,19 @@ class ConfigGenerator
|
||||
|
||||
// 2b-bis. Contextes standards FreePBX / Passerelles FXO : [from-trunk] et [from-pstn]
|
||||
$lines[] = "[from-trunk]";
|
||||
$lines[] = "exten => _[+*#0-9a-zA-Z].,1,NoOp(Appel entrant trunk [from-trunk] EXTEN=\${EXTEN} Appelant=\${CALLERID(num)})";
|
||||
$lines[] = "exten => _[+*#0-9a-zA-Z].,1,NoOp(Appel entrant trunk [from-trunk] EXTEN=\${EXTEN} Endpoint=\${CHANNEL(endpoint)} Appelant=\${CALLERID(num)})";
|
||||
$lines[] = " same => n,ExecIf(\$[\"\${CALLERID(num):0:3}\" = \"+33\"]?Set(CALLERID(num)=0\${CALLERID(num):3}))";
|
||||
$lines[] = " same => n,ExecIf(\$[\"\${CALLERID(num):0:4}\" = \"0033\"]?Set(CALLERID(num)=0\${CALLERID(num):4}))";
|
||||
$lines[] = " same => n,GotoIf(\$[\"\${DB(blacklist/\${CALLERID(num)})}\" != \"\"]?app-blacklisted,s,1)";
|
||||
$lines[] = " same => n,ExecIf(\$[\"\${EXTEN:0:3}\" = \"+33\"]?Goto(from-external,0\${EXTEN:3},1))";
|
||||
$lines[] = " same => n,ExecIf(\$[\"\${EXTEN:0:3}\" = \"+33\"]?Set(EXTEN=0\${EXTEN:3}))";
|
||||
$lines[] = " same => n,GotoIf(\$[\"\${DIALPLAN_EXISTS(from-trunk-\${CHANNEL(endpoint)},\${EXTEN},1)}\" = \"1\"]?from-trunk-\${CHANNEL(endpoint)},\${EXTEN},1)";
|
||||
$lines[] = " same => n,GotoIf(\$[\"\${DIALPLAN_EXISTS(from-trunk-\${CHANNEL(endpoint)},s,1)}\" = \"1\"]?from-trunk-\${CHANNEL(endpoint)},s,1)";
|
||||
$lines[] = " same => n,Goto(from-external,\${EXTEN},1)";
|
||||
$lines[] = "exten => s,1,NoOp(Appel entrant trunk [from-trunk] sur s - Appelant=\${CALLERID(num)})";
|
||||
$lines[] = "exten => s,1,NoOp(Appel entrant trunk [from-trunk] sur s - Endpoint=\${CHANNEL(endpoint)} Appelant=\${CALLERID(num)})";
|
||||
$lines[] = " same => n,ExecIf(\$[\"\${CALLERID(num):0:3}\" = \"+33\"]?Set(CALLERID(num)=0\${CALLERID(num):3}))";
|
||||
$lines[] = " same => n,ExecIf(\$[\"\${CALLERID(num):0:4}\" = \"0033\"]?Set(CALLERID(num)=0\${CALLERID(num):4}))";
|
||||
$lines[] = " same => n,GotoIf(\$[\"\${DB(blacklist/\${CALLERID(num)})}\" != \"\"]?app-blacklisted,s,1)";
|
||||
$lines[] = " same => n,GotoIf(\$[\"\${DIALPLAN_EXISTS(from-trunk-\${CHANNEL(endpoint)},s,1)}\" = \"1\"]?from-trunk-\${CHANNEL(endpoint)},s,1)";
|
||||
$lines[] = " same => n,Goto(from-external,s,1)";
|
||||
$lines[] = "";
|
||||
$lines[] = "[from-pstn]";
|
||||
@@ -1326,6 +1329,30 @@ class ConfigGenerator
|
||||
$lines[] = "exten => s,1,Goto(from-trunk,s,1)";
|
||||
$lines[] = "";
|
||||
|
||||
// 2b-ter. Contextes dédiés par Trunk pour isolation des routes et préfixe CID
|
||||
foreach ($trunks as $t) {
|
||||
$epName = ($t['registration_mode'] === 'receive' && trim((string)($t['username'] ?? '')) !== '')
|
||||
? trim((string)$t['username'])
|
||||
: trim((string)$t['name']);
|
||||
if ($epName === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$trunkCtx = "from-trunk-{$epName}";
|
||||
$lines[] = "; --- Contexte Entrant dédié au Trunk {$t['name']} (Endpoint: {$epName}) ---";
|
||||
$lines[] = "[{$trunkCtx}]";
|
||||
foreach ($this->generateTrunkInboundRoutes($t, $mohSoundsMap, "trunk_{$t['id']}") as $l) {
|
||||
$lines[] = $l;
|
||||
}
|
||||
$lines[] = "";
|
||||
if ($t['name'] !== $epName) {
|
||||
$lines[] = "[from-trunk-{$t['name']}]";
|
||||
$lines[] = "exten => _[+*#0-9a-zA-Z].,1,Goto({$trunkCtx},\${EXTEN},1)";
|
||||
$lines[] = "exten => s,1,Goto({$trunkCtx},s,1)";
|
||||
$lines[] = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Contexte pour appels rejetés par la liste noire
|
||||
$lines[] = "[app-blacklisted]";
|
||||
$lines[] = "exten => s,1,NoOp(Appelant \${CALLERID(num)} bloque par la liste noire)";
|
||||
@@ -1352,6 +1379,7 @@ class ConfigGenerator
|
||||
$setMohLines[] = " same => n,Set(CHANNEL(musicclass)={$trunkMohClass})";
|
||||
}
|
||||
|
||||
$trunkCidPrefix = trim((string)($t['cid_name_prefix'] ?? ''));
|
||||
$routes = self::normalizeInboundRoutes((string)($t['did_routes_json'] ?? '[]'));
|
||||
$routeIdx = 0;
|
||||
foreach ($routes as $rule) {
|
||||
@@ -1382,12 +1410,12 @@ class ConfigGenerator
|
||||
}
|
||||
$lines[] = "; Inbound Route [{$desc}] ({$t['name']}) : DID={$didPattern} / Appelant=Any{$timeInfo}";
|
||||
$lines[] = "exten => {$didPattern},1,NoOp(Inbound [{$desc}] Appelant=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_did") as $rl) {
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_did", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
if ($isAnyDid) {
|
||||
$lines[] = "exten => s,1,NoOp(Inbound [{$desc}] sur s Appelant=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_s") as $rl) {
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_s", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
}
|
||||
@@ -1409,12 +1437,12 @@ class ConfigGenerator
|
||||
foreach ($cidVariants as $cidVar) {
|
||||
$vIdx++;
|
||||
$lines[] = "exten => {$didPattern}/{$cidVar},1,NoOp(Inbound Filter [{$desc}] CID=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_cid_{$vIdx}") as $rl) {
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_cid_{$vIdx}", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
if ($isAnyDid) {
|
||||
$lines[] = "exten => s/{$cidVar},1,NoOp(Inbound Filter [{$desc}] sur s CID=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_scid_{$vIdx}") as $rl) {
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$t['id']}_{$routeIdx}_scid_{$vIdx}", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
}
|
||||
@@ -1918,6 +1946,7 @@ class ConfigGenerator
|
||||
'did' => $did,
|
||||
'description' => $desc ?: ($cid !== 'Any' ? "Filtre {$cid}" : "Route {$did}"),
|
||||
'destination' => $dest,
|
||||
'cid_prefix' => trim((string)($item['cid_prefix'] ?? '')),
|
||||
'time_condition_enabled' => (int)$timeCondition,
|
||||
'time_start' => $timeStart,
|
||||
'time_finish' => $timeFinish,
|
||||
@@ -1950,7 +1979,106 @@ class ConfigGenerator
|
||||
return $out;
|
||||
}
|
||||
|
||||
private function buildInboundRouteLines(array $rule, array $setMohLines, string $desc, string $tagId): array
|
||||
private function generateTrunkInboundRoutes(array $t, array $mohSoundsMap, string $tagPrefix): array
|
||||
{
|
||||
$lines = [];
|
||||
$mohSoundId = (int)($t['moh_sound_id'] ?? 0);
|
||||
$trunkMohClass = ($mohSoundId > 0 && isset($mohSoundsMap[$mohSoundId]))
|
||||
? 'moh-sound-' . $mohSoundsMap[$mohSoundId]['slug']
|
||||
: 'default';
|
||||
|
||||
$setMohLines = [];
|
||||
if ($trunkMohClass !== 'default') {
|
||||
$setMohLines[] = " same => n,Set(__MOHCLASS={$trunkMohClass})";
|
||||
$setMohLines[] = " same => n,Set(CHANNEL(musicclass)={$trunkMohClass})";
|
||||
}
|
||||
|
||||
$trunkCidPrefix = trim((string)($t['cid_name_prefix'] ?? ''));
|
||||
$routes = self::normalizeInboundRoutes((string)($t['did_routes_json'] ?? '[]'));
|
||||
$routeIdx = 0;
|
||||
$hasAnyRoute = false;
|
||||
|
||||
foreach ($routes as $rule) {
|
||||
$routeIdx++;
|
||||
$cidRaw = trim((string)($rule['cid'] ?? 'Any'));
|
||||
$didRaw = trim((string)($rule['did'] ?? 'Any'));
|
||||
$desc = trim((string)($rule['description'] ?? 'Route entrante'));
|
||||
$dest = trim((string)($rule['destination'] ?? $t['inbound_dest'] ?? 'hangup'));
|
||||
|
||||
$isAnyDid = ($didRaw === '' || strcasecmp($didRaw, 'any') === 0 || $didRaw === '*' || $didRaw === '_X.');
|
||||
$isAnyCid = ($cidRaw === '' || strcasecmp($cidRaw, 'any') === 0 || $cidRaw === '*');
|
||||
|
||||
$didPattern = $isAnyDid ? '_X.' : preg_replace('/[^0-9+XZN._\[\]\-]/', '', $didRaw);
|
||||
if ($didPattern === '') {
|
||||
$didPattern = '_X.';
|
||||
}
|
||||
|
||||
$timeInfo = !empty($rule['time_condition_enabled'])
|
||||
? " [Horaires: {$rule['time_start']}-{$rule['time_finish']} {$rule['weekdays']}]"
|
||||
: "";
|
||||
|
||||
if ($isAnyCid) {
|
||||
if ($didPattern === '_X.') {
|
||||
$hasAnyRoute = true;
|
||||
}
|
||||
$lines[] = "; Inbound Route [{$desc}] : DID={$didPattern} / Appelant=Any{$timeInfo}";
|
||||
$lines[] = "exten => {$didPattern},1,NoOp(Inbound [{$desc}] Appelant=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$tagPrefix}_{$routeIdx}_did", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
if ($isAnyDid) {
|
||||
$lines[] = "exten => s,1,NoOp(Inbound [{$desc}] sur s Appelant=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$tagPrefix}_{$routeIdx}_s", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$cidClean = preg_replace('/[^0-9+XZN._\[\]\-]/', '', $cidRaw);
|
||||
if ($cidClean === '') {
|
||||
continue;
|
||||
}
|
||||
$cidVariants = [$cidClean];
|
||||
if (str_starts_with($cidClean, '_0') && strlen($cidClean) > 2 && $cidClean[2] !== '0') {
|
||||
$rest = substr($cidClean, 2);
|
||||
$cidVariants[] = '_0033' . $rest;
|
||||
$cidVariants[] = '_+33' . $rest;
|
||||
}
|
||||
|
||||
$lines[] = "; Inbound Route Filtrage Appelant [{$desc}] : DID={$didPattern} / CID={$cidClean}{$timeInfo}";
|
||||
$vIdx = 0;
|
||||
foreach ($cidVariants as $cidVar) {
|
||||
$vIdx++;
|
||||
$lines[] = "exten => {$didPattern}/{$cidVar},1,NoOp(Inbound Filter [{$desc}] CID=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$tagPrefix}_{$routeIdx}_cid_{$vIdx}", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
if ($isAnyDid) {
|
||||
$lines[] = "exten => s/{$cidVar},1,NoOp(Inbound Filter [{$desc}] sur s CID=\${CALLERID(num)})";
|
||||
foreach ($this->buildInboundRouteLines($rule, $setMohLines, $desc, "{$tagPrefix}_{$routeIdx}_scid_{$vIdx}", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$hasAnyRoute) {
|
||||
$defaultDest = trim((string)($t['inbound_dest'] ?? 'hangup')) ?: 'hangup';
|
||||
$lines[] = "; Fallback Inbound Trunk {$t['name']}";
|
||||
$lines[] = "exten => _X.,1,NoOp(Inbound Trunk {$t['name']} par defaut vers \${EXTEN})";
|
||||
foreach ($this->buildInboundRouteLines(['destination' => $defaultDest], $setMohLines, "Fallback {$t['name']}", "{$tagPrefix}_fb", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
$lines[] = "exten => s,1,NoOp(Inbound Trunk {$t['name']} sur s)";
|
||||
foreach ($this->buildInboundRouteLines(['destination' => $defaultDest], $setMohLines, "Fallback {$t['name']}", "{$tagPrefix}_fbs", $trunkCidPrefix) as $rl) {
|
||||
$lines[] = $rl;
|
||||
}
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
private function buildInboundRouteLines(array $rule, array $setMohLines, string $desc, string $tagId, string $trunkCidPrefix = ''): array
|
||||
{
|
||||
$dest = trim((string)($rule['destination'] ?? 'hangup'));
|
||||
$timeEnabled = !empty($rule['time_condition_enabled']);
|
||||
@@ -1965,6 +2093,13 @@ class ConfigGenerator
|
||||
$out[] = $sml;
|
||||
}
|
||||
|
||||
$cidPrefix = trim((string)($rule['cid_prefix'] ?? '')) ?: $trunkCidPrefix;
|
||||
if ($cidPrefix !== '' && !str_starts_with($dest, 'terminate-') && $dest !== 'hangup' && $dest !== 'busy' && $dest !== 'congestion') {
|
||||
$formattedPrefix = rtrim($cidPrefix) . ' ';
|
||||
$out[] = " same => n,ExecIf(\$[\"\${CALLERID(name)}\" = \"\"]?Set(CALLERID(name)=\${CALLERID(num)}))";
|
||||
$out[] = " same => n,Set(CALLERID(name)={$formattedPrefix}\${CALLERID(name)})";
|
||||
}
|
||||
|
||||
if ($timeEnabled) {
|
||||
$tag = "tc_{$tagId}";
|
||||
$out[] = " same => n,GotoIfTime({$timeRange},{$weekdays},*,*?{$tag}_open)";
|
||||
|
||||
@@ -163,6 +163,7 @@ class Database
|
||||
did_routes_json TEXT NOT NULL DEFAULT '{}',
|
||||
outbound_prefix VARCHAR(32) NOT NULL DEFAULT '',
|
||||
custom_endpoint_params TEXT NOT NULL DEFAULT '',
|
||||
cid_name_prefix VARCHAR(64) NOT NULL DEFAULT '',
|
||||
enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0, 1)),
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
@@ -576,6 +577,7 @@ class Database
|
||||
'custom_reg_params' => "TEXT NOT NULL DEFAULT ''",
|
||||
'custom_aor_params' => "TEXT NOT NULL DEFAULT ''",
|
||||
'moh_sound_id' => "INTEGER NOT NULL DEFAULT 0",
|
||||
'cid_name_prefix' => "VARCHAR(64) NOT NULL DEFAULT ''",
|
||||
];
|
||||
|
||||
foreach ($extraColumns as $colName => $colDef) {
|
||||
|
||||
Reference in new issue
Block a user