; Asterisk Management Portal (AMP) ; Copyright (C) 2004 Coalescent Systems Inc ; dialparties.agi (http://www.sprackett.com/asterisk/) ; Asterisk::AGI (http://asterisk.gnuinter.net/) ; gsm (http://www.ibiblio.org/pub/Linux/utils/compress/!INDEX.short.html) ; loligo sounds (http://www.loligo.com/asterisk/sounds/) ; mpg123 (http://voip-info.org/wiki-Asterisk+config+musiconhold.conf) ; include extension contexts generated from AMP #include extensions_additional.conf ; Customizations to this dialplan should be made in extensions_custom.conf ; See extensions_custom.conf.sample for an example #include extensions_custom.conf [from-trunk] ; just an alias since VoIP shouldn't be called PSTN include => from-pstn [from-pstn] include => from-pstn-custom ; create this context in extensions_custom.conf to include customizations include => ext-did include => from-pstn-timecheck ; this has to be included otherwise it overrides ext-did exten => fax,1,Goto(ext-fax,in_fax,1) [from-pstn-timecheck] exten => _.,1,Goto(s,1) ; catch-all matching for calls that have DID info (if a DID route hasn't matched them) exten => s,1,GotoIf($[${IN_OVERRIDE} = forcereghours]?from-pstn-reghours,s,1:) exten => s,2,GotoIf($[${IN_OVERRIDE} = forceafthours]?from-pstn-afthours,s,1:) exten => s,3,GotoIfTime(${REGTIME}|${REGDAYS}|*|*?from-pstn-reghours,s,1:) exten => s,4,Goto(from-pstn-afthours,s,1) [from-pstn-reghours] exten => s,1,GotoIf($[${FAX_RX} = disabled]?from-pstn-reghours-nofax,s,1:2) ; if fax detection is disabled, then jump to from-pstn-nofax - else continue exten => s,2,Answer exten => s,3,Playtones(ring) ; play fake ring so caller doesn't wonder what's going on exten => s,4,NVFaxDetect(4) ; detect faxes while playing ring sound - goes to "fax" extension if detected exten => s,5,SetVar(intype=${INCOMING}) exten => s,6,Cut(intype=intype,-,1) exten => s,7,GotoIf($[${intype} = EXT]?8:9) ; If INCOMING starts with EXT, then assume its an extension exten => s,8,Goto(ext-local,${INCOMING:4},1) exten => s,9,GotoIf($[${intype} = GRP]?10:11) ; If INCOMING starts with GRP, then assume its a ring group exten => s,10,Goto(ext-group,${INCOMING:4},1) exten => s,11,GotoIf($[${intype} = QUE]?12:13) exten => s,12,Goto(ext-queues,${INCOMING:4},1) exten => s,13,Goto(${INCOMING},s,1) ; not EXT or GR1 - it's an auto attendant exten => fax,1,Goto(ext-fax,in_fax,1) exten => h,1,Hangup [from-pstn-reghours-nofax] exten => s,1,SetVar(intype=${INCOMING}) exten => s,2,Cut(intype=intype,-,1) exten => s,3,GotoIf($[${intype} = EXT]?4:5) ; If INCOMING starts with EXT, then assume its an extension exten => s,4,Goto(ext-local,${INCOMING:4},1) exten => s,5,GotoIf($[${intype} = GRP]?6:7) ; If INCOMING starts with GRP, then assume its a ring group exten => s,6,Goto(ext-group,${INCOMING:4},1) exten => s,7,GotoIf($[${intype} = QUE]?8:11) ;queue exten => s,8,Answer ; answer call before queue exten => s,9,Wait(1) exten => s,10,Goto(ext-queues,${INCOMING:4},1) exten => s,11,Answer ; answer call before auto attendant exten => s,12,Wait(1) exten => s,13,Goto(${INCOMING},s,1) ; not EXT or GR1 - it's an auto attendant exten => h,1,Hangup [from-pstn-afthours] exten => s,1,GotoIf($[${FAX_RX} = disabled]?from-pstn-afthours-nofax,s,1:2) ; if fax detection is disabled, then jump to from-pstn-nofax - else continue exten => s,2,Answer exten => s,3,Playtones(ring) ; play fake ring so caller doesn't wonder what's going on exten => s,4,NVFaxDetect(4) ; detect faxes while playing ring sound - goes to "fax" extension if detected exten => s,5,SetVar(intype=${AFTER_INCOMING}) exten => s,6,Cut(intype=intype,-,1) exten => s,7,GotoIf($[${intype} = EXT]?8:9) ; If INCOMING starts with EXT, then assume its an extension exten => s,8,Goto(ext-local,${AFTER_INCOMING:4},1) exten => s,9,GotoIf($[${intype} = GRP]?10:11) ; If INCOMING starts with GRP, then assume its a ring group exten => s,10,Goto(ext-group,${AFTER_INCOMING:4},1) exten => s,11,GotoIf($[${intype} = QUE]?12:13) exten => s,12,Goto(ext-queues,${AFTER_INCOMING:4},1) exten => s,13,Goto(${AFTER_INCOMING},s,1) ; not EXT or GR1 - it's an auto attendant exten => fax,1,Goto(ext-fax,in_fax,1) exten => h,1,Hangup [from-pstn-afthours-nofax] exten => s,1,SetVar(intype=${AFTER_INCOMING}) exten => s,2,Cut(intype=intype,-,1) exten => s,3,GotoIf($[${intype} = EXT]?4:5) ; If INCOMING starts with EXT, then assume its an extension exten => s,4,Goto(ext-local,${AFTER_INCOMING:4},1) exten => s,5,GotoIf($[${intype} = GRP]?6:7) ; If INCOMING starts with GRP, then assume its a ring group exten => s,6,Goto(ext-group,${AFTER_INCOMING:4},1) exten => s,7,GotoIf($[${intype} = QUE]?8:11) ;queue exten => s,8,Answer ; answer call before queue exten => s,9,Wait(1) exten => s,10,Goto(ext-queues,${AFTER_INCOMING:4},1) exten => s,11,Answer ; answer call before auto attendant exten => s,12,Wait(1) exten => s,13,Goto(${AFTER_INCOMING},s,1) ; not EXT or GR1 - it's an auto attendant exten => h,1,Hangup ; ############################################################################ ; Macros [macro] ; ############################################################################ ; Rings one or more extensions. Handles things like call forwarding and DND ; We don't call dial directly for anything internal anymore. ; ARGS: $TIMER, $OPTIONS, $EXT1, $EXT2, $EXT3, ... ; Use a Macro call such as the following: ; Macro(dial,$DIAL_TIMER,$DIAL_OPTIONS,$EXT1,$EXT2,$EXT3,...) [macro-dial] exten => s,1,GotoIf($[ "${MACRO_CONTEXT}" = "macro-rg-group" ]?4:2) ; if this is from rg-group, don't strip prefix exten => s,2,GotoIf($["${CALLERIDNAME:0:${LEN(${RGPREFIX})}}" != "${RGPREFIX}"]?5:4) ; check for ring-group prefix exten => s,3,SetCIDName(${CALLERIDNAME:${LEN(${RGPREFIX})}}) ; strip off prefix exten => s,4,AGI,dialparties.agi exten => s,5,NoOp(Returned from dialparties with no extensions to call) exten => s,6,SetVar(DIALSTATUS=BUSY) exten => s,10,Dial(${ds}) ; dialparties will set the priority to 10 if $ds is not null exten => s,20,NoOp(Returned from dialparties with hunt groups to dial ) exten => s,21,SetVar(HuntLoop=0) exten => s,22,GotoIf($[$[${HuntMembers}] >= 1]?30 ) ; if this is from rg-group, don't strip prefix exten => s,23,NoOp(Returning there are no members left in the hunt group to ring) exten => s,30,SetVar(HuntMember=HuntMember${HuntLoop}) exten => s,31,GotoIf($[$[${CALLTRACE_HUNT} != "" ] & $["${RingGroupMethod}" = "hunt" ]]?32:35 ) ; Set CAll Trace for Hunt member we are going to call exten => s,32,Cut(CT_EXTEN=ARG3,,$[${HuntLoop} + 1]) exten => s,33,DBput(CALLTRACE/${CT_EXTEN}=${CALLTRACE_HUNT}) exten => s,34,Goto(s,42) exten => s,35,GotoIf($[$[${CALLTRACE_HUNT} != "" ] & $["${RingGroupMethod}" = "memoryhunt" ]]?36:50 ) ;Set Call Trace for each hunt member we are going to call "Memory groups have multiple members to set CALL TRACE For hence the loop exten => s,36,SetVar(CTLoop=0) exten => s,37,GotoIf($[${CTLoop} > ${HuntLoop}]?42 ) ; if this is from rg-group, don't strip prefix exten => s,38,Cut(CT_EXTEN=ARG3,,$[${CTLoop} + 1]) exten => s,39,DBput(CALLTRACE/${CT_EXTEN}=${CALLTRACE_HUNT}) exten => s,40,SetVar(CTLoop=$[1 + ${CTLoop}]) exten => s,41,Goto(s,37) exten => s,42,Dial(${${HuntMember}}${ds} ) ; dialparties will set the priority to 20 if $ds is not null and its a hunt group exten => s,43,SetVar(HuntLoop=$[1 + ${HuntLoop}]) exten => s,44,SetVar(HuntMembers=$[${HuntMembers} - 1]) exten => s,45,Goto(s,22) exten => s,50,DBdel(CALLTRACE/${CT_EXTEN}) exten => s,51,Goto(s,42) ;exten => s,1,GotoIf($[ "${MACRO_CONTEXT}" = "macro-rg-group" ]?4:2) ; if this is from rg-group, don't strip prefix ;exten => s,2,GotoIf($[${CALLERIDNAME:0:${LEN(${RGPREFIX})}} != ${RGPREFIX}]?4:3) ; check for ring-group prefix ;exten => s,3,SetCIDName(${CALLERIDNAME:${LEN(${RGPREFIX})}}) ; strip off prefix ;exten => s,4,AGI,dialparties.agi ;exten => s,5,NoOp(Returned from dialparties with no extensions to call) ;exten => s,6,SetVar(DIALSTATUS=BUSY) ;exten => s,10,Dial(${ds}) ; dialparties will set the priority to 10 if $ds is not null ; Ring an extension, if the extension is busy or there is no answer send it ; to voicemail ; ARGS: $VMBOX, $EXT [macro-exten-vm] exten => s,1,Macro(user-callerid) exten => s,2,Setvar(FROMCONTEXT=exten-vm) exten => s,3,Macro(record-enable,${ARG2},IN) exten => s,4,Macro(dial,${RINGTIMER},${DIAL_OPTIONS},${ARG2}) exten => s,5,GotoIf($[${CHANNEL:0:5} = Local]?s-${DIALSTATUS},1) ; if the channel is Local, then do not go to voicemail. This is primarily to avoid vm for call-forwarded extensions in ring groups exten => s,6,GotoIf($[${ARG1} = novm]?s-${DIALSTATUS},1) ; no voicemail in use for this extension exten => s,7,NoOp(Sending to Voicemail box ${ARG2}) exten => s,8,Macro(vm,${ARG1},${DIALSTATUS}) exten => s-BUSY,1,NoOp(Extension is reporting BUSY and has no Voicemail) exten => s-BUSY,2,Busy() exten => s-BUSY,3,Wait(60) exten => s-BUSY,4,NoOp() exten => _s-.,1,Congestion() [macro-vm] exten => s,1,Macro(user-callerid) exten => s,2,Goto(s-${ARG2},1) exten => s-BUSY,1,Voicemail(b${ARG1}) ; Voicemail Busy message exten => s-BUSY,2,Hangup() exten => _s-.,1,Voicemail(u${ARG1}) ; Voicemail Unavailable message exten => _s-.,2,Hangup() exten => o,1,Background(one-moment-please) ; 0 during vm message will hangup exten => o,2,GotoIf($["foo${FROM_DID}" = "foo"]?from-pstn,s,1:from-pstn,${FROM_DID},1) exten => a,1,VoiceMailMain(${ARG1}) exten => a,2,Hangup ; For some reason, if I don't run setCIDname, CALLERIDNAME will be blank in my AGI ; ARGS: none [macro-fixcid] exten => s,1,SetCIDName(${CALLERIDNAME}) ; Ring groups of phones ; ARGS: comma separated extension list ; 1 - Ring Group Strategy ; 2 - ringtimer ; 3 - prefix ; 4 - extension list [macro-rg-group] exten => s,1,Macro(user-callerid) exten => s,2,GotoIf($[${CALLERIDNAME:0:${LEN(${RGPREFIX})}} != ${RGPREFIX}]?4:3) ; check for old prefix exten => s,3,SetCIDName(${CALLERIDNAME:${LEN(${RGPREFIX})}}) ; strip off old prefix exten => s,4,Setvar(RGPREFIX=${ARG3}) ; set new prefix exten => s,5,SetCIDName(${RGPREFIX}${CALLERIDNAME}) ; add prefix to callerid name exten => s,6,Setvar(RecordMethod=Group) ; set new prefix exten => s,7,Macro(record-enable,${MACRO_EXTEN},${RecordMethod}) exten => s,8,SetVar(RingGroupMethod=${ARG1}) ; exten => s,9,Macro(dial,${ARG2},${DIAL_OPTIONS},${ARG4}) exten => s,10,SetVar(RingGroupMethod='') ; ; ; Outgoing channel(s) are busy ... inform the client ; [macro-outisbusy] exten => s,1,Playback(all-circuits-busy-now) exten => s,2,Playback(pls-try-call-later) exten => s,3,Macro(hangupcall) ; What to do on hangup. [macro-hangupcall] exten => s,1,ResetCDR(w) exten => s,2,NoCDR() exten => s,3,Wait(5) exten => s,4,Hangup [macro-faxreceive] exten => s,1,SetVar(FAXFILE=/var/spool/asterisk/fax/${UNIQUEID}.tif) exten => s,2,SetVar(EMAILADDR=${FAX_RX_EMAIL}) exten => s,3,rxfax(${FAXFILE}) exten => s,103,SetVar(EMAILADDR=${FAX_RX_EMAIL}) exten => s,104,Goto(3) ; dialout and strip the prefix [macro-dialout] exten => s,1,Macro(user-callerid) exten => s,2,GotoIf($[foo${ECID${CALLERIDNUM}} = foo]?5) ;check for CID override for exten exten => s,3,SetCallerID(${ECID${CALLERIDNUM}}) exten => s,4,Goto(7) exten => s,5,GotoIf($[foo${OUTCID_${ARG1}} = foo]?7) ;check for CID override for trunk exten => s,6,SetCallerID(${OUTCID_${ARG1}}) exten => s,7,SetVar(length=${LEN(${DIAL_OUT_${ARG1}})}) exten => s,8,Dial(${OUT_${ARG1}}/${ARG2:${length}}) exten => s,9,Congestion exten => s,109,Macro(outisbusy) ; dialout using default OUT trunk - no prefix [macro-dialout-default] exten => s,1,Macro(user-callerid) exten => s,2,Macro(record-enable,${CALLERIDNUM},OUT) exten => s,3,Macro(outbound-callerid,${ARG1}) exten => s,4,Dial(${OUT}/${ARG1}) exten => s,5,Congestion exten => s,105,Macro(outisbusy) ; dialout using a trunk, using pattern matching (don't strip any prefix) ; arg1 = trunk number, arg2 = number, arg3 = route password [macro-dialout-trunk] exten => s,1,GotoIf($[foo${ARG3} = foo]?3:2)) ; arg3 is pattern password exten => s,2,Authenticate(${ARG3}) exten => s,3,Macro(user-callerid) exten => s,4,Macro(record-enable,${CALLERIDNUM},OUT) exten => s,5,Macro(outbound-callerid,${ARG1}) exten => s,6,SetGroup(OUT_${ARG1}) ;exten => s,7,CheckGroup(${OUTMAXCHANS_${ARG1}}) exten => s,7,GotoIf($[ ${GROUP_COUNT()} > ${OUTMAXCHANS_${ARG1}}]?108) ; if we've used up the max channels, continue at (n+101) exten => s,8,SetVar(DIAL_NUMBER=${ARG2}) exten => s,9,SetVar(DIAL_TRUNK=${ARG1}) exten => s,10,AGI(fixlocalprefix) ; this sets DIAL_NUMBER to the proper dial string for this trunk exten => s,11,SetVar(OUTNUM=${OUTPREFIX_${ARG1}}${DIAL_NUMBER}) ; OUTNUM is the final dial number exten => s,12,Cut(custom=OUT_${ARG1},:,1) ; Custom trunks are prefixed with "AMP:" exten => s,13,GotoIf($[${custom} = AMP]?16) exten => s,14,Dial(${OUT_${ARG1}}/${OUTNUM}) ; Regular Trunk Dial exten => s,15,Goto(s-${DIALSTATUS},1) ; This is a custom trunk. Substitute $OUTNUM$ with the actual number and rebuild the dialstring ; example trunks: "AMP:CAPI/XXXXXXXX:b$OUTNUM$,30,r", "AMP:OH323/$OUTNUM$@XX.XX.XX.XX:XXXX" exten => s,16,Cut(pre_num=OUT_${ARG1},$,1) exten => s,17,Cut(the_num=OUT_${ARG1},$,2) ; this is where we expect to find string OUTNUM exten => s,18,Cut(post_num=OUT_${ARG1},$,3) exten => s,19,GotoIf($[${the_num} = OUTNUM]?20:21) ; if we didn't find "OUTNUM", then skip to Dial exten => s,20,SetVar(the_num=${OUTNUM}) ; replace "OUTNUM" with the actual number to dial exten => s,21,Dial(${pre_num:4}${the_num}${post_num}) exten => s,22,Goto(s-${DIALSTATUS},1) exten => s,108,Noop(max channels used up) exten => s-BUSY,1,NoOp(Trunk is reporting BUSY) exten => s-BUSY,2,Busy() exten => s-BUSY,3,Wait(60) exten => s-BUSY,4,NoOp() exten => _s-.,1,NoOp(Dial failed due to ${DIALSTATUS}) ; Adds a dynamic agent/member to a Queue ; Prompts for call-back number - in not entered, uses CIDNum [macro-agent-add] exten => s,1,Wait(1) exten => s,2,Macro(user-callerid) exten => s,3,Read(CALLBACKNUM,agent-user) ; get callback number from user exten => s,4,GotoIf($[foo${CALLBACKNUM} = foo]?5:7)) ; if user just pressed # or timed out, use cidnum exten => s,5,SetVar(CALLBACKNUM=${CALLERIDNUM}) exten => s,6,GotoIf($[foo${CALLBACKNUM} = foo]?2)) ; if still no number, start over exten => s,7,GotoIf($[foo${ARG2} = foo]?9:8)) ; arg2 is queue password exten => s,8,Authenticate(${ARG2}) exten => s,9,AddQueueMember(${ARG1}|Local/${CALLBACKNUM}@from-internal) ; using chan_local allows us to have agents over trunks exten => s,10,Wait(1) exten => s,11,Playback(agent-loginok) exten => s,12,Hangup() ; Removes a dynamic agent/member from a Queue ; Prompts for call-back number - in not entered, uses CIDNum [macro-agent-del] exten => s,1,Wait(1) exten => s,2,Macro(user-callerid) exten => s,3,Read(CALLBACKNUM,agent-user) ; get callback number from user exten => s,4,GotoIf($[foo${CALLBACKNUM} = foo]?5:7)) ; if user just pressed # or timed out, use cidnum exten => s,5,SetVar(CALLBACKNUM=${CALLERIDNUM}) exten => s,6,GotoIf($[foo${CALLBACKNUM} = foo]?2)) ; if still no number, start over exten => s,7,RemoveQueueMember(${ARG1}|Local/${CALLBACKNUM}@from-internal) exten => s,8,Wait(1) exten => s,9,Playback(agent-loggedoff) exten => s,10,Hangup() ; arg1 = trunk number, arg2 = number [macro-dialout-enum] exten => s,1,Macro(user-callerid) exten => s,2,Macro(record-enable,${CALLERIDNUM},OUT) exten => s,3,Macro(outbound-callerid,${ARG1}) exten => s,4,SetGroup(OUT_${ARG1}) exten => s,5,CheckGroup(${OUTMAXCHANS_${ARG1}}) ; if we've used up the max channels, continue at (n+101) exten => s,6,SetVar(DIAL_NUMBER=${ARG2}) exten => s,7,SetVar(DIAL_TRUNK=${ARG1}) exten => s,8,AGI(fixlocalprefix) ; this sets DIAL_NUMBER to the proper dial string for this trunk exten => s,9,EnumLookup(${DIAL_NUMBER}) exten => s,10,GotoIf($[$[${ENUM:0:3} = SIP] | $[${ENUM:0:3} = IAX]]?11:63) exten => s,11,Dial(${ENUM}) exten => s,12,Goto(s-${DIALSTATUS},1) ; if dial fails (ie, all channels are busy), continue at 116 (n+101) ; exit points for macro exten => s,63,NoOp(EnumLookup failed) exten => s,106,NoOp(max channels used up) exten => s-BUSY,1,NoOp(Trunk is reporting BUSY) exten => s-BUSY,2,Busy() exten => s-BUSY,3,Wait(60) exten => s-BUSY,4,NoOp() exten => _s-.,1,NoOp(Dial failed due to ${DIALSTATUS}) [macro-record-enable] exten => s,1,GotoIf(${LEN(${BLINDTRANSFER})} > 0?2:4) exten => s,2,ResetCDR(w) exten => s,3,StopMonitor() exten => s,4,AGI(recordingcheck,${TIMESTAMP},${UNIQUEID}) exten => s,5,Noop(No recording needed) exten => s,999,Monitor(wav49,${CALLFILENAME}, mb) ;exten => s,3,BackGround(for-quality-purposes) ;exten => s,4,BackGround(this-call-may-be) ;exten => s,5,BackGround(recorded) ; This macro is for dev purposes and just dumps channel/app variables. Useful when designing new contexts. [macro-dumpvars] exten => s,1,Noop(ACCOUNTCODE=${ACCOUNTCODE}) exten => s,2,Noop(ANSWEREDTIME=${ANSWEREDTIME}) exten => s,3,Noop(BLINDTRANSFER=${BLINDTRANSFER}) exten => s,4,Noop(CALLERID=${CALLERID}) exten => s,5,Noop(CALLERIDNAME=${CALLERIDNAME}) exten => s,6,Noop(CALLERIDNUM=${CALLERIDNUM}) exten => s,7,Noop(CALLINGPRES=${CALLINGPRES}) exten => s,8,Noop(CHANNEL=${CHANNEL}) exten => s,9,Noop(CONTEXT=${CONTEXT}) exten => s,10,Noop(DATETIME=${DATETIME}) exten => s,11,Noop(DIALEDPEERNAME=${DIALEDPEERNAME}) exten => s,12,Noop(DIALEDPEERNUMBER=${DIALEDPEERNUMBER}) exten => s,13,Noop(DIALEDTIME=${DIALEDTIME}) exten => s,14,Noop(DIALSTATUS=${DIALSTATUS}) exten => s,15,Noop(DNID=${DNID}) exten => s,16,Noop(EPOCH=${EPOCH}) exten => s,17,Noop(EXTEN=${EXTEN}) exten => s,18,Noop(HANGUPCAUSE=${HANGUPCAUSE}) exten => s,19,Noop(INVALID_EXTEN=${INVALID_EXTEN}) exten => s,20,Noop(LANGUAGE=${LANGUAGE}) exten => s,21,Noop(MEETMESECS=${MEETMESECS}) exten => s,22,Noop(PRIORITY=${PRIORITY}) exten => s,23,Noop(RDNIS=${RDNIS}) exten => s,24,Noop(SIPDOMAIN=${SIPDOMAIN}) exten => s,25,Noop(SIP_CODEC=${SIP_CODEC}) exten => s,26,Noop(SIPCALLID=${SIPCALLID}) exten => s,27,Noop(SIPUSERAGENT=${SIPUSERAGENT}) exten => s,28,Noop(TIMESTAMP=${TIMESTAMP}) exten => s,29,Noop(TXTCIDNAME=${TXTCIDNAME}) exten => s,30,Noop(UNIQUEID=${UNIQUEID}) exten => s,31,Noop(TOUCH_MONITOR=${TOUCH_MONITOR}) exten => s,32,Noop(MACRO_CONTEXT=${MACRO_CONTEXT}) exten => s,33,Noop(MACRO_EXTEN=${MACRO_EXTEN}) exten => s,34,Noop(MACRO_PRIORITY=${MACRO_PRIORITY}) [macro-user-logon] ; check device type exten => s,1,DBget(DEVICETYPE=DEVICE/${CALLERIDNUM}/type) exten => s,2,GotoIf($[${DEVICETYPE} = fixed]?s-FIXED,1) ; get user's extension exten => s,3,SetVar(AMPUSER=${ARG1}) exten => s,4,GotoIf($[foo${AMPUSER} = foo]?5:9) exten => s,5,BackGround(please-enter-your) exten => s,6,Playback(extension) exten => s,7,Read(AMPUSER,then-press-pound) ; get user's password and authenticate exten => s,8,Wait(1) exten => s,9,DBget(AMPUSERPASS=AMPUSER/${AMPUSER}/password) exten => s,10,GotoIf($[${LEN(${AMPUSERPASS})} = 0]?s-NOPASSWORD,1) ; do not continue if the user has already logged onto this device exten => s,11,DBget(DEVICEUSER=DEVICE/${CALLERIDNUM}/user) exten => s,12,GotoIf($[${DEVICEUSER} = ${AMPUSER}]?s-ALREADYLOGGEDON,1) exten => s,13,Authenticate(${AMPUSERPASS}) ; devices can only be mapped to one user - loggoff anyone else who is here exten => s,14,Macro(user-logoff) ; map user to device exten => s,15,DBget(AMPUSERDEVICES=AMPUSER/${AMPUSER}/device) exten => s,16,GotoIf($[${LEN(${AMPUSERDEVICES})} = 0]?18) exten => s,17,SetVar(AMPUSERDEVICES=${AMPUSERDEVICES}&) exten => s,18,SetVar(AMPUSERDEVICES=${AMPUSERDEVICES}${CALLERIDNUM}) exten => s,19,DBPut(AMPUSER/${AMPUSER}/device=${AMPUSERDEVICES}) ; map device to user exten => s,20,DBPut(DEVICE/${CALLERIDNUM}/user=${AMPUSER}) ; create symlink from dummy device mailbox to user's mailbox exten => s,21,System(/bin/ln -s /var/spool/asterisk/voicemail/default/${AMPUSER}/ /var/spool/asterisk/voicemail/device/${CALLERIDNUM}) exten => s-FIXED,1,NoOp(Device is FIXED and cannot be logged into) exten => s-FIXED,2,Playback(ha/phone) exten => s-FIXED,3,SayDigits(${CALLERIDNUM}) exten => s-FIXED,4,Playback(is-curntly-unavail) exten => s-FIXED,5,Playback(vm-goodbye) exten => s-FIXED,6,Hangup ;TODO should play msg indicated device cannot be logged into exten => s-ALREADYLOGGEDON,1,NoOp(This device has already been logged into by this user) exten => s-ALREADYLOGGEDON,2,Playback(vm-goodbye) exten => s-ALREADYLOGGEDON,3,Hangup ;TODO should play msg indicated device is already logged into exten => s-NOPASSWORD,1,NoOp(This extension does not exist or no password is set) exten => s-NOPASSWORD,2,Playback(an-error-has-occured) exten => s-NOPASSWORD,3,Playback(vm-goodbye) exten => s-NOPASSWORD,4,Hangup ;TODO should play msg indicated device is already logged into [macro-user-logoff] ; check device type exten => s,1,DBget(DEVICETYPE=DEVICE/${CALLERIDNUM}/type) exten => s,2,GotoIf($[${DEVICETYPE} = fixed]?s-FIXED,1) ; remove entry from user's DEVICE key ; delete the symlink to user's voicemail box exten => s,3,System(rm -f /var/spool/asterisk/voicemail/device/${CALLERIDNUM}) exten => s,4,DBget(DEVAMPUSER=DEVICE/${CALLERIDNUM}/user) exten => s,5,DBget(AMPUSERDEVICES=AMPUSER/${DEVAMPUSER}/device) exten => s,6,AGI(list-item-remove.php,${AMPUSERDEVICES},${CALLERIDNUM},AMPUSERDEVICES,&) ; reset user -> device mapping ; users can log onto multiple devices, need to just remove device from value exten => s,7,DBput(AMPUSER/${DEVAMPUSER}/device=${AMPUSERDEVICES}) ; reset device -> user mapping exten => s,8,DBput(DEVICE/${CALLERIDNUM}/user=none) exten => s,9,Playback(vm-goodbye) exten => s-FIXED,1,NoOp(Device is FIXED and cannot be logged out of) exten => s-FIXED,2,Playback(an-error-has-occured) exten => s-FIXED,3,Playback(vm-goodbye) exten => s-FIXED,4,Hangup ;TODO should play msg indicated device cannot be logged into ;sets the callerid of the device to that of the logged in user [macro-user-callerid] exten => s,1,DBget(AMPUSER=DEVICE/${CALLERIDNUM}/user) exten => s,2,DBget(AMPUSERCIDNAME=AMPUSER/${AMPUSER}/cidname) exten => s,3,GotoIf($["foo${AMPUSERCIDNAME}" = "foo"]?5) exten => s,4,SetCallerID(\"${AMPUSERCIDNAME}\" <${AMPUSER}>) exten => s,5,NoOp(Using CallerID ${CALLERID}) ; overrides callerid out trunks ; arg1 is trunk ; macro-user-callerid should be called _before_ using this macro [macro-outbound-callerid] exten => s,1,DBget(USEROUTCID=AMPUSER/${CALLERIDNUM}/outboundcid) exten => s,2,GotoIf($["foo${OUTCID_${ARG1}:1:2}" = "foo"]?4) ;check for CID override for trunk exten => s,3,SetCallerID(${OUTCID_${ARG1}}) exten => s,4,GotoIf($["foo${USEROUTCID:1:2}" = "foo"]?6) ; check CID override for extension exten => s,5,SetCallerID(${USEROUTCID}) exten => s,6,NoOp(CallerID set to ${CALLERID}) ; ############################################################################ ; Applications [app] ; ############################################################################ ; [app-directory] ;DIR-CONTEXT set in Digital Receptionist exten => #,1,Wait(1) exten => #,2,AGI(directory,${DIR-CONTEXT},ext-local,${DIRECTORY:0:1}${DIRECTORY_OPTS}o) exten => #,3,Playback(vm-goodbye) exten => #,4,Hangup ; *411 will access the entire directory (not just a single context) exten => *411,1,Answer exten => *411,2,Wait(1) exten => *411,3,AGI(directory,general,ext-local,${DIRECTORY:0:1}${DIRECTORY_OPTS}) exten => *411,4,Playback(vm-goodbye) exten => *411,5,Hangup exten => h,1,Hangup exten => o,1,GotoIf($["foo${FROM_DID}" = "foo"]?from-pstn,s,1:from-pstn,${FROM_DID},1) [app-dnd] exten => *78,1,Answer exten => *78,2,Wait(1) exten => *78,3,Macro(user-callerid) exten => *78,4,DBput(DND/${CALLERIDNUM}=YES) exten => *78,5,Playback(do-not-disturb) exten => *78,6,Playback(activated) exten => *78,7,Macro(hangupcall) exten => *79,1,Answer exten => *79,2,Wait(1) exten => *79,3,Macro(user-callerid) exten => *79,4,DBdel(DND/${CALLERIDNUM}) exten => *79,5,Playback(do-not-disturb) exten => *79,6,Playback(de-activated) exten => *79,7,Macro(hangupcall) [app-messagecenter] exten => *98,1,Answer exten => *98,2,Wait(1) exten => *98,3,VoiceMailMain(default) exten => *98,4,Macro(hangupcall) exten => _*98X.,1,Answer ; can dial *98 to skip 'mailbox' prompt. Useful for speedial. exten => _*98X.,2,Wait(1) exten => _*98X.,3,VoiceMailMain(${EXTEN:3}@default) exten => _*98X.,4,Macro(hangupcall) exten => *97,1,Answer exten => *97,2,Wait(1) exten => *97,3,Macro(user-callerid) exten => *97,4,VoicemailMain(${CALLERIDNUM}@default) exten => *97,5,Macro(hangupcall) exten => asterisk,1,VoiceMailMain(${CALLERIDNUM}) [app-callwaiting] exten => *70,1,Answer exten => *70,2,Wait(1) exten => *70,3,Macro(user-callerid) exten => *70,4,DBput(CW/${CALLERIDNUM}=ENABLED) exten => *70,5,Playback(call-waiting) exten => *70,6,Playback(activated) exten => *70,7,Macro(hangupcall) exten => *71,1,Answer exten => *71,2,Wait(1) exten => *71,3,Macro(user-callerid) exten => *71,4,DBdel(CW/${CALLERIDNUM}) exten => *71,5,Playback(call-waiting) exten => *71,6,Playback(de-activated) exten => *71,7,Macro(hangupcall) [app-callforward] ; dialed call forward app - forwards calling extension exten => _*72.,1,Macro(user-callerid) exten => _*72.,2,DBput(CF/${CALLERIDNUM}=${EXTEN:3}) exten => _*72.,3,Answer exten => _*72.,4,Wait(1) exten => _*72.,5,Playback(call-fwd-unconditional) exten => _*72.,6,Playback(for) exten => _*72.,7,Playback(extension) exten => _*72.,8,SayDigits(${CALLERIDNUM}) exten => _*72.,9,Playback(is-set-to) exten => _*72.,10,SayDigits(${EXTEN:3}) exten => _*72.,11,Macro(hangupcall) ; prompting call forward app - forwards entered extension exten => *72,1,Answer exten => *72,2,Wait(1) exten => *72,3,BackGround(please-enter-your) exten => *72,4,Playback(extension) exten => *72,5,Read(fromext,then-press-pound) exten => *72,6,Wait(1) exten => *72,7,BackGround(ent-target-attendant) exten => *72,8,Read(toext,then-press-pound) exten => *72,9,Wait(1) exten => *72,10,DBput(CF/${fromext}=${toext}) exten => *72,11,Playback(call-fwd-unconditional) exten => *72,12,Playback(for) exten => *72,13,Playback(extension) exten => *72,14,SayDigits(${fromext}) exten => *72,15,Playback(is-set-to) exten => *72,16,SayDigits(${toext}) exten => *72,17,Macro(hangupcall) ; cancels dialed extension call forward exten => _*73.,1,DBdel(CF/${EXTEN:3}) exten => _*73.,2,Answer exten => _*73.,3,Wait(1) exten => _*73.,4,SayDigits(${EXTEN:3}) exten => _*73.,5,Playback(call-fwd-cancelled) exten => _*73.,6,Macro(hangupcall) ; cancels call forward for calling extension exten => *73,1,Macro(user-callerid) exten => *73,2,DBdel(CF/${CALLERIDNUM}) exten => *73,3,Answer exten => *73,4,Wait(1) exten => *73,5,Playback(call-fwd-cancelled) exten => *73,6,Macro(hangupcall) ; dialed call forward on busy app - forwards calling extension when busy exten => _*90.,1,Macro(user-callerid) exten => _*90.,2,DBput(CFB/${CALLERIDNUM}=${EXTEN:3}) exten => _*90.,3,Answer exten => _*90.,4,Wait(1) exten => _*90.,5,Playback(call-fwd-on-busy) exten => _*90.,6,Playback(for) exten => _*90.,7,Playback(extension) exten => _*90.,8,SayDigits(${CALLERIDNUM}) exten => _*90.,9,Playback(is-set-to) exten => _*90.,10,SayDigits(${EXTEN:3}) exten => _*90.,11,Macro(hangupcall) ; cancels call forward on busy for calling extension exten => *91,1,Macro(user-callerid) exten => *91,2,DBdel(CFB/${CALLERIDNUM}) exten => *91,3,Answer exten => *91,4,Wait(1) exten => *91,5,Playback(call-fwd-on-busy) exten => *91,6,Playback(de-activated) exten => *91,7,Macro(hangupcall) exten => h,1,Hangup [app-calltrace] ; We can't have our timeouts or dial digits collide with other applications ; or extensions, so we build the app in pieces exten => *69,1,Goto(app-calltrace-perform,s,1) [app-calltrace-perform] exten => s,1,Macro(user-callerid) exten => s,2,Answer exten => s,3,Wait(1) exten => s,4,Background(info-about-last-call) exten => s,5,Background(telephone-number) exten => s,6,Dbget(lastcaller=CALLTRACE/${CALLERIDNUM}) exten => s,7,GotoIf($[${lastcaller}]?8:14) exten => s,8,SayDigits(${lastcaller}) exten => s,9,DigitTimeout(3) exten => s,10,ResponseTimeout(7) exten => s,11,Background(to-call-this-number) exten => s,12,Background(press-1) exten => s,13,Goto(16) exten => s,14,Playback(from-unknown-caller) exten => s,15,Macro(hangupcall) exten => s,16,NoOp exten => 1,1,Goto(from-internal,${lastcaller},1); exten => i,1,Playback(vm-goodbye) exten => i,2,Macro(hangupcall) exten => t,1,Playback(vm-goodbye) exten => t,2,Macro(hangupcall) [app-userlogonoff] exten => *11,1,Macro(user-logon) exten => *11,2,Hangup() exten => _*11.,1,Macro(user-logon,${EXTEN:3}) exten => _*11.,2,Hangup() exten => *12,1,Macro(user-logoff) exten => *12,2,Hangup() ; ############################################################################ ; Inbound Contexts [from] ; ############################################################################ [from-sip-external] ;give external sip users congestion and hangup exten => _.,1,AbsoluteTimeout(15) exten => _.,2,Congestion exten => _.,3,Hangup [from-internal] ;allow phones to use applications include => app-userlogonoff include => app-directory include => app-dnd include => app-callforward include => app-callwaiting include => app-messagecenter include => app-calltrace include => parkedcalls include => from-internal-custom ;allow phones to dial other extensions include => ext-fax include => ext-local include => ext-group include => ext-queues include => ext-zapbarge include => ext-meetme include => ext-record include => ext-test ;allow phones to access trunks include => outbound-allroutes exten => s,1,Macro(hangupcall) exten => h,1,Macro(hangupcall) ; ############################################################################ ; Extension Contexts [ext] ; ############################################################################ [ext-zapbarge] exten => 888,1,Macro(user-callerid) exten => 888,2,SetGroup(${CALLERIDNUM}) exten => 888,3,Answer exten => 888,4,Wait(1) exten => 888,5,ZapBarge exten => 888,6,Hangup [ext-meetme] exten => _111,1,Answer exten => _111,2,Wait(1) exten => _111,3,GotoIf($[${CALLERIDNUM} = ${EXTEN:1}]?5:4) exten => _111,4,MeetMe(${EXTEN}|sM) exten => _111,5,MeetMe(${EXTEN}|asM) exten => _112,1,Answer exten => _112,2,Wait(1) exten => _112,3,GotoIf($[${CALLERIDNUM} = ${EXTEN:1}]?5:4) exten => _112,4,MeetMe(${EXTEN}|sM) exten => _112,5,MeetMe(${EXTEN}|asM) [ext-fax] exten => s,1,Answer exten => s,2,Goto(in_fax,1) exten => in_fax,1,StopPlaytones ; you must do this or it will play ring sounds over your fax exten => in_fax,2,GotoIf($[${FAX_RX} = system]?3:analog_fax,1) exten => in_fax,3,Macro(faxreceive) exten => in_fax,4,Hangup exten => analog_fax,1,GotoIf($[${FAX_RX} = disabled]?3:2) ;if fax is disabled, just hang up exten => analog_fax,2,DBGet(DIAL=DEVICE/${FAX_RX}/dial); exten => analog_fax,3,Dial(${DIAL},20,d) exten => analog_fax,4,Hangup exten => out_fax,1,txfax(${TXFAX_NAME}|caller) exten => out_fax,2,Hangup exten => h,1,system(tiff2ps -2eaz ${FAXFILE} | ps2pdf - ${FAXFILE}.pdf) exten => h,2,system(mime-construct --to ${EMAILADDR} --subject "Fax from ${CALLERIDNUM} ${CALLERIDNAME}" --attachment ${CALLERIDNUM}.pdf --type application/pdf --file ${FAXFILE}.pdf) exten => h,3,system(rm ${FAXFILE} ${FAXFILE}.pdf) exten => h,4,Hangup() [ext-record] exten => *77,1,Macro(user-callerid) exten => *77,2,Wait(2) exten => *77,3,Record(${CALLERIDNUM}ivrrecording:wav) exten => *77,4,Wait(2) exten => *77,5,Hangup exten => *99,1,Macro(user-callerid) exten => *99,2,Playback(${CALLERIDNUM}ivrrecording) exten => *99,3,Wait(2) exten => *99,4,Hangup ;this is where parked calls go if they time-out. Should probably re-ring [default] include => ext-local exten => s,1,Playback(vm-goodbye) exten => s,2,Macro(hangupcall) [ext-test] exten => 7777,1,Goto(from-pstn,s,1) exten => 666,1,Goto(ext-fax,in_fax,1) exten => h,1,Macro(hangupcall) ;echo test exten => *43,1,Answer exten => *43,2,Wait(2) exten => *43,3,Playback(demo-echotest) exten => *43,4,Echo exten => *43,5,Playback(demo-echodone) exten => *43,6,Hangup