function xmlEscape(value: string): string { return value .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } export interface GatewayParams { gatewayName: string; host: string; proxy?: string; realm?: string; register: boolean; username?: string; password?: string; fromUser?: string; fromDomain?: string; registerProxy?: string; outboundProxy?: string; expireSeconds: number; retrySeconds: number; callerIdName?: string; callerIdNumber?: string; dtmfMode: "RFC2833" | "INFO" | "INBAND"; ping: boolean; pingFrequency: number; transport: "UDP" | "TCP" | "TLS"; } const DTMF_VALUES: Record = { RFC2833: "rfc2833", INFO: "info", INBAND: "inband", }; /** * XML de gateway do Sofia (agente.md secao 41). Escrito em * sip_profiles/external/.xml pelo b2bcall-fs-config e carregado * via `sofia profile external rescan` — o profile "external" já vem com * `` na config vanilla. */ export function buildGatewayXml(params: GatewayParams): string { const lines: string[] = []; const param = (name: string, value: string | number | boolean | undefined) => { if (value === undefined || value === "") return; lines.push(` `); }; param("username", params.username); param("password", params.password); param("realm", params.realm ?? params.host); param("proxy", params.proxy ?? params.host); param("register", params.register); param("expire-seconds", params.expireSeconds); param("retry-seconds", params.retrySeconds); param("from-user", params.fromUser ?? params.username); param("from-domain", params.fromDomain ?? params.host); param("register-proxy", params.registerProxy); param("outbound-proxy", params.outboundProxy); param("caller-id-in-from", true); param("extension", params.fromUser ?? params.username); param("dtmf-type", DTMF_VALUES[params.dtmfMode]); param("register-transport", params.transport.toLowerCase()); if (params.ping) { param("ping", params.pingFrequency); } return ` ${lines.join("\n")} `; }