; 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}]?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,Setvar(FROMCONTEXT=exten-vm) exten => s,2,Macro(record-enable,${ARG2},IN) exten => s,3,Macro(dial,${RINGTIMER},${DIAL_OPTIONS},${ARG2}) exten => s,4,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,5,GotoIf($[${ARG1} = novm]?s-${DIALSTATUS},1) ; no voicemail in use for this extension exten => s,6,NoOp(Sending to Voicemail box ${ARG1}) exten => s,7,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,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 - ringtimer ; 2 - preifx ; 3 - extension list [macro-rg-group] exten => s,1,GotoIf($[${CALLERIDNAME:0:${LEN(${RGPREFIX})}} != ${RGPREFIX}]?3:2) ; check for old prefix exten => s,2,SetCIDName(${CALLERIDNAME:${LEN(${RGPREFIX})}}) ; strip off old prefix exten => s,3,Setvar(RGPREFIX=${ARG2}) ; set new prefix exten => s,4,SetCIDName(${RGPREFIX}${CALLERIDNAME}) ; add prefix to callerid name exten => s,5,Setvar(RecordMethod=Group) ; set new prefix exten => s,6,Macro(record-enable,${MACRO_EXTEN},${RecordMethod}) exten => s,7,Macro(dial,${ARG1},${DIAL_OPTIONS},${ARG3}) ;exten => s,1,GotoIf($[${CALLERIDNAME:0:${LEN(${RGPREFIX})}} != ${RGPREFIX}]?3:2) ; check for old prefix ;exten => s,2,SetCIDName(${CALLERIDNAME:${LEN(${RGPREFIX})}}) ; strip off old prefix ;exten => s,3,Setvar(RGPREFIX=${ARG2}) ; set new prefix ;;exten => s,4,Noop(${RGPREFIX} ${CALLERIDNAME}) ;exten => s,4,SetCIDName(${RGPREFIX}${CALLERIDNAME}) ; add prefix to callerid name ;;exten => s,6,Noop(Dial group ${ARG3}) ;exten => s,5,Macro(dial,${ARG1},${DIAL_OPTIONS},${ARG3}) ;exten => s,1,Setvar(GRP=${GRP}) ;my original choice of variable GROUP is now overwritten by SetGroup. Copy contents to GRP ;exten => s,2,SetGroup(${CALLERIDNUM}) ;exten => s,3,Setvar(FROMCONTEXT=rg-group) ;exten => s,4,SetCIDName(${PRE}${CALLERIDNAME}) ;exten => s,5,Macro(dial,${RINGTIMER},${DIAL_OPTIONS},${GRP}) ; ; Outgoing channel(s) are busy ... inform the client ; [macro-outisbusy] exten => s,1,Playback(allison7/all-circuits-busy-now) exten => s,2,Playback(allison7/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,GotoIf($[foo${ECID${CALLERIDNUM}} = foo]?4) ;check for CID override for exten exten => s,2,SetCallerID(${ECID${CALLERIDNUM}}) exten => s,3,Goto(6) exten => s,4,GotoIf($[foo${OUTCID_${ARG1}} = foo]?6) ;check for CID override for trunk exten => s,5,SetCallerID(${OUTCID_${ARG1}}) exten => s,6,SetVar(length=${LEN(${DIAL_OUT_${ARG1}})}) exten => s,7,Dial(${OUT_${ARG1}}/${ARG2:${length}}) exten => s,8,Congestion exten => s,108,Macro(outisbusy) ; dialout using default OUT trunk - no prefix [macro-dialout-default] exten => s,1,Macro(record-enable,${CALLERIDNUM},OUT) 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} = foo]?7) ;check for CID override for trunk exten => s,6,SetCallerID(${OUTCID}) exten => s,7,Dial(${OUT}/${ARG1}) exten => s,8,Congestion exten => s,108,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(record-enable,${CALLERIDNUM},OUT) exten => s,4,GotoIf($[foo${ECID${CALLERIDNUM}} = foo]?7) ;check for CID override for exten exten => s,5,SetCallerID(${ECID${CALLERIDNUM}}) exten => s,6,Goto(9) exten => s,7,GotoIf($[foo${OUTCID_${ARG1}} = foo]?9) ;check for CID override for trunk exten => s,8,SetCallerID(${OUTCID_${ARG1}}) exten => s,9,SetGroup(OUT_${ARG1}) exten => s,10,CheckGroup(${OUTMAXCHANS_${ARG1}}) ; if we've used up the max channels, continue at 109 (n+101) exten => s,11,SetVar(DIAL_NUMBER=${ARG2}) exten => s,12,SetVar(DIAL_TRUNK=${ARG1}) exten => s,13,AGI(fixlocalprefix) ; this sets DIAL_NUMBER to the proper dial string for this trunk exten => s,14,SetVar(OUTNUM=${OUTPREFIX_${ARG1}}${DIAL_NUMBER}) ; OUTNUM is the final dial number exten => s,15,Cut(custom=OUT_${ARG1},:,1) ; Custom trunks are prefixed with "AMP:" exten => s,16,GotoIf($[${custom} = AMP]?19) exten => s,17,Dial(${OUT_${ARG1}}/${OUTNUM}) ; Regular Trunk Dial exten => s,18,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,19,Cut(pre_num=OUT_${ARG1},$,1) exten => s,20,Cut(the_num=OUT_${ARG1},$,2) ; this is where we expect to find string OUTNUM exten => s,21,Cut(post_num=OUT_${ARG1},$,3) exten => s,22,GotoIf($[${the_num} = OUTNUM]?23:24) ; if we didn't find "OUTNUM", then skip to Dial exten => s,23,SetVar(the_num=${OUTNUM}) ; replace "OUTNUM" with the actual number to dial exten => s,24,Dial(${pre_num:4}${the_num}${post_num}) exten => s,25,Goto(s-${DIALSTATUS},1) exten => s,111,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,NoOp 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,NoOp 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(record-enable,${CALLERIDNUM},OUT) exten => s,2,GotoIf($[foo${ECID${CALLERIDNUM}} = foo]?3) ;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,SetGroup(OUT_${ARG1}) exten => s,8,CheckGroup(${OUTMAXCHANS_${ARG1}}) ; if we've used up the max channels, continue at 108 (n+101) exten => s,9,SetVar(DIAL_NUMBER=${ARG2}) exten => s,10,SetVar(DIAL_TRUNK=${ARG1}) exten => s,11,AGI(fixlocalprefix) ; this sets DIAL_NUMBER to the proper dial string for this trunk exten => s,12,EnumLookup(${DIAL_NUMBER}) exten => s,13,GotoIf($[$[${ENUM:0:3} = SIP] | $[${ENUM:0:3} = IAX]]?14:63) exten => s,14,Dial(${ENUM}) exten => s,15,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,109,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,GotoIf($["${ARG2}" = "OUT"]?5:8) exten => s,5,DBGet(RecEnable=RECORD-OUT/${ARG1}) exten => s,6,SetVar(CALLFILENAME=OUT${ARG1}-${TIMESTAMP}-${UNIQUEID}) exten => s,7,Goto(s,14) exten => s,8,GotoIf($["${ARG2}" = "Group"]?9:12) exten => s,9,AGI(recordingcheck) exten => s,10,SetVar(CALLFILENAME=g${ARG1}-${TIMESTAMP}-${UNIQUEID}) exten => s,11,Goto(s,14) exten => s,12,DBGet(RecEnable=RECORD-IN/${ARG1}) exten => s,13,SetVar(CALLFILENAME=${TIMESTAMP}-${UNIQUEID}) exten => s,14,GotoIf($["${RecEnable}" = "ENABLED"]?15:99) exten => s,15,Monitor(wav49,${CALLFILENAME}, mb) exten => s,99,Noop(NO RECORDING NEEDED) ;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})