From c59b8876aa0bac400a50172c822497d59255f835 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Sat, 28 Apr 2007 19:52:37 +0000 Subject: [PATCH] Merge changes from team/russell/dundi_results This introduces two new dialplan functions: DUNDIQUERY and DUNDIRESULT. DUNDIQUERY lets you intitiate a DUNDi query from the dialplan. Then, DUNDIRESULT will let you find out how many results there are, and access each one without having to the query again. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@62267 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- CHANGES | 3 + pbx/pbx_dundi.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 197 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index dfa0e7036d..07d7ec52b8 100644 --- a/CHANGES +++ b/CHANGES @@ -69,6 +69,9 @@ DUNDi changes done using a global variable or a dialplan function. Using the SHELL() function would allow you to have an external script set the weight for each response. + * Added two new dialplan functions, DUNDIQUERY and DUNDIRESULT. These + functions will allow you to initiate a DUNDi query from the dialplan, + find out how many results there are, and access each one. Voicemail Changes ----------------- diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index 21a06a079b..ee28d596f3 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -72,6 +72,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astdb.h" #include "asterisk/acl.h" #include "asterisk/aes.h" +#include "asterisk/app.h" #include "dundi-parser.h" @@ -3838,13 +3839,200 @@ static struct ast_custom_function dundi_function = { .syntax = "DUNDILOOKUP(number[|context[|options]])", .desc = "This will do a DUNDi lookup of the given phone number.\n" "If no context is given, the default will be e164. The result of\n" - "this function will the Technology/Resource found in the DUNDi\n" - "lookup. If no results were found, the result will be blank.\n" + "this function will return the Technology/Resource found in the first result\n" + "in the DUNDi lookup. If no results were found, the result will be blank.\n" "If the 'b' option is specified, the internal DUNDi cache will\n" "be bypassed.\n", .read = dundifunc_read, }; +enum { + OPT_BYPASS_CACHE = (1 << 0), +}; + +AST_APP_OPTIONS(dundi_query_opts, BEGIN_OPTIONS + AST_APP_OPTION('b', OPT_BYPASS_CACHE), +END_OPTIONS ); + +unsigned int dundi_result_id; + +struct dundi_result_datastore { + struct dundi_result results[MAX_RESULTS]; + unsigned int num_results; + unsigned int id; +}; + +static void drds_destroy(struct dundi_result_datastore *drds) +{ + free(drds); +} + +static void drds_destroy_cb(void *data) +{ + struct dundi_result_datastore *drds = data; + drds_destroy(drds); +} + +const struct ast_datastore_info dundi_result_datastore_info = { + .type = "DUNDIQUERY", + .destroy = drds_destroy_cb, +}; + +static int dundi_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + struct ast_module_user *u; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(number); + AST_APP_ARG(context); + AST_APP_ARG(options); + ); + struct ast_flags opts = { 0, }; + char *parse; + struct dundi_result_datastore *drds; + struct ast_datastore *datastore; + + u = ast_module_user_add(chan); + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n"); + ast_module_user_remove(u); + return -1; + } + + if (!chan) { + ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n"); + ast_module_user_remove(u); + return -1; + } + + parse = ast_strdupa(data); + + AST_STANDARD_APP_ARGS(args, parse); + + if (!ast_strlen_zero(args.options)) + ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options); + + if (ast_strlen_zero(args.context)) + args.context = "e164"; + + if (!(drds = ast_calloc(1, sizeof(*drds)))) { + ast_module_user_remove(u); + return -1; + } + + drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1); + snprintf(buf, len, "%u", drds->id); + + if (!(datastore = ast_channel_datastore_alloc(&dundi_result_datastore_info, buf))) { + drds_destroy(drds); + ast_module_user_remove(u); + return -1; + } + + datastore->data = drds; + + drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context, + args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE)); + + if (drds->num_results > 0) + sort_results(drds->results, drds->num_results); + + ast_channel_datastore_add(chan, datastore); + + ast_module_user_remove(u); + + return 0; +} + +static struct ast_custom_function dundi_query_function = { + .name = "DUNDIQUERY", + .synopsis = "Initiate a DUNDi query.", + .syntax = "DUNDIQUERY(number[|context[|options]])", + .desc = "This will do a DUNDi lookup of the given phone number.\n" + "If no context is given, the default will be e164. The result of\n" + "this function will be a numeric ID that can be used to retrieve\n" + "the results with the DUNDIRESULT function. If the 'b' option is\n" + "is specified, the internal DUNDi cache will be bypassed.\n", + .read = dundi_query_read, +}; + +static int dundi_result_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + struct ast_module_user *u; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(id); + AST_APP_ARG(resultnum); + ); + char *parse; + unsigned int num; + struct dundi_result_datastore *drds; + struct ast_datastore *datastore; + int res = -1; + + u = ast_module_user_add(chan); + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n"); + goto finish; + } + + if (!chan) { + ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n"); + goto finish; + } + + parse = ast_strdupa(data); + + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_strlen_zero(args.resultnum)) { + ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n"); + goto finish; + } + + if (!(datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id))) { + ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id); + goto finish; + } + drds = datastore->data; + + if (!strcasecmp(args.resultnum, "getnum")) { + snprintf(buf, len, "%u", drds->num_results); + res = 0; + goto finish; + } + + if (sscanf(args.resultnum, "%u", &num) != 1) { + ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n", + args.resultnum); + goto finish; + } + + if (num && num <= drds->num_results) { + snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest); + res = 0; + } else + ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id); + +finish: + ast_module_user_remove(u); + + return res; +} + +static struct ast_custom_function dundi_result_function = { + .name = "DUNDIRESULT", + .synopsis = "Retrieve results from a DUNDIQUERY", + .syntax = "DUNDIRESULT(id|resultnum)", + .desc = "This function will retrieve results from a previous use\n" + "of the DUNDIQUERY function.\n" + " id - This argument is the identifier returned by the DUNDIQUERY function.\n" + " resultnum - This is the number of the result that you want to retrieve.\n" + " Results start at 1. If this argument is specified as \"getnum\",\n" + " then it will return the total number of results that are available.\n", + .read = dundi_result_read, +}; + static void mark_peers(void) { struct dundi_peer *peer; @@ -4526,6 +4714,8 @@ static int unload_module(void) ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry)); ast_unregister_switch(&dundi_switch); ast_custom_function_unregister(&dundi_function); + ast_custom_function_unregister(&dundi_query_function); + ast_custom_function_unregister(&dundi_result_function); sched_context_destroy(sched); return 0; @@ -4590,6 +4780,8 @@ static int load_module(void) if (ast_register_switch(&dundi_switch)) ast_log(LOG_ERROR, "Unable to register DUNDi switch\n"); ast_custom_function_register(&dundi_function); + ast_custom_function_register(&dundi_query_function); + ast_custom_function_register(&dundi_result_function); if (option_verbose > 1) { ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n",