Merge ENUM fixes (bug #99)
authorMark Spencer <markster@digium.com>
Thu, 14 Aug 2003 21:33:49 +0000 (21:33 +0000)
committerMark Spencer <markster@digium.com>
Thu, 14 Aug 2003 21:33:49 +0000 (21:33 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1335 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_enumlookup.c
enum.c

index 20a7304..d547f8a 100755 (executable)
@@ -35,9 +35,12 @@ static char *synopsis = "Lookup number in ENUM";
 static char *descrip = 
 "  EnumLookup(exten):  Looks up an extension via ENUM and sets\n"
 "the variable 'ENUM'.  Returns -1 on hangup, or 0 on completion\n"
-"regardless of whether the lookup was successful.  If the lookup\n"
-"was *not* successful and there exists a priority n + 101, then\n"
-"that priority will be taken next.\n" ;
+"regardless of whether the lookup was successful. Currently, the\n"
+"enumservices SIP and TEL are recognized. A good SIP entry\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;
 
@@ -49,7 +52,7 @@ static int enumlookup_exec(struct ast_channel *chan, void *data)
        char tech[80];
        char dest[80];
        char tmp[256];
-       char *c;
+       char *c,*t;
        struct localuser *u;
        if (!data || !strlen(data)) {
                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;
                        snprintf(tmp, sizeof(tmp), "SIP/%s", c);
                        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)) {
                        ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech);
                        res = 0;
diff --git a/enum.c b/enum.c
index 4bb5bd3..b3a0a3c 100755 (executable)
--- a/enum.c
+++ b/enum.c
@@ -21,6 +21,9 @@
 #include <arpa/nameser.h>
 #include <resolv.h>
 #include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
 
 #include <asterisk/logger.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;
 }
 
-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 flags[80] = "";
        unsigned char services[80] = "";
        unsigned char regexp[80] = "";
        unsigned char repl[80] = "";
+       unsigned char temp[80] = "";
+       unsigned char delim;
+       unsigned char *delim2;
+       unsigned char *pattern, *subst, *d;
        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)) {
                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");
                return -1;
        } 
+
 #if 0
+       printf("Input: %s\n", naptrinput);
        printf("Flags: %s\n", flags);
        printf("Services: %s\n", services);
        printf("Regexp: %s\n", regexp);
        printf("Repl: %s\n", repl);
 #endif
-       if (!strncmp(regexp, "!^.*$!", 6)) {
-               if (!strncmp(services, "E2U+voice:", 10)) {
-                       if (regexp[strlen(regexp) - 1] == '!')
-                               regexp[strlen(regexp) - 1] = '\0';
+
+       if (tolower(flags[0]) != 'u') {
+               ast_log(LOG_WARNING, "Flag must be 'U' or 'u'.\n");
+               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
-                       printf("Technology: %s\n", services + 10);
-                       printf("Destination: %s\n", regexp + 6);
+       printf("Pattern: %s\n", pattern);
+       printf("Subst: %s\n", subst);
 #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;
 }
 
-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.
@@ -255,7 +349,7 @@ static int parse_answer(unsigned char *dst, int dstlen, unsigned char *tech, int
                        return -1;
                }
                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");
                        if (strlen(dst))
                                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];
        char tmp[259 + 80];
+       char naptrinput[80] = "+";
        int pos = strlen(number) - 1;
        int newpos=0;
        int res = -1;
@@ -279,7 +374,9 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
        res_ninit(&enumstate);  
        if (chan && ast_autoservice_start(chan) < 0)
                return -1;
-       
+
+       strncat(naptrinput, number, sizeof(naptrinput) - 2);
+
        if (pos > 128)
                pos = 128;
        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) {
                        /* Ooh, a reload... */
                        s = toplevs;
+                       version = enumver;
                } else {
                        s = s->next;
                }
@@ -309,7 +407,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
                        break;
        }
        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);
                        ret = 0;
                } else {