;;;;;;;;; NPSTN NA 201905011 - Boilerplate Template for New NPSTN Nodes
#include verification.conf ; this includes /etc/asterisk/verification.conf in the main Asterisk dialplan (loaded via extensions.conf)
; no need to include verification.conf if your node is eXtensible - it's automatic

[globals] ; Global variables that persist across all calls are defined here
; "Core" variables that MUST be defined on ALL NPSTN nodes
clli=NPSTNCLLI0 ; the unique CLLI of your node
zipcode=00000 ; your ZIP code (00000 for nodes outside the U.S.A.)
maindisa=5551111 ; number to your primary NPSTN DISA (if you don't have one, then any NPSTN number that comes into your switch from NPSTN)
allowdisathru=YES ; See npstn.us/docs/ to learn more about what this variable does
allowpstnthru=YES ; See npstn.us/docs/ to learn more about what this variable does
npstnkey=abcdefghijklmnopqrstuvwxyz ; your NPSTN UCP auth key (dial the business office at 116 if you need one)
usedefaultblacklistresult=1 ; Automatically restrict nuisance callers according to recommendations

; NOTE: This starter NPSTN code is intended to be a minimalist, bare bones Asterisk configuration for Asterisk newbies
; NOTE: Making your node eXtensible (see https://npstn.us/docs) is highly recommended if you are an Asterisk newbie as it makes node maintenance easy and hassle free, while conveniently bringing you many of the latest features! Some dialplan contexts in this started config are already in the eXtensible dialplan; you must remove any duplicate contexts if you make your node eXtensible.

; NOTE: NPSTN has a "billing" functionality that is purely for fun. The idea is to show you all the calls you make on NPSTN and what they would have cost back in the day. The bill is for fun, and you are not actually charged anything. NPSTN is and always will be 100% free.

; "Add-on" variables that are used only for convenience purposes on this node - in this case to define the path to audio files
dialtone=custom/signal/dialtone ; File path to audio file
busy=custom/signal/busy ; File path to audio file
reorder=custom/signal/reorder ; File path to audio file
ccad=custom/signal/ccad ; File path to audio file
acbn=custom/signal/acbn ; File path to audio file
nnis=custom/signal/nnis ; File path to audio file

; Number range assignments assignments
OC1=555 ; your office code's NNX (NOT NNX-X, whether or not you have all its thousands blocks) - create OC2, OC3, etc. if you have multiple blocks
		; This sample implementation assumes the thousand blocks 555-1 and 555-9 have been assigned (adjust accordingly based on YOUR assignment)
		; The individual extensions pre-created in [local] all adhere to the NPSTN numbering standards

[local-operator-ring] ; 0/411/611/121/131/141/161/etc.
exten => _X!,1,Dial(SIP/operator) ; change this to whatever endpoint(s) should ring local/inward operator calls on your switch
	same => n,Goto(npstn-operator-route,invalid,1)
; If desired, different endpoints can ring for different call types (e.g. 121, 131, 141, etc.)

[local] ; Define all local extensions here, except ATA lines which are automatically covered by the [ata] fallthrough
exten => _${OC1}XXXX,1,Gosub(SIPxNumToPeer,s,1(${EXTEN})) ; Check the ten-thousand block for SIP peers
	same => n,GotoIf($["${GOSUB_RETVAL}"=""]?intercept:ata)
	same => n(ata),Gosub(ata,s,1(${GOSUB_RETVAL})) ; Dial SIP peer if it exists
	same => n,Hangup()
	same => n(intercept),Gosub(nnis,s,1) ; Intercept message if SIP peer does not exist
	same => n,Hangup()
exten => ${OC1}1111,1,Goto(dt,s,1) ; DISA access
exten => ${OC1}9901,1,SayAlpha(${clli}) ; "Switch verification"
	same => n,Hangup()
exten => ${OC1}9931,1,Goto(echotest,s,1) ; Echo test
exten => ${OC1}9932,1,Progress()
	same => n,Wait(7200) ; Silent termination
	same => n,Hangup()
exten => ${OC1}9958,1,SayDigits(${CALLERID(num)}) ; a primitive ANAC
	same => n,Hangup()
exten => ${OC1}9960,1,Gosub(mwtone,s,1) ; Milliwatt test tone
	same => n,Hangup()
exten => ${OC1}9970,1,Gosub(busy,s,1) ; Always busy
	same => n,Hangup()
exten => ${OC1}9971,1,Gosub(reorder,s,1) ; Always reorder
	same => n,Hangup()
exten => ${OC1}9990,1,Dial(Local/ring@ringout,,m(ringback)) ; Number that always rings "forever"

[ringout]
exten => ring,1,Wait(7200)
	same => n,Hangup()

[private] ; Any extensions you want to be able to dial but want to keep off-limits to outside callers
exten => ${OC1}9876,1,Answer()
	same => n,Hangup()

;;; Any additional contexts you need
[echotest] ; Echo test
exten => s,1,Progress()
	same => n,Echo()
	same => n,Hangup()

[mwtone] ; Milliwatt test tone
exten => s,1,Set(VOLUME(TX)=8)
	same => n,Wait(0.5)
	same => n,PlayTones(1004/1000)
	same => n,Wait(600)
	same => n,Set(VOLUME(TX)=1)
	same => n,Return

[from-npstn-tieline]
exten => _sX!,1,Gosub(npstn-verify,${maindisa},1)
	same => n,ExecIf($["${clidverif:-1:1}"!="0"]?Hangup(21))
	same => n,Goto(${EXTEN:1},1)
	same => n,Goto(npstn-public-tielines,${EXTEN:1},1)

[npstn-public-tielines]
exten => _X!,1,Hangup(34)
exten => 1,1,Goto(dt,s,1) ; should go *DIRECTLY* to dial tone (DISA) with NO inpulsing, e.g. dt,s,1
; additional tie lines can be added if you have multiple dial tones e.g. exten => 2,1,Goto(dt2,s,1) or exten => 2,1,Goto(dt,DT2,1), etc.

[local-operator-custom]
exten => _X!,1,Goto(npstn-operator-route,invalid,1)
exten => 102,1,PlayTones(1004) ; 102 MW test
	same => n,Wait(600)
	same => n,Hangup()
; other local test lines (e.g. exten => 105 for 105-type test, etc.)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; You should not need to touch anything below here ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[from-npstn] ; Incoming calls from NPSTN
exten => _X!,1,Gosub(npstn-verify,${EXTEN},1)
	same => n,Gosub(npstn-blacklist-check,s,1)
	same => n,GotoIf($[${GOSUB_RETVAL}>=2.5]?reject)
	same => n,GotoIf($["${clidverif}"="11"]?:accept)
	same => n,GotoIf($[${GROUP_COUNT(npstnspam@cvs)}<5]?:reject)
	same => n(accept),Goto(external-users,${EXTEN},1)
	same => n(reject),Hangup(21)

[from-npstn-operator] ; Incoming calls to/from NPSTN operators
exten => s,1,Goto(000,1)
exten => _X!,1,Gosub(npstn-verify,${EXTEN},1)
	same => n,ExecIf($["${clidverif}"!="10"]?Hangup(21))
	same => n,Set(GROUP(npstnoperatortrunks)=0)
	same => n,ExecIf($[${GROUP_COUNT(0@npstnoperatortrunks)}>10]?Hangup(34))
	same => n,Goto(npstn-operator-route,${EXTEN},1)

[external-users] ; External calls from various places (NPSTN, possibly C*NET, PSTN, and other networks, arrive here)
include => local ; Include the contents of the [local] context

[internal-users]
include => private ; Note: accessible only by *direct* dialing from ATA lines (not via DISA)
include => local
include => longdistance ; If the number dialed is not local, go "out" to NPSTN

[from-internal] ; Incoming calls from local SIP devices (have your ATA off-hook auto-dial/hotline "6" - see https://npstn.us/docs/#ata for instructions/guidance)
exten => 6,1,Answer()
	same => n,Goto(dt,s,1) ; Use extension "6" for ATA off-hook auto-dial for immediate NPSTN city dialtone (could likewise do 9 for PSTN, 7 for C*NET, etc.)
;exten => _X!,1,Set(CHANNEL(hangup_handler_push)=npstnticket,${EXTEN},1(${STRFTIME(${EPOCH},,%s)},${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)},${CALLERID(num)})) ; NPSTN Toll Ticketing v2
;	same => n,Goto(internal-users,${EXTEN},1) ; doesn't work

[SIPxNumToPeer] ; NPSTNNA 20191130 ; Returns SIP peer of a number or 000 if peer/number does not exist
exten => s,1,Set(num=${ARG1})
	same => n,GotoIf($["${num}"=""]?dne)
	same => n,Set(scriptexists=${STAT(e,/etc/asterisk/scripts/sipcontext.sh)})
	same => n,GotoIf($["${scriptexists}"="1"]?use)
	same => n(download),System(wget https://phreaknet.org/npstn/code/sipcontext.sh -P /etc/asterisk/scripts/)
	same => n(perm),System(chmod 777 /etc/asterisk/scripts/sipcontext.sh)
	same => n(use),Set(peer=${SHELL(/etc/asterisk/scripts/sipcontext.sh "${num}")})
	same => n,GotoIf($["${peer}"=""]?dne)
	same => n,Return(${peer})
	same => n(dne),Return()

[ata] ; Automatically dials the SIP peer by name (ARG1 = SIP peer name)
exten => s,1,Dial(SIP/${ARG1},,m(ringback)g)
	same => n,GotoIf($["${DIALSTATUS}"="CHANUNAVAIL"]?reorder,1)
	same => n,GotoIf($["${DIALSTATUS}"="BUSY"]?busy,1)
	same => n,GotoIf($["${DIALSTATUS}"="CONGESTION"]?reorder,1)
	same => n,GotoIf($["${DIALSTATUS}"="NOANSWER"]?reorder,1)
	same => n,Return()
exten => busy,1,GoSub(busy,s,1)
	same => n,Return()
exten => reorder,1,GoSub(reorder,s,1)
	same => n,Return()
exten => ccad,1,GoSub(ccad,s,1)
	same => n,Return()
exten => acbn,1,GoSub(allcktsbusy,s,1)
	same => n,Return()

[busy] ; Busy signal (~60ipm)
exten => s,1,Playback(${busy},noanswer)
	;same => n,GoTo(1) ; to loop the busy signal, uncomment this line
	same => n,Return()

[reorder] ; Reorder signal (~120ipm)
exten => s,1,Playback(${reorder},noanswer)
	;same => n,GoTo(1) ; to loop the reorder signal, uncomment this line
	same => n,Return()

[ccad] ; Cannot Be Completed As Dialed Intercept
exten => s,1,Playback(${ccad},noanswer)
	same => n,Return()

[nnis] ; Number Not In Service Intercept
exten => s,1,Playback(${nnis},noanswer)
	same => n,Return()

[allcktsbusy] ; All Circuits Busy Intercept
exten => s,1,Playback(${acbn},noanswer)
	same => n,Return()

[dt] ; NPSTN dialtone ; this dial tone is a simplified version that does not handle all possible #s
; A better [dt] is available in the NPSTN Docs here: https://npstn.us/docs/#disa-goto
exten => s,1,Progress()
	same => n(begin),Set(num=)
	same => n,Read(num1,${dialtone},1,n) ; n option prevents answer supervision
	same => n,Set(num=${num}${num1})
	same => n,GotoIf($["${num}"=""]?permsig)
	same => n,GotoIf($["${num}"="0"]?done)
	same => n,Read(num2,,1,n)
	same => n,Set(num=${num}${num2})
	same => n,Read(num3,,1,n)
	same => n,Set(num=${num}${num3})
	same => n,GotoIf($["${num1}${num2}"="11"]?done)
	same => n,GotoIf($["${num2}${num3}"="11"]?done)
	same => n,GotoIf($["${num1}"="1"]?ld8)
	same => n,GotoIf($["${num}"="660"]?done)
	same => n,GotoIf($["${num}"="958"]?done)
	same => n,GotoIf($["${num}"="959"]?done)
	same => n,Read(station,,4,n)
	same => n,Set(num=${num}${station})
	same => n,GoTo(done)
	same => n(ld8),Read(station,,5,n)
	same => n,Set(num=${num}${station})
	same => n(done),Dial(Local/${num}@dtroute/n,,g) ; Prevent local call optimization for more advanced features
	same => n,ExecIf($["${HANGUPCAUSE}"="29"]?Dial(Local/${num}@npstnanifail/n,,g)) ; AST_CAUSE_FACILITY_REJECTED = 29 ; "ANI fail", cancel billing, route call through TSP instead
	same => n,Goto(begin)
	same => n(permsig),GoTo(dtdest,permsig,1)

[npstnanifail]
exten => check,1,NoOp()
	same => n,GotoIf($["${clidverif}"="11"]?fail)
	same => n,GotoIf($["${clidverif}"="19"]?fail)
	same => n,GotoIf($["${clidverif}"="32"]?fail)
	same => n,Return(0)
	same => n(fail),Return(1)
exten => _X!,1,GoSub(npstn-out-verify,${EXTEN},1)
	same => n,GotoIf($["${GOSUB_RETVAL}"="0"]?npstn-out-blocked,s,1)
	same => n,GoSub(dialnpstn,start,1(0${EXTEN},disable,${zipcode},${maindisa})) ; 0+ @ TSP will handle all billing, if any
	same => n,Hangup()

[dtroute]
exten => _X!,1,Set(CHANNEL(hangup_handler_push)=npstnticket,${num},1(${STRFTIME(${EPOCH},,%s)},${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)},${CALLERID(num)})) ; NPSTN Toll Ticketing v2
	same => n,Dial(Local/${EXTEN}@dtdest/n) ; a double dial is unfortunately required to prevent multiple CDR events from messing with the entire CDR for the call (e.g. a Dial followed by Confbridge)

[dtdest] ; Routes calls from [dt]
exten => permsig,1,GoSub(dialnpstn,start,1(,disable,${zipcode},${maindisa}))
	same => n,Hangup()
include => local
include => dtnpstn

[longdistance] ; Outgoing NPSTN access for internal users
exten => _X!,1,GoTo(dtnpstn,${EXTEN},1)

[dtnpstn]
exten => _X!,1,Set(originalclid=${CALLERID(all)}) ; Any other calls should be sent "out" to NPSTN
	same => n,GoSub(npstn-out-verify,${EXTEN},1)
	same => n,GotoIf($["${GOSUB_RETVAL}"="0"]?npstn-out-blocked,s,1)
	same => n,GoSub(npstnanifail,check,1) ; ANI FAIL CHECK
	same => n,ExecIf($["${GOSUB_RETVAL}"="1"]?Hangup(29)) ; ANI FAIL CHECK - prevent switch from ticketing by hanging up with cause code 29, call will get sent to TSP
	same => n,GoSub(dialnpstn,start,1(${EXTEN},disable,${zipcode},${maindisa}))
	same => n,Set(CALLERID(all)=${originalclid})
	same => n,Hangup()

[dialnpstn] ; NPSTN 20190215 NA ; Sends a call to NPSTN
exten => start,1,Set(num=${ARG1})
	same => n,GotoIf($[${LEN("${ARG4}")}>2]?clidoverride)
	same => n,Set(lookup=${SHELL(curl "https://crtc.npstn.us/api/v1/?auth=${npstnkey}&lookup=${ARG1}&cid=${CALLERID(num)}&sntandem=${ARG2}&zipcode=${ARG3}")})
	same => n,GoTo(verify)
	same => n(clidoverride),Set(lookup=${SHELL(curl "https://crtc.npstn.us/api/v1/?auth=${npstnkey}&lookup=${ARG1}&cid=${ARG4}&sntandem=${ARG2}&zipcode=${ARG3}")})
	same => n(verify),GoSub(lookupchan,s,1(${lookup})) ; verifies lookup for extra security
	same => n,GotoIf($["${GOSUB_RETVAL}"="0"]?npstn-BLOCKED,1)
	same => n,GoSub(lookupipcheck,s,1(${lookup})) ; verifies the destination is a public IP address
	same => n,GotoIf($["${GOSUB_RETVAL}"="0"]?:npstn-BLOCKED,1) ; proceed if 0
	same => n,NoOp(NPSTN ROUTE TO: ${lookup})
	same => n,Dial(${lookup},,g)
	same => n,GoTo(npstn-${DIALSTATUS},1)
exten => npstn-ANSWER,1,Return()
exten => npstn-NOANSWER,1,Return()
exten => npstn-BUSY,1,GoSub(busy,s,1)
	same => n,Return()
exten => npstn-CONGESTION,1,GotoIf($["${forcesecurechannel}"="1"]?cktsbusy) ; secure calls must be direct, if there is congestion, do not try an alternate route
	same => n,GotoIf($[${DIALPLAN_EXISTS(snroute,${ARG1},1)}]?sntandem) ; StepNet nodes can trunk via StepNet backbone for Alternate Route Selection
	same => n,GotoIf($["${altrouteattempted}"=""]?:cktsbusy) ; Don't try alternate routing more than once
	same => n,Set(altrouteattempted=1)
	same => n,Set(lookup=${SHELL(curl "https://crtc.npstn.us/api/v1/?auth=${npstnkey}&lookup=${ARG1}&sntandem=yes&zipcode=${ARG3}")})
	same => n,Goto(start,verify)
	same => n(sntandem),Gosub(snroute,${ARG1:-7},1) ; try an alternate route via StepNet backbone
	same => n,Set(snrouting=${GOSUB_RETVAL})
	same => n(altroute),Gosub(sndialstring,${ARG1:-7},1(${snrouting:0:4}111)) ; Alternate routing for circuit busy conditions ; send only last 7 in case 1+ calls are congested and failover here
	same => n,Set(lookup=${GOSUB_RETVAL})
	same => n,Set(IAXVAR(snrouting)=${snrouting})
	same => n,Set(IAXVAR(sncount)=3) ; Tandem through one node only (min is 3, this prevents further tandeming)
	same => n(verify),Gosub(lookupchan,s,1(${lookup})) ; verifies lookup for extra security
	same => n,GotoIf($["${GOSUB_RETVAL}"="0"]?npstn-BLOCKED,1)
	same => n,Gosub(lookupipcheck,s,1(${lookup})) ; verifies the destination is a public IP address
	same => n,GotoIf($["${GOSUB_RETVAL}"="0"]?:npstn-BLOCKED,1) ; proceed if 0
	same => n,NoOp(NPSTN ROUTE TO: ${lookup})
	same => n,Dial(${lookup},,g)
	same => n,GotoIf($["${DIALSTATUS}"="CONGESTION"]?:npstn-${DIALSTATUS},1)
	same => n,GotoIf($[${LEN(${snrouting})}>4]?:cktsbusy)
	same => n,Set(snrouting=${snrouting:4})
	same => n,Goto(altroute) ; Obtain another alternate routing
	same => n(cktsbusy),Gosub(allcktsbusy,s,1())
	same => n,Return()
exten => npstn-CHANUNAVAIL,1,GoSub(reorder,s,1)
	same => n,Return()
exten => npstn-BLOCKED,1,GoSub(ccad,s,1)
	same => n,Return()
exten => _npstn-.,1,Return()

[npstnticket] ; NPSTNNA 20201213 ; EXTEN = # called, ARG1 = ss, ARG2 = tt, ARG3 = ANI (at time of hangup handler instantiation)
exten => _X!,1,NoOp(DIALSTATUS: ${DIALSTATUS} / HANGUPCAUSE: ${HANGUPCAUSE} / CDR: duration: ${CDR(duration)} / billsec: ${CDR(billsec)} / start: ${CDR(start)} / answer: ${CDR(answer)} / end: ${CDR(end)})
	same => n,ExecIf($["${LEN(${FILTER(0-9,${CALLERID(num)})})}"="0"]?Set(CALLERID(num)=${ARG3})) ; restore original ANI if it was modified later
	same => n,Set(duration=${CDR(billsec)})
	same => n,Set(start=${CDR(answer)})
	same => n,GotoIf($["${CDR(answer)}"=""]?done) ; Don't even try to ticket the call if it wasn't answered (this includes cancelling ticketing on ANI fails, i.e. HANGUPCAUSE=29)
	same => n,ExecIf($["${CDR(billsec)}"="0"]?ExecIf($[${LEN(${CDR(answer)})}>0]?Set(duration=$[${STRFTIME(${EPOCH},,%s)}-${ARG1}]))) ; edge case: calls where called called party hangs up first...
	same => n,ExecIf($["${CDR(billsec)}"="0"]?ExecIf($[${LEN(${CDR(answer)})}>0]?Set(start=${ARG2}))) ; ...so fall back to old way of doing it, use ss/tt, which includes ring time in billing
	same => n,Gosub(npstnbilling2,${EXTEN},1(${duration},${start}))
	same => n(done),Return()

[npstnbilling2] ; NPSTN NA 20201213 NPSTN Toll Ticketing v2; EXTEN= # dialed, ARG1= duration, ARG2= billing start time, ARG3 = type, ARG4= clid override
exten => _[ABCD].,1,GoTo(${EXTEN:1},1) ; Only ARG1 and ARG2 are required ; ARG3 through ARG6 are only used by NPSTNNA01
exten => _X!,1,GoToIf($["${ARG1}"=""]?done) ; Prevent WARNING errors if there are insufficient arguments
	same => n,Set(duration=${ARG1}) ; CDR(billsec)
	same => n,Set(start=${ARG2}) ; CDR(answer)
	same => n,Set(type=${ARG3}) ; optional argument, default=direct
	same => n,ExecIf($["${ARG3}"=""]?Set(type=direct))
	same => n,ExecIf($["${ARG4}"=""]?Set(ani=${FILTER(0-9A-Za-z,${CALLERID(num)})}):Set(ani=${FILTER(0-9A-Za-z,${ARG4})}))
	same => n,Set(callee=${FILTER(0-9,${EXTEN})})
	same => n,Set(request=${SHELL(curl "https://npstn.us/api/billing/?ani=${ani}&callee=${callee}&type=${type}&duration=${duration}&key=${npstnkey}&clli=${clli}&year=${start:0:4}&month=${start:5:2}&day=${start:8:2}&hr=${start:11:2}&min=${start:14:2}&sec=${start:17:2}")})
	same => n,Return()

[npstn-operator-route]
exten => 000,1,Goto(s,1)
exten => _000.,1,Goto(local-operator-ring,${EXTEN:3},1) ; Network operator ring group
exten => _1[2346]1,1,Goto(local-operator-ring,${EXTEN},1) ; 121 = inward, 131 = information, 141 = rate/route
exten => s,1,PlayTones(2600)
	same => n,Wait(0.04) ; wink, to indicate ready to receive digits
	same => n,StopPlayTones()
	same => n,GotoIf($["${IAXVAR(optrunktype)}"="1"]?dtmf,1:mf,1)
exten => mf,1,ExecIf($[${DIALPLAN_EXISTS(mf-get-number,s,1)}]?Gosub(mf-get-number,s,1):Hangup(69)) ; receive additional digits if MF capable
	same => n,Goto(${GOSUB_RETVAL},1)
exten => dtmf,1,Set(TIMEOUT(response)=20)
	same => n,Read(digits) ; for now, read additional digits using DTMF: ideally, this is using MF on switches supporting it
	same => n,GotoIf($["${FILTER(0-9,${digits})}"=""]?invalid,1)
	same => n,Goto(${FILTER(0-9,${digits})},1)
exten => _NXX!,1,NoOp() ; NXX routings
	same => n,Set(ext=${EXTEN:3})
	same => n,ExecIf($["${ext}"=""]?Set(ext=s))
	same => n,Set(lookup=${SHELL(curl "https://api.phreaknet.org/routing/?key=${npstnkey}&code=${EXTEN:0:3}")})
	same => n,GotoIf($["${lookup}"=""|"${lookup}"="0"]?invalid,1)
	same => n,Gosub(npstn-out-verify,${EXTEN},1)
	same => n,Dial(${lookup}${ext})
	same => n,Goto(invalid,1)
exten => _NXX0XX!,1,NoOp() ; NXX0XX routings
	same => n,Set(ext=${EXTEN:6})
	same => n,ExecIf($["${ext}"=""]?Set(ext=s))
	same => n,Set(lookup=${SHELL(curl "https://api.phreaknet.org/routing/?key=${npstnkey}&code=${EXTEN:0:6}")})
	same => n,Gosub(npstn-out-verify,${EXTEN},1)
	same => n,GotoIf($["${lookup}"=""|"${lookup}"="0"]?invalid,1)
	same => n,Dial(${lookup}${ext})
	same => n,Goto(invalid,1)
exten => invalid,1,PlayTones(congestion)
	same => n,Wait(600)
	same => n,Hangup()
exten => _NNXXXXX,1,Goto(dtroute,${EXTEN},1)
include => local-operator-custom
