]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
mod_lcr update. MODAPP-340, MODAPP-355
authorRupa Schomaker <rupa@rupa.com>
Sun, 20 Jun 2010 01:08:06 +0000 (20:08 -0500)
committerRupa Schomaker <rupa@rupa.com>
Sun, 20 Jun 2010 01:08:06 +0000 (20:08 -0500)
 arbitrary b-leg vars, limit support, lcr/ endpoint
 custom_sql now is field based rather than position based
 NOTE: custom_sql is incompat with prior version

src/mod/applications/mod_lcr/mod_lcr.c

index 4e85a11d42b46e60c0b7877f153c1dac3e8a8319..0e45be39de9190b55169cad84d05749be39e177e 100755 (executable)
 #define LCR_SYNTAX "lcr <digits> [<lcr profile>] [caller_id] [intrastate] [as xml]"
 #define LCR_ADMIN_SYNTAX "lcr_admin show profiles"
 
-/* SQL Query places */
-/* these now make up a map that describes the location of
-   the field based on name */
-#define LCR_DIGITS_PLACE 0
-#define LCR_CARRIER_PLACE 1
-#define LCR_RATE_PLACE 2
-#define LCR_GW_PREFIX_PLACE 3
-#define LCR_GW_SUFFIX_PLACE 4
-#define LCR_LSTRIP_PLACE 5
-#define LCR_TSTRIP_PLACE 6
-#define LCR_PREFIX_PLACE 7
-#define LCR_SUFFIX_PLACE 8
-#define LCR_CODEC_PLACE 9
-#define LCR_CID_PLACE 10
-#define LCR_USER_RATE_PLACE 11
-
-#define LCR_QUERY_COLS_REQUIRED 9
-#define LCR_QUERY_COLS 12
-
-#define LCR_HEADERS_COUNT 6
+#define LCR_HEADERS_COUNT 7
 
 #define LCR_HEADERS_DIGITS 0
 #define LCR_HEADERS_CARRIER 1
 #define LCR_HEADERS_DIALSTRING 3
 #define LCR_HEADERS_CODEC 4
 #define LCR_HEADERS_CID 5
+#define LCR_HEADERS_LIMIT 6
 
-#define LCR_
 static char headers[LCR_HEADERS_COUNT][32] = {
        "Digit Match",
        "Carrier",
        "Rate",
        "Dialstring",
        "Codec",
-       "CID Regexp"
+       "CID Regexp",
+       "Limit",
 };
 
 /* sql for random function */
@@ -93,6 +75,10 @@ struct lcr_obj {
        size_t digit_len;
        char *codec;
        char *cid;
+       char *limit_realm;
+       char *limit_id;
+       int limit_max;
+       switch_event_t *fields;
        struct lcr_obj *prev;
        struct lcr_obj *next;
 };
@@ -104,6 +90,7 @@ struct max_obj {
        size_t codec;
        size_t cid;
        size_t dialstring;
+       size_t limit;
 };
 
 typedef struct lcr_obj lcr_obj_t;
