The extension config file

The configuration file /etc/asterisk/extensions.conf is often referred to as the “dial plan”. This configuration file controls the execution of phone operations and how the phone calls are routed. It also allows for programming to place conditions on the behavior of the system.

The extensions.conf file should be organized by sections. Usually the first section is a context named [general], followed by [globals]. There are special macro contexts that start with [macro-] that are used to define reusable execution patterns. In addition to the predefined contexts, the Asterisk administrator can add additional contexts, with their choice of name, used to define the execution of the SIP peers.

Starting with the [general] section, this is where you define a few general options regarding the Dialplan. The setting here include static, writeprotect, autofallthrough, clearglobalvars, and priorityjumping. Below is a table explaining each of these settings.

static Currently this option affects only the console operation of the “dialplan save” command. The default value is no, but in the sample extensions.conf installed with Asterisk it is set to yes. It also requires the writeprotect setting to be no.
writeprotect If writeprotect=no and static=yes, then you may save the current dialplan with the console command “dialplan save”. The default value is no. 

Use the  “dialplan save” command with caution. It will overwrite your existing extensions.conf with a new one generated from the current dialplan, erasing previous data.

autofallthrough If the autofallthrough setting is set and an extension reaches the end of it procedures and is not ended, it will cause an extension to terminate the call with BUSY, CONGESTION or HANGUP, depending on Asterisk’s best guess. If autofallthrough is not set, then if an extension runs out of things to do, asterisk will wait for a new extension to be dialed.
clearglobalvars If clearglobalvars is set, global variables will be cleared and reparsed on an extensions reload, or Asterisk reload. If clearglobalvars is not set, then global variables will persist through reloads, and even if deleted from the extensions.conf or one if its included files, will remain set to the previous value.
priorityjumping Iif priorityjumping is set to ‘yes’, then applications that support ‘jumping’ to a different priority based on the result of their operations will do so. Individual applications can also be requested to do this by passing a ‘j’ option in their arguments.

The [globals] section is used to define global variables that can be used throughout the dial plan. Unlike many programming languages, the names of the variables are not case sensitive. This means that the variable RINGTIME and ringtime are the same. For example, to set a variable named RINGTIME to hold a value of 5, simply add the line RINGTIME=5 to the [globals] section.

The [macro-] sections provide code that is reusable within the dialplan.  Using variables a context can be created that that will a set of instructions to repeat using differing values depending on the call. For example to create a context used for macros that will be named “alternative” a context named [macro-alternative] would be created.

