Index: funcs/func_enum.c
===================================================================
--- funcs/func_enum.c	(revision 93156)
+++ funcs/func_enum.c	(working copy)
@@ -103,11 +103,23 @@
 
 	}
 
+	/* Actually, I don't see the need for it, as get_enum already ignores non-digits. /ol/2k7/01/08 */
+	if (!strchr(args.options, 'd'))
+		for (s = p = args.number; *s; s++) {
+			if (*s != '-') {
+				snprintf(tmp, sizeof(tmp), "%c", *s);
+				strncat(num, tmp, sizeof(num));
+			}
+		}
+	else 
+		ast_copy_string(num, args.number, sizeof(num));
+ 
 	res = ast_get_enum(chan, num, dest, sizeof(dest), tech, sizeof(tech), args.zone,
 			   args.options, record);
+ 	p = strchr(dest, ':');
 
-	p = strchr(dest, ':');
-	if (p && strcasecmp(tech, "ALL"))
+	/* Remove the URI scheme if not searched for ALL and option 'u' isn't specified. */
+	if (p && strcasecmp(tech, "ALL") && !strchr(args.options, 'u'))
 		ast_copy_string(buf, p + 1, len);
 	else
 		ast_copy_string(buf, dest, len);
@@ -127,33 +139,54 @@
 	.desc =
 		"Option 'c' returns an integer count of the number of NAPTRs of a certain RR type.\n"
 		"Combination of 'c' and Method-type of 'ALL' will return a count of all NAPTRs for the record.\n"
+		"Option 'u' returns the full URI and does not strip off the URI-scheme.\n"
+		"Option 's' triggers ISN specific rewriting\n"
+		"Option 'i' looks for branches into an Infrastructure ENUM tree\n"
+		"Option 'd' for a direct DNS lookup without any flipping of digits\n"
 		"Defaults are: Method-type=sip, no options, record=1, zone-suffix=e164.arpa\n\n"
 		"For more information, see doc/enum.txt",
 	.read = function_enum,
 };
 
+static char *txtcid_synopsis = "Syntax: TXTCIDNAME(number[|zone-suffix])\n";
+
 static int function_txtcidname(struct ast_channel *chan, char *cmd,
 			       char *data, char *buf, size_t len)
 {
 	int res;
-	char tech[80];
 	char txt[256] = "";
-	char dest[80];
 	struct ast_module_user *u;
+ 
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(number);
+		AST_APP_ARG(zone);
+	);
 
 	buf[0] = '\0';
 
 
 	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "TXTCIDNAME requires an argument (number)\n");
+		ast_log(LOG_WARNING, txtcid_synopsis);
 		return -1;
 	}
 
 	u = ast_module_user_add(chan);
 
-	res = ast_get_txt(chan, data, dest, sizeof(dest), tech, sizeof(tech), txt,
-			  sizeof(txt));
+	AST_STANDARD_APP_ARGS(args, data);
+ 
+	if (args.argc < 1) {
+		ast_log(LOG_WARNING, txtcid_synopsis);
+		return -1;
+	}
 
+ 	u = ast_module_user_add(chan);
+
+	if (!args.zone)
+		args.zone = "e164.arpa";
+ 
+
+	res = ast_get_txt(chan, args.number, txt, sizeof(txt), args.zone);
+
 	if (!ast_strlen_zero(txt))
 		ast_copy_string(buf, txt, len);
 
@@ -165,11 +198,11 @@
 static struct ast_custom_function txtcidname_function = {
 	.name = "TXTCIDNAME",
 	.synopsis = "TXTCIDNAME looks up a caller name via DNS",
-	.syntax = "TXTCIDNAME(<number>)",
+	.syntax = "TXTCIDNAME(<number>[|zone-suffix])",
 	.desc =
 		"This function looks up the given phone number in DNS to retrieve\n"
 		"the caller id name.  The result will either be blank or be the value\n"
-		"found in the TXT record in DNS.\n",
+		"found in the TXT record in DNS. The default zone-suffix is e164.arpa.\n",
 	.read = function_txtcidname,
 };
 
Index: include/asterisk/enum.h
===================================================================
--- include/asterisk/enum.h	(revision 93156)
+++ include/asterisk/enum.h	(working copy)
@@ -32,10 +32,12 @@
 	\param maxloc	Max length
 	\param technology     Technology (from url scheme in response)
                        You can set it to get particular answer RR, if there are many techs in DNS response, example: "sip"
-                       If you need any record, then set it to empty string
+                        If you need any record, then set it to "ALL" string.
 	\param maxtech  Max length
