--- asterisk/apps/app_enumlookup.c 2005-08-30 23:35:09.000000000 +0300 +++ asterisk-m/apps/app_enumlookup.c 2005-09-03 00:10:42.000000000 +0300 @@ -38,7 +38,7 @@ static char *synopsis = "Lookup number in ENUM"; -static char *descrip = +static char *descrip = " EnumLookup(exten): Looks up an extension via ENUM and sets\n" "the variable 'ENUM'. For VoIP URIs this variable will \n" "look like 'TECHNOLOGY/URI' with the appropriate technology.\n" @@ -71,6 +71,9 @@ char dest[80]; char tmp[256]; char *c,*t; + + tech[0] = '\0'; + struct localuser *u; if (!data || ast_strlen_zero(data)) { @@ -79,7 +82,7 @@ } LOCAL_USER_ADD(u); 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); } LOCAL_USER_REMOVE(u); @@ -105,7 +108,7 @@ snprintf(tmp, sizeof(tmp), "%s/%s", h323driver, c); /* do a s!;.*!! on the H323 URI */ t = strchr(c,';'); - if (t) + if (t) *t = 0; pbx_builtin_setvar_helper(chan, "ENUM", tmp); } else if (!strcasecmp(tech, "iax")) { @@ -130,7 +133,7 @@ res = 0; } else { /* now copy over the number, skipping all non-digits and stop at ; or NULL */ - t = tmp; + t = tmp; while( *c && (*c != ';') && (t - tmp < (sizeof(tmp) - 1))) { if (isdigit(*c)) *t++ = *c; diff -Naur asterisk/enum.c asterisk-m/enum.c --- asterisk/enum.c 2005-08-30 23:35:09.000000000 +0300 +++ asterisk-m/enum.c 2005-09-03 23:11:36.000000000 +0300 @@ -87,9 +87,12 @@ /*--- 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) { + + char tech_return[80]; char *oanswer = answer; char flags[512] = ""; char services[512] = ""; + unsigned char *p; char regexp[512] = ""; char repl[512] = ""; char temp[512] = ""; @@ -102,9 +105,10 @@ regex_t preg; regmatch_t pmatch[9]; + tech_return[0] = '\0'; dst[0] = '\0'; - + if (len < sizeof(struct naptr)) { ast_log(LOG_WARNING, "NAPTR record length too short\n"); return -1; @@ -113,29 +117,30 @@ len -= sizeof(struct naptr); if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) { ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n"); - return -1; - } else { - answer += res; - len -= res; + return -1; + } else { + answer += res; + len -= res; } if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) { ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n"); - return -1; - } else { - answer += res; - len -= res; + return -1; + } else { + answer += res; + len -= res; } if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) { ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n"); - return -1; - } else { - answer += res; - len -= res; + return -1; + } else { + answer += res; + len -= res; } + 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"); return -1; - } + } if (option_debug > 2) /* Advanced NAPTR debugging */ ast_log(LOG_DEBUG, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n", @@ -146,29 +151,27 @@ return -1; } - if ((!strncasecmp(services, "e2u+sip", 7)) || - (!strncasecmp(services, "sip+e2u", 7))) { - ast_copy_string(tech, "sip", techsize); - } else if ((!strncasecmp(services, "e2u+h323", 8)) || - (!strncasecmp(services, "h323+e2u", 8))) { - ast_copy_string(tech, "h323", techsize); - } else if ((!strncasecmp(services, "e2u+x-iax2", 10)) || - (!strncasecmp(services, "e2u+iax2", 8)) || - (!strncasecmp(services, "iax2+e2u", 8))) { - 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); + p = strstr(services, "e2u+"); + if(p == NULL) + p = strstr(services, "E2U+"); + if(p){ + p = p + 4; + if(strchr(p, ':')){ + p = strchr(p, ':') + 1; + } + ast_copy_string(tech_return, p, sizeof(tech_return)); } 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"); - return 0; + + p = strstr(services, "+e2u"); + 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 @@ -179,7 +182,7 @@ if (regexp_len < 7) { ast_log(LOG_WARNING, "Regex too short to be meaningful.\n"); return -1; - } + } delim = regexp[0]; @@ -197,6 +200,7 @@ #if 0 printf("Pattern: %s\n", pattern); printf("Subst: %s\n", subst); + printf("Input: %s\n", naptrinput); #endif /* @@ -221,8 +225,8 @@ } regfree(&preg); - d = temp; - d_len--; + d = temp; + d_len--; while( *subst && (d_len > 0) ) { if ((subst[0] == '\\') && isdigit(subst[1]) && (pmatch[subst[1]-'0'].rm_so != -1)) { backref = subst[1]-'0'; @@ -246,9 +250,35 @@ *d = 0; ast_copy_string(dst, temp, dstsize); dst[dstsize - 1] = '\0'; - return 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)txt */ ast_copy_string(c->txt, answer, len < c->txtlen ? len : (c->txtlen)); - + /* just to be safe, let's make sure c->txt is null terminated */ c->txt[(c->txtlen)-1] = '\0'; @@ -298,45 +332,122 @@ static int enum_callback(void *context, char *answer, int len, char *fullanswer) { struct enum_context *c = (struct enum_context *)context; + void *p = NULL; + int res; + + res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput); - if (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"); 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)) - return 1; + if(c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */ + snprintf(c->dst, c->dstlen, "%d", c->position); + } return 0; } /*--- 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; char tmp[259 + 512]; - char naptrinput[512] = "+"; + char naptrinput[512]; int pos = strlen(number) - 1; int newpos = 0; int ret = -1; struct enum_search *s = NULL; 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.dst = dst; /* Return string */ context.dstlen = dstlen; - context.tech = tech; /* Return string */ + context.tech = tech; 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) pos = 128; - while(pos >= 0) { - tmp[newpos++] = number[pos--]; - tmp[newpos++] = '.'; + + /* 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++] = '.'; + } + 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) return -1; @@ -349,7 +460,9 @@ } else { 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); } ast_mutex_unlock(&enumlock); @@ -358,17 +471,65 @@ ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback); if (ret > 0) break; + if(suffix != NULL) + break; } if (ret < 0) { ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno)); 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[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 + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#include + +#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/config.h" */ + +#include "asterisk/enum.h" + +/* static char h323driver[80] = ""; */ +#define H323DRIVERDEFAULT "H323" + +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 */ + diff -Naur asterisk/include/asterisk/enum.h asterisk-m/include/asterisk/enum.h --- asterisk/include/asterisk/enum.h 2005-08-30 23:35:12.000000000 +0300 +++ asterisk-m/include/asterisk/enum.h 2005-09-03 23:27:28.000000000 +0300 @@ -29,20 +29,25 @@ #include "asterisk/channel.h" -/*! \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 number Number in E164 format without the + (for e164.arpa) or format - requested by enum service used (enum.conf) + \param number E164 number with or without the leading + \param location Number returned (or SIP uri) \param maxloc Max length \param tech Technology (from url scheme in response) \param maxtech Max length -*/ -extern int ast_get_enum(struct ast_channel *chan, const char *number, char *location, int maxloc, char *technology, int maxtech); + \param tech Technology (from url scheme in response) + 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 \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 maxloc Max length of number \param tech Technology (not used in TXT records)