#include "asterisk.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <regex.h>
#include <unistd.h>
#include <errno.h>
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/enum.h"
#include "asterisk/dns.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Data Structures | |
struct | enum_context |
struct | enum_naptr_rr |
struct | enum_search |
struct | naptr |
Defines | |
#define | ENUMLOOKUP_OPTIONS_COUNT 1 |
#define | TOPLEV "e164.arpa." |
Functions | |
int | ast_enum_init (void) |
Initialize the ENUM support subsystem. | |
int | ast_enum_reload (void) |
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) |
ENUM lookup. | |
int | ast_get_txt (struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen) |
Get TXT record from DNS. Really has nothing to do with enum, but anyway... | |
AST_MUTEX_DEFINE_STATIC (enumlock) | |
static int | enum_callback (void *context, unsigned char *answer, int len, unsigned char *fullanswer) |
Callback from ENUM lookup function. | |
static struct enum_search * | enum_newtoplev (char *s) |
Add enum tree to linked list. | |
static unsigned int | parse_ie (char *data, unsigned int maxdatalen, unsigned char *src, unsigned int srclen) |
Parse NAPTR record information elements. | |
static int | parse_naptr (char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput) |
Parse DNS NAPTR record used in ENUM ---. | |
static int | txt_callback (void *context, unsigned char *answer, int len, unsigned char *fullanswer) |
Callback for TXT record lookup. | |
Variables | |
struct naptr | __packed__ |
static int | enumver |
static struct enum_search * | toplevs |
Definition in file enum.c.
#define ENUMLOOKUP_OPTIONS_COUNT 1 |
#define TOPLEV "e164.arpa." |
The IETF Enum standard root, managed by the ITU
Definition at line 80 of file enum.c.
Referenced by ast_enum_init().
int ast_enum_init | ( | void | ) |
Initialize the ENUM support subsystem.
Definition at line 627 of file enum.c.
Referenced by ast_enum_reload(), and main().
00628 { 00629 struct ast_config *cfg; 00630 struct enum_search *s, *sl; 00631 struct ast_variable *v; 00632 00633 /* Destroy existing list */ 00634 ast_mutex_lock(&enumlock); 00635 s = toplevs; 00636 while(s) { 00637 sl = s; 00638 s = s->next; 00639 free(sl); 00640 } 00641 toplevs = NULL; 00642 cfg = ast_config_load("enum.conf"); 00643 if (cfg) { 00644 sl = NULL; 00645 v = ast_variable_browse(cfg, "general"); 00646 while(v) { 00647 if (!strcasecmp(v->name, "search")) { 00648 s = enum_newtoplev(v->value); 00649 if (s) { 00650 if (sl) 00651 sl->next = s; 00652 else 00653 toplevs = s; 00654 sl = s; 00655 } 00656 } 00657 v = v->next; 00658 } 00659 ast_config_destroy(cfg); 00660 } else { 00661 toplevs = enum_newtoplev(TOPLEV); 00662 } 00663 enumver++; 00664 ast_mutex_unlock(&enumlock); 00665 return 0; 00666 }
int ast_enum_reload | ( | void | ) |
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 | |||
) |
ENUM lookup.
Lookup entry in ENUM Returns 1 if found, 0 if not found, -1 on hangup.
Definition at line 390 of file enum.c.
Referenced by function_enum().
00391 { 00392 struct enum_context context; 00393 char tmp[259 + 512]; 00394 char naptrinput[512]; 00395 int pos = strlen(number) - 1; 00396 int newpos = 0; 00397 int ret = -1; 00398 struct enum_search *s = NULL; 00399 int version = -1; 00400 /* for ISN rewrite */ 00401 char *p1 = NULL; 00402 char *p2 = NULL; 00403 int k = 0; 00404 int i = 0; 00405 int z = 0; 00406 00407 ast_copy_string(naptrinput, number[0] == 'n' ? number+1 : number, sizeof(naptrinput)); 00408 00409 context.naptrinput = naptrinput; /* The number */ 00410 context.dst = dst; /* Return string */ 00411 context.dstlen = dstlen; 00412 context.tech = tech; 00413 context.techlen = techlen; 00414 context.options = 0; 00415 context.position = record; 00416 context.naptr_rrs = NULL; 00417 context.naptr_rrs_count = 0; 00418 00419 if (options != NULL) { 00420 if (*options == 'c') { 00421 context.options = ENUMLOOKUP_OPTIONS_COUNT; 00422 context.position = 0; 00423 } 00424 } 00425 00426 ast_log(LOG_DEBUG, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n", 00427 number, tech, suffix, context.options, context.position); 00428 00429 if (pos > 128) 00430 pos = 128; 00431 00432 /* ISN rewrite */ 00433 p1 = strchr(number, '*'); 00434 00435 if (number[0] == 'n') { /* do not perform ISN rewrite ('n' is testing flag) */ 00436 p1 = NULL; 00437 k = 1; /* strip 'n' from number */ 00438 } 00439 00440 if (p1 != NULL) { 00441 p2 = p1+1; 00442 while (p1 > number){ 00443 p1--; 00444 tmp[newpos++] = *p1; 00445 tmp[newpos++] = '.'; 00446 } 00447 if (*p2) { 00448 while(*p2 && newpos < 128){ 00449 tmp[newpos++] = *p2; 00450 p2++; 00451 } 00452 tmp[newpos++] = '.'; 00453 } 00454 00455 } else { 00456 while (pos >= k) { 00457 if (isdigit(number[pos])) { 00458 tmp[newpos++] = number[pos]; 00459 tmp[newpos++] = '.'; 00460 } 00461 pos--; 00462 } 00463 } 00464 00465 if (chan && ast_autoservice_start(chan) < 0) 00466 return -1; 00467 00468 if(suffix) { 00469 ast_copy_string(tmp + newpos, suffix, sizeof(tmp) - newpos); 00470 ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback); 00471 ast_log(LOG_DEBUG, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret); 00472 } else { 00473 ret = -1; /* this is actually dead code since the demise of app_enum.c */ 00474 for (;;) { 00475 ast_mutex_lock(&enumlock); 00476 if (version != enumver) { 00477 /* Ooh, a reload... */ 00478 s = toplevs; 00479 version = enumver; 00480 } else { 00481 s = s->next; 00482 } 00483 ast_mutex_unlock(&enumlock); 00484 00485 if (!s) 00486 break; 00487 00488 ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos); 00489 ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback); 00490 ast_log(LOG_DEBUG, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret); 00491 if (ret > 0) 00492 break; 00493 } 00494 } 00495 00496 if (ret < 0) { 00497 ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno)); 00498 strcpy(dst, "0"); 00499 ret = 0; 00500 } 00501 00502 if (context.naptr_rrs_count >= context.position && ! (context.options & ENUMLOOKUP_OPTIONS_COUNT)) { 00503 /* sort array by NAPTR order/preference */ 00504 for (k = 0; k < context.naptr_rrs_count; k++) { 00505 for (i = 0; i < context.naptr_rrs_count; i++) { 00506 /* use order first and then preference to compare */ 00507 if ((ntohs(context.naptr_rrs[k].naptr.order) < ntohs(context.naptr_rrs[i].naptr.order) 00508 && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos) 00509 || (ntohs(context.naptr_rrs[k].naptr.order) > ntohs(context.naptr_rrs[i].naptr.order) 00510 && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){ 00511 z = context.naptr_rrs[k].sort_pos; 00512 context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos; 00513 context.naptr_rrs[i].sort_pos = z; 00514 continue; 00515 } 00516 if (ntohs(context.naptr_rrs[k].naptr.order) == ntohs(context.naptr_rrs[i].naptr.order)) { 00517 if ((ntohs(context.naptr_rrs[k].naptr.pref) < ntohs(context.naptr_rrs[i].naptr.pref) 00518 && context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos) 00519 || (ntohs(context.naptr_rrs[k].naptr.pref) > ntohs(context.naptr_rrs[i].naptr.pref) 00520 && context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){ 00521 z = context.naptr_rrs[k].sort_pos; 00522 context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos; 00523 context.naptr_rrs[i].sort_pos = z; 00524 } 00525 } 00526 } 00527 } 00528 for (k = 0; k < context.naptr_rrs_count; k++) { 00529 if (context.naptr_rrs[k].sort_pos == context.position-1) { 00530 ast_copy_string(context.dst, context.naptr_rrs[k].result, dstlen); 00531 ast_copy_string(context.tech, context.naptr_rrs[k].tech, techlen); 00532 break; 00533 } 00534 } 00535 } else if (!(context.options & ENUMLOOKUP_OPTIONS_COUNT)) { 00536 context.dst[0] = 0; 00537 } 00538 if (chan) 00539 ret |= ast_autoservice_stop(chan); 00540 00541 for (k = 0; k < context.naptr_rrs_count; k++) { 00542 free(context.naptr_rrs[k].result); 00543 free(context.naptr_rrs[k].tech); 00544 } 00545 00546 free(context.naptr_rrs); 00547 00548 return ret; 00549 }
int ast_get_txt | ( | struct ast_channel * | chan, | |
const char * | number, | |||
char * | dst, | |||
int | dstlen, | |||
char * | tech, | |||
int | techlen, | |||
char * | txt, | |||
int | txtlen | |||
) |
Get TXT record from DNS. Really has nothing to do with enum, but anyway...
Lookup DNS TXT record (used by app TXTCIDnum.
Definition at line 554 of file enum.c.
Referenced by function_txtcidname().
00555 { 00556 struct enum_context context; 00557 char tmp[259 + 512]; 00558 char naptrinput[512] = "+"; 00559 int pos = strlen(number) - 1; 00560 int newpos = 0; 00561 int ret = -1; 00562 struct enum_search *s = NULL; 00563 int version = -1; 00564 00565 strncat(naptrinput, number, sizeof(naptrinput) - 2); 00566 00567 context.naptrinput = naptrinput; 00568 context.dst = dst; 00569 context.dstlen = dstlen; 00570 context.tech = tech; 00571 context.techlen = techlen; 00572 context.txt = txt; 00573 context.txtlen = txtlen; 00574 00575 if (pos > 128) 00576 pos = 128; 00577 while (pos >= 0) { 00578 tmp[newpos++] = number[pos--]; 00579 tmp[newpos++] = '.'; 00580 } 00581 00582 if (chan && ast_autoservice_start(chan) < 0) 00583 return -1; 00584 00585 for (;;) { 00586 ast_mutex_lock(&enumlock); 00587 if (version != enumver) { 00588 /* Ooh, a reload... */ 00589 s = toplevs; 00590 version = enumver; 00591 } else { 00592 s = s->next; 00593 } 00594 if (s) { 00595 ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos); 00596 } 00597 ast_mutex_unlock(&enumlock); 00598 if (!s) 00599 break; 00600 00601 ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback); 00602 if (ret > 0) 00603 break; 00604 } 00605 if (ret < 0) { 00606 if (option_debug > 1) 00607 ast_log(LOG_DEBUG, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno)); 00608 ret = 0; 00609 } 00610 if (chan) 00611 ret |= ast_autoservice_stop(chan); 00612 return ret; 00613 }
AST_MUTEX_DEFINE_STATIC | ( | enumlock | ) |
static int enum_callback | ( | void * | context, | |
unsigned char * | answer, | |||
int | len, | |||
unsigned char * | fullanswer | |||
) | [static] |
Callback from ENUM lookup function.
Definition at line 353 of file enum.c.
References ast_log(), ast_realloc, ast_strlen_zero(), enum_context::dst, enum_context::dstlen, ENUMLOOKUP_OPTIONS_COUNT, LOG_WARNING, enum_naptr_rr::naptr, enum_context::naptr_rrs, enum_context::naptr_rrs_count, enum_context::naptrinput, enum_context::options, parse_naptr(), enum_context::position, enum_naptr_rr::result, enum_naptr_rr::sort_pos, strdup, enum_naptr_rr::tech, enum_context::tech, and enum_context::techlen.
Referenced by ast_get_enum().
00354 { 00355 struct enum_context *c = context; 00356 void *p = NULL; 00357 int res; 00358 00359 res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput); 00360 00361 if (res < 0) { 00362 ast_log(LOG_WARNING, "Failed to parse naptr :(\n"); 00363 return -1; 00364 } else if (res > 0 && !ast_strlen_zero(c->dst)){ /* ok, we got needed NAPTR */ 00365 if (c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */ 00366 c->position++; 00367 snprintf(c->dst, c->dstlen, "%d", c->position); 00368 } else { 00369 if ((p = ast_realloc(c->naptr_rrs, sizeof(*c->naptr_rrs) * (c->naptr_rrs_count + 1)))) { 00370 c->naptr_rrs = p; 00371 memcpy(&c->naptr_rrs[c->naptr_rrs_count].naptr, answer, sizeof(c->naptr_rrs->naptr)); 00372 c->naptr_rrs[c->naptr_rrs_count].result = strdup(c->dst); 00373 c->naptr_rrs[c->naptr_rrs_count].tech = strdup(c->tech); 00374 c->naptr_rrs[c->naptr_rrs_count].sort_pos = c->naptr_rrs_count; 00375 c->naptr_rrs_count++; 00376 } 00377 c->dst[0] = 0; 00378 } 00379 return 0; 00380 } 00381 00382 if (c->options & ENUMLOOKUP_OPTIONS_COUNT) { /* counting RRs */ 00383 snprintf(c->dst, c->dstlen, "%d", c->position); 00384 } 00385 00386 return 0; 00387 }
static struct enum_search* enum_newtoplev | ( | char * | s | ) | [static, read] |
Add enum tree to linked list.
Definition at line 616 of file enum.c.
References ast_calloc, and enum_search::toplev.
Referenced by ast_enum_init().
00617 { 00618 struct enum_search *tmp; 00619 00620 if ((tmp = ast_calloc(1, sizeof(*tmp)))) { 00621 ast_copy_string(tmp->toplev, s, sizeof(tmp->toplev)); 00622 } 00623 return tmp; 00624 }
static unsigned int parse_ie | ( | char * | data, | |
unsigned int | maxdatalen, | |||
unsigned char * | src, | |||
unsigned int | srclen | |||
) | [static] |
Parse NAPTR record information elements.
Definition at line 98 of file enum.c.
References ast_log(), len, and LOG_WARNING.
Referenced by parse_naptr().
00099 { 00100 unsigned int len, olen; 00101 00102 len = olen = (unsigned int) src[0]; 00103 src++; 00104 srclen--; 00105 00106 if (len > srclen) { 00107 ast_log(LOG_WARNING, "ENUM parsing failed: Wanted %d characters, got %d\n", len, srclen); 00108 return -1; 00109 } 00110 00111 if (len > maxdatalen) 00112 len = maxdatalen; 00113 memcpy(data, src, len); 00114 00115 return olen + 1; 00116 }
static int parse_naptr | ( | char * | dst, | |
int | dstsize, | |||
char * | tech, | |||
int | techsize, | |||
unsigned char * | answer, | |||
int | len, | |||
char * | naptrinput | |||
) | [static] |
Parse DNS NAPTR record used in ENUM ---.
Definition at line 119 of file enum.c.
References ast_log(), LOG_DEBUG, LOG_WARNING, option_debug, and parse_ie().
Referenced by enum_callback().
00120 { 00121 char tech_return[80]; 00122 unsigned char *oanswer = answer; 00123 char flags[512] = ""; 00124 char services[512] = ""; 00125 char *p; 00126 char regexp[512] = ""; 00127 char repl[512] = ""; 00128 char temp[512] = ""; 00129 char delim; 00130 char *delim2; 00131 char *pattern, *subst, *d; 00132 int res; 00133 int regexp_len, size, backref; 00134 int d_len = sizeof(temp) - 1; 00135 regex_t preg; 00136 regmatch_t pmatch[9]; 00137 00138 tech_return[0] = '\0'; 00139 00140 dst[0] = '\0'; 00141 00142 if (len < sizeof(struct naptr)) { 00143 ast_log(LOG_WARNING, "NAPTR record length too short\n"); 00144 return -1; 00145 } 00146 answer += sizeof(struct naptr); 00147 len -= sizeof(struct naptr); 00148 if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) { 00149 ast_log(LOG_WARNING, "Failed to get flags from NAPTR record\n"); 00150 return -1; 00151 } else { 00152 answer += res; 00153 len -= res; 00154 } 00155 if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) { 00156 ast_log(LOG_WARNING, "Failed to get services from NAPTR record\n"); 00157 return -1; 00158 } else { 00159 answer += res; 00160 len -= res; 00161 } 00162 if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0) { 00163 ast_log(LOG_WARNING, "Failed to get regexp from NAPTR record\n"); 00164 return -1; 00165 } else { 00166 answer += res; 00167 len -= res; 00168 } 00169 00170 if ((res = dn_expand(oanswer, answer + len, answer, repl, sizeof(repl) - 1)) < 0) { 00171 ast_log(LOG_WARNING, "Failed to expand hostname\n"); 00172 return -1; 00173 } 00174 00175 if (option_debug > 2) /* Advanced NAPTR debugging */ 00176 ast_log(LOG_DEBUG, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n", 00177 naptrinput, flags, services, regexp, repl); 00178 00179 if (tolower(flags[0]) != 'u') { 00180 ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n"); 00181 return -1; 00182 } 00183 00184 p = strstr(services, "e2u+"); 00185 if (p == NULL) 00186 p = strstr(services, "E2U+"); 00187 if (p){ 00188 p = p + 4; 00189 if (strchr(p, ':')){ 00190 p = strchr(p, ':') + 1; 00191 } 00192 ast_copy_string(tech_return, p, sizeof(tech_return)); 00193 } else { 00194 00195 p = strstr(services, "+e2u"); 00196 if (p == NULL) 00197 p = strstr(services, "+E2U"); 00198 if (p) { 00199 *p = 0; 00200 p = strchr(services, ':'); 00201 if (p) 00202 *p = 0; 00203 ast_copy_string(tech_return, services, sizeof(tech_return)); 00204 } 00205 } 00206 00207 /* DEDBUGGING STUB 00208 ast_copy_string(regexp, "!^\\+43(.*)$!\\1@bla.fasel!", sizeof(regexp) - 1); 00209 */ 00210 00211 regexp_len = strlen(regexp); 00212 if (regexp_len < 7) { 00213 ast_log(LOG_WARNING, "Regex too short to be meaningful.\n"); 00214 return -1; 00215 } 00216 00217 00218 delim = regexp[0]; 00219 delim2 = strchr(regexp + 1, delim); 00220 if ((delim2 == NULL) || (regexp[regexp_len-1] != delim)) { 00221 ast_log(LOG_WARNING, "Regex delimiter error (on \"%s\").\n",regexp); 00222 return -1; 00223 } 00224 00225 pattern = regexp + 1; 00226 *delim2 = 0; 00227 subst = delim2 + 1; 00228 regexp[regexp_len-1] = 0; 00229 00230 /* 00231 * now do the regex wizardry. 00232 */ 00233 00234 if (regcomp(&preg, pattern, REG_EXTENDED | REG_NEWLINE)) { 00235 ast_log(LOG_WARNING, "NAPTR Regex compilation error (regex = \"%s\").\n",regexp); 00236 return -1; 00237 } 00238 00239 if (preg.re_nsub > 9) { 00240 ast_log(LOG_WARNING, "NAPTR Regex compilation error: too many subs.\n"); 00241 regfree(&preg); 00242 return -1; 00243 } 00244 00245 if (regexec(&preg, naptrinput, 9, pmatch, 0)) { 00246 ast_log(LOG_WARNING, "NAPTR Regex match failed.\n"); 00247 regfree(&preg); 00248 return -1; 00249 } 00250 regfree(&preg); 00251 00252 d = temp; 00253 d_len--; 00254 while (*subst && (d_len > 0)) { 00255 if ((subst[0] == '\\') && isdigit(subst[1]) && (pmatch[subst[1]-'0'].rm_so != -1)) { 00256 backref = subst[1]-'0'; 00257 size = pmatch[backref].rm_eo - pmatch[backref].rm_so; 00258 if (size > d_len) { 00259 ast_log(LOG_WARNING, "Not enough space during NAPTR regex substitution.\n"); 00260 return -1; 00261 } 00262 memcpy(d, naptrinput + pmatch[backref].rm_so, size); 00263 d += size; 00264 d_len -= size; 00265 subst += 2; 00266 } else if (isprint(*subst)) { 00267 *d++ = *subst++; 00268 d_len--; 00269 } else { 00270 ast_log(LOG_WARNING, "Error during regex substitution.\n"); 00271 return -1; 00272 } 00273 } 00274 *d = 0; 00275 ast_copy_string(dst, temp, dstsize); 00276 dst[dstsize - 1] = '\0'; 00277 00278 if (*tech != '\0'){ /* check if it is requested NAPTR */ 00279 if (!strncasecmp(tech, "ALL", techsize)){ 00280 return 1; /* return or count any RR */ 00281 } 00282 if (!strncasecmp(tech_return, tech, sizeof(tech_return)<techsize?sizeof(tech_return):techsize)){ 00283 ast_copy_string(tech, tech_return, techsize); 00284 return 1; /* we got out RR */ 00285 } else { /* go to the next RR in the DNS answer */ 00286 return 0; 00287 } 00288 } 00289 00290 /* tech was not specified, return first parsed RR */ 00291 ast_copy_string(tech, tech_return, techsize); 00292 00293 return 1; 00294 }
static int txt_callback | ( | void * | context, | |
unsigned char * | answer, | |||
int | len, | |||
unsigned char * | fullanswer | |||
) | [static] |
Callback for TXT record lookup.
Definition at line 321 of file enum.c.
References enum_context::txt, and enum_context::txtlen.
Referenced by ast_get_txt().
00322 { 00323 struct enum_context *c = (struct enum_context *)context; 00324 00325 if (answer == NULL) { 00326 c->txt = NULL; 00327 c->txtlen = 0; 00328 return 0; 00329 } 00330 00331 /* skip over first byte, as for some reason it's a vertical tab character */ 00332 answer += 1; 00333 len -= 1; 00334 00335 /* answer is not null-terminated, but should be */ 00336 /* this is safe to do, as answer has extra bytes on the end we can 00337 * safely overwrite with a null */ 00338 answer[len] = '\0'; 00339 /* now increment len so that len includes the null, so that we can 00340 * compare apples to apples */ 00341 len +=1; 00342 00343 /* finally, copy the answer into c->txt */ 00344 ast_copy_string(c->txt, (const char *) answer, len < c->txtlen ? len : (c->txtlen)); 00345 00346 /* just to be safe, let's make sure c->txt is null terminated */ 00347 c->txt[(c->txtlen)-1] = '\0'; 00348 00349 return 1; 00350 }
struct naptr __packed__ |
struct enum_search * toplevs [static] |
Referenced by ast_enum_init(), ast_get_enum(), and ast_get_txt().