-	\param suffix   Zone suffix (if is NULL then use enum.conf 'search' variable)
-	\param options  Options ('c' to count number of NAPTR RR)
+	\param suffix   Zone suffix (WARNING: No defaults here any more!)
+	\param options  Options ('c' to count number of NAPTR RR, or number - the position of required RR in the answer list, 
+			'u' for full URI return (do not stript URI scheme), 'i' for Infrastructure ENUM lookup, 's' for ISN
+			based lookup, 'd' for direct DNS query.)
 	\param record   The position of required RR in the answer list
 */
 int ast_get_enum(struct ast_channel *chan, const char *number, char *location, int maxloc, char *technology, 
@@ -44,14 +46,11 @@
 /*!	\brief Lookup DNS TXT record (used by app TXTCIDnum
 	\param chan	Channel
 	\param number   E164 number with or without the leading +
-	\param location	Number returned	(or SIP uri)
-	\param maxloc	Max length of number
-	\param technology 	Technology (not used in TXT records)
-	\param maxtech	Max length
 	\param txt	Text string (return value)
 	\param maxtxt	Max length of "txt"
+	\param suffix   Zone suffix
 */
-int ast_get_txt(struct ast_channel *chan, const char *number, char *location, int maxloc, char *technology, int maxtech, char *txt, int maxtxt);
+int ast_get_txt(struct ast_channel *chan, const char *number, char *txt, int txtlen, char *suffix);
 
 int ast_enum_init(void);
 int ast_enum_reload(void);
Index: main/enum.c
===================================================================
--- main/enum.c	(revision 93156)
+++ main/enum.c	(working copy)
@@ -35,9 +35,14 @@
  * - ENUM SIP: http://www.ietf.org/rfc/rfc3764.txt
  * - IANA ENUM Services: http://www.iana.org/assignments/enum-services
  *
+ * - I-ENUM: 
+ *   http://tools.ietf.org/wg/enum/draft-ietf-enum-combined/
+ *   http://tools.ietf.org/wg/enum/draft-ietf-enum-branch-location-record/
+ *
  * \par Possible improvement
  * \todo Implement a caching mechanism for multile enum lookups
  * - See http://bugs.digium.com/view.php?id=6739
+ * \todo The service type selection needs to be redone.
  */
 
 #include "asterisk.h"
@@ -77,18 +82,344 @@
 #define T_TXT 16
 #endif
 
-#define TOPLEV "e164.arpa."	/*!< The IETF Enum standard root, managed by the ITU */
+static int enum_verbose = 0;
+static char ienum_branchlabel[32] = "i";
+/* how to do infrastructure enum branch location resolution? */
+#define ENUMLOOKUP_BLR_CC       0
+#define ENUMLOOKUP_BLR_TXT      1
+#define ENUMLOOKUP_BLR_EBL      2
+static int ebl_alg = ENUMLOOKUP_BLR_CC;
+ 
+/* EBL record provisional type code */
+#define T_EBL      65300
 
-/* Linked list from config file */
-static struct enum_search {
-	char toplev[512];
-	struct enum_search *next;
-} *toplevs;
+AST_MUTEX_DEFINE_STATIC(enumlock);
 
-static int enumver;
+/*! \brief Determine the length of a country code when given an E.164 string */
+/*
+ * Input: E.164 number w/o leading +
+ *
+ * Output: number of digits in the country code
+ * 	   0 on invalid number
+ *
+ * ALgorithm:
+ *   3 digits is the default length of a country code.
+ *   country codes 1 and 7 are a single digit.
+ *   the following country codes are two digits: 20, 27, 30-34, 36, 39,
+ *     40, 41, 43-49, 51-58, 60-66, 81, 82, 84, 86, 90-95, 98.
+ */
+static int cclen(const char *number)
+{
+	char d1,d2;
 
-AST_MUTEX_DEFINE_STATIC(enumlock);
+	if (!number || (strlen(number) < 3))
+		return(0);
 
+	d1 = number[0];
+	d2 = number[1];
+	
+	if (!isdigit(d2)) 
+		return(0);
+
+	switch(d1) {
+		case '1':
+		case '7':
+			return(1);
+		case '2':
+			if ((d2 == '0') || (d1 == '7'))
+				return(2);
+			break;
+		case '3':
+			if ((d2 >= '0') && (d1 <= '4'))
+				return(2);
+			if ((d2 == '6') || (d1 == '9'))
+				return(2);
+			break;
+		case '4':
+			if (d2 != '2')
+				return(2);
+			break;
+		case '5':
+			if ((d2 >= '1') && (d1 <= '8'))
+				return(2);
+			break;
+		case '6':
+			if (d1 <= '6')
+				return(2);
+			break;
+		case '8':
+			if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6')) 
+				return(2);
+			break;
+		case '9':
+			if (d1 <= '5')
+				return(2);
+			if (d2 == '8')
+				return(2);
+			break;
+		default:
+			return(0);
+	}
+
+	return(3);
+}
+
+
+struct txt_context {
+	char txt[1024];		/* TXT record in TXT lookup */
+	int txtlen;		/* Length */
+};
+
+/*! \brief Callback for TXT record lookup, /ol version */
+static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
+{
+	struct txt_context *c = (struct txt_context *)context;
+	unsigned int i;
+
+	c->txt[0] = 0;	/* default to empty */
+	c->txtlen = 0;
+
+	if (answer == NULL) {
+		return 0;
+	}
+
+	/* RFC1035: 
+	 *
+	 * <character-string> is a single length octet followed by that number of characters.
+	 * TXT-DATA        One or more <character-string>s.
+	 *
+	 * We only take the first string here.
+	 */
+
+	i = *answer++;
+	len -= 1;
+
+	if (i > len) {	/* illegal packet */
+		ast_log(LOG_WARNING, "txt_callback: malformed TXT record.\n");
+		return 0;
+	}
+
+	if (i >= sizeof(c->txt)) {	/* too long? */
+		ast_log(LOG_WARNING, "txt_callback: TXT record too long.\n");
+		i = sizeof(c->txt) - 1;
+	}
+
+	ast_copy_string(c->txt, (char *)answer, i + 1);  /* this handles the \0 termination */
+	c->txtlen = i;
+
+	return 1;
+}
+
+
+/*! \brief Determine the branch location record as stored in a TXT record */
+/*
+ * Input: CC code
+ *
+ * Output: number of digits in the number before the i-enum branch 
+ *
+ * Algorithm:  Build <ienum_branchlabel>.c.c.<suffix> and look for a TXT lookup.
+ * 		Return atoi(TXT-record).
+ * 		Return -1 on not found.
+ *
+ */
+static int blr_txt(const char *cc, const char *suffix)
+{
+	struct txt_context context;
+	char domain[128] = "";
+	char *p1,*p2;
+	int ret;
+
+	ast_mutex_lock(&enumlock);
+
+	if (enum_verbose > 4)
+		ast_verbose(VERBOSE_PREFIX_4 "blr_txt()  cc='%s', suffix='%s', c_bl='%s'\n", 
+					cc, suffix, ienum_branchlabel);
+
+	if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
+		ast_mutex_unlock(&enumlock);
+		ast_log(LOG_WARNING, "ERROR: string sizing in blr_txt.\n");
+		return(-1);
+	}
+
+	strcpy(domain, ienum_branchlabel);
+	p1 = domain + strlen(domain);
+	ast_mutex_unlock(&enumlock);
+
+	*p1++ = '.';
+	*p1   = 0;
+		
+	p2 = (char *) cc + strlen(cc) - 1;
+	while(p2 >= cc) {
+		if (isdigit(*p2)) {
+			*p1++ = *p2;
+			*p1++ = '.';
+		}
+		p2--;
+	}
+	strcat(p1, suffix);
+
+	if (enum_verbose > 4)
+		ast_verbose(VERBOSE_PREFIX_4 "blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);
+
+	ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback);
+	
+	if (ret > 0) {
+		ret = atoi(context.txt);
+
+		if ((ret>=0) && (ret<20)) {
+			if (enum_verbose > 3)
+				ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
+			return(ret);
+		}
+	}
+	
+	if (enum_verbose > 3)
+		ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);
+
+	return(-1);
+}
+
+
+struct ebl_context {
+	unsigned char pos;
+	char separator[256];		/* label to insert */
+	int sep_len;			/* Length */
+	char apex[256];			/* new Apex */
+	int apex_len;			/* Length */
+};
+
+/*! \brief Callback for EBL record lookup */
+static int ebl_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
+{
+	struct ebl_context *c = (struct ebl_context *)context;
+	unsigned int i;
+
+	c->pos = 0;	/* default to empty */
+	c->separator[0] = 0;
+	c->sep_len = 0;
+	c->apex[0] = 0;	
+	c->apex_len = 0;
+
+	if (answer == NULL) {
+		return 0;
+	}
+
+	/* draft-lendl-enum-branch-location-record-00
+	 *
+	 *      0  1  2  3  4  5  6  7
+	 *    +--+--+--+--+--+--+--+--+
+	 *    |       POSITION        |
+	 *    +--+--+--+--+--+--+--+--+
+	 *    /       SEPARATOR       /
+	 *    +--+--+--+--+--+--+--+--+
+	 *    /         APEX          /
+	 *    +--+--+--+--+--+--+--+--+
+	 *
+	 *  where POSITION is a single byte, SEPARATOR is a <character-string>
+	 *  and APEX is a <domain-name>. 
+	 * 
+	 */
+
+	c->pos = *answer++;
+	len -= 1;
+
+	if ((c->pos > 15) || len < 2) {	/* illegal packet */
+		ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
+		return 0;
+	}
+
+	i = *answer++;
+	len -= 1;
+	if (i > len) {	/* illegal packet */
+		ast_log(LOG_WARNING, "ebl_callback: malformed EBL record.\n");
+		return 0;
+	}
+
+	ast_copy_string(c->separator, (char *)answer, i + 1);
+	c->sep_len = i;
+
+	answer += i;
+	len -= i;
+
+	if ((i = dn_expand((unsigned char *)fullanswer, (unsigned char *)answer + len, 
+				(unsigned char *)answer, c->apex, sizeof(c->apex) - 1)) < 0) {
+		ast_log(LOG_WARNING, "Failed to expand hostname\n");
+		return 0;
+	}
+	c->apex[i] = 0;
+	c->apex_len = i;
+
+	return 1;
+}
+
+/*! \brief Evaluate the I-ENUM branch as stored in an EBL record */
+/*
+ * Input: CC code
+ *
+ * Output: number of digits in the number before the i-enum branch 
+ *
+ * Algorithm:  Build <ienum_branchlabel>.c.c.<suffix> and look for an EBL record 
+ * 		Return pos and fill in separator and apex.
+ * 		Return -1 on not found.
+ *
+ */
+static int blr_ebl(const char *cc, const char *suffix, char *separator, int sep_len, char* apex, int apex_len)
+{
+	struct ebl_context context;
+	char domain[128] = "";
+	char *p1,*p2;
+	int ret;
+
+	ast_mutex_lock(&enumlock);
+	
+	if (enum_verbose > 4)
+		ast_verbose(VERBOSE_PREFIX_4 "blr_ebl()  cc='%s', suffix='%s', c_bl='%s'\n", 
+					cc, suffix, ienum_branchlabel);
+
+	if (sizeof(domain) < (strlen(cc) * 2 + strlen(ienum_branchlabel) + strlen(suffix) + 2)) {
+		ast_mutex_unlock(&enumlock);
+		ast_log(LOG_WARNING, "ERROR: string sizing in blr_EBL.\n");
+		return(-1);
+	}
+
+	strcpy(domain, ienum_branchlabel);
+	p1 = domain + strlen(domain);
+	ast_mutex_unlock(&enumlock);
+
+	*p1++ = '.';
+	*p1   = 0;
+		
+	p2 = (char *) cc + strlen(cc) - 1;
+	while(p2 >= cc) {
+		if (isdigit(*p2)) {
+			*p1++ = *p2;
+			*p1++ = '.';
+		}
+		p2--;
+	}
+	strcat(p1, suffix);
+
+	if (enum_verbose > 4)
+		ast_verbose(VERBOSE_PREFIX_4 "blr_ebl() FQDN for EBL record: %s, cc was %s\n", domain, cc);
+
+	ret = ast_search_dns(&context, domain, C_IN, T_EBL, ebl_callback);
+	if (ret > 0) {
+		ret = context.pos;
+
+		if ((ret>=0) && (ret<20)) {
+			if (enum_verbose > 3)
+				ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR EBL record for %s is %d/%s/%s)\n", 
+							cc, ret, context.separator, context.apex);
+			ast_copy_string(separator, context.separator, sep_len);
+			ast_copy_string(apex, context.apex, apex_len);
+			return(ret);
+		}
+	}
+	if (enum_verbose > 3)
+		ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR EBL record for %s not found (apex: %s)\n", cc, suffix);
+	return(-1);
+}
+
 struct naptr {
 	unsigned short order;
 	unsigned short pref;
@@ -116,10 +447,10 @@
 }
 
 /*! \brief Parse DNS NAPTR record used in ENUM ---*/
