Index: modules/enum/enum_mod.h
diff -Nau modules/enum/enum_mod.h.orig modules/enum/enum_mod.h
--- modules/enum/enum_mod.h.orig	2010-01-18 15:54:52.842465412 +0100
+++ modules/enum/enum_mod.h	2010-01-18 15:55:20.812190874 +0100
@@ -41,5 +41,7 @@
 extern str i_branchlabel;    /* the label branching off the infrastructure tree */
 extern str i_bl_alg;         /* how to know where to branch off */
 
+extern str isnsuffix;        /* str version of isn_suffix */
+
 
 #endif /* ENUM_MOD_H */
Index: modules/enum/enum_mod.c
diff -Nau modules/enum/enum_mod.c.orig modules/enum/enum_mod.c
--- modules/enum/enum_mod.c.orig	2010-01-18 15:52:57.316263519 +0100
+++ modules/enum/enum_mod.c	2010-01-18 15:52:42.844229824 +0100
@@ -55,6 +55,8 @@
 char* i_enum_suffix = "e164.arpa.";
 char* bl_algorithm = "cc";
 
+char* isn_suffix = "freenum.org.";
+
 
 /*
  * Internal module variables
@@ -67,6 +69,8 @@
 str i_branchlabel;
 str i_bl_alg;
 
+str isnsuffix;
+
 
 /*
  * Exported functions
@@ -94,6 +98,11 @@
 	 REQUEST_ROUTE},
 	{"i_enum_query", (cmd_function)i_enum_query_2, 2, fixup_str_str, 0,
 	 REQUEST_ROUTE},
+	{"isn_query", (cmd_function)isn_query_0, 0, 0, 0, REQUEST_ROUTE},
+	{"isn_query", (cmd_function)isn_query_1, 1, fixup_str_null,
+	 fixup_free_str_null, REQUEST_ROUTE},
+	{"isn_query", (cmd_function)isn_query_2, 2, fixup_str_str, 
+	 fixup_free_str_str, REQUEST_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -107,6 +116,7 @@
 	{"branchlabel", STR_PARAM, &branchlabel},
 	{"i_enum_suffix", STR_PARAM, &i_enum_suffix},
 	{"bl_algorithm", STR_PARAM, &bl_algorithm},
+	{"isn_suffix", STR_PARAM, &isn_suffix},
 	{0, 0, 0}
 };
 
@@ -152,6 +162,9 @@
 	i_bl_alg.s = bl_algorithm;
 	i_bl_alg.len = strlen(bl_algorithm);
 
+	isnsuffix.s = isn_suffix;
+	isnsuffix.len = strlen(isn_suffix.s);
+
 	return 0;
 }
 
Index: modules/enum/enum.h
diff -Nau modules/enum/enum.h.orig modules/enum/enum.h
--- modules/enum/enum.h.orig	2010-01-18 15:54:40.361624448 +0100
+++ modules/enum/enum.h	2010-01-18 15:54:43.090330399 +0100
@@ -66,5 +66,13 @@
 int i_enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2);
 int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service);
 
+/*
+ * Make ISN query and if query succeeds, replace current uri with the
+ * result of the query
+ */
+int isn_query_0(struct sip_msg* _msg, char* _str1, char* _str2);
+int isn_query_1(struct sip_msg* _msg, char* _suffix, char* _str2);
+int isn_query_2(struct sip_msg* _msg, char* _suffix, char* _service);
+
 
 #endif /* ENUM_H */
Index: modules/enum/enum.c
diff -Nau modules/enum/enum.c.orig modules/enum/enum.c
--- modules/enum/enum.c.orig	2010-01-18 15:57:10.995902181 +0100
+++ modules/enum/enum.c	2010-01-18 15:46:19.642209178 +0100
@@ -736,6 +736,84 @@
 }
 
 
