From fcb999c01c22548f582f167e1b1e86f0c3a5a2fd Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Mon, 18 Sep 2006 19:54:18 +0000 Subject: merge qwell's CLI verbification work git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43212 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- pbx/pbx_ael.c | 35 +- pbx/pbx_config.c | 1103 +++++++++++++++++++++++++++++++++++++++++++++++------- pbx/pbx_dundi.c | 137 ++++--- 3 files changed, 1050 insertions(+), 225 deletions(-) (limited to 'pbx') diff --git a/pbx/pbx_ael.c b/pbx/pbx_ael.c index c45f73601..cbef91f6a 100644 --- a/pbx/pbx_ael.c +++ b/pbx/pbx_ael.c @@ -3861,25 +3861,42 @@ static int ael2_reload(int fd, int argc, char *argv[]) return (pbx_load_module()); } -static struct ast_cli_entry ael_cli[] = { - { { "ael", "reload", NULL }, ael2_reload, "Reload AEL configuration"}, - { { "ael", "debug", "read", NULL }, ael2_debug_read, "Enable AEL read debug (does nothing)"}, - { { "ael", "debug", "tokens", NULL }, ael2_debug_tokens, "Enable AEL tokens debug (does nothing)"}, - { { "ael", "debug", "macros", NULL }, ael2_debug_macros, "Enable AEL macros debug (does nothing)"}, - { { "ael", "debug", "contexts", NULL }, ael2_debug_contexts, "Enable AEL contexts debug (does nothing)"}, - { { "ael", "no", "debug", NULL }, ael2_no_debug, "Disable AEL debug messages"}, +static struct ast_cli_entry cli_ael_no_debug = { + { "ael", "no", "debug", NULL }, + ael2_no_debug, NULL, + NULL }; + +static struct ast_cli_entry cli_ael[] = { + { { "ael", "reload", NULL }, + ael2_reload, "Reload AEL configuration" }, + + { { "ael", "debug", "read", NULL }, + ael2_debug_read, "Enable AEL read debug (does nothing)" }, + + { { "ael", "debug", "tokens", NULL }, + ael2_debug_tokens, "Enable AEL tokens debug (does nothing)" }, + + { { "ael", "debug", "macros", NULL }, + ael2_debug_macros, "Enable AEL macros debug (does nothing)" }, + + { { "ael", "debug", "contexts", NULL }, + ael2_debug_contexts, "Enable AEL contexts debug (does nothing)" }, + + { { "ael", "nodebug", NULL }, + ael2_no_debug, "Disable AEL debug messages", + NULL, NULL, &cli_ael_no_debug }, }; static int unload_module(void) { ast_context_destroy(NULL, registrar); - ast_cli_unregister_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0])); + ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry)); return 0; } static int load_module(void) { - ast_cli_register_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0])); + ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry)); return (pbx_load_module()); } diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index e63ab74ae..801438ffd 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -58,55 +58,54 @@ static struct ast_context *local_contexts = NULL; /* * Help for commands provided by this module ... */ -static char context_dont_include_help[] = -"Usage: dont include in \n" -" Remove an included context from another context.\n"; - -static char context_remove_extension_help[] = -"Usage: remove extension exten@context [priority]\n" -" Remove an extension from a given context. If a priority\n" -" is given, only that specific priority from the given extension\n" -" will be removed.\n"; - -static char context_add_include_help[] = -"Usage: include in \n" -" Include a context in another context.\n"; - -static char save_dialplan_help[] = -"Usage: save dialplan [/path/to/extension/file]\n" -" Save dialplan created by pbx_config module.\n" -"\n" -"Example: save dialplan (/etc/asterisk/extensions.conf)\n" -" save dialplan /home/markster (/home/markster/extensions.conf)\n"; - static char context_add_extension_help[] = -"Usage: add extension ,,, into \n" -" [replace]\n\n" +"Usage: dialplan add extension ,,,\n" +" into [replace]\n\n" " This command will add new extension into . If there is an\n" " existence of extension with the same priority and last 'replace'\n" " arguments is given here we simply replace this extension.\n" "\n" -"Example: add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n" +"Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n" " Now, you can dial 6123 and talk to Markster :)\n"; +static char context_remove_extension_help[] = +"Usage: dialplan remove extension exten@context [priority]\n" +" Remove an extension from a given context. If a priority\n" +" is given, only that specific priority from the given extension\n" +" will be removed.\n"; + static char context_add_ignorepat_help[] = -"Usage: add ignorepat into \n" +"Usage: dialplan add ignorepat into \n" " This command adds a new ignore pattern into context \n" "\n" -"Example: add ignorepat _3XX into local\n"; +"Example: dialplan add ignorepat _3XX into local\n"; static char context_remove_ignorepat_help[] = -"Usage: remove ignorepat from \n" +"Usage: dialplan remove ignorepat from \n" " This command removes an ignore pattern from context \n" "\n" -"Example: remove ignorepat _3XX from local\n"; +"Example: dialplan remove ignorepat _3XX from local\n"; + +static char context_add_include_help[] = +"Usage: dialplan add include into \n" +" Include a context in another context.\n"; + +static char context_remove_include_help[] = +"Usage: dialplan remove include from \n" +" Remove an included context from another context.\n"; + +static char save_dialplan_help[] = +"Usage: dialplan save [/path/to/extension/file]\n" +" Save dialplan created by pbx_config module.\n" +"\n" +"Example: dialplan save (/etc/asterisk/extensions.conf)\n" +" dialplan save /home/markster (/home/markster/extensions.conf)\n"; static char reload_extensions_help[] = -"Usage: reload extensions.conf without reloading any other modules\n" +"Usage: dialplan reload\n" +" reload extensions.conf without reloading any other modules\n" " This command does not delete global variables unless\n" -" clearglobalvars is set to yes in extensions.conf\n" -"\n" -"Example: extensions reload\n"; +" clearglobalvars is set to yes in extensions.conf\n"; /* * Implementation of functions provided by this module @@ -115,16 +114,16 @@ static char reload_extensions_help[] = /*! * REMOVE INCLUDE command stuff */ -static int handle_context_dont_include(int fd, int argc, char *argv[]) +static int handle_context_dont_include_deprecated(int fd, int argc, char *argv[]) { if (argc != 5) return RESULT_SHOWUSAGE; - if (strcmp(argv[3], "in")) + if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE; if (!ast_context_remove_include(argv[4], argv[2], registrar)) { - ast_cli(fd, "We are not including '%s' in '%s' now\n", + ast_cli(fd, "We are not including '%s' into '%s' now\n", argv[2], argv[4]); return RESULT_SUCCESS; } @@ -134,6 +133,25 @@ static int handle_context_dont_include(int fd, int argc, char *argv[]) return RESULT_FAILURE; } +static int handle_context_remove_include(int fd, int argc, char *argv[]) +{ + if (argc != 6) + return RESULT_SHOWUSAGE; + + if (strcmp(argv[4], "into")) + return RESULT_SHOWUSAGE; + + if (!ast_context_remove_include(argv[5], argv[3], registrar)) { + ast_cli(fd, "We are not including '%s' into '%s' now\n", + argv[3], argv[5]); + return RESULT_SUCCESS; + } + + ast_cli(fd, "Failed to remove '%s' include from '%s' context\n", + argv[3], argv[5]); + return RESULT_FAILURE; +} + /*! \brief return true if 'name' is included by context c */ static int lookup_ci(struct ast_context *c, const char *name) { @@ -209,7 +227,7 @@ static int split_ec(const char *src, char **ext, char ** const ctx) } /* _X_ is the string we need to complete */ -static char *complete_context_dont_include(const char *line, const char *word, +static char *complete_context_dont_include_deprecated(const char *line, const char *word, int pos, int state) { int which = 0; @@ -330,10 +348,131 @@ static char *complete_context_dont_include(const char *line, const char *word, return NULL; } +static char *complete_context_remove_include(const char *line, const char *word, + int pos, int state) +{ + int which = 0; + char *res = NULL; + int len = strlen(word); /* how many bytes to match */ + struct ast_context *c = NULL; + + if (pos == 3) { /* "dialplan remove include _X_" */ + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock context list\n"); + return NULL; + } + /* walk contexts and their includes, return the n-th match */ + while (!res && (c = ast_walk_contexts(c))) { + struct ast_include *i = NULL; + + if (ast_lock_context(c)) /* error ? skip this one */ + continue; + + while ( !res && (i = ast_walk_context_includes(c, i)) ) { + const char *i_name = ast_get_include_name(i); + struct ast_context *nc = NULL; + int already_served = 0; + + if (!partial_match(i_name, word, len)) + continue; /* not matched */ + + /* check if this include is already served or not */ + + /* go through all contexts again till we reach actual + * context or already_served = 1 + */ + while ( (nc = ast_walk_contexts(nc)) && nc != c && !already_served) + already_served = lookup_ci(nc, i_name); + + if (!already_served && ++which > state) + res = strdup(i_name); + } + ast_unlock_context(c); + } + + ast_unlock_contexts(); + return res; + } else if (pos == 4) { /* "dialplan remove include CTX _X_" */ + /* + * complete as 'from', but only if previous context is really + * included somewhere + */ + char *context, *dupline; + const char *s = skip_words(line, 3); /* skip 'dialplan' 'remove' 'include' */ + + if (state > 0) + return NULL; + context = dupline = strdup(s); + if (!dupline) { + ast_log(LOG_ERROR, "Out of free memory\n"); + return NULL; + } + strsep(&dupline, " "); + + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock contexts list\n"); + free(context); + return NULL; + } + + /* go through all contexts and check if is included ... */ + while (!res && (c = ast_walk_contexts(c))) + if (lookup_ci(c, context)) /* context is really included, complete "from" command */ + res = strdup("from"); + ast_unlock_contexts(); + if (!res) + ast_log(LOG_WARNING, "%s not included anywhere\n", context); + free(context); + return res; + } else if (pos == 5) { /* "dialplan remove include CTX from _X_" */ + /* + * Context from which we removing include ... + */ + char *context, *dupline, *from; + const char *s = skip_words(line, 3); /* skip 'dialplan' 'remove' 'include' */ + context = dupline = strdup(s); + if (!dupline) { + ast_log(LOG_ERROR, "Out of free memory\n"); + return NULL; + } + + strsep(&dupline, " "); /* skip context */ + + /* fourth word must be 'from' */ + from = strsep(&dupline, " "); + if (!from || strcmp(from, "from")) { + free(context); + return NULL; + } + + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock context list\n"); + free(context); + return NULL; + } + + /* walk through all contexts ... */ + c = NULL; + while ( !res && (c = ast_walk_contexts(c))) { + const char *c_name = ast_get_context_name(c); + if (!partial_match(c_name, word, len)) /* not a good target */ + continue; + /* walk through all includes and check if it is our context */ + if (lookup_ci(c, context) && ++which > state) + res = strdup(c_name); + } + ast_unlock_contexts(); + free(context); + return res; + } + + return NULL; +} + /*! * REMOVE EXTENSION command stuff */ -static int handle_context_remove_extension(int fd, int argc, char *argv[]) +static int handle_context_remove_extension_deprecated(int fd, int argc, char *argv[]) { int removing_priority = 0; char *exten, *context; @@ -400,6 +539,73 @@ static int handle_context_remove_extension(int fd, int argc, char *argv[]) return ret; } +static int handle_context_remove_extension(int fd, int argc, char *argv[]) +{ + int removing_priority = 0; + char *exten, *context; + int ret = RESULT_FAILURE; + + if (argc != 5 && argc != 4) return RESULT_SHOWUSAGE; + + /* + * Priority input checking ... + */ + if (argc == 5) { + char *c = argv[4]; + + /* check for digits in whole parameter for right priority ... + * why? because atoi (strtol) returns 0 if any characters in + * string and whole extension will be removed, it's not good + */ + if (!strcmp("hint", c)) + removing_priority = PRIORITY_HINT; + else { + while (*c && isdigit(*c)) + c++; + if (*c) { /* non-digit in string */ + ast_cli(fd, "Invalid priority '%s'\n", argv[4]); + return RESULT_FAILURE; + } + removing_priority = atoi(argv[4]); + } + + if (removing_priority == 0) { + ast_cli(fd, "If you want to remove whole extension, please " \ + "omit priority argument\n"); + return RESULT_FAILURE; + } + } + + /* XXX original overwrote argv[3] */ + /* + * Format exten@context checking ... + */ + if (split_ec(argv[3], &exten, &context)) + return RESULT_FAILURE; /* XXX malloc failure */ + if ((!strlen(exten)) || (!(strlen(context)))) { + ast_cli(fd, "Missing extension or context name in third argument '%s'\n", + argv[3]); + free(exten); + return RESULT_FAILURE; + } + + if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) { + if (!removing_priority) + ast_cli(fd, "Whole extension %s@%s removed\n", + exten, context); + else + ast_cli(fd, "Extension %s@%s with priority %d removed\n", + exten, context, removing_priority); + + ret = RESULT_SUCCESS; + } else { + ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context); + ret = RESULT_FAILURE; + } + free(exten); + return ret; +} + #define BROKEN_READLINE 1 #ifdef BROKEN_READLINE @@ -447,7 +653,7 @@ static int fix_complete_args(const char *line, char **word, int *pos) } #endif /* BROKEN_READLINE */ -static char *complete_context_remove_extension(const char *line, const char *word, int pos, +static char *complete_context_remove_extension_deprecated(const char *line, const char *word, int pos, int state) { char *ret = NULL; @@ -569,29 +775,151 @@ static char *complete_context_remove_extension(const char *line, const char *wor return ret; } -/*! - * Include context ... - */ -static int handle_context_add_include(int fd, int argc, char *argv[]) +static char *complete_context_remove_extension(const char *line, const char *word, int pos, + int state) { - if (argc != 5) /* include context CTX in CTX */ - return RESULT_SHOWUSAGE; + char *ret = NULL; + int which = 0; - /* third arg must be 'in' ... */ - if (strcmp(argv[3], "in") && strcmp(argv[3], "into")) /* XXX why both ? */ - return RESULT_SHOWUSAGE; +#ifdef BROKEN_READLINE + char *word2; + /* + * Fix arguments, *word is a new allocated structure, REMEMBER to + * free *word when you want to return from this function ... + */ + if (fix_complete_args(line, &word2, &pos)) { + ast_log(LOG_ERROR, "Out of free memory\n"); + return NULL; + } + word = word2; +#endif - if (ast_context_add_include(argv[4], argv[2], registrar)) { - switch (errno) { - case ENOMEM: - ast_cli(fd, "Out of memory for context addition\n"); - break; + if (pos == 3) { /* 'dialplan remove extension _X_' (exten@context ... */ + struct ast_context *c = NULL; + char *context = NULL, *exten = NULL; + int le = 0; /* length of extension */ + int lc = 0; /* length of context */ - case EBUSY: - ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); - break; + lc = split_ec(word, &exten, &context); +#ifdef BROKEN_READLINE + free(word2); +#endif + if (lc) /* error */ + return NULL; + le = strlen(exten); + lc = strlen(context); - case EEXIST: + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock context list\n"); + goto error2; + } + + /* find our context ... */ + while ( (c = ast_walk_contexts(c)) ) { /* match our context if any */ + struct ast_exten *e = NULL; + /* XXX locking ? */ + if (!partial_match(ast_get_context_name(c), context, lc)) + continue; /* context not matched */ + while ( (e = ast_walk_context_extensions(c, e)) ) { /* try to complete extensions ... */ + if ( partial_match(ast_get_extension_name(e), exten, le) && ++which > state) { /* n-th match */ + /* If there is an extension then return exten@context. XXX otherwise ? */ + if (exten) + asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c)); + break; + } + } + if (e) /* got a match */ + break; + } + + ast_unlock_contexts(); + error2: + if (exten) + free(exten); + } else if (pos == 4) { /* 'dialplan remove extension EXT _X_' (priority) */ + char *exten = NULL, *context, *p; + struct ast_context *c; + int le, lc, len; + const char *s = skip_words(line, 3); /* skip 'dialplan' 'remove' 'extension' */ + int i = split_ec(s, &exten, &context); /* parse ext@context */ + + if (i) /* error */ + goto error3; + if ( (p = strchr(exten, ' ')) ) /* remove space after extension */ + *p = '\0'; + if ( (p = strchr(context, ' ')) ) /* remove space after context */ + *p = '\0'; + le = strlen(exten); + lc = strlen(context); + len = strlen(word); + if (le == 0 || lc == 0) + goto error3; + + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock context list\n"); + goto error3; + } + + /* walk contexts */ + c = NULL; + while ( (c = ast_walk_contexts(c)) ) { + /* XXX locking on c ? */ + struct ast_exten *e; + if (strcmp(ast_get_context_name(c), context) != 0) + continue; + /* got it, we must match here */ + e = NULL; + while ( (e = ast_walk_context_extensions(c, e)) ) { + struct ast_exten *priority; + char buffer[10]; + + if (strcmp(ast_get_extension_name(e), exten) != 0) + continue; + /* XXX lock e ? */ + priority = NULL; + while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) { + snprintf(buffer, sizeof(buffer), "%u", ast_get_extension_priority(priority)); + if (partial_match(buffer, word, len) && ++which > state) /* n-th match */ + ret = strdup(buffer); + } + break; + } + break; + } + ast_unlock_contexts(); + error3: + if (exten) + free(exten); +#ifdef BROKEN_READLINE + free(word2); +#endif + } + return ret; +} + +/*! + * Include context ... + */ +static int handle_context_add_include_deprecated(int fd, int argc, char *argv[]) +{ + if (argc != 5) /* include context CTX in CTX */ + return RESULT_SHOWUSAGE; + + /* third arg must be 'in' ... */ + if (strcmp(argv[3], "in") && strcmp(argv[3], "into")) /* XXX why both ? */ + return RESULT_SHOWUSAGE; + + if (ast_context_add_include(argv[4], argv[2], registrar)) { + switch (errno) { + case ENOMEM: + ast_cli(fd, "Out of memory for context addition\n"); + break; + + case EBUSY: + ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); + break; + + case EEXIST: ast_cli(fd, "Context '%s' already included in '%s' context\n", argv[2], argv[4]); break; @@ -617,7 +945,52 @@ static int handle_context_add_include(int fd, int argc, char *argv[]) return RESULT_SUCCESS; } -static char *complete_context_add_include(const char *line, const char *word, int pos, +static int handle_context_add_include(int fd, int argc, char *argv[]) +{ + if (argc != 6) /* dialplan add include CTX in CTX */ + return RESULT_SHOWUSAGE; + + /* fifth arg must be 'into' ... */ + if (strcmp(argv[4], "into")) + return RESULT_SHOWUSAGE; + + if (ast_context_add_include(argv[5], argv[3], registrar)) { + switch (errno) { + case ENOMEM: + ast_cli(fd, "Out of memory for context addition\n"); + break; + + case EBUSY: + ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); + break; + + case EEXIST: + ast_cli(fd, "Context '%s' already included in '%s' context\n", + argv[3], argv[5]); + break; + + case ENOENT: + case EINVAL: + ast_cli(fd, "There is no existence of context '%s'\n", + errno == ENOENT ? argv[5] : argv[3]); + break; + + default: + ast_cli(fd, "Failed to include '%s' in '%s' context\n", + argv[3], argv[5]); + break; + } + return RESULT_FAILURE; + } + + /* show some info ... */ + ast_cli(fd, "Context '%s' included in '%s' context\n", + argv[3], argv[5]); + + return RESULT_SUCCESS; +} + +static char *complete_context_add_include_deprecated(const char *line, const char *word, int pos, int state) { struct ast_context *c; @@ -712,6 +1085,101 @@ static char *complete_context_add_include(const char *line, const char *word, in return NULL; } +static char *complete_context_add_include(const char *line, const char *word, int pos, + int state) +{ + struct ast_context *c; + int which = 0; + char *ret = NULL; + int len = strlen(word); + + if (pos == 3) { /* 'dialplan add include _X_' (context) ... */ + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock context list\n"); + return NULL; + } + for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) + if (partial_match(ast_get_context_name(c), word, len) && ++which > state) + ret = strdup(ast_get_context_name(c)); + ast_unlock_contexts(); + return ret; + } else if (pos == 4) { /* dialplan add include CTX _X_ */ + /* complete as 'into' if context exists or we are unable to check */ + char *context, *dupline; + struct ast_context *c; + const char *s = skip_words(line, 3); /* should not fail */ + + if (state != 0) /* only once */ + return NULL; + + /* parse context from line ... */ + context = dupline = strdup(s); + if (!context) { + ast_log(LOG_ERROR, "Out of free memory\n"); + return strdup("into"); + } + strsep(&dupline, " "); + + /* check for context existence ... */ + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock context list\n"); + /* our fault, we can't check, so complete 'into' ... */ + ret = strdup("into"); + } else { + for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) + if (!strcmp(context, ast_get_context_name(c))) + ret = strdup("into"); /* found */ + ast_unlock_contexts(); + } + free(context); + return ret; + } else if (pos == 5) { /* 'dialplan add include CTX into _X_' (dst context) */ + char *context, *dupline, *into; + const char *s = skip_words(line, 3); /* should not fail */ + context = dupline = strdup(s); + if (!dupline) { + ast_log(LOG_ERROR, "Out of free memory\n"); + return NULL; + } + strsep(&dupline, " "); /* skip context */ + into = strsep(&dupline, " "); + /* error if missing context or fifth word is not 'into' */ + if (!strlen(context) || strcmp(into, "into")) { + ast_log(LOG_ERROR, "bad context %s or missing into %s\n", + context, into); + goto error3; + } + + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock context list\n"); + goto error3; + } + + for (c = NULL; (c = ast_walk_contexts(c)); ) + if (!strcmp(context, ast_get_context_name(c))) + break; + if (c) { /* first context exists, go on... */ + /* go through all contexts ... */ + for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) { + if (!strcmp(context, ast_get_context_name(c))) + continue; /* skip ourselves */ + if (partial_match(ast_get_context_name(c), word, len) && + !lookup_ci(c, context) /* not included yet */ && + ++which > state) + ret = strdup(ast_get_context_name(c)); + } + } else { + ast_log(LOG_ERROR, "context %s not found\n", context); + } + ast_unlock_contexts(); + error3: + free(context); + return ret; + } + + return NULL; +} + /*! * \brief 'save dialplan' CLI command implementation functions ... */ @@ -936,7 +1404,7 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) /*! * \brief ADD EXTENSION command stuff */ -static int handle_context_add_extension(int fd, int argc, char *argv[]) +static int handle_context_add_extension_deprecated(int fd, int argc, char *argv[]) { char *whole_exten; char *exten, *prior; @@ -1029,31 +1497,123 @@ static int handle_context_add_extension(int fd, int argc, char *argv[]) return RESULT_SUCCESS; } - -/*! add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */ -static char *complete_context_add_extension(const char *line, const char *word, - int pos, int state) +static int handle_context_add_extension(int fd, int argc, char *argv[]) { - int which = 0; - - if (pos == 3) { /* complete 'into' word ... */ - return (state == 0) ? strdup("into") : NULL; - } else if (pos == 4) { /* complete context */ - struct ast_context *c = NULL; - int len = strlen(word); - char *res = NULL; + char *whole_exten; + char *exten, *prior; + int iprior = -2; + char *cidmatch, *app, *app_data; + char *start, *end; - /* try to lock contexts list ... */ - if (ast_lock_contexts()) { - ast_log(LOG_WARNING, "Failed to lock contexts list\n"); - return NULL; - } + /* check for arguments at first */ + if (argc != 6 && argc != 7) + return RESULT_SHOWUSAGE; + if (strcmp(argv[3], "into")) + return RESULT_SHOWUSAGE; + if (argc == 7) if (strcmp(argv[6], "replace")) return RESULT_SHOWUSAGE; - /* walk through all contexts */ - while ( !res && (c = ast_walk_contexts(c)) ) - if (partial_match(ast_get_context_name(c), word, len) && ++which > state) - res = strdup(ast_get_context_name(c)); - ast_unlock_contexts(); + /* XXX overwrite argv[3] */ + whole_exten = argv[3]; + exten = strsep(&whole_exten,","); + if (strchr(exten, '/')) { + cidmatch = exten; + strsep(&cidmatch,"/"); + } else { + cidmatch = NULL; + } + prior = strsep(&whole_exten,","); + if (prior) { + if (!strcmp(prior, "hint")) { + iprior = PRIORITY_HINT; + } else { + if (sscanf(prior, "%d", &iprior) != 1) { + ast_cli(fd, "'%s' is not a valid priority\n", prior); + prior = NULL; + } + } + } + app = whole_exten; + if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) { + *start = *end = '\0'; + app_data = start + 1; + ast_process_quotes_and_slashes(app_data, ',', '|'); + } else { + if (app) { + app_data = strchr(app, ','); + if (app_data) { + *app_data = '\0'; + app_data++; + } + } else + app_data = NULL; + } + + if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) + return RESULT_SHOWUSAGE; + + if (!app_data) + app_data=""; + if (ast_add_extension(argv[5], argc == 6 ? 1 : 0, exten, iprior, NULL, cidmatch, app, + (void *)strdup(app_data), free, registrar)) { + switch (errno) { + case ENOMEM: + ast_cli(fd, "Out of free memory\n"); + break; + + case EBUSY: + ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); + break; + + case ENOENT: + ast_cli(fd, "No existence of '%s' context\n", argv[5]); + break; + + case EEXIST: + ast_cli(fd, "Extension %s@%s with priority %s already exists\n", + exten, argv[5], prior); + break; + + default: + ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n", + exten, prior, app, app_data, argv[5]); + break; + } + return RESULT_FAILURE; + } + + if (argc == 7) + ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n", + exten, argv[5], prior, exten, prior, app, app_data); + else + ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n", + exten, prior, app, app_data, argv[5]); + + return RESULT_SUCCESS; +} + +/*! dialplan add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */ +static char *complete_context_add_extension_deprecated(const char *line, const char *word, int pos, int state) +{ + int which = 0; + + if (pos == 3) { /* complete 'into' word ... */ + return (state == 0) ? strdup("into") : NULL; + } else if (pos == 4) { /* complete context */ + struct ast_context *c = NULL; + int len = strlen(word); + char *res = NULL; + + /* try to lock contexts list ... */ + if (ast_lock_contexts()) { + ast_log(LOG_WARNING, "Failed to lock contexts list\n"); + return NULL; + } + + /* walk through all contexts */ + while ( !res && (c = ast_walk_contexts(c)) ) + if (partial_match(ast_get_context_name(c), word, len) && ++which > state) + res = strdup(ast_get_context_name(c)); + ast_unlock_contexts(); return res; } else if (pos == 5) { return state == 0 ? strdup("replace") : NULL; @@ -1061,10 +1621,39 @@ static char *complete_context_add_extension(const char *line, const char *word, return NULL; } +static char *complete_context_add_extension(const char *line, const char *word, int pos, int state) +{ + int which = 0; + + if (pos == 4) { /* complete 'into' word ... */ + return (state == 0) ? strdup("into") : NULL; + } else if (pos == 5) { /* complete context */ + struct ast_context *c = NULL; + int len = strlen(word); + char *res = NULL; + + /* try to lock contexts list ... */ + if (ast_lock_contexts()) { + ast_log(LOG_WARNING, "Failed to lock contexts list\n"); + return NULL; + } + + /* walk through all contexts */ + while ( !res && (c = ast_walk_contexts(c)) ) + if (partial_match(ast_get_context_name(c), word, len) && ++which > state) + res = strdup(ast_get_context_name(c)); + ast_unlock_contexts(); + return res; + } else if (pos == 6) { + return state == 0 ? strdup("replace") : NULL; + } + return NULL; +} + /*! * IGNOREPAT CLI stuff */ -static int handle_context_add_ignorepat(int fd, int argc, char *argv[]) +static int handle_context_add_ignorepat_deprecated(int fd, int argc, char *argv[]) { if (argc != 5) return RESULT_SHOWUSAGE; @@ -1103,7 +1692,46 @@ static int handle_context_add_ignorepat(int fd, int argc, char *argv[]) return RESULT_SUCCESS; } -static char *complete_context_add_ignorepat(const char *line, const char *word, +static int handle_context_add_ignorepat(int fd, int argc, char *argv[]) +{ + if (argc != 6) + return RESULT_SHOWUSAGE; + if (strcmp(argv[4], "into")) + return RESULT_SHOWUSAGE; + + if (ast_context_add_ignorepat(argv[5], argv[3], registrar)) { + switch (errno) { + case ENOMEM: + ast_cli(fd, "Out of free memory\n"); + break; + + case ENOENT: + ast_cli(fd, "There is no existence of '%s' context\n", argv[5]); + break; + + case EEXIST: + ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n", + argv[3], argv[5]); + break; + + case EBUSY: + ast_cli(fd, "Failed to lock context(s) list, please, try again later\n"); + break; + + default: + ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n", + argv[3], argv[5]); + break; + } + return RESULT_FAILURE; + } + + ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n", + argv[3], argv[5]); + return RESULT_SUCCESS; +} + +static char *complete_context_add_ignorepat_deprecated(const char *line, const char *word, int pos, int state) { if (pos == 3) @@ -1152,7 +1780,56 @@ static char *complete_context_add_ignorepat(const char *line, const char *word, return NULL; } -static int handle_context_remove_ignorepat(int fd, int argc, char *argv[]) +static char *complete_context_add_ignorepat(const char *line, const char *word, + int pos, int state) +{ + if (pos == 4) + return state == 0 ? strdup("into") : NULL; + else if (pos == 5) { + struct ast_context *c; + int which = 0; + char *dupline, *ignorepat = NULL; + const char *s; + char *ret = NULL; + int len = strlen(word); + + /* XXX skip first three words 'dialplan' 'add' 'ignorepat' */ + s = skip_words(line, 3); + if (s == NULL) + return NULL; + dupline = strdup(s); + if (!dupline) { + ast_log(LOG_ERROR, "Malloc failure\n"); + return NULL; + } + ignorepat = strsep(&dupline, " "); + + if (ast_lock_contexts()) { + ast_log(LOG_ERROR, "Failed to lock contexts list\n"); + return NULL; + } + + for (c = NULL; !ret && (c = ast_walk_contexts(c));) { + int found = 0; + + if (!partial_match(ast_get_context_name(c), word, len)) + continue; /* not mine */ + if (ignorepat) /* there must be one, right ? */ + found = lookup_c_ip(c, ignorepat); + if (!found && ++which > state) + ret = strdup(ast_get_context_name(c)); + } + + if (ignorepat) + free(ignorepat); + ast_unlock_contexts(); + return ret; + } + + return NULL; +} + +static int handle_context_remove_ignorepat_deprecated(int fd, int argc, char *argv[]) { if (argc != 5) return RESULT_SHOWUSAGE; @@ -1186,17 +1863,41 @@ static int handle_context_remove_ignorepat(int fd, int argc, char *argv[]) return RESULT_SUCCESS; } -static int pbx_load_module(void); - -static int handle_reload_extensions(int fd, int argc, char *argv[]) +static int handle_context_remove_ignorepat(int fd, int argc, char *argv[]) { - if (argc!=2) + if (argc != 6) return RESULT_SHOWUSAGE; - pbx_load_module(); + if (strcmp(argv[4], "from")) + return RESULT_SHOWUSAGE; + + if (ast_context_remove_ignorepat(argv[5], argv[3], registrar)) { + switch (errno) { + case EBUSY: + ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); + break; + + case ENOENT: + ast_cli(fd, "There is no existence of '%s' context\n", argv[5]); + break; + + case EINVAL: + ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n", + argv[3], argv[5]); + break; + + default: + ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[3], argv[5]); + break; + } + return RESULT_FAILURE; + } + + ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n", + argv[3], argv[5]); return RESULT_SUCCESS; } -static char *complete_context_remove_ignorepat(const char *line, const char *word, +static char *complete_context_remove_ignorepat_deprecated(const char *line, const char *word, int pos, int state) { struct ast_context *c; @@ -1278,61 +1979,185 @@ static char *complete_context_remove_ignorepat(const char *line, const char *wor return NULL; } +static char *complete_context_remove_ignorepat(const char *line, const char *word, + int pos, int state) +{ + struct ast_context *c; + int which = 0; + char *ret = NULL; + + if (pos == 3) { + int len = strlen(word); + if (ast_lock_contexts()) { + ast_log(LOG_WARNING, "Failed to lock contexts list\n"); + return NULL; + } + + for (c = NULL; !ret && (c = ast_walk_contexts(c));) { + struct ast_ignorepat *ip; + + if (ast_lock_context(c)) /* error, skip it */ + continue; + + for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) { + if (partial_match(ast_get_ignorepat_name(ip), word, len) && ++which > state) { + /* n-th match */ + struct ast_context *cw = NULL; + int found = 0; + while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) { + /* XXX do i stop on c, or skip it ? */ + found = lookup_c_ip(cw, ast_get_ignorepat_name(ip)); + } + if (!found) + ret = strdup(ast_get_ignorepat_name(ip)); + } + } + ast_unlock_context(c); + } + ast_unlock_contexts(); + return ret; + } else if (pos == 4) { + return state == 0 ? strdup("from") : NULL; + } else if (pos == 5) { /* XXX check this */ + char *dupline, *duplinet, *ignorepat; + int len = strlen(word); + + dupline = strdup(line); + if (!dupline) { + ast_log(LOG_WARNING, "Out of free memory\n"); + return NULL; + } + + duplinet = dupline; + strsep(&duplinet, " "); + strsep(&duplinet, " "); + ignorepat = strsep(&duplinet, " "); + + if (!ignorepat) { + free(dupline); + return NULL; + } + + if (ast_lock_contexts()) { + ast_log(LOG_WARNING, "Failed to lock contexts list\n"); + free(dupline); + return NULL; + } + + for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) { + if (ast_lock_context(c)) /* fail, skip it */ + continue; + if (!partial_match(ast_get_context_name(c), word, len)) + continue; + if (lookup_c_ip(c, ignorepat) && ++which > state) + ret = strdup(ast_get_context_name(c)); + ast_unlock_context(c); + } + ast_unlock_contexts(); + free(dupline); + return NULL; + } + + return NULL; +} + +static int pbx_load_module(void); + +static int handle_reload_extensions(int fd, int argc, char *argv[]) +{ + if (argc != 2) + return RESULT_SHOWUSAGE; + pbx_load_module(); + return RESULT_SUCCESS; +} + /*! * CLI entries for commands provided by this module */ -static struct ast_cli_entry context_dont_include_cli = - { { "dont", "include", NULL }, handle_context_dont_include, - "Remove a specified include from context", context_dont_include_help, - complete_context_dont_include }; - -static struct ast_cli_entry context_remove_extension_cli = - { { "remove", "extension", NULL }, handle_context_remove_extension, - "Remove a specified extension", context_remove_extension_help, - complete_context_remove_extension }; - -static struct ast_cli_entry context_add_include_cli = - { { "include", "context", NULL }, handle_context_add_include, - "Include context in other context", context_add_include_help, - complete_context_add_include }; - -static struct ast_cli_entry save_dialplan_cli = - { { "save", "dialplan", NULL }, handle_save_dialplan, - "Save dialplan", save_dialplan_help }; - -static struct ast_cli_entry context_add_extension_cli = - { { "add", "extension", NULL }, handle_context_add_extension, - "Add new extension into context", context_add_extension_help, - complete_context_add_extension }; - -static struct ast_cli_entry context_add_ignorepat_cli = - { { "add", "ignorepat", NULL }, handle_context_add_ignorepat, - "Add new ignore pattern", context_add_ignorepat_help, - complete_context_add_ignorepat }; - -static struct ast_cli_entry context_remove_ignorepat_cli = - { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat, - "Remove ignore pattern from context", context_remove_ignorepat_help, - complete_context_remove_ignorepat }; - -static struct ast_cli_entry reload_extensions_cli = - { { "extensions", "reload", NULL}, handle_reload_extensions, - "Reload extensions and *only* extensions", reload_extensions_help }; +static struct ast_cli_entry cli_dont_include_deprecated = { + { "dont", "include", NULL }, + handle_context_dont_include_deprecated, NULL, + NULL, complete_context_dont_include_deprecated }; + +static struct ast_cli_entry cli_remove_extension_deprecated = { + { "remove", "extension", NULL }, + handle_context_remove_extension_deprecated, NULL, + NULL, complete_context_remove_extension_deprecated }; + +static struct ast_cli_entry cli_include_context_deprecated = { + { "include", "context", NULL }, + handle_context_add_include_deprecated, NULL, + NULL, complete_context_add_include_deprecated }; + +static struct ast_cli_entry cli_add_extension_deprecated = { + { "add", "extension", NULL }, + handle_context_add_extension_deprecated, NULL, + NULL, complete_context_add_extension_deprecated }; + +static struct ast_cli_entry cli_add_ignorepat_deprecated = { + { "add", "ignorepat", NULL }, + handle_context_add_ignorepat_deprecated, NULL, + NULL, complete_context_add_ignorepat_deprecated }; + +static struct ast_cli_entry cli_remove_ignorepat_deprecated = { + { "remove", "ignorepat", NULL }, + handle_context_remove_ignorepat_deprecated, NULL, + NULL, complete_context_remove_ignorepat_deprecated }; + +static struct ast_cli_entry cli_extensions_reload_deprecated = { + { "extensions", "reload", NULL }, + handle_reload_extensions, NULL, + NULL }; + +static struct ast_cli_entry cli_save_dialplan_deprecated = { + { "save", "dialplan", NULL }, + handle_save_dialplan, NULL, + NULL }; + +static struct ast_cli_entry cli_pbx_config[] = { + { { "dialplan", "add", "extension", NULL }, + handle_context_add_extension, "Add new extension into context", + context_add_extension_help, complete_context_add_extension, &cli_add_extension_deprecated }, + + { { "dialplan", "remove", "extension", NULL }, + handle_context_remove_extension, "Remove a specified extension", + context_remove_extension_help, complete_context_remove_extension, &cli_remove_extension_deprecated }, + + { { "dialplan", "add", "ignorepat", NULL }, + handle_context_add_ignorepat, "Add new ignore pattern", + context_add_ignorepat_help, complete_context_add_ignorepat, &cli_add_ignorepat_deprecated }, + + { { "dialplan", "remove", "ignorepat", NULL }, + handle_context_remove_ignorepat, "Remove ignore pattern from context", + context_remove_ignorepat_help, complete_context_remove_ignorepat, &cli_remove_ignorepat_deprecated }, + + { { "dialplan", "add", "include", NULL }, + handle_context_add_include, "Include context in other context", + context_add_include_help, complete_context_add_include, &cli_include_context_deprecated }, + + { { "dialplan", "remove", "include", NULL }, + handle_context_remove_include, "Remove a specified include from context", + context_remove_include_help, complete_context_remove_include, &cli_dont_include_deprecated }, + + { { "dialplan", "reload", NULL }, + handle_reload_extensions, "Reload extensions and *only* extensions", + reload_extensions_help, NULL, &cli_extensions_reload_deprecated }, +}; + + +static struct ast_cli_entry cli_dialplan_save = { + { "dialplan", "save", NULL }, + handle_save_dialplan, "Save dialplan", + save_dialplan_help, NULL, &cli_save_dialplan_deprecated }; /*! * Standard module functions ... */ static int unload_module(void) { - ast_cli_unregister(&context_add_extension_cli); if (static_config && !write_protect_config) - ast_cli_unregister(&save_dialplan_cli); - ast_cli_unregister(&context_add_include_cli); - ast_cli_unregister(&context_dont_include_cli); - ast_cli_unregister(&context_remove_extension_cli); - ast_cli_unregister(&context_remove_ignorepat_cli); - ast_cli_unregister(&context_add_ignorepat_cli); - ast_cli_unregister(&reload_extensions_cli); + ast_cli_unregister(&cli_dialplan_save); + ast_cli_unregister_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry)); ast_context_destroy(NULL, registrar); return 0; } @@ -1617,15 +2442,9 @@ static int load_module(void) if (pbx_load_module()) return AST_MODULE_LOAD_DECLINE; - ast_cli_register(&context_remove_extension_cli); - ast_cli_register(&context_dont_include_cli); - ast_cli_register(&context_add_include_cli); if (static_config && !write_protect_config) - ast_cli_register(&save_dialplan_cli); - ast_cli_register(&context_add_extension_cli); - ast_cli_register(&context_add_ignorepat_cli); - ast_cli_register(&context_remove_ignorepat_cli); - ast_cli_register(&reload_extensions_cli); + ast_cli_register(&cli_dialplan_save); + ast_cli_register_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry)); return 0; } diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index 338e77749..5d62c641d 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -2677,50 +2677,67 @@ static char flush_usage[] = "'stats' is present, clears timer statistics instead of normal\n" "operation.\n"; -static struct ast_cli_entry cli_debug = - { { "dundi", "debug", NULL }, dundi_do_debug, "Enable DUNDi debugging", debug_usage }; - -static struct ast_cli_entry cli_store_history = - { { "dundi", "store", "history", NULL }, dundi_do_store_history, "Enable DUNDi historic records", store_history_usage }; - -static struct ast_cli_entry cli_no_store_history = - { { "dundi", "no", "store", "history", NULL }, dundi_no_store_history, "Disable DUNDi historic records", no_store_history_usage }; - -static struct ast_cli_entry cli_flush = - { { "dundi", "flush", NULL }, dundi_flush, "Flush DUNDi cache", flush_usage }; - -static struct ast_cli_entry cli_no_debug = - { { "dundi", "no", "debug", NULL }, dundi_no_debug, "Disable DUNDi debugging", no_debug_usage }; - -static struct ast_cli_entry cli_show_peers = - { { "dundi", "show", "peers", NULL }, dundi_show_peers, "Show defined DUNDi peers", show_peers_usage }; - -static struct ast_cli_entry cli_show_trans = - { { "dundi", "show", "trans", NULL }, dundi_show_trans, "Show active DUNDi transactions", show_trans_usage }; - -static struct ast_cli_entry cli_show_entityid = - { { "dundi", "show", "entityid", NULL }, dundi_show_entityid, "Display Global Entity ID", show_entityid_usage }; - -static struct ast_cli_entry cli_show_mappings = - { { "dundi", "show", "mappings", NULL }, dundi_show_mappings, "Show DUNDi mappings", show_mappings_usage }; - -static struct ast_cli_entry cli_show_precache = - { { "dundi", "show", "precache", NULL }, dundi_show_precache, "Show DUNDi precache", show_precache_usage }; - -static struct ast_cli_entry cli_show_requests = - { { "dundi", "show", "requests", NULL }, dundi_show_requests, "Show DUNDi requests", show_requests_usage }; - -static struct ast_cli_entry cli_show_peer = - { { "dundi", "show", "peer", NULL }, dundi_show_peer, "Show info on a specific DUNDi peer", show_peer_usage, complete_peer_4 }; - -static struct ast_cli_entry cli_lookup = - { { "dundi", "lookup", NULL }, dundi_do_lookup, "Lookup a number in DUNDi", lookup_usage }; - -static struct ast_cli_entry cli_precache = - { { "dundi", "precache", NULL }, dundi_do_precache, "Precache a number in DUNDi", precache_usage }; - -static struct ast_cli_entry cli_queryeid = - { { "dundi", "query", NULL }, dundi_do_query, "Query a DUNDi EID", query_usage }; +static struct ast_cli_entry cli_dundi[] = { + { { "dundi", "debug", NULL }, + dundi_do_debug, "Enable DUNDi debugging", + debug_usage }, + + { { "dundi", "store", "history", NULL }, + dundi_do_store_history, "Enable DUNDi historic records", + store_history_usage }, + + { { "dundi", "no", "store", "history", NULL }, + dundi_no_store_history, "Disable DUNDi historic records", + no_store_history_usage }, + + { { "dundi", "flush", NULL }, + dundi_flush, "Flush DUNDi cache", + flush_usage }, + + { { "dundi", "no", "debug", NULL }, + dundi_no_debug, "Disable DUNDi debugging", + no_debug_usage }, + + { { "dundi", "show", "peers", NULL }, + dundi_show_peers, "Show defined DUNDi peers", + show_peers_usage }, + + { { "dundi", "show", "trans", NULL }, + dundi_show_trans, "Show active DUNDi transactions", + show_trans_usage }, + + { { "dundi", "show", "entityid", NULL }, + dundi_show_entityid, "Display Global Entity ID", + show_entityid_usage }, + + { { "dundi", "show", "mappings", NULL }, + dundi_show_mappings, "Show DUNDi mappings", + show_mappings_usage }, + + { { "dundi", "show", "precache", NULL }, + dundi_show_precache, "Show DUNDi precache", + show_precache_usage }, + + { { "dundi", "show", "requests", NULL }, + dundi_show_requests, "Show DUNDi requests", + show_requests_usage }, + + { { "dundi", "show", "peer", NULL }, + dundi_show_peer, "Show info on a specific DUNDi peer", + show_peer_usage, complete_peer_4 }, + + { { "dundi", "lookup", NULL }, + dundi_do_lookup, "Lookup a number in DUNDi", + lookup_usage }, + + { { "dundi", "precache", NULL }, + dundi_do_precache, "Precache a number in DUNDi", + precache_usage }, + + { { "dundi", "query", NULL }, + dundi_do_query, "Query a DUNDi EID", + query_usage }, +}; static struct dundi_transaction *create_transaction(struct dundi_peer *p) { @@ -4438,21 +4455,7 @@ static int unload_module(void) { ast_module_user_hangup_all(); - ast_cli_unregister(&cli_debug); - ast_cli_unregister(&cli_store_history); - ast_cli_unregister(&cli_flush); - ast_cli_unregister(&cli_no_debug); - ast_cli_unregister(&cli_no_store_history); - ast_cli_unregister(&cli_show_peers); - ast_cli_unregister(&cli_show_entityid); - ast_cli_unregister(&cli_show_trans); - ast_cli_unregister(&cli_show_requests); - ast_cli_unregister(&cli_show_mappings); - ast_cli_unregister(&cli_show_precache); - ast_cli_unregister(&cli_show_peer); - ast_cli_unregister(&cli_lookup); - ast_cli_unregister(&cli_precache); - ast_cli_unregister(&cli_queryeid); + 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); sched_context_destroy(sched); @@ -4518,21 +4521,7 @@ static int load_module(void) if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); - ast_cli_register(&cli_debug); - ast_cli_register(&cli_store_history); - ast_cli_register(&cli_flush); - ast_cli_register(&cli_no_debug); - ast_cli_register(&cli_no_store_history); - ast_cli_register(&cli_show_peers); - ast_cli_register(&cli_show_entityid); - ast_cli_register(&cli_show_trans); - ast_cli_register(&cli_show_requests); - ast_cli_register(&cli_show_mappings); - ast_cli_register(&cli_show_precache); - ast_cli_register(&cli_show_peer); - ast_cli_register(&cli_lookup); - ast_cli_register(&cli_precache); - ast_cli_register(&cli_queryeid); + ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry)); if (ast_register_switch(&dundi_switch)) ast_log(LOG_ERROR, "Unable to register DUNDi switch\n"); ast_custom_function_register(&dundi_function); -- cgit v1.2.3