@@ -117,12 +104,16 @@ struct profile_obj {
        uint16_t id;
        char *order_by;
        char *custom_sql;
+       char *export_fields_str;
+       int export_fields_cnt;
+       char **export_fields;
+       char *limit_type;
        switch_bool_t custom_sql_has_percent;
        switch_bool_t custom_sql_has_vars;
        switch_bool_t profile_has_intrastate;
        switch_bool_t profile_has_intralata;
        switch_bool_t profile_has_npanxx;
-
+       
        switch_bool_t reorder_by_rate;
        switch_bool_t quote_in_list;
        switch_bool_t info_in_headers;
@@ -174,21 +165,21 @@ static const char *do_cid(switch_memory_pool_t *pool, const char *cid, const cha
        char *src_regex = NULL;
        char *dst_regex = NULL;
        switch_channel_t *channel = NULL;
-
+       
        if (!zstr(cid)) {
                len = strlen(cid);
        } else {
                goto done;
        }
-
+       
        src = switch_core_strdup(pool, cid);
        /* check that this is a valid regexp and split the string */
-
-       if ((src[0] == '/') && src[len - 1] == '/') {
+       
+       if ((src[0] == '/') && src[len-1] == '/') {
                /* strip leading / trailing slashes */
-               src[len - 1] = '\0';
+               src[len-1] = '\0';
                src++;
-
+               
                /* break on first / */
                dst = strchr(src, '/');
                *dst = '\0';
@@ -217,12 +208,12 @@ static const char *do_cid(switch_memory_pool_t *pool, const char *cid, const cha
                        switch_safe_free(tmp_regex);
                        dst = dst_regex;
                }
-
+                       
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "expanded src: %s, dst: %s\n", src, dst);
        }
-
+  
        if ((proceed = switch_regex_perform(number, src, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
-               len = (uint32_t) (strlen(src) + strlen(dst) + 10) * proceed;    /* guestimate size */
+               len = (uint32_t) (strlen(src) + strlen(dst) + 10) * proceed; /* guestimate size */
                if (!(substituted = switch_core_alloc(pool, len))) {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Memory Error!\n");
                        goto done;
@@ -234,74 +225,101 @@ static const char *do_cid(switch_memory_pool_t *pool, const char *cid, const cha
        }
 
        switch_regex_safe_free(re);
-
+       
        return substituted;
-
-  done:
+       
+done:
        switch_regex_safe_free(re);
        return number;
 }
 
-static char *get_bridge_data(switch_memory_pool_t *pool, char *dialed_number, char *caller_id, lcr_route cur_route, profile_t *profile,
-                                                        switch_core_session_t *session)
+static char *get_bridge_data(switch_memory_pool_t *pool, char *dialed_number, char *caller_id, lcr_route cur_route, profile_t *profile, switch_core_session_t *session)
 {
        size_t lstrip;
-       size_t tstrip;
+       size_t  tstrip;
        char *data = NULL;
        char *destination_number = NULL;
-       char *orig_destination_number = NULL;
+       char *orig_destination_number = NULL; 
        char *codec = NULL;
        char *cid = NULL;
        char *header = NULL;
        char *user_rate = NULL;
+       char *export_fields = NULL;
 
        orig_destination_number = destination_number = switch_core_strdup(pool, dialed_number);
-
+       
        tstrip = ((cur_route->digit_len - cur_route->tstrip) + 1);
        lstrip = cur_route->lstrip;
-
+       
        if (cur_route->tstrip > 0) {
                if (strlen(destination_number) > tstrip) {
                        destination_number[tstrip] = '\0';
-               } else {
-                       destination_number[0] = '\0';
                }
-       }
+               else {
+                       destination_number[0] = '\0';
+                              }
+    }
        if (cur_route->lstrip > 0) {
                if (strlen(destination_number) > lstrip) {
                        destination_number += lstrip;
-               } else {
+               }
+               else {
                        destination_number[0] = '\0';
                }
-       }
+       }       
        codec = "";
        if (!zstr(cur_route->codec)) {
                codec = switch_core_sprintf(pool, ",absolute_codec_string=%s", cur_route->codec);
        }
-
+       
        cid = "";
        if (!zstr(cur_route->cid)) {
-               cid = switch_core_sprintf(pool, ",origination_caller_id_number=%s", do_cid(pool, cur_route->cid, caller_id, session));
+               cid = switch_core_sprintf(pool, ",origination_caller_id_number=%s", 
+                                                                 do_cid(pool, cur_route->cid, caller_id, session));
        }
-
+       
        header = "";
        if (profile->info_in_headers) {
-               header = switch_core_sprintf(pool, ",sip_h_X-LCR-INFO=lcr_rate=%s;lcr_carrier=%s", cur_route->rate_str, cur_route->carrier_name);
+               header = switch_core_sprintf(pool, ",sip_h_X-LCR-INFO=lcr_rate=%s;lcr_carrier=%s",
+                                                                         cur_route->rate_str, 
+                                                                         cur_route->carrier_name);
        }
-
+       
        if (zstr(cur_route->user_rate_str)) {
                user_rate = "";
        } else {
                user_rate = switch_core_sprintf(pool, ",lcr_user_rate=%s", cur_route->user_rate_str);
        }
-
+       
+       export_fields = "";
+       if (profile->export_fields_cnt > 0) {
+               int i = 0;
+               char *val = NULL;
+               for (i = 0; i < profile->export_fields_cnt; i++) {
+                       val = switch_event_get_header(cur_route->fields, profile->export_fields[i]);
+                       if (val) {
+                               export_fields = switch_core_sprintf(pool, "%s,%s=%s", 
+                                                                                                       export_fields,
+                                                                                                       profile->export_fields[i], 
+                                                                                                       val);
+                       }
+               }
+       }
+       
        if (profile->enable_sip_redir) {
-               data =
-                       switch_core_sprintf(pool, "%s%s%s%s%s", cur_route->gw_prefix, cur_route->prefix, destination_number, cur_route->suffix, cur_route->gw_suffix);
+               data = switch_core_sprintf(pool, "%s%s%s%s%s"
+                                                                       , cur_route->gw_prefix, cur_route->prefix
+                                                                       , destination_number, cur_route->suffix, cur_route->gw_suffix);
        } else {
-               data =
-                       switch_core_sprintf(pool, "[lcr_carrier=%s,lcr_rate=%s%s%s%s%s]%s%s%s%s%s", cur_route->carrier_name, cur_route->rate_str, user_rate, codec, cid,
-                                                               header, cur_route->gw_prefix, cur_route->prefix, destination_number, cur_route->suffix, cur_route->gw_suffix);
+               data = switch_core_sprintf(pool, "[lcr_carrier=%s,lcr_rate=%s%s%s%s%s%s]%s%s%s%s%s"
+                                                                       , cur_route->carrier_name, cur_route->rate_str
+                                                                       , user_rate, codec, cid, header, export_fields
+                                                                       , cur_route->gw_prefix, cur_route->prefix
+                                                                       , destination_number, cur_route->suffix, cur_route->gw_suffix);
+       }
+                       
+       if (session && (switch_string_var_check_const(data) || switch_string_has_escaped_data(data))) {
+               data = switch_channel_expand_variables(switch_core_session_get_channel(session), data);
        }
 
        if (session && (switch_string_var_check_const(data) || switch_string_has_escaped_data(data))) {
@@ -315,13 +333,13 @@ static char *get_bridge_data(switch_memory_pool_t *pool, char *dialed_number, ch
 static profile_t *locate_profile(const char *profile_name)
 {
        profile_t *profile = NULL;
-
+       
        if (zstr(profile_name)) {
                profile = globals.default_profile;
        } else if (!(profile = switch_core_hash_find(globals.profile_hash, profile_name))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error invalid profile %s\n", profile_name);
        }
-
+       
        return profile;
 }
 
@@ -334,6 +352,7 @@ static void init_max_lens(max_len maxes)
        maxes->rate = 8;
        maxes->codec = (headers[LCR_HEADERS_CODEC] == NULL ? 0 : strlen(headers[LCR_HEADERS_CODEC]));
        maxes->cid = (headers[LCR_HEADERS_CID] == NULL ? 0 : strlen(headers[LCR_HEADERS_CID]));
+       maxes->limit = (headers[LCR_HEADERS_LIMIT] == NULL ? 0 : strlen(headers[LCR_HEADERS_LIMIT]));
 }
 
 static switch_status_t process_max_lengths(max_obj_t *maxes, lcr_route routes, char *destination_number)
@@ -354,41 +373,48 @@ static switch_status_t process_max_lengths(max_obj_t *maxes, lcr_route routes, c
        for (current = routes; current; current = current->next) {
                size_t this_len;
 
-               if (current->carrier_name != NULL) {
+               if (current->carrier_name) {
                        this_len = strlen(current->carrier_name);
                        if (this_len > maxes->carrier_name) {
                                maxes->carrier_name = this_len;
                        }
                }
-               if (current->dialstring != NULL) {
+               if (current->dialstring) {
                        this_len = strlen(current->dialstring);
                        if (this_len > maxes->dialstring) {
                                maxes->dialstring = this_len;
                        }
                }
-               if (current->digit_str != NULL) {
+               if (current->digit_str) {
                        if (current->digit_len > maxes->digit_str) {
                                maxes->digit_str = current->digit_len;
-                       }
+                       } 
                }
-               if (current->rate_str != NULL) {
+               if (current->rate_str) {
                        this_len = strlen(current->rate_str);
                        if (this_len > maxes->rate) {
                                maxes->rate = this_len;
                        }
                }
-               if (current->codec != NULL) {
-                       this_len = strlen(current->codec);
+               if (current->codec) {
+                       this_len= strlen(current->codec);
                        if (this_len > maxes->codec) {
                                maxes->codec = this_len;
                        }
                }
-               if (current->cid != NULL) {
+               if (current->cid) {
                        this_len = strlen(current->cid);
                        if (this_len > maxes->cid) {
                                maxes->cid = this_len;
                        }
                }
+
+               if (current->limit_realm && current->limit_id) {
+                       this_len = strlen(current->limit_realm) + strlen(current->limit_id) + 5;
+                       if (this_len > maxes->limit) {
+                               maxes->limit = this_len;
+                       }
+               }
        }
        return SWITCH_STATUS_SUCCESS;
 }
@@ -397,14 +423,13 @@ static switch_cache_db_handle_t *lcr_get_db_handle(void)
 {
        switch_cache_db_connection_options_t options = { {0} };
        switch_cache_db_handle_t *dbh = NULL;
-
+       
        if (!zstr(globals.odbc_dsn)) {
                options.odbc_options.dsn = globals.odbc_dsn;
                options.odbc_options.user = globals.odbc_user;
                options.odbc_options.pass = globals.odbc_pass;
 
-               if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
-                       dbh = NULL;
+               if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS) dbh = NULL;
        }
        return dbh;
 }
@@ -435,23 +460,23 @@ static switch_bool_t set_db_random()
                db_random = "random()";
                return SWITCH_TRUE;
        }
-
+       
        return SWITCH_FALSE;
 }
 
 /* make a new string with digits only */
-static char *string_digitsonly(switch_memory_pool_t *pool, const char *str)
+static char *string_digitsonly(switch_memory_pool_t *pool, const char *str) 
 {
        char *p, *np, *newstr;
        size_t len;
 
-       p = (char *) str;
+       p = (char *)str;
 
        len = strlen(str);
-       newstr = switch_core_alloc(pool, len + 1);
+       newstr = switch_core_alloc(pool, len+1);
        np = newstr;
-
-       while (*p) {
+       
+       while(*p) {
                if (switch_isdigit(*p)) {
                        *np = *p;
                        np++;
@@ -483,10 +508,14 @@ static char *expand_digits(switch_memory_pool_t *pool, char *digits, switch_bool
 
        digit_len = strlen(digits);
        digits_copy = switch_core_strdup(pool, digits);
-
+       
        for (n = digit_len; n > 0; n--) {
                digits_copy[n] = '\0';
-               dig_stream.write_function(&dig_stream, "%s%s%s%s", (n == digit_len ? "" : ", "), (quote ? "'" : ""), digits_copy, (quote ? "'" : ""));
+               dig_stream.write_function(&dig_stream, "%s%s%s%s", 
+                                                                       (n==digit_len ? "" : ", "), 
+                                                                       (quote ? "'" : ""),
+                                                                       digits_copy,
+                                                                       (quote ? "'" : ""));
        }
 
        ret = switch_core_strdup(pool, dig_stream.data);
@@ -497,41 +526,42 @@ static char *expand_digits(switch_memory_pool_t *pool, char *digits, switch_bool
 /* format the custom sql */
 static char *format_custom_sql(const char *custom_sql, callback_t *cb_struct, const char *digits)
 {
-       char *tmpSQL = NULL;
-       char *newSQL = NULL;
+       char * tmpSQL = NULL;
+       char * newSQL = NULL;
        switch_channel_t *channel;
-
+       
        /* first replace %s with digits to maintain backward compat */
        if (cb_struct->profile->custom_sql_has_percent == SWITCH_TRUE) {
                tmpSQL = switch_string_replace(custom_sql, "%q", digits);
                newSQL = tmpSQL;
        }
-
+       
        /* expand the vars */
        if (cb_struct->profile->custom_sql_has_vars == SWITCH_TRUE) {
                if (cb_struct->session) {
                        channel = switch_core_session_get_channel(cb_struct->session);
                        switch_assert(channel);
                        /*
-                          newSQL = switch_channel_expand_variables_escape(channel, 
-                          tmpSQL ? tmpSQL : custom_sql,
-                          escape_sql);
-                        */
-                       newSQL = switch_channel_expand_variables(channel, tmpSQL ? tmpSQL : custom_sql);
+                       newSQL = switch_channel_expand_variables_escape(channel, 
+                                                                                                                       tmpSQL ? tmpSQL : custom_sql,
+                                                                                                                       escape_sql);
+                       */
+                       newSQL = switch_channel_expand_variables(channel, 
+                                                                                                               tmpSQL ? tmpSQL : custom_sql);
                } else if (cb_struct->event) {
                        /* use event system to expand vars */
                        newSQL = switch_event_expand_headers(cb_struct->event, tmpSQL ? tmpSQL : custom_sql);
-
+                       
                } else {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_CRIT,
-                                                         "mod_lcr called without a valid session while using a custom_sql that has channel variables.\n");
+                                                               "mod_lcr called without a valid session while using a custom_sql that has channel variables.\n");
                }
        }
-
+       
        if (tmpSQL != newSQL) {
                switch_safe_free(tmpSQL);
        }
-
+       
        if (newSQL == NULL) {
                return (char *) custom_sql;
        } else {
@@ -543,7 +573,7 @@ static switch_bool_t lcr_execute_sql_callback(char *sql, switch_core_db_callback
 {
        switch_bool_t retval = SWITCH_FALSE;
        switch_cache_db_handle_t *dbh = NULL;
-
+       
        if (globals.odbc_dsn && (dbh = lcr_get_db_handle())) {
                if (switch_cache_db_execute_sql_callback(dbh, sql, callback, pdata, NULL) != SWITCH_STATUS_SUCCESS) {
                        retval = SWITCH_FALSE;
@@ -555,54 +585,64 @@ static switch_bool_t lcr_execute_sql_callback(char *sql, switch_core_db_callback
        return retval;
 }
 
+/* CF = compare field */
+#define CF(x) !strcmp(x, columnNames[i])
+
 static int route_add_callback(void *pArg, int argc, char **argv, char **columnNames)
 {
        lcr_route additional = NULL;
        lcr_route current = NULL;
        callback_t *cbt = (callback_t *) pArg;
        char *key = NULL;
+       int i = 0;
 
        switch_memory_pool_t *pool = cbt->pool;
-
-
-       if (argc < LCR_QUERY_COLS_REQUIRED) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
-                                                 "Unexpected number of columns returned for SQL.  Returned column count: %d. "
-                                                 "If using a custom sql for this profile, verify it is correct.  Otherwise file a bug report.\n", argc);
-               return SWITCH_STATUS_GENERR;
-       }
-
-       if (zstr(argv[LCR_GW_PREFIX_PLACE]) && zstr(argv[LCR_GW_SUFFIX_PLACE])) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-                                                 "There's no way to dial this Gateway: Carrier: \"%s\" Prefix: \"%s\", Suffix \"%s\"\n",
-                                                 switch_str_nil(argv[LCR_CARRIER_PLACE]), switch_str_nil(argv[LCR_GW_PREFIX_PLACE]), switch_str_nil(argv[LCR_GW_SUFFIX_PLACE]));
-               return SWITCH_STATUS_SUCCESS;
-       }
-
-       cbt->matches++;
+       
        additional = switch_core_alloc(pool, sizeof(lcr_obj_t));
-
-       additional->digit_len = strlen(argv[LCR_DIGITS_PLACE]);
-       additional->digit_str = switch_core_strdup(pool, switch_str_nil(argv[LCR_DIGITS_PLACE]));
-       additional->suffix = switch_core_strdup(pool, switch_str_nil(argv[LCR_SUFFIX_PLACE]));
-       additional->prefix = switch_core_strdup(pool, switch_str_nil(argv[LCR_PREFIX_PLACE]));
-       additional->carrier_name = switch_core_strdup(pool, switch_str_nil(argv[LCR_CARRIER_PLACE]));
-       additional->rate = (float) atof(switch_str_nil(argv[LCR_RATE_PLACE]));
-       additional->rate_str = switch_core_sprintf(pool, "%0.5f", additional->rate);
-       additional->gw_prefix = switch_core_strdup(pool, switch_str_nil(argv[LCR_GW_PREFIX_PLACE]));
-       additional->gw_suffix = switch_core_strdup(pool, switch_str_nil(argv[LCR_GW_SUFFIX_PLACE]));
-       additional->lstrip = atoi(switch_str_nil(argv[LCR_LSTRIP_PLACE]));
-       additional->tstrip = atoi(switch_str_nil(argv[LCR_TSTRIP_PLACE]));
-       if (argc > LCR_CODEC_PLACE) {
-               additional->codec = switch_core_strdup(pool, switch_str_nil(argv[LCR_CODEC_PLACE]));
-       }
-       if (argc > LCR_CID_PLACE) {
-               additional->cid = switch_core_strdup(pool, switch_str_nil(argv[LCR_CID_PLACE]));
-       }
-       if (argc > LCR_USER_RATE_PLACE) {
-               additional->user_rate = (float) atof(switch_str_nil(argv[LCR_USER_RATE_PLACE]));
-               additional->user_rate_str = switch_core_sprintf(pool, "%0.5f", additional->user_rate);
+       additional->fields = switch_core_alloc(pool, sizeof(switch_event_t));
+
+       for (i = 0; i < argc ; i++) {
+               if (CF("lcr_digits")) {
+                       additional->digit_len = strlen(argv[i]);
+                       additional->digit_str = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_prefix")) {
+                       additional->prefix = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_suffix")) {
+                       additional->suffix = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_carrier_name")) {
+                       additional->carrier_name = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_rate_field")) {
+                       additional->rate = (float)atof(switch_str_nil(argv[i]));
+                       additional->rate_str = switch_core_sprintf(pool, "%0.5f", additional->rate);
+               } else if (CF("lcr_gw_prefix")) {
+                       additional->gw_prefix = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_gw_suffix")) {
+                       additional->gw_suffix = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_lead_strip")) {
+                       additional->lstrip = atoi(switch_str_nil(argv[i]));
+               } else if (CF("lcr_trail_strip")) {
+                       additional->tstrip = atoi(switch_str_nil(argv[i]));
+               } else if (CF("lcr_codec")) {
+                       additional->codec = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_cid")) {
+                       additional->cid = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_user_rate")) {
+                       additional->user_rate = (float)atof(switch_str_nil(argv[i]));
+                       additional->user_rate_str = switch_core_sprintf(pool, "%0.5f", additional->user_rate);
+               } else if (CF("lcr_limit_realm")) {
+                       additional->limit_realm = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_limit_id")) {
+                       additional->limit_id = switch_core_strdup(pool, switch_str_nil(argv[i]));
+               } else if (CF("lcr_limit_max")) {
+                       additional->limit_max = (float)atof(switch_str_nil(argv[i]));
+               }
+               
+               /* add all fields to the fields event */
+               switch_event_add_header_string(additional->fields, SWITCH_STACK_BOTTOM, columnNames[i], argv[i]);
        }
+       
+       cbt->matches++;
+       
        additional->dialstring = get_bridge_data(pool, cbt->lookup_number, cbt->cid, additional, cbt->profile, cbt->session);
 
        if (cbt->head == NULL) {
@@ -617,12 +657,14 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
                return SWITCH_STATUS_SUCCESS;
        }
 
-
+       
        for (current = cbt->head; current; current = current->next) {
-
+       
                key = switch_core_sprintf(pool, "%s:%s", additional->gw_prefix, additional->gw_suffix);
                if (switch_core_hash_find(cbt->dedup_hash, key)) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring Duplicate route for termination point (%s)\n", key);
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+                                                               "Ignoring Duplicate route for termination point (%s)\n",
+                                                               key);
                        break;
                }
 
@@ -642,12 +684,13 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
                        if (current->rate > additional->rate) {
                                /* insert myself here */
                                if (current->prev != NULL) {
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding %s before %s\n", additional->carrier_name, current->carrier_name);
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding %s before %s\n", 
+                                                                               additional->carrier_name, current->carrier_name);
                                        current->prev->next = additional;
                                } else {
                                        /* put this one at the head */
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Inserting %s to list head before %s\n",
-                                                                         additional->carrier_name, current->carrier_name);
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Inserting %s to list head before %s\n", 
+                                                                               additional->carrier_name, current->carrier_name);
                                        cbt->head = additional;
                                }
                                additional->next = current;
@@ -659,7 +702,7 @@ static int route_add_callback(void *pArg, int argc, char **argv, char **columnNa
                                break;
                        } else if (current->next == NULL) {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "adding %s to end of list after %s\n",
-                                                                 additional->carrier_name, current->carrier_name);
+                                                                       additional->carrier_name, current->carrier_name);
                                current->next = additional;
                                additional->prev = current;
                                if (switch_core_hash_insert(cbt->dedup_hash, key, additional) != SWITCH_STATUS_SUCCESS) {
@@ -677,7 +720,7 @@ static int intrastatelata_callback(void *pArg, int argc, char **argv, char **col
 {
        int count = 0;
        callback_t *cbt = (callback_t *) pArg;
-
+       
        count = atoi(argv[1]);
        if (count == 1) {
                if (!strcmp(argv[0], "state")) {
@@ -687,50 +730,51 @@ static int intrastatelata_callback(void *pArg, int argc, char **argv, char **col
                }
        }
 
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Type: %s, Count: %d\n", argv[0], count);
-
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Type: %s, Count: %d\n", argv[0], count);    
+       
        return SWITCH_STATUS_SUCCESS;
 }
 
 static switch_status_t is_intrastatelata(callback_t *cb_struct)
 {
        char *sql = NULL;
-
+       
        /* extract npa nxx - make some assumptions about format:
           e164 format without the +
           NANP only (so 11 digits starting with 1)
         */
-       if (!cb_struct->lookup_number || (strlen(cb_struct->lookup_number) != 11 && *cb_struct->lookup_number != '1') || 
+       if (!cb_struct->lookup_number || strlen(cb_struct->lookup_number) != 11 || *cb_struct->lookup_number != '1' || 
                !switch_is_number(cb_struct->lookup_number)) {
                /* dest doesn't appear to be NANP number */
                return SWITCH_STATUS_GENERR;
        }
-       if (!cb_struct->cid || (strlen(cb_struct->cid) != 11 && *cb_struct->cid != '1') || !switch_is_number(cb_struct->cid)) {
+       if (!cb_struct->cid || strlen(cb_struct->cid) != 11 || *cb_struct->cid != '1' || !switch_is_number(cb_struct->cid)) {
                /* cid not NANP */
                return SWITCH_STATUS_GENERR;
        }
-
+       
        /* assume that if the area code (plus leading 1) are the same we're intrastate */
        /* probably a bad assumption */
        /*
-          if (!strncmp(cb_struct->lookup_number, cb_struct->cid, 4)) {
-          cb_struct->intrastate = SWITCH_TRUE;
-          return SWITCH_STATUS_SUCCESS;
-          }
-        */
-
+       if (!strncmp(cb_struct->lookup_number, cb_struct->cid, 4)) {
+               cb_struct->intrastate = SWITCH_TRUE;
+               return SWITCH_STATUS_SUCCESS;
+       }
+       */
+       
        sql = switch_core_sprintf(cb_struct->pool,
-                                                         "SELECT 'state', count(DISTINCT state) FROM npa_nxx_company_ocn WHERE (npa=%3.3s AND nxx=%3.3s) OR (npa=%3.3s AND nxx=%3.3s)"
-                                                         " UNION "
-                                                         "SELECT 'lata', count(DISTINCT lata) FROM npa_nxx_company_ocn WHERE (npa=%3.3s AND nxx=%3.3s) OR (npa=%3.3s AND nxx=%3.3s)",
-                                                         cb_struct->lookup_number + 1, cb_struct->lookup_number + 4,
-                                                         cb_struct->cid + 1, cb_struct->cid + 4,
-                                                         cb_struct->lookup_number + 1, cb_struct->lookup_number + 4, cb_struct->cid + 1, cb_struct->cid + 4);
-
-       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", sql);
-
-       return (lcr_execute_sql_callback(sql, intrastatelata_callback, cb_struct));
-
+                                                               "SELECT 'state', count(DISTINCT state) FROM npa_nxx_company_ocn WHERE (npa=%3.3s AND nxx=%3.3s) OR (npa=%3.3s AND nxx=%3.3s)"
+                                                               " UNION "
+                                                               "SELECT 'lata', count(DISTINCT lata) FROM npa_nxx_company_ocn WHERE (npa=%3.3s AND nxx=%3.3s) OR (npa=%3.3s AND nxx=%3.3s)",
+                                                               cb_struct->lookup_number+1, cb_struct->lookup_number+4,
+                                                               cb_struct->cid+1, cb_struct->cid+4,
+                                                               cb_struct->lookup_number+1, cb_struct->lookup_number+4,
+                                                               cb_struct->cid+1, cb_struct->cid+4);
+
+       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", sql);    
+
+       return(lcr_execute_sql_callback(sql, intrastatelata_callback, cb_struct));
+       
 }
 
 static switch_status_t lcr_do_lookup(callback_t *cb_struct)
@@ -746,26 +790,26 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
        char *safe_sql = NULL;
        char *rate_field = NULL;
        char *user_rate_field = NULL;
-
+       
        switch_assert(cb_struct->lookup_number != NULL);
 
        digits_copy = string_digitsonly(cb_struct->pool, digits);
        if (zstr(digits_copy)) {
                return SWITCH_STATUS_GENERR;
        }
-
+       
        /* allocate the dedup hash */
        if (switch_core_hash_init(&cb_struct->dedup_hash, cb_struct->pool) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_ERROR, "Error initializing the dedup hash\n");
                return SWITCH_STATUS_GENERR;
        }
-
+       
        digits_expanded = expand_digits(cb_struct->pool, digits_copy, cb_struct->profile->quote_in_list);
-
+       
        if (profile->profile_has_npanxx == SWITCH_TRUE) {
                is_intrastatelata(cb_struct);
        }
-
+       
        /* set our rate field based on env and profile */
        if (cb_struct->intralata == SWITCH_TRUE && profile->profile_has_intralata == SWITCH_TRUE) {
                rate_field = switch_core_strdup(cb_struct->pool, "intralata_rate");
@@ -779,7 +823,7 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
        }
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "intra routing [state:%d lata:%d] so rate field is [%s]\n",
                                          cb_struct->intrastate, cb_struct->intralata, rate_field);
-
+       
        /* set some channel vars if we have a session */
        if (cb_struct->session) {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "we have a session\n");
@@ -806,7 +850,6 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
        /* format the custom_sql */
        safe_sql = format_custom_sql(profile->custom_sql, cb_struct, digits_copy);
        if (!safe_sql) {
-               switch_event_safe_destroy(&cb_struct->event);
                switch_core_hash_destroy(&cb_struct->dedup_hash);
                return SWITCH_STATUS_GENERR;
        }
@@ -816,13 +859,12 @@ static switch_status_t lcr_do_lookup(callback_t *cb_struct)
                /* channel_expand_variables returned the same string to us, no need to free */
                switch_safe_free(safe_sql);
        }
-
-       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", (char *) sql_stream.data);
-
-       lookup_status = lcr_execute_sql_callback((char *) sql_stream.data, route_add_callback, cb_struct);
+       
+       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(cb_struct->session), SWITCH_LOG_DEBUG, "SQL: %s\n", (char *)sql_stream.data);    
+       
+       lookup_status = lcr_execute_sql_callback((char *)sql_stream.data, route_add_callback, cb_struct);
 
        switch_safe_free(sql_stream.data);
-       switch_event_safe_destroy(&cb_struct->event);
        switch_core_hash_destroy(&cb_struct->dedup_hash);
 
        if (lookup_status) {
@@ -842,15 +884,16 @@ static switch_bool_t test_profile(char *lcr_profile)
        switch_event_create(&event, SWITCH_EVENT_MESSAGE);
        routes.event = event;
        routes.pool = pool;
-
+       
        if (!(routes.profile = locate_profile(lcr_profile))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown profile: %s\n", lcr_profile);
                return SWITCH_FALSE;
        }
-
+       
        routes.lookup_number = "15555551212";
        routes.cid = "18005551212";
-       return (lcr_do_lookup(&routes) == SWITCH_STATUS_SUCCESS) ? SWITCH_TRUE : SWITCH_FALSE;
+       return (lcr_do_lookup(&routes) == SWITCH_STATUS_SUCCESS) ?
+               SWITCH_TRUE : SWITCH_FALSE;
 }
 
 static switch_status_t lcr_load_config()
@@ -886,16 +929,19 @@ static switch_status_t lcr_load_config()
                        }
                }
        }
-
+       
        /* initialize sql here, 'cause we need to verify custom_sql for each profile below */
        if (globals.odbc_dsn) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dsn is \"%s\", user is \"%s\"\n", globals.odbc_dsn, globals.odbc_user);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG
+                                                 , "dsn is \"%s\", user is \"%s\"\n"
+                                                 , globals.odbc_dsn, globals.odbc_user
+                                                 );
                if (!(dbh = lcr_get_db_handle())) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
                        switch_goto_status(SWITCH_STATUS_FALSE, done);
                }
        }
-
+       
        if (set_db_random() == SWITCH_TRUE) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Database RANDOM function set to %s\n", db_random);
        } else {
@@ -915,9 +961,11 @@ static switch_status_t lcr_load_config()
                        char *enable_sip_redir = NULL;
                        char *id_s = NULL;
                        char *custom_sql = NULL;
+                       char *export_fields = NULL;
+                       char *limit_type = NULL;
                        int argc, x = 0;
                        char *argv[4] = { 0 };
-
+                       
                        SWITCH_STANDARD_STREAM(order_by);
 
                        for (param = switch_xml_child(x_profile, "param"); param; param = param->next) {
@@ -925,12 +973,12 @@ static switch_status_t lcr_load_config()
 
                                var = (char *) switch_xml_attr_soft(param, "name");
                                val = (char *) switch_xml_attr_soft(param, "value");
-
-                               if (!strcasecmp(var, "order_by") && !zstr(val)) {
+                               
+                               if (!strcasecmp(var, "order_by")  && !zstr(val)) {
                                        thisorder = &order_by;
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "param val is %s\n", val);
                                        if ((argc = switch_separate_string(val, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) {
-                                               for (x = 0; x < argc; x++) {
+                                               for (x=0; x<argc; x++) {
                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "arg #%d/%d is %s\n", x, argc, argv[x]);
                                                        if (!zstr(argv[x])) {
                                                                if (!strcasecmp(argv[x], "quality")) {
@@ -965,80 +1013,87 @@ static switch_status_t lcr_load_config()
                                        info_in_headers = val;
                                } else if (!strcasecmp(var, "quote_in_list") && !zstr(val)) {
                                        quote_in_list = val;
+                               } else if (!strcasecmp(var, "export_fields") && !zstr(val)) {
+                                       export_fields = val;
+                               } else if (!strcasecmp(var, "limit_type") && !zstr(val)) {
+                                       limit_type = val;
                                } else if (!strcasecmp(var, "enable_sip_redir") && !zstr(val)) {
                                        enable_sip_redir = val;
                                }
                        }
-
+                       
                        if (zstr(name)) {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No name specified.\n");
                        } else {
                                profile = switch_core_alloc(globals.pool, sizeof(*profile));
                                memset(profile, 0, sizeof(profile_t));
                                profile->name = switch_core_strdup(globals.pool, name);
-
-                               if (!zstr((char *) order_by.data)) {
-                                       profile->order_by = switch_core_strdup(globals.pool, (char *) order_by.data);
+                               
+                               if (!zstr((char *)order_by.data)) {
+                                       profile->order_by = switch_core_strdup(globals.pool, (char *)order_by.data);
                                } else {
                                        /* default to rate */
                                        profile->order_by = ", ${lcr_rate_field}";
                                }
 
                                if (!zstr(id_s)) {
-                                       profile->id = (uint16_t) atoi(id_s);
+                                       profile->id = (uint16_t)atoi(id_s);
                                }
-
+                               
                                /* SWITCH_STANDARD_STREAM doesn't use pools.  but we only have to free sql_stream.data */
                                SWITCH_STANDARD_STREAM(sql_stream);
                                if (zstr(custom_sql)) {
                                        /* use default sql */
-                                       sql_stream.write_function(&sql_stream,
-                                                                                         "SELECT l.digits, c.carrier_name, l.${lcr_rate_field}, cg.prefix AS gw_prefix, cg.suffix AS gw_suffix, l.lead_strip, l.trail_strip, l.prefix, l.suffix ");
+                                       sql_stream.write_function(&sql_stream, 
+                                                                                         "SELECT l.digits AS lcr_digits, c.carrier_name AS lcr_carrier_name, l.${lcr_rate_field} AS lcr_rate_field, cg.prefix AS lcr_gw_prefix, cg.suffix AS lcr_gw_suffix, l.lead_strip AS lcr_lead_strip, l.trail_strip AS lcr_trail_strip, l.prefix AS lcr_prefix, l.suffix AS lcr_suffix "
+                                                                                         );
                                        if (db_check("SELECT codec from carrier_gateway limit 1") == SWITCH_TRUE) {
-                                               sql_stream.write_function(&sql_stream, ", cg.codec ");
+                                               sql_stream.write_function(&sql_stream, ", cg.codec AS lcr_codec ");
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "codec field defined.\n");
                                        } else {
-                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-                                                                                 "codec field not defined, please update your lcr carrier_gateway database schema.\n");
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "codec field not defined, please update your lcr carrier_gateway database schema.\n");
                                        }
                                        if (db_check("SELECT cid from lcr limit 1") == SWITCH_TRUE) {
-                                               sql_stream.write_function(&sql_stream, ", l.cid ");
+                                               sql_stream.write_function(&sql_stream, ", l.cid AS lcr_cid ");
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cid field defined.\n");
                                        } else {
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "cid field not defined, please update your lcr database schema.\n");
                                        }
-                                       sql_stream.write_function(&sql_stream,
-                                                                                         "FROM lcr l JOIN carriers c ON l.carrier_id=c.id JOIN carrier_gateway cg ON c.id=cg.carrier_id WHERE c.enabled = '1' AND cg.enabled = '1' AND l.enabled = '1' AND digits IN (");
+                                       sql_stream.write_function(&sql_stream, "FROM lcr l JOIN carriers c ON l.carrier_id=c.id JOIN carrier_gateway cg ON c.id=cg.carrier_id WHERE c.enabled = '1' AND cg.enabled = '1' AND l.enabled = '1' AND digits IN (");
                                        sql_stream.write_function(&sql_stream, "${lcr_query_expanded_digits}");
                                        sql_stream.write_function(&sql_stream, ") AND CURRENT_TIMESTAMP BETWEEN date_start AND date_end ");
                                        if (profile->id > 0) {
                                                sql_stream.write_function(&sql_stream, "AND lcr_profile=%d ", profile->id);
                                        }
-                                       sql_stream.write_function(&sql_stream, "ORDER BY digits DESC%s", profile->order_by);
+                                       sql_stream.write_function(&sql_stream, "ORDER BY digits DESC%s", 
+                                                                                                                       profile->order_by);
                                        if (db_random) {
                                                sql_stream.write_function(&sql_stream, ", %s", db_random);
                                        }
                                        sql_stream.write_function(&sql_stream, ";");
-
+                                       
                                        custom_sql = sql_stream.data;
                                }
-
-
+                               
+                               
                                profile->profile_has_intralata = db_check("SELECT intralata_rate FROM lcr LIMIT 1");
                                if (profile->profile_has_intralata != SWITCH_TRUE) {
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-                                                                         "no \"intralata_rate\" field found in the \"lcr\" table, routing by intralata rates will be disabled until the field is added and mod_lcr is reloaded\n");
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+                                                                         "no \"intralata_rate\" field found in the \"lcr\" table, routing by intralata rates will be disabled until the field is added and mod_lcr is reloaded\n"
+                                                                         );
                                }
                                profile->profile_has_intrastate = db_check("SELECT intrastate_rate FROM lcr LIMIT 1");
                                if (profile->profile_has_intrastate != SWITCH_TRUE) {
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-                                                                         "no \"intrastate_rate\" field found in the \"lcr\" table, routing by intrastate rates will be disabled until the field is added and mod_lcr is reloaded\n");
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+                                                                         "no \"intrastate_rate\" field found in the \"lcr\" table, routing by intrastate rates will be disabled until the field is added and mod_lcr is reloaded\n"
+                                                                         );
                                }
-
+                               
                                profile->profile_has_npanxx = db_check("SELECT npa, nxx, state FROM npa_nxx_company_ocn LIMIT 1");
                                if (profile->profile_has_npanxx != SWITCH_TRUE) {
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-                                                                         "no \"npa_nxx_company_ocn\" table found in the \"lcr\" database, automatic intrastate detection will be disabled until the table is added and mod_lcr is reloaded\n");
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 
+                                                                         "no \"npa_nxx_company_ocn\" table found in the \"lcr\" database, automatic intrastate detection will be disabled until the table is added and mod_lcr is reloaded\n"
+                                                                         );
                                }
 
                                if (switch_string_var_check_const(custom_sql) || switch_string_has_escaped_data(custom_sql)) {
@@ -1047,12 +1102,12 @@ static switch_status_t lcr_load_config()
                                if (strstr(custom_sql, "%")) {
                                        profile->custom_sql_has_percent = SWITCH_TRUE;
                                }
-                               profile->custom_sql = switch_core_strdup(globals.pool, (char *) custom_sql);
-
+                               profile->custom_sql = switch_core_strdup(globals.pool, (char *)custom_sql);
+                               
                                if (!zstr(reorder_by_rate)) {
                                        profile->reorder_by_rate = switch_true(reorder_by_rate);
                                }
-
+                               
                                if (!zstr(info_in_headers)) {
                                        profile->info_in_headers = switch_true(info_in_headers);
                                }
@@ -1064,7 +1119,30 @@ static switch_status_t lcr_load_config()
                                if (!zstr(quote_in_list)) {
                                        profile->quote_in_list = switch_true(quote_in_list);
                                }
-
+                               
+                               if (!zstr(export_fields)) {
+                                       int argc2 = 0;
+                                       char *argv2[50] = { 0 };
+                                       char **argvdup = NULL;
+                                       char *dup = switch_core_strdup(globals.pool, export_fields);
+                                       argc2 = switch_separate_string(dup, ',', argv2, (sizeof(argv2) / sizeof(argv2[0])));
+                                       profile->export_fields_str = switch_core_strdup(globals.pool, export_fields);
+                                       profile->export_fields_cnt = argc2;
+                                       argvdup = switch_core_alloc(globals.pool, sizeof(argv2));
+                                       memcpy(argvdup, argv2, sizeof(argv2));
+                                       profile->export_fields = argvdup;
+                               }
+                               
+                               if (!zstr(limit_type)) {
+                                       if (!strcasecmp(limit_type, "hash")) {
+                                               profile->limit_type = "hash";
+                                       } else {
+                                               profile->limit_type = "sql";
+                                       }
+                               } else {
+                                       profile->limit_type = "sql";
+                               }
+                               
                                switch_core_hash_insert(globals.profile_hash, profile->name, profile);
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Loaded lcr profile %s.\n", profile->name);
                                /* test the profile */
@@ -1077,7 +1155,7 @@ static switch_status_t lcr_load_config()
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Removing INVALID Profile %s.\n", profile->name);
                                        switch_core_hash_delete(globals.profile_hash, profile->name);
                                }
-
+                               
                        }
                        switch_safe_free(order_by.data);
                        switch_safe_free(sql_stream.data);
@@ -1085,7 +1163,7 @@ static switch_status_t lcr_load_config()
        } else {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "No lcr profiles defined.\n");
        }
