diff --git a/main/enum.c b/main/enum.c index 344ae404d56414ff1febcb3bf4216e99d878f360..12c39e87f1e79ddd00f3c5eae6c1e5a25533c4df 100644 --- a/main/enum.c +++ b/main/enum.c @@ -931,37 +931,88 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds return ret; } +/*! \internal + * \brief Format a phone number as a domain in an ENUM-adjacent way. + * + * Creates a domain name suitable for query by: + * + * 1. Removing non-digits + * 2. Adding a '.' between adjacent digits + * 3. Reversing the string + * 4. Appending the specified suffix (or e164.arpa if none is specified) + */ +static char *format_numeric_domain(const char *number, const char *suffix) +{ + char *buffer, *dst; + size_t suffix_length; + size_t number_length = strlen(number); + const char *src = number + number_length - 1; + + if (!suffix) { + suffix = "e164.arpa"; + } + + suffix_length = strlen(suffix); + + dst = buffer = ast_malloc( + (number_length * 2) /* We need 2 bytes per input digit */ + + suffix_length /* ... plus however long the suffix is */ + + 1 /* ... plus room for the '.' separator */ + + 1 /* ... and room for the \0 byte at the end */); + + if (buffer) { + while (src >= number) { + if (isdigit(*src)) { + *dst++ = *src; + *dst++ = '.'; + } + src--; + } + + /* The length arguments below make sure that the \0 byte is copied into + the final string */ + if (*suffix == '.') { + memcpy(dst, &suffix[1], suffix_length); + } else { + memcpy(dst, suffix, suffix_length + 1); + } + } + + return buffer; +} + int ast_get_txt(struct ast_channel *chan, const char *number, char *txt, int txtlen, char *suffix) { struct txt_context context; - char tmp[259 + 512]; - int pos = strlen(number) - 1; - int newpos = 0; - int ret = -1; + char *domain; + int ret; + int autoservice = 0; ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix); - if (pos > 128) { - pos = 128; + domain = format_numeric_domain(number, suffix); + if (!domain) { + return -1; } - while (pos >= 0) { - if (isdigit(number[pos])) { - tmp[newpos++] = number[pos]; - tmp[newpos++] = '.'; - } - pos--; + if (chan) { + /* DNS might take a while, so service the channel while we're blocked */ + autoservice = !ast_autoservice_start(chan); } - ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos); - - if (ret < 0) { - ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno)); - ret = 0; - } else { + ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback); + if (ret > 0) { ast_copy_string(txt, context.txt, txtlen); + } else { + ast_debug(2, "No such number found in ENUM: %s (%s)\n", domain, strerror(errno)); } - return ret; + + if (autoservice) { + ast_autoservice_stop(chan); + } + + ast_free(domain); + return 0; } /*! \brief Initialize the ENUM support subsystem */