mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 03:50:31 +00:00
Merge ENUM fixes (bug #99)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1335 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -35,9 +35,12 @@ static char *synopsis = "Lookup number in ENUM";
|
|||||||
static char *descrip =
|
static char *descrip =
|
||||||
" EnumLookup(exten): Looks up an extension via ENUM and sets\n"
|
" EnumLookup(exten): Looks up an extension via ENUM and sets\n"
|
||||||
"the variable 'ENUM'. Returns -1 on hangup, or 0 on completion\n"
|
"the variable 'ENUM'. Returns -1 on hangup, or 0 on completion\n"
|
||||||
"regardless of whether the lookup was successful. If the lookup\n"
|
"regardless of whether the lookup was successful. Currently, the\n"
|
||||||
"was *not* successful and there exists a priority n + 101, then\n"
|
"enumservices SIP and TEL are recognized. A good SIP entry\n"
|
||||||
"that priority will be taken next.\n" ;
|
"will result in normal priority handling, whereas a good TEL entry\n"
|
||||||
|
"will increase the priority by 51 (if existing)\n"
|
||||||
|
"If the lookup was *not* successful and there exists a priority n + 101,\n"
|
||||||
|
"then that priority will be taken next.\n" ;
|
||||||
|
|
||||||
STANDARD_LOCAL_USER;
|
STANDARD_LOCAL_USER;
|
||||||
|
|
||||||
@@ -49,7 +52,7 @@ static int enumlookup_exec(struct ast_channel *chan, void *data)
|
|||||||
char tech[80];
|
char tech[80];
|
||||||
char dest[80];
|
char dest[80];
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
char *c;
|
char *c,*t;
|
||||||
struct localuser *u;
|
struct localuser *u;
|
||||||
if (!data || !strlen(data)) {
|
if (!data || !strlen(data)) {
|
||||||
ast_log(LOG_WARNING, "EnumLookup requires an argument (extension)\n");
|
ast_log(LOG_WARNING, "EnumLookup requires an argument (extension)\n");
|
||||||
@@ -69,6 +72,30 @@ static int enumlookup_exec(struct ast_channel *chan, void *data)
|
|||||||
c += 4;
|
c += 4;
|
||||||
snprintf(tmp, sizeof(tmp), "SIP/%s", c);
|
snprintf(tmp, sizeof(tmp), "SIP/%s", c);
|
||||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||||
|
} else if (!strcasecmp(tech, "tel")) {
|
||||||
|
c = dest;
|
||||||
|
if (!strncmp(c, "tel:", 4))
|
||||||
|
c += 4;
|
||||||
|
|
||||||
|
if (c[0] != '+') {
|
||||||
|
ast_log(LOG_NOTICE, "tel: uri must start with a \"+\" (got '%s')\n", c);
|
||||||
|
res = 0;
|
||||||
|
} else {
|
||||||
|
/* now copy over the number, skipping all non-digits and stop at ; or NULL */
|
||||||
|
t = tmp;
|
||||||
|
while( *c && (*c != ';') && (t - tmp < (sizeof(tmp) - 1))) {
|
||||||
|
if (isdigit(*c))
|
||||||
|
*t++ = *c;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
*t = 0;
|
||||||
|
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||||
|
ast_log(LOG_NOTICE, "tel: ENUM set to \"%s\"\n", tmp);
|
||||||
|
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 51, chan->callerid))
|
||||||
|
chan->priority += 50;
|
||||||
|
else
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
} else if (strlen(tech)) {
|
} else if (strlen(tech)) {
|
||||||
ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech);
|
ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech);
|
||||||
res = 0;
|
res = 0;
|
||||||
|
126
enum.c
126
enum.c
@@ -21,6 +21,9 @@
|
|||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
#include <resolv.h>
|
#include <resolv.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
|
|
||||||
#include <asterisk/logger.h>
|
#include <asterisk/logger.h>
|
||||||
#include <asterisk/options.h>
|
#include <asterisk/options.h>
|
||||||
@@ -129,14 +132,23 @@ static int parse_ie(unsigned char *data, int maxdatalen, unsigned char *src, int
|
|||||||
return olen + 1;
|
return olen + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len)
|
static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput)
|
||||||
{
|
{
|
||||||
unsigned char *oanswer = answer;
|
unsigned char *oanswer = answer;
|
||||||
unsigned char flags[80] = "";
|
unsigned char flags[80] = "";
|
||||||
unsigned char services[80] = "";
|
unsigned char services[80] = "";
|
||||||
unsigned char regexp[80] = "";
|
unsigned char regexp[80] = "";
|
||||||
unsigned char repl[80] = "";
|
unsigned char repl[80] = "";
|
||||||
|
unsigned char temp[80] = "";
|
||||||
|
unsigned char delim;
|
||||||
|
unsigned char *delim2;
|
||||||
|
unsigned char *pattern, *subst, *d;
|
||||||
int res;
|
int res;
|
||||||
|
int regexp_len, size, backref;
|
||||||
|
int d_len = sizeof(temp) - 1;
|
||||||
|
regex_t preg;
|
||||||
|
regmatch_t pmatch[9];
|
||||||
|
|
||||||
|
|
||||||
if (len < sizeof(struct naptr)) {
|
if (len < sizeof(struct naptr)) {
|
||||||
printf("Length too short\n");
|
printf("Length too short\n");
|
||||||
@@ -158,29 +170,111 @@ static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize
|
|||||||
ast_log(LOG_WARNING, "Failed to expand hostname\n");
|
ast_log(LOG_WARNING, "Failed to expand hostname\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
printf("Input: %s\n", naptrinput);
|
||||||
printf("Flags: %s\n", flags);
|
printf("Flags: %s\n", flags);
|
||||||
printf("Services: %s\n", services);
|
printf("Services: %s\n", services);
|
||||||
printf("Regexp: %s\n", regexp);
|
printf("Regexp: %s\n", regexp);
|
||||||
printf("Repl: %s\n", repl);
|
printf("Repl: %s\n", repl);
|
||||||
#endif
|
#endif
|
||||||
if (!strncmp(regexp, "!^.*$!", 6)) {
|
|
||||||
if (!strncmp(services, "E2U+voice:", 10)) {
|
if (tolower(flags[0]) != 'u') {
|
||||||
if (regexp[strlen(regexp) - 1] == '!')
|
ast_log(LOG_WARNING, "Flag must be 'U' or 'u'.\n");
|
||||||
regexp[strlen(regexp) - 1] = '\0';
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!strncasecmp(services, "e2u+sip", 7)) ||
|
||||||
|
(!strncasecmp(services, "sip+e2u", 7))) {
|
||||||
|
strncpy(tech, "sip", techsize -1);
|
||||||
|
} else if ((!strncasecmp(services, "e2u+tel", 7)) ||
|
||||||
|
(!strncasecmp(services, "tel+e2u", 7))) {
|
||||||
|
strncpy(tech, "tel", techsize -1);
|
||||||
|
} else if (strncasecmp(services, "e2u+voice:", 10)) {
|
||||||
|
ast_log(LOG_WARNING, "Services must be e2u+sip, sip+e2u, e2u+tel, tel+e2u or e2u+voice:\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEDBUGGING STUB
|
||||||
|
strcpy(regexp, "!^\\+43(.*)$!\\1@bla.fasel!");
|
||||||
|
*/
|
||||||
|
|
||||||
|
regexp_len = strlen(regexp);
|
||||||
|
if (regexp_len < 7) {
|
||||||
|
ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
delim = regexp[0];
|
||||||
|
delim2 = strchr(regexp + 1, delim);
|
||||||
|
if ((delim2 == NULL) || (regexp[regexp_len-1] != delim)) {
|
||||||
|
ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n",regexp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern = regexp + 1;
|
||||||
|
*delim2 = 0;
|
||||||
|
subst = delim2 + 1;
|
||||||
|
regexp[regexp_len-1] = 0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printf("Technology: %s\n", services + 10);
|
printf("Pattern: %s\n", pattern);
|
||||||
printf("Destination: %s\n", regexp + 6);
|
printf("Subst: %s\n", subst);
|
||||||
#endif
|
#endif
|
||||||
strncpy(dst, regexp + 6, dstsize);
|
|
||||||
strncpy(tech, services + 10, techsize);
|
/*
|
||||||
|
* now do the regex wizardry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
|
||||||
|
ast_log(LOG_WARNING, "Regex compilation error (regex = \"%s\").\n",regexp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg.re_nsub > 9) {
|
||||||
|
ast_log(LOG_WARNING, "Regex compilation error: too many subs.\n");
|
||||||
|
regfree(&preg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regexec(&preg, naptrinput, 9, pmatch, 0)) {
|
||||||
|
ast_log(LOG_WARNING, "Regex match failed.\n");
|
||||||
|
regfree(&preg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
regfree(&preg);
|
||||||
|
|
||||||
|
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';
|
||||||
|
size = pmatch[backref].rm_eo - pmatch[backref].rm_so;
|
||||||
|
if (size > d_len) {
|
||||||
|
ast_log(LOG_WARNING, "Not enough space during regex substitution.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(d, naptrinput + pmatch[backref].rm_so, size);
|
||||||
|
d += size;
|
||||||
|
d_len -= size;
|
||||||
|
subst += 2;
|
||||||
|
} else if (isprint(*subst)) {
|
||||||
|
*d++ = *subst++;
|
||||||
|
d_len--;
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_WARNING, "Error during regex substitution.\n");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
ast_log(LOG_WARNING, "Non-total substitution not yet supported\n");
|
*d = 0;
|
||||||
|
strncpy(dst, temp, dstsize);
|
||||||
|
d = strchr(services, ':');
|
||||||
|
if (d)
|
||||||
|
strncpy(tech, d+1, techsize -1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_answer(unsigned char *dst, int dstlen, unsigned char *tech, int techlen, unsigned char *answer, int len)
|
static int parse_answer(unsigned char *dst, int dstlen, unsigned char *tech, int techlen, unsigned char *answer, int len, char *naptrinput)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This function is influenced by "ser" the SIP router.
|
* This function is influenced by "ser" the SIP router.
|
||||||
@@ -255,7 +349,7 @@ static int parse_answer(unsigned char *dst, int dstlen, unsigned char *tech, int
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((ntohs(ans->class) == C_IN) && (ntohs(ans->rtype) == T_NAPTR)) {
|
if ((ntohs(ans->class) == C_IN) && (ntohs(ans->rtype) == T_NAPTR)) {
|
||||||
if (parse_naptr(dst, dstlen, tech, techlen, answer, ntohs(ans->size)))
|
if (parse_naptr(dst, dstlen, tech, techlen, answer, ntohs(ans->size), naptrinput))
|
||||||
ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
|
ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
|
||||||
if (strlen(dst))
|
if (strlen(dst))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -269,6 +363,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
|
|||||||
{
|
{
|
||||||
unsigned char answer[MAX_SIZE];
|
unsigned char answer[MAX_SIZE];
|
||||||
char tmp[259 + 80];
|
char tmp[259 + 80];
|
||||||
|
char naptrinput[80] = "+";
|
||||||
int pos = strlen(number) - 1;
|
int pos = strlen(number) - 1;
|
||||||
int newpos=0;
|
int newpos=0;
|
||||||
int res = -1;
|
int res = -1;
|
||||||
@@ -280,6 +375,8 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
|
|||||||
if (chan && ast_autoservice_start(chan) < 0)
|
if (chan && ast_autoservice_start(chan) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
strncat(naptrinput, number, sizeof(naptrinput) - 2);
|
||||||
|
|
||||||
if (pos > 128)
|
if (pos > 128)
|
||||||
pos = 128;
|
pos = 128;
|
||||||
while(pos >= 0) {
|
while(pos >= 0) {
|
||||||
@@ -295,6 +392,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
|
|||||||
if (version != enumver) {
|
if (version != enumver) {
|
||||||
/* Ooh, a reload... */
|
/* Ooh, a reload... */
|
||||||
s = toplevs;
|
s = toplevs;
|
||||||
|
version = enumver;
|
||||||
} else {
|
} else {
|
||||||
s = s->next;
|
s = s->next;
|
||||||
}
|
}
|
||||||
@@ -309,7 +407,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
if ((res = parse_answer(dst, dstlen, tech, techlen, answer, res))) {
|
if ((res = parse_answer(dst, dstlen, tech, techlen, answer, res, naptrinput))) {
|
||||||
ast_log(LOG_WARNING, "Parse error returned %d\n", res);
|
ast_log(LOG_WARNING, "Parse error returned %d\n", res);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user