-
+       
        /* define default profile  */
        if (!globals.default_profile) {
                profile = switch_core_alloc(globals.pool, sizeof(*profile));
@@ -1096,12 +1174,206 @@ static switch_status_t lcr_load_config()
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting system defined default profile.");
        }
 
-  done:
+done:
        switch_cache_db_release_db_handle(&dbh);
        switch_xml_free(xml);
        return status;
 }
 
+/* fake chan_lcr */
+switch_endpoint_interface_t *lcr_endpoint_interface;
+static switch_call_cause_t lcr_outgoing_channel(switch_core_session_t *session,
+                                                                                                 switch_event_t *var_event,
+                                                                                                 switch_caller_profile_t *outbound_profile,
+                                                                                                 switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
+                                                                                                 switch_call_cause_t *cancel_cause);
+switch_io_routines_t lcr_io_routines = {
+       /*.outgoing_channel */ lcr_outgoing_channel
+};
+
+static switch_call_cause_t lcr_outgoing_channel(switch_core_session_t *session,
+                                                                                                 switch_event_t *var_event,
+                                                                                                 switch_caller_profile_t *outbound_profile,
+                                                                                                 switch_core_session_t **new_session, switch_memory_pool_t **new_pool, switch_originate_flag_t flags,
+                                                                                                 switch_call_cause_t *cancel_cause)
+{
+       switch_call_cause_t cause = SWITCH_CAUSE_NONE;
+       char *dest = NULL;
+       switch_originate_flag_t myflags = SOF_NONE;
+       const char *cid_name_override = NULL;
+       const char *cid_num_override = NULL;
+       switch_channel_t *new_channel = NULL;
+       unsigned int timelimit = 60;
+       const char *skip, *var;
+
+       switch_memory_pool_t *pool = NULL;
+       callback_t routes = { 0 };
+       lcr_route cur_route = { 0 };
+       char *lcr_profile = NULL;
+       switch_event_t *event = NULL;
+       const char *intrastate = NULL;
+       const char *intralata = NULL;
+       switch_core_session_t *mysession = NULL;
+       switch_channel_t *channel = NULL;
+       switch_caller_profile_t *caller_profile = NULL;
+       
+       dest = strdup(outbound_profile->destination_number);
+       
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Entering lcr endpoint for %s\n", dest);
+       
+       if (!dest) {
+               goto done;
+       }
+       
+       switch_core_new_memory_pool(&pool);
+       routes.pool = pool;
+
+       if (var_event && (skip = switch_event_get_header(var_event, "lcr_recurse_variables")) && switch_false(skip)) {
+               if ((var = switch_event_get_header(var_event, SWITCH_CALL_TIMEOUT_VARIABLE)) || (var = switch_event_get_header(var_event, "leg_timeout"))) {
+                       timelimit = atoi(var);
+               }
+               var_event = NULL;
+       }
+
+       if (session) {
+               mysession = session;
+               channel = switch_core_session_get_channel(session);
+               if ((var = switch_channel_get_variable(channel, SWITCH_CALL_TIMEOUT_VARIABLE)) || (var = switch_event_get_header(var_event, "leg_timeout"))) {
+                       timelimit = atoi(var);
+               }
+               routes.session = session;
+               caller_profile = switch_channel_get_caller_profile(channel);
+               intrastate = switch_channel_get_variable(channel, "intrastate");
+               intralata = switch_channel_get_variable(channel, "intralata");
+               cid_name_override = switch_channel_get_variable(channel, "origination_caller_id_name");
+               cid_num_override = switch_channel_get_variable(channel, "origination_caller_id_number");
+               if (zstr(cid_name_override)) {
+                       cid_name_override = switch_channel_get_variable(channel, "effective_caller_id_name");
+               }
+               if (zstr(cid_num_override)) {
+                       cid_num_override = switch_channel_get_variable(channel, "effective_caller_id_number");
+               }
+               if ((var = switch_channel_get_variable(channel, SWITCH_CALL_TIMEOUT_VARIABLE)) || (var = switch_event_get_header(var_event, "leg_timeout"))) {
+                       timelimit = atoi(var);
+               }
+       } else if (var_event) {
+               char *session_uuid = switch_event_get_header(var_event, "ent_originate_aleg_uuid");
+               if (session_uuid) {
+                       mysession = switch_core_session_locate(session_uuid);
+               }
+               cid_name_override = switch_event_get_header(var_event, "origination_caller_id_name");
+               cid_num_override = switch_event_get_header(var_event, "origination_caller_id_number");
+               if (zstr(cid_name_override)) {
+                       cid_name_override = switch_event_get_header(var_event, "effective_caller_id_name");
+               }
+               if (zstr(cid_num_override)) {
+                       cid_num_override = switch_event_get_header(var_event, "caller_id_number");
+               }
+               if ((var = switch_event_get_header(var_event, SWITCH_CALL_TIMEOUT_VARIABLE)) || (var = switch_event_get_header(var_event, "leg_timeout"))) {
+                       timelimit = atoi(var);
+               }
+               
+               intrastate = switch_event_get_header(var_event, "intrastate");
+               intralata = switch_event_get_header(var_event, "intralata");
+               //switch_event_dup(&event, var_event);
+               routes.event = var_event;
+       } else {
+               switch_event_create(&event, SWITCH_EVENT_MESSAGE);
+               routes.event = event;
+       }
+       routes.lookup_number = dest;
+       routes.cid = (char *) cid_num_override;
+       
+       if ((flags & SOF_FORKED_DIAL)) {
+               myflags |= SOF_NOBLOCK;
+       }
+
+       if (!(routes.profile = locate_profile(lcr_profile))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown profile: %s\n", lcr_profile);
+               goto done;
+       }
+
+       if (!zstr(intralata) && !strcasecmp((char *)intralata, "true")) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Select routes based on intralata rates\n");
+               routes.intralata = SWITCH_FALSE;
+       } else if (!zstr(intrastate) && !strcasecmp((char *)intrastate, "true")) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Select routes based on intrastate rates\n");
+               routes.intrastate = SWITCH_TRUE;
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Select routes based on interstate rates\n");
+               routes.intrastate = SWITCH_FALSE;
+       }
+       
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "LCR Lookup on %s\n", dest);
+
+       if (lcr_do_lookup(&routes) == SWITCH_STATUS_SUCCESS) {
+               if (channel) {
+                       if (zstr(switch_channel_get_variable(channel, "import"))) {
+                               switch_channel_set_variable(channel, "import", "lcr_carrier,lcr_rate");
+                       } else {
+                               const char *tmp = switch_channel_get_variable(channel, "import");
+                               if (!strstr(tmp, "lcr_carrier,lcr_rate")) {
+                                       switch_channel_set_variable_printf(channel, "import", "%s,lcr_carrier,lcr_rate", tmp);
+                               }
+                       }
+               }
+
+               for (cur_route = routes.head; cur_route; cur_route = cur_route->next) {
+                       switch_bool_t pop_limit = SWITCH_FALSE;
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Trying route: %s\n", cur_route->dialstring);
+                       if (mysession && cur_route->limit_realm && cur_route->limit_id) {
+                               if (switch_limit_incr(routes.profile->limit_type, mysession, cur_route->limit_realm, cur_route->limit_id, cur_route->limit_max, 0) == SWITCH_STATUS_SUCCESS) {
+                                       pop_limit = SWITCH_TRUE;
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Limit exceeded for route %s, session: %s\n", cur_route->dialstring, mysession ? "true" : "false");
+                                       continue;
+                               }
+                       }
+                       if (switch_ivr_originate(session, new_session, &cause, cur_route->dialstring, timelimit, NULL,
+                                                                        cid_name_override, cid_num_override, NULL, var_event, myflags, cancel_cause) == SWITCH_STATUS_SUCCESS) {
+                               const char *context;
+                               switch_caller_profile_t *cp;
+
+                               new_channel = switch_core_session_get_channel(*new_session);
+
+                               if ((context = switch_channel_get_variable(new_channel, "lcr_context"))) {
+                                       if ((cp = switch_channel_get_caller_profile(new_channel))) {
+                                               cp->context = switch_core_strdup(cp->pool, context);
+                                       }
+                               }
+                               switch_core_session_rwunlock(*new_session);
+                               break;
+                       }
+                       
+                       /* did not connect, release limit */
+                       if (pop_limit) {
+                               switch_limit_release(routes.profile->limit_type, mysession, cur_route->limit_realm, cur_route->limit_id);
+                       }
+                       if (cause == SWITCH_CAUSE_LOSE_RACE || cause == SWITCH_CAUSE_ORIGINATOR_CANCEL) {
+                               break;
+                       }
+               }
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "LCR lookup failed for %s\n", caller_profile->destination_number);
+       }
+
+  done:
+       if (event) {
+               switch_event_destroy(&event);
+       }
+       if (mysession) {
+               switch_core_session_rwunlock(mysession);
+       }
+       switch_core_destroy_memory_pool(&pool);
+       switch_safe_free(dest);
+
+       if (cause == SWITCH_CAUSE_NONE) {
+               cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+       }
+
+       return cause;
+}
+
 SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt)
 {
        switch_caller_extension_t *extension = NULL;
@@ -1132,17 +1404,17 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt)
        intralata = switch_channel_get_variable(channel, "intralata");
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", intrastate);
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intralata channel var is [%s]\n", intralata);
-       if (!zstr(intralata) && !strcasecmp((char *) intralata, "true")) {
+       if (!zstr(intralata) && !strcasecmp((char *)intralata, "true")) {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on intralata rates\n");
                routes.intralata = SWITCH_FALSE;
-       } else if (!zstr(intrastate) && !strcasecmp((char *) intrastate, "true")) {
+       } else if (!zstr(intrastate) && !strcasecmp((char *)intrastate, "true")) {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on intrastate rates\n");
                routes.intrastate = SWITCH_TRUE;
        } else {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on interstate rates\n");
                routes.intrastate = SWITCH_FALSE;
        }
-
+       
        if (!caller_profile) {
                caller_profile = switch_channel_get_caller_profile(channel);
        }
@@ -1158,16 +1430,40 @@ SWITCH_STANDARD_DIALPLAN(lcr_dialplan_hunt)
 
                switch_channel_set_variable(channel, SWITCH_CONTINUE_ON_FAILURE_VARIABLE, "true");
                switch_channel_set_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "true");
