mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-29 15:36:13 +00:00 
			
		
		
		
	Merge ENUM fixes (bug #99)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1335 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -35,9 +35,12 @@ static char *synopsis = "Lookup number in ENUM"; | |||||||
| static char *descrip =  | static char *descrip =  | ||||||
| "  EnumLookup(exten):  Looks up an extension via ENUM and sets\n" | "  EnumLookup(exten):  Looks up an extension via ENUM and sets\n" | ||||||
| "the variable 'ENUM'.  Returns -1 on hangup, or 0 on completion\n" | "the variable 'ENUM'.  Returns -1 on hangup, or 0 on completion\n" | ||||||
| "regardless of whether the lookup was successful.  If the lookup\n" | "regardless of whether the lookup was successful. Currently, the\n" | ||||||
| "was *not* successful and there exists a priority n + 101, then\n" | "enumservices SIP and TEL are recognized. A good SIP entry\n" | ||||||
| "that priority will be taken next.\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; | STANDARD_LOCAL_USER; | ||||||
|  |  | ||||||
| @@ -49,7 +52,7 @@ static int enumlookup_exec(struct ast_channel *chan, void *data) | |||||||
| 	char tech[80]; | 	char tech[80]; | ||||||
| 	char dest[80]; | 	char dest[80]; | ||||||
| 	char tmp[256]; | 	char tmp[256]; | ||||||
| 	char *c; | 	char *c,*t; | ||||||
| 	struct localuser *u; | 	struct localuser *u; | ||||||
| 	if (!data || !strlen(data)) { | 	if (!data || !strlen(data)) { | ||||||
| 		ast_log(LOG_WARNING, "EnumLookup requires an argument (extension)\n"); | 		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; | 				c += 4; | ||||||
| 			snprintf(tmp, sizeof(tmp), "SIP/%s", c); | 			snprintf(tmp, sizeof(tmp), "SIP/%s", c); | ||||||
| 			pbx_builtin_setvar_helper(chan, "ENUM", tmp); | 			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)) { | 		} else if (strlen(tech)) { | ||||||
| 			ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech); | 			ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech); | ||||||
| 			res = 0; | 			res = 0; | ||||||
|   | |||||||
							
								
								
									
										126
									
								
								enum.c
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								enum.c
									
									
									
									
									
								
							| @@ -21,6 +21,9 @@ | |||||||
| #include <arpa/nameser.h> | #include <arpa/nameser.h> | ||||||
| #include <resolv.h> | #include <resolv.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
|  | #include <ctype.h> | ||||||
|  | #include <regex.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <asterisk/logger.h> | #include <asterisk/logger.h> | ||||||
| #include <asterisk/options.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; | 	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 *oanswer = answer; | ||||||
| 	unsigned char flags[80] = ""; | 	unsigned char flags[80] = ""; | ||||||
| 	unsigned char services[80] = ""; | 	unsigned char services[80] = ""; | ||||||
| 	unsigned char regexp[80] = ""; | 	unsigned char regexp[80] = ""; | ||||||
| 	unsigned char repl[80] = ""; | 	unsigned char repl[80] = ""; | ||||||
|  | 	unsigned char temp[80] = ""; | ||||||
|  | 	unsigned char delim; | ||||||
|  | 	unsigned char *delim2; | ||||||
|  | 	unsigned char *pattern, *subst, *d; | ||||||
| 	int res; | 	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)) { | 	if (len < sizeof(struct naptr)) { | ||||||
| 		printf("Length too short\n"); | 		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"); | 		ast_log(LOG_WARNING, "Failed to expand hostname\n"); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	}  | 	}  | ||||||
|  |  | ||||||
| #if 0 | #if 0 | ||||||
|  | 	printf("Input: %s\n", naptrinput); | ||||||
| 	printf("Flags: %s\n", flags); | 	printf("Flags: %s\n", flags); | ||||||
| 	printf("Services: %s\n", services); | 	printf("Services: %s\n", services); | ||||||
| 	printf("Regexp: %s\n", regexp); | 	printf("Regexp: %s\n", regexp); | ||||||
| 	printf("Repl: %s\n", repl); | 	printf("Repl: %s\n", repl); | ||||||
| #endif | #endif | ||||||
| 	if (!strncmp(regexp, "!^.*$!", 6)) { |  | ||||||
| 		if (!strncmp(services, "E2U+voice:", 10)) { | 	if (tolower(flags[0]) != 'u') { | ||||||
| 			if (regexp[strlen(regexp) - 1] == '!') | 		ast_log(LOG_WARNING, "Flag must be 'U' or 'u'.\n"); | ||||||
| 				regexp[strlen(regexp) - 1] = '\0'; | 		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 | #if 0 | ||||||
| 			printf("Technology: %s\n", services + 10); | 	printf("Pattern: %s\n", pattern); | ||||||
| 			printf("Destination: %s\n", regexp + 6); | 	printf("Subst: %s\n", subst); | ||||||
| #endif | #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; | 	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. | 	 * 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; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 		if ((ntohs(ans->class) == C_IN) && (ntohs(ans->rtype) == T_NAPTR)) { | 		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"); | 				ast_log(LOG_WARNING, "Failed to parse naptr :(\n"); | ||||||
| 			if (strlen(dst)) | 			if (strlen(dst)) | ||||||
| 				return 0; | 				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]; | 	unsigned char answer[MAX_SIZE]; | ||||||
| 	char tmp[259 + 80]; | 	char tmp[259 + 80]; | ||||||
|  | 	char naptrinput[80] = "+"; | ||||||
| 	int pos = strlen(number) - 1; | 	int pos = strlen(number) - 1; | ||||||
| 	int newpos=0; | 	int newpos=0; | ||||||
| 	int res = -1; | 	int res = -1; | ||||||
| @@ -280,6 +375,8 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds | |||||||
| 	if (chan && ast_autoservice_start(chan) < 0) | 	if (chan && ast_autoservice_start(chan) < 0) | ||||||
| 		return -1; | 		return -1; | ||||||
|  |  | ||||||
|  | 	strncat(naptrinput, number, sizeof(naptrinput) - 2); | ||||||
|  |  | ||||||
| 	if (pos > 128) | 	if (pos > 128) | ||||||
| 		pos = 128; | 		pos = 128; | ||||||
| 	while(pos >= 0) { | 	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) { | 		if (version != enumver) { | ||||||
| 			/* Ooh, a reload... */ | 			/* Ooh, a reload... */ | ||||||
| 			s = toplevs; | 			s = toplevs; | ||||||
|  | 			version = enumver; | ||||||
| 		} else { | 		} else { | ||||||
| 			s = s->next; | 			s = s->next; | ||||||
| 		} | 		} | ||||||
| @@ -309,7 +407,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds | |||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| 	if (res > 0) { | 	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); | 			ast_log(LOG_WARNING, "Parse error returned %d\n", res); | ||||||
| 			ret = 0; | 			ret = 0; | ||||||
| 		} else { | 		} else { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user