+/*
+ * Call isn_query_2 with module parameter suffix and default service.
+ */
+int isn_query_0(struct sip_msg* _msg, char* _str1, char* _str2)
+{
+	return isn_query_2(_msg, (char *)(&isnsuffix), (char *)(&service));
+}
+
+
+/*
+ * Call isn_query_2 with given suffix and default service.
+ */
+int isn_query_1(struct sip_msg* _msg, char* _suffix, char* _str2)
+{
+	return isn_query_2(_msg, _suffix, (char *)(&service));
+}
+
+
+/*
+ * See documentation in README file.
+ */
+int isn_query_2(struct sip_msg* _msg, char* _suffix, char* _service)
+{
+	char *user_s = NULL;
+	int user_len, i, j;
+	char name[MAX_DOMAIN_SIZE] = {0};
+	char string[17] = {0};
+	char szItad[17] = {0};
+	size_t nItlen = 0;
+
+	str *suffix, *service;
+
+	suffix = (str*)_suffix;
+	service = (str*)_service;
+
+	if (parse_sip_msg_uri(_msg) < 0) {
+		LM_ERR("Parsing of R-URI failed\n");
+		return -1;
+	}
+
+	user_s = _msg->parsed_uri.user.s;
+	user_len = _msg->parsed_uri.user.len;
+
+	memcpy(&(string[0]), user_s, user_len);
+	string[user_len] = (char)0;
+
+	/* Do primitive test for correct ISN format, */
+	/* and set szItad to the ISN ITAD (RFC 3872/2871). */
+	/* Correct ISN format guessed from freenum.org and IANA */
+	/* doc http://www.iana.org/assignments/trip-parameters/ */
+	{
+		char *pAster = strchr(string, '*');
+		if (pAster && (nItlen = strspn(pAster + sizeof(char), "0123456789")))
+			strncpy(szItad, pAster + sizeof(char), nItlen);
+		else {
+			LM_ERR("R-URI user does not contain a valid ISN\n");
+			return -1;
+		}
+	}
+
+	/* Ammend the original ENUM E.164 string logic to process */
+	/* ISN numbers instead, which include a nonreversed ITAD. */
+	i = user_len - nItlen - sizeof(char); /* Ex: *1212 */
+	j = 0;
+	while (i--) {
+		name[j] = user_s[i];
+		name[j + 1] = '.';
+		j = j + 2;
+	}
+
+	strcat(name + j, szItad);  /* Copy the unreversed ITAD, */
+	name[j + nItlen] = '.';    /* and append a trailing dot. */
+	memcpy(name + j + nItlen + sizeof(char), suffix->s, suffix->len + 1);
+
+	return do_query(_msg, string, name, service);
+}
+
+
 /*********** INFRASTRUCTURE ENUM ***************/
 
 /*
Index: modules/enum/README
diff -Nau modules/enum/README.orig modules/enum/README
--- modules/enum/README.orig	2010-01-18 17:59:52.034172367 +0100
+++ modules/enum/README	2010-01-18 18:01:30.730633377 +0100
@@ -10,8 +10,8 @@
 
    Copyright © 2002, 2003 Juha Heinanen
    Revision History
-   Revision $Revision: 5906 $ $Date: 2009-07-21 10:45:05 +0300
-                              (Tue, 21 Jul 2009) $
+   Revision $Revision: 5907 $ $Date: 2010-01-18 10:45:05 +0100
+                              (Mon, 18 Jan 2010) $
      __________________________________________________________
 
    Table of Contents
@@ -25,28 +25,32 @@
               1.3.1. domain_suffix (string)
               1.3.2. tel_uri_params (string)
               1.3.3. i_enum_suffix (string)
-              1.3.4. branchlabel (string)
-              1.3.5. bl_algorithm (string)
+              1.3.4. isn_suffix (string)
+              1.3.5. branchlabel (string)
+              1.3.6. bl_algorithm (string)
 
         1.4. Exported Functions
 
               1.4.1. enum_query(["suffix"[,"service"]])
               1.4.2. enum_pv_query("pvar"[,"suffix"[,"service"]])
               1.4.3. i_enum_query(["suffix"[,"service"]])
-              1.4.4. is_from_user_enum()
+              1.4.4. isn_query(["suffix"[,"service"]])
+              1.4.5. is_from_user_enum()
 
    List of Examples
 
    1.1. Setting domain_suffix module parameter
    1.2. Setting tel_uri_params module parameter
    1.3. Setting i_enum_suffix module parameter
-   1.4. Setting brachlabel module parameter
-   1.5. Zone file example
+   1.4. Setting isn_query usage module parameter
+   1.5. Setting branchlabel module parameter
    1.6. Zone file example
-   1.7. Setting the bl_algorithm module parameter
-   1.8. enum_query usage
-   1.9. enum_pv_query usage
-   1.10. is_from_user_enum usage
+   1.7. Zone file example
+   1.8. Setting the bl_algorithm module parameter
+   1.9. enum_query usage
+   1.10. enum_pv_query usage
+   1.11. isn_query usage
+   1.12. is_from_user_enum usage
 
 Chapter 1. Admin Guide
 
@@ -113,6 +117,22 @@
    function does an enum lookup on the from user and returns true
    if found, false otherwise.
 
+   In addition to standard ENUM, support for ISN (ITAD Subscriber
+   Numbers) is provided as well. To allow ISN lookups to resolve,
+   a different formatting algorithm is expected by the DNS server.
+   Whereas a ENUM NAPTR record expects a DNS query of the form
+   9.8.7.6.5.4.3.2.1.<suffix>, ISN method expects a DNS query of
+   the form 6.5.1212.<suffix>. That is, a valid ISN number includes
+   a prefix of '56' in the example. The rest of the number is a
+   ITAD (Internet Telephony Administrative Domain) as defined
+   in RFCs 3872 and 2871, and as allocated by the IANA in
+   http://www.iana.org/assignments/trip-parameters. The ITAD is
+   left intact and not refersed as ENUM requires. To learn more
+   about ISN please refer to documents at www.freenum.org.
+
+   To complete a ISN lookup on the user part of the Request-URI,
+   isn_query() is used instead of enum_query().
+
 1.2. Dependencies
 
    The module depends on the following modules (in the other words
@@ -158,17 +178,27 @@
    Example 1.3. Setting i_enum_suffix module parameter
 modparam("enum", "i_enum_suffix", "e1234.arpa.")
 
-1.3.4. branchlabel (string)
+1.3.4. isn_suffix (string)
+
+   The domain suffix to be used for isn_query() lookups. Can be
+   overridden by a parameter to isn_query.
+
+   Default value is "freenum.org."
+
+   Example 1.4. Setting isn_suffix module parameter
+modparam("enum", "isn_suffix", "freenum.org.")
+
+1.3.5. branchlabel (string)
 
    This parameter determines which label i_enum_query() will use
    to branch off to the infrastructure ENUM tree.
 
    Default value is ""i""
 
-   Example 1.4. Setting brachlabel module parameter
+   Example 1.5. Setting branchlabel module parameter
 modparam("enum", "branchlabel", "i")
 
-1.3.5. bl_algorithm (string)
+1.3.6. bl_algorithm (string)
 
    This parameter determines which algorithm i_enum_query() will
    use to select the position in the DNS tree where the
@@ -182,7 +212,7 @@
    [branchlabel].[reverse-country-code].[i_enum_suffix] to
    indicate after how many digits the label should in inserted.
 
-   Example 1.5. Zone file example
+   Example 1.6. Zone file example
 i.1.e164.arpa.                     IN TXT   "4"
 9.9.9.8.7.6.5.i.4.3.2.1.e164.arpa. IN NAPTR "NAPTR content for  +1 234 5
 678 999"
@@ -196,7 +226,7 @@
    allocated yet. This version of the code uses 65300. See
    resolve.h.
 
-   Example 1.6. Zone file example
+   Example 1.7. Zone file example
 i.1.e164.arpa.     TYPE65300  \# 14 (
                               04    ; position
                               01 69 ; separator
@@ -208,7 +238,7 @@
 
    Default value is "cc"
 
-   Example 1.7. Setting the bl_algorithm module parameter
+   Example 1.8. Setting the bl_algorithm module parameter
 modparam("enum", "bl_algorithm", "txt")
 
 1.4. Exported Functions
@@ -225,7 +255,7 @@
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.8. enum_query usage
+   Example 1.9. enum_query usage
 ...
 # search for "e2u+sip" in freenum.org
 enum_query("freenum.org.");
@@ -262,7 +292,7 @@
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.9. enum_pv_query usage
+   Example 1.10. enum_pv_query usage
 ...
 # search for "e2u+sip" in freenum.org
 enum_pv_query("$avp(i:100)", "freenum.org.");
@@ -296,14 +326,42 @@
    ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-haberle
    r-carrier-enum-01.txt for the rationale behind this function.
 
-1.4.4. is_from_user_enum()
+1.4.4.  isn_query(["suffix"[,"service"]])
+
+   The function performs a ISN query and rewrites the
+   Request-URI with the result of the query. See Section 1.1,
+   "Overview" for more information.
+
+   Meaning of the parameters is as follows:
+     * suffix - Suffix to be appended to the domain name.
+     * service - Service string to be used in the service field.
+
+   This function can be used from REQUEST_ROUTE.
+
+   See ftp://www.ietf.org/rfc/rfc3872.txt and
+   ftp://www.ietf.org/rfc/rfc2871.txt for information
+   regarding the ITAD part of the ISN string.
+
+   Example 1.11. isn_query usage
+...
+# search for "e2u+sip" in freenum.org
+isn_query("freenum.org.");
+...
+# search for "e2u+sip" in default tree (configured as parameter)
+enum_query();
+...
+# search for "e2u+voice:sip" in freenum.org
+enum_query("freenum.org.","voice");
+...
+
+1.4.5. is_from_user_enum()
 
    Checks if the user part of from URI is found in an enum lookup.
    Returns 1 if yes and -1 if not.
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.10. is_from_user_enum usage
+   Example 1.12. is_from_user_enum usage
 ...
 if (is_from_user_enum()) {
         ....
Index: modules/enum/doc/enum.xml
diff -Nau modules/enum/doc/enum.xml.orig modules/enum/doc/enum.xml
--- modules/enum/doc/enum.xml.orig	2009-10-16 02:31:52.000000000 +0200
+++ modules/enum/doc/enum.xml	2010-01-18 18:01:15.954172402 +0100
@@ -33,8 +33,8 @@
 	</copyright>
 	<revhistory>
 	    <revision>
-		<revnumber>$Revision: 5901 $</revnumber>
-		<date>$Date: 2009-07-21 10:45:05 +0300 (Tue, 21 Jul 2009) $</date>
+		<revnumber>$Revision: 5907 $</revnumber>
+		<date>$Date: 2010-01-18 10:45:05 +0100 (Mon, 18 Jan 2010) $</date>
 	    </revision>
 	</revhistory>
     </bookinfo>
Index: modules/enum/doc/enum_admin.xml
diff -Nau modules/enum/doc/enum_admin.xml.orig modules/enum/doc/enum_admin.xml
--- modules/enum/doc/enum_admin.xml.orig	2010-01-18 12:33:30.053644000 +0100
+++ modules/enum/doc/enum_admin.xml	2010-01-18 18:14:59.583157910 +0100
@@ -75,6 +75,24 @@
 		and -1 if not.
 	</para>
 	<para>
+		In addition to standard ENUM, support for ISN (ITAD Subscriber
+		Numbers) is provided as well. To allow ISN lookups to resolve,
+		a different formatting algorithm is expected by the DNS server.
+		Whereas a ENUM NAPTR record expects a DNS query of the form
+		9.8.7.6.5.4.3.2.1.<suffix>, ISN method expects a DNS query of
+		the form 6.5.1212.<suffix>. That is, a valid ISN number includes
+		a prefix of '56' in the example. The rest of the number is a
+		ITAD (Internet Telephony Administrative Domain) as defined
+		in RFCs 3872 and 2871, and as allocated by the IANA in
+		http://www.iana.org/assignments/trip-parameters. The ITAD is
+		left intact and not refersed as ENUM requires. To learn more
+		about ISN please refer to documents at www.freenum.org.
+	</para>
+	<para>
+		To complete a ISN lookup on the user part of the Request-URI,
+		isn_query() is used instead of enum_query().
+	</para>
+	<para>
 		Enum module also implements is_from_user_enum function.
 		This function does an enum lookup on the from user and
 		returns true if found, false otherwise.
@@ -153,6 +171,22 @@
                 </example>
         </section>
         <section>
+                <title><varname>isn_suffix</varname> (string)</title>
+                <para>
+                The domain suffix to be used for isn_query() lookups. Can
+                be overridden by a parameter to isn_query.
+                </para>
+                <para>
+                Default value is <quote>freenum.org.</quote>
+                </para>
+                <example>
+                <title>Setting isn_suffix module parameter</title>
+                <programlisting format="linespecific">
+modparam("enum", "isn_suffix", "freenum.org.")
+</programlisting>
+                </example>
+        </section>
+        <section>
                 <title><varname>branchlabel</varname> (string)</title>
                 <para>
                 This parameter determines which label i_enum_query() will use
@@ -162,7 +196,7 @@
                 Default value is <quote>"i"</quote>
                 </para>
                 <example>
-                <title>Setting brachlabel module parameter</title>
+                <title>Setting branchlabel module parameter</title>
                 <programlisting format="linespecific">
 modparam("enum", "branchlabel", "i")
 </programlisting>
@@ -353,6 +387,53 @@
         </section>
 
 	<section>
+		<title>
+		<function moreinfo="none">isn_query(["suffix"[,"service"]])</function>
+		</title>
+		<para>
+		The function performs a ISN query and rewrites the Request-URI with 
+		the result of the query. See <xref linkend="sec-overview"/> for more 
+		information.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>suffix</emphasis> - Suffix to be appended to the 
+			domain name.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>service</emphasis> - Service string to be used in 
+			the service field.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+			This function can be used from REQUEST_ROUTE.
+		</para>
+		<para>
+			See ftp://www.ietf.org/rfc/rfc3872.txt and
+			ftp://www.ietf.org/rfc/rfc2871.txt for information
+			regarding the ITAD part of the ISN string.
+		</para>
+		<example>
+		<title><function moreinfo="none">isn_query</function> usage</title>
+		<programlisting format="linespecific">
+...
+# search for "e2u+sip" in freenum.org 
+isn_query("freenum.org.");
+...
+# search for "e2u+sip" in default tree (configured as parameter)
+isn_query();
+...
+# search for "e2u+voice:sip" in freenum.org
+isn_query("freenum.org.","voice");
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
 		<title><function moreinfo="none">is_from_user_enum()</function></title>
 		<para>
 		Checks if the user part of from <abbrev>URI</abbrev>