-static int parse_naptr(char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, char *naptrinput)
+static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len, unsigned char *naptrinput)
 {
 	char tech_return[80];
-	unsigned char *oanswer = answer;
+	char *oanswer = (char *)answer;
 	char flags[512] = "";
 	char services[512] = "";
 	char *p;
@@ -167,7 +498,7 @@
 		len -= res;
 	}
 
-	if ((res = dn_expand(oanswer, answer + len, answer, repl, sizeof(repl) - 1)) < 0) {
+	if ((res = dn_expand((unsigned char *)oanswer, (unsigned char *)answer + len, (unsigned char *)answer, repl, sizeof(repl) - 1)) < 0) {
 		ast_log(LOG_WARNING, "Failed to expand hostname\n");
 		return -1;
 	}
@@ -176,6 +507,10 @@
 		ast_log(LOG_DEBUG, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
 			naptrinput, flags, services, regexp, repl);
 
+	if (enum_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
+			naptrinput, flags, services, regexp, repl);
+			
 	if (tolower(flags[0]) != 'u') {
 		ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
 		return -1;
@@ -227,6 +562,12 @@
 	subst   = delim2 + 1;
 	regexp[regexp_len-1] = 0;
 
+#if 0
+	printf("Pattern: %s\n", pattern);
+	printf("Subst: %s\n", subst);
+       printf("Input: %s\n", naptrinput);
+#endif
+
 /*
  * now do the regex wizardry.
  */
@@ -242,7 +583,7 @@
 		return -1;
 	}
 
-	if (regexec(&preg, naptrinput, 9, pmatch, 0)) {
+	if (regexec(&preg, (char *)naptrinput, 9, pmatch, 0)) {
 		ast_log(LOG_WARNING, "NAPTR Regex match failed.\n");
 		regfree(&preg);
 		return -1;
@@ -272,7 +613,7 @@
 		}
 	}
 	*d = 0;
-	ast_copy_string(dst, temp, dstsize);
+	ast_copy_string((char *)dst, temp, dstsize);
 	dst[dstsize - 1] = '\0';
 
 	if (*tech != '\0'){ /* check if it is requested NAPTR */
@@ -281,7 +622,7 @@
 		}
 		if (!strncasecmp(tech_return, tech, sizeof(tech_return)<techsize?sizeof(tech_return):techsize)){
 			ast_copy_string(tech, tech_return, techsize);
-			return 1; /* we got out RR */
+			return 1; /* we got our RR */
 		} else { /* go to the next RR in the DNS answer */
 			return 0;
 		}
@@ -295,6 +636,12 @@
 
 /* do not return requested value, just count RRs and return thei number in dst */
 #define ENUMLOOKUP_OPTIONS_COUNT       1
+/* do an ISN style lookup */
+#define ENUMLOOKUP_OPTIONS_ISN		2
+/* do a infrastructure ENUM lookup */
+#define ENUMLOOKUP_OPTIONS_IENUM	4
+/* do a direct DNS lookup: no reversal */
+#define ENUMLOOKUP_OPTIONS_DIRECT	8
 
 struct enum_naptr_rr {
 	struct naptr naptr; /* order and preference of RR */
@@ -311,44 +658,13 @@
 	char *txt;	/* TXT record in TXT lookup */
 	int txtlen;	/* Length */
 	char *naptrinput;	/* The number to lookup */
-	int position; /* used as counter for RRs or specifies position of required RR */
+	int position; /* specifies position of required RR */
+	int count; /* used as counter for RRs */
 	int options; /* options , see ENUMLOOKUP_OPTIONS_* defined above */
 	struct enum_naptr_rr *naptr_rrs; /* array of parsed NAPTR RRs */
 	int naptr_rrs_count; /* Size of array naptr_rrs */
 };
 
-/*! \brief Callback for TXT record lookup */
-static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
-{
-	struct enum_context *c = (struct enum_context *)context;
-
-	if (answer == NULL) {
-		c->txt = NULL;
-		c->txtlen = 0;
-		return 0;
-	}
-
-	/* skip over first byte, as for some reason it's a vertical tab character */
-	answer += 1;
-	len -= 1;
-
-	/* answer is not null-terminated, but should be */
-	/* this is safe to do, as answer has extra bytes on the end we can
-	 * safely overwrite with a null */
-	answer[len] = '\0';
-	/* now increment len so that len includes the null, so that we can
-	 * compare apples to apples */
-	len +=1;
-
-	/* finally, copy the answer into c->txt */
-	ast_copy_string(c->txt, (const char *) answer, len < c->txtlen ? len : (c->txtlen));
-
-	/* just to be safe, let's make sure c->txt is null terminated */
-	c->txt[(c->txtlen)-1] = '\0';
-
-	return 1;
-}
-
 /*! \brief Callback from ENUM lookup function */
 static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
 {
@@ -356,15 +672,15 @@
 	void *p = NULL;
 	int res;
 
-	res = parse_naptr(c->dst, c->dstlen, c->tech, c->techlen, answer, len, c->naptrinput);
+	res = parse_naptr((unsigned char *)c->dst, c->dstlen, c->tech, c->techlen, answer, len, (unsigned char *)c->naptrinput);
 
 	if (res < 0) {
 		ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
 		return -1;
 	} else if (res > 0 && !ast_strlen_zero(c->dst)){ /* ok, we got needed NAPTR */
 		if (c->options & ENUMLOOKUP_OPTIONS_COUNT){ /* counting RRs */
-			c->position++;
-			snprintf(c->dst, c->dstlen, "%d", c->position);
+			c->count++;
+			snprintf(c->dst, c->dstlen, "%d", c->count);
 		} else  {
 			if ((p = ast_realloc(c->naptr_rrs, sizeof(*c->naptr_rrs) * (c->naptr_rrs_count + 1)))) {
 				c->naptr_rrs = p;
@@ -380,7 +696,7 @@
 	}
 
 	if (c->options & ENUMLOOKUP_OPTIONS_COUNT) 	{ /* counting RRs */
-		snprintf(c->dst, c->dstlen, "%d", c->position);
+		snprintf(c->dst, c->dstlen, "%d", c->count);
 	}
 
 	return 0;
@@ -390,13 +706,13 @@
 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 context;
-	char tmp[259 + 512];
-	char naptrinput[512];
-	int pos = strlen(number) - 1;
-	int newpos = 0;
+	char tmp[512];
+	char domain[256];
+	char left[128];
+	char middle[128];
+	char naptrinput[128];
+	char apex[128] = "";
 	int ret = -1;
-	struct enum_search *s = NULL;
-	int version = -1;
 	/* for ISN rewrite */
 	char *p1 = NULL;
 	char *p2 = NULL;
@@ -404,6 +720,32 @@
 	int i = 0;
 	int z = 0;
 
+	int spaceleft = 0;
+	struct timeval time_start, time_end;
+ 
+	if (ast_strlen_zero(suffix)) {
+		ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
+		return -1;
+	}
+		
+	if (enum_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "ast_get_enum(num='%s', tech='%s', suffix='%s', options='%s', record=%d\n",
+			number, tech, suffix, options, record);
+
+/*
+  We don't need that any more, that "n" preceding the number has been replaced by a flag
+  in the options paramter.
+	ast_copy_string(naptrinput, number, sizeof(naptrinput));
+*/
+/*
+ * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
+ * We need to preserve that as the regex inside NAPTRs expect the +.
+ *
+ * But for the domain generation, the '+' is a nuissance, so we get rid of it.
+*/
+	if (number[0] == '+')
+		number++;
+	
 	ast_copy_string(naptrinput, number[0] == 'n' ? number+1 : number, sizeof(naptrinput));
 
 	context.naptrinput = naptrinput;	/* The number */
@@ -413,86 +755,197 @@
 	context.techlen = techlen;
 	context.options = 0;
 	context.position = record;
+	context.count = 0;
 	context.naptr_rrs = NULL;
 	context.naptr_rrs_count = 0;
 
-	if (options != NULL) {
-		if (*options == 'c') {
-			context.options = ENUMLOOKUP_OPTIONS_COUNT;
-			context.position = 0;
-		}
+	/*
+	 * Process options:
+	 *
+	 * 	c	Return count, not URI
+	 * 	i	Use infrastructure ENUM 
+	 * 	s	Do ISN transformation
+	 * 	d	Direct DNS query: no reversing.
+	 *
+	 */
+	if (options != NULL){
+		if (strchr(options,'s'))
+			context.options |= ENUMLOOKUP_OPTIONS_ISN;
+		else if (strchr(options,'i'))
+			context.options |= ENUMLOOKUP_OPTIONS_IENUM;
+		else if (strchr(options,'d'))
+			context.options |= ENUMLOOKUP_OPTIONS_DIRECT;
+
+		if (strchr(options,'c'))
+			context.options |= ENUMLOOKUP_OPTIONS_COUNT;
 	}
 
-	ast_log(LOG_DEBUG, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
-			number, tech, suffix, context.options, context.position);
+	if (context.position < 1)	/* 0th place makes no sense */
+		context.position = 1;
+ 
+	if (enum_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "ENUM options(%s): pos=%d, options='%d'\n",
+			options, context.position, context.options);
+ 
+	/*
+	 * This code does more than simple RFC3261 ENUM. All these rewriting 
+	 * schemes have in common that they build the FQDN for the NAPTR lookup
+	 * by concatenating
+	 *    - a number which needs be flipped and "."-seperated 	(left)
+	 *    - some fixed string					(middle)
+	 *    - an Apex.						(apex)
+	 *
+	 * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
+	 * ISN:  number = "middle*left", apex=from args
+	 * I-ENUM: EBL parameters build the split, can change apex
+	 * Direct: left="", middle=argument, apex=from args
+	 *
+	 */
 
-	if (pos > 128)
-		pos = 128;
+	/* default: the whole number will be flipped, no middle domain component */
+	ast_copy_string(left, number, sizeof(left));
+	middle[0] = '\0';
+	/*
+	 * I-ENUM can change the apex, thus we copy it 
+	 */
+	ast_copy_string(apex, suffix, sizeof(apex));
+ 	/* ISN rewrite */
+	if ((context.options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
+		*p1++ = '\0';
+		ast_copy_string(left, number, sizeof(left));
+		ast_copy_string(middle, p1, sizeof(middle)-2);
+		strcat(middle, ".");
+		
+		if (enum_verbose > 1)
+			ast_verbose(VERBOSE_PREFIX_2 "ISN ENUM: left=%s, middle='%s'\n",
+				left, middle);
+	/* Direct DNS lookup rewrite */
+	} else if (context.options & ENUMLOOKUP_OPTIONS_DIRECT) {
+ 
+		left[0] = 0; /* nothing to flip around */
+		ast_copy_string(middle, number, sizeof(middle)-2);
+		strcat(middle, ".");
 
-	/* ISN rewrite */
-	p1 = strchr(number, '*');
+		if (enum_verbose > 1)
+			ast_verbose(VERBOSE_PREFIX_2 "DIRECT ENUM:  middle='%s'\n", middle);
 
-	if (number[0] == 'n') { /* do not perform ISN rewrite ('n' is testing flag) */
-		p1 = NULL;
-		k = 1; /* strip 'n' from number */
-	}
+	/* Infrastructure ENUM rewrite */
+	} else if (context.options & ENUMLOOKUP_OPTIONS_IENUM) {
+		int sdl=0;
+		char cc[8];
+		char sep[256], n_apex[256];
+		int cc_len = cclen(number);
+		sdl = cc_len;
 
-	if (p1 != NULL) {
-		p2 = p1+1;
-		while (p1 > number){
-			p1--;
-			tmp[newpos++] = *p1;
-			tmp[newpos++] = '.';
+		ast_mutex_lock(&enumlock);
+		ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
+		ast_mutex_unlock(&enumlock);
+
+		switch(ebl_alg) {
+			case ENUMLOOKUP_BLR_EBL:
+				strncpy(cc, number, cc_len); /* cclen() never returns more than 3 */
+				cc[cc_len] = 0;
+
+				sdl = blr_ebl(cc, suffix, sep, sizeof(sep)-1, n_apex, sizeof(n_apex)-1);
+
+				if (sdl >= 0) {
+					ast_copy_string(apex, n_apex, sizeof(apex));
+					if (enum_verbose > 1)
+						ast_verbose(VERBOSE_PREFIX_2 "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
+				} else {
+					sdl = cc_len;
+				}
+				break;
+
+			case ENUMLOOKUP_BLR_TXT:
+				strncpy(cc, number, cc_len); /* cclen() never returns more than 3 */
+				cc[cc_len] = 0;
+
+				sdl = blr_txt(cc, suffix);
+
+				if (sdl < 0) 
+					sdl = cc_len;
+				break;
+
+			case ENUMLOOKUP_BLR_CC:	/* BLR is at the country-code level */
+			default:
+				sdl = cc_len;
+				break;
 		}
-		if (*p2) {
-			while(*p2 && newpos < 128){
-				tmp[newpos++] = *p2;
-				p2++;
-			}
-			tmp[newpos++] = '.';
+
+		if (sdl > strlen(number)) {	/* Number too short for this sdl? */
+			ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
+			return 0;
 		}
 
-	} else {
-		while (pos >= k) {
-			if (isdigit(number[pos])) {
-				tmp[newpos++] = number[pos];
-				tmp[newpos++] = '.';
+		ast_copy_string(left, number+sdl, sizeof(left));
+
+		ast_mutex_lock(&enumlock);
+		ast_copy_string(middle, sep, sizeof(middle) - 2);
+		strcat(middle, ".");
+		ast_mutex_unlock(&enumlock);
+
+		/* check the space we need for middle */
+		if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
+			ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
+			return -1;
+		}
+
+		p1 = middle + strlen(middle);
+		p2 = (char *) number + sdl - 1;
+		while(p2 >= number) {
+			if (isdigit(*p2)) {
+				*p1++ = *p2;
+				*p1++ = '.';
 			}
-			pos--;
+			p2--;
 		}
+		*p1 = '\0';
+
+		if (enum_verbose > 1)
+			ast_verbose(VERBOSE_PREFIX_2 "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n",
+				cc_len, left, middle, apex);
+
 	}
 
+	if (strlen(left)*2 + 2 > sizeof(domain)) {
+		ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
+		return -1;
+	}
+
+	/* flip left into domain */
+	p1 = domain;
+	p2 = left + strlen(left);
+	while(p2 >= left) {
+		if (isdigit(*p2)) {
+			*p1++ = *p2;
+			*p1++ = '.';
+		}
+		p2--;
+	}
+	*p1 = '\0';
+
+
 	if (chan && ast_autoservice_start(chan) < 0)
 		return -1;
 
-	if(suffix) {
-		ast_copy_string(tmp + newpos, suffix, sizeof(tmp) - newpos);
-		ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
-		ast_log(LOG_DEBUG, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
-	} else {
-		ret = -1;		/* this is actually dead code since the demise of app_enum.c */
-		for (;;) {
-			ast_mutex_lock(&enumlock);
-			if (version != enumver) {
-				/* Ooh, a reload... */
-				s = toplevs;
-				version = enumver;
-			} else {
-				s = s->next;
-			}
-			ast_mutex_unlock(&enumlock);
+	spaceleft = sizeof(tmp) - 2;
+	ast_copy_string(tmp, domain, spaceleft);
+	spaceleft -= strlen(domain);
 
-			if (!s)
-				break;
-	
-			ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
-			ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
-			ast_log(LOG_DEBUG, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
-			if (ret > 0)
-				break;
-		}
+	if (*middle) {
+		strncat(tmp, middle, spaceleft);
+		spaceleft -= strlen(middle);
 	}
 
+	time_start = ast_tvnow();
+	ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
+	time_end = ast_tvnow();
+
+	if (enum_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "ast_get_enum() profiling: %s, %s, %d ms\n", 
+			(ret>0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));
+
 	if (ret < 0) {
 		ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
 		strcpy(dst, "0");
@@ -549,118 +1002,81 @@
 }
 
 /*! \brief Get TXT record from DNS.
-	Really has nothing to do with enum, but anyway...
- */
-int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen)
+ 	Really has nothing to do with enum, but anyway...
+
+	Actually, there is now an internet-draft which describes how callerID should
+	be stored in ENUM domains: draft-ietf-enum-cnam-04.txt
+
+	The algorithm implemented here will thus be obsolete soon.
+*/
+int ast_get_txt(struct ast_channel *chan, const char *number, char *txt, int txtlen, char *suffix)
 {
-	struct enum_context context;
+	struct txt_context context;
 	char tmp[259 + 512];
-	char naptrinput[512] = "+";
-	int pos = strlen(number) - 1;
+	int pos;
 	int newpos = 0;
 	int ret = -1;
-	struct enum_search *s = NULL;
-	int version = -1;
 
-	strncat(naptrinput, number, sizeof(naptrinput) - 2);
+	ast_log(LOG_DEBUG, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
 
-	context.naptrinput = naptrinput;
-	context.dst = dst;
-	context.dstlen = dstlen;
-	context.tech = tech;
-	context.techlen = techlen;
-	context.txt = txt;
-	context.txtlen = txtlen;
+	if (chan && ast_autoservice_start(chan) < 0)
+		return -1;
+ 
+	pos = strlen(number) - 1;
 
 	if (pos > 128)
 		pos = 128;
 	while (pos >= 0) {
-		tmp[newpos++] = number[pos--];
-		tmp[newpos++] = '.';
+		if (isdigit(number[pos])) {
+			tmp[newpos++] = number[pos];
+			tmp[newpos++] = '.';
+		}
+		pos--;
 	}
 
-	if (chan && ast_autoservice_start(chan) < 0)
-		return -1;
 
-	for (;;) {
-		ast_mutex_lock(&enumlock);
-		if (version != enumver) {
-			/* Ooh, a reload... */
-			s = toplevs;
-			version = enumver;
-		} else {
-			s = s->next;
-		}
-		if (s) {
-			ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
-		}
-		ast_mutex_unlock(&enumlock);
-		if (!s)
-			break;
-
-		ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback);
-		if (ret > 0)
-			break;
-	}
+	ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
+	
 	if (ret < 0) {
 		if (option_debug > 1)
 			ast_log(LOG_DEBUG, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
 		ret = 0;
-	}
+	} else 
+		ast_copy_string(txt, context.txt, txtlen);
+	
 	if (chan)
 		ret |= ast_autoservice_stop(chan);
 	return ret;
 }
 
-/*! \brief Add enum tree to linked list */
-static struct enum_search *enum_newtoplev(char *s)
-{
-	struct enum_search *tmp;
-
-	if ((tmp = ast_calloc(1, sizeof(*tmp)))) {		
-		ast_copy_string(tmp->toplev, s, sizeof(tmp->toplev));
-	}
-	return tmp;
-}
-
 /*! \brief Initialize the ENUM support subsystem */
 int ast_enum_init(void)
 {
 	struct ast_config *cfg;
-	struct enum_search *s, *sl;
-	struct ast_variable *v;
+	const char *string;
 
-	/* Destroy existing list */
 	ast_mutex_lock(&enumlock);
-	s = toplevs;
-	while(s) {
-		sl = s;
-		s = s->next;
-		free(sl);
-	}
-	toplevs = NULL;
+	
 	cfg = ast_config_load("enum.conf");
 	if (cfg) {
-		sl = NULL;
-		v = ast_variable_browse(cfg, "general");
-		while(v) {
-			if (!strcasecmp(v->name, "search")) {
-				s = enum_newtoplev(v->value);
-				if (s) {
-					if (sl)
-						sl->next = s;
-					else
-						toplevs = s;
-					sl = s;
-				}
-			}
-			v = v->next;
+		if ((string=ast_variable_retrieve(cfg, "ienum", "branchlabel"))) {
+			ast_copy_string(ienum_branchlabel, string, sizeof(ienum_branchlabel));
 		}
-		ast_config_destroy(cfg);
-	} else {
-		toplevs = enum_newtoplev(TOPLEV);
+
+		if ((string=ast_variable_retrieve(cfg, "ienum", "ebl_alg"))) {
+			ebl_alg = ENUMLOOKUP_BLR_CC; /* default */
+
+			if (!strcasecmp(string, "txt"))
+				ebl_alg = ENUMLOOKUP_BLR_TXT; 
+			else if (!strcasecmp(string, "ebl"))
+				ebl_alg = ENUMLOOKUP_BLR_EBL; 
+			else if (!strcasecmp(string, "cc"))
+				ebl_alg = ENUMLOOKUP_BLR_CC; 
+			else
+				ast_log(LOG_WARNING, "No valid parameter for ienum/ebl_alg.\n");
+		}
+ 		ast_config_destroy(cfg);
 	}
-	enumver++;
 	ast_mutex_unlock(&enumlock);
 	return 0;
 }
