enum.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * Funding provided by nic.at
  9. *
  10. * See http://www.asterisk.org for more information about
  11. * the Asterisk project. Please do not directly contact
  12. * any of the maintainers of this project for assistance;
  13. * the project provides a web site, mailing lists and IRC
  14. * channels for your use.
  15. *
  16. * This program is free software, distributed under the terms of
  17. * the GNU General Public License Version 2. See the LICENSE file
  18. * at the top of the source tree.
  19. */
  20. /*! \file
  21. *
  22. * \brief ENUM Support for Asterisk
  23. *
  24. */
  25. #include <sys/types.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <arpa/nameser.h>
  29. #if __APPLE_CC__ >= 1495
  30. #include <arpa/nameser_compat.h>
  31. #endif
  32. #include <resolv.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <ctype.h>
  36. #include <regex.h>
  37. #include <unistd.h>
  38. #include <errno.h>
  39. #include "asterisk.h"
  40. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  41. #include "asterisk/logger.h"
  42. #include "asterisk/options.h"
  43. #include "asterisk/enum.h"
  44. #include "asterisk/dns.h"
  45. #include "asterisk/channel.h"
  46. #include "asterisk/config.h"
  47. #include "asterisk/utils.h"
  48. #ifdef __APPLE__
  49. #undef T_NAPTR
  50. #define T_NAPTR 35
  51. #endif
  52. #ifdef __APPLE__
  53. #undef T_TXT
  54. #define T_TXT 16
  55. #endif
  56. /* The IETF Enum standard root, managed by the ITU */
  57. #define TOPLEV "e164.arpa."
  58. /* Linked list from config file */
  59. static struct enum_search {
  60. char toplev[512];
  61. struct enum_search *next;
  62. } *toplevs;
  63. static int enumver = 0;
  64. AST_MUTEX_DEFINE_STATIC(enumlock);
  65. struct naptr {
  66. unsigned short order;
  67. unsigned short pref;
  68. } __attribute__ ((__packed__));
  69. /*--- parse_ie: Parse NAPTR record information elements */
  70. static unsigned int parse_ie(unsigned char *data, unsigned int maxdatalen, unsigned char *src, unsigned int srclen)
  71. {
  72. unsigned int len, olen;
  73. len = olen = (unsigned int) src[0];
  74. src++;
  75. srclen--;
  76. if (len > srclen) {
  77. ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %d characters, got %d\n", len, srclen);
  78. return -1;
  79. }
  80. if (len > maxdatalen)
  81. len = maxdatalen;
  82. memcpy(data, src, len);
  83. return olen + 1;
  84. }
  85. /*--- parse_naptr: Parse DNS NAPTR record used in ENUM ---*/
  86. static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, unsigned char *naptrinput)
  87. {
  88. char tech_return[80];
  89. char *oanswer = answer;
  90. char flags[512] = "";
  91. char services[512] = "";
  92. char *p;
  93. char regexp[512] = "";
  94. char repl[512] = "";
  95. char temp[512] = "";
  96. char delim;
  97. char *delim2;
  98. char *pattern, *subst, *d;
  99. int res;
  100. int regexp_len, size, backref;
  101. int d_len = sizeof(temp) - 1;
  102. regex_t preg;
  103. regmatch_t pmatch[9];
  104. tech_return[0] = '\0';
  105. dst[0] = '\0';
  106. if (len < sizeof(struct naptr)) {
  107. ast_log(LOG_WARNING, "NAPTR record length too short\n");
  108. return -1;
  109. }
  110. answer += sizeof(struct naptr);
  111. len -= sizeof(struct naptr);
  112. if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
  113. ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n");
  114. return -1;
  115. } else {
  116. answer += res;
  117. len -= res;
  118. }
  119. if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
  120. ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n");
  121. return -1;
  122. } else {
  123. answer += res;
  124. len -= res;
  125. }
  126. if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) {
  127. ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n");
  128. return -1;
  129. } else {
  130. answer += res;
  131. len -= res;
  132. }
  133. if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) {
  134. ast_log(LOG_WARNING, "Failed to expand hostname\n");
  135. return -1;
  136. }
  137. if (option_debug > 2) /* Advanced NAPTR debugging */
  138. ast_log(LOG_DEBUG, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
  139. naptrinput, flags, services, regexp, repl);
  140. if (tolower(flags[0]) != 'u') {
  141. ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
  142. return -1;
  143. }
  144. p = strstr(services, "e2u+");
  145. if (p == NULL)
  146. p = strstr(services, "E2U+");
  147. if (p){
  148. p = p + 4;
  149. if (strchr(p, ':')){
  150. p = strchr(p, ':') + 1;
  151. }
  152. ast_copy_string(tech_return, p, sizeof(tech_return));
  153. } else {
  154. p = strstr(services, "+e2u");
  155. if (p == NULL)
  156. p = strstr(services, "+E2U");
  157. if (p) {
  158. *p = 0;
  159. p = strchr(services, ':');
  160. if (p)
  161. *p = 0;
  162. ast_copy_string(tech_return, services, sizeof(tech_return));
  163. }
  164. }
  165. /* DEDBUGGING STUB
  166. ast_copy_string(regexp, "!^\\+43(.*)$!\\1@bla.fasel!", sizeof(regexp) - 1);
  167. */
  168. regexp_len = strlen(regexp);
  169. if (regexp_len < 7) {
  170. ast_log(LOG_WARNING, "Regex too short to be meaningful.\n");
  171. return -1;
  172. }
  173. delim = regexp[0];
  174. delim2 = strchr(regexp + 1, delim);
  175. if ((delim2 == NULL) || (regexp[regexp_len-1] != delim)) {
  176. ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n",regexp);
  177. return -1;
  178. }
  179. pattern = regexp + 1;
  180. *delim2 = 0;
  181. subst = delim2 + 1;
  182. regexp[regexp_len-1] = 0;
  183. /*
  184. * now do the regex wizardry.
  185. */
  186. if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) {
  187. ast_log(LOG_WARNING, "NAPTR Regex compilation error (regex = \"%s\").\n",regexp);
  188. return -1;
  189. }
  190. if (preg.re_nsub > 9) {
  191. ast_log(LOG_WARNING, "NAPTR Regex compilation error: too many subs.\n");
  192. regfree(&preg);
  193. return -1;
  194. }
  195. if (regexec(&preg, naptrinput, 9, pmatch, 0)) {
  196. ast_log(LOG_WARNING, "NAPTR Regex match failed.\n");
  197. regfree(&preg);
  198. return -1;
  199. }
  200. regfree(&preg);
  201. d = temp;
  202. d_len--;
  203. while (*subst && (d_len > 0)) {
  204. if ((subst[0] == '\\') && isdigit(subst[1]) && (pmatch[subst[1]-'0'].rm_so != -1)) {
  205. backref = subst[1]-'0';
  206. size = pmatch[backref].rm_eo - pmatch[backref].rm_so;
  207. if (size > d_len) {
  208. ast_log(LOG_WARNING, "Not enough space during NAPTR regex substitution.\n");
  209. return -1;
  210. }
  211. memcpy(d, naptrinput + pmatch[backref].rm_so, size);
  212. d += size;
  213. d_len -= size;
  214. subst += 2;
  215. } else if (isprint(*subst)) {
  216. *d++ = *subst++;
  217. d_len--;
  218. } else {
  219. ast_log(LOG_WARNING, "Error during regex substitution.\n");
  220. return -1;
  221. }
  222. }
  223. *d = 0;
  224. ast_copy_string(dst, temp, dstsize);
  225. dst[dstsize - 1] = '\0';
  226. if (*tech != '\0'){ /* check if it is requested NAPTR */
  227. if (!strncasecmp(tech, "ALL", techsize)){
  228. return 1; /* return or count any RR */
  229. }
  230. if (!strncasecmp(tech_return, tech, sizeof(tech_return)<techsize?sizeof(tech_return):techsize)){
  231. ast_copy_string(tech, tech_return, techsize);
  232. return 1; /* we got out RR */
  233. } else { /* go to the next RR in the DNS answer */
  234. return 0;
  235. }
  236. }
  237. /* tech was not specified, return first parsed RR */
  238. ast_copy_string(tech, tech_return, techsize);
  239. return 1;
  240. }
  241. /* do not return requested value, just count RRs and return thei number in dst */
  242. #define ENUMLOOKUP_OPTIONS_COUNT 1
  243. struct enum_naptr_rr {
  244. struct naptr naptr; /* order and preference of RR */
  245. char *result; /* result of naptr parsing,e.g.: tel:+5553 */
  246. char *tech; /* Technology (from URL scheme) */
  247. int sort_pos; /* sort position */
  248. };
  249. struct enum_context {
  250. char *dst; /* Destination part of URL from ENUM */
  251. int dstlen; /* Length */
  252. char *tech; /* Technology (from URL scheme) */
  253. int techlen; /* Length */
  254. char *txt; /* TXT record in TXT lookup */
  255. int txtlen; /* Length */
  256. char *naptrinput; /* The number to lookup */
  257. int position; /* used as counter for RRs or specifies position of required RR */
  258. int options; /* options , see ENUMLOOKUP_OPTIONS_* defined above */
  259. struct enum_naptr_rr *naptr_rrs; /* array of parsed NAPTR RRs */
  260. int naptr_rrs_count; /* Size of array naptr_rrs */
  261. };
  262. /*--- txt_callback: Callback for TXT record lookup */
  263. static int txt_callback(void *context, char *answer, int len, char *fullanswer)
  264. {
  265. struct enum_context *c = (struct enum_context *)context;
  266. if (answer == NULL) {
  267. c->txt = NULL;
  268. c->txtlen = 0;
  269. return 0;
  270. }
  271. /* skip over first byte, as for some reason it's a vertical tab character */
  272. answer += 1;
  273. len -= 1;
  274. /* answer is not null-terminated, but should be */
  275. /* this is safe to do, as answer has extra bytes on the end we can
  276. safely overwrite with a null */
  277. answer[len] = '\0';
  278. /* now increment len so that len includes the null, so that we can
  279. compare apples to apples */
  280. len +=1;
  281. /* finally, copy the answer into c->txt */
  282. ast_copy_string(c->txt, answer, len < c->txtlen ? len : (c->txtlen));
  283. /* just to be safe, let's make sure c->txt is null terminated */
  284. c->txt[(c->txtlen)-1] = '\0';
  285. return 1;
  286. }
  287. /*--- enum_callback: Callback from ENUM lookup function */
  288. static int enum_callback(void *context, char *answer, int len, char *fullanswer)
  289. {
  290. struct enum_context *c = (struct enum_context *)context;
  291. void *p = NULL;
  292. int res;
  293. res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput);
  294. if (res < 0) {
  295. ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
  296. return -1;
  297. } else if (res > 0 && !ast_strlen_zero(c->dst)){ /* ok, we got needed NAPTR */
  298. if (c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */
  299. c->position++;
  300. snprintf(c->dst, c->dstlen, "%d", c->position);
  301. } else {
  302. p = realloc(c->naptr_rrs, sizeof(struct enum_naptr_rr)*(c->naptr_rrs_count+1));
  303. if (p) {
  304. c->naptr_rrs = (struct enum_naptr_rr*)p;
  305. memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(struct naptr));
  306. c->naptr_rrs[c->naptr_rrs_count].result = strdup(c->dst);
  307. c->naptr_rrs[c->naptr_rrs_count].tech = strdup(c->tech);
  308. c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count;
  309. c->naptr_rrs_count++;
  310. }
  311. c->dst[0] = 0;
  312. }
  313. return 0;
  314. }
  315. if (c->options & ENUMLOOKUP_OPTIONS_COUNT) { /* counting RRs */
  316. snprintf(c->dst, c->dstlen, "%d", c->position);
  317. }
  318. return 0;
  319. }
  320. /*--- ast_get_enum: ENUM lookup */
  321. int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options)
  322. {
  323. struct enum_context context;
  324. char tmp[259 + 512];
  325. char naptrinput[512];
  326. int pos = strlen(number) - 1;
  327. int newpos = 0;
  328. int ret = -1;
  329. struct enum_search *s = NULL;
  330. int version = -1;
  331. /* for ISN rewrite */
  332. char *p1 = NULL;
  333. char *p2 = NULL;
  334. int k = 0;
  335. int i = 0;
  336. int z = 0;
  337. if (number[0] == 'n') {
  338. strncpy(naptrinput, number+1, sizeof(naptrinput));
  339. } else {
  340. strncpy(naptrinput, number, sizeof(naptrinput));
  341. }
  342. context.naptrinput = naptrinput; /* The number */
  343. context.dst = dst; /* Return string */
  344. context.dstlen = dstlen;
  345. context.tech = tech;
  346. context.techlen = techlen;
  347. context.options = 0;
  348. context.position = 1;
  349. context.naptr_rrs = NULL;
  350. context.naptr_rrs_count = 0;
  351. if (options != NULL){
  352. if (*options == 'c'){
  353. context.options = ENUMLOOKUP_OPTIONS_COUNT;
  354. context.position = 0;
  355. } else {
  356. context.position = atoi(options);
  357. if (context.position < 1)
  358. context.position = 1;
  359. }
  360. }
  361. if (pos > 128)
  362. pos = 128;
  363. /* ISN rewrite */
  364. p1 = strchr(number, '*');
  365. if (number[0] == 'n') { /* do not perform ISN rewrite ('n' is testing flag) */
  366. p1 = NULL;
  367. k = 1; /* strip 'n' from number */
  368. }
  369. if (p1 != NULL) {
  370. p2 = p1+1;
  371. while (p1 > number){
  372. p1--;
  373. tmp[newpos++] = *p1;
  374. tmp[newpos++] = '.';
  375. }
  376. if (*p2) {
  377. while(*p2 && newpos < 128){
  378. tmp[newpos++] = *p2;
  379. p2++;
  380. }
  381. tmp[newpos++] = '.';
  382. }
  383. } else {
  384. while (pos >= k) {
  385. if (isdigit(number[pos])) {
  386. tmp[newpos++] = number[pos];
  387. tmp[newpos++] = '.';
  388. }
  389. pos--;
  390. }
  391. }
  392. if (chan && ast_autoservice_start(chan) < 0)
  393. return -1;
  394. for (;;) {
  395. ast_mutex_lock(&enumlock);
  396. if (version != enumver) {
  397. /* Ooh, a reload... */
  398. s = toplevs;
  399. version = enumver;
  400. } else {
  401. s = s->next;
  402. }
  403. if (suffix != NULL) {
  404. strncpy(tmp + newpos, suffix, sizeof(tmp) - newpos - 1);
  405. } else if (s) {
  406. strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
  407. }
  408. ast_mutex_unlock(&enumlock);
  409. if (!s)
  410. break;
  411. ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
  412. if (ret > 0)
  413. break;
  414. if (suffix != NULL)
  415. break;
  416. }
  417. if (ret < 0) {
  418. ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
  419. ret = 0;
  420. }
  421. if (context.naptr_rrs_count >= context.position && ! (context.options & ENUMLOOKUP_OPTIONS_COUNT)) {
  422. /* sort array by NAPTR order/preference/tech */
  423. for (k = 0; k < context.naptr_rrs_count; k++) {
  424. for (i = 0; i < context.naptr_rrs_count; i++) {
  425. /* Compare by order first. */
  426. if ((ntohs(context.naptr_rrs[k].naptr.order) < ntohs(context.naptr_rrs[i].naptr.order)
  427. && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
  428. || (ntohs(context.naptr_rrs[k].naptr.order) > ntohs(context.naptr_rrs[i].naptr.order)
  429. && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
  430. z = context.naptr_rrs[k].sort_pos;
  431. context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
  432. context.naptr_rrs[i].sort_pos = z;
  433. } else if (ntohs(context.naptr_rrs[k].naptr.order) == ntohs(context.naptr_rrs[i].naptr.order)) {
  434. /* Order is the same, so sort by preference next */
  435. if (ntohs(context.naptr_rrs[k].naptr.pref) == ntohs(context.naptr_rrs[i].naptr.pref)) {
  436. /* Preference is the same, so sort by tech */
  437. if ((strcmp(context.naptr_rrs[k].tech, context.naptr_rrs[i].tech) < 0
  438. && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
  439. || (strcmp(context.naptr_rrs[k].tech, context.naptr_rrs[i].tech) > 0
  440. && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)) {
  441. z = context.naptr_rrs[k].sort_pos;
  442. context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
  443. context.naptr_rrs[i].sort_pos = z;
  444. }
  445. } else if ((ntohs(context.naptr_rrs[k].naptr.pref) < ntohs(context.naptr_rrs[i].naptr.pref)
  446. && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
  447. || (ntohs(context.naptr_rrs[k].naptr.pref) > ntohs(context.naptr_rrs[i].naptr.pref)
  448. && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
  449. z = context.naptr_rrs[k].sort_pos;
  450. context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
  451. context.naptr_rrs[i].sort_pos = z;
  452. }
  453. }
  454. }
  455. }
  456. for (k = 0; k < context.naptr_rrs_count; k++) {
  457. if (context.naptr_rrs[k].sort_pos == context.position - 1) {
  458. ast_copy_string(context.dst, context.naptr_rrs[k].result, dstlen);
  459. ast_copy_string(context.tech, context.naptr_rrs[k].tech, techlen);
  460. break;
  461. }
  462. }
  463. } else if (!(context.options & ENUMLOOKUP_OPTIONS_COUNT)) {
  464. context.dst[0] = 0;
  465. }
  466. if (chan)
  467. ret |= ast_autoservice_stop(chan);
  468. for (k=0; k<context.naptr_rrs_count; k++) {
  469. free(context.naptr_rrs[k].result);
  470. free(context.naptr_rrs[k].tech);
  471. }
  472. free(context.naptr_rrs);
  473. return ret;
  474. }
  475. /*--- ast_get_txt: Get TXT record from DNS.
  476. Really has nothing to do with enum, but anyway...
  477. */
  478. int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen)
  479. {
  480. struct enum_context context;
  481. char tmp[259 + 512];
  482. char naptrinput[512] = "+";
  483. int pos = strlen(number) - 1;
  484. int newpos = 0;
  485. int ret = -1;
  486. struct enum_search *s = NULL;
  487. int version = -1;
  488. strncat(naptrinput, number, sizeof(naptrinput) - 2);
  489. context.naptrinput = naptrinput;
  490. context.dst = dst;
  491. context.dstlen = dstlen;
  492. context.tech = tech;
  493. context.techlen = techlen;
  494. context.txt = txt;
  495. context.txtlen = txtlen;
  496. if (pos > 128)
  497. pos = 128;
  498. while (pos >= 0) {
  499. tmp[newpos++] = number[pos--];
  500. tmp[newpos++] = '.';
  501. }
  502. if (chan && ast_autoservice_start(chan) < 0)
  503. return -1;
  504. for (;;) {
  505. ast_mutex_lock(&enumlock);
  506. if (version != enumver) {
  507. /* Ooh, a reload... */
  508. s = toplevs;
  509. version = enumver;
  510. } else {
  511. s = s->next;
  512. }
  513. if (s) {
  514. strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
  515. }
  516. ast_mutex_unlock(&enumlock);
  517. if (!s)
  518. break;
  519. ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback);
  520. if (ret > 0)
  521. break;
  522. }
  523. if (ret < 0) {
  524. ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
  525. ret = 0;
  526. }
  527. if (chan)
  528. ret |= ast_autoservice_stop(chan);
  529. return ret;
  530. }
  531. /*--- enum_newtoplev: Add enum tree to linked list ---*/
  532. static struct enum_search *enum_newtoplev(char *s)
  533. {
  534. struct enum_search *tmp;
  535. tmp = malloc(sizeof(struct enum_search));
  536. if (tmp) {
  537. memset(tmp, 0, sizeof(struct enum_search));
  538. ast_copy_string(tmp->toplev, s, sizeof(tmp->toplev));
  539. }
  540. return tmp;
  541. }
  542. /*--- ast_enum_init: Initialize the ENUM support subsystem */
  543. int ast_enum_init(void)
  544. {
  545. struct ast_config *cfg;
  546. struct enum_search *s, *sl;
  547. struct ast_variable *v;
  548. /* Destroy existing list */
  549. ast_mutex_lock(&enumlock);
  550. s = toplevs;
  551. while(s) {
  552. sl = s;
  553. s = s->next;
  554. free(sl);
  555. }
  556. toplevs = NULL;
  557. cfg = ast_config_load("enum.conf");
  558. if (cfg) {
  559. sl = NULL;
  560. v = ast_variable_browse(cfg, "general");
  561. while(v) {
  562. if (!strcasecmp(v->name, "search")) {
  563. s = enum_newtoplev(v->value);
  564. if (s) {
  565. if (sl)
  566. sl->next = s;
  567. else
  568. toplevs = s;
  569. sl = s;
  570. }
  571. }
  572. v = v->next;
  573. }
  574. ast_config_destroy(cfg);
  575. } else {
  576. toplevs = enum_newtoplev(TOPLEV);
  577. }
  578. enumver++;
  579. ast_mutex_unlock(&enumlock);
  580. return 0;
  581. }
  582. int ast_enum_reload(void)
  583. {
  584. return ast_enum_init();
  585. }