Compare commits
1
Commits
v1.6.6
..
18368027ee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18368027ee |
No files matched your search
@@ -38,3 +38,8 @@ Thumbs.db
|
|||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
# Environnement local de développement (exclu de Git)
|
||||||
|
/.dev
|
||||||
|
/.env
|
||||||
|
/.env.local
|
||||||
|
|
||||||
+4
-6
@@ -1155,7 +1155,6 @@ try {
|
|||||||
$send_rpid = (int)!empty($payload['send_rpid']);
|
$send_rpid = (int)!empty($payload['send_rpid']);
|
||||||
$send_diversion = isset($payload['send_diversion']) ? (int)!empty($payload['send_diversion']) : 1;
|
$send_diversion = isset($payload['send_diversion']) ? (int)!empty($payload['send_diversion']) : 1;
|
||||||
$trust_id_inbound = isset($payload['trust_id_inbound']) ? (int)!empty($payload['trust_id_inbound']) : 1;
|
$trust_id_inbound = isset($payload['trust_id_inbound']) ? (int)!empty($payload['trust_id_inbound']) : 1;
|
||||||
$trust_id_outbound = isset($payload['trust_id_outbound']) ? (int)!empty($payload['trust_id_outbound']) : 1;
|
|
||||||
$max_retries = max(0, (int)($payload['max_retries'] ?? 10000));
|
$max_retries = max(0, (int)($payload['max_retries'] ?? 10000));
|
||||||
$forbidden_retry_interval = max(0, (int)($payload['forbidden_retry_interval'] ?? 600));
|
$forbidden_retry_interval = max(0, (int)($payload['forbidden_retry_interval'] ?? 600));
|
||||||
$fatal_retry_interval = max(0, (int)($payload['fatal_retry_interval'] ?? 0));
|
$fatal_retry_interval = max(0, (int)($payload['fatal_retry_interval'] ?? 0));
|
||||||
@@ -1229,7 +1228,6 @@ try {
|
|||||||
':send_rpid' => $send_rpid,
|
':send_rpid' => $send_rpid,
|
||||||
':send_diversion' => $send_diversion,
|
':send_diversion' => $send_diversion,
|
||||||
':trust_id_inbound' => $trust_id_inbound,
|
':trust_id_inbound' => $trust_id_inbound,
|
||||||
':trust_id_outbound' => $trust_id_outbound,
|
|
||||||
':codecs' => $codecs,
|
':codecs' => $codecs,
|
||||||
':dtmf_mode' => $dtmf_mode,
|
':dtmf_mode' => $dtmf_mode,
|
||||||
':media_encryption' => $media_encryption,
|
':media_encryption' => $media_encryption,
|
||||||
@@ -1271,7 +1269,7 @@ try {
|
|||||||
fatal_retry_interval = :fatal_retry_interval, line_support = :line_support,
|
fatal_retry_interval = :fatal_retry_interval, line_support = :line_support,
|
||||||
from_user = :from_user, from_domain = :from_domain, outbound_callerid = :outbound_callerid,
|
from_user = :from_user, from_domain = :from_domain, outbound_callerid = :outbound_callerid,
|
||||||
send_pai = :send_pai, send_rpid = :send_rpid, send_diversion = :send_diversion,
|
send_pai = :send_pai, send_rpid = :send_rpid, send_diversion = :send_diversion,
|
||||||
trust_id_inbound = :trust_id_inbound, trust_id_outbound = :trust_id_outbound, codecs = :codecs, dtmf_mode = :dtmf_mode,
|
trust_id_inbound = :trust_id_inbound, codecs = :codecs, dtmf_mode = :dtmf_mode,
|
||||||
media_encryption = :media_encryption, nat_symmetric = :nat_symmetric,
|
media_encryption = :media_encryption, nat_symmetric = :nat_symmetric,
|
||||||
direct_media = :direct_media, qualify_frequency = :qualify_frequency,
|
direct_media = :direct_media, qualify_frequency = :qualify_frequency,
|
||||||
max_channels = :max_channels, timers = :timers, language = :language,
|
max_channels = :max_channels, timers = :timers, language = :language,
|
||||||
@@ -1293,7 +1291,7 @@ try {
|
|||||||
registration_mode, register, server_uri, client_uri, contact_user, expiration, retry_interval,
|
registration_mode, register, server_uri, client_uri, contact_user, expiration, retry_interval,
|
||||||
max_retries, forbidden_retry_interval, fatal_retry_interval, line_support,
|
max_retries, forbidden_retry_interval, fatal_retry_interval, line_support,
|
||||||
from_user, from_domain, outbound_callerid, send_pai, send_rpid, send_diversion,
|
from_user, from_domain, outbound_callerid, send_pai, send_rpid, send_diversion,
|
||||||
trust_id_inbound, trust_id_outbound, codecs, dtmf_mode, media_encryption, nat_symmetric, direct_media,
|
trust_id_inbound, codecs, dtmf_mode, media_encryption, nat_symmetric, direct_media,
|
||||||
qualify_frequency, max_channels, timers, language, rtp_keepalive, t38_udptl,
|
qualify_frequency, max_channels, timers, language, rtp_keepalive, t38_udptl,
|
||||||
fax_detect, inband_progress, match_ips, context, inbound_dest, did_routes_json,
|
fax_detect, inband_progress, match_ips, context, inbound_dest, did_routes_json,
|
||||||
outbound_prefix, custom_endpoint_params, custom_reg_params, custom_aor_params, moh_sound_id,
|
outbound_prefix, custom_endpoint_params, custom_reg_params, custom_aor_params, moh_sound_id,
|
||||||
@@ -1303,7 +1301,7 @@ try {
|
|||||||
:registration_mode, :register, :server_uri, :client_uri, :contact_user, :expiration, :retry_interval,
|
:registration_mode, :register, :server_uri, :client_uri, :contact_user, :expiration, :retry_interval,
|
||||||
:max_retries, :forbidden_retry_interval, :fatal_retry_interval, :line_support,
|
:max_retries, :forbidden_retry_interval, :fatal_retry_interval, :line_support,
|
||||||
:from_user, :from_domain, :outbound_callerid, :send_pai, :send_rpid, :send_diversion,
|
:from_user, :from_domain, :outbound_callerid, :send_pai, :send_rpid, :send_diversion,
|
||||||
:trust_id_inbound, :trust_id_outbound, :codecs, :dtmf_mode, :media_encryption, :nat_symmetric, :direct_media,
|
:trust_id_inbound, :codecs, :dtmf_mode, :media_encryption, :nat_symmetric, :direct_media,
|
||||||
:qualify_frequency, :max_channels, :timers, :language, :rtp_keepalive, :t38_udptl,
|
:qualify_frequency, :max_channels, :timers, :language, :rtp_keepalive, :t38_udptl,
|
||||||
:fax_detect, :inband_progress, :match_ips, :context, :inbound_dest, :did_routes_json,
|
:fax_detect, :inband_progress, :match_ips, :context, :inbound_dest, :did_routes_json,
|
||||||
:outbound_prefix, :custom_endpoint_params, :custom_reg_params, :custom_aor_params, :moh_sound_id,
|
:outbound_prefix, :custom_endpoint_params, :custom_reg_params, :custom_aor_params, :moh_sound_id,
|
||||||
@@ -1320,7 +1318,7 @@ try {
|
|||||||
fatal_retry_interval = excluded.fatal_retry_interval, line_support = excluded.line_support,
|
fatal_retry_interval = excluded.fatal_retry_interval, line_support = excluded.line_support,
|
||||||
from_user = excluded.from_user, from_domain = excluded.from_domain, outbound_callerid = excluded.outbound_callerid,
|
from_user = excluded.from_user, from_domain = excluded.from_domain, outbound_callerid = excluded.outbound_callerid,
|
||||||
send_pai = excluded.send_pai, send_rpid = excluded.send_rpid, send_diversion = excluded.send_diversion,
|
send_pai = excluded.send_pai, send_rpid = excluded.send_rpid, send_diversion = excluded.send_diversion,
|
||||||
trust_id_inbound = excluded.trust_id_inbound, trust_id_outbound = excluded.trust_id_outbound, codecs = excluded.codecs, dtmf_mode = excluded.dtmf_mode,
|
trust_id_inbound = excluded.trust_id_inbound, codecs = excluded.codecs, dtmf_mode = excluded.dtmf_mode,
|
||||||
media_encryption = excluded.media_encryption, nat_symmetric = excluded.nat_symmetric,
|
media_encryption = excluded.media_encryption, nat_symmetric = excluded.nat_symmetric,
|
||||||
direct_media = excluded.direct_media, qualify_frequency = excluded.qualify_frequency,
|
direct_media = excluded.direct_media, qualify_frequency = excluded.qualify_frequency,
|
||||||
max_channels = excluded.max_channels, timers = excluded.timers, language = excluded.language,
|
max_channels = excluded.max_channels, timers = excluded.timers, language = excluded.language,
|
||||||
|
|||||||
@@ -2355,7 +2355,6 @@ function openTrunkModal(trunk = null) {
|
|||||||
form.elements['send_rpid'].checked = trunk ? Number(trunk.send_rpid ?? 0) === 1 : false;
|
form.elements['send_rpid'].checked = trunk ? Number(trunk.send_rpid ?? 0) === 1 : false;
|
||||||
form.elements['send_diversion'].checked = trunk ? Number(trunk.send_diversion ?? 1) === 1 : true;
|
form.elements['send_diversion'].checked = trunk ? Number(trunk.send_diversion ?? 1) === 1 : true;
|
||||||
form.elements['trust_id_inbound'].checked = trunk ? Number(trunk.trust_id_inbound ?? 1) === 1 : true;
|
form.elements['trust_id_inbound'].checked = trunk ? Number(trunk.trust_id_inbound ?? 1) === 1 : true;
|
||||||
form.elements['trust_id_outbound'].checked = trunk ? Number(trunk.trust_id_outbound ?? 1) === 1 : true;
|
|
||||||
|
|
||||||
// Onglet 3 : Codecs, NAT, Timers, T.38 & Identify
|
// Onglet 3 : Codecs, NAT, Timers, T.38 & Identify
|
||||||
form.elements['codecs'].value = trunk ? (trunk.codecs || 'alaw,ulaw,g722') : 'alaw,ulaw,g722';
|
form.elements['codecs'].value = trunk ? (trunk.codecs || 'alaw,ulaw,g722') : 'alaw,ulaw,g722';
|
||||||
@@ -3789,8 +3788,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
payload.send_pai = form.elements['send_pai'].checked ? 1 : 0;
|
payload.send_pai = form.elements['send_pai'].checked ? 1 : 0;
|
||||||
payload.send_rpid = form.elements['send_rpid'].checked ? 1 : 0;
|
payload.send_rpid = form.elements['send_rpid'].checked ? 1 : 0;
|
||||||
payload.send_diversion = form.elements['send_diversion'].checked ? 1 : 0;
|
payload.send_diversion = form.elements['send_diversion'].checked ? 1 : 0;
|
||||||
payload.trust_id_inbound = form.elements['trust_id_inbound'].checked ? 1 : 0;
|
payload.trust_id_inbound = form.elements['trust_id_inbound'].checked ? 1 : 0;
|
||||||
payload.trust_id_outbound = form.elements['trust_id_outbound'].checked ? 1 : 0;
|
|
||||||
payload.nat_symmetric = form.elements['nat_symmetric'].checked ? 1 : 0;
|
payload.nat_symmetric = form.elements['nat_symmetric'].checked ? 1 : 0;
|
||||||
payload.direct_media = form.elements['direct_media'].checked ? 1 : 0;
|
payload.direct_media = form.elements['direct_media'].checked ? 1 : 0;
|
||||||
payload.inband_progress = form.elements['inband_progress'].checked ? 1 : 0;
|
payload.inband_progress = form.elements['inband_progress'].checked ? 1 : 0;
|
||||||
|
|||||||
+21
-6
@@ -19,6 +19,10 @@ $hasBranding = !empty($companyName) || !empty($companyLogo);
|
|||||||
|
|
||||||
$appVerData = file_exists(__DIR__ . '/../version.json') ? json_decode((string)file_get_contents(__DIR__ . '/../version.json'), true) : [];
|
$appVerData = file_exists(__DIR__ . '/../version.json') ? json_decode((string)file_get_contents(__DIR__ . '/../version.json'), true) : [];
|
||||||
$appVersion = $appVerData['version'] ?? '1.5.0';
|
$appVersion = $appVerData['version'] ?? '1.5.0';
|
||||||
|
|
||||||
|
// Détection de l'environnement de développement : présence de .dev local ou branche git dev
|
||||||
|
$isDevEnv = file_exists(__DIR__ . '/../.dev')
|
||||||
|
|| (trim((string)@shell_exec('git -C ' . escapeshellarg(__DIR__) . ' rev-parse --abbrev-ref HEAD 2>/dev/null')) === 'dev');
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr" class="h-full">
|
<html lang="fr" class="h-full">
|
||||||
@@ -26,7 +30,7 @@ $appVersion = $appVerData['version'] ?? '1.5.0';
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="nexus-app-version" content="<?= htmlspecialchars($appVersion) ?>">
|
<meta name="nexus-app-version" content="<?= htmlspecialchars($appVersion) ?>">
|
||||||
<title>NexusPBX — Supervision & Téléphonie IP • Powered by Asterisk</title>
|
<title><?= $isDevEnv ? '🛠️ [DEV] ' : '' ?>NexusPBX — Supervision & Téléphonie IP • Powered by Asterisk</title>
|
||||||
<link rel="icon" type="image/png" href="/assets/favicon.png?v=<?= file_exists(__DIR__ . '/assets/favicon.png') ? filemtime(__DIR__ . '/assets/favicon.png') : 1 ?>">
|
<link rel="icon" type="image/png" href="/assets/favicon.png?v=<?= file_exists(__DIR__ . '/assets/favicon.png') ? filemtime(__DIR__ . '/assets/favicon.png') : 1 ?>">
|
||||||
<link rel="apple-touch-icon" href="/assets/logo.png?v=<?= file_exists(__DIR__ . '/assets/logo.png') ? filemtime(__DIR__ . '/assets/logo.png') : 1 ?>">
|
<link rel="apple-touch-icon" href="/assets/logo.png?v=<?= file_exists(__DIR__ . '/assets/logo.png') ? filemtime(__DIR__ . '/assets/logo.png') : 1 ?>">
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
@@ -162,7 +166,12 @@ $appVersion = $appVerData['version'] ?? '1.5.0';
|
|||||||
<div class="flex items-center gap-4 mb-6">
|
<div class="flex items-center gap-4 mb-6">
|
||||||
<img src="/assets/logo.png?v=<?= file_exists(__DIR__ . '/assets/logo.png') ? filemtime(__DIR__ . '/assets/logo.png') : 1 ?>" alt="NexusPBX Logo" class="w-20 h-20 sm:w-24 sm:h-24 object-contain shrink-0 filter drop-shadow-xl">
|
<img src="/assets/logo.png?v=<?= file_exists(__DIR__ . '/assets/logo.png') ? filemtime(__DIR__ . '/assets/logo.png') : 1 ?>" alt="NexusPBX Logo" class="w-20 h-20 sm:w-24 sm:h-24 object-contain shrink-0 filter drop-shadow-xl">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight leading-none mb-1">NexusPBX</h1>
|
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight leading-none mb-1 flex items-center gap-2">
|
||||||
|
NexusPBX
|
||||||
|
<?php if ($isDevEnv): ?>
|
||||||
|
<span class="px-2 py-0.5 text-xs font-mono font-extrabold tracking-wider rounded bg-amber-500/20 text-amber-300 border border-amber-500/40">DEV</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</h1>
|
||||||
<p class="text-xs text-slate-300">Supervision & Téléphonie IP • Powered by Asterisk</p>
|
<p class="text-xs text-slate-300">Supervision & Téléphonie IP • Powered by Asterisk</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -212,6 +221,9 @@ $appVersion = $appVerData['version'] ?? '1.5.0';
|
|||||||
Nexus<span class="text-indigo-400">PBX</span>
|
Nexus<span class="text-indigo-400">PBX</span>
|
||||||
</div>
|
</div>
|
||||||
<span id="app-version-badge" class="px-1.5 py-0.5 text-[10px] font-mono font-bold tracking-wider rounded bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">v<?= htmlspecialchars($appVersion) ?></span>
|
<span id="app-version-badge" class="px-1.5 py-0.5 text-[10px] font-mono font-bold tracking-wider rounded bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">v<?= htmlspecialchars($appVersion) ?></span>
|
||||||
|
<?php if ($isDevEnv): ?>
|
||||||
|
<span class="px-1.5 py-0.5 text-[10px] font-mono font-black tracking-wider rounded bg-amber-500/25 text-amber-300 border border-amber-500/50 shadow-xs shadow-amber-500/20 animate-pulse">DEV</span>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-[10px] text-slate-400 font-medium tracking-wide mt-0.5">Powered by Asterisk</div>
|
<div class="text-[10px] text-slate-400 font-medium tracking-wide mt-0.5">Powered by Asterisk</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -494,6 +506,13 @@ $appVersion = $appVerData['version'] ?? '1.5.0';
|
|||||||
|
|
||||||
<!-- Boutons d'action globaux -->
|
<!-- Boutons d'action globaux -->
|
||||||
<div class="flex items-center gap-2.5">
|
<div class="flex items-center gap-2.5">
|
||||||
|
<?php if ($isDevEnv): ?>
|
||||||
|
<div class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-xs font-bold bg-amber-500/15 text-amber-300 border border-amber-500/30">
|
||||||
|
<span class="w-2 h-2 rounded-full bg-amber-400 animate-pulse"></span>
|
||||||
|
<span class="hidden md:inline font-mono">SERVEUR</span> DEV
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Badge Notification Mise à Jour Disponible -->
|
<!-- Badge Notification Mise à Jour Disponible -->
|
||||||
<button id="header-update-badge" type="button" onclick="openUpdatePanel()" style="display:none;"
|
<button id="header-update-badge" type="button" onclick="openUpdatePanel()" style="display:none;"
|
||||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-xs font-bold bg-amber-500/20 hover:bg-amber-500/30 text-amber-300 border border-amber-500/40 shadow-sm transition animate-pulse" title="Une mise à jour NexusPBX est disponible ! Cliquez pour voir les détails.">
|
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-xs font-bold bg-amber-500/20 hover:bg-amber-500/30 text-amber-300 border border-amber-500/40 shadow-sm transition animate-pulse" title="Une mise à jour NexusPBX est disponible ! Cliquez pour voir les détails.">
|
||||||
@@ -3949,10 +3968,6 @@ $appVersion = $appVerData['version'] ?? '1.5.0';
|
|||||||
<input type="checkbox" name="trust_id_inbound" value="1" checked class="rounded bg-anthracite-900 border-anthracite-600">
|
<input type="checkbox" name="trust_id_inbound" value="1" checked class="rounded bg-anthracite-900 border-anthracite-600">
|
||||||
<span>Accepter l'identité entrante PAI/RPID (<code class="text-indigo-300">trust_id_inbound = yes</code>)</span>
|
<span>Accepter l'identité entrante PAI/RPID (<code class="text-indigo-300">trust_id_inbound = yes</code>)</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center gap-2 text-xs text-slate-200 cursor-pointer">
|
|
||||||
<input type="checkbox" name="trust_id_outbound" value="1" checked class="rounded bg-anthracite-900 border-anthracite-600">
|
|
||||||
<span>Transmettre l'identité sortante Caller ID (<code class="text-indigo-300">trust_id_outbound = yes</code>)</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+7
-101
@@ -67,25 +67,6 @@ class ConfigGenerator
|
|||||||
$lines[] = "; ===========================================================================";
|
$lines[] = "; ===========================================================================";
|
||||||
$lines[] = "";
|
$lines[] = "";
|
||||||
|
|
||||||
$rtpTimeout = max(5, (int)($settings['rtp_timeout'] ?? 30));
|
|
||||||
$rtpHoldTimeout = max(0, (int)($settings['rtp_timeout_hold'] ?? 0));
|
|
||||||
$rtpKeepalive = max(0, (int)($settings['rtp_keepalive'] ?? 15));
|
|
||||||
|
|
||||||
$tcpKeepaliveLines = [
|
|
||||||
"tcp_keepalive_enable = yes",
|
|
||||||
"tcp_keepalive_idle_time = 20",
|
|
||||||
"tcp_keepalive_interval_time = 5",
|
|
||||||
"tcp_keepalive_probe_count = 3",
|
|
||||||
];
|
|
||||||
|
|
||||||
// 0. Paramètres globaux PJSIP (Keepalive applicatif TLS/TCP toutes les 30s pour postes hors réseau / NAT)
|
|
||||||
$lines[] = "; --- PARAMÈTRES GLOBAUX PJSIP (KEEPALIVE NAT / HORS RÉSEAU) ---";
|
|
||||||
$lines[] = "[global]";
|
|
||||||
$lines[] = "type = global";
|
|
||||||
$lines[] = "keep_alive_interval = 30";
|
|
||||||
$lines[] = "contact_expiration_check_interval = 15";
|
|
||||||
$lines[] = "";
|
|
||||||
|
|
||||||
// 1. Transport UDP (Postes internes LAN & Trunks standards)
|
// 1. Transport UDP (Postes internes LAN & Trunks standards)
|
||||||
$lines[] = "; --- TRANSPORT UDP (LAN / INTERNE) ---";
|
$lines[] = "; --- TRANSPORT UDP (LAN / INTERNE) ---";
|
||||||
$lines[] = "[transport-udp]";
|
$lines[] = "[transport-udp]";
|
||||||
@@ -129,7 +110,6 @@ class ConfigGenerator
|
|||||||
$lines[] = "external_signaling_port = {$extUdpPort}";
|
$lines[] = "external_signaling_port = {$extUdpPort}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
array_push($lines, ...$tcpKeepaliveLines);
|
|
||||||
$lines[] = "allow_reload = no";
|
$lines[] = "allow_reload = no";
|
||||||
$lines[] = "";
|
$lines[] = "";
|
||||||
|
|
||||||
@@ -200,7 +180,6 @@ class ConfigGenerator
|
|||||||
$lines[] = "external_signaling_port = {$extTlsPort}";
|
$lines[] = "external_signaling_port = {$extTlsPort}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
array_push($lines, ...$tcpKeepaliveLines);
|
|
||||||
$lines[] = "allow_reload = no";
|
$lines[] = "allow_reload = no";
|
||||||
$lines[] = "";
|
$lines[] = "";
|
||||||
|
|
||||||
@@ -242,15 +221,6 @@ class ConfigGenerator
|
|||||||
$lines[] = "force_rport = yes";
|
$lines[] = "force_rport = yes";
|
||||||
$lines[] = "rewrite_contact = yes";
|
$lines[] = "rewrite_contact = yes";
|
||||||
$lines[] = "direct_media = no";
|
$lines[] = "direct_media = no";
|
||||||
// Détection automatique et purge des flux RTP fantômes / morts (coupure réseau, NAT hors réseau)
|
|
||||||
$lines[] = "rtp_timeout = {$rtpTimeout}";
|
|
||||||
$lines[] = "rtp_timeout_hold = {$rtpHoldTimeout}";
|
|
||||||
if ($rtpKeepalive > 0) {
|
|
||||||
$lines[] = "rtp_keepalive = {$rtpKeepalive}";
|
|
||||||
}
|
|
||||||
$lines[] = "timers = yes";
|
|
||||||
$lines[] = "timers_min_se = 90";
|
|
||||||
$lines[] = "timers_sess_expires = 1800";
|
|
||||||
if ($wantsTls && $hasTlsCerts) {
|
if ($wantsTls && $hasTlsCerts) {
|
||||||
// Verrouillage strict du transport TLS : refuse le repli sur UDP
|
// Verrouillage strict du transport TLS : refuse le repli sur UDP
|
||||||
$lines[] = "transport = transport-tls";
|
$lines[] = "transport = transport-tls";
|
||||||
@@ -325,14 +295,13 @@ class ConfigGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
$context = trim((string)($trunk['context'] ?? 'from-external')) ?: 'from-external';
|
$context = trim((string)($trunk['context'] ?? 'from-external')) ?: 'from-external';
|
||||||
$fromUser = trim((string)($trunk['from_user'] ?? ''));
|
$fromUser = trim((string)($trunk['from_user'] ?? '')) ?: $username;
|
||||||
$fromDomain = trim((string)($trunk['from_domain'] ?? '')) ?: $host;
|
$fromDomain = trim((string)($trunk['from_domain'] ?? '')) ?: $host;
|
||||||
$callerId = trim((string)($trunk['outbound_callerid'] ?? ''));
|
$callerId = trim((string)($trunk['outbound_callerid'] ?? ''));
|
||||||
$sendPai = ((int)($trunk['send_pai'] ?? 1) === 1) ? 'yes' : 'no';
|
$sendPai = ((int)($trunk['send_pai'] ?? 1) === 1) ? 'yes' : 'no';
|
||||||
$sendRpid = ((int)($trunk['send_rpid'] ?? 0) === 1) ? 'yes' : 'no';
|
$sendRpid = ((int)($trunk['send_rpid'] ?? 0) === 1) ? 'yes' : 'no';
|
||||||
$sendDiversion = ((int)($trunk['send_diversion'] ?? 1) === 1) ? 'yes' : 'no';
|
$sendDiversion = ((int)($trunk['send_diversion'] ?? 1) === 1) ? 'yes' : 'no';
|
||||||
$trustInbound = ((int)($trunk['trust_id_inbound'] ?? 1) === 1) ? 'yes' : 'no';
|
$trustInbound = ((int)($trunk['trust_id_inbound'] ?? 1) === 1) ? 'yes' : 'no';
|
||||||
$trustOutbound = (!isset($trunk['trust_id_outbound']) || (int)$trunk['trust_id_outbound'] === 1) ? 'yes' : 'no';
|
|
||||||
$dtmfMode = trim((string)($trunk['dtmf_mode'] ?? 'rfc4733')) ?: 'rfc4733';
|
$dtmfMode = trim((string)($trunk['dtmf_mode'] ?? 'rfc4733')) ?: 'rfc4733';
|
||||||
$mediaEnc = trim((string)($trunk['media_encryption'] ?? 'no')) ?: 'no';
|
$mediaEnc = trim((string)($trunk['media_encryption'] ?? 'no')) ?: 'no';
|
||||||
$natSym = ((int)($trunk['nat_symmetric'] ?? 1) === 1) ? 'yes' : 'no';
|
$natSym = ((int)($trunk['nat_symmetric'] ?? 1) === 1) ? 'yes' : 'no';
|
||||||
@@ -384,10 +353,9 @@ class ConfigGenerator
|
|||||||
if ($outboundProxy !== '') {
|
if ($outboundProxy !== '') {
|
||||||
$lines[] = "outbound_proxy = {$outboundProxy}";
|
$lines[] = "outbound_proxy = {$outboundProxy}";
|
||||||
}
|
}
|
||||||
// Note : Ne JAMAIS positionner la directive "callerid" dans la section endpoint d'un Trunk PJSIP.
|
if ($callerId !== '') {
|
||||||
// Dans Asterisk, "callerid" sur un endpoint sert de valeur par défaut pour les appels ENTRANTS,
|
$lines[] = "callerid = {$callerId}";
|
||||||
// ce qui écraserait le numéro de l'appelant externe (ex: mobile 06...).
|
}
|
||||||
// Le CallerID sortant du Trunk (outbound_callerid) est appliqué uniquement dans le Dialplan sortant.
|
|
||||||
$lines[] = "disallow = all";
|
$lines[] = "disallow = all";
|
||||||
foreach ($codecs as $codec) {
|
foreach ($codecs as $codec) {
|
||||||
$lines[] = "allow = {$codec}";
|
$lines[] = "allow = {$codec}";
|
||||||
@@ -402,10 +370,7 @@ class ConfigGenerator
|
|||||||
$lines[] = "send_rpid = {$sendRpid}";
|
$lines[] = "send_rpid = {$sendRpid}";
|
||||||
$lines[] = "send_diversion = {$sendDiversion}";
|
$lines[] = "send_diversion = {$sendDiversion}";
|
||||||
$lines[] = "trust_id_inbound = {$trustInbound}";
|
$lines[] = "trust_id_inbound = {$trustInbound}";
|
||||||
$lines[] = "trust_id_outbound = {$trustOutbound}";
|
|
||||||
$lines[] = "timers = {$timers}";
|
$lines[] = "timers = {$timers}";
|
||||||
$lines[] = "rtp_timeout = {$rtpTimeout}";
|
|
||||||
$lines[] = "rtp_timeout_hold = {$rtpHoldTimeout}";
|
|
||||||
if ($rtpKeepalive > 0) {
|
if ($rtpKeepalive > 0) {
|
||||||
$lines[] = "rtp_keepalive = {$rtpKeepalive}";
|
$lines[] = "rtp_keepalive = {$rtpKeepalive}";
|
||||||
}
|
}
|
||||||
@@ -1193,9 +1158,7 @@ class ConfigGenerator
|
|||||||
|
|
||||||
// 3. Positionnement du CallerID Sortant de la route
|
// 3. Positionnement du CallerID Sortant de la route
|
||||||
if ($rCid !== '') {
|
if ($rCid !== '') {
|
||||||
foreach ($this->buildCallerIdDialplan($rCid) as $cidStmt) {
|
$sub[] = " same => n,Set(CALLERID(all)={$rCid})";
|
||||||
$sub[] = $cidStmt;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Séquence de Trunks avec bascule automatique (Failover)
|
// 4. Séquence de Trunks avec bascule automatique (Failover)
|
||||||
@@ -1209,10 +1172,8 @@ class ConfigGenerator
|
|||||||
$tSlug = $tObj ? $this->slugify($tObj['name']) : $this->slugify($tKey);
|
$tSlug = $tObj ? $this->slugify($tObj['name']) : $this->slugify($tKey);
|
||||||
$tFallbackCid = $tObj ? trim((string)($tObj['outbound_callerid'] ?? '')) : '';
|
$tFallbackCid = $tObj ? trim((string)($tObj['outbound_callerid'] ?? '')) : '';
|
||||||
|
|
||||||
if ($rCid === '' && $tFallbackCid !== '') {
|
if ($rCid === '' && $tFallbackCid !== '' && $overrideCid) {
|
||||||
foreach ($this->buildCallerIdDialplan($tFallbackCid) as $cidStmt) {
|
$sub[] = " same => n,Set(CALLERID(all)={$tFallbackCid})";
|
||||||
$sub[] = $cidStmt;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$validTrunkCount++;
|
$validTrunkCount++;
|
||||||
@@ -2296,60 +2257,5 @@ class ConfigGenerator
|
|||||||
$slug = preg_replace('/[^a-z0-9]+/', '-', $slug);
|
$slug = preg_replace('/[^a-z0-9]+/', '-', $slug);
|
||||||
return trim($slug, '-') ?: 'default';
|
return trim($slug, '-') ?: 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Formate les instructions Dialplan pour le positionnement du Caller ID (Nom, Numéro, Présentation, CallerID all)
|
|
||||||
* afin de garantir la transmission du CNAM (Caller ID Name) et du CLI par Asterisk PJSIP.
|
|
||||||
*
|
|
||||||
* @param string $cidString Chaîne du type '"Sytelis Consulting" <0422560185>', 'Sytelis <0422560185>', '0422560185' ou 'Sytelis'
|
|
||||||
* @param string $indent
|
|
||||||
* @return array<string>
|
|
||||||
*/
|
|
||||||
private function buildCallerIdDialplan(string $cidString, string $indent = ' same => n,'): array
|
|
||||||
{
|
|
||||||
$cidString = trim($cidString);
|
|
||||||
if ($cidString === '') {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$name = '';
|
|
||||||
$num = '';
|
|
||||||
|
|
||||||
// Formats reconnus :
|
|
||||||
// 1. "Nom Complet" <0422560185> ou Nom Complet <0422560185>
|
|
||||||
if (preg_match('/^(?:\"?([^\"<>]+?)\"?\s*)?<([^>]+)>$/u', $cidString, $m)) {
|
|
||||||
$name = trim($m[1] ?? '');
|
|
||||||
$num = trim($m[2] ?? '');
|
|
||||||
} elseif (preg_match('/^<([^>]+)>$/', $cidString, $m)) {
|
|
||||||
$num = trim($m[1]);
|
|
||||||
} elseif (preg_match('/^\+?[0-9*#]+$/', $cidString)) {
|
|
||||||
$num = $cidString;
|
|
||||||
} else {
|
|
||||||
// Uniquement un nom
|
|
||||||
$name = trim($cidString, " \t\n\r\0\x0B\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
$lines = [];
|
|
||||||
if ($num !== '') {
|
|
||||||
$lines[] = "{$indent}Set(CALLERID(num)={$num})";
|
|
||||||
$lines[] = "{$indent}Set(CALLERID(num-pres)=allowed_passed_screen)";
|
|
||||||
}
|
|
||||||
if ($name !== '') {
|
|
||||||
$cleanName = str_replace('"', '', $name);
|
|
||||||
$lines[] = "{$indent}Set(CALLERID(name)=\"{$cleanName}\")";
|
|
||||||
$lines[] = "{$indent}Set(CALLERID(name-pres)=allowed_passed_screen)";
|
|
||||||
}
|
|
||||||
if ($name !== '' && $num !== '') {
|
|
||||||
$cleanName = str_replace('"', '', $name);
|
|
||||||
$lines[] = "{$indent}Set(CALLERID(all)=\"{$cleanName}\" <{$num}>)";
|
|
||||||
} elseif ($num !== '') {
|
|
||||||
$lines[] = "{$indent}Set(CALLERID(all)={$num})";
|
|
||||||
} elseif ($name !== '') {
|
|
||||||
$cleanName = str_replace('"', '', $name);
|
|
||||||
$lines[] = "{$indent}Set(CALLERID(all)=\"{$cleanName}\")";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $lines;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,6 @@ class Database
|
|||||||
send_pai INTEGER NOT NULL DEFAULT 1 CHECK (send_pai IN (0, 1)),
|
send_pai INTEGER NOT NULL DEFAULT 1 CHECK (send_pai IN (0, 1)),
|
||||||
send_rpid INTEGER NOT NULL DEFAULT 0 CHECK (send_rpid IN (0, 1)),
|
send_rpid INTEGER NOT NULL DEFAULT 0 CHECK (send_rpid IN (0, 1)),
|
||||||
trust_id_inbound INTEGER NOT NULL DEFAULT 1 CHECK (trust_id_inbound IN (0, 1)),
|
trust_id_inbound INTEGER NOT NULL DEFAULT 1 CHECK (trust_id_inbound IN (0, 1)),
|
||||||
trust_id_outbound INTEGER NOT NULL DEFAULT 1 CHECK (trust_id_outbound IN (0, 1)),
|
|
||||||
codecs VARCHAR(64) NOT NULL DEFAULT 'alaw,ulaw,g722',
|
codecs VARCHAR(64) NOT NULL DEFAULT 'alaw,ulaw,g722',
|
||||||
dtmf_mode VARCHAR(16) NOT NULL DEFAULT 'rfc4733',
|
dtmf_mode VARCHAR(16) NOT NULL DEFAULT 'rfc4733',
|
||||||
media_encryption VARCHAR(16) NOT NULL DEFAULT 'no',
|
media_encryption VARCHAR(16) NOT NULL DEFAULT 'no',
|
||||||
@@ -526,7 +525,6 @@ class Database
|
|||||||
'moh_sound_id' => "INTEGER NOT NULL DEFAULT 0",
|
'moh_sound_id' => "INTEGER NOT NULL DEFAULT 0",
|
||||||
'cid_name_prefix' => "VARCHAR(64) NOT NULL DEFAULT ''",
|
'cid_name_prefix' => "VARCHAR(64) NOT NULL DEFAULT ''",
|
||||||
'dial_options' => "VARCHAR(32) NOT NULL DEFAULT 'tTR'",
|
'dial_options' => "VARCHAR(32) NOT NULL DEFAULT 'tTR'",
|
||||||
'trust_id_outbound' => "INTEGER NOT NULL DEFAULT 1 CHECK (trust_id_outbound IN (0, 1))",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($extraColumns as $colName => $colDef) {
|
foreach ($extraColumns as $colName => $colDef) {
|
||||||
|
|||||||
+2
-7
@@ -1,14 +1,9 @@
|
|||||||
{
|
{
|
||||||
"version": "1.6.6",
|
"version": "1.6.2",
|
||||||
"codename": "Helios",
|
"codename": "Helios",
|
||||||
"release_date": "2026-11-10",
|
"release_date": "2026-11-05",
|
||||||
"min_php_version": "8.2",
|
"min_php_version": "8.2",
|
||||||
"changelog": [
|
"changelog": [
|
||||||
"PJSIP Endpoints & Trunks : injection effective de rtp_timeout, rtp_timeout_hold, rtp_keepalive et SIP Session Timers (RFC 4028) sur chaque endpoint PJSIP pour raccrocher instantanément les canaux fantômes",
|
|
||||||
"PJSIP Global & Transports TLS/TCP : keepalive applicatif réduit à 30s (keep_alive_interval = 30), vérification expiration contacts toutes les 15s et TCP keepalives noyau (20s/5s/3) pour fiabiliser les BLF et postes hors réseau derrière NAT",
|
|
||||||
"Trunks SIP : dissociation stricte du CallerID sortant du Trunk (suppression de callerid dans l'endpoint PJSIP pour préserver l'affichage du numéro appelant réel sur les appels entrants)",
|
|
||||||
"Trunks SIP : suppression du forçage de from_user afin de préserver l'en-tête SIP From dynamique avec Nom d'appelant (CNAM) pour OVH / Orange",
|
|
||||||
"Trunks SIP & Routage Sortant : activation systématique de trust_id_outbound et formatage strict du Caller ID Name (CNAM) pour affichage garanti chez les opérateurs distants (OVH, Orange, etc.)",
|
|
||||||
"Sauvegarde & Restauration : versionnage dynamique automatique basé sur la version installée (résolution du tag figé v1.2.0)",
|
"Sauvegarde & Restauration : versionnage dynamique automatique basé sur la version installée (résolution du tag figé v1.2.0)",
|
||||||
"Mises à jour système OTA : déclenchement garanti d'une sauvegarde Disaster Recovery complète pré-mise à jour (visible et restaurable dans l'interface)",
|
"Mises à jour système OTA : déclenchement garanti d'une sauvegarde Disaster Recovery complète pré-mise à jour (visible et restaurable dans l'interface)",
|
||||||
"Interface Sauvegardes : nouveau badge identifiant la source (Pré-MàJ, Auto, Manuel)",
|
"Interface Sauvegardes : nouveau badge identifiant la source (Pré-MàJ, Auto, Manuel)",
|
||||||
|
|||||||
Reference in new issue
Block a user