diff options
Diffstat (limited to 'cli.c')
-rwxr-xr-x | cli.c | 179 |
1 files changed, 153 insertions, 26 deletions
@@ -27,6 +27,11 @@ #include <readline/readline.h> /* For module directory */ #include "asterisk.h" +#include "build.h" + +#define VERSION_INFO "Asterisk " ASTERISK_VERSION " built by " BUILD_USER "@" BUILD_HOSTNAME \ + " on a " BUILD_MACHINE " running " BUILD_OS + void ast_cli(int fd, char *fmt, ...) { @@ -66,6 +71,21 @@ static char chanlist_help[] = " Lists currently defined channels and some information about\n" " them.\n"; +static char reload_help[] = +"Usage: reload\n" +" Reloads configuration files for all modules which support\n" +" reloading.\n"; + +static char set_verbose_help[] = +"Usage: set verbose <level>\n" +" Sets level of verbose messages to be displayed. 0 means\n" +" no messages should be displayed.\n"; + +static char softhangup_help[] = +"Usage: soft hangup <channel>\n" +" Request that a channel be hung up. The hangup takes effect\n" +" the next time the driver reads or writes from the channel\n"; + static int handle_load(int fd, int argc, char *argv[]) { if (argc != 2) @@ -77,6 +97,32 @@ static int handle_load(int fd, int argc, char *argv[]) return RESULT_SUCCESS; } +static int handle_reload(int fd, int argc, char *argv[]) +{ + if (argc != 1) + return RESULT_SHOWUSAGE; + ast_module_reload(); + return RESULT_SUCCESS; +} + +static int handle_set_verbose(int fd, int argc, char *argv[]) +{ + int val; + /* Has a hidden 'at least' argument */ + if ((argc != 3) && (argc != 4)) + return RESULT_SHOWUSAGE; + if ((argc == 4) && strcasecmp(argv[2], "atleast")) + return RESULT_SHOWUSAGE; + if (argc == 3) + option_verbose = atoi(argv[2]); + else { + val = atoi(argv[3]); + if (val > option_verbose) + option_verbose = val; + } + return RESULT_SUCCESS; +} + static int handle_unload(int fd, int argc, char *argv[]) { int x; @@ -122,30 +168,41 @@ static char modlist_help[] = " Shows Asterisk modules currently in use, and usage " "statistics.\n"; +static char version_help[] = +"Usage: show version\n" +" Shows Asterisk version information.\n "; + static int handle_modlist(int fd, int argc, char *argv[]) { if (argc != 2) return RESULT_SHOWUSAGE; - pthread_mutex_lock(&climodentrylock); + ast_pthread_mutex_lock(&climodentrylock); climodentryfd = fd; ast_cli(fd, MODLIST_FORMAT2, "Module", "Description", "Use Count"); ast_update_module_list(modlist_modentry); climodentryfd = -1; - pthread_mutex_unlock(&climodentrylock); + ast_pthread_mutex_unlock(&climodentrylock); return RESULT_SUCCESS; } +static int handle_version(int fd, int argc, char *argv[]) +{ + if (argc != 2) + return RESULT_SHOWUSAGE; + ast_cli(fd, VERSION_INFO); + return RESULT_SUCCESS; +} static int handle_chanlist(int fd, int argc, char *argv[]) { -#define FORMAT_STRING "%15s (%-10s %-12s %-4d) %-12s %-15s\n" -#define FORMAT_STRING2 "%15s (%-10s %-12s %-4s) %-12s %-15s\n" +#define FORMAT_STRING "%15s (%-10s %-12s %-4d) %7s %-12s %-15s\n" +#define FORMAT_STRING2 "%15s (%-10s %-12s %-4s) %7s %-12s %-15s\n" struct ast_channel *c=NULL; if (argc != 2) return RESULT_SHOWUSAGE; c = ast_channel_walk(NULL); - ast_cli(fd, FORMAT_STRING2, "Channel", "Context", "Extension", "Pri", "Appl.", "Data"); + ast_cli(fd, FORMAT_STRING2, "Channel", "Context", "Extension", "Pri", "State", "Appl.", "Data"); while(c) { - ast_cli(fd, FORMAT_STRING, c->name, c->context, c->exten, c->priority, + ast_cli(fd, FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->state), c->appl ? c->appl : "(None)", c->data ? ( strlen(c->data) ? c->data : "(Empty)" ): "(None)"); c = ast_channel_walk(c); } @@ -156,6 +213,52 @@ static char showchan_help[] = "Usage: show channel <channel>\n" " Shows lots of information about the specified channel.\n"; +static char commandcomplete_help[] = +"Usage: _command complete \"<line>\" text state\n" +" This function is used internally to help with command completion and should.\n" +" never be called by the user directly.\n"; + +static int handle_softhangup(int fd, int argc, char *argv[]) +{ + struct ast_channel *c=NULL; + if (argc != 3) + return RESULT_SHOWUSAGE; + c = ast_channel_walk(NULL); + while(c) { + if (!strcasecmp(c->name, argv[2])) { + ast_cli(fd, "Requested Hangup on channel '%s'\n", c->name); + c->softhangup = 1; + break; + } + c = ast_channel_walk(c); + } + if (!c) + ast_cli(fd, "%s is not a known channel\n", argv[2]); + return RESULT_SUCCESS; +} + +static char *__ast_cli_generator(char *text, char *word, int state, int lock); + +static int handle_commandcomplete(int fd, int argc, char *argv[]) +{ + char *buf; +#if 0 + printf("Search for %d args: '%s', '%s', '%s', '%s'\n", argc, argv[0], argv[1], argv[2], argv[3]); +#endif + if (argc != 5) + return RESULT_SHOWUSAGE; + buf = __ast_cli_generator(argv[2], argv[3], atoi(argv[4]), 0); +#if 0 + printf("Search for '%s' %s %d got '%s'\n", argv[2], argv[3], atoi(argv[4]), buf); +#endif + if (buf) { + ast_cli(fd, buf); + free(buf); + } else + ast_cli(fd, "NULL\n"); + return RESULT_SUCCESS; +} + static int handle_showchan(int fd, int argc, char *argv[]) { struct ast_channel *c=NULL; @@ -170,12 +273,12 @@ static int handle_showchan(int fd, int argc, char *argv[]) " Type: %s\n" " Caller ID: %s\n" " DNID Digits: %s\n" - " State: %d\n" + " State: %s (%d)\n" " Rings: %d\n" " WriteFormat: %d\n" " ReadFormat: %d\n" " NativeFormat: %d\n" - "File Descriptor: %d\n" + "1st File Descriptor: %d\n" " -- PBX --\n" " Context: %s\n" " Extension: %s\n" @@ -186,8 +289,8 @@ static int handle_showchan(int fd, int argc, char *argv[]) " Blocking in: %s\n", c->name, c->type, (c->callerid ? c->callerid : "(N/A)"), - (c->dnid ? c->dnid : "(N/A)" ), c->state, c->rings, c->nativeformats, c->writeformat, c->readformat, - c->fd, c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ), + (c->dnid ? c->dnid : "(N/A)" ), ast_state2str(c->state), c->state, c->rings, c->nativeformats, c->writeformat, c->readformat, + c->fds[0], c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ), ( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"), c->stack, (c->blocking ? c->blockproc : "(Not Blocking)")); @@ -206,8 +309,10 @@ static char *complete_ch(char *line, char *word, int pos, int state) int which=0; c = ast_channel_walk(NULL); while(c) { - if (++which > state) - break; + if (!strncasecmp(word, c->name, strlen(word))) { + if (++which > state) + break; + } c = ast_channel_walk(c); } return c ? strdup(c->name) : NULL; @@ -223,7 +328,7 @@ static char *complete_fn(char *line, char *word, int pos, int state) strncpy(filename, word, sizeof(filename)); else snprintf(filename, sizeof(filename), "%s/%s", AST_MODULE_DIR, word); - c = filename_completion_function(filename, state); + c = (char*)filename_completion_function(filename, state); if (c && word[0] != '/') c += (strlen(AST_MODULE_DIR) + 1); return c ? strdup(c) : c; @@ -234,11 +339,16 @@ static int handle_help(int fd, int argc, char *argv[]); static struct ast_cli_entry builtins[] = { /* Keep alphabetized */ { { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help }, + { { "_command", "complete", NULL }, handle_commandcomplete, "Command complete", commandcomplete_help }, { { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn }, + { { "reload", NULL }, handle_reload, "Reload configuration", reload_help }, + { { "set", "verbose", NULL }, handle_set_verbose, "Set level of verboseness", set_verbose_help }, { { "show", "channel", NULL }, handle_showchan, "Display information on a specific channel", showchan_help, complete_ch }, { { "show", "channels", NULL }, handle_chanlist, "Display information on channels", chanlist_help }, { { "show", "modules", NULL }, handle_modlist, "List modules and info", modlist_help }, + { { "soft", "hangup", NULL }, handle_softhangup, "Request a hangup on a given channel", softhangup_help, complete_ch }, { { "unload", NULL }, handle_unload, "Unload a dynamic module by name", unload_help, complete_fn }, + { { "version", NULL }, handle_version, "Display version info", version_help }, { { NULL }, NULL, NULL, NULL } }; @@ -327,7 +437,7 @@ static char *find_best(char *argv[]) int ast_cli_unregister(struct ast_cli_entry *e) { struct ast_cli_entry *cur, *l=NULL; - pthread_mutex_lock(&clilock); + ast_pthread_mutex_lock(&clilock); cur = helpers; while(cur) { if (e == cur) { @@ -342,7 +452,7 @@ int ast_cli_unregister(struct ast_cli_entry *e) l = cur; cur = cur->next; } - pthread_mutex_unlock(&clilock); + ast_pthread_mutex_unlock(&clilock); return 0; } @@ -351,11 +461,11 @@ int ast_cli_register(struct ast_cli_entry *e) struct ast_cli_entry *cur, *l=NULL; char fulle[80], fulltst[80]; static int len; - pthread_mutex_lock(&clilock); + ast_pthread_mutex_lock(&clilock); join2(fulle, sizeof(fulle), e->cmda); if (find_cli(e->cmda, -1)) { ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", fulle); - pthread_mutex_unlock(&clilock); + ast_pthread_mutex_unlock(&clilock); return -1; } cur = helpers; @@ -384,7 +494,7 @@ int ast_cli_register(struct ast_cli_entry *e) helpers = e; e->next = NULL; } - pthread_mutex_unlock(&clilock); + ast_pthread_mutex_unlock(&clilock); return 0; } @@ -417,6 +527,9 @@ static int help_workhorse(int fd, char *match[]) fullcmd = fullcmd1; e1++; } + /* Hide commands that start with '_' */ + if (fullcmd[0] == '_') + continue; if (match) { if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) { continue; @@ -469,6 +582,11 @@ static char *parse_args(char *s, int *max, char *argv[]) goto normal; else quoted = !quoted; + if (quoted && whitespace) { + /* If we're starting a quote, coming off white space start a new word, too */ + argv[x++] = cur; + whitespace=0; + } escaped = 0; break; case ' ': @@ -514,7 +632,7 @@ normal: return dup; } -char *ast_cli_generator(char *text, char *word, int state) +static char *__ast_cli_generator(char *text, char *word, int state, int lock) { char *argv[AST_MAX_ARGS]; struct ast_cli_entry *e, *e1, *e2; @@ -528,7 +646,8 @@ char *ast_cli_generator(char *text, char *word, int state) if ((dup = parse_args(text, &x, argv))) { join(matchstr, sizeof(matchstr), argv); - pthread_mutex_lock(&clilock); + if (lock) + ast_pthread_mutex_lock(&clilock); e1 = builtins; e2 = helpers; while(e1->cmda[0] || e2) { @@ -549,7 +668,7 @@ char *ast_cli_generator(char *text, char *word, int state) fullcmd = fullcmd1; e1++; } - if (!strncasecmp(matchstr, fullcmd, strlen(matchstr))) { + if ((fullcmd[0] != '_') && !strncasecmp(matchstr, fullcmd, strlen(matchstr))) { /* We contain the first part of one or more commands */ matchnum++; if (matchnum > state) { @@ -560,7 +679,8 @@ char *ast_cli_generator(char *text, char *word, int state) res = e->cmda[x]; } if (res) { - pthread_mutex_unlock(&clilock); + if (lock) + ast_pthread_mutex_unlock(&clilock); return res ? strdup(res) : NULL; } } @@ -569,17 +689,24 @@ char *ast_cli_generator(char *text, char *word, int state) /* We have a command in its entirity within us -- theoretically only one command can have this occur */ fullcmd = e->generator(text, word, (strlen(word) ? (x - 1) : (x)), state); - pthread_mutex_unlock(&clilock); + if (lock) + ast_pthread_mutex_unlock(&clilock); return fullcmd; } } - pthread_mutex_unlock(&clilock); + if (lock) + ast_pthread_mutex_unlock(&clilock); free(dup); } return NULL; } +char *ast_cli_generator(char *text, char *word, int state) +{ + return __ast_cli_generator(text, word, state, 1); +} + int ast_cli_command(int fd, char *s) { char *argv[AST_MAX_ARGS]; @@ -590,7 +717,7 @@ int ast_cli_command(int fd, char *s) if ((dup = parse_args(s, &x, argv))) { /* We need at least one entry, or ignore */ if (x > 0) { - pthread_mutex_lock(&clilock); + ast_pthread_mutex_lock(&clilock); e = find_cli(argv, 0); if (e) { switch(e->handler(fd, x, argv)) { @@ -601,7 +728,7 @@ int ast_cli_command(int fd, char *s) } } else ast_cli(fd, "No such command '%s' (type 'help' for help)\n", find_best(argv)); - pthread_mutex_unlock(&clilock); + ast_pthread_mutex_unlock(&clilock); } free(dup); } else { |