-               switch_channel_set_variable(channel, "import", "lcr_carrier,lcr_rate");
+               if (zstr(switch_channel_get_variable(channel, "import"))) {
+                       switch_channel_set_variable(channel, "import", "lcr_carrier,lcr_rate");
+               } else {
+                       const char *tmp = switch_channel_get_variable(channel, "import");
+                       if (!strstr(tmp, "lcr_carrier,lcr_rate")) {
+                               switch_channel_set_variable_printf(channel, "import", "%s,lcr_carrier,lcr_rate", tmp);
+                       }
+               }
 
                for (cur_route = routes.head; cur_route; cur_route = cur_route->next) {
-                       switch_caller_extension_add_application(session, extension, "bridge", cur_route->dialstring);
+                       char *app = NULL;
+                       char *argc = NULL;
+                       if (cur_route->limit_realm && cur_route->limit_id) {
+                               app = "limit_execute";
+                               argc = switch_core_sprintf(pool, "%s %s %s %d bridge %s",
+                                                                                       routes.profile->limit_type,
+                                                                                       cur_route->limit_realm,
+                                                                                       cur_route->limit_id,
+                                                                                       cur_route->limit_max,
+                                                                                       cur_route->dialstring);
+                       } else {
+                               app = "bridge";
+                               argc = cur_route->dialstring;
+                       }
+                       switch_caller_extension_add_application(session, extension, app, argc);
                }
        } else {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "LCR lookup failed for %s\n", caller_profile->destination_number);
        }
 
