00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 85533 $")
00029
00030 #include <unistd.h>
00031 #include <stdlib.h>
00032 #include <sys/signal.h>
00033 #include <stdio.h>
00034 #include <signal.h>
00035 #include <string.h>
00036 #include <ctype.h>
00037 #include <regex.h>
00038
00039 #include "asterisk/logger.h"
00040 #include "asterisk/options.h"
00041 #include "asterisk/cli.h"
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/lock.h"
00049 #include "editline/readline/readline.h"
00050 #include "asterisk/threadstorage.h"
00051
00052 extern unsigned long global_fin, global_fout;
00053
00054 AST_THREADSTORAGE(ast_cli_buf, ast_cli_buf_init);
00055
00056
00057 #define AST_CLI_INITLEN 256
00058
00059 void ast_cli(int fd, char *fmt, ...)
00060 {
00061 int res;
00062 struct ast_dynamic_str *buf;
00063 va_list ap;
00064
00065 if (!(buf = ast_dynamic_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
00066 return;
00067
00068 va_start(ap, fmt);
00069 res = ast_dynamic_str_thread_set_va(&buf, 0, &ast_cli_buf, fmt, ap);
00070 va_end(ap);
00071
00072 if (res != AST_DYNSTR_BUILD_FAILED)
00073 ast_carefulwrite(fd, buf->str, strlen(buf->str), 100);
00074 }
00075
00076 static AST_LIST_HEAD_STATIC(helpers, ast_cli_entry);
00077
00078 static char load_help[] =
00079 "Usage: module load <module name>\n"
00080 " Loads the specified module into Asterisk.\n";
00081
00082 static char unload_help[] =
00083 "Usage: module unload [-f|-h] <module name>\n"
00084 " Unloads the specified module from Asterisk. The -f\n"
00085 " option causes the module to be unloaded even if it is\n"
00086 " in use (may cause a crash) and the -h module causes the\n"
00087 " module to be unloaded even if the module says it cannot, \n"
00088 " which almost always will cause a crash.\n";
00089
00090 static char help_help[] =
00091 "Usage: help [topic]\n"
00092 " When called with a topic as an argument, displays usage\n"
00093 " information on the given command. If called without a\n"
00094 " topic, it provides a list of commands.\n";
00095
00096 static char chanlist_help[] =
00097 "Usage: core show channels [concise|verbose]\n"
00098 " Lists currently defined channels and some information about them. If\n"
00099 " 'concise' is specified, the format is abridged and in a more easily\n"
00100 " machine parsable format. If 'verbose' is specified, the output includes\n"
00101 " more and longer fields.\n";
00102
00103 static char reload_help[] =
00104 "Usage: module reload [module ...]\n"
00105 " Reloads configuration files for all listed modules which support\n"
00106 " reloading, or for all supported modules if none are listed.\n";
00107
00108 static char verbose_help[] =
00109 "Usage: core set verbose <level>\n"
00110 " Sets level of verbose messages to be displayed. 0 means\n"
00111 " no messages should be displayed. Equivalent to -v[v[v...]]\n"
00112 " on startup\n";
00113
00114 static char debug_help[] =
00115 "Usage: core set debug <level> [filename]\n"
00116 " Sets level of core debug messages to be displayed. 0 means\n"
00117 " no messages should be displayed. Equivalent to -d[d[d...]]\n"
00118 " on startup. If filename is specified, debugging will be\n"
00119 " limited to just that file.\n";
00120
00121 static char nodebug_help[] =
00122 "Usage: core set debug off\n"
00123 " Turns off core debug messages.\n";
00124
00125 static char logger_mute_help[] =
00126 "Usage: logger mute\n"
00127 " Disables logging output to the current console, making it possible to\n"
00128 " gather information without being disturbed by scrolling lines.\n";
00129
00130 static char softhangup_help[] =
00131 "Usage: soft hangup <channel>\n"
00132 " Request that a channel be hung up. The hangup takes effect\n"
00133 " the next time the driver reads or writes from the channel\n";
00134
00135 static char group_show_channels_help[] =
00136 "Usage: group show channels [pattern]\n"
00137 " Lists all currently active channels with channel group(s) specified.\n"
00138 " Optional regular expression pattern is matched to group names for each\n"
00139 " channel.\n";
00140
00141 static int handle_load_deprecated(int fd, int argc, char *argv[])
00142 {
00143 if (argc != 2)
00144 return RESULT_SHOWUSAGE;
00145 if (ast_load_resource(argv[1])) {
00146 ast_cli(fd, "Unable to load module %s\n", argv[1]);
00147 return RESULT_FAILURE;
00148 }
00149 return RESULT_SUCCESS;
00150 }
00151
00152 static int handle_load(int fd, int argc, char *argv[])
00153 {
00154 if (argc != 3)
00155 return RESULT_SHOWUSAGE;
00156 if (ast_load_resource(argv[2])) {
00157 ast_cli(fd, "Unable to load module %s\n", argv[2]);
00158 return RESULT_FAILURE;
00159 }
00160 return RESULT_SUCCESS;
00161 }
00162
00163 static int handle_reload_deprecated(int fd, int argc, char *argv[])
00164 {
00165 int x;
00166 int res;
00167 if (argc < 1)
00168 return RESULT_SHOWUSAGE;
00169 if (argc > 1) {
00170 for (x = 1; x < argc; x++) {
00171 res = ast_module_reload(argv[x]);
00172 switch(res) {
00173 case 0:
00174 ast_cli(fd, "No such module '%s'\n", argv[x]);
00175 break;
00176 case 1:
00177 ast_cli(fd, "Module '%s' does not support reload\n", argv[x]);
00178 break;
00179 }
00180 }
00181 } else
00182 ast_module_reload(NULL);
00183 return RESULT_SUCCESS;
00184 }
00185
00186 static int handle_reload(int fd, int argc, char *argv[])
00187 {
00188 int x;
00189 int res;
00190 if (argc < 2)
00191 return RESULT_SHOWUSAGE;
00192 if (argc > 2) {
00193 for (x = 2; x < argc; x++) {
00194 res = ast_module_reload(argv[x]);
00195 switch(res) {
00196 case 0:
00197 ast_cli(fd, "No such module '%s'\n", argv[x]);
00198 break;
00199 case 1:
00200 ast_cli(fd, "Module '%s' does not support reload\n", argv[x]);
00201 break;
00202 }
00203 }
00204 } else
00205 ast_module_reload(NULL);
00206 return RESULT_SUCCESS;
00207 }
00208
00209 static int handle_set_verbose_deprecated(int fd, int argc, char *argv[])
00210 {
00211 int val = 0;
00212 int oldval = option_verbose;
00213
00214
00215 if (argc == 3)
00216 option_verbose = atoi(argv[2]);
00217 else if (argc == 4) {
00218 if (strcasecmp(argv[2], "atleast"))
00219 return RESULT_SHOWUSAGE;
00220 val = atoi(argv[3]);
00221 if (val > option_verbose)
00222 option_verbose = val;
00223 } else
00224 return RESULT_SHOWUSAGE;
00225
00226 if (oldval != option_verbose && option_verbose > 0)
00227 ast_cli(fd, "Verbosity was %d and is now %d\n", oldval, option_verbose);
00228 else if (oldval > 0 && option_verbose > 0)
00229 ast_cli(fd, "Verbosity is at least %d\n", option_verbose);
00230 else if (oldval > 0 && option_verbose == 0)
00231 ast_cli(fd, "Verbosity is now OFF\n");
00232
00233 return RESULT_SUCCESS;
00234 }
00235
00236 static int handle_verbose(int fd, int argc, char *argv[])
00237 {
00238 int oldval = option_verbose;
00239 int newlevel;
00240 int atleast = 0;
00241
00242 if ((argc < 4) || (argc > 5))
00243 return RESULT_SHOWUSAGE;
00244
00245 if (!strcasecmp(argv[3], "atleast"))
00246 atleast = 1;
00247
00248 if (!atleast) {
00249 if (argc > 4)
00250 return RESULT_SHOWUSAGE;
00251
00252 option_verbose = atoi(argv[3]);
00253 } else {
00254 if (argc < 5)
00255 return RESULT_SHOWUSAGE;
00256
00257 newlevel = atoi(argv[4]);
00258 if (newlevel > option_verbose)
00259 option_verbose = newlevel;
00260 }
00261 if (oldval > 0 && option_verbose == 0)
00262 ast_cli(fd, "Verbosity is now OFF\n");
00263 else if (option_verbose > 0) {
00264 if (oldval == option_verbose)
00265 ast_cli(fd, "Verbosity is at least %d\n", option_verbose);
00266 else
00267 ast_cli(fd, "Verbosity was %d and is now %d\n", oldval, option_verbose);
00268 }
00269
00270 return RESULT_SUCCESS;
00271 }
00272
00273 static int handle_set_debug_deprecated(int fd, int argc, char *argv[])
00274 {
00275 int val = 0;
00276 int oldval = option_debug;
00277
00278
00279 if (argc == 3)
00280 option_debug = atoi(argv[2]);
00281 else if (argc == 4) {
00282 if (strcasecmp(argv[2], "atleast"))
00283 return RESULT_SHOWUSAGE;
00284 val = atoi(argv[3]);
00285 if (val > option_debug)
00286 option_debug = val;
00287 } else
00288 return RESULT_SHOWUSAGE;
00289
00290 if (oldval != option_debug && option_debug > 0)
00291 ast_cli(fd, "Core debug was %d and is now %d\n", oldval, option_debug);
00292 else if (oldval > 0 && option_debug > 0)
00293 ast_cli(fd, "Core debug is at least %d\n", option_debug);
00294 else if (oldval > 0 && option_debug == 0)
00295 ast_cli(fd, "Core debug is now OFF\n");
00296
00297 return RESULT_SUCCESS;
00298 }
00299
00300 static int handle_set_debug(int fd, int argc, char *argv[])
00301 {
00302 int oldval = option_debug;
00303 int newlevel;
00304 int atleast = 0;
00305 char *filename = '\0';
00306
00307
00308
00309
00310
00311
00312 if ((argc < 4) || (argc > 6))
00313 return RESULT_SHOWUSAGE;
00314
00315 if (!strcasecmp(argv[3], "atleast"))
00316 atleast = 1;
00317
00318 if (!atleast) {
00319 if (argc > 5)
00320 return RESULT_SHOWUSAGE;
00321
00322 if (sscanf(argv[3], "%d", &newlevel) != 1)
00323 return RESULT_SHOWUSAGE;
00324
00325 if (argc == 4) {
00326 debug_filename[0] = '\0';
00327 } else {
00328 filename = argv[4];
00329 ast_copy_string(debug_filename, filename, sizeof(debug_filename));
00330 }
00331
00332 option_debug = newlevel;
00333 } else {
00334 if (argc < 5 || argc > 6)
00335 return RESULT_SHOWUSAGE;
00336
00337 if (sscanf(argv[4], "%d", &newlevel) != 1)
00338 return RESULT_SHOWUSAGE;
00339
00340 if (argc == 5) {
00341 debug_filename[0] = '\0';
00342 } else {
00343 filename = argv[5];
00344 ast_copy_string(debug_filename, filename, sizeof(debug_filename));
00345 }
00346
00347 if (newlevel > option_debug)
00348 option_debug = newlevel;
00349 }
00350
00351 if (oldval > 0 && option_debug == 0)
00352 ast_cli(fd, "Core debug is now OFF\n");
00353 else if (option_debug > 0) {
00354 if (filename) {
00355 if (oldval == option_debug)
00356 ast_cli(fd, "Core debug is at least %d, file '%s'\n", option_debug, filename);
00357 else
00358 ast_cli(fd, "Core debug was %d and is now %d, file '%s'\n", oldval, option_debug, filename);
00359 } else {
00360 if (oldval == option_debug)
00361 ast_cli(fd, "Core debug is at least %d\n", option_debug);
00362 else
00363 ast_cli(fd, "Core debug was %d and is now %d\n", oldval, option_debug);
00364 }
00365 }
00366
00367 return RESULT_SUCCESS;
00368 }
00369
00370 static int handle_nodebug(int fd, int argc, char *argv[])
00371 {
00372 int oldval = option_debug;
00373 if (argc != 4)
00374 return RESULT_SHOWUSAGE;
00375
00376 option_debug = 0;
00377 debug_filename[0] = '\0';
00378
00379 if (oldval > 0)
00380 ast_cli(fd, "Core debug is now OFF\n");
00381 return RESULT_SUCCESS;
00382 }
00383
00384 static int handle_debuglevel_deprecated(int fd, int argc, char *argv[])
00385 {
00386 int newlevel;
00387 char *filename = "<any>";
00388 if ((argc < 3) || (argc > 4))
00389 return RESULT_SHOWUSAGE;
00390 if (sscanf(argv[2], "%d", &newlevel) != 1)
00391 return RESULT_SHOWUSAGE;
00392 option_debug = newlevel;
00393 if (argc == 4) {
00394 filename = argv[3];
00395 ast_copy_string(debug_filename, filename, sizeof(debug_filename));
00396 } else {
00397 debug_filename[0] = '\0';
00398 }
00399 ast_cli(fd, "Debugging level set to %d, file '%s'\n", newlevel, filename);
00400 return RESULT_SUCCESS;
00401 }
00402
00403 static int handle_logger_mute(int fd, int argc, char *argv[])
00404 {
00405 if (argc < 2 || argc > 3)
00406 return RESULT_SHOWUSAGE;
00407 if (argc == 3 && !strcasecmp(argv[2], "silent"))
00408 ast_console_toggle_mute(fd, 1);
00409 else
00410 ast_console_toggle_mute(fd, 0);
00411 return RESULT_SUCCESS;
00412 }
00413
00414 static int handle_unload_deprecated(int fd, int argc, char *argv[])
00415 {
00416 int x;
00417 int force = AST_FORCE_SOFT;
00418 if (argc < 2)
00419 return RESULT_SHOWUSAGE;
00420 for (x = 1; x < argc; x++) {
00421 if (argv[x][0] == '-') {
00422 switch(argv[x][1]) {
00423 case 'f':
00424 force = AST_FORCE_FIRM;
00425 break;
00426 case 'h':
00427 force = AST_FORCE_HARD;
00428 break;
00429 default:
00430 return RESULT_SHOWUSAGE;
00431 }
00432 } else if (x != argc - 1)
00433 return RESULT_SHOWUSAGE;
00434 else if (ast_unload_resource(argv[x], force)) {
00435 ast_cli(fd, "Unable to unload resource %s\n", argv[x]);
00436 return RESULT_FAILURE;
00437 }
00438 }
00439 return RESULT_SUCCESS;
00440 }
00441
00442 static int handle_unload(int fd, int argc, char *argv[])
00443 {
00444 int x;
00445 int force = AST_FORCE_SOFT;
00446 if (argc < 3)
00447 return RESULT_SHOWUSAGE;
00448 for (x = 2; x < argc; x++) {
00449 if (argv[x][0] == '-') {
00450 switch(argv[x][1]) {
00451 case 'f':
00452 force = AST_FORCE_FIRM;
00453 break;
00454 case 'h':
00455 force = AST_FORCE_HARD;
00456 break;
00457 default:
00458 return RESULT_SHOWUSAGE;
00459 }
00460 } else if (x != argc - 1)
00461 return RESULT_SHOWUSAGE;
00462 else if (ast_unload_resource(argv[x], force)) {
00463 ast_cli(fd, "Unable to unload resource %s\n", argv[x]);
00464 return RESULT_FAILURE;
00465 }
00466 }
00467 return RESULT_SUCCESS;
00468 }
00469
00470 #define MODLIST_FORMAT "%-30s %-40.40s %-10d\n"
00471 #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
00472
00473 AST_MUTEX_DEFINE_STATIC(climodentrylock);
00474 static int climodentryfd = -1;
00475
00476 static int modlist_modentry(const char *module, const char *description, int usecnt, const char *like)
00477 {
00478
00479 if (strcasestr(module, like) ) {
00480 ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
00481 return 1;
00482 }
00483 return 0;
00484 }
00485
00486 static char modlist_help[] =
00487 "Usage: module show [like <keyword>]\n"
00488 " Shows Asterisk modules currently in use, and usage statistics.\n";
00489
00490 static char uptime_help[] =
00491 "Usage: core show uptime [seconds]\n"
00492 " Shows Asterisk uptime information.\n"
00493 " The seconds word returns the uptime in seconds only.\n";
00494
00495 static void print_uptimestr(int fd, time_t timeval, const char *prefix, int printsec)
00496 {
00497 int x;
00498 char timestr[256]="", *s = timestr;
00499 size_t maxbytes = sizeof(timestr);
00500
00501 #define SECOND (1)
00502 #define MINUTE (SECOND*60)
00503 #define HOUR (MINUTE*60)
00504 #define DAY (HOUR*24)
00505 #define WEEK (DAY*7)
00506 #define YEAR (DAY*365)
00507 #define ESS(x) ((x == 1) ? "" : "s")
00508 #define NEEDCOMMA(x) ((x)? ",": "")
00509 if (timeval < 0)
00510 return;
00511 if (printsec) {
00512 ast_build_string(&s, &maxbytes, "%lu", (u_long)timeval);
00513 timeval = 0;
00514 }
00515 if (timeval > YEAR) {
00516 x = (timeval / YEAR);
00517 timeval -= (x * YEAR);
00518 ast_build_string(&s, &maxbytes, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval));
00519 }
00520 if (timeval > WEEK) {
00521 x = (timeval / WEEK);
00522 timeval -= (x * WEEK);
00523 ast_build_string(&s, &maxbytes, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval));
00524 }
00525 if (timeval > DAY) {
00526 x = (timeval / DAY);
00527 timeval -= (x * DAY);
00528 ast_build_string(&s, &maxbytes, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval));
00529 }
00530 if (timeval > HOUR) {
00531 x = (timeval / HOUR);
00532 timeval -= (x * HOUR);
00533 ast_build_string(&s, &maxbytes, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval));
00534 }
00535 if (timeval > MINUTE) {
00536 x = (timeval / MINUTE);
00537 timeval -= (x * MINUTE);
00538 ast_build_string(&s, &maxbytes, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval));
00539 }
00540 x = timeval;
00541 if (x > 0)
00542 ast_build_string(&s, &maxbytes, "%d second%s ", x, ESS(x));
00543 if (timestr[0] != '\0')
00544 ast_cli(fd, "%s: %s\n", prefix, timestr);
00545 }
00546
00547 static int handle_showuptime_deprecated(int fd, int argc, char *argv[])
00548 {
00549
00550 time_t curtime = time(NULL);
00551 int printsec = (argc == 3 && !strcasecmp(argv[2],"seconds"));
00552
00553 if (argc != 2 && !printsec)
00554 return RESULT_SHOWUSAGE;
00555 if (ast_startuptime)
00556 print_uptimestr(fd, curtime - ast_startuptime, "System uptime", printsec);
00557 if (ast_lastreloadtime)
00558 print_uptimestr(fd, curtime - ast_lastreloadtime, "Last reload", printsec);
00559 return RESULT_SUCCESS;
00560 }
00561
00562 static int handle_showuptime(int fd, int argc, char *argv[])
00563 {
00564
00565 time_t curtime = time(NULL);
00566 int printsec = (argc == 4 && !strcasecmp(argv[3],"seconds"));
00567
00568 if (argc != 3 && !printsec)
00569 return RESULT_SHOWUSAGE;
00570 if (ast_startuptime)
00571 print_uptimestr(fd, curtime - ast_startuptime, "System uptime", printsec);
00572 if (ast_lastreloadtime)
00573 print_uptimestr(fd, curtime - ast_lastreloadtime, "Last reload", printsec);
00574 return RESULT_SUCCESS;
00575 }
00576
00577 static int handle_modlist(int fd, int argc, char *argv[])
00578 {
00579 char *like = "";
00580 if (argc == 3)
00581 return RESULT_SHOWUSAGE;
00582 else if (argc >= 4) {
00583 if (strcmp(argv[2],"like"))
00584 return RESULT_SHOWUSAGE;
00585 like = argv[3];
00586 }
00587
00588 ast_mutex_lock(&climodentrylock);
00589 climodentryfd = fd;
00590 ast_cli(fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
00591 ast_cli(fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
00592 climodentryfd = -1;
00593 ast_mutex_unlock(&climodentrylock);
00594 return RESULT_SUCCESS;
00595 }
00596 #undef MODLIST_FORMAT
00597 #undef MODLIST_FORMAT2
00598
00599 #define FORMAT_STRING "%-20.20s %-20.20s %-7.7s %-30.30s\n"
00600 #define FORMAT_STRING2 "%-20.20s %-20.20s %-7.7s %-30.30s\n"
00601 #define CONCISE_FORMAT_STRING "%s!%s!%s!%d!%s!%s!%s!%s!%s!%d!%s!%s\n"
00602 #define VERBOSE_FORMAT_STRING "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-20.20s\n"
00603 #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-20.20s\n"
00604
00605 static int handle_chanlist_deprecated(int fd, int argc, char *argv[])
00606 {
00607 struct ast_channel *c = NULL;
00608 char durbuf[10] = "-";
00609 char locbuf[40];
00610 char appdata[40];
00611 int duration;
00612 int durh, durm, durs;
00613 int numchans = 0, concise = 0, verbose = 0;
00614
00615 concise = (argc == 3 && (!strcasecmp(argv[2],"concise")));
00616 verbose = (argc == 3 && (!strcasecmp(argv[2],"verbose")));
00617
00618 if (argc < 2 || argc > 3 || (argc == 3 && !concise && !verbose))
00619 return RESULT_SHOWUSAGE;
00620
00621 if (!concise && !verbose)
00622 ast_cli(fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
00623 else if (verbose)
00624 ast_cli(fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
00625 "CallerID", "Duration", "Accountcode", "BridgedTo");
00626
00627 while ((c = ast_channel_walk_locked(c)) != NULL) {
00628 struct ast_channel *bc = ast_bridged_channel(c);
00629 if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
00630 duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
00631 if (verbose) {
00632 durh = duration / 3600;
00633 durm = (duration % 3600) / 60;
00634 durs = duration % 60;
00635 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
00636 } else {
00637 snprintf(durbuf, sizeof(durbuf), "%d", duration);
00638 }
00639 } else {
00640 durbuf[0] = '\0';
00641 }
00642 if (concise) {
00643 ast_cli(fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00644 c->appl ? c->appl : "(None)",
00645 S_OR(c->data, ""),
00646 S_OR(c->cid.cid_num, ""),
00647 S_OR(c->accountcode, ""),
00648 c->amaflags,
00649 durbuf,
00650 bc ? bc->name : "(None)");
00651 } else if (verbose) {
00652 ast_cli(fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00653 c->appl ? c->appl : "(None)",
00654 c->data ? S_OR(c->data, "(Empty)" ): "(None)",
00655 S_OR(c->cid.cid_num, ""),
00656 durbuf,
00657 S_OR(c->accountcode, ""),
00658 bc ? bc->name : "(None)");
00659 } else {
00660 if (!ast_strlen_zero(c->context) && !ast_strlen_zero(c->exten))
00661 snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
00662 else
00663 strcpy(locbuf, "(None)");
00664 if (c->appl)
00665 snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, c->data ? c->data : "");
00666 else
00667 strcpy(appdata, "(None)");
00668 ast_cli(fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
00669 }
00670 numchans++;
00671 ast_channel_unlock(c);
00672 }
00673 if (!concise) {
00674 ast_cli(fd, "%d active channel%s\n", numchans, ESS(numchans));
00675 if (option_maxcalls)
00676 ast_cli(fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
00677 ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
00678 ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
00679 else
00680 ast_cli(fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
00681 }
00682 return RESULT_SUCCESS;
00683 }
00684
00685 static int handle_chanlist(int fd, int argc, char *argv[])
00686 {
00687 struct ast_channel *c = NULL;
00688 char durbuf[10] = "-";
00689 char locbuf[40];
00690 char appdata[40];
00691 int duration;
00692 int durh, durm, durs;
00693 int numchans = 0, concise = 0, verbose = 0;
00694
00695 concise = (argc == 4 && (!strcasecmp(argv[3],"concise")));
00696 verbose = (argc == 4 && (!strcasecmp(argv[3],"verbose")));
00697
00698 if (argc < 3 || argc > 4 || (argc == 4 && !concise && !verbose))
00699 return RESULT_SHOWUSAGE;
00700
00701 if (!concise && !verbose)
00702 ast_cli(fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
00703 else if (verbose)
00704 ast_cli(fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
00705 "CallerID", "Duration", "Accountcode", "BridgedTo");
00706
00707 while ((c = ast_channel_walk_locked(c)) != NULL) {
00708 struct ast_channel *bc = ast_bridged_channel(c);
00709 if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
00710 duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
00711 if (verbose) {
00712 durh = duration / 3600;
00713 durm = (duration % 3600) / 60;
00714 durs = duration % 60;
00715 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
00716 } else {
00717 snprintf(durbuf, sizeof(durbuf), "%d", duration);
00718 }
00719 } else {
00720 durbuf[0] = '\0';
00721 }
00722 if (concise) {
00723 ast_cli(fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00724 c->appl ? c->appl : "(None)",
00725 S_OR(c->data, ""),
00726 S_OR(c->cid.cid_num, ""),
00727 S_OR(c->accountcode, ""),
00728 c->amaflags,
00729 durbuf,
00730 bc ? bc->name : "(None)");
00731 } else if (verbose) {
00732 ast_cli(fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00733 c->appl ? c->appl : "(None)",
00734 c->data ? S_OR(c->data, "(Empty)" ): "(None)",
00735 S_OR(c->cid.cid_num, ""),
00736 durbuf,
00737 S_OR(c->accountcode, ""),
00738 bc ? bc->name : "(None)");
00739 } else {
00740 if (!ast_strlen_zero(c->context) && !ast_strlen_zero(c->exten))
00741 snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
00742 else
00743 strcpy(locbuf, "(None)");
00744 if (c->appl)
00745 snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, c->data ? c->data : "");
00746 else
00747 strcpy(appdata, "(None)");
00748 ast_cli(fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
00749 }
00750 numchans++;
00751 ast_channel_unlock(c);
00752 }
00753 if (!concise) {
00754 ast_cli(fd, "%d active channel%s\n", numchans, ESS(numchans));
00755 if (option_maxcalls)
00756 ast_cli(fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
00757 ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
00758 ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
00759 else
00760 ast_cli(fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
00761 }
00762 return RESULT_SUCCESS;
00763 }
00764
00765 #undef FORMAT_STRING
00766 #undef FORMAT_STRING2
00767 #undef CONCISE_FORMAT_STRING
00768 #undef VERBOSE_FORMAT_STRING
00769 #undef VERBOSE_FORMAT_STRING2
00770
00771 static char showchan_help[] =
00772 "Usage: core show channel <channel>\n"
00773 " Shows lots of information about the specified channel.\n";
00774
00775 static char debugchan_help[] =
00776 "Usage: core set debug channel <channel> [off]\n"
00777 " Enables/disables debugging on a specific channel.\n";
00778
00779 static char commandcomplete_help[] =
00780 "Usage: _command complete \"<line>\" text state\n"
00781 " This function is used internally to help with command completion and should.\n"
00782 " never be called by the user directly.\n";
00783
00784 static char commandnummatches_help[] =
00785 "Usage: _command nummatches \"<line>\" text \n"
00786 " This function is used internally to help with command completion and should.\n"
00787 " never be called by the user directly.\n";
00788
00789 static char commandmatchesarray_help[] =
00790 "Usage: _command matchesarray \"<line>\" text \n"
00791 " This function is used internally to help with command completion and should.\n"
00792 " never be called by the user directly.\n";
00793
00794 static int handle_softhangup(int fd, int argc, char *argv[])
00795 {
00796 struct ast_channel *c=NULL;
00797 if (argc != 3)
00798 return RESULT_SHOWUSAGE;
00799 c = ast_get_channel_by_name_locked(argv[2]);
00800 if (c) {
00801 ast_cli(fd, "Requested Hangup on channel '%s'\n", c->name);
00802 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
00803 ast_channel_unlock(c);
00804 } else
00805 ast_cli(fd, "%s is not a known channel\n", argv[2]);
00806 return RESULT_SUCCESS;
00807 }
00808
00809 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
00810
00811 static int handle_commandmatchesarray(int fd, int argc, char *argv[])
00812 {
00813 char *buf, *obuf;
00814 int buflen = 2048;
00815 int len = 0;
00816 char **matches;
00817 int x, matchlen;
00818
00819 if (argc != 4)
00820 return RESULT_SHOWUSAGE;
00821 if (!(buf = ast_malloc(buflen)))
00822 return RESULT_FAILURE;
00823 buf[len] = '\0';
00824 matches = ast_cli_completion_matches(argv[2], argv[3]);
00825 if (matches) {
00826 for (x=0; matches[x]; x++) {
00827 matchlen = strlen(matches[x]) + 1;
00828 if (len + matchlen >= buflen) {
00829 buflen += matchlen * 3;
00830 obuf = buf;
00831 if (!(buf = ast_realloc(obuf, buflen)))
00832
00833 free(obuf);
00834 }
00835 if (buf)
00836 len += sprintf( buf + len, "%s ", matches[x]);
00837 free(matches[x]);
00838 matches[x] = NULL;
00839 }
00840 free(matches);
00841 }
00842
00843 if (buf) {
00844 ast_cli(fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
00845 free(buf);
00846 } else
00847 ast_cli(fd, "NULL\n");
00848
00849 return RESULT_SUCCESS;
00850 }
00851
00852
00853
00854 static int handle_commandnummatches(int fd, int argc, char *argv[])
00855 {
00856 int matches = 0;
00857
00858 if (argc != 4)
00859 return RESULT_SHOWUSAGE;
00860
00861 matches = ast_cli_generatornummatches(argv[2], argv[3]);
00862
00863 ast_cli(fd, "%d", matches);
00864
00865 return RESULT_SUCCESS;
00866 }
00867
00868 static int handle_commandcomplete(int fd, int argc, char *argv[])
00869 {
00870 char *buf;
00871
00872 if (argc != 5)
00873 return RESULT_SHOWUSAGE;
00874 buf = __ast_cli_generator(argv[2], argv[3], atoi(argv[4]), 0);
00875 if (buf) {
00876 ast_cli(fd, buf);
00877 free(buf);
00878 } else
00879 ast_cli(fd, "NULL\n");
00880 return RESULT_SUCCESS;
00881 }
00882
00883 static int handle_debugchan_deprecated(int fd, int argc, char *argv[])
00884 {
00885 struct ast_channel *c=NULL;
00886 int is_all;
00887
00888
00889 if (argc != 3)
00890 return RESULT_SHOWUSAGE;
00891
00892 is_all = !strcasecmp("all", argv[2]);
00893 if (is_all) {
00894 global_fin |= DEBUGCHAN_FLAG;
00895 global_fout |= DEBUGCHAN_FLAG;
00896 c = ast_channel_walk_locked(NULL);
00897 } else {
00898 c = ast_get_channel_by_name_locked(argv[2]);
00899 if (c == NULL)
00900 ast_cli(fd, "No such channel %s\n", argv[2]);
00901 }
00902 while (c) {
00903 if (!(c->fin & DEBUGCHAN_FLAG) || !(c->fout & DEBUGCHAN_FLAG)) {
00904 c->fin |= DEBUGCHAN_FLAG;
00905 c->fout |= DEBUGCHAN_FLAG;
00906 ast_cli(fd, "Debugging enabled on channel %s\n", c->name);
00907 }
00908 ast_channel_unlock(c);
00909 if (!is_all)
00910 break;
00911 c = ast_channel_walk_locked(c);
00912 }
00913 ast_cli(fd, "Debugging on new channels is enabled\n");
00914 return RESULT_SUCCESS;
00915 }
00916
00917 static int handle_core_set_debug_channel(int fd, int argc, char *argv[])
00918 {
00919 struct ast_channel *c = NULL;
00920 int is_all, is_off = 0;
00921
00922
00923 if (argc == 6 && strcmp(argv[5], "off") == 0)
00924 is_off = 1;
00925 else if (argc != 5)
00926 return RESULT_SHOWUSAGE;
00927
00928 is_all = !strcasecmp("all", argv[4]);
00929 if (is_all) {
00930 if (is_off) {
00931 global_fin &= ~DEBUGCHAN_FLAG;
00932 global_fout &= ~DEBUGCHAN_FLAG;
00933 } else {
00934 global_fin |= DEBUGCHAN_FLAG;
00935 global_fout |= DEBUGCHAN_FLAG;
00936 }
00937 c = ast_channel_walk_locked(NULL);
00938 } else {
00939 c = ast_get_channel_by_name_locked(argv[4]);
00940 if (c == NULL)
00941 ast_cli(fd, "No such channel %s\n", argv[4]);
00942 }
00943 while (c) {
00944 if (!(c->fin & DEBUGCHAN_FLAG) || !(c->fout & DEBUGCHAN_FLAG)) {
00945 if (is_off) {
00946 c->fin &= ~DEBUGCHAN_FLAG;
00947 c->fout &= ~DEBUGCHAN_FLAG;
00948 } else {
00949 c->fin |= DEBUGCHAN_FLAG;
00950 c->fout |= DEBUGCHAN_FLAG;
00951 }
00952 ast_cli(fd, "Debugging %s on channel %s\n", is_off ? "disabled" : "enabled", c->name);
00953 }
00954 ast_channel_unlock(c);
00955 if (!is_all)
00956 break;
00957 c = ast_channel_walk_locked(c);
00958 }
00959 ast_cli(fd, "Debugging on new channels is %s\n", is_off ? "disabled" : "enabled");
00960 return RESULT_SUCCESS;
00961 }
00962
00963 static int handle_nodebugchan_deprecated(int fd, int argc, char *argv[])
00964 {
00965 struct ast_channel *c=NULL;
00966 int is_all;
00967
00968 if (argc != 4)
00969 return RESULT_SHOWUSAGE;
00970 is_all = !strcasecmp("all", argv[3]);
00971 if (is_all) {
00972 global_fin &= ~DEBUGCHAN_FLAG;
00973 global_fout &= ~DEBUGCHAN_FLAG;
00974 c = ast_channel_walk_locked(NULL);
00975 } else {
00976 c = ast_get_channel_by_name_locked(argv[3]);
00977 if (c == NULL)
00978 ast_cli(fd, "No such channel %s\n", argv[3]);
00979 }
00980 while(c) {
00981 if ((c->fin & DEBUGCHAN_FLAG) || (c->fout & DEBUGCHAN_FLAG)) {
00982 c->fin &= ~DEBUGCHAN_FLAG;
00983 c->fout &= ~DEBUGCHAN_FLAG;
00984 ast_cli(fd, "Debugging disabled on channel %s\n", c->name);
00985 }
00986 ast_channel_unlock(c);
00987 if (!is_all)
00988 break;
00989 c = ast_channel_walk_locked(c);
00990 }
00991 ast_cli(fd, "Debugging on new channels is disabled\n");
00992 return RESULT_SUCCESS;
00993 }
00994
00995 static int handle_showchan_deprecated(int fd, int argc, char *argv[])
00996 {
00997 struct ast_channel *c=NULL;
00998 struct timeval now;
00999 char buf[2048];
01000 char cdrtime[256];
01001 char nf[256], wf[256], rf[256];
01002 long elapsed_seconds=0;
01003 int hour=0, min=0, sec=0;
01004
01005 if (argc != 3)
01006 return RESULT_SHOWUSAGE;
01007 now = ast_tvnow();
01008 c = ast_get_channel_by_name_locked(argv[2]);
01009 if (!c) {
01010 ast_cli(fd, "%s is not a known channel\n", argv[2]);
01011 return RESULT_SUCCESS;
01012 }
01013 if(c->cdr) {
01014 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
01015 hour = elapsed_seconds / 3600;
01016 min = (elapsed_seconds % 3600) / 60;
01017 sec = elapsed_seconds % 60;
01018 snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
01019 } else
01020 strcpy(cdrtime, "N/A");
01021 ast_cli(fd,
01022 " -- General --\n"
01023 " Name: %s\n"
01024 " Type: %s\n"
01025 " UniqueID: %s\n"
01026 " Caller ID: %s\n"
01027 " Caller ID Name: %s\n"
01028 " DNID Digits: %s\n"
01029 " State: %s (%d)\n"
01030 " Rings: %d\n"
01031 " NativeFormats: %s\n"
01032 " WriteFormat: %s\n"
01033 " ReadFormat: %s\n"
01034 " WriteTranscode: %s\n"
01035 " ReadTranscode: %s\n"
01036 "1st File Descriptor: %d\n"
01037 " Frames in: %d%s\n"
01038 " Frames out: %d%s\n"
01039 " Time to Hangup: %ld\n"
01040 " Elapsed Time: %s\n"
01041 " Direct Bridge: %s\n"
01042 "Indirect Bridge: %s\n"
01043 " -- PBX --\n"
01044 " Context: %s\n"
01045 " Extension: %s\n"
01046 " Priority: %d\n"
01047 " Call Group: %llu\n"
01048 " Pickup Group: %llu\n"
01049 " Application: %s\n"
01050 " Data: %s\n"
01051 " Blocking in: %s\n",
01052 c->name, c->tech->type, c->uniqueid,
01053 S_OR(c->cid.cid_num, "(N/A)"),
01054 S_OR(c->cid.cid_name, "(N/A)"),
01055 S_OR(c->cid.cid_dnid, "(N/A)"), ast_state2str(c->_state), c->_state, c->rings,
01056 ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
01057 ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
01058 ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
01059 c->writetrans ? "Yes" : "No",
01060 c->readtrans ? "Yes" : "No",
01061 c->fds[0],
01062 c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
01063 c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
01064 (long)c->whentohangup,
01065 cdrtime, c->_bridge ? c->_bridge->name : "<none>", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
01066 c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
01067 ( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
01068 (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
01069
01070 if(pbx_builtin_serialize_variables(c,buf,sizeof(buf)))
01071 ast_cli(fd," Variables:\n%s\n",buf);
01072 if(c->cdr && ast_cdr_serialize_variables(c->cdr,buf, sizeof(buf), '=', '\n', 1))
01073 ast_cli(fd," CDR Variables:\n%s\n",buf);
01074
01075 ast_channel_unlock(c);
01076 return RESULT_SUCCESS;
01077 }
01078
01079 static int handle_showchan(int fd, int argc, char *argv[])
01080 {
01081 struct ast_channel *c=NULL;
01082 struct timeval now;
01083 char buf[2048];
01084 char cdrtime[256];
01085 char nf[256], wf[256], rf[256];
01086 long elapsed_seconds=0;
01087 int hour=0, min=0, sec=0;
01088
01089 if (argc != 4)
01090 return RESULT_SHOWUSAGE;
01091 now = ast_tvnow();
01092 c = ast_get_channel_by_name_locked(argv[3]);
01093 if (!c) {
01094 ast_cli(fd, "%s is not a known channel\n", argv[3]);
01095 return RESULT_SUCCESS;
01096 }
01097 if(c->cdr) {
01098 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
01099 hour = elapsed_seconds / 3600;
01100 min = (elapsed_seconds % 3600) / 60;
01101 sec = elapsed_seconds % 60;
01102 snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
01103 } else
01104 strcpy(cdrtime, "N/A");
01105 ast_cli(fd,
01106 " -- General --\n"
01107 " Name: %s\n"
01108 " Type: %s\n"
01109 " UniqueID: %s\n"
01110 " Caller ID: %s\n"
01111 " Caller ID Name: %s\n"
01112 " DNID Digits: %s\n"
01113 " State: %s (%d)\n"
01114 " Rings: %d\n"
01115 " NativeFormats: %s\n"
01116 " WriteFormat: %s\n"
01117 " ReadFormat: %s\n"
01118 " WriteTranscode: %s\n"
01119 " ReadTranscode: %s\n"
01120 "1st File Descriptor: %d\n"
01121 " Frames in: %d%s\n"
01122 " Frames out: %d%s\n"
01123 " Time to Hangup: %ld\n"
01124 " Elapsed Time: %s\n"
01125 " Direct Bridge: %s\n"
01126 "Indirect Bridge: %s\n"
01127 " -- PBX --\n"
01128 " Context: %s\n"
01129 " Extension: %s\n"
01130 " Priority: %d\n"
01131 " Call Group: %llu\n"
01132 " Pickup Group: %llu\n"
01133 " Application: %s\n"
01134 " Data: %s\n"
01135 " Blocking in: %s\n",
01136 c->name, c->tech->type, c->uniqueid,
01137 S_OR(c->cid.cid_num, "(N/A)"),
01138 S_OR(c->cid.cid_name, "(N/A)"),
01139 S_OR(c->cid.cid_dnid, "(N/A)"), ast_state2str(c->_state), c->_state, c->rings,
01140 ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
01141 ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
01142 ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
01143 c->writetrans ? "Yes" : "No",
01144 c->readtrans ? "Yes" : "No",
01145 c->fds[0],
01146 c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
01147 c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
01148 (long)c->whentohangup,
01149 cdrtime, c->_bridge ? c->_bridge->name : "<none>", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
01150 c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
01151 ( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
01152 (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
01153
01154 if(pbx_builtin_serialize_variables(c,buf,sizeof(buf)))
01155 ast_cli(fd," Variables:\n%s\n",buf);
01156 if(c->cdr && ast_cdr_serialize_variables(c->cdr,buf, sizeof(buf), '=', '\n', 1))
01157 ast_cli(fd," CDR Variables:\n%s\n",buf);
01158
01159 ast_channel_unlock(c);
01160 return RESULT_SUCCESS;
01161 }
01162
01163
01164
01165
01166
01167 char *ast_cli_complete(const char *word, char *const choices[], int state)
01168 {
01169 int i, which = 0, len;
01170 len = ast_strlen_zero(word) ? 0 : strlen(word);
01171
01172 for (i = 0; choices[i]; i++) {
01173 if ((!len || !strncasecmp(word, choices[i], len)) && ++which > state)
01174 return ast_strdup(choices[i]);
01175 }
01176 return NULL;
01177 }
01178
01179 static char *complete_show_channels_deprecated(const char *line, const char *word, int pos, int state)
01180 {
01181 static char *choices[] = { "concise", "verbose", NULL };
01182
01183 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
01184 }
01185
01186 static char *complete_show_channels(const char *line, const char *word, int pos, int state)
01187 {
01188 static char *choices[] = { "concise", "verbose", NULL };
01189
01190 return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
01191 }
01192
01193 char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
01194 {
01195 struct ast_channel *c = NULL;
01196 int which = 0;
01197 int wordlen;
01198 char notfound = '\0';
01199 char *ret = ¬found;
01200
01201 if (pos != rpos)
01202 return NULL;
01203
01204 wordlen = strlen(word);
01205
01206 while (ret == ¬found && (c = ast_channel_walk_locked(c))) {
01207 if (!strncasecmp(word, c->name, wordlen) && ++which > state)
01208 ret = ast_strdup(c->name);
01209 ast_channel_unlock(c);
01210 }
01211 return ret == ¬found ? NULL : ret;
01212 }
01213
01214 static char *complete_ch_3(const char *line, const char *word, int pos, int state)
01215 {
01216 return ast_complete_channels(line, word, pos, state, 2);
01217 }
01218
01219 static char *complete_ch_4(const char *line, const char *word, int pos, int state)
01220 {
01221 return ast_complete_channels(line, word, pos, state, 3);
01222 }
01223
01224 static char *complete_ch_5(const char *line, const char *word, int pos, int state)
01225 {
01226 return ast_complete_channels(line, word, pos, state, 4);
01227 }
01228
01229 static char *complete_mod_2(const char *line, const char *word, int pos, int state)
01230 {
01231 return ast_module_helper(line, word, pos, state, 1, 1);
01232 }
01233
01234 static char *complete_mod_3_nr(const char *line, const char *word, int pos, int state)
01235 {
01236 return ast_module_helper(line, word, pos, state, 2, 0);
01237 }
01238
01239 static char *complete_mod_3(const char *line, const char *word, int pos, int state)
01240 {
01241 return ast_module_helper(line, word, pos, state, 2, 1);
01242 }
01243
01244 static char *complete_mod_4(const char *line, const char *word, int pos, int state)
01245 {
01246 return ast_module_helper(line, word, pos, state, 3, 0);
01247 }
01248
01249 static char *complete_fn_2(const char *line, const char *word, int pos, int state)
01250 {
01251 char *c;
01252 char filename[256];
01253
01254 if (pos != 1)
01255 return NULL;
01256
01257 if (word[0] == '/')
01258 ast_copy_string(filename, word, sizeof(filename));
01259 else
01260 snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
01261
01262 c = filename_completion_function(filename, state);
01263
01264 if (c && word[0] != '/')
01265 c += (strlen(ast_config_AST_MODULE_DIR) + 1);
01266
01267 return c ? strdup(c) : c;
01268 }
01269
01270 static char *complete_fn_3(const char *line, const char *word, int pos, int state)
01271 {
01272 char *c;
01273 char filename[256];
01274
01275 if (pos != 2)
01276 return NULL;
01277
01278 if (word[0] == '/')
01279 ast_copy_string(filename, word, sizeof(filename));
01280 else
01281 snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
01282
01283 c = filename_completion_function(filename, state);
01284
01285 if (c && word[0] != '/')
01286 c += (strlen(ast_config_AST_MODULE_DIR) + 1);
01287
01288 return c ? strdup(c) : c;
01289 }
01290
01291 static int group_show_channels(int fd, int argc, char *argv[])
01292 {
01293 #define FORMAT_STRING "%-25s %-20s %-20s\n"
01294
01295 struct ast_group_info *gi = NULL;
01296 int numchans = 0;
01297 regex_t regexbuf;
01298 int havepattern = 0;
01299
01300 if (argc < 3 || argc > 4)
01301 return RESULT_SHOWUSAGE;
01302
01303 if (argc == 4) {
01304 if (regcomp(®exbuf, argv[3], REG_EXTENDED | REG_NOSUB))
01305 return RESULT_SHOWUSAGE;
01306 havepattern = 1;
01307 }
01308
01309 ast_cli(fd, FORMAT_STRING, "Channel", "Group", "Category");
01310
01311 ast_app_group_list_lock();
01312
01313 gi = ast_app_group_list_head();
01314 while (gi) {
01315 if (!havepattern || !regexec(®exbuf, gi->group, 0, NULL, 0)) {
01316 ast_cli(fd, FORMAT_STRING, gi->chan->name, gi->group, (ast_strlen_zero(gi->category) ? "(default)" : gi->category));
01317 numchans++;
01318 }
01319 gi = AST_LIST_NEXT(gi, list);
01320 }
01321
01322 ast_app_group_list_unlock();
01323
01324 if (havepattern)
01325 regfree(®exbuf);
01326
01327 ast_cli(fd, "%d active channel%s\n", numchans, (numchans != 1) ? "s" : "");
01328 return RESULT_SUCCESS;
01329 #undef FORMAT_STRING
01330 }
01331
01332 static int handle_help(int fd, int argc, char *argv[]);
01333
01334 static char * complete_help(const char *text, const char *word, int pos, int state)
01335 {
01336
01337 int l = strlen(text);
01338
01339 if (l > 5)
01340 l = 5;
01341 text += l;
01342
01343 return __ast_cli_generator(text, word, state, 0);
01344 }
01345
01346
01347
01348
01349
01350 static struct ast_cli_entry builtins[] = {
01351
01352 { { "_command", "complete", NULL },
01353 handle_commandcomplete, "Command complete",
01354 commandcomplete_help },
01355
01356 { { "_command", "nummatches", NULL },
01357 handle_commandnummatches, "Returns number of command matches",
01358 commandnummatches_help },
01359
01360 { { "_command", "matchesarray", NULL },
01361 handle_commandmatchesarray, "Returns command matches array",
01362 commandmatchesarray_help },
01363
01364 { { NULL }, NULL, NULL, NULL }
01365 };
01366
01367 static struct ast_cli_entry cli_debug_channel_deprecated = {
01368 { "debug", "channel", NULL },
01369 handle_debugchan_deprecated, NULL,
01370 NULL, complete_ch_3 };
01371
01372 static struct ast_cli_entry cli_debug_level_deprecated = {
01373 { "debug", "level", NULL },
01374 handle_debuglevel_deprecated, NULL,
01375 NULL };
01376
01377 static struct ast_cli_entry cli_set_debug_deprecated = {
01378 { "set", "debug", NULL },
01379 handle_set_debug_deprecated, NULL,
01380 NULL, NULL, &cli_debug_level_deprecated };
01381
01382 static struct ast_cli_entry cli_set_verbose_deprecated = {
01383 { "set", "verbose", NULL },
01384 handle_set_verbose_deprecated, NULL,
01385 NULL };
01386
01387 static struct ast_cli_entry cli_show_channel_deprecated = {
01388 { "show", "channel", NULL },
01389 handle_showchan_deprecated, NULL,
01390 NULL, complete_ch_3 };
01391
01392 static struct ast_cli_entry cli_show_channels_deprecated = {
01393 { "show", "channels", NULL },
01394 handle_chanlist_deprecated, NULL,
01395 NULL, complete_show_channels_deprecated };
01396
01397 static struct ast_cli_entry cli_show_modules_deprecated = {
01398 { "show", "modules", NULL },
01399 handle_modlist, NULL,
01400 NULL };
01401
01402 static struct ast_cli_entry cli_show_modules_like_deprecated = {
01403 { "show", "modules", "like", NULL },
01404 handle_modlist, NULL,
01405 NULL, complete_mod_4 };
01406
01407 static struct ast_cli_entry cli_module_load_deprecated = {
01408 { "load", NULL },
01409 handle_load_deprecated, NULL,
01410 NULL, complete_fn_2 };
01411
01412 static struct ast_cli_entry cli_module_reload_deprecated = {
01413 { "reload", NULL },
01414 handle_reload_deprecated, NULL,
01415 NULL, complete_mod_2 };
01416
01417 static struct ast_cli_entry cli_module_unload_deprecated = {
01418 { "unload", NULL },
01419 handle_unload_deprecated, NULL,
01420 NULL, complete_mod_2 };
01421
01422 static struct ast_cli_entry cli_show_uptime_deprecated = {
01423 { "show", "uptime", NULL },
01424 handle_showuptime_deprecated, "Show uptime information",
01425 NULL };
01426
01427 static struct ast_cli_entry cli_cli[] = {
01428
01429 { { "no", "debug", "channel", NULL },
01430 handle_nodebugchan_deprecated, NULL,
01431 NULL, complete_ch_4 },
01432
01433 { { "core", "show", "channels", NULL },
01434 handle_chanlist, "Display information on channels",
01435 chanlist_help, complete_show_channels, &cli_show_channels_deprecated },
01436
01437 { { "core", "show", "channel", NULL },
01438 handle_showchan, "Display information on a specific channel",
01439 showchan_help, complete_ch_4, &cli_show_channel_deprecated },
01440
01441 { { "core", "set", "debug", "channel", NULL },
01442 handle_core_set_debug_channel, "Enable/disable debugging on a channel",
01443 debugchan_help, complete_ch_5, &cli_debug_channel_deprecated },
01444
01445 { { "core", "set", "debug", NULL },
01446 handle_set_debug, "Set level of debug chattiness",
01447 debug_help, NULL, &cli_set_debug_deprecated },
01448
01449 { { "core", "set", "debug", "off", NULL },
01450 handle_nodebug, "Turns off debug chattiness",
01451 nodebug_help },
01452
01453 { { "core", "set", "verbose", NULL },
01454 handle_verbose, "Set level of verboseness",
01455 verbose_help, NULL, &cli_set_verbose_deprecated },
01456
01457 { { "group", "show", "channels", NULL },
01458 group_show_channels, "Display active channels with group(s)",
01459 group_show_channels_help },
01460
01461 { { "help", NULL },
01462 handle_help, "Display help list, or specific help on a command",
01463 help_help, complete_help },
01464
01465 { { "logger", "mute", NULL },
01466 handle_logger_mute, "Toggle logging output to a console",
01467 logger_mute_help },
01468
01469 { { "module", "show", NULL },
01470 handle_modlist, "List modules and info",
01471 modlist_help, NULL, &cli_show_modules_deprecated },
01472
01473 { { "module", "show", "like", NULL },
01474 handle_modlist, "List modules and info",
01475 modlist_help, complete_mod_4, &cli_show_modules_like_deprecated },
01476
01477 { { "module", "load", NULL },
01478 handle_load, "Load a module by name",
01479 load_help, complete_fn_3, &cli_module_load_deprecated },
01480
01481 { { "module", "reload", NULL },
01482 handle_reload, "Reload configuration",
01483 reload_help, complete_mod_3, &cli_module_reload_deprecated },
01484
01485 { { "module", "unload", NULL },
01486 handle_unload, "Unload a module by name",
01487 unload_help, complete_mod_3_nr, &cli_module_unload_deprecated },
01488
01489 { { "core", "show", "uptime", NULL },
01490 handle_showuptime, "Show uptime information",
01491 uptime_help, NULL, &cli_show_uptime_deprecated },
01492
01493 { { "soft", "hangup", NULL },
01494 handle_softhangup, "Request a hangup on a given channel",
01495 softhangup_help, complete_ch_3 },
01496 };
01497
01498
01499 void ast_builtins_init(void)
01500 {
01501 struct ast_cli_entry *e;
01502
01503 for (e = builtins; e->cmda[0] != NULL; e++) {
01504 char buf[80];
01505 ast_join(buf, sizeof(buf), e->cmda);
01506 e->_full_cmd = strdup(buf);
01507 if (!e->_full_cmd)
01508 ast_log(LOG_WARNING, "-- cannot allocate <%s>\n", buf);
01509 }
01510
01511 ast_cli_register_multiple(cli_cli, sizeof(cli_cli) / sizeof(struct ast_cli_entry));
01512 }
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523 struct cli_iterator {
01524 struct ast_cli_entry *builtins;
01525 struct ast_cli_entry *helpers;
01526 };
01527
01528 static struct ast_cli_entry *cli_next(struct cli_iterator *i)
01529 {
01530 struct ast_cli_entry *e;
01531
01532 if (i->builtins == NULL && i->helpers == NULL) {
01533
01534 i->builtins = builtins;
01535 i->helpers = AST_LIST_FIRST(&helpers);
01536 }
01537 e = i->builtins;
01538 if (!e->cmda[0] || (i->helpers &&
01539 strcmp(i->helpers->_full_cmd, e->_full_cmd) < 0)) {
01540
01541 e = i->helpers;
01542 if (e)
01543 i->helpers = AST_LIST_NEXT(e, list);
01544 } else {
01545 (i->builtins)++;
01546 }
01547 return e;
01548 }
01549
01550
01551
01552
01553
01554
01555
01556
01557 static struct ast_cli_entry *find_cli(char *const cmds[], int match_type)
01558 {
01559 int matchlen = -1;
01560 struct ast_cli_entry *cand = NULL, *e=NULL;
01561 struct cli_iterator i = { NULL, NULL};
01562
01563 while( (e = cli_next(&i)) ) {
01564 int y;
01565 for (y = 0 ; cmds[y] && e->cmda[y]; y++) {
01566 if (strcasecmp(e->cmda[y], cmds[y]))
01567 break;
01568 }
01569 if (e->cmda[y] == NULL) {
01570 if (cmds[y] == NULL)
01571 break;
01572
01573 if (match_type != 0)
01574 continue;
01575
01576 } else {
01577 if (cmds[y] == NULL)
01578 continue;
01579
01580 if (match_type == 0)
01581 continue;
01582 if (match_type == 1)
01583 continue;
01584 if (cmds[y+1] != NULL || e->cmda[y+1] != NULL)
01585 continue;
01586
01587 }
01588 if (y > matchlen) {
01589 matchlen = y;
01590 cand = e;
01591 }
01592 }
01593 return e ? e : cand;
01594 }
01595
01596 static char *find_best(char *argv[])
01597 {
01598 static char cmdline[80];
01599 int x;
01600
01601 char *myargv[AST_MAX_CMD_LEN];
01602 for (x=0;x<AST_MAX_CMD_LEN;x++)
01603 myargv[x]=NULL;
01604 AST_LIST_LOCK(&helpers);
01605 for (x=0;argv[x];x++) {
01606 myargv[x] = argv[x];
01607 if (!find_cli(myargv, -1))
01608 break;
01609 }
01610 AST_LIST_UNLOCK(&helpers);
01611 ast_join(cmdline, sizeof(cmdline), myargv);
01612 return cmdline;
01613 }
01614
01615 static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
01616 {
01617 if (e->deprecate_cmd) {
01618 __ast_cli_unregister(e->deprecate_cmd, e);
01619 }
01620 if (e->inuse) {
01621 ast_log(LOG_WARNING, "Can't remove command that is in use\n");
01622 } else {
01623 AST_LIST_LOCK(&helpers);
01624 AST_LIST_REMOVE(&helpers, e, list);
01625 AST_LIST_UNLOCK(&helpers);
01626 free(e->_full_cmd);
01627 }
01628 return 0;
01629 }
01630
01631 static int __ast_cli_register(struct ast_cli_entry *e, struct ast_cli_entry *ed)
01632 {
01633 struct ast_cli_entry *cur;
01634 char fulle[80] ="";
01635 int lf, ret = -1;
01636
01637 ast_join(fulle, sizeof(fulle), e->cmda);
01638 AST_LIST_LOCK(&helpers);
01639
01640 if (find_cli(e->cmda, 1)) {
01641 ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", fulle);
01642 goto done;
01643 }
01644 e->_full_cmd = ast_strdup(fulle);
01645 if (!e->_full_cmd)
01646 goto done;
01647
01648 if (ed) {
01649 e->deprecated = 1;
01650 e->summary = ed->summary;
01651 e->usage = ed->usage;
01652
01653
01654
01655
01656
01657 e->_deprecated_by = S_OR(ed->_deprecated_by, ed->_full_cmd);
01658 } else {
01659 e->deprecated = 0;
01660 }
01661
01662 lf = strlen(fulle);
01663 AST_LIST_TRAVERSE_SAFE_BEGIN(&helpers, cur, list) {
01664 int len = strlen(cur->_full_cmd);
01665 if (lf < len)
01666 len = lf;
01667 if (strncasecmp(fulle, cur->_full_cmd, len) < 0) {
01668 AST_LIST_INSERT_BEFORE_CURRENT(&helpers, e, list);
01669 break;
01670 }
01671 }
01672 AST_LIST_TRAVERSE_SAFE_END;
01673
01674 if (!cur)
01675 AST_LIST_INSERT_TAIL(&helpers, e, list);
01676 ret = 0;
01677
01678 done:
01679 AST_LIST_UNLOCK(&helpers);
01680
01681 if (e->deprecate_cmd) {
01682
01683 __ast_cli_register(e->deprecate_cmd, e);
01684 }
01685
01686 return ret;
01687 }
01688
01689
01690 int ast_cli_unregister(struct ast_cli_entry *e)
01691 {
01692 return __ast_cli_unregister(e, NULL);
01693 }
01694
01695
01696 int ast_cli_register(struct ast_cli_entry *e)
01697 {
01698 return __ast_cli_register(e, NULL);
01699 }
01700
01701
01702
01703
01704 void ast_cli_register_multiple(struct ast_cli_entry *e, int len)
01705 {
01706 int i;
01707
01708 for (i = 0; i < len; i++)
01709 ast_cli_register(e + i);
01710 }
01711
01712 void ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
01713 {
01714 int i;
01715
01716 for (i = 0; i < len; i++)
01717 ast_cli_unregister(e + i);
01718 }
01719
01720
01721
01722
01723
01724
01725
01726 static int help1(int fd, char *match[], int locked)
01727 {
01728 char matchstr[80] = "";
01729 struct ast_cli_entry *e;
01730 int len = 0;
01731 int found = 0;
01732 struct cli_iterator i = { NULL, NULL};
01733
01734 if (match) {
01735 ast_join(matchstr, sizeof(matchstr), match);
01736 len = strlen(matchstr);
01737 }
01738 if (!locked)
01739 AST_LIST_LOCK(&helpers);
01740 while ( (e = cli_next(&i)) ) {
01741
01742 if (e->_full_cmd[0] == '_')
01743 continue;
01744
01745 if (e->deprecated)
01746 continue;
01747 if (match && strncasecmp(matchstr, e->_full_cmd, len))
01748 continue;
01749 ast_cli(fd, "%25.25s %s\n", e->_full_cmd, S_OR(e->summary, ""));
01750 found++;
01751 }
01752 AST_LIST_UNLOCK(&helpers);
01753 if (!locked && !found && matchstr[0])
01754 ast_cli(fd, "No such command '%s'.\n", matchstr);
01755 return 0;
01756 }
01757
01758 static int help_workhorse(int fd, char *match[])
01759 {
01760 return help1(fd, match, 0 );
01761 }
01762
01763 static int handle_help(int fd, int argc, char *argv[])
01764 {
01765 char fullcmd[80];
01766 struct ast_cli_entry *e;
01767
01768 if (argc < 1)
01769 return RESULT_SHOWUSAGE;
01770 if (argc == 1)
01771 return help_workhorse(fd, NULL);
01772
01773 AST_LIST_LOCK(&helpers);
01774 e = find_cli(argv + 1, 1);
01775 if (!e)
01776 return help1(fd, argv + 1, 1 );
01777 if (e->usage)
01778 ast_cli(fd, "%s", e->usage);
01779 else {
01780 ast_join(fullcmd, sizeof(fullcmd), argv+1);
01781 ast_cli(fd, "No help text available for '%s'.\n", fullcmd);
01782 }
01783 AST_LIST_UNLOCK(&helpers);
01784 return RESULT_SUCCESS;
01785 }
01786
01787 static char *parse_args(const char *s, int *argc, char *argv[], int max, int *trailingwhitespace)
01788 {
01789 char *dup, *cur;
01790 int x = 0;
01791 int quoted = 0;
01792 int escaped = 0;
01793 int whitespace = 1;
01794
01795 *trailingwhitespace = 0;
01796 if (s == NULL)
01797 return NULL;
01798
01799 if (!(dup = ast_strdup(s)))
01800 return NULL;
01801
01802 cur = dup;
01803
01804 for (; *s ; s++) {
01805 if (x >= max - 1) {
01806 ast_log(LOG_WARNING, "Too many arguments, truncating at %s\n", s);
01807 break;
01808 }
01809 if (*s == '"' && !escaped) {
01810 quoted = !quoted;
01811 if (quoted && whitespace) {
01812
01813 argv[x++] = cur;
01814 whitespace = 0;
01815 }
01816 } else if ((*s == ' ' || *s == '\t') && !(quoted || escaped)) {
01817
01818
01819
01820
01821 if (!whitespace) {
01822 *cur++ = '\0';
01823 whitespace = 1;
01824 }
01825 } else if (*s == '\\' && !escaped) {
01826 escaped = 1;
01827 } else {
01828 if (whitespace) {
01829
01830 argv[x++] = cur;
01831 whitespace = 0;
01832 }
01833 *cur++ = *s;
01834 escaped = 0;
01835 }
01836 }
01837
01838 *cur++ = '\0';
01839
01840
01841
01842
01843 argv[x] = NULL;
01844 *argc = x;
01845 *trailingwhitespace = whitespace;
01846 return dup;
01847 }
01848
01849
01850 int ast_cli_generatornummatches(const char *text, const char *word)
01851 {
01852 int matches = 0, i = 0;
01853 char *buf = NULL, *oldbuf = NULL;
01854
01855 while ((buf = ast_cli_generator(text, word, i++))) {
01856 if (!oldbuf || strcmp(buf,oldbuf))
01857 matches++;
01858 if (oldbuf)
01859 free(oldbuf);
01860 oldbuf = buf;
01861 }
01862 if (oldbuf)
01863 free(oldbuf);
01864 return matches;
01865 }
01866
01867 char **ast_cli_completion_matches(const char *text, const char *word)
01868 {
01869 char **match_list = NULL, *retstr, *prevstr;
01870 size_t match_list_len, max_equal, which, i;
01871 int matches = 0;
01872
01873
01874 match_list_len = 1;
01875 while ((retstr = ast_cli_generator(text, word, matches)) != NULL) {
01876 if (matches + 1 >= match_list_len) {
01877 match_list_len <<= 1;
01878 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(*match_list))))
01879 return NULL;
01880 }
01881 match_list[++matches] = retstr;
01882 }
01883
01884 if (!match_list)
01885 return match_list;
01886
01887
01888
01889
01890 prevstr = match_list[1];
01891 max_equal = strlen(prevstr);
01892 for (which = 2; which <= matches; which++) {
01893 for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
01894 continue;
01895 max_equal = i;
01896 }
01897
01898 if (!(retstr = ast_malloc(max_equal + 1)))
01899 return NULL;
01900
01901 ast_copy_string(retstr, match_list[1], max_equal + 1);
01902 match_list[0] = retstr;
01903
01904
01905 if (matches + 1 >= match_list_len) {
01906 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list))))
01907 return NULL;
01908 }
01909 match_list[matches + 1] = NULL;
01910
01911 return match_list;
01912 }
01913
01914 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
01915 {
01916 char *argv[AST_MAX_ARGS];
01917 struct ast_cli_entry *e;
01918 struct cli_iterator i = { NULL, NULL };
01919 int x = 0, argindex, matchlen;
01920 int matchnum=0;
01921 char *ret = NULL;
01922 char matchstr[80] = "";
01923 int tws = 0;
01924 char *dup = parse_args(text, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws);
01925
01926 if (!dup)
01927 return NULL;
01928 argindex = (!ast_strlen_zero(word) && x>0) ? x-1 : x;
01929
01930 ast_join(matchstr, sizeof(matchstr)-1, argv);
01931 matchlen = strlen(matchstr);
01932 if (tws) {
01933 strcat(matchstr, " ");
01934 if (matchlen)
01935 matchlen++;
01936 }
01937 if (lock)
01938 AST_LIST_LOCK(&helpers);
01939 while( !ret && (e = cli_next(&i)) ) {
01940 int lc = strlen(e->_full_cmd);
01941 if (e->_full_cmd[0] != '_' && lc > 0 && matchlen <= lc &&
01942 !strncasecmp(matchstr, e->_full_cmd, matchlen)) {
01943
01944 if (e->cmda[argindex] && ++matchnum > state)
01945 ret = strdup(e->cmda[argindex]);
01946 } else if (e->generator && !strncasecmp(matchstr, e->_full_cmd, lc) && matchstr[lc] < 33) {
01947
01948
01949 ret = e->generator(matchstr, word, argindex, state);
01950 }
01951 }
01952 if (lock)
01953 AST_LIST_UNLOCK(&helpers);
01954 free(dup);
01955 return ret;
01956 }
01957
01958 char *ast_cli_generator(const char *text, const char *word, int state)
01959 {
01960 return __ast_cli_generator(text, word, state, 1);
01961 }
01962
01963 int ast_cli_command(int fd, const char *s)
01964 {
01965 char *argv[AST_MAX_ARGS];
01966 struct ast_cli_entry *e;
01967 int x;
01968 char *dup;
01969 int tws;
01970
01971 if (!(dup = parse_args(s, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws)))
01972 return -1;
01973
01974
01975 if (x > 0) {
01976 AST_LIST_LOCK(&helpers);
01977 e = find_cli(argv, 0);
01978 if (e)
01979 e->inuse++;
01980 AST_LIST_UNLOCK(&helpers);
01981 if (e) {
01982 switch(e->handler(fd, x, argv)) {
01983 case RESULT_SHOWUSAGE:
01984 if (e->usage)
01985 ast_cli(fd, "%s", e->usage);
01986 else
01987 ast_cli(fd, "Invalid usage, but no usage information available.\n");
01988 AST_LIST_LOCK(&helpers);
01989 if (e->deprecated)
01990 ast_cli(fd, "The '%s' command is deprecated and will be removed in a future release. Please use '%s' instead.\n", e->_full_cmd, e->_deprecated_by);
01991 AST_LIST_UNLOCK(&helpers);
01992 break;
01993 default:
01994 AST_LIST_LOCK(&helpers);
01995 if (e->deprecated == 1) {
01996 ast_cli(fd, "The '%s' command is deprecated and will be removed in a future release. Please use '%s' instead.\n", e->_full_cmd, e->_deprecated_by);
01997 e->deprecated = 2;
01998 }
01999 AST_LIST_UNLOCK(&helpers);
02000 break;
02001 }
02002 } else
02003 ast_cli(fd, "No such command '%s' (type 'help' for help)\n", find_best(argv));
02004 if (e)
02005 ast_atomic_fetchadd_int(&e->inuse, -1);
02006 }
02007 free(dup);
02008
02009 return 0;
02010 }
02011
02012 int ast_cli_command_multiple(int fd, size_t size, const char *s)
02013 {
02014 char cmd[512];
02015 int x, y = 0, count = 0;
02016
02017 for (x = 0; x < size; x++) {
02018 cmd[y] = s[x];
02019 y++;
02020 if (s[x] == '\0') {
02021 ast_cli_command(fd, cmd);
02022 y = 0;
02023 count++;
02024 }
02025 }
02026 return count;
02027 }