Wed Oct 28 11:45:37 2009

Asterisk developer's documentation


enum.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * Funding provided by nic.at
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief ENUM Support for Asterisk
00024  *
00025  * \author Mark Spencer <markster@digium.com>
00026  *
00027  * \arg Funding provided by nic.at
00028  *
00029  * \par Enum standards
00030  *
00031  * - NAPTR records: http://ietf.nri.reston.va.us/rfc/rfc2915.txt
00032  * - DNS SRV records: http://www.ietf.org/rfc/rfc2782.txt
00033  * - ENUM http://www.ietf.org/rfc/rfc3761.txt
00034  * - ENUM for H.323: http://www.ietf.org/rfc/rfc3762.txt
00035  * - ENUM SIP: http://www.ietf.org/rfc/rfc3764.txt
00036  * - IANA ENUM Services: http://www.iana.org/assignments/enum-services
00037  *
00038  * \par Possible improvement
00039  * \todo Implement a caching mechanism for multile enum lookups
00040  * - See http://bugs.digium.com/view.php?id=6739
00041  */
00042 
00043 #include "asterisk.h"
00044 
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 180535 $")
00046 
00047 #include <sys/socket.h>
00048 #include <netinet/in.h>
00049 #include <arpa/nameser.h>
00050 #ifdef __APPLE__
00051 #if __APPLE_CC__ >= 1495
00052 #include <arpa/nameser_compat.h>
00053 #endif
00054 #endif
00055 #include <resolv.h>
00056 #include <ctype.h>
00057 #include <regex.h>
00058 
00059 #include "asterisk/enum.h"
00060 #include "asterisk/dns.h"
00061 #include "asterisk/channel.h"
00062 #include "asterisk/config.h"
00063 #include "asterisk/utils.h"
00064 #include "asterisk/manager.h"
00065 
00066 #ifdef __APPLE__
00067 #undef T_NAPTR
00068 #define T_NAPTR 35
00069 #endif
00070 
00071 #ifdef __APPLE__
00072 #undef T_TXT
00073 #define T_TXT 16
00074 #endif
00075 
00076 #define TOPLEV "e164.arpa."   /*!< The IETF Enum standard root, managed by the ITU */
00077 
00078 /* Linked list from config file */
00079 static struct enum_search {
00080    char toplev[512];
00081    struct enum_search *next;
00082 } *toplevs;
00083 
00084 static int enumver;
00085 
00086 AST_MUTEX_DEFINE_STATIC(enumlock);
00087 
00088 /*! \brief Parse NAPTR record information elements */
00089 static unsigned int parse_ie(char *data, unsigned int maxdatalen, unsigned char *src, unsigned int srclen)
00090 {
00091    unsigned int len, olen;
00092 
00093    len = olen = (unsigned int) src[0];
00094    src++;
00095    srclen--;
00096 
00097    if (len > srclen) {
00098       ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %d characters, got %d\n", len, srclen);
00099       return -1;
00100    }
00101 
00102    if (len > maxdatalen)
00103       len = maxdatalen;
00104    memcpy(data, src, len);
00105 
00106    return olen + 1;
00107 }
00108 
00109 /*! \brief Parse DNS NAPTR record used in ENUM ---*/
00110 static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput)
00111 {
00112    char tech_return[80];
00113    unsigned char *oanswer = answer;
00114    char flags[512] = "";
00115    char services[512] = "";
00116    char *p;
00117    char regexp[512] = "";
00118    char repl[512] = "";
00119    char tempdst[512] = "";
00120    char errbuff[512] = "";
00121    char delim;
00122    char *delim2;
00123    char *pattern, *subst, *d;
00124    int res;
00125    int regexp_len, rc;
00126    int size, matchindex; /* size is the size of the backreference sub. */
00127    int d_len = sizeof(tempdst) - 1;
00128    static const int max_bt = 10; /* max num of regexp backreference allowed, must remain 10 to guarantee a valid backreference index */
00129    regex_t preg;
00130    regmatch_t pmatch[max_bt];
00131 
00132    tech_return[0] = '\0';
00133 
00134    dst[0] = '\0';
00135 
00136    if (len < sizeof(struct naptr)) {
00137       ast_log(LOG_WARNING, "NAPTR record length too short\n");
00138       return -1;
00139    }
00140    answer += sizeof(struct naptr);
00141    len -= sizeof(struct naptr);
00142    if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
00143       ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n");
00144       return -1;
00145    } else {
00146       answer += res;
00147       len -= res;
00148    }
00149    if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
00150       ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n");
00151       return -1;
00152    } else {
00153       answer += res;
00154       len -= res;
00155    }
00156    if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) {
00157       ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n");
00158       return -1;
00159    } else {
00160       answer += res;
00161       len -= res;
00162    }
00163 
00164    if ((res = dn_expand(oanswer, answer + len, answer, repl, sizeof(repl) - 1)) < 0) {
00165       ast_log(LOG_WARNING, "Failed to expand hostname\n");
00166       return -1;
00167    }
00168 
00169    ast_debug(3, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
00170       naptrinput, flags, services, regexp, repl);
00171 
00172    if (tolower(flags[0]) != 'u') {
00173       ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
00174       return -1;
00175    }
00176 
00177    p = strstr(services, "e2u+");
00178    if (p == NULL)
00179       p = strstr(services, "E2U+");
00180    if (p){
00181       p = p + 4;
00182       if (strchr(p, ':')){
00183          p = strchr(p, ':') + 1;
00184       }
00185       ast_copy_string(tech_return, p, sizeof(tech_return));
00186    } else {
00187 
00188       p = strstr(services, "+e2u");
00189       if (p == NULL)
00190          p = strstr(services, "+E2U");
00191       if (p) {
00192          *p = 0;
00193          p = strchr(services, ':');
00194          if (p)
00195             *p = 0;
00196          ast_copy_string(tech_return, services, sizeof(tech_return));
00197       }
00198    }
00199 
00200    regexp_len = strlen(regexp);
00201    if (regexp_len < 7) {
00202       ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
00203       return -1;
00204    }
00205 
00206    /* this takes the first character of the regexp (which is a delimiter) 
00207     * and uses that character to find the index of the second delimiter */
00208    delim = regexp[0];
00209    delim2 = strchr(regexp + 1, delim);
00210    if ((delim2 == NULL) || (regexp[regexp_len - 1] != delim)) {  /* is the second delimiter found, and is the end of the regexp a delimiter */
00211       ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00212       return -1;
00213    } else if (strchr((delim2 + 1), delim) == NULL) { /* if the second delimiter is found, make sure there is a third instance.  this could be the end one instead of the middle */
00214       ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n", regexp);
00215       return -1;
00216    }
00217    pattern = regexp + 1;   /* pattern is the regex without the begining and ending delimiter */
00218    *delim2 = 0;    /* zero out the middle delimiter */
00219    subst   = delim2 + 1; /* dst substring is everything after the second delimiter. */
00220    regexp[regexp_len - 1] = 0; /* zero out the last delimiter */
00221 
00222 /*
00223  * now do the regex wizardry.
00224  */
00225 
00226    if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
00227       ast_log(LOG_WARNING, "NAPTR Regex compilation error (regex = \"%s\").\n", regexp);
00228       return -1;
00229    }
00230 
00231    if (preg.re_nsub > ARRAY_LEN(pmatch)) {
00232       ast_log(LOG_WARNING, "NAPTR Regex compilation error: too many subs.\n");
00233       regfree(&preg);
00234       return -1;
00235    }
00236    /* pmatch is an array containing the substring indexes for the regex backreference sub.
00237     * max_bt is the maximum number of backreferences allowed to be stored in pmatch */
00238    if ((rc = regexec(&preg, (char *) naptrinput, max_bt, pmatch, 0))) {
00239       regerror(rc, &preg, errbuff, sizeof(errbuff));
00240       ast_log(LOG_WARNING, "NAPTR Regex match failed. Reason: %s\n", errbuff);
00241       regfree(&preg);
00242       return -1;
00243    }
00244    regfree(&preg);
00245 
00246    d = tempdst;
00247    d_len--;
00248 
00249    /* perform the backreference sub. Search the subst for backreferences,
00250     * when a backreference is found, retrieve the backreferences number.
00251     * use the backreference number as an index for pmatch to retrieve the
00252     * beginning and ending indexes of the substring to insert as the backreference.
00253     * if no backreference is found, continue copying the subst into tempdst */
00254    while (*subst && (d_len > 0)) {
00255       if ((subst[0] == '\\') && isdigit(subst[1])) { /* is this character the beginning of a backreference */
00256          matchindex = (int) (subst[1] - '0');
00257          if (matchindex >= ARRAY_LEN(pmatch)) {
00258             ast_log(LOG_WARNING, "Error during regex substitution. Invalid pmatch index.\n");
00259             return -1;
00260          }
00261          /* pmatch len is 10. we are garanteed a single char 0-9 is a valid index */
00262          size = pmatch[matchindex].rm_eo - pmatch[matchindex].rm_so;
00263          if (size > d_len) {
00264             ast_log(LOG_WARNING, "Not enough space during NAPTR regex substitution.\n");
00265             return -1;
00266          }
00267          /* are the pmatch indexes valid for the input length */
00268          if ((strlen((char *) naptrinput) >= pmatch[matchindex].rm_eo) && (pmatch[matchindex].rm_so <= pmatch[matchindex].rm_eo)) {
00269             memcpy(d, (naptrinput + (int) pmatch[matchindex].rm_so), size);  /* copy input substring into backreference marker */
00270             d_len -= size;
00271             subst += 2;  /* skip over backreference characters to next valid character */
00272             d += size;
00273          } else {
00274             ast_log(LOG_WARNING, "Error during regex substitution. Invalid backreference index.\n");
00275             return -1;
00276          }
00277       } else if (isprint(*subst)) {
00278          *d++ = *subst++;
00279          d_len--;
00280       } else {
00281          ast_log(LOG_WARNING, "Error during regex substitution.\n");
00282          return -1;
00283       }
00284    }
00285    *d = 0;
00286    ast_copy_string((char *) dst, tempdst, dstsize);
00287    dst[dstsize - 1] = '\0';
00288 
00289    if (*tech != '\0'){ /* check if it is requested NAPTR */
00290       if (!strncasecmp(tech, "ALL", techsize)){
00291          return 1; /* return or count any RR */
00292       }
00293       if (!strncasecmp(tech_return, tech, sizeof(tech_return)<techsize?sizeof(tech_return):techsize)){
00294          ast_copy_string(tech, tech_return, techsize);
00295          return 1; /* we got out RR */
00296       } else { /* go to the next RR in the DNS answer */
00297          return 0;
00298       }
00299    }
00300 
00301    /* tech was not specified, return first parsed RR */
00302    ast_copy_string(tech, tech_return, techsize);
00303    return 1;
00304 }
00305 
00306 /* do not return requested value, just count RRs and return thei number in dst */
00307 #define ENUMLOOKUP_OPTIONS_COUNT       1
00308 
00309 
00310 /*! \brief Callback for TXT record lookup */
00311 static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00312 {
00313    struct enum_context *c = (struct enum_context *)context;
00314 
00315    if (answer == NULL) {
00316       c->txt = NULL;
00317       c->txtlen = 0;
00318       return 0;
00319    }
00320 
00321    /* skip over first byte, as for some reason it's a vertical tab character */
00322    answer += 1;
00323    len -= 1;
00324 
00325    /* answer is not null-terminated, but should be */
00326    /* this is safe to do, as answer has extra bytes on the end we can
00327     * safely overwrite with a null */
00328    answer[len] = '\0';
00329    /* now increment len so that len includes the null, so that we can
00330     * compare apples to apples */
00331    len +=1;
00332 
00333    /* finally, copy the answer into c->txt */
00334    ast_copy_string(c->txt, (const char *) answer, len < c->txtlen ? len : (c->txtlen));
00335 
00336    /* just to be safe, let's make sure c->txt is null terminated */
00337    c->txt[(c->txtlen) - 1] = '\0';
00338 
00339    return 1;
00340 }
00341 
00342 /*! \brief Callback from ENUM lookup function */
00343 static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00344 {
00345    struct enum_context *c = context;
00346    void *p = NULL;
00347    int res;
00348 
00349    res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput);
00350 
00351    if (res < 0) {
00352       ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
00353       return -1;
00354    } else if (res > 0 && !ast_strlen_zero(c->dst)){ /* ok, we got needed NAPTR */
00355       if (c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */
00356          c->position++;
00357          snprintf(c->dst, c->dstlen, "%d", c->position);
00358       } else  {
00359          if ((p = ast_realloc(c->naptr_rrs, sizeof(*c->naptr_rrs) * (c->naptr_rrs_count + 1)))) {
00360             c->naptr_rrs = p;
00361             memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(c->naptr_rrs->naptr));
00362             c->naptr_rrs[c->naptr_rrs_count].result = ast_strdup(c->dst);
00363             c->naptr_rrs[c->naptr_rrs_count].tech = ast_strdup(c->tech);
00364             c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count;
00365             c->naptr_rrs_count++;
00366          }
00367          c->dst[0] = 0;
00368       }
00369       return 0;
00370    }
00371 
00372    if (c->options & ENUMLOOKUP_OPTIONS_COUNT)   { /* counting RRs */
00373       snprintf(c->dst, c->dstlen, "%d", c->position);
00374    }
00375 
00376    return 0;
00377 }
00378 
00379 /* ENUM lookup */
00380 int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options, unsigned int record, struct enum_context **argcontext)
00381 {
00382    struct enum_context *context;
00383    char tmp[259 + 512];
00384    char naptrinput[512];
00385    int pos = strlen(number) - 1;
00386    int newpos = 0;
00387    int ret = -1;
00388    struct enum_search *s = NULL;
00389    int version = -1;
00390    /* for ISN rewrite */
00391    char *p1 = NULL;
00392    char *p2 = NULL;
00393    int k = 0;
00394    int i = 0;
00395    int z = 0;
00396 
00397    if (!(context = ast_calloc(1, sizeof(*context))))
00398       return -1;
00399 
00400    ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
00401 
00402    context->naptrinput = naptrinput;   /* The number */
00403    context->dst = dst;        /* Return string */
00404    context->dstlen = dstlen;
00405    context->tech = tech;
00406    context->techlen = techlen;
00407    context->options = 0;
00408    context->position = record;
00409    context->naptr_rrs = NULL;
00410    context->naptr_rrs_count = 0;
00411 
00412    if (options != NULL) {
00413       if (*options == 'c') {
00414          context->options = ENUMLOOKUP_OPTIONS_COUNT;
00415          context->position = 0;
00416       }
00417    }
00418 
00419    ast_debug(1, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
00420          number, tech, suffix, context->options, context->position);
00421 
00422    if (pos > 128)
00423       pos = 128;
00424 
00425    /* ISN rewrite */
00426    p1 = strchr(number, '*');
00427 
00428    if (number[0] == 'n') { /* do not perform ISN rewrite ('n' is testing flag) */
00429       p1 = NULL;
00430       k = 1; /* strip 'n' from number */
00431    }
00432 
00433    if (p1 != NULL) {
00434       p2 = p1 + 1;
00435       while (p1 > number){
00436          p1--;
00437          tmp[newpos++] = *p1;
00438          tmp[newpos++] = '.';
00439       }
00440       if (*p2) {
00441          while (*p2 && newpos < 128){
00442             tmp[newpos++] = *p2;
00443             p2++;
00444          }
00445          tmp[newpos++] = '.';
00446       }
00447 
00448    } else {
00449       while (pos >= k) {
00450          if (isdigit(number[pos])) {
00451             tmp[newpos++] = number[pos];
00452             tmp[newpos++] = '.';
00453          }
00454          pos--;
00455       }
00456    }
00457 
00458    if (chan && ast_autoservice_start(chan) < 0) {
00459       ast_free(context);
00460       return -1;
00461    }
00462 
00463    if (suffix) {
00464       ast_copy_string(tmp + newpos, suffix, sizeof(tmp) - newpos);
00465       ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
00466       ast_debug(1, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
00467    } else {
00468       ret = -1;      /* this is actually dead code since the demise of app_enum.c */
00469       for (;;) {
00470          ast_mutex_lock(&enumlock);
00471          if (version != enumver) {
00472             /* Ooh, a reload... */
00473             s = toplevs;
00474             version = enumver;
00475          } else {
00476             s = s->next;
00477          }
00478          ast_mutex_unlock(&enumlock);
00479 
00480          if (!s)
00481             break;
00482    
00483          ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
00484          ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
00485          ast_debug(1, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
00486          if (ret > 0)
00487             break;
00488       }
00489    }
00490 
00491    if (ret < 0) {
00492       ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
00493       strcpy(dst, "0");
00494       ret = 0;
00495    }
00496 
00497    if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
00498       /* sort array by NAPTR order/preference */
00499       for (k = 0; k < context->naptr_rrs_count; k++) {
00500          for (i = 0; i < context->naptr_rrs_count; i++) {
00501             /* use order first and then preference to compare */
00502             if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
00503                   && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
00504                || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
00505                   && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)){
00506                z = context->naptr_rrs[k].sort_pos;
00507                context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
00508                context->naptr_rrs[i].sort_pos = z;
00509                continue;
00510             }
00511             if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
00512                if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
00513                      && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
00514                   || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
00515                      && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)){
00516                   z = context->naptr_rrs[k].sort_pos;
00517                   context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
00518                   context->naptr_rrs[i].sort_pos = z;
00519                }
00520             }
00521          }
00522       }
00523       for (k = 0; k < context->naptr_rrs_count; k++) {
00524          if (context->naptr_rrs[k].sort_pos == context->position - 1) {
00525             ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
00526             ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
00527             break;
00528          }
00529       }
00530    } else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
00531       context->dst[0] = 0;
00532    }
00533    if (chan)
00534       ret |= ast_autoservice_stop(chan);
00535 
00536    if (!argcontext) {
00537       for (k = 0; k < context->naptr_rrs_count; k++) {
00538          ast_free(context->naptr_rrs[k].result);
00539          ast_free(context->naptr_rrs[k].tech);
00540       }
00541       ast_free(context->naptr_rrs);
00542       ast_free(context);
00543    } else
00544       *argcontext = context;
00545 
00546    return ret;
00547 }
00548 
00549 /* Get TXT record from DNS. Really has nothing to do with enum, but anyway... */
00550 int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen)
00551 {
00552    struct enum_context context;
00553    char tmp[259 + 512];
00554    char naptrinput[512] = "+";
00555    int pos = strlen(number) - 1;
00556    int newpos = 0;
00557    int ret = -1;
00558    struct enum_search *s = NULL;
00559    int version = -1;
00560 
00561    strncat(naptrinput, number, sizeof(naptrinput) - 2);
00562 
00563    context.naptrinput = naptrinput;
00564    context.dst = dst;
00565    context.dstlen = dstlen;
00566    context.tech = tech;
00567    context.techlen = techlen;
00568    context.txt = txt;
00569    context.txtlen = txtlen;
00570 
00571    if (pos > 128)
00572       pos = 128;
00573    while (pos >= 0) {
00574       tmp[newpos++] = number[pos--];
00575       tmp[newpos++] = '.';
00576    }
00577 
00578    if (chan && ast_autoservice_start(chan) < 0)
00579       return -1;
00580 
00581    for (;;) {
00582       ast_mutex_lock(&enumlock);
00583       if (version != enumver) {
00584          /* Ooh, a reload... */
00585          s = toplevs;
00586          version = enumver;
00587       } else {
00588          s = s->next;
00589       }
00590       if (s) {
00591          ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
00592       }
00593       ast_mutex_unlock(&enumlock);
00594       if (!s)
00595          break;
00596 
00597       ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback);
00598       if (ret > 0)
00599          break;
00600    }
00601    if (ret < 0) {
00602       ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
00603       ret = 0;
00604    }
00605    if (chan)
00606       ret |= ast_autoservice_stop(chan);
00607    return ret;
00608 }
00609 
00610 /*! \brief Add enum tree to linked list */
00611 static struct enum_search *enum_newtoplev(const char *s)
00612 {
00613    struct enum_search *tmp;
00614 
00615    if ((tmp = ast_calloc(1, sizeof(*tmp)))) {      
00616       ast_copy_string(tmp->toplev, s, sizeof(tmp->toplev));
00617    }
00618    return tmp;
00619 }
00620 
00621 /*! \brief Initialize the ENUM support subsystem */
00622 static int private_enum_init(int reload)
00623 {
00624    struct ast_config *cfg;
00625    struct enum_search *s, *sl;
00626    struct ast_variable *v;
00627    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00628 
00629    if ((cfg = ast_config_load("enum.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
00630       return 0;
00631 
00632    /* Destroy existing list */
00633    ast_mutex_lock(&enumlock);
00634    s = toplevs;
00635    while (s) {
00636       sl = s;
00637       s = s->next;
00638       ast_free(sl);
00639    }
00640    toplevs = NULL;
00641    if (cfg) {
00642       sl = NULL;
00643       v = ast_variable_browse(cfg, "general");
00644       while (v) {
00645          if (!strcasecmp(v->name, "search")) {
00646             s = enum_newtoplev(v->value);
00647             if (s) {
00648                if (sl)
00649                   sl->next = s;
00650                else
00651                   toplevs = s;
00652                sl = s;
00653             }
00654          }
00655          v = v->next;
00656       }
00657       ast_config_destroy(cfg);
00658    } else {
00659       toplevs = enum_newtoplev(TOPLEV);
00660    }
00661    enumver++;
00662    ast_mutex_unlock(&enumlock);
00663    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n");
00664    return 0;
00665 }
00666 
00667 int ast_enum_init(void)
00668 {
00669    return private_enum_init(0);
00670 }
00671 
00672 int ast_enum_reload(void)
00673 {
00674    return private_enum_init(1);
00675 }

Generated on Wed Oct 28 11:45:37 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6