mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
extensive ENUM support update, including ENUMLOOKUP() dialplan function (issue #5201 with mods)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6579 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -71,6 +71,9 @@ static int enumlookup_exec(struct ast_channel *chan, void *data)
|
|||||||
char dest[80];
|
char dest[80];
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
char *c,*t;
|
char *c,*t;
|
||||||
|
|
||||||
|
tech[0] = '\0';
|
||||||
|
|
||||||
struct localuser *u;
|
struct localuser *u;
|
||||||
|
|
||||||
if (!data || ast_strlen_zero(data)) {
|
if (!data || ast_strlen_zero(data)) {
|
||||||
@@ -79,7 +82,7 @@ static int enumlookup_exec(struct ast_channel *chan, void *data)
|
|||||||
}
|
}
|
||||||
LOCAL_USER_ADD(u);
|
LOCAL_USER_ADD(u);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
res = ast_get_enum(chan, data, dest, sizeof(dest), tech, sizeof(tech));
|
res = ast_get_enum(chan, data, dest, sizeof(dest), tech, sizeof(tech), NULL, NULL);
|
||||||
printf("ENUM got '%d'\n", res);
|
printf("ENUM got '%d'\n", res);
|
||||||
}
|
}
|
||||||
LOCAL_USER_REMOVE(u);
|
LOCAL_USER_REMOVE(u);
|
||||||
|
306
doc/README.enum
Executable file
306
doc/README.enum
Executable file
@@ -0,0 +1,306 @@
|
|||||||
|
README.enum
|
||||||
|
|
||||||
|
2005-09-06
|
||||||
|
jtodd@loligo.com
|
||||||
|
|
||||||
|
The ENUMLOOKUP function is more complex than it first may appear, and
|
||||||
|
this guide is to give a general overview and set of examples that may
|
||||||
|
be well-suited for the advanced user to evaluate in their
|
||||||
|
consideration of ENUM or ENUM-like lookup strategies. This document
|
||||||
|
assumes a familiarity with ENUM (RFC3761) or ENUM-like methods, as
|
||||||
|
well as familiarity with NAPTR DNS records (RFC2915, RFC3401-3404).
|
||||||
|
For an overview of NAPTR records, and the use of NAPTRs in the ENUM
|
||||||
|
global phone-number-to-DNS mapping scheme, please see
|
||||||
|
http://www.voip-info.org/tiki-index.php?page=ENUM for more detail.
|
||||||
|
|
||||||
|
Using ENUM within Asterisk can be simple or complex, depending on how
|
||||||
|
many failover methods and redundancy procedures you wish to utilize.
|
||||||
|
Implementation of ENUM paths is supposedly defined by the person
|
||||||
|
creating the NAPTR records, but the local administrator may choose to
|
||||||
|
ignore certain NAPTR response methods (URI types) or prefer some over
|
||||||
|
others, which is in contradiction to the RFC. The ENUMLOOKUP method
|
||||||
|
simply provides administrators a method for determining NAPTR results
|
||||||
|
in either the globally unique ENUM (e164.arpa) DNS tree, or in other
|
||||||
|
ENUM-like DNS trees which are not globally unique. The methods to
|
||||||
|
actually create channels ("dial") results given by the ENUMLOOKUP
|
||||||
|
function is then up to the administrator to implement in a way that
|
||||||
|
best suits their environment.
|
||||||
|
|
||||||
|
Function: EnumLookup(<number>[,pointer_type[,options[,zone_suffix]]])
|
||||||
|
|
||||||
|
Performs an ENUM tree lookup on the specified number, method type,
|
||||||
|
and (optionally) ordinal offset, and returns one of four different values:
|
||||||
|
|
||||||
|
1) post-parsed NAPTR of one method (URI) type
|
||||||
|
2) count of elements of one method (URI) type
|
||||||
|
3) count of all method types
|
||||||
|
4) full URI of method at a particular point in the list of all possible methods
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
number = telephone number or search string. Only numeric values
|
||||||
|
within this string are parsed; all other digits are ignored for
|
||||||
|
search, but are re-written during NAPTR regexp expansion.
|
||||||
|
|
||||||
|
service_type = tel, sip, h323, iax2, mailto, ...[any other string],
|
||||||
|
ALL. Default type is "sip".
|
||||||
|
Special name of "ALL" will create a list of method types across
|
||||||
|
all NAPTR records for the search number, and then put the results
|
||||||
|
in an ordinal list starting with 1. The position <number>
|
||||||
|
specified will then be returned, starting with 1 as the first
|
||||||
|
record (lowest value) in the list. The service types are not
|
||||||
|
hardcoded in Asterisk except for the default (sip) if no other
|
||||||
|
service type specified; any method type string (IANA-approved or
|
||||||
|
not) may be used except for the string "ALL".
|
||||||
|
|
||||||
|
options = optional specifiers.
|
||||||
|
c = count. Returns the number of records of this type are returned
|
||||||
|
(regardless of order or priority.) If "ALL" is the specified
|
||||||
|
service_type, then a count of all methods will be returned for the
|
||||||
|
DNS record.
|
||||||
|
<integer> = The record in priority/order sequence based on the
|
||||||
|
total count of records passed back by the query. If a service_type
|
||||||
|
is specified, all entries of that type will be sorted into an
|
||||||
|
ordinal list starting with 1 (by order first, then priority).
|
||||||
|
The default of <options> is "1"
|
||||||
|
|
||||||
|
zone_suffix = allows customization of the ENUM zone. Default is e164.arpa.
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLE USES:
|
||||||
|
|
||||||
|
Let's use this ENUM list as an example (note that these examples exist
|
||||||
|
in the DNS, and will hopefully remain in place as example
|
||||||
|
destinations, but they may change or become invalid over time. The
|
||||||
|
end result URIs are not guaranteed to actually work, since some of
|
||||||
|
these hostnames or SIP proxies are imaginary. Of course, the tel:
|
||||||
|
replies go to directory assistance for New York City and San
|
||||||
|
Francisco...) Also note that the complex SIP NAPTR at weight 30 will
|
||||||
|
strip off the leading "+" from the dialed string if it exists. This
|
||||||
|
is probably a better NAPTR than hard-coding the number into the NAPTR,
|
||||||
|
and it is included as a more complex regexp example, though other
|
||||||
|
simpler NAPTRs will work just as well.
|
||||||
|
|
||||||
|
|
||||||
|
0.2.0.1.1.6.5.1.0.3.1.fox-den.com. 3600 IN NAPTR 10 100 "u" "E2U+tel" "!^\\+13015611020$!tel:+12125551212!" .
|
||||||
|
0.2.0.1.1.6.5.1.0.3.1.fox-den.com. 3600 IN NAPTR 21 100 "u" "E2U+tel" "!^\\+13015611020$!tel:+14155551212!" .
|
||||||
|
0.2.0.1.1.6.5.1.0.3.1.fox-den.com. 3600 IN NAPTR 25 100 "u" "E2U+sip" "!^\\+13015611020$!sip:2203@sip.fox-den.com!" .
|
||||||
|
0.2.0.1.1.6.5.1.0.3.1.fox-den.com. 3600 IN NAPTR 26 100 "u" "E2U+sip" "!^\\+13015611020$!sip:1234@sip-2.fox-den.com!" .
|
||||||
|
0.2.0.1.1.6.5.1.0.3.1.fox-den.com. 3600 IN NAPTR 30 100 "u" "E2U+sip" "!^\\+*([^\\*]*)!sip:\\1@sip-3.fox-den.com!" .
|
||||||
|
0.2.0.1.1.6.5.1.0.3.1.fox-den.com. 3600 IN NAPTR 55 100 "u" "E2U+mailto" "!^\\+13015611020$!mailto:jtodd@fox-den.com!" .
|
||||||
|
|
||||||
|
Example 1: Simplest case, using first SIP return (use all defaults
|
||||||
|
except for domain name)
|
||||||
|
exten => 100,1,Set(foo=ENUMLOOKUP(13015611020,,,fox-den.com))
|
||||||
|
returns: ${foo}="2203@sip.fox-den.com"
|
||||||
|
|
||||||
|
Example 2: What is the first "tel" pointer type for this number?
|
||||||
|
(after sorting by order/preference; default of "1" is assumed in
|
||||||
|
options field)
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(13015611020,tel,,loligo.com)})
|
||||||
|
returns: ${foo}="+12125551212"
|
||||||
|
|
||||||
|
Example 3: How many "sip" pointer type entries are there for this number?
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(13015611020,sip,c,loligo.com)})
|
||||||
|
returns: ${foo}=3
|
||||||
|
|
||||||
|
Example 4: For all the "tel" pointer type entries, what is the second
|
||||||
|
one in the list? (after sorting by preference)
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(13015611020,tel,2,loligo.com)})
|
||||||
|
returns: ${foo}="+5553"
|
||||||
|
|
||||||
|
Example 5: How many NAPTRs (tel, sip, mailto, etc.) are in the list for this number?
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(13015611020,ALL,c,loligo.com)})
|
||||||
|
returns: ${foo}=6
|
||||||
|
|
||||||
|
Example 6: Give back the second full URI in the sorted list of all NAPTR URIs:
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(13015611020,ALL,2,loligo.com)})
|
||||||
|
returns: ${foo}="tel:14155551212" [note the "tel:" prefix in the string]
|
||||||
|
|
||||||
|
Example 7: Look up first SIP entry for the number in the e164.arpa zone (all defaults)
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(+437203001721)})
|
||||||
|
returns: ${foo}="enum-test@sip.nemox.net" [note: this result is
|
||||||
|
subject to change as it is "live" DNS and not under my control]
|
||||||
|
|
||||||
|
|
||||||
|
Example 8: Look up the ISN mapping in freenum.org alpha test zone
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(1234*256,,,freenum.org)})
|
||||||
|
returns: ${foo}="1234@204.91.156.10" [note: this result is subject
|
||||||
|
to change as it is "live" DNS]
|
||||||
|
|
||||||
|
Example 9: Give back the first SIP pointer for a number in the
|
||||||
|
enum.yoydynelabs.com zone (invalid lookup)
|
||||||
|
exten => 100,1,Set(foo=${ENUMLOOKUP(1234567890,sip,1,enum.yoyodynelabs.com)})
|
||||||
|
returns: ${foo}=""
|
||||||
|
|
||||||
|
|
||||||
|
Usage notes and subtle features:
|
||||||
|
|
||||||
|
a) The use of "+" in lookups is confusing, and warrants further
|
||||||
|
explanation. All E.164 numbers ("global phone numbers") by
|
||||||
|
definition need a leading "+" during ENUM lookup. If you neglect to
|
||||||
|
add a leading "+", you may discover that numbers that seem to exist
|
||||||
|
in the DNS aren't getting matched by the system or are returned with
|
||||||
|
a null string result. This is due to the NAPTR reply requiring a
|
||||||
|
"+" in the regular expression matching sequence. Older versions of
|
||||||
|
Asterisk add a "+" from within the code, which may confuse
|
||||||
|
administrators converting to the new function. Please ensure that
|
||||||
|
all ENUM (e164.arpa) lookups contain a leading "+" before lookup, so
|
||||||
|
ensure your lookup includes the leading plus sign. Other DNS trees
|
||||||
|
may or may not require a leading "+" - check before using those
|
||||||
|
trees, as it is possible the parsed NAPTRs will not provide correct
|
||||||
|
results unless you have the correct dialed string. If you get
|
||||||
|
console messages like "WARNING[24907]: enum.c:222 parse_naptr: NAPTR
|
||||||
|
Regex match failed." then it is very possible that the returned
|
||||||
|
NAPTR expects a leading "+" in the search string (or the returned
|
||||||
|
NAPTR is mis-formed.)
|
||||||
|
|
||||||
|
b) If a query is performed of type "c" ("count") and let's say you
|
||||||
|
get back 5 records and then some seconds later a query is made
|
||||||
|
against record 5 in the list, it may not be the case that the DNS
|
||||||
|
resolver has the same answers as it did a second or two ago - maybe
|
||||||
|
there are only 4 records in the list in the newest query. The
|
||||||
|
resolver should be the canonical storage location for DNS records,
|
||||||
|
since that is the intent of ENUM. However, some obscure future
|
||||||
|
cases may have wildly changing NAPTR records within several seconds.
|
||||||
|
This is a corner case, and probably only worth noting as a very rare
|
||||||
|
circumstance. (note: I do not object to Asterisk's dnsmgr method of
|
||||||
|
locally caching DNS replies, but this method needs to honor the TTL
|
||||||
|
given by the remote zone master. Currently, the ENUMLOOKUP function
|
||||||
|
does not use the dnsmgr method of caching local DNS replies.)
|
||||||
|
|
||||||
|
c) If you want strict NAPTR value ordering, then it will be
|
||||||
|
necessary to use the "ALL" method to incrementally step through the
|
||||||
|
different returned NAPTR pointers. You will need to use string
|
||||||
|
manipulation to strip off the returned method types, since the
|
||||||
|
results will look like "sip:12125551212" in the returned value.
|
||||||
|
This is a non-trivial task, though it is required in order to have
|
||||||
|
strict RFC compliance and to comply with the desires of the remote
|
||||||
|
party who is presenting NAPTRs in a particular order for a reason.
|
||||||
|
|
||||||
|
d) Default behavior for the function (even in event of an error) is
|
||||||
|
to move to the next priority, and the result is a null value. Most
|
||||||
|
ENUM lookups are going to be failures, and it is the responsibility
|
||||||
|
of the dialplan administrator to manage error conditions within
|
||||||
|
their dialplan. This is a change from the old app_enumlookup method
|
||||||
|
and it's arbitrary priority jumping based on result type or failure.
|
||||||
|
|
||||||
|
e) Anything other than digits will be ignored in lookup strings.
|
||||||
|
Example: a search string of "+4372030blah01721" will turn into
|
||||||
|
1.2.7.1.0.0.3.0.2.7.3.4.e164.arpa. for the lookup. The NAPTR
|
||||||
|
parsing may cause unexpected results if there are strings inside
|
||||||
|
your NAPTR lookups.
|
||||||
|
|
||||||
|
f) If there exist multiple records with the same weight and order as
|
||||||
|
a result of your query, the function will RANDOMLY select a single
|
||||||
|
NAPTR from those equal results.
|
||||||
|
|
||||||
|
g) Currently, the function ignores the settings in enum.conf as the
|
||||||
|
search zone name is now specified within the function, and the H323
|
||||||
|
driver can be chosen by the user via the dialplan. There were no
|
||||||
|
other values in this file, and so it becomes deprecated.
|
||||||
|
|
||||||
|
h) The function will digest and return NAPTRs which use older
|
||||||
|
(depricated) style, reversed method strings such as "sip+E2U"
|
||||||
|
instead of the more modern "E2U+sip"
|
||||||
|
|
||||||
|
i) There is no provision for multi-part methods at this time. If
|
||||||
|
there are multiple NAPTRs with (as an example) a method of
|
||||||
|
"E2U+voice:sip" and then another NAPTR in the same DNS record with a
|
||||||
|
method of ""E2U+sip", the system will treat these both as method
|
||||||
|
"sip" and they will be separate records from the perspective of the
|
||||||
|
function. Of course, if both records point to the same URI and have
|
||||||
|
equal priority/weight (as is often the case) then this will cause no
|
||||||
|
serious difficulty, but it bears mentioning.
|
||||||
|
|
||||||
|
j) ISN (ITAD Subscriber Number) usage: If the search number is of
|
||||||
|
the form ABC*DEF (where ABC and DEF are at least one numeric digit)
|
||||||
|
then perform an ISN-style lookup where the lookup is manipulated to
|
||||||
|
C.B.A.DEF.domain.tld (all other settings and options apply.) See
|
||||||
|
http://www.freenum.org/ for more details on ISN lookups. In the
|
||||||
|
unlikely event you wish to avoid ISN re-writes, put an "n" as the
|
||||||
|
first digit of the search string - the "n" will be ignored for the search.
|
||||||
|
|
||||||
|
|
||||||
|
==EXAMPLES==
|
||||||
|
|
||||||
|
All examples below except where noted use "e164.arpa" as the
|
||||||
|
referenced domain, which is the default domain name for ENUMLOOKUP.
|
||||||
|
All numbers are assumed to not have a leading "+" as dialed by the
|
||||||
|
inbound channel, so that character is added where necessary during
|
||||||
|
ENUMLOOKUP function calls.
|
||||||
|
|
||||||
|
; example 1
|
||||||
|
;
|
||||||
|
; Assumes North American international dialing (011) prefix.
|
||||||
|
; Look up the first SIP result and send the call there, otherwise
|
||||||
|
; send the call out a PRI. This is the most simple possible
|
||||||
|
; ENUM example, but only uses the first SIP reply in the list of
|
||||||
|
; NAPTR(s).
|
||||||
|
;
|
||||||
|
exten => _011.,1,Set(enumresult=${ENUMLOOKUP(+${EXTEN:3})})
|
||||||
|
exten => _011.,n,Dial(SIP/${enumlookup})
|
||||||
|
exten => _011.,n,Dial(Zap/g1/${EXTEN})
|
||||||
|
;
|
||||||
|
; end example 1
|
||||||
|
|
||||||
|
; example 2
|
||||||
|
;
|
||||||
|
; Assumes North American international dialing (011) prefix.
|
||||||
|
; Check to see if there are multiple SIP NAPTRs returned by
|
||||||
|
; the lookup, and dial each in order. If none work (or none
|
||||||
|
; exist) then send the call out a PRI, group 1.
|
||||||
|
;
|
||||||
|
exten => _011.,1,Set(sipcount=${ENUMLOOKUP(${EXTEN:3},sip,c)}|counter=0)
|
||||||
|
exten => _011.,n,While($["${counter}"<"${sipcount}"])
|
||||||
|
exten => _011.,n,Set(counter=$[${counter}+1])
|
||||||
|
exten => _011.,n,Dial(SIP/${ENUMLOOKUP(+${EXTEN:3},sip,${counter})})
|
||||||
|
exten => _011.,n,EndWhile
|
||||||
|
exten => _011.,n,Dial(Zap/g1/${EXTEN})
|
||||||
|
;
|
||||||
|
; end example 2
|
||||||
|
|
||||||
|
; example 3
|
||||||
|
;
|
||||||
|
; This example expects an ${EXTEN} that is an e.164 number (like
|
||||||
|
; 14102241145 or 437203001721)
|
||||||
|
; Search through e164.arpa and then also search through e164.org
|
||||||
|
; to see if there are any valid SIP or IAX termination capabilities.
|
||||||
|
; If none, send call out via Zap channel 1.
|
||||||
|
;
|
||||||
|
; Start first with e164.arpa zone...
|
||||||
|
;
|
||||||
|
exten => _X.,1,Set(sipcount=${ENUMLOOKUP(${EXTEN},sip,c)}|counter=0)
|
||||||
|
exten => _X.,2,GotoIf($["${counter}"<"${sipcount}"]?3:6)
|
||||||
|
exten => _X.,3,Set(counter=$[${counter}+1])
|
||||||
|
exten => _X.,4,Dial(SIP/${ENUMLOOKUP(+${EXTEN},sip,${counter})})
|
||||||
|
exten => _X.,5,GotoIf($["${counter}"<"${sipcount}"]?3:6)
|
||||||
|
;
|
||||||
|
exten => _X.,6,Set(iaxcount=${ENUMLOOKUP(${EXTEN},iax2,c)}|counter=0)
|
||||||
|
exten => _X.,7,GotoIf($["${counter}"<"${iaxcount}"]?8:11)
|
||||||
|
exten => _X.,8,Set(counter=$[${counter}+1])
|
||||||
|
exten => _X.,9,Dial(IAX2/${ENUMLOOKUP(+${EXTEN},iax,${counter})})
|
||||||
|
exten => _X.,10,GotoIf($["${counter}"<"${iaxcount}"]?8:11)
|
||||||
|
;
|
||||||
|
exten => _X.,11,NoOp("No valid entries in e164.arpa for ${EXTEN} - checking in e164.org")
|
||||||
|
;
|
||||||
|
; ...then also try e164.org, and look for SIP and IAX NAPTRs...
|
||||||
|
;
|
||||||
|
exten => _X.,12,Set(sipcount=${ENUMLOOKUP(${EXTEN},sip,c,e164.org)}|counter=0)
|
||||||
|
exten => _X.,13,GotoIf($["${counter}"<"${sipcount}"]?14:17)
|
||||||
|
exten => _X.,14,Set(counter=$[${counter}+1])
|
||||||
|
exten => _X.,15,Dial(SIP/${ENUMLOOKUP(+${EXTEN},sip,${counter},e164.org)})
|
||||||
|
exten => _X.,16,GotoIf($["${counter}"<"${sipcount}"]?14:17)
|
||||||
|
;
|
||||||
|
exten => _X.,17,Set(iaxcount=${ENUMLOOKUP(${EXTEN},iax2,c,e164.org)}|counter=0)
|
||||||
|
exten => _X.,18,GotoIf($["${counter}"<"${iaxcount}"]?19:22)
|
||||||
|
exten => _X.,19,Set(counter=$[${counter}+1])
|
||||||
|
exten => _X.,20,Dial(IAX2/${ENUMLOOKUP(+${EXTEN},iax,${counter},e164.org)})
|
||||||
|
exten => _X.,21,GotoIf($["${counter}"<"${iaxcount}"]?19:22)
|
||||||
|
;
|
||||||
|
; ...then send out PRI.
|
||||||
|
;
|
||||||
|
exten => _X.,22,NoOp("No valid entries in e164.org for ${EXTEN} - sending out via Zap")
|
||||||
|
exten => _X.,23,Dial(Zap/g1/${EXTEN})
|
||||||
|
;
|
||||||
|
; end example 3
|
225
enum.c
225
enum.c
@@ -87,9 +87,12 @@ static int parse_ie(char *data, int maxdatalen, char *src, int srclen)
|
|||||||
/*--- parse_naptr: Parse DNS NAPTR record used in ENUM ---*/
|
/*--- parse_naptr: Parse DNS NAPTR record used in ENUM ---*/
|
||||||
static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *answer, int len, char *naptrinput)
|
static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *answer, int len, char *naptrinput)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char tech_return[80];
|
||||||
char *oanswer = answer;
|
char *oanswer = answer;
|
||||||
char flags[512] = "";
|
char flags[512] = "";
|
||||||
char services[512] = "";
|
char services[512] = "";
|
||||||
|
unsigned char *p;
|
||||||
char regexp[512] = "";
|
char regexp[512] = "";
|
||||||
char repl[512] = "";
|
char repl[512] = "";
|
||||||
char temp[512] = "";
|
char temp[512] = "";
|
||||||
@@ -102,6 +105,7 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a
|
|||||||
regex_t preg;
|
regex_t preg;
|
||||||
regmatch_t pmatch[9];
|
regmatch_t pmatch[9];
|
||||||
|
|
||||||
|
tech_return[0] = '\0';
|
||||||
|
|
||||||
dst[0] = '\0';
|
dst[0] = '\0';
|
||||||
|
|
||||||
@@ -132,6 +136,7 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a
|
|||||||
answer += res;
|
answer += res;
|
||||||
len -= res;
|
len -= res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) {
|
if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) {
|
||||||
ast_log(LOG_WARNING, "Failed to expand hostname\n");
|
ast_log(LOG_WARNING, "Failed to expand hostname\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -146,29 +151,27 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!strncasecmp(services, "e2u+sip", 7)) ||
|
p = strstr(services, "e2u+");
|
||||||
(!strncasecmp(services, "sip+e2u", 7))) {
|
if(p == NULL)
|
||||||
ast_copy_string(tech, "sip", techsize);
|
p = strstr(services, "E2U+");
|
||||||
} else if ((!strncasecmp(services, "e2u+h323", 8)) ||
|
if(p){
|
||||||
(!strncasecmp(services, "h323+e2u", 8))) {
|
p = p + 4;
|
||||||
ast_copy_string(tech, "h323", techsize);
|
if(strchr(p, ':')){
|
||||||
} else if ((!strncasecmp(services, "e2u+x-iax2", 10)) ||
|
p = strchr(p, ':') + 1;
|
||||||
(!strncasecmp(services, "e2u+iax2", 8)) ||
|
}
|
||||||
(!strncasecmp(services, "iax2+e2u", 8))) {
|
ast_copy_string(tech_return, p, sizeof(tech_return));
|
||||||
ast_copy_string(tech, "iax2", techsize);
|
|
||||||
} else if ((!strncasecmp(services, "e2u+x-iax", 9)) ||
|
|
||||||
(!strncasecmp(services, "e2u+iax", 7)) ||
|
|
||||||
(!strncasecmp(services, "iax+e2u", 7))) {
|
|
||||||
ast_copy_string(tech, "iax", techsize);
|
|
||||||
} else if ((!strncasecmp(services, "e2u+tel", 7)) ||
|
|
||||||
(!strncasecmp(services, "tel+e2u", 7))) {
|
|
||||||
ast_copy_string(tech, "tel", techsize);
|
|
||||||
} else if (!strncasecmp(services, "e2u+voice:", 10)) {
|
|
||||||
ast_copy_string(tech, services+10, techsize);
|
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_DEBUG,
|
|
||||||
"Services must be e2u+${tech}, ${tech}+e2u, or e2u+voice: where $tech is from (sip, h323, tel, iax, iax2). \n");
|
p = strstr(services, "+e2u");
|
||||||
return 0;
|
if(p == NULL)
|
||||||
|
p = strstr(services, "+E2U");
|
||||||
|
if(p){
|
||||||
|
*p = 0;
|
||||||
|
p = strchr(services, ':');
|
||||||
|
if(p)
|
||||||
|
*p = 0;
|
||||||
|
ast_copy_string(tech_return, services, sizeof(tech_return));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DEDBUGGING STUB
|
/* DEDBUGGING STUB
|
||||||
@@ -197,6 +200,7 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a
|
|||||||
#if 0
|
#if 0
|
||||||
printf("Pattern: %s\n", pattern);
|
printf("Pattern: %s\n", pattern);
|
||||||
printf("Subst: %s\n", subst);
|
printf("Subst: %s\n", subst);
|
||||||
|
printf("Input: %s\n", naptrinput);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -246,8 +250,34 @@ static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, char *a
|
|||||||
*d = 0;
|
*d = 0;
|
||||||
ast_copy_string(dst, temp, dstsize);
|
ast_copy_string(dst, temp, dstsize);
|
||||||
dst[dstsize - 1] = '\0';
|
dst[dstsize - 1] = '\0';
|
||||||
|
|
||||||
|
if(*tech != '\0'){ /* check if it is requested NAPTR */
|
||||||
|
if(!strncasecmp(tech, "ALL", techsize)){
|
||||||
|
return 1; /* return or count any RR */
|
||||||
|
}
|
||||||
|
if(!strncasecmp(tech_return, tech, sizeof(tech_return)<techsize?sizeof(tech_return):techsize)){
|
||||||
|
ast_copy_string(tech, tech_return, techsize);
|
||||||
|
return 1; /* we got out RR */
|
||||||
|
} else { /* go to the next RR in the DNS answer */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tech was not specified, return first parsed RR */
|
||||||
|
ast_copy_string(tech, tech_return, techsize);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do not return requested value, just count RRs and return thei number in dst */
|
||||||
|
#define ENUMLOOKUP_OPTIONS_COUNT 1
|
||||||
|
|
||||||
|
struct enum_naptr_rr {
|
||||||
|
struct naptr naptr; /* order and preference of RR */
|
||||||
|
char *result; /* result of naptr parsing,e.g.: tel:+5553 */
|
||||||
|
char *tech; /* Technology (from URL scheme) */
|
||||||
|
int sort_pos; /* sort position */
|
||||||
|
};
|
||||||
|
|
||||||
struct enum_context {
|
struct enum_context {
|
||||||
char *dst; /* Destination part of URL from ENUM */
|
char *dst; /* Destination part of URL from ENUM */
|
||||||
@@ -257,6 +287,10 @@ struct enum_context {
|
|||||||
char *txt; /* TXT record in TXT lookup */
|
char *txt; /* TXT record in TXT lookup */
|
||||||
int txtlen; /* Length */
|
int txtlen; /* Length */
|
||||||
char *naptrinput; /* The number to lookup */
|
char *naptrinput; /* The number to lookup */
|
||||||
|
int position; /* used as counter for RRs or specifies position of required RR */
|
||||||
|
int options; /* options , see ENUMLOOKUP_OPTIONS_* defined above */
|
||||||
|
struct enum_naptr_rr *naptr_rrs; /* array of parsed NAPTR RRs */
|
||||||
|
int naptr_rrs_count; /* Size of array naptr_rrs */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*--- txt_callback: Callback for TXT record lookup */
|
/*--- txt_callback: Callback for TXT record lookup */
|
||||||
@@ -298,44 +332,121 @@ static int txt_callback(void *context, char *answer, int len, char *fullanswer)
|
|||||||
static int enum_callback(void *context, char *answer, int len, char *fullanswer)
|
static int enum_callback(void *context, char *answer, int len, char *fullanswer)
|
||||||
{
|
{
|
||||||
struct enum_context *c = (struct enum_context *)context;
|
struct enum_context *c = (struct enum_context *)context;
|
||||||
|
void *p = NULL;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput)) {
|
res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput);
|
||||||
|
|
||||||
|
if(res < 0){
|
||||||
ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
|
ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if(res > 0 && !ast_strlen_zero(c->dst)){ /* ok, we got needed NAPTR */
|
||||||
|
if(c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */
|
||||||
|
c->position++;
|
||||||
|
snprintf(c->dst, c->dstlen, "%d", c->position);
|
||||||
|
} else {
|
||||||
|
p = realloc(c->naptr_rrs, sizeof(struct enum_naptr_rr)*(c->naptr_rrs_count+1));
|
||||||
|
if(p){
|
||||||
|
c->naptr_rrs = (struct enum_naptr_rr*)p;
|
||||||
|
memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(struct naptr));
|
||||||
|
/* printf("order=%d, pref=%d\n", ntohs(c->naptr_rrs[c->naptr_rrs_count].naptr.order), ntohs(c->naptr_rrs[c->naptr_rrs_count].naptr.pref)); */
|
||||||
|
c->naptr_rrs[c->naptr_rrs_count].result = strdup(c->dst);
|
||||||
|
c->naptr_rrs[c->naptr_rrs_count].tech = strdup(c->tech);
|
||||||
|
c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count;
|
||||||
|
c->naptr_rrs_count++;
|
||||||
|
}
|
||||||
|
c->dst[0] = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ast_strlen_zero(c->dst))
|
if(c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */
|
||||||
return 1;
|
snprintf(c->dst, c->dstlen, "%d", c->position);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--- ast_get_enum: ENUM lookup */
|
/*--- ast_get_enum: ENUM lookup */
|
||||||
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen)
|
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options)
|
||||||
{
|
{
|
||||||
struct enum_context context;
|
struct enum_context context;
|
||||||
char tmp[259 + 512];
|
char tmp[259 + 512];
|
||||||
char naptrinput[512] = "+";
|
char naptrinput[512];
|
||||||
int pos = strlen(number) - 1;
|
int pos = strlen(number) - 1;
|
||||||
int newpos = 0;
|
int newpos = 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
struct enum_search *s = NULL;
|
struct enum_search *s = NULL;
|
||||||
int version = -1;
|
int version = -1;
|
||||||
|
/* for ISN rewrite */
|
||||||
|
char *p1 = NULL;
|
||||||
|
char *p2 = NULL;
|
||||||
|
int k = 0;
|
||||||
|
int i = 0;
|
||||||
|
int z = 0;
|
||||||
|
|
||||||
strncat(naptrinput, number, sizeof(naptrinput) - 2);
|
if(number[0] == 'n'){
|
||||||
|
strncpy(naptrinput, number+1, sizeof(naptrinput));
|
||||||
|
} else {
|
||||||
|
strncpy(naptrinput, number, sizeof(naptrinput));
|
||||||
|
}
|
||||||
|
|
||||||
context.naptrinput = naptrinput; /* The number */
|
context.naptrinput = naptrinput; /* The number */
|
||||||
context.dst = dst; /* Return string */
|
context.dst = dst; /* Return string */
|
||||||
context.dstlen = dstlen;
|
context.dstlen = dstlen;
|
||||||
context.tech = tech; /* Return string */
|
context.tech = tech;
|
||||||
context.techlen = techlen;
|
context.techlen = techlen;
|
||||||
|
context.options = 0;
|
||||||
|
context.position = 1;
|
||||||
|
context.naptr_rrs = NULL;
|
||||||
|
context.naptr_rrs_count = 0;
|
||||||
|
|
||||||
|
if(options != NULL){
|
||||||
|
if(*options == 'c'){
|
||||||
|
context.options = ENUMLOOKUP_OPTIONS_COUNT;
|
||||||
|
context.position = 0;
|
||||||
|
} else {
|
||||||
|
context.position = atoi(options);
|
||||||
|
if(context.position < 1)
|
||||||
|
context.position = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pos > 128)
|
if (pos > 128)
|
||||||
pos = 128;
|
pos = 128;
|
||||||
while(pos >= 0) {
|
|
||||||
tmp[newpos++] = number[pos--];
|
/* ISN rewrite */
|
||||||
|
p1 = strchr(number, '*');
|
||||||
|
|
||||||
|
if(number[0] == 'n'){ /* do not perform ISN rewrite ('n' is testing flag) */
|
||||||
|
p1 = NULL;
|
||||||
|
k = 1; /* strip 'n' from number */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p1 != NULL){
|
||||||
|
p2 = p1+1;
|
||||||
|
while(p1 > number){
|
||||||
|
p1--;
|
||||||
|
tmp[newpos++] = *p1;
|
||||||
tmp[newpos++] = '.';
|
tmp[newpos++] = '.';
|
||||||
}
|
}
|
||||||
|
if(*p2){
|
||||||
|
while(*p2 && newpos < 128){
|
||||||
|
tmp[newpos++] = *p2;
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
tmp[newpos++] = '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
while(pos >= k) {
|
||||||
|
if(isdigit(number[pos])){
|
||||||
|
tmp[newpos++] = number[pos];
|
||||||
|
tmp[newpos++] = '.';
|
||||||
|
}
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (chan && ast_autoservice_start(chan) < 0)
|
if (chan && ast_autoservice_start(chan) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -349,7 +460,9 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
|
|||||||
} else {
|
} else {
|
||||||
s = s->next;
|
s = s->next;
|
||||||
}
|
}
|
||||||
if (s) {
|
if(suffix != NULL){
|
||||||
|
strncpy(tmp + newpos, suffix, sizeof(tmp) - newpos - 1);
|
||||||
|
} else if (s) {
|
||||||
strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
|
strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
|
||||||
}
|
}
|
||||||
ast_mutex_unlock(&enumlock);
|
ast_mutex_unlock(&enumlock);
|
||||||
@@ -358,13 +471,61 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
|
|||||||
ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
|
ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
break;
|
break;
|
||||||
|
if(suffix != NULL)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
|
ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(context.naptr_rrs_count >= context.position && ! (context.options & ENUMLOOKUP_OPTIONS_COUNT)){
|
||||||
|
/* sort array by NAPTR order/preference */
|
||||||
|
for(k=0; k<context.naptr_rrs_count; k++){
|
||||||
|
for(i=0; i<context.naptr_rrs_count; i++){
|
||||||
|
/* use order first and then preference to compare */
|
||||||
|
if((ntohs(context.naptr_rrs[k].naptr.order) < ntohs(context.naptr_rrs[i].naptr.order)
|
||||||
|
&& context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
|
||||||
|
|| (ntohs(context.naptr_rrs[k].naptr.order) > ntohs(context.naptr_rrs[i].naptr.order)
|
||||||
|
&& context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
|
||||||
|
z = context.naptr_rrs[k].sort_pos;
|
||||||
|
context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
|
||||||
|
context.naptr_rrs[i].sort_pos = z;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(ntohs(context.naptr_rrs[k].naptr.order) == ntohs(context.naptr_rrs[i].naptr.order)){
|
||||||
|
if((ntohs(context.naptr_rrs[k].naptr.pref) < ntohs(context.naptr_rrs[i].naptr.pref)
|
||||||
|
&& context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
|
||||||
|
|| (ntohs(context.naptr_rrs[k].naptr.pref) > ntohs(context.naptr_rrs[i].naptr.pref)
|
||||||
|
&& context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
|
||||||
|
z = context.naptr_rrs[k].sort_pos;
|
||||||
|
context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
|
||||||
|
context.naptr_rrs[i].sort_pos = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(k=0; k<context.naptr_rrs_count; k++){
|
||||||
|
if(context.naptr_rrs[k].sort_pos == context.position-1){
|
||||||
|
ast_copy_string(context.dst, context.naptr_rrs[k].result, dstlen);
|
||||||
|
ast_copy_string(context.tech, context.naptr_rrs[k].tech, techlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if( !(context.options & ENUMLOOKUP_OPTIONS_COUNT) ) {
|
||||||
|
context.dst[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan)
|
if (chan)
|
||||||
ret |= ast_autoservice_stop(chan);
|
ret |= ast_autoservice_stop(chan);
|
||||||
|
|
||||||
|
for(k=0; k<context.naptr_rrs_count; k++){
|
||||||
|
free(context.naptr_rrs[k].result);
|
||||||
|
free(context.naptr_rrs[k].tech);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(context.naptr_rrs);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
174
funcs/func_enum.c
Executable file
174
funcs/func_enum.c
Executable file
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Asterisk -- A telephony toolkit for Linux.
|
||||||
|
*
|
||||||
|
* Enum Functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005
|
||||||
|
*
|
||||||
|
* Oleksiy Krivoshey <oleksiyk@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "asterisk.h"
|
||||||
|
|
||||||
|
#ifndef BUILTIN_FUNC
|
||||||
|
#include "asterisk/module.h"
|
||||||
|
#endif /* BUILTIN_FUNC */
|
||||||
|
#include "asterisk/channel.h"
|
||||||
|
#include "asterisk/pbx.h"
|
||||||
|
#include "asterisk/utils.h"
|
||||||
|
|
||||||
|
#include "asterisk/lock.h"
|
||||||
|
#include "asterisk/file.h"
|
||||||
|
#include "asterisk/logger.h"
|
||||||
|
|
||||||
|
#include "asterisk/pbx.h"
|
||||||
|
#include "asterisk/options.h"
|
||||||
|
|
||||||
|
#include "asterisk/enum.h"
|
||||||
|
|
||||||
|
static char* synopsis = "Syntax: ENUMLOOKUP(number[,Method-type[,options|record#[,zone-suffix]]])\n";
|
||||||
|
|
||||||
|
STANDARD_LOCAL_USER;
|
||||||
|
|
||||||
|
LOCAL_USER_DECL;
|
||||||
|
|
||||||
|
static char *function_enum(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int res=0;
|
||||||
|
char tech[80];
|
||||||
|
char dest[80] = "";
|
||||||
|
char *zone;
|
||||||
|
char *options;
|
||||||
|
struct localuser *u;
|
||||||
|
char *params[4];
|
||||||
|
char *p = data;
|
||||||
|
char *s;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (!data || ast_strlen_zero(data)) {
|
||||||
|
ast_log(LOG_WARNING, synopsis);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(i>3){
|
||||||
|
ast_log(LOG_WARNING, synopsis);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
params[i++] = p;
|
||||||
|
p = strchr(p, '|');
|
||||||
|
if(p){
|
||||||
|
*p = '\0';
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
} while(p);
|
||||||
|
|
||||||
|
if(i < 1){
|
||||||
|
ast_log(LOG_WARNING, synopsis);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (i > 1 && strlen(params[1]) == 0) || i < 2){
|
||||||
|
ast_copy_string(tech, "sip", sizeof(tech));
|
||||||
|
} else {
|
||||||
|
ast_copy_string(tech, params[1], sizeof(tech));
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (i > 3 && strlen(params[3]) == 0) || i<4){
|
||||||
|
zone = "e164.arpa";
|
||||||
|
} else {
|
||||||
|
zone = params[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (i > 2 && strlen(params[2]) == 0) || i<3){
|
||||||
|
options = "1";
|
||||||
|
} else {
|
||||||
|
options = params[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strip any '-' signs from number */
|
||||||
|
p = params[0];
|
||||||
|
/*
|
||||||
|
while(*p == '+'){
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
s = p;
|
||||||
|
i = 0;
|
||||||
|
while(*p && *s){
|
||||||
|
if(*s == '-'){
|
||||||
|
s++;
|
||||||
|
} else {
|
||||||
|
p[i++] = *s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p[i] = 0;
|
||||||
|
|
||||||
|
LOCAL_USER_ACF_ADD(u);
|
||||||
|
|
||||||
|
res = ast_get_enum(chan, p, dest, sizeof(dest), tech, sizeof(tech), zone, options);
|
||||||
|
|
||||||
|
LOCAL_USER_REMOVE(u);
|
||||||
|
|
||||||
|
p = strchr(dest, ':');
|
||||||
|
if(p && strncasecmp(tech, "ALL", sizeof(tech))) {
|
||||||
|
ast_copy_string(buf, p+1, sizeof(dest));
|
||||||
|
} else {
|
||||||
|
ast_copy_string(buf, dest, sizeof(dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef BUILTIN_FUNC
|
||||||
|
static
|
||||||
|
#endif
|
||||||
|
struct ast_custom_function enum_function = {
|
||||||
|
.name = "ENUMLOOKUP",
|
||||||
|
.synopsis = "ENUMLOOKUP allows for general or specific querying of NAPTR records"
|
||||||
|
" or counts of NAPTR types for ENUM or ENUM-like DNS pointers",
|
||||||
|
.syntax = "ENUMLOOKUP(number[,Method-type[,options|record#[,zone-suffix]]])",
|
||||||
|
.desc = "Option 'c' returns an integer count of the number of NAPTRs of a certain RR type.\n"
|
||||||
|
"Combination of 'c' and Method-type of 'ALL' will return a count of all NAPTRs for the record.\n"
|
||||||
|
"Defaults are: Method-type=sip, no options, record=1, zone-suffix=e164.arpa\n\n"
|
||||||
|
"For more information, see README.enum",
|
||||||
|
.read = function_enum,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef BUILTIN_FUNC
|
||||||
|
|
||||||
|
static char *tdesc = "ENUMLOOKUP allows for general or specific querying of NAPTR records or counts of NAPTR types for ENUM or ENUM-like DNS pointers";
|
||||||
|
|
||||||
|
int unload_module(void)
|
||||||
|
{
|
||||||
|
return ast_custom_function_unregister(&enum_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_module(void)
|
||||||
|
{
|
||||||
|
return ast_custom_function_register(&enum_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *description(void)
|
||||||
|
{
|
||||||
|
return tdesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usecount(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *key()
|
||||||
|
{
|
||||||
|
return ASTERISK_GPL_KEY;
|
||||||
|
}
|
||||||
|
#endif /* BUILTIN_FUNC */
|
||||||
|
|
@@ -31,18 +31,23 @@
|
|||||||
|
|
||||||
/*! \brief Lookup entry in ENUM Returns 1 if found, 0 if not found, -1 on hangup
|
/*! \brief Lookup entry in ENUM Returns 1 if found, 0 if not found, -1 on hangup
|
||||||
\param chan Channel
|
\param chan Channel
|
||||||
\param number Number in E164 format without the + (for e164.arpa) or format
|
\param number E164 number with or without the leading +
|
||||||
requested by enum service used (enum.conf)
|
|
||||||
\param location Number returned (or SIP uri)
|
\param location Number returned (or SIP uri)
|
||||||
\param maxloc Max length
|
\param maxloc Max length
|
||||||
\param tech Technology (from url scheme in response)
|
\param tech Technology (from url scheme in response)
|
||||||
\param maxtech Max length
|
\param maxtech Max length
|
||||||
*/
|
\param tech Technology (from url scheme in response)
|
||||||
extern int ast_get_enum(struct ast_channel *chan, const char *number, char *location, int maxloc, char *technology, int maxtech);
|
You can set it to get particular answer RR, if there are many techs in DNS response, example: "sip"
|
||||||
|
If you need any record, then set it to empty string
|
||||||
|
\param maxtech Max length
|
||||||
|
\param suffix Zone suffix (if is NULL then use enum.conf 'search' variable)
|
||||||
|
\param options Options ('c' to count number of NAPTR RR, or number - the position of required RR in the answer list
|
||||||
|
|
||||||
|
*/
|
||||||
|
extern int ast_get_enum(struct ast_channel *chan, const char *number, char *location, int maxloc, char *technology, int maxtech, char* suffix, char* options);
|
||||||
/*! \brief Lookup DNS TXT record (used by app TXTCIDnum
|
/*! \brief Lookup DNS TXT record (used by app TXTCIDnum
|
||||||
\param chan Channel
|
\param chan Channel
|
||||||
\param number E164 number without the +
|
\param number E164 number with or without the leading +
|
||||||
\param locatio Number returned (or SIP uri)
|
\param locatio Number returned (or SIP uri)
|
||||||
\param maxloc Max length of number
|
\param maxloc Max length of number
|
||||||
\param tech Technology (not used in TXT records)
|
\param tech Technology (not used in TXT records)
|
||||||
|
Reference in New Issue
Block a user