diff --git a/public/api.php b/public/api.php
index 1edabb4..91ecdc6 100644
--- a/public/api.php
+++ b/public/api.php
@@ -1086,7 +1086,15 @@ try {
$username = trim((string)($payload['username'] ?? ''));
$auth_username = trim((string)($payload['auth_username'] ?? ''));
$secret = trim((string)($payload['secret'] ?? ''));
- $register = ($auth_mode === 'ip') ? 0 : (int)!empty($payload['register']);
+
+ $rawRegMode = strtolower(trim((string)($payload['registration_mode'] ?? '')));
+ if (in_array($rawRegMode, ['send', 'receive', 'none'], true)) {
+ $registration_mode = $rawRegMode;
+ } else {
+ $registration_mode = (!empty($payload['register']) && $auth_mode !== 'ip') ? 'send' : 'none';
+ }
+ $register = ($registration_mode === 'send') ? 1 : 0;
+
$server_uri = trim((string)($payload['server_uri'] ?? ''));
$client_uri = trim((string)($payload['client_uri'] ?? ''));
$contact_user = trim((string)($payload['contact_user'] ?? ''));
@@ -1130,8 +1138,17 @@ try {
$cleanDidRoutes = ConfigGenerator::normalizeInboundRoutes(json_encode($didRoutesRaw));
$did_routes_json = json_encode($cleanDidRoutes, JSON_UNESCAPED_UNICODE);
- if ($name === '' || $host === '') {
- throw new InvalidArgumentException("Le nom du Trunk et l'hôte SIP opérateur sont requis.");
+ if ($name === '') {
+ throw new InvalidArgumentException("Le nom du Trunk est requis.");
+ }
+ if ($registration_mode === 'receive') {
+ if ($username === '' || $secret === '') {
+ throw new InvalidArgumentException("En mode Réception (ex: passerelle Grandstream HT813 / Livebox), l'Identifiant (Username) et le Mot de passe SIP sont requis pour authentifier la passerelle.");
+ }
+ } else {
+ if ($host === '') {
+ throw new InvalidArgumentException("L'hôte SIP opérateur (Serveur SIP) est requis.");
+ }
}
$params = [
@@ -1144,6 +1161,7 @@ try {
':username' => $username,
':auth_username' => $auth_username,
':secret' => $secret,
+ ':registration_mode' => $registration_mode,
':register' => $register,
':server_uri' => $server_uri,
':client_uri' => $client_uri,
@@ -1192,7 +1210,8 @@ try {
UPDATE trunks SET
name = :name, host = :host, port = :port, outbound_proxy = :outbound_proxy,
transport = :transport, auth_mode = :auth_mode, username = :username,
- auth_username = :auth_username, secret = :secret, register = :register,
+ auth_username = :auth_username, secret = :secret,
+ registration_mode = :registration_mode, register = :register,
server_uri = :server_uri, client_uri = :client_uri, contact_user = :contact_user,
expiration = :expiration, retry_interval = :retry_interval,
max_retries = :max_retries, forbidden_retry_interval = :forbidden_retry_interval,
@@ -1217,7 +1236,7 @@ try {
$stmt = $db->prepare('
INSERT INTO trunks (
name, host, port, outbound_proxy, transport, auth_mode, username, auth_username, secret,
- 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,
from_user, from_domain, outbound_callerid, send_pai, send_rpid, send_diversion,
trust_id_inbound, codecs, dtmf_mode, media_encryption, nat_symmetric, direct_media,
@@ -1226,7 +1245,7 @@ try {
outbound_prefix, custom_endpoint_params, custom_reg_params, custom_aor_params, moh_sound_id, enabled
) VALUES (
:name, :host, :port, :outbound_proxy, :transport, :auth_mode, :username, :auth_username, :secret,
- :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,
:from_user, :from_domain, :outbound_callerid, :send_pai, :send_rpid, :send_diversion,
:trust_id_inbound, :codecs, :dtmf_mode, :media_encryption, :nat_symmetric, :direct_media,
@@ -1237,7 +1256,8 @@ try {
ON CONFLICT(name) DO UPDATE SET
host = excluded.host, port = excluded.port, outbound_proxy = excluded.outbound_proxy,
transport = excluded.transport, auth_mode = excluded.auth_mode, username = excluded.username,
- auth_username = excluded.auth_username, secret = excluded.secret, register = excluded.register,
+ auth_username = excluded.auth_username, secret = excluded.secret,
+ registration_mode = excluded.registration_mode, register = excluded.register,
server_uri = excluded.server_uri, client_uri = excluded.client_uri, contact_user = excluded.contact_user,
expiration = excluded.expiration, retry_interval = excluded.retry_interval,
max_retries = excluded.max_retries, forbidden_retry_interval = excluded.forbidden_retry_interval,
@@ -1259,9 +1279,10 @@ try {
$stmt->execute($params);
}
+ $displayHost = $host !== '' ? "{$host}:{$port}" : "Passerelle locale / HT813";
echo json_encode([
'success' => true,
- 'message' => "Trunk SIP « {$name} » ({$host}:{$port}) sauvegardé avec tous ses paramètres PJSIP.",
+ 'message' => "Trunk SIP « {$name} » ({$displayHost}) sauvegardé avec tous ses paramètres PJSIP.",
]);
break;
diff --git a/public/assets/app.js b/public/assets/app.js
index 9257e6c..a3c232d 100644
--- a/public/assets/app.js
+++ b/public/assets/app.js
@@ -1579,14 +1579,25 @@ function renderTrunksTable() {
tbody.innerHTML = rows.map(t => {
const slug = `trunk-${slugifyTrunkName(t.name)}`;
const regInfo = regs[slug];
+ const regMode = t.registration_mode || (Number(t.register) === 1 ? 'send' : 'none');
const isIpAuth = t.auth_mode === 'ip';
- const wantsReg = !isIpAuth && Number(t.register) === 1;
let statusBadge = '';
if (Number(t.enabled ?? 1) === 0) {
statusBadge = `Désactivé `;
- } else if (isIpAuth || !wantsReg) {
- statusBadge = `Peering / Sans Reg. `;
+ } else if (regMode === 'receive') {
+ const contacts = appState.metrics?.asterisk?.contacts || [];
+ const isOnline = contacts.some(c =>
+ (c.extension === slug || c.extension === t.username || (t.username && c.uri && c.uri.includes(t.username)))
+ && String(c.status || '').toLowerCase().includes('avail')
+ );
+ if (isOnline) {
+ statusBadge = ` Passerelle En ligne `;
+ } else {
+ statusBadge = `En attente passerelle (Receive) `;
+ }
+ } else if (isIpAuth || regMode === 'none') {
+ statusBadge = `Peering IP direct `;
} else if (regInfo && /Registered/i.test(regInfo.status)) {
statusBadge = ` Registered `;
} else if (regInfo) {
@@ -1618,7 +1629,9 @@ function renderTrunksTable() {
${statusBadge}
- ${escapeHtml(t.host)}:${Number(t.port)}
+
+ ${t.host ? escapeHtml(t.host) + ':' + Number(t.port || 5060) : 'Passerelle locale (Dynamique)'}
+
${t.outbound_proxy ? `Proxy: ${escapeHtml(t.outbound_proxy)}
` : ''}
@@ -2085,6 +2098,57 @@ function parseFreePbxConfig() {
}
}
+function onTrunkRegistrationModeChange(mode) {
+ const form = document.getElementById('form-trunk');
+ if (!form) return;
+
+ const hostInput = form.elements['host'];
+ const hostLabel = document.getElementById('trunk-host-label');
+ const hostHint = document.getElementById('trunk-host-hint');
+ const receiveGuide = document.getElementById('trunk-receive-guide');
+ const regNotice = document.getElementById('trunk-reg-outbound-notice');
+
+ if (mode === 'receive') {
+ if (hostInput) {
+ hostInput.required = false;
+ hostInput.placeholder = 'Optionnel (vide = IP découverte dynamiquement au REGISTER du HT813)';
+ }
+ if (hostLabel) {
+ hostLabel.innerHTML = 'Serveur SIP / IP Passerelle (Optionnel en mode Réception) ';
+ }
+ hostHint?.classList.remove('hidden');
+ receiveGuide?.classList.remove('hidden');
+ regNotice?.classList.remove('hidden');
+ if (form.elements['register']) form.elements['register'].checked = false;
+ if (form.elements['line_support']) form.elements['line_support'].checked = false;
+ } else if (mode === 'none') {
+ if (hostInput) {
+ hostInput.required = true;
+ hostInput.placeholder = 'ex: 192.168.1.250 ou sbc.direct.net';
+ }
+ if (hostLabel) {
+ hostLabel.innerHTML = 'Serveur SIP / SBC / Passerelle * (Host / IP) ';
+ }
+ hostHint?.classList.add('hidden');
+ receiveGuide?.classList.add('hidden');
+ regNotice?.classList.remove('hidden');
+ if (form.elements['register']) form.elements['register'].checked = false;
+ } else {
+ // mode === 'send'
+ if (hostInput) {
+ hostInput.required = true;
+ hostInput.placeholder = 'ex: sbc.operateur.net ou siptrunk.ovh.net';
+ }
+ if (hostLabel) {
+ hostLabel.innerHTML = 'Serveur SIP / SBC / Passerelle * (Host / IP) ';
+ }
+ hostHint?.classList.add('hidden');
+ receiveGuide?.classList.add('hidden');
+ regNotice?.classList.add('hidden');
+ if (form.elements['register']) form.elements['register'].checked = true;
+ }
+}
+
function applyTrunkArchitecture(arch) {
const form = document.getElementById('form-trunk');
if (!form) return;
@@ -2095,17 +2159,31 @@ function applyTrunkArchitecture(arch) {
port: 5060,
transport: 'udp',
auth_mode: 'userpass',
+ registration_mode: 'send',
register: true,
line_support: true,
media_encryption: 'no',
nat_symmetric: true,
qualify_frequency: 60
},
+ gateway_receive: {
+ label: 'Passerelle FXO / Analogique (Grandstream HT813, Livebox, ATA)',
+ port: 5060,
+ transport: 'udp',
+ auth_mode: 'userpass',
+ registration_mode: 'receive',
+ register: false,
+ line_support: false,
+ media_encryption: 'no',
+ nat_symmetric: true,
+ qualify_frequency: 60
+ },
ip_peering: {
label: 'Peering IP / SBC / Passerelle (Sans REGISTER)',
port: 5060,
transport: 'udp',
auth_mode: 'ip',
+ registration_mode: 'none',
register: false,
line_support: false,
media_encryption: 'no',
@@ -2117,6 +2195,7 @@ function applyTrunkArchitecture(arch) {
port: 5061,
transport: 'tls',
auth_mode: 'userpass',
+ registration_mode: 'send',
register: true,
line_support: true,
media_encryption: 'sdes',
@@ -2134,6 +2213,13 @@ function applyTrunkArchitecture(arch) {
form.querySelectorAll('input[name="auth_mode"]').forEach(r => { r.checked = (r.value === a.auth_mode); });
toggleTrunkAuthFields(a.auth_mode);
+ if (a.registration_mode) {
+ form.querySelectorAll('input[name="registration_mode"]').forEach(r => {
+ r.checked = (r.value === a.registration_mode);
+ });
+ onTrunkRegistrationModeChange(a.registration_mode);
+ }
+
form.elements['register'].checked = a.register;
form.elements['line_support'].checked = a.line_support;
form.elements['media_encryption'].value = a.media_encryption;
@@ -2152,11 +2238,18 @@ function openTrunkModal(trunk = null) {
form.elements['id'].value = trunk ? trunk.id : '';
form.elements['name'].value = trunk ? trunk.name : '';
- form.elements['host'].value = trunk ? trunk.host : '';
+ form.elements['host'].value = trunk ? (trunk.host ?? '') : '';
form.elements['port'].value = trunk ? (trunk.port ?? 5060) : 5060;
form.elements['outbound_proxy'].value = trunk ? (trunk.outbound_proxy ?? '') : '';
form.elements['transport'].value = trunk ? (trunk.transport ?? 'udp') : 'udp';
+ const regMode = trunk ? (trunk.registration_mode || (Number(trunk.register) === 1 ? 'send' : 'none')) : 'send';
+ form.querySelectorAll('input[name="registration_mode"]').forEach(r => {
+ r.checked = (r.value === regMode);
+ });
+ onTrunkRegistrationModeChange(regMode);
+ form.elements['transport'].value = trunk ? (trunk.transport ?? 'udp') : 'udp';
+
const authMode = trunk ? (trunk.auth_mode || 'userpass') : 'userpass';
form.querySelectorAll('input[name="auth_mode"]').forEach(r => {
r.checked = (r.value === authMode);
@@ -2168,6 +2261,17 @@ function openTrunkModal(trunk = null) {
form.elements['secret'].value = trunk ? (trunk.secret ?? '') : '';
form.elements['enabled'].checked = trunk ? Number(trunk.enabled ?? 1) === 1 : true;
+ const uInput = form.elements['username'];
+ const updateGuide = () => {
+ const val = uInput.value.trim() || 'Même valeur que Username';
+ const gUser = document.getElementById('ht813-guide-user');
+ const gAuth = document.getElementById('ht813-guide-auth');
+ if (gUser) gUser.textContent = val;
+ if (gAuth) gAuth.textContent = val;
+ };
+ uInput.oninput = updateGuide;
+ updateGuide();
+
// Onglet 2 : Registration & Identité SIP
form.elements['register'].checked = trunk ? Number(trunk.register ?? 1) === 1 : true;
form.elements['line_support'].checked = trunk ? Number(trunk.line_support ?? 1) === 1 : true;
@@ -3583,6 +3687,7 @@ document.addEventListener('DOMContentLoaded', () => {
const fd = new FormData(form);
const payload = Object.fromEntries(fd.entries());
+ payload.registration_mode = form.querySelector('input[name="registration_mode"]:checked')?.value || 'send';
payload.enabled = form.elements['enabled'].checked ? 1 : 0;
payload.register = form.elements['register'].checked ? 1 : 0;
payload.line_support = form.elements['line_support'].checked ? 1 : 0;
diff --git a/public/index.php b/public/index.php
index 0dcc708..1e77f67 100644
--- a/public/index.php
+++ b/public/index.php
@@ -3278,6 +3278,9 @@ $currentUser = Auth::getUsername();
Trunk avec Enregistrement (REGISTER + Auth)
+
+ 📟 Passerelle FXO / Analogique (HT813, Livebox)
+
Peering IP / SBC / Passerelle (Sans REGISTER)
@@ -3340,16 +3343,78 @@ $currentUser = Auth::getUsername();
+
+
+
+ Mode d'Enregistrement SIP (Registration)
+ Définit le sens de l'enregistrement ou le mode peering
+
+
+
+
+
+
+ Émission (Send)
+ Défaut
+
+
Asterisk s'enregistre vers l'opérateur (OVH, Keyyo...). Serveur SIP requis.
+
+
+
+
+
+
+ Réception (Receive)
+ Passerelle FXO
+
+
La passerelle s'enregistre sur Asterisk (Grandstream HT813, Livebox). Hôte libre.
+
+
+
+
+
+
+ Aucun (None)
+ Peering IP
+
+
Interconnexion directe sans enregistrement (Trunk IP dédié, SBC). Serveur SIP requis.
+
+
+
+
+
+
+
+ 💡 Guide Rapide : Paramétrage de votre Grandstream HT813 / HT503 (FXO)
+
+
+ Dans l'interface web du boîtier HT813 (onglet FXO Port relié à la prise téléphone verte de votre Livebox / Box opérateur) :
+
+
+
• Primary SIP Server : = htmlspecialchars($_SERVER['SERVER_ADDR'] ?? '10.10.175.204') ?>:5060
+
• SIP Registration : Yes
+
• SIP User ID : Même valeur que Username
+
• Authenticate ID : Même valeur que Username
+
• Authenticate Password : Votre mot de passe secret
+
• Stage Method (1/2) : 1 (Recommandé pour appel direct)
+
+ • Unconditional Call Forward to VoIP : Définir User ID = votre numéro (ex: 0494679572) et SIP Server = ch1:= htmlspecialchars($_SERVER['SERVER_ADDR'] ?? '10.10.175.204') ?>:5060;
+
+
+
+
+
-
+
+
+ ℹ️
+ En mode Réception (Passerelle type HT813) ou Peering IP direct (None) , Asterisk n'émet aucun SIP REGISTER sortant. Les paramètres d'enregistrement ci-dessous ne s'appliquent qu'en mode Émission (Send) .
+
+
Paramètres d'Enregistrement SIP ([type = registration])
diff --git a/src/ConfigGenerator.php b/src/ConfigGenerator.php
index 1ef29f7..49ffd08 100644
--- a/src/ConfigGenerator.php
+++ b/src/ConfigGenerator.php
@@ -308,15 +308,40 @@ class ConfigGenerator
$codecs = array_filter(array_map('trim', explode(',', (string)($trunk['codecs'] ?? 'alaw,ulaw'))));
$hasAuth = ($authMode !== 'ip' && $username !== '' && $secret !== '');
- $lines[] = "; --- Trunk : {$trunk['name']} ({$host}:{$port} [{$trProto}]) ---";
+ $regMode = trim((string)($trunk['registration_mode'] ?? ''));
+ if (!in_array($regMode, ['send', 'receive', 'none'], true)) {
+ $regMode = ((int)($trunk['register'] ?? 1) === 1) ? 'send' : 'none';
+ }
+
+ $matchIpsRaw = trim((string)($trunk['match_ips'] ?? ''));
+
+ $hostPortDisplay = $host !== '' ? "{$host}:{$port}" : "Passerelle Réception Dynamique";
+ $lines[] = "; --- Trunk : {$trunk['name']} ({$hostPortDisplay} [{$trProto}] - Mode: {$regMode}) ---";
$lines[] = "[trunk-{$slug}]";
$lines[] = "type = endpoint";
$lines[] = "context = {$context}";
$lines[] = "transport = {$transport}";
- if ($hasAuth) {
+
+ if ($regMode === 'receive') {
+ // Passerelle locale (ex: Grandstream HT813, Livebox, ATA) s'enregistrant sur Asterisk
+ $lines[] = "auth = trunk-{$slug}-auth";
$lines[] = "outbound_auth = trunk-{$slug}-auth";
+ if ($username !== '' && $username !== "trunk-{$slug}") {
+ $lines[] = "aors = trunk-{$slug},{$username}";
+ } else {
+ $lines[] = "aors = trunk-{$slug}";
+ }
+ if ($host !== '' || $matchIpsRaw !== '') {
+ $lines[] = "identify_by = auth_username,username,ip";
+ } else {
+ $lines[] = "identify_by = auth_username,username";
+ }
+ } else {
+ if ($hasAuth) {
+ $lines[] = "outbound_auth = trunk-{$slug}-auth";
+ }
+ $lines[] = "aors = trunk-{$slug}";
}
- $lines[] = "aors = trunk-{$slug}";
if ($outboundProxy !== '') {
$lines[] = "outbound_proxy = {$outboundProxy}";
}
@@ -377,10 +402,16 @@ class ConfigGenerator
}
$lines[] = "";
- // Section AOR du Trunk (nommée trunk-$slug)
+ // Section AOR du Trunk (nommée trunk-$slug et alias username si mode receive)
$lines[] = "[trunk-{$slug}]";
$lines[] = "type = aor";
- $lines[] = "contact = sip:{$host}:{$port}";
+ if ($regMode === 'receive') {
+ // En mode réception, l'IP/port de la passerelle est découvert dynamiquement lors du REGISTER
+ $lines[] = "max_contacts = 1";
+ $lines[] = "remove_existing = yes";
+ } else {
+ $lines[] = "contact = sip:{$host}:{$port}";
+ }
$lines[] = "qualify_frequency = {$qualifyFreq}";
if ($outboundProxy !== '') {
$lines[] = "outbound_proxy = {$outboundProxy}";
@@ -396,8 +427,21 @@ class ConfigGenerator
}
$lines[] = "";
+ // AOR supplémentaire pour identifier l'enregistrement par identifiant/numéro (ex: 0494679572)
+ if ($regMode === 'receive' && $username !== '' && $username !== "trunk-{$slug}") {
+ $lines[] = "[{$username}]";
+ $lines[] = "type = aor";
+ $lines[] = "max_contacts = 1";
+ $lines[] = "remove_existing = yes";
+ $lines[] = "qualify_frequency = {$qualifyFreq}";
+ if ($outboundProxy !== '') {
+ $lines[] = "outbound_proxy = {$outboundProxy}";
+ }
+ $lines[] = "";
+ }
+
// Section Auth du Trunk
- if ($hasAuth) {
+ if ($hasAuth || $regMode === 'receive') {
$lines[] = "[trunk-{$slug}-auth]";
$lines[] = "type = auth";
$lines[] = "auth_type = userpass";
@@ -406,8 +450,8 @@ class ConfigGenerator
$lines[] = "";
}
- // Section Registration du Trunk
- if ((int)($trunk['register'] ?? 1) === 1 && $hasAuth) {
+ // Section Registration du Trunk (uniquement en mode émission 'send')
+ if ($regMode === 'send' && (int)($trunk['register'] ?? 1) === 1 && $hasAuth) {
$serverUri = trim((string)($trunk['server_uri'] ?? '')) ?: "sip:{$host}:{$port}";
$clientUri = trim((string)($trunk['client_uri'] ?? '')) ?: "sip:{$username}@{$fromDomain}:{$port}";
$contactUser = trim((string)($trunk['contact_user'] ?? ''));
@@ -453,19 +497,22 @@ class ConfigGenerator
$lines[] = "";
}
- // Section Identify (Reconnaissance d'IPs / sous-réseaux opérateur)
- $matchIpsRaw = trim((string)($trunk['match_ips'] ?? ''));
- $matchList = $matchIpsRaw !== ''
- ? array_filter(array_map('trim', preg_split('/[\s,;]+/', $matchIpsRaw) ?: []))
- : [$host];
+ // Section Identify (Reconnaissance d'IPs / sous-réseaux opérateur ou passerelle)
+ if ($matchIpsRaw !== '' || ($regMode !== 'receive' && $host !== '') || ($regMode === 'receive' && $host !== '')) {
+ $matchList = $matchIpsRaw !== ''
+ ? array_filter(array_map('trim', preg_split('/[\s,;]+/', $matchIpsRaw) ?: []))
+ : ($host !== '' ? [$host] : []);
- $lines[] = "[trunk-{$slug}-identify]";
- $lines[] = "type = identify";
- $lines[] = "endpoint = trunk-{$slug}";
- foreach ($matchList as $mIp) {
- $lines[] = "match = {$mIp}";
+ if (!empty($matchList)) {
+ $lines[] = "[trunk-{$slug}-identify]";
+ $lines[] = "type = identify";
+ $lines[] = "endpoint = trunk-{$slug}";
+ foreach ($matchList as $mIp) {
+ $lines[] = "match = {$mIp}";
+ }
+ $lines[] = "";
+ }
}
- $lines[] = "";
}
}
diff --git a/src/Database.php b/src/Database.php
index 35ae98a..f178a7a 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -128,7 +128,7 @@ class Database
CREATE TABLE IF NOT EXISTS trunks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(64) NOT NULL UNIQUE,
- host VARCHAR(128) NOT NULL,
+ host VARCHAR(128) NOT NULL DEFAULT '',
port INTEGER NOT NULL DEFAULT 5060,
outbound_proxy VARCHAR(128) NOT NULL DEFAULT '',
transport VARCHAR(8) NOT NULL DEFAULT 'udp',
@@ -136,6 +136,7 @@ class Database
username VARCHAR(64) NOT NULL DEFAULT '',
auth_username VARCHAR(64) NOT NULL DEFAULT '',
secret VARCHAR(128) NOT NULL DEFAULT '',
+ registration_mode VARCHAR(16) NOT NULL DEFAULT 'send' CHECK (registration_mode IN ('send', 'receive', 'none')),
register INTEGER NOT NULL DEFAULT 1 CHECK (register IN (0, 1)),
server_uri VARCHAR(192) NOT NULL DEFAULT '',
client_uri VARCHAR(192) NOT NULL DEFAULT '',
@@ -561,6 +562,7 @@ class Database
// Colonnes universelles PJSIP supplémentaires (Session Timers, Fax T.38, Diversion, Retries, Langue, Keepalive)
$extraColumns = [
+ 'registration_mode' => "VARCHAR(16) NOT NULL DEFAULT 'send'",
'max_retries' => "INTEGER NOT NULL DEFAULT 10000",
'forbidden_retry_interval' => "INTEGER NOT NULL DEFAULT 600",
'fatal_retry_interval' => "INTEGER NOT NULL DEFAULT 0",
@@ -579,6 +581,9 @@ class Database
foreach ($extraColumns as $colName => $colDef) {
if (!in_array($colName, $existing, true)) {
$db->exec("ALTER TABLE trunks ADD COLUMN {$colName} {$colDef}");
+ if ($colName === 'registration_mode') {
+ $db->exec("UPDATE trunks SET registration_mode = CASE WHEN register = 1 THEN 'send' ELSE 'none' END");
+ }
}
}
}