A sample file of extensions.conf is provided with the installation of Asterisk. It may be helpful to review the sample to see how the dialplan is constructed. In the next lesson a new extensions.conf file will be created. Below is the contents of the sample file. To save space, lines with just comments and spacing have been removed, showing just the uncommented lines of code:
[general] static=yes
writeprotect=no
clearglobalvars=no
[globals] CONSOLE=Console/dsp ; Console interface for demo
IAXINFO=guest ; IAXtel username/password
TRUNK=DAHDI/G2 ; Trunk interface
TRUNKMSD=1 ; MSD digits to strip (usually 1 or 0)
[dundi-e164-canonical] [dundi-e164-customers] [dundi-e164-via-pstn] [dundi-e164-local] include => dundi-e164-canonical
include => dundi-e164-customers
include => dundi-e164-via-pstn
[dundi-e164-switch] switch => DUNDi/e164
[dundi-e164-lookup] include => dundi-e164-local
include => dundi-e164-switch
[macro-dundi-e164] exten => s,1,Goto(${ARG1},1)
include => dundi-e164-lookup
[iaxtel700] exten => _91700XXXXXXX,1,Dial(IAX2/${GLOBAL(IAXINFO)}@iaxtel.com/${EXTEN:1}@iaxtel)
[iaxprovider] [trunkint] exten => _9011.,1,Macro(dundi-e164,${EXTEN:4})
exten => _9011.,n,Dial(${GLOBAL(TRUNK)}/${FILTER(0-9,${EXTEN:${GLOBAL(TRUNKMSD)}})})
[trunkld] exten => _91NXXNXXXXXX,1,Macro(dundi-e164,${EXTEN:1})
exten => _91NXXNXXXXXX,n,Dial(${GLOBAL(TRUNK)}/${EXTEN:${GLOBAL(TRUNKMSD)}})
[trunklocal] exten => _9NXXXXXX,1,Dial(${GLOBAL(TRUNK)}/${EXTEN:${GLOBAL(TRUNKMSD)}})
[trunktollfree] exten => _91800NXXXXXX,1,Dial(${GLOBAL(TRUNK)}/${EXTEN:${GLOBAL(TRUNKMSD)}})
exten => _91888NXXXXXX,1,Dial(${GLOBAL(TRUNK)}/${EXTEN:${GLOBAL(TRUNKMSD)}})
exten => _91877NXXXXXX,1,Dial(${GLOBAL(TRUNK)}/${EXTEN:${GLOBAL(TRUNKMSD)}})
exten => _91866NXXXXXX,1,Dial(${GLOBAL(TRUNK)}/${EXTEN:${GLOBAL(TRUNKMSD)}})
[international] ignorepat => 9
include => longdistance
include => trunkint
[longdistance] ignorepat => 9
include => local
include => trunkld
[local] ignorepat => 9
include => default
include => trunklocal
include => iaxtel700
include => trunktollfree
include => iaxprovider
include => parkedcalls
[outbound-freenum] exten => _X*X!,1,Goto(outbound-freenum2,${EXTEN},1)
exten => _XX*X!,1,Goto(outbound-freenum2,${EXTEN},1)
exten => _XXX*X!,1,Goto(outbound-freenum2,${EXTEN},1)
exten => _XXXX*X!,1,Goto(outbound-freenum2,${EXTEN},1)
exten => _XXXXX*X!,1,Goto(outbound-freenum2,${EXTEN},1)
exten => _XXXXXX*X!,1,Goto(outbound-freenum2,${EXTEN},1)
[outbound-freenum2] exten => _X!,1,Verbose(2,Performing ISN lookup for ${EXTEN})
same => n,Set(SUFFIX=${CUT(EXTEN,*,2-)}) ; make sure the suffix is all digits as well
same => n,GotoIf($["${FILTER(0-9,${SUFFIX})}" != "${SUFFIX}"]?fn-CONGESTION,1)
same => n,Set(TIMEOUT(absolute)=10800)
same => n,Set(isnresult=${ENUMLOOKUP(${EXTEN},sip,,1,freenum.org)}) ; perform our lookup with freenum.org
same => n,GotoIf($["${isnresult}" != ""]?from)
same => n,Set(DIALSTATUS=CONGESTION)
same => n,Goto(fn-CONGESTION,1)
same => n(from),Set(__SIPFROMUSER=${CALLERID(num)})
same => n,GotoIf($["${GLOBAL(FREENUMDOMAIN)}" = ""]?dial) ; check if we set the FREENUMDOMAIN global variable in [global] same => n,Set(__SIPFROMDOMAIN=${GLOBAL(FREENUMDOMAIN)}) ; if we did set it, then we'll use it for our outbound dialing domain
same => n(dial),Dial(SIP/${isnresult},40)
same => n,Goto(fn-${DIALSTATUS},1)
exten => fn-BUSY,1,Busy()
exten => _f[n]-.,1,NoOp(ISN: ${DIALSTATUS})
same => n,Congestion()
[macro-trunkdial] exten => s,1,Dial(${ARG1})
exten => s,n,Goto(s-${DIALSTATUS},1)
exten => s-NOANSWER,1,Hangup
exten => s-BUSY,1,Hangup
exten => _s-.,1,NoOp
[stdexten] exten => _X.,50000(stdexten),NoOp(Start stdexten)
exten => _X.,n,Set(LOCAL(ext)=${EXTEN})
exten => _X.,n,Set(LOCAL(dev)=${ARG1})
exten => _X.,n,Set(LOCAL(cntx)=${ARG2})
exten => _X.,n,Set(LOCAL(mbx)=${ext}${IF($[!${ISNULL(${cntx})}]?@${cntx})})
exten => _X.,n,Dial(${dev},20) ; Ring the interface, 20 seconds maximum
exten => _X.,n,Goto(stdexten-${DIALSTATUS},1) ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER)
exten => stdexten-NOANSWER,1,Voicemail(${mbx},u) ; If unavailable, send to voicemail w/ unavail announce
exten => stdexten-NOANSWER,n,Return() ; If they press #, return to start
exten => stdexten-BUSY,1,Voicemail(${mbx},b) ; If busy, send to voicemail w/ busy announce
exten => stdexten-BUSY,n,Return() ; If they press #, return to start
exten => _stde[x]te[n]-.,1,Goto(stdexten-NOANSWER,1) ; Treat anything else as no answer
exten => a,1,VoicemailMain(${mbx}) ; If they press *, send the user into VoicemailMain
exten => a,n,Return()
[stdPrivacyexten] exten => _X.,60000(stdPrivacyexten),NoOp(Start stdPrivacyexten)
exten => _X.,n,Set(LOCAL(ext)=${ARG1})
exten => _X.,n,Set(LOCAL(dev)=${ARG2})
exten => _X.,n,Set(LOCAL(dontcntx)=${ARG3})
exten => _X.,n,Set(LOCAL(tortcntx)=${ARG4})
exten => _X.,n,Set(LOCAL(cntx)=${ARG5})
exten => _X.,n,Set(LOCAL(mbx)="${ext}"$["${cntx}" ? "@${cntx}" :: ""])
exten => _X.,n,Dial(${dev},20,p) ; Ring the interface, 20 seconds maximum, call screening
exten => _X.,n,Goto(stdexten-${DIALSTATUS},1) ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER)
exten => stdexten-NOANSWER,1,Voicemail(${mbx},u) ; If unavailable, send to voicemail w/ unavail announce
exten => stdexten-NOANSWER,n,NoOp(Finish stdPrivacyexten NOANSWER)
exten => stdexten-NOANSWER,n,Return() ; If they press #, return to start
exten => stdexten-BUSY,1,Voicemail(${mbx},b) ; If busy, send to voicemail w/ busy announce
exten => stdexten-BUSY,n,NoOp(Finish stdPrivacyexten BUSY)
exten => stdexten-BUSY,n,Return() ; If they press #, return to start
exten => stdexten-DONTCALL,1,Goto(${dontcntx},s,1) ; Callee chose to send this call to a polite "Don't call again" script.
exten => stdexten-TORTURE,1,Goto(${tortcntx},s,1) ; Callee chose to send this call to a telemarketer torture script.
exten => _stde[x]te[n]-.,1,Goto(stdexten-NOANSWER,1) ; Treat anything else as no answer
exten => a,1,VoicemailMain(${mbx}) ; If they press *, send the user into VoicemailMain
exten => a,n,Return
[macro-page];
exten => s,1,ChanIsAvail(${ARG1},s) ; s is for ANY call
exten => s,n,GoToIf($[${AVAILSTATUS} = "1"]?autoanswer:fail)
exten => s,n(autoanswer),Set(_ALERT_INFO="RA") ; This is for the PolyComs
exten => s,n,SIPAddHeader(Call-Info: Answer-After=0) ; This is for the Grandstream, Snoms, and Others
exten => s,n,NoOp() ; Add others here and Post on the Wiki!!!!
exten => s,n,Dial(${ARG1})
exten => s,n(fail),Hangup
[demo] include => stdexten
exten => s,1,Wait(1) ; Wait a second, just for fun
exten => s,n,Answer ; Answer the line
exten => s,n,Set(TIMEOUT(digit)=5) ; Set Digit Timeout to 5 seconds
exten => s,n,Set(TIMEOUT(response)=10) ; Set Response Timeout to 10 seconds
exten => s,n(restart),BackGround(demo-congrats) ; Play a congratulatory message
exten => s,n(instruct),BackGround(demo-instruct) ; Play some instructions
exten => s,n,WaitExten ; Wait for an extension to be dialed.
exten => 2,1,BackGround(demo-moreinfo) ; Give some more information.
exten => 2,n,Goto(s,instruct)
exten => 3,1,Set(CHANNEL(language)=fr) ; Set language to french
exten => 3,n,Goto(s,restart) ; Start with the congratulations
exten => 1000,1,Goto(default,s,1)
exten => 1234,1,Playback(transfer,skip) ; "Please hold while..."
exten => 1234,n,Gosub(${EXTEN},stdexten(${GLOBAL(CONSOLE)}))
exten => 1234,n,Goto(default,s,1) ; exited Voicemail
exten => 1235,1,Voicemail(1234,u) ; Right to voicemail
exten => 1236,1,Dial(Console/dsp) ; Ring forever
exten => 1236,n,Voicemail(1234,b) ; Unless busy
exten => #,1,Playback(demo-thanks) ; "Thanks for trying the demo"
exten => #,n,Hangup ; Hang them up.
exten => t,1,Goto(#,1) ; If they take too long, give up
exten => i,1,Playback(invalid) ; "That's not valid, try again"
exten => 500,1,Playback(demo-abouttotry); Let them know what's going on
exten => 500,n,Dial(IAX2/[email protected]/s@default) ; Call the Asterisk demo
exten => 500,n,Playback(demo-nogo) ; Couldn't connect to the demo site
exten => 500,n,Goto(s,6) ; Return to the start over message.
exten => 600,1,Playback(demo-echotest) ; Let them know what's going on
exten => 600,n,Echo ; Do the echo test
exten => 600,n,Playback(demo-echodone) ; Let them know it's over
exten => 600,n,Goto(s,6) ; Start over
exten => 76245,1,Macro(page,SIP/Grandstream1)
exten => _7XXX,1,Macro(page,SIP/${EXTEN})
exten => 7999,1,Set(TIMEOUT(absolute)=60)
exten => 7999,2,Page(Local/Grandstream1@page&Local/Xlite1@page&Local/1234@page/n,d)
exten => 8500,1,VoicemailMain
exten => 8500,n,Goto(s,6)
[page] exten => _X.,1,Macro(page,SIP/${EXTEN})
[public] include => demo
[default] include => demo
[time] exten => _X.,30000(time),NoOp(Time: ${EXTEN} ${timezone})
exten => _X.,n,Wait(0.25)
exten => _X.,n,Answer()
exten => _X.,n,Set(FUTURETIME=$[${EPOCH} + 12])
exten => _X.,n,SayUnixTime(${FUTURETIME},Zulu,HNS)
exten => _X.,n,SayPhonetic(z)
exten => _X.,n,SayUnixTime(${FUTURETIME},${timezone},HNS)
exten => _X.,n,Playback(spy-local)
exten => _X.,n,WaitUntil(${FUTURETIME})
exten => _X.,n,Playback(beep)
exten => _X.,n,Return()
[ani] exten => _X.,40000(ani),NoOp(ANI: ${EXTEN})
exten => _X.,n,Wait(0.25)
exten => _X.,n,Answer()
exten => _X.,n,Playback(vm-from)
exten => _X.,n,SayDigits(${CALLERID(ani)})
exten => _X.,n,Wait(1.25)
exten => _X.,n,SayDigits(${CALLERID(ani)}) ; playback again in case of missed digit
exten => _X.,n,Return()