{ lib, cfg, models, intercomEntries }: let # Phones that have voicemail enabled vmPhones = lib.filterAttrs (_: phone: phone.voicemailTimeout != null) cfg.phones; hasVoicemail = vmPhones != {}; pjsip = '' [transport-tcp] type = transport protocol = tcp bind = 0.0.0.0:${toString cfg.sipPort} [transport-udp] type = transport protocol = udp bind = 0.0.0.0:${toString cfg.sipPort} ; --- templates --- [endpoint-cisco-8961](!) type = endpoint context = internal transport = transport-tcp disallow = all allow = ulaw allow = alaw allow = g722 allow = g726 allow = ilbc allow = gsm direct_media = no trust_id_inbound = yes [endpoint-generic](!) type = endpoint context = internal transport = transport-tcp disallow = all allow = ulaw allow = alaw allow = g722 direct_media = no [auth-userpass](!) type = auth auth_type = userpass ; --- phones --- '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (key: phone: let m = models.${phone.model}; in '' [${key}](${m.endpointTemplate}) auth = auth-${key} aors = ${key} ${lib.optionalString (phone.voicemailTimeout != null) "mailboxes = ${phone.extension}@voicemail\n set_var=VOICEMAIL_MAILBOX=${phone.extension}"} [auth-${key}](auth-userpass) username = ${key} password = ${phone.password} [${key}] type = aor max_contacts = ${toString m.maxContacts} remove_existing = yes '') cfg.phones) + lib.concatMapStringsSep "\n" (ic: '' [${ic.endpoint}](${ic.endpointTemplate}) auth = auth-${ic.endpoint} aors = ${ic.endpoint} [auth-${ic.endpoint}](auth-userpass) username = ${ic.endpoint} password = ${ic.password} [${ic.endpoint}] type = aor max_contacts = ${toString ic.maxContacts} remove_existing = yes '') intercomEntries; # Reverse map: extension number -> pjsip endpoint key extensionToEndpoint = lib.foldlAttrs (acc: key: phone: acc // { ${phone.extension} = key; } ) {} cfg.phones; # All page endpoints: intercom line for provisioned phones, regular for others allPageEndpoints = lib.concatStringsSep "&" (lib.mapAttrsToList (key: phone: let m = models.${phone.model}; in if m.hasProvisioning && cfg.intercomPrefix != null then "PJSIP/${key}-intercom" else "PJSIP/${key}" ) cfg.phones); extensions = '' [internal] '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (ext: extCfg: if extCfg.mode == "app" then "exten => ${ext},1,${extCfg.app}" else if extCfg.mode == "page" then "exten => ${ext},1,Page(${allPageEndpoints},i,120)" else if lib.hasAttr ext extensionToEndpoint then let phoneKey = extensionToEndpoint.${ext}; phone = cfg.phones.${phoneKey}; in if phone.voicemailTimeout != null then ''exten => ${ext},1,Dial(PJSIP/${phoneKey},${toString phone.voicemailTimeout}) same => n,VoiceMail(${ext}@voicemail,u)'' else "exten => ${ext},1,Dial(PJSIP/${phoneKey})" else "exten => ${ext},1,Hangup() ; WARNING: no endpoint assigned to extension ${ext}" ) cfg.extensions) + "\n" + lib.concatMapStringsSep "\n" (ic: "exten => ${ic.extension},1,Dial(PJSIP/${ic.endpoint},30)" ) intercomEntries + lib.optionalString hasVoicemail "\nexten => *97,1,VoiceMailMain(\${VOICEMAIL_MAILBOX}@voicemail,sa(0))"; rtp = '' [general] rtpstart = ${toString cfg.rtpStart} rtpend = ${toString cfg.rtpEnd} ''; voicemail = '' [general] format = ulaw [voicemail] '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (_: phone: let displayName = cfg.extensions.${phone.extension}.displayName; in " ${phone.extension} => ,${displayName},,attach=no" ) vmPhones); in { "pjsip.conf" = pjsip; "extensions.conf" = extensions; "rtp.conf" = rtp; } // lib.optionalAttrs hasVoicemail { "voicemail.conf" = voicemail; }