-  end:
+end:
+       if (event) {
+               switch_event_destroy(&event);
+       }
        if (!session) {
                switch_core_destroy_memory_pool(&pool);
        }
@@ -1178,9 +1474,9 @@ void str_repeat(size_t how_many, char *what, switch_stream_handle_t *str_stream)
 {
        size_t i;
 
-       /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "repeating %d of '%s'\n", (int)how_many, what); */
-
-       for (i = 0; i < how_many; i++) {
+       /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "repeating %d of '%s'\n", (int)how_many, what);*/
+       
+       for (i=0; i<how_many; i++) {
                str_stream->write_function(str_stream, "%s", what);
        }
 }
@@ -1217,8 +1513,9 @@ SWITCH_STANDARD_APP(lcr_app_function)
        routes.pool = pool;
 
        intra = switch_channel_get_variable(channel, "intrastate");
-       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", zstr(intra) ? "undef" : intra);
-       if (zstr(intra) || strcasecmp((char *) intra, "true")) {
+       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "intrastate channel var is [%s]\n", 
+                                       zstr(intra) ? "undef" : intra);
+       if (zstr(intra) || strcasecmp((char *)intra, "true")) {
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on interstate rates\n");
                routes.intrastate = SWITCH_FALSE;
        } else {
@@ -1237,7 +1534,7 @@ SWITCH_STANDARD_APP(lcr_app_function)
                if (argc > 1) {
                        lcr_profile = argv[1];
                }
-
+               
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "LCR Lookup on %s using profile %s\n", dest, lcr_profile);
                routes.lookup_number = dest;
                if (caller_profile) {
@@ -1247,7 +1544,7 @@ SWITCH_STANDARD_APP(lcr_app_function)
                        }
                }
 
