Search:
RFC Compliant ENUM Macro
Synopsis
Set 'DIAL_NUMBER' to be the number you wish to do an enumlookup on, and hand it to this.Recent code changes
- 2010-03-28: Improved tel: redirection. Only AEL script.
- 2010-03-28: Update to v1.6 syntax (Gosub(), not ¯o). Only AEL script.
- 2010-03-28: Consistenly use enumdial context.
- 2008-11-27: Delimit e.164 hosts with space (not dash).
- 2008-06-14: Fix avoid quotes in numeric comparison. Only ext script.
- 2007-11-30: Fix avoid quotes in numeric comparison. Only ext script.
- 2007-05-25: Update to v1.4 ENUMLOOKUP syntax (5 params, not 4).
Example
exten => s,1,Gosub(enumdial,s,1(7079964444))Original ext implementation
Requires Asterisk 1.6. Might work on earlier releases if changing the following:
- Rewrite to use ENUMLOOKUP() instead of ENUMQUERY() and ENUMRESULT().
; RFC Compliant ENUM Macro
;
; Main author: Rob Thomas <xrobau@gmail.com>
;
; Set 'DIAL_NUMBER' to be the number you wish to do an enumlookup on,
; and hand it to this.
;
; Latest code change: 2010-03-28 (wiki page rev. 28)
;
; Origin: http://www.voip-info.org/wiki/view/RFC+Compliant+ENUM+Macro
[enumdial]
exten => s,1,Set(DIAL_NUMBER=${ARG1})
exten => s,n,Set(E164NETWORKS=e164.arpa nrenum.net e164.info e164.org)
exten => s,n,GotoIf($[${DIAL_NUMBER:0:1} = "+"]?begin) ; Skip next line if it already is prefixed by a plus
exten => s,n,Set(DIAL_NUMBER=+${DIAL_NUMBER}) ; Add a plus to the start, because ENUMLOOKUP needs it.
; Checking here to see if there are any e164 networks left to check.
exten => s,n(begin),GotoIf($[${LEN(${E164NETWORKS})} < 2]?failed)
; There are, so we take the first one
exten => s,n,Set(ENUMNET=${CUT(E164NETWORKS, ,1)})
; And trim it from the front of E164NETWORKS
exten => s,n,Set(E164NETWORKS=${CUT(E164NETWORKS, ,2-)})
; OK, this is now quite complex. To remain compliant, we have to iterate
; through, in order, the returned records. Since we want to make this
; call over the network, we can ignore tel: lines. Even if it's first
; priority.
exten => s,n,Set(ENUMID=${ENUMQUERY(${DIAL_NUMBER},ALL,${ENUMNET})})
exten => s,n,Set(ENUMCOUNT=${ENUMRESULT(${ENUMID},getnum)})
; Documentation is wrong. It can return nothing if the enum lookup fails. Grr.
; Now the count may be zero, so if it is, check the next network
exten => s,n,GotoIf($["${ENUMCOUNT}" = "0"]?begin)
exten => s,n,GotoIf($["x${ENUMCOUNT}" = "x"]?begin)
; Now, let's start through them.
exten => s,n,Set(ENUMPTR=1)
exten => s,n(startloop),Set(ENUM=${ENUMRESULT(${ENUMID},${ENUMPTR})})
; Sanity check the return, make sure there's something in there.
exten => s,n,GotoIf($[${LEN(${ENUM})} = 0]?continue)
exten => s,n,GotoIf($["${ENUM:0:3}" = "iax"]?iaxuri)
exten => s,n,GotoIf($["${ENUM:0:3}" = "sip"]?sipuri)
; It doesn't matter if you don't have h323 enabled, as when it tries to dial, it cares
; about dialstatus and retries if there are any enum results left.
exten => s,n,GotoIf($[${ENUM:0:3} = "h32"]?h323uri)
; If we're here, it's not a protocol we know about. Let's increment the pointer
; and if it's more than ENUMCOUNT, we know we've run out of options. Try the
; next e164 network.
exten => s,n(continue),Set(ENUMPTR=$[${ENUMPTR} + 1])
exten => s,n,GotoIf($[${ENUMPTR} > ${ENUMCOUNT}]?begin)
; OK. If we're here, we've still got some enum entries to go through. Back to
; the start with you!
exten => s,n,Goto(startloop)
; If the prefix is 'sip:'...
exten => s,n(sipuri),Set(DIALSTR=SIP/${ENUM:4})
exten => s,n,Goto(dodial)
; If it's IAX2...
exten => s,n(iaxuri),Set(DIALSTR=IAX2/${ENUM:5})
exten => s,n,Goto(dodial)
; Or even if it's H323.
exten => s,n(h323uri),Set(DIALSTR=H323/${ENUM:5})
exten => s,n(dodial),Dial(${DIALSTR})
exten => s,n,NoOp(Dial exited in macro-enum-dialout with ${DIALSTATUS})
; Now, if we're still here, that means the Dial failed for some reason.
; If it's CONGESTION or CHANUNAVAIL we probably want to try again on a
; different channel. However, if it's the last one, we don't have any
; left, and I didn't keep any previous dialstatuses, so hopefully
; someone looking throught the logs would have seen the NoOp's
exten => s,n,GotoIf($[${ENUMPTR} = ${ENUMCOUNT}]?noneleft)
exten => s,n,GotoIf($[$[${DIALSTATUS} = "CHANUNAVAIL"] | $[${DIALSTATUS} = "CONGESTION"] ]?continue)
; If we're here, then it's BUSY or NOANSWER or something and well, deal with it.
exten => s,n(noneleft),Goto(s-${DIALSTATUS},1)
; Here are the exit points for the macro.
exten => s,n(failed),NoOp(Enum lookups failed)
exten => s,n,Goto(end)
exten => s,n(nochans),NoOp(max channels used up)
exten => s,n(end),NoOp(Exiting enumdial)
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(Enum dial failed due to ${DIALSTATUS})
AEL implementation
Functional differences from original:
- takes additional arguments:
- IsPOTS - generic flag if number called is a POTS/PSTN number or provider-specific (unused currently)
- Timeout
- DialOpts
- looks up tel: URLs
- limited to 5 successive lookups to avoid endless loop
- does not (but should it?) add delay at dialstatus BUSY
Requires Asterisk 1.6. Might work on earlier releases if changing the following:
- Rewrite to use ¯o instead of Gosub().
- Rewrite to use ENUMLOOKUP() instead of ENUMQUERY() and ENUMRESULT().
/*
RFC Compliant ENUM Macro
Main author: Luke-Jr <luke@dashjr.org>
Based on code by Rob Thomas <xrobau@gmail.com>
Set 'DIAL_NUMBER' to be the number you wish to do an enumlookup on, and
hand it to this.
Latest code change: 2010-03-28 (wiki page rev. 31)
Origin: http://www.voip-info.org/wiki/view/RFC+Compliant+ENUM+Macro
*/
macro enumdial(exten, IsPOTS, Timeout, DialOpts) {
Set(DIAL_NUMBER=${exten});
Set(E164NETWORKS=e164.arpa nrenum.net e164.info e164.org);
if ("${DIAL_NUMBER:0:1}" != "+")
// Add a plus to the start, because ENUMLOOKUP needs it.
Set(DIAL_NUMBER=+${DIAL_NUMBER});
Set(ENUMSEEN=${ENUMSEEN} ${DIAL_NUMBER});
if (${FIELDQTY(ENUMSEEN, )} > 5) { // max enum depth we will go
// This is to prevent a looping enum entry; there is no
// other safe way to be sure we don't get stuck in such
// a trap.
Set(DIALSTATUS=EnumMaxDepth);
goto end;
};
// Checking here to see if there are any e164 networks left to
// check.
for (Gosub(iterator,s,1(${E164NETWORKS},ENUMNET)); "${ENUMNET}" != ""; Gosub(iterate,s,1(ENUMNET))) {
// OK, this is now quite complex. To remain compliant,
// we have to iterate through, in order, the returned
// records.
Set(ENUMID=${ENUMQUERY(${DIAL_NUMBER},ALL,${ENUMNET})});
Set(ENUMCOUNT=${ENUMRESULT(${ENUMID},getnum)});
// Documentation is wrong. It can return nothing if the
// enum lookup fails. Grr.
if ("${ENUMCOUNT}" = "")
ENUMCOUNT=0;
// Now, let's start through them.
for (ENUMPTR=1; ${ENUMPTR} <= ${ENUMCOUNT}; ENUMPTR=${ENUMPTR} + 1) {
Set(ENUM=${ENUMRESULT(${ENUMID},${ENUMPTR})});
// Sanity check the return, make sure there's
// something in there.
if (${LEN(${ENUM})} = 0)
continue;
Set(DIALSTR=);
Set(DIALSTATUS=);
switch(${CUT(ENUM,:,1)}) {
case sip:
Set(DIALSTR=SIP/${ENUM:4});
break;
case iax2:
Set(DIALSTR=IAX2/${ENUM:5});
break;
// It doesn't matter if you don't have h323
// enabled, as when it tries to dial, it cares
// about dialstatus and retries if there are any
// enum results left.
case h323:
Set(DIALSTR=H323/${ENUM:5});
break;
case tel:
// redirect to another number...
if (${"LISTFILTER(ENUMSEEN, ,${DIAL_NUMBER})}" = "${DIAL_NUMBER}") {
NoOp(Redirect to tel: ${ENUM});
Gosub(enumdial,s,1(${ENUM:4}));
} else {
NoOp(Skip already tried tel: ${ENUM});
Set(DIALSTATUS=CONGESTION);
};
break;
default:
// If we're here, it's not a protocol we
// know about.
Set(DIALSTATUS=CHANUNAVAIL);
break;
};
if ("${DIALSTR}" != "") {
Dial(${DIALSTR},${Timeout},o${DialOpts});
NoOp(Dial exited in enumdial with ${DIALSTATUS});
};
// Now, if we're still here, that means the Dial
// failed for some reason.
// If it's CONGESTION or CHANUNAVAIL we probably
// want to try again on a different channel.
// However, if it's the last one, we don't have
// any left, and I didn't keep any previous
// dialstatuses, so hopefully someone looking
// throught the logs would have seen the NoOp's
if ("${DIALSTATUS}" != "CONGESTION" & "${DIALSTATUS}" != "CHANUNAVAIL") {
NoOp(Enum Dial(${DIALSTR}) failed due to ${DIALSTATUS});
goto end;
};
};
};
end:
NoOp(EnumLookups failed);
return;
};
macro iterate(varname) {
current=${${varname}_current} + 1;
SET(${varname}=${CUT(${varname}_choices, ,${current})});
SET(${varname}_current=${current});
return;
};
macro iterator(choices, varname) {
SET(${varname}_choices=${choices});
SET(${varname}_current=0);
Gosub(iterate,s,1(${varname}));
return;
};
Created by: xrobau,Last modification on Mon 29 of Mar, 2010 [15:39 UTC] by JonasSmedegaard

Page Changes