-
+       
                if (!(routes.profile = locate_profile(lcr_profile))) {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Unknown profile: %s\n", lcr_profile);
                        goto end;
@@ -1276,28 +1573,41 @@ SWITCH_STANDARD_APP(lcr_app_function)
                                } else {
                                        dig_stream.write_function(&dig_stream, "%s", cur_route->dialstring);
                                }
+                               cnt++;
                        }
                        
                        switch_snprintf(vbuf, sizeof(vbuf), "%d", cnt - 1);
                        switch_channel_set_variable(channel, "lcr_route_count", vbuf);
                        switch_channel_set_variable(channel, "lcr_auto_route", (char *)dig_stream.data);
-                       switch_channel_set_variable(channel, "import", "lcr_carrier,lcr_rate");
+                       if (zstr(switch_channel_get_variable(channel, "import"))) {
+                               switch_channel_set_variable(channel, "import", "lcr_carrier,lcr_rate");
+                       } else {
+                               const char *tmp = switch_channel_get_variable(channel, "import");
+                               if (!strstr(tmp, "lcr_carrier,lcr_rate")) {
+                                       switch_channel_set_variable_printf(channel, "import", "%s,lcr_carrier,lcr_rate", tmp);
+                               }
+                       }
                        free(dig_stream.data);
                } else {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "LCR lookup failed for %s\n", dest);
                }
        }
-
-  end:
+       
+end:
+       if (routes.event) {
+               switch_event_destroy(&event);
+       }
        if (!session) {
                switch_core_destroy_memory_pool(&pool);
        }
 }
 
-static void write_data(switch_stream_handle_t *stream, switch_bool_t as_xml, const char *key, const char *data, int indent, int maxlen)
-{
+static void write_data(switch_stream_handle_t *stream, switch_bool_t as_xml, const char *key, const char *data, int indent, int maxlen) {
+       if (!data) {
+               data = "";
+       }
        if (as_xml) {
-               str_repeat(indent * 2, " ", stream);
+               str_repeat(indent*2, " ", stream);
                stream->write_function(stream, "<%s>%s</%s>\n", key, data, key);
        } else {
                stream->write_function(stream, " | %s", data);
@@ -1319,13 +1629,17 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
        switch_event_t *event;
        switch_status_t lookup_status = SWITCH_STATUS_SUCCESS;
        switch_bool_t as_xml = SWITCH_FALSE;
-       int rowcount = 0;
+       char *event_str = NULL;
+       switch_xml_t event_xml = NULL;
+       int rowcount=0;
 
        if (zstr(cmd)) {
                goto usage;
        }
 
-       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "data passed to lcr is [%s]\n", cmd);
+       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG
+                                         , "data passed to lcr is [%s]\n", cmd
+                                         );
 
        if (session) {
                pool = switch_core_session_get_pool(session);
@@ -1336,7 +1650,7 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
                cb_struct.event = event;
        }
        cb_struct.pool = pool;
-
+       
        mydata = switch_core_strdup(pool, cmd);
 
        if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
@@ -1347,27 +1661,29 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
                }
                if (argc > 2) {
                        int i;
-                       for (i = 2; i < argc; i++) {
+                       for (i=2; i<argc; i++) {
                                if (!strcasecmp(argv[i], "intrastate")) {
                                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Select routes based on intrastate rates\n");
                                        cb_struct.intrastate = SWITCH_TRUE;
                                } else if (!strcasecmp(argv[i], "as")) {
                                        i++;
                                        if (argv[i] && !strcasecmp(argv[i], "xml")) {
-                                               as_xml = SWITCH_TRUE;
-                                       } else {
-                                               goto usage;
-                                       }
+                                                       as_xml = SWITCH_TRUE;
+                                               } else {
+                                                       goto usage;
+                                               }
                                } else {
                                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Caller ID to [%s]\n", argv[i]);
                                        /* the only other option we have right now is caller id */
                                        cb_struct.cid = switch_core_strdup(pool, argv[i]);
                                }
                        }
-               }
+               } 
                if (zstr(cb_struct.cid)) {
                        cb_struct.cid = "18005551212";
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Using default CID [%s]\n", cb_struct.cid);
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING
+                                                         , "Using default CID [%s]\n", cb_struct.cid
+                                                         );
                }
 
 
@@ -1411,6 +1727,11 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
                                        str_repeat(len, " ", stream);
                                }
 
+                               stream->write_function(stream, " | %s", headers[LCR_HEADERS_LIMIT]);
+                               if ((len = (maximum_lengths.limit - strlen(headers[LCR_HEADERS_LIMIT]))) > 0) {
+                                       str_repeat(len, " ", stream);
+                               }
+                               
                                stream->write_function(stream, " | %s", headers[LCR_HEADERS_DIALSTRING]);
                                if ((len = (maximum_lengths.dialstring - strlen(headers[LCR_HEADERS_DIALSTRING]))) > 0) {
                                        str_repeat(len, " ", stream);
@@ -1427,7 +1748,7 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
                                if (as_xml) {
                                        stream->write_function(stream, "  <row id=\"%d\">\n", rowcount);
                                }
-
+                               
                                write_data(stream, as_xml, "prefix", current->digit_str, 2, maximum_lengths.digit_str);
                                write_data(stream, as_xml, "carrier_name", current->carrier_name, 2, maximum_lengths.carrier_name);
                                write_data(stream, as_xml, "rate", current->rate_str, 2, maximum_lengths.rate);
@@ -1442,9 +1763,25 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
                                } else {
                                        write_data(stream, as_xml, "cid", "", 2, maximum_lengths.cid);
                                }
-
+                               
+                               if (current->limit_realm && current->limit_id) {
+                                       char *str = NULL;
+                                       str = switch_core_sprintf(pool, "%s %s %d", current->limit_realm, current->limit_id, current->limit_max);
+                                       
+                                       write_data(stream, as_xml, "limit", str, 2, maximum_lengths.limit);
+                               } else {
+                                       write_data(stream, as_xml, "limit", "", 2, maximum_lengths.limit);
+                               }
+                               
                                write_data(stream, as_xml, "dialstring", current->dialstring, 2, maximum_lengths.dialstring);
-
+                               if (as_xml) {
+                                       event_xml = switch_event_xmlize(current->fields, NULL);
+                                       event_str = switch_xml_toxml(event_xml, SWITCH_FALSE);
+                                       stream->write_function(stream, event_str);
+                                       switch_xml_free(event_xml);
+                                       switch_safe_free(event_str);
+                               }
+                               
                                if (as_xml) {
                                        stream->write_function(stream, "  </row>\n");
                                } else {
@@ -1468,14 +1805,14 @@ SWITCH_STANDARD_API(dialplan_lcr_function)
                }
        }
 
-  end:
+end:
        if (!session) {
                if (pool) {
                        switch_core_destroy_memory_pool(&pool);
                }
        }
        return SWITCH_STATUS_SUCCESS;
-  usage:
+usage:
        stream->write_function(stream, "USAGE: %s\n", LCR_SYNTAX);
        goto end;
 }
@@ -1504,7 +1841,7 @@ SWITCH_STANDARD_API(dialplan_lcr_admin_function)
                        for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
                                switch_hash_this(hi, NULL, NULL, &val);
                                profile = (profile_t *) val;
-
+                               
                                stream->write_function(stream, "Name:\t\t%s\n", profile->name);
                                if (zstr(profile->custom_sql)) {
                                        stream->write_function(stream, " ID:\t\t%d\n", profile->id);
@@ -1517,10 +1854,17 @@ SWITCH_STANDARD_API(dialplan_lcr_admin_function)
                                stream->write_function(stream, " has intrastate:\t%s\n", profile->profile_has_intrastate ? "true" : "false");
                                stream->write_function(stream, " has intralata:\t%s\n", profile->profile_has_intralata ? "true" : "false");
                                stream->write_function(stream, " has npanxx:\t%s\n", profile->profile_has_npanxx ? "true" : "false");
-                               stream->write_function(stream, " Reorder rate:\t%s\n", profile->reorder_by_rate ? "enabled" : "disabled");
-                               stream->write_function(stream, " Info in headers:\t%s\n", profile->info_in_headers ? "enabled" : "disabled");
-                               stream->write_function(stream, " Sip Redirection Mode:\t%s\n", profile->enable_sip_redir ? "enabled" : "disabled");
-                               stream->write_function(stream, " Quote IN() List:\t%s\n", profile->quote_in_list ? "enabled" : "disabled");
+                               stream->write_function(stream, " Reorder rate:\t%s\n", 
+                                                                               profile->reorder_by_rate ? "enabled" : "disabled");
+                               stream->write_function(stream, " Info in headers:\t%s\n", 
+                                                                               profile->info_in_headers ? "enabled" : "disabled");
+                               stream->write_function(stream, " Quote IN() List:\t%s\n", 
+                                                                               profile->quote_in_list ? "enabled" : "disabled");
+                               stream->write_function(stream, " Sip Redirection Mode:\t%s\n", 
+                                                                               profile->enable_sip_redir ? "enabled" : "disabled");
+                               stream->write_function(stream, " Import fields:\t%s\n", 
+                                       profile->export_fields_str ? profile->export_fields_str : "(null)");
+                               stream->write_function(stream, " Limit type:\t%s\n", profile->limit_type);
                                stream->write_function(stream, "\n");
                        }
                } else {
@@ -1529,20 +1873,20 @@ SWITCH_STANDARD_API(dialplan_lcr_admin_function)
        }
        switch_safe_free(mydata);
        return SWITCH_STATUS_SUCCESS;
-  usage:
+usage:
        switch_safe_free(mydata);
        stream->write_function(stream, "-ERR %s\n", LCR_ADMIN_SYNTAX);
        return SWITCH_STATUS_SUCCESS;
-
+               
 }
-
+       
 SWITCH_MODULE_LOAD_FUNCTION(mod_lcr_load)
 {
        switch_api_interface_t *dialplan_lcr_api_interface;
        switch_api_interface_t *dialplan_lcr_api_admin_interface;
        switch_application_interface_t *app_interface;
        switch_dialplan_interface_t *dp_interface;
-
+       
        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
 
        if (!switch_odbc_available()) {
@@ -1567,6 +1911,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_lcr_load)
                                   lcr_app_function, "<number>", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
        SWITCH_ADD_DIALPLAN(dp_interface, "lcr", lcr_dialplan_hunt);
 
+       lcr_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+       lcr_endpoint_interface->interface_name = "lcr";
+       lcr_endpoint_interface->io_routines = &lcr_io_routines;
+       
        /* indicate that the module should continue to be loaded */
        return SWITCH_STATUS_SUCCESS;
 }