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 #include <unistd.h>
00026 #include <stdlib.h>
00027 #include <sys/signal.h>
00028 #include <stdio.h>
00029 #include <signal.h>
00030 #include <string.h>
00031 #include <ctype.h>
00032
00033 #include "asterisk.h"
00034
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 11281 $")
00036
00037 #include "asterisk/logger.h"
00038 #include "asterisk/options.h"
00039 #include "asterisk/cli.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/manager.h"
00044 #include "asterisk/utils.h"
00045 #include "asterisk/lock.h"
00046
00047 #include "editline/readline/readline.h"
00048
00049 #include "asterisk/version.h"
00050
00051 extern const char *ast_build_hostname;
00052 extern const char *ast_build_kernel;
00053 extern const char *ast_build_machine;
00054 extern const char *ast_build_os;
00055 extern const char *ast_build_date;
00056 extern const char *ast_build_user;
00057
00058 extern unsigned long global_fin, global_fout;
00059
00060 void ast_cli(int fd, char *fmt, ...)
00061 {
00062 char *stuff;
00063 int res = 0;
00064 va_list ap;
00065
00066 va_start(ap, fmt);
00067 res = vasprintf(&stuff, fmt, ap);
00068 va_end(ap);
00069 if (res == -1) {
00070 ast_log(LOG_ERROR, "Out of memory\n");
00071 } else {
00072 ast_carefulwrite(fd, stuff, strlen(stuff), 100);
00073 free(stuff);
00074 }
00075 }
00076
00077 AST_MUTEX_DEFINE_STATIC(clilock);
00078
00079 struct ast_cli_entry *helpers = NULL;
00080
00081 static char load_help[] =
00082 "Usage: load <module name>\n"
00083 " Loads the specified module into Asterisk.\n";
00084
00085 static char unload_help[] =
00086 "Usage: unload [-f|-h] <module name>\n"
00087 " Unloads the specified module from Asterisk. The -f\n"
00088 " option causes the module to be unloaded even if it is\n"
00089 " in use (may cause a crash) and the -h module causes the\n"
00090 " module to be unloaded even if the module says it cannot, \n"
00091 " which almost always will cause a crash.\n";
00092
00093 static char help_help[] =
00094 "Usage: help [topic]\n"
00095 " When called with a topic as an argument, displays usage\n"
00096 " information on the given command. If called without a\n"
00097 " topic, it provides a list of commands.\n";
00098
00099 static char chanlist_help[] =
00100 "Usage: show channels [concise|verbose]\n"
00101 " Lists currently defined channels and some information about them. If\n"
00102 " 'concise' is specified, the format is abridged and in a more easily\n"
00103 " machine parsable format. If 'verbose' is specified, the output includes\n"
00104 " more and longer fields.\n";
00105
00106 static char reload_help[] =
00107 "Usage: reload [module ...]\n"
00108 " Reloads configuration files for all listed modules which support\n"
00109 " reloading, or for all supported modules if none are listed.\n";
00110
00111 static char set_verbose_help[] =
00112 "Usage: set verbose <level>\n"
00113 " Sets level of verbose messages to be displayed. 0 means\n"
00114 " no messages should be displayed. Equivalent to -v[v[v...]]\n"
00115 " on startup\n";
00116
00117 static char set_debug_help[] =
00118 "Usage: set debug <level>\n"
00119 " Sets level of core debug messages to be displayed. 0 means\n"
00120 " no messages should be displayed. Equivalent to -d[d[d...]]\n"
00121 " on startup.\n";
00122
00123 static char softhangup_help[] =
00124 "Usage: soft hangup <channel>\n"
00125 " Request that a channel be hung up. The hangup takes effect\n"
00126 " the next time the driver reads or writes from the channel\n";
00127
00128 static int handle_load(int fd, int argc, char *argv[])
00129 {
00130 if (argc != 2)
00131 return RESULT_SHOWUSAGE;
00132 if (ast_load_resource(argv[1])) {
00133 ast_cli(fd, "Unable to load module %s\n", argv[1]);
00134 return RESULT_FAILURE;
00135 }
00136 return RESULT_SUCCESS;
00137 }
00138
00139 static int handle_reload(int fd, int argc, char *argv[])
00140 {
00141 int x;
00142 int res;
00143 if (argc < 1)
00144 return RESULT_SHOWUSAGE;
00145 if (argc > 1) {
00146 for (x=1;x<argc;x++) {
00147 res = ast_module_reload(argv[x]);
00148 switch(res) {
00149 case 0:
00150 ast_cli(fd, "No such module '%s'\n", argv[x]);
00151 break;
00152 case 1:
00153 ast_cli(fd, "Module '%s' does not support reload\n", argv[x]);
00154 break;
00155 }
00156 }
00157 } else
00158 ast_module_reload(NULL);
00159 return RESULT_SUCCESS;
00160 }
00161
00162 static int handle_set_verbose(int fd, int argc, char *argv[])
00163 {
00164 int val = 0;
00165 int oldval = 0;
00166
00167
00168 if ((argc != 3) && (argc != 4))
00169 return RESULT_SHOWUSAGE;
00170 if ((argc == 4) && strcasecmp(argv[2], "atleast"))
00171 return RESULT_SHOWUSAGE;
00172 oldval = option_verbose;
00173 if (argc == 3)
00174 option_verbose = atoi(argv[2]);
00175 else {
00176 val = atoi(argv[3]);
00177 if (val > option_verbose)
00178 option_verbose = val;
00179 }
00180 if (oldval != option_verbose && option_verbose > 0)
00181 ast_cli(fd, "Verbosity was %d and is now %d\n", oldval, option_verbose);
00182 else if (oldval > 0 && option_verbose > 0)
00183 ast_cli(fd, "Verbosity is at least %d\n", option_verbose);
00184 else if (oldval > 0 && option_verbose == 0)
00185 ast_cli(fd, "Verbosity is now OFF\n");
00186 return RESULT_SUCCESS;
00187 }
00188
00189 static int handle_set_debug(int fd, int argc, char *argv[])
00190 {
00191 int val = 0;
00192 int oldval = 0;
00193
00194 if ((argc != 3) && (argc != 4))
00195 return RESULT_SHOWUSAGE;
00196 if ((argc == 4) && strcasecmp(argv[2], "atleast"))
00197 return RESULT_SHOWUSAGE;
00198 oldval = option_debug;
00199 if (argc == 3)
00200 option_debug = atoi(argv[2]);
00201 else {
00202 val = atoi(argv[3]);
00203 if (val > option_debug)
00204 option_debug = val;
00205 }
00206 if (oldval != option_debug && option_debug > 0)
00207 ast_cli(fd, "Core debug was %d and is now %d\n", oldval, option_debug);
00208 else if (oldval > 0 && option_debug > 0)
00209 ast_cli(fd, "Core debug is at least %d\n", option_debug);
00210 else if (oldval > 0 && option_debug == 0)
00211 ast_cli(fd, "Core debug is now OFF\n");
00212 return RESULT_SUCCESS;
00213 }
00214
00215 static int handle_unload(int fd, int argc, char *argv[])
00216 {
00217 int x;
00218 int force=AST_FORCE_SOFT;
00219 if (argc < 2)
00220 return RESULT_SHOWUSAGE;
00221 for (x=1;x<argc;x++) {
00222 if (argv[x][0] == '-') {
00223 switch(argv[x][1]) {
00224 case 'f':
00225 force = AST_FORCE_FIRM;
00226 break;
00227 case 'h':
00228 force = AST_FORCE_HARD;
00229 break;
00230 default:
00231 return RESULT_SHOWUSAGE;
00232 }
00233 } else if (x != argc - 1)
00234 return RESULT_SHOWUSAGE;
00235 else if (ast_unload_resource(argv[x], force)) {
00236 ast_cli(fd, "Unable to unload resource %s\n", argv[x]);
00237 return RESULT_FAILURE;
00238 }
00239 }
00240 return RESULT_SUCCESS;
00241 }
00242
00243 #define MODLIST_FORMAT "%-30s %-40.40s %-10d\n"
00244 #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
00245
00246 AST_MUTEX_DEFINE_STATIC(climodentrylock);
00247 static int climodentryfd = -1;
00248
00249 static int modlist_modentry(const char *module, const char *description, int usecnt, const char *like)
00250 {
00251
00252 if (strcasestr(module, like) ) {
00253 ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
00254 return 1;
00255 }
00256 return 0;
00257 }
00258
00259 static char modlist_help[] =
00260 "Usage: show modules [like keyword]\n"
00261 " Shows Asterisk modules currently in use, and usage statistics.\n";
00262
00263 static char version_help[] =
00264 "Usage: show version\n"
00265 " Shows Asterisk version information.\n";
00266
00267 static char uptime_help[] =
00268 "Usage: show uptime [seconds]\n"
00269 " Shows Asterisk uptime information.\n"
00270 " The seconds word returns the uptime in seconds only.\n";
00271
00272 static char *format_uptimestr(time_t timeval)
00273 {
00274 int years = 0, weeks = 0, days = 0, hours = 0, mins = 0, secs = 0;
00275 char timestr[256]="";
00276 int bytes = 0;
00277 int maxbytes = 0;
00278 int offset = 0;
00279 #define SECOND (1)
00280 #define MINUTE (SECOND*60)
00281 #define HOUR (MINUTE*60)
00282 #define DAY (HOUR*24)
00283 #define WEEK (DAY*7)
00284 #define YEAR (DAY*365)
00285 #define ESS(x) ((x == 1) ? "" : "s")
00286
00287 maxbytes = sizeof(timestr);
00288 if (timeval < 0)
00289 return NULL;
00290 if (timeval > YEAR) {
00291 years = (timeval / YEAR);
00292 timeval -= (years * YEAR);
00293 if (years > 0) {
00294 snprintf(timestr + offset, maxbytes, "%d year%s, ", years, ESS(years));
00295 bytes = strlen(timestr + offset);
00296 offset += bytes;
00297 maxbytes -= bytes;
00298 }
00299 }
00300 if (timeval > WEEK) {
00301 weeks = (timeval / WEEK);
00302 timeval -= (weeks * WEEK);
00303 if (weeks > 0) {
00304 snprintf(timestr + offset, maxbytes, "%d week%s, ", weeks, ESS(weeks));
00305 bytes = strlen(timestr + offset);
00306 offset += bytes;
00307 maxbytes -= bytes;
00308 }
00309 }
00310 if (timeval > DAY) {
00311 days = (timeval / DAY);
00312 timeval -= (days * DAY);
00313 if (days > 0) {
00314 snprintf(timestr + offset, maxbytes, "%d day%s, ", days, ESS(days));
00315 bytes = strlen(timestr + offset);
00316 offset += bytes;
00317 maxbytes -= bytes;
00318 }
00319 }
00320 if (timeval > HOUR) {
00321 hours = (timeval / HOUR);
00322 timeval -= (hours * HOUR);
00323 if (hours > 0) {
00324 snprintf(timestr + offset, maxbytes, "%d hour%s, ", hours, ESS(hours));
00325 bytes = strlen(timestr + offset);
00326 offset += bytes;
00327 maxbytes -= bytes;
00328 }
00329 }
00330 if (timeval > MINUTE) {
00331 mins = (timeval / MINUTE);
00332 timeval -= (mins * MINUTE);
00333 if (mins > 0) {
00334 snprintf(timestr + offset, maxbytes, "%d minute%s, ", mins, ESS(mins));
00335 bytes = strlen(timestr + offset);
00336 offset += bytes;
00337 maxbytes -= bytes;
00338 }
00339 }
00340 secs = timeval;
00341
00342 if (secs > 0) {
00343 snprintf(timestr + offset, maxbytes, "%d second%s", secs, ESS(secs));
00344 }
00345
00346 return timestr ? strdup(timestr) : NULL;
00347 }
00348
00349 static int handle_showuptime(int fd, int argc, char *argv[])
00350 {
00351 time_t curtime, tmptime;
00352 char *timestr;
00353 int printsec;
00354
00355 printsec = ((argc == 3) && (!strcasecmp(argv[2],"seconds")));
00356 if ((argc != 2) && (!printsec))
00357 return RESULT_SHOWUSAGE;
00358
00359 time(&curtime);
00360 if (ast_startuptime) {
00361 tmptime = curtime - ast_startuptime;
00362 if (printsec) {
00363 ast_cli(fd, "System uptime: %lu\n",(u_long)tmptime);
00364 } else {
00365 timestr = format_uptimestr(tmptime);
00366 if (timestr) {
00367 ast_cli(fd, "System uptime: %s\n", timestr);
00368 free(timestr);
00369 }
00370 }
00371 }
00372 if (ast_lastreloadtime) {
00373 tmptime = curtime - ast_lastreloadtime;
00374 if (printsec) {
00375 ast_cli(fd, "Last reload: %lu\n", (u_long) tmptime);
00376 } else {
00377 timestr = format_uptimestr(tmptime);
00378 if ((timestr) && (!printsec)) {
00379 ast_cli(fd, "Last reload: %s\n", timestr);
00380 free(timestr);
00381 }
00382 }
00383 }
00384 return RESULT_SUCCESS;
00385 }
00386
00387 static int handle_modlist(int fd, int argc, char *argv[])
00388 {
00389 char *like = "";
00390 if (argc == 3)
00391 return RESULT_SHOWUSAGE;
00392 else if (argc >= 4) {
00393 if (strcmp(argv[2],"like"))
00394 return RESULT_SHOWUSAGE;
00395 like = argv[3];
00396 }
00397
00398 ast_mutex_lock(&climodentrylock);
00399 climodentryfd = fd;
00400 ast_cli(fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
00401 ast_cli(fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
00402 climodentryfd = -1;
00403 ast_mutex_unlock(&climodentrylock);
00404 return RESULT_SUCCESS;
00405 }
00406 #undef MODLIST_FORMAT
00407 #undef MODLIST_FORMAT2
00408
00409 static int handle_version(int fd, int argc, char *argv[])
00410 {
00411 if (argc != 2)
00412 return RESULT_SHOWUSAGE;
00413 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
00414 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
00415 ast_build_machine, ast_build_os, ast_build_date);
00416 return RESULT_SUCCESS;
00417 }
00418
00419 static int handle_chanlist(int fd, int argc, char *argv[])
00420 {
00421 #define FORMAT_STRING "%-20.20s %-20.20s %-7.7s %-30.30s\n"
00422 #define FORMAT_STRING2 "%-20.20s %-20.20s %-7.7s %-30.30s\n"
00423 #define CONCISE_FORMAT_STRING "%s:%s:%s:%d:%s:%s:%s:%s:%s:%d:%s:%s\n"
00424 #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"
00425 #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"
00426
00427 struct ast_channel *c = NULL, *bc = NULL;
00428 char durbuf[10] = "-";
00429 char locbuf[40];
00430 char appdata[40];
00431 int duration;
00432 int durh, durm, durs;
00433 int numchans = 0, concise = 0, verbose = 0;
00434
00435 concise = (argc == 3 && (!strcasecmp(argv[2],"concise")));
00436 verbose = (argc == 3 && (!strcasecmp(argv[2],"verbose")));
00437
00438 if (argc < 2 || argc > 3 || (argc == 3 && !concise && !verbose))
00439 return RESULT_SHOWUSAGE;
00440
00441 if (!concise && !verbose)
00442 ast_cli(fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
00443 else if (verbose)
00444 ast_cli(fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
00445 "CallerID", "Duration", "Accountcode", "BridgedTo");
00446 while ((c = ast_channel_walk_locked(c)) != NULL) {
00447 bc = ast_bridged_channel(c);
00448 if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
00449 duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
00450 if (verbose) {
00451 durh = duration / 3600;
00452 durm = (duration % 3600) / 60;
00453 durs = duration % 60;
00454 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
00455 } else {
00456 snprintf(durbuf, sizeof(durbuf), "%d", duration);
00457 }
00458 } else {
00459 durbuf[0] = '\0';
00460 }
00461 if (concise) {
00462 ast_cli(fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00463 c->appl ? c->appl : "(None)", c->data ? ( !ast_strlen_zero(c->data) ? c->data : "" ): "",
00464 (c->cid.cid_num && !ast_strlen_zero(c->cid.cid_num)) ? c->cid.cid_num : "",
00465 (c->accountcode && !ast_strlen_zero(c->accountcode)) ? c->accountcode : "", c->amaflags,
00466 durbuf, bc ? bc->name : "(None)");
00467 } else if (verbose) {
00468 ast_cli(fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00469 c->appl ? c->appl : "(None)", c->data ? ( !ast_strlen_zero(c->data) ? c->data : "(Empty)" ): "(None)",
00470 (c->cid.cid_num && !ast_strlen_zero(c->cid.cid_num)) ? c->cid.cid_num : "", durbuf,
00471 (c->accountcode && !ast_strlen_zero(c->accountcode)) ? c->accountcode : "", bc ? bc->name : "(None)");
00472 } else {
00473 if (!ast_strlen_zero(c->context) && !ast_strlen_zero(c->exten))
00474 snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
00475 else
00476 strcpy(locbuf, "(None)");
00477 if (c->appl) {
00478 snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, c->data ? c->data : "");
00479 } else {
00480 strcpy(appdata, "(None)");
00481 }
00482 ast_cli(fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
00483 }
00484 numchans++;
00485 ast_mutex_unlock(&c->lock);
00486 }
00487 if (!concise) {
00488 ast_cli(fd, "%d active channel%s\n", numchans, (numchans!=1) ? "s" : "");
00489 if (option_maxcalls)
00490 ast_cli(fd, "%d of %d max active call%s (%5.2f%% of capacity)\n", ast_active_calls(), option_maxcalls, (ast_active_calls()!=1) ? "s" : "", ((float)ast_active_calls() / (float)option_maxcalls) * 100.0);
00491 else
00492 ast_cli(fd, "%d active call%s\n", ast_active_calls(), (ast_active_calls()!=1) ? "s" : "");
00493 }
00494 return RESULT_SUCCESS;
00495
00496 #undef FORMAT_STRING
00497 #undef FORMAT_STRING2
00498 #undef CONCISE_FORMAT_STRING
00499 #undef VERBOSE_FORMAT_STRING
00500 #undef VERBOSE_FORMAT_STRING2
00501 }
00502
00503 static char showchan_help[] =
00504 "Usage: show channel <channel>\n"
00505 " Shows lots of information about the specified channel.\n";
00506
00507 static char debugchan_help[] =
00508 "Usage: debug channel <channel>\n"
00509 " Enables debugging on a specific channel.\n";
00510
00511 static char debuglevel_help[] =
00512 "Usage: debug level <level> [filename]\n"
00513 " Set debug to specified level (0 to disable). If filename\n"
00514 "is specified, debugging will be limited to just that file.\n";
00515
00516 static char nodebugchan_help[] =
00517 "Usage: no debug channel <channel>\n"
00518 " Disables debugging on a specific channel.\n";
00519
00520 static char commandcomplete_help[] =
00521 "Usage: _command complete \"<line>\" text state\n"
00522 " This function is used internally to help with command completion and should.\n"
00523 " never be called by the user directly.\n";
00524
00525 static char commandnummatches_help[] =
00526 "Usage: _command nummatches \"<line>\" text \n"
00527 " This function is used internally to help with command completion and should.\n"
00528 " never be called by the user directly.\n";
00529
00530 static char commandmatchesarray_help[] =
00531 "Usage: _command matchesarray \"<line>\" text \n"
00532 " This function is used internally to help with command completion and should.\n"
00533 " never be called by the user directly.\n";
00534
00535 static int handle_softhangup(int fd, int argc, char *argv[])
00536 {
00537 struct ast_channel *c=NULL;
00538 if (argc != 3)
00539 return RESULT_SHOWUSAGE;
00540 c = ast_get_channel_by_name_locked(argv[2]);
00541 if (c) {
00542 ast_cli(fd, "Requested Hangup on channel '%s'\n", c->name);
00543 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
00544 ast_mutex_unlock(&c->lock);
00545 } else
00546 ast_cli(fd, "%s is not a known channel\n", argv[2]);
00547 return RESULT_SUCCESS;
00548 }
00549
00550 static char *__ast_cli_generator(char *text, char *word, int state, int lock);
00551
00552 static int handle_commandmatchesarray(int fd, int argc, char *argv[])
00553 {
00554 char *buf, *obuf;
00555 int buflen = 2048;
00556 int len = 0;
00557 char **matches;
00558 int x, matchlen;
00559
00560 if (argc != 4)
00561 return RESULT_SHOWUSAGE;
00562 buf = malloc(buflen);
00563 if (!buf)
00564 return RESULT_FAILURE;
00565 buf[len] = '\0';
00566 matches = ast_cli_completion_matches(argv[2], argv[3]);
00567 if (matches) {
00568 for (x=0; matches[x]; x++) {
00569 #if 0
00570 printf("command matchesarray for '%s' %s got '%s'\n", argv[2], argv[3], matches[x]);
00571 #endif
00572 matchlen = strlen(matches[x]) + 1;
00573 if (len + matchlen >= buflen) {
00574 buflen += matchlen * 3;
00575 obuf = buf;
00576 buf = realloc(obuf, buflen);
00577 if (!buf)
00578
00579 free(obuf);
00580 }
00581 if (buf)
00582 len += sprintf( buf + len, "%s ", matches[x]);
00583 free(matches[x]);
00584 matches[x] = NULL;
00585 }
00586 free(matches);
00587 }
00588 #if 0
00589 printf("array for '%s' %s got '%s'\n", argv[2], argv[3], buf);
00590 #endif
00591
00592 if (buf) {
00593 ast_cli(fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
00594 free(buf);
00595 } else
00596 ast_cli(fd, "NULL\n");
00597
00598 return RESULT_SUCCESS;
00599 }
00600
00601
00602
00603 static int handle_commandnummatches(int fd, int argc, char *argv[])
00604 {
00605 int matches = 0;
00606
00607 if (argc != 4)
00608 return RESULT_SHOWUSAGE;
00609
00610 matches = ast_cli_generatornummatches(argv[2], argv[3]);
00611
00612 #if 0
00613 printf("Search for '%s' %s got '%d'\n", argv[2], argv[3], matches);
00614 #endif
00615 ast_cli(fd, "%d", matches);
00616
00617 return RESULT_SUCCESS;
00618 }
00619
00620 static int handle_commandcomplete(int fd, int argc, char *argv[])
00621 {
00622 char *buf;
00623 #if 0
00624 printf("Search for %d args: '%s', '%s', '%s', '%s'\n", argc, argv[0], argv[1], argv[2], argv[3]);
00625 #endif
00626 if (argc != 5)
00627 return RESULT_SHOWUSAGE;
00628 buf = __ast_cli_generator(argv[2], argv[3], atoi(argv[4]), 0);
00629 #if 0
00630 printf("Search for '%s' %s %d got '%s'\n", argv[2], argv[3], atoi(argv[4]), buf);
00631 #endif
00632 if (buf) {
00633 ast_cli(fd, buf);
00634 free(buf);
00635 } else
00636 ast_cli(fd, "NULL\n");
00637 return RESULT_SUCCESS;
00638 }
00639
00640 static int handle_debuglevel(int fd, int argc, char *argv[])
00641 {
00642 int newlevel;
00643 char *filename = "<any>";
00644 if ((argc < 3) || (argc > 4))
00645 return RESULT_SHOWUSAGE;
00646 if (sscanf(argv[2], "%d", &newlevel) != 1)
00647 return RESULT_SHOWUSAGE;
00648 option_debug = newlevel;
00649 if (argc == 4) {
00650 filename = argv[3];
00651 ast_copy_string(debug_filename, filename, sizeof(debug_filename));
00652 } else {
00653 debug_filename[0] = '\0';
00654 }
00655 ast_cli(fd, "Debugging level set to %d, file '%s'\n", newlevel, filename);
00656 return RESULT_SUCCESS;
00657 }
00658
00659 #define DEBUGCHAN_FLAG 0x80000000
00660
00661 static int handle_debugchan(int fd, int argc, char *argv[])
00662 {
00663 struct ast_channel *c=NULL;
00664 int is_all;
00665 if (argc != 3)
00666 return RESULT_SHOWUSAGE;
00667
00668 is_all = !strcasecmp("all", argv[2]);
00669 if (is_all) {
00670 global_fin |= DEBUGCHAN_FLAG;
00671 global_fout |= DEBUGCHAN_FLAG;
00672 c = ast_channel_walk_locked(NULL);
00673 } else {
00674 c = ast_get_channel_by_name_locked(argv[2]);
00675 if (c == NULL)
00676 ast_cli(fd, "No such channel %s\n", argv[2]);
00677 }
00678 while(c) {
00679 if (!(c->fin & DEBUGCHAN_FLAG) || !(c->fout & DEBUGCHAN_FLAG)) {
00680 c->fin |= DEBUGCHAN_FLAG;
00681 c->fout |= DEBUGCHAN_FLAG;
00682 ast_cli(fd, "Debugging enabled on channel %s\n", c->name);
00683 }
00684 ast_mutex_unlock(&c->lock);
00685 if (!is_all)
00686 break;
00687 c = ast_channel_walk_locked(c);
00688 }
00689 ast_cli(fd, "Debugging on new channels is enabled\n");
00690 return RESULT_SUCCESS;
00691 }
00692
00693 static int handle_nodebugchan(int fd, int argc, char *argv[])
00694 {
00695 struct ast_channel *c=NULL;
00696 int is_all;
00697 if (argc != 4)
00698 return RESULT_SHOWUSAGE;
00699 is_all = !strcasecmp("all", argv[3]);
00700 if (is_all) {
00701 global_fin &= ~DEBUGCHAN_FLAG;
00702 global_fout &= ~DEBUGCHAN_FLAG;
00703 c = ast_channel_walk_locked(NULL);
00704 } else {
00705 c = ast_get_channel_by_name_locked(argv[3]);
00706 if (c == NULL)
00707 ast_cli(fd, "No such channel %s\n", argv[3]);
00708 }
00709 while(c) {
00710 if ((c->fin & DEBUGCHAN_FLAG) || (c->fout & DEBUGCHAN_FLAG)) {
00711 c->fin &= ~DEBUGCHAN_FLAG;
00712 c->fout &= ~DEBUGCHAN_FLAG;
00713 ast_cli(fd, "Debugging disabled on channel %s\n", c->name);
00714 }
00715 ast_mutex_unlock(&c->lock);
00716 if (!is_all)
00717 break;
00718 c = ast_channel_walk_locked(c);
00719 }
00720 ast_cli(fd, "Debugging on new channels is disabled\n");
00721 return RESULT_SUCCESS;
00722 }
00723
00724
00725
00726 static int handle_showchan(int fd, int argc, char *argv[])
00727 {
00728 struct ast_channel *c=NULL;
00729 struct timeval now;
00730 char buf[2048];
00731 char cdrtime[256];
00732 long elapsed_seconds=0;
00733 int hour=0, min=0, sec=0;
00734
00735 if (argc != 3)
00736 return RESULT_SHOWUSAGE;
00737 now = ast_tvnow();
00738 c = ast_get_channel_by_name_locked(argv[2]);
00739 if (!c) {
00740 ast_cli(fd, "%s is not a known channel\n", argv[2]);
00741 return RESULT_SUCCESS;
00742 }
00743 if(c->cdr) {
00744 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
00745 hour = elapsed_seconds / 3600;
00746 min = (elapsed_seconds % 3600) / 60;
00747 sec = elapsed_seconds % 60;
00748 snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
00749 } else
00750 strcpy(cdrtime, "N/A");
00751 ast_cli(fd,
00752 " -- General --\n"
00753 " Name: %s\n"
00754 " Type: %s\n"
00755 " UniqueID: %s\n"
00756 " Caller ID: %s\n"
00757 " Caller ID Name: %s\n"
00758 " DNID Digits: %s\n"
00759 " State: %s (%d)\n"
00760 " Rings: %d\n"
00761 " NativeFormat: %d\n"
00762 " WriteFormat: %d\n"
00763 " ReadFormat: %d\n"
00764 "1st File Descriptor: %d\n"
00765 " Frames in: %d%s\n"
00766 " Frames out: %d%s\n"
00767 " Time to Hangup: %ld\n"
00768 " Elapsed Time: %s\n"
00769 " Direct Bridge: %s\n"
00770 "Indirect Bridge: %s\n"
00771 " -- PBX --\n"
00772 " Context: %s\n"
00773 " Extension: %s\n"
00774 " Priority: %d\n"
00775 " Call Group: %d\n"
00776 " Pickup Group: %d\n"
00777 " Application: %s\n"
00778 " Data: %s\n"
00779 " Blocking in: %s\n",
00780 c->name, c->type, c->uniqueid,
00781 (c->cid.cid_num ? c->cid.cid_num : "(N/A)"),
00782 (c->cid.cid_name ? c->cid.cid_name : "(N/A)"),
00783 (c->cid.cid_dnid ? c->cid.cid_dnid : "(N/A)" ), ast_state2str(c->_state), c->_state, c->rings, c->nativeformats, c->writeformat, c->readformat,
00784 c->fds[0], c->fin & 0x7fffffff, (c->fin & 0x80000000) ? " (DEBUGGED)" : "",
00785 c->fout & 0x7fffffff, (c->fout & 0x80000000) ? " (DEBUGGED)" : "", (long)c->whentohangup,
00786 cdrtime, c->_bridge ? c->_bridge->name : "<none>", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
00787 c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
00788 ( c-> data ? (!ast_strlen_zero(c->data) ? c->data : "(Empty)") : "(None)"),
00789 (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
00790
00791 if(pbx_builtin_serialize_variables(c,buf,sizeof(buf)))
00792 ast_cli(fd," Variables:\n%s\n",buf);
00793 if(c->cdr && ast_cdr_serialize_variables(c->cdr,buf, sizeof(buf), '=', '\n', 1))
00794 ast_cli(fd," CDR Variables:\n%s\n",buf);
00795
00796 ast_mutex_unlock(&c->lock);
00797 return RESULT_SUCCESS;
00798 }
00799
00800 static char *complete_show_channels(char *line, char *word, int pos, int state)
00801 {
00802 static char *choices[] = { "concise", "verbose" };
00803 int match = 0;
00804 int x;
00805 if (pos != 2)
00806 return NULL;
00807 for (x=0;x<sizeof(choices) / sizeof(choices[0]);x++) {
00808 if (!strncasecmp(word, choices[x], strlen(word))) {
00809 match++;
00810 if (match > state) return strdup(choices[x]);
00811 }
00812 }
00813 return NULL;
00814 }
00815
00816 static char *complete_ch_helper(char *line, char *word, int pos, int state, int rpos)
00817 {
00818 struct ast_channel *c = NULL;
00819 int which=0;
00820 char *ret = NULL;
00821
00822 if (pos != rpos)
00823 return NULL;
00824 while ( (c = ast_channel_walk_locked(c)) != NULL) {
00825 if (!strncasecmp(word, c->name, strlen(word))) {
00826 if (++which > state) {
00827 ret = strdup(c->name);
00828 ast_mutex_unlock(&c->lock);
00829 break;
00830 }
00831 }
00832 ast_mutex_unlock(&c->lock);
00833 }
00834 return ret;
00835 }
00836
00837 static char *complete_ch_3(char *line, char *word, int pos, int state)
00838 {
00839 return complete_ch_helper(line, word, pos, state, 2);
00840 }
00841
00842 static char *complete_ch_4(char *line, char *word, int pos, int state)
00843 {
00844 return complete_ch_helper(line, word, pos, state, 3);
00845 }
00846
00847 static char *complete_mod_2(char *line, char *word, int pos, int state)
00848 {
00849 return ast_module_helper(line, word, pos, state, 1, 1);
00850 }
00851
00852 static char *complete_mod_4(char *line, char *word, int pos, int state)
00853 {
00854 return ast_module_helper(line, word, pos, state, 3, 0);
00855 }
00856
00857 static char *complete_fn(char *line, char *word, int pos, int state)
00858 {
00859 char *c;
00860 char filename[256];
00861 if (pos != 1)
00862 return NULL;
00863 if (word[0] == '/')
00864 ast_copy_string(filename, word, sizeof(filename));
00865 else
00866 snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_MODULE_DIR, word);
00867 c = (char*)filename_completion_function(filename, state);
00868 if (c && word[0] != '/')
00869 c += (strlen((char*)ast_config_AST_MODULE_DIR) + 1);
00870 return c ? strdup(c) : c;
00871 }
00872
00873 static int handle_help(int fd, int argc, char *argv[]);
00874
00875 static struct ast_cli_entry builtins[] = {
00876
00877 { { "_command", "complete", NULL }, handle_commandcomplete, "Command complete", commandcomplete_help },
00878 { { "_command", "nummatches", NULL }, handle_commandnummatches, "Returns number of command matches", commandnummatches_help },
00879 { { "_command", "matchesarray", NULL }, handle_commandmatchesarray, "Returns command matches array", commandmatchesarray_help },
00880 { { "debug", "channel", NULL }, handle_debugchan, "Enable debugging on a channel", debugchan_help, complete_ch_3 },
00881 { { "debug", "level", NULL }, handle_debuglevel, "Set global debug level", debuglevel_help },
00882 { { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help },
00883 { { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn },
00884 { { "no", "debug", "channel", NULL }, handle_nodebugchan, "Disable debugging on a channel", nodebugchan_help, complete_ch_4 },
00885 { { "reload", NULL }, handle_reload, "Reload configuration", reload_help, complete_mod_2 },
00886 { { "set", "debug", NULL }, handle_set_debug, "Set level of debug chattiness", set_debug_help },
00887 { { "set", "verbose", NULL }, handle_set_verbose, "Set level of verboseness", set_verbose_help },
00888 { { "show", "channel", NULL }, handle_showchan, "Display information on a specific channel", showchan_help, complete_ch_3 },
00889 { { "show", "channels", NULL }, handle_chanlist, "Display information on channels", chanlist_help, complete_show_channels },
00890 { { "show", "modules", NULL }, handle_modlist, "List modules and info", modlist_help },
00891 { { "show", "modules", "like", NULL }, handle_modlist, "List modules and info", modlist_help, complete_mod_4 },
00892 { { "show", "uptime", NULL }, handle_showuptime, "Show uptime information", uptime_help },
00893 { { "show", "version", NULL }, handle_version, "Display version info", version_help },
00894 { { "soft", "hangup", NULL }, handle_softhangup, "Request a hangup on a given channel", softhangup_help, complete_ch_3 },
00895 { { "unload", NULL }, handle_unload, "Unload a dynamic module by name", unload_help, complete_fn },
00896 { { NULL }, NULL, NULL, NULL }
00897 };
00898
00899 static struct ast_cli_entry *find_cli(char *cmds[], int exact)
00900 {
00901 int x;
00902 int y;
00903 int match;
00904 struct ast_cli_entry *e=NULL;
00905
00906 for (e=helpers;e;e=e->next) {
00907 match = 1;
00908 for (y=0;match && cmds[y]; y++) {
00909 if (!e->cmda[y] && !exact)
00910 break;
00911 if (!e->cmda[y] || strcasecmp(e->cmda[y], cmds[y]))
00912 match = 0;
00913 }
00914 if ((exact > -1) && e->cmda[y])
00915 match = 0;
00916 if (match)
00917 break;
00918 }
00919 if (e)
00920 return e;
00921 for (x=0;builtins[x].cmda[0];x++) {
00922
00923 match = 1;
00924 for (y=0;match && cmds[y]; y++) {
00925
00926
00927 if (!builtins[x].cmda[y] && !exact)
00928 break;
00929
00930
00931
00932 if (!builtins[x].cmda[y] || strcasecmp(builtins[x].cmda[y], cmds[y]))
00933 match = 0;
00934 }
00935
00936
00937 if ((exact > -1) && builtins[x].cmda[y])
00938 match = 0;
00939 if (match)
00940 return &builtins[x];
00941 }
00942 return NULL;
00943 }
00944
00945 static void join(char *dest, size_t destsize, char *w[], int tws)
00946 {
00947 int x;
00948
00949 if (!dest || destsize < 1) {
00950 return;
00951 }
00952 dest[0] = '\0';
00953 for (x=0;w[x];x++) {
00954 if (x)
00955 strncat(dest, " ", destsize - strlen(dest) - 1);
00956 strncat(dest, w[x], destsize - strlen(dest) - 1);
00957 }
00958 if (tws && !ast_strlen_zero(dest))
00959 strncat(dest, " ", destsize - strlen(dest) - 1);
00960 }
00961
00962 static void join2(char *dest, size_t destsize, char *w[])
00963 {
00964 int x;
00965
00966 if (!dest || destsize < 1) {
00967 return;
00968 }
00969 dest[0] = '\0';
00970 for (x=0;w[x];x++) {
00971 strncat(dest, w[x], destsize - strlen(dest) - 1);
00972 }
00973 }
00974
00975 static char *find_best(char *argv[])
00976 {
00977 static char cmdline[80];
00978 int x;
00979
00980 char *myargv[AST_MAX_CMD_LEN];
00981 for (x=0;x<AST_MAX_CMD_LEN;x++)
00982 myargv[x]=NULL;
00983 for (x=0;argv[x];x++) {
00984 myargv[x] = argv[x];
00985 if (!find_cli(myargv, -1))
00986 break;
00987 }
00988 join(cmdline, sizeof(cmdline), myargv, 0);
00989 return cmdline;
00990 }
00991
00992 int ast_cli_unregister(struct ast_cli_entry *e)
00993 {
00994 struct ast_cli_entry *cur, *l=NULL;
00995 ast_mutex_lock(&clilock);
00996 cur = helpers;
00997 while(cur) {
00998 if (e == cur) {
00999 if (e->inuse) {
01000 ast_log(LOG_WARNING, "Can't remove command that is in use\n");
01001 } else {
01002
01003 if (l)
01004 l->next = e->next;
01005 else
01006 helpers = e->next;
01007 e->next = NULL;
01008 break;
01009 }
01010 }
01011 l = cur;
01012 cur = cur->next;
01013 }
01014 ast_mutex_unlock(&clilock);
01015 return 0;
01016 }
01017
01018 int ast_cli_register(struct ast_cli_entry *e)
01019 {
01020 struct ast_cli_entry *cur, *l=NULL;
01021 char fulle[80] ="", fulltst[80] ="";
01022 static int len;
01023 ast_mutex_lock(&clilock);
01024 join2(fulle, sizeof(fulle), e->cmda);
01025 if (find_cli(e->cmda, -1)) {
01026 ast_mutex_unlock(&clilock);
01027 ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", fulle);
01028 return -1;
01029 }
01030 cur = helpers;
01031 while(cur) {
01032 join2(fulltst, sizeof(fulltst), cur->cmda);
01033 len = strlen(fulltst);
01034 if (strlen(fulle) < len)
01035 len = strlen(fulle);
01036 if (strncasecmp(fulle, fulltst, len) < 0) {
01037 if (l) {
01038 e->next = l->next;
01039 l->next = e;
01040 } else {
01041 e->next = helpers;
01042 helpers = e;
01043 }
01044 break;
01045 }
01046 l = cur;
01047 cur = cur->next;
01048 }
01049 if (!cur) {
01050 if (l)
01051 l->next = e;
01052 else
01053 helpers = e;
01054 e->next = NULL;
01055 }
01056 ast_mutex_unlock(&clilock);
01057 return 0;
01058 }
01059
01060
01061
01062
01063 void ast_cli_register_multiple(struct ast_cli_entry *e, int len)
01064 {
01065 int i;
01066
01067 for (i=0; i < len; i++)
01068 ast_cli_register(e + i);
01069 }
01070
01071 void ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
01072 {
01073 int i;
01074
01075 for (i=0; i < len; i++)
01076 ast_cli_unregister(e + i);
01077 }
01078
01079 static int help_workhorse(int fd, char *match[])
01080 {
01081 char fullcmd1[80] = "";
01082 char fullcmd2[80] = "";
01083 char matchstr[80];
01084 char *fullcmd = NULL;
01085 struct ast_cli_entry *e, *e1, *e2;
01086 e1 = builtins;
01087 e2 = helpers;
01088 if (match)
01089 join(matchstr, sizeof(matchstr), match, 0);
01090 while(e1->cmda[0] || e2) {
01091 if (e2)
01092 join(fullcmd2, sizeof(fullcmd2), e2->cmda, 0);
01093 if (e1->cmda[0])
01094 join(fullcmd1, sizeof(fullcmd1), e1->cmda, 0);
01095 if (!e1->cmda[0] ||
01096 (e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
01097
01098 e = e2;
01099 fullcmd = fullcmd2;
01100
01101 e2 = e2->next;
01102 } else {
01103
01104 e = e1;
01105 fullcmd = fullcmd1;
01106 e1++;
01107 }
01108
01109 if (fullcmd[0] == '_')
01110 continue;
01111 if (match) {
01112 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
01113 continue;
01114 }
01115 }
01116 ast_cli(fd, "%25.25s %s\n", fullcmd, e->summary);
01117 }
01118 return 0;
01119 }
01120
01121 static int handle_help(int fd, int argc, char *argv[]) {
01122 struct ast_cli_entry *e;
01123 char fullcmd[80];
01124 if ((argc < 1))
01125 return RESULT_SHOWUSAGE;
01126 if (argc > 1) {
01127 e = find_cli(argv + 1, 1);
01128 if (e) {
01129 if (e->usage)
01130 ast_cli(fd, "%s", e->usage);
01131 else {
01132 join(fullcmd, sizeof(fullcmd), argv+1, 0);
01133 ast_cli(fd, "No help text available for '%s'.\n", fullcmd);
01134 }
01135 } else {
01136 if (find_cli(argv + 1, -1)) {
01137 return help_workhorse(fd, argv + 1);
01138 } else {
01139 join(fullcmd, sizeof(fullcmd), argv+1, 0);
01140 ast_cli(fd, "No such command '%s'.\n", fullcmd);
01141 }
01142 }
01143 } else {
01144 return help_workhorse(fd, NULL);
01145 }
01146 return RESULT_SUCCESS;
01147 }
01148
01149 static char *parse_args(char *s, int *argc, char *argv[], int max, int *trailingwhitespace)
01150 {
01151 char *dup, *cur;
01152 int x = 0;
01153 int quoted = 0;
01154 int escaped = 0;
01155 int whitespace = 1;
01156
01157 *trailingwhitespace = 0;
01158 if (!(dup = strdup(s)))
01159 return NULL;
01160
01161 cur = dup;
01162 while (*s) {
01163 if ((*s == '"') && !escaped) {
01164 quoted = !quoted;
01165 if (quoted & whitespace) {
01166
01167 if (x >= (max - 1)) {
01168 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
01169 break;
01170 }
01171 argv[x++] = cur;
01172 whitespace = 0;
01173 }
01174 escaped = 0;
01175 } else if (((*s == ' ') || (*s == '\t')) && !(quoted || escaped)) {
01176
01177
01178
01179
01180 if (!whitespace) {
01181 *(cur++) = '\0';
01182 whitespace = 1;
01183 }
01184 } else if ((*s == '\\') && !escaped) {
01185 escaped = 1;
01186 } else {
01187 if (whitespace) {
01188
01189 if (x >= (max - 1)) {
01190 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
01191 break;
01192 }
01193 argv[x++] = cur;
01194 whitespace = 0;
01195 }
01196 *(cur++) = *s;
01197 escaped = 0;
01198 }
01199 s++;
01200 }
01201
01202 *(cur++) = '\0';
01203 argv[x] = NULL;
01204 *argc = x;
01205 *trailingwhitespace = whitespace;
01206 return dup;
01207 }
01208
01209
01210 int ast_cli_generatornummatches(char *text, char *word)
01211 {
01212 int matches = 0, i = 0;
01213 char *buf = NULL, *oldbuf = NULL;
01214
01215 while ( (buf = ast_cli_generator(text, word, i++)) ) {
01216 if (!oldbuf || strcmp(buf,oldbuf))
01217 matches++;
01218 if (oldbuf)
01219 free(oldbuf);
01220 oldbuf = buf;
01221 }
01222 if (oldbuf)
01223 free(oldbuf);
01224 return matches;
01225 }
01226
01227 char **ast_cli_completion_matches(char *text, char *word)
01228 {
01229 char **match_list = NULL, *retstr, *prevstr;
01230 size_t match_list_len, max_equal, which, i;
01231 int matches = 0;
01232
01233 match_list_len = 1;
01234 while ((retstr = ast_cli_generator(text, word, matches)) != NULL) {
01235 if (matches + 1 >= match_list_len) {
01236 match_list_len <<= 1;
01237 match_list = realloc(match_list, match_list_len * sizeof(char *));
01238 }
01239 match_list[++matches] = retstr;
01240 }
01241
01242 if (!match_list)
01243 return (char **) NULL;
01244
01245 which = 2;
01246 prevstr = match_list[1];
01247 max_equal = strlen(prevstr);
01248 for (; which <= matches; which++) {
01249 for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
01250 continue;
01251 max_equal = i;
01252 }
01253
01254 retstr = malloc(max_equal + 1);
01255 (void) strncpy(retstr, match_list[1], max_equal);
01256 retstr[max_equal] = '\0';
01257 match_list[0] = retstr;
01258
01259 if (matches + 1 >= match_list_len)
01260 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
01261 match_list[matches + 1] = (char *) NULL;
01262
01263 return (match_list);
01264 }
01265
01266 static char *__ast_cli_generator(char *text, char *word, int state, int lock)
01267 {
01268 char *argv[AST_MAX_ARGS];
01269 struct ast_cli_entry *e, *e1, *e2;
01270 int x;
01271 int matchnum=0;
01272 char *dup, *res;
01273 char fullcmd1[80] = "";
01274 char fullcmd2[80] = "";
01275 char matchstr[80] = "";
01276 char *fullcmd = NULL;
01277 int tws;
01278
01279 if ((dup = parse_args(text, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws))) {
01280 join(matchstr, sizeof(matchstr), argv, tws);
01281 if (lock)
01282 ast_mutex_lock(&clilock);
01283 e1 = builtins;
01284 e2 = helpers;
01285 while(e1->cmda[0] || e2) {
01286 if (e2)
01287 join(fullcmd2, sizeof(fullcmd2), e2->cmda, tws);
01288 if (e1->cmda[0])
01289 join(fullcmd1, sizeof(fullcmd1), e1->cmda, tws);
01290 if (!e1->cmda[0] ||
01291 (e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
01292
01293 e = e2;
01294 fullcmd = fullcmd2;
01295
01296 e2 = e2->next;
01297 } else {
01298
01299 e = e1;
01300 fullcmd = fullcmd1;
01301 e1++;
01302 }
01303 if ((fullcmd[0] != '_') && !strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
01304
01305
01306 if (!ast_strlen_zero(word) && x>0) {
01307 res = e->cmda[x-1];
01308 } else {
01309 res = e->cmda[x];
01310 }
01311 if (res) {
01312 matchnum++;
01313 if (matchnum > state) {
01314 if (lock)
01315 ast_mutex_unlock(&clilock);
01316 free(dup);
01317 return strdup(res);
01318 }
01319 }
01320 }
01321 if (e->generator && !strncasecmp(matchstr, fullcmd, strlen(fullcmd)) &&
01322 (matchstr[strlen(fullcmd)] < 33)) {
01323
01324
01325 fullcmd = e->generator(matchstr, word, (!ast_strlen_zero(word) ? (x - 1) : (x)), state);
01326 if (fullcmd) {
01327 if (lock)
01328 ast_mutex_unlock(&clilock);
01329 free(dup);
01330 return fullcmd;
01331 }
01332 }
01333
01334 }
01335 if (lock)
01336 ast_mutex_unlock(&clilock);
01337 free(dup);
01338 }
01339 return NULL;
01340 }
01341
01342 char *ast_cli_generator(char *text, char *word, int state)
01343 {
01344 return __ast_cli_generator(text, word, state, 1);
01345 }
01346
01347 int ast_cli_command(int fd, char *s)
01348 {
01349 char *argv[AST_MAX_ARGS];
01350 struct ast_cli_entry *e;
01351 int x;
01352 char *dup;
01353 int tws;
01354
01355 if ((dup = parse_args(s, &x, argv, sizeof(argv) / sizeof(argv[0]), &tws))) {
01356
01357 if (x > 0) {
01358 ast_mutex_lock(&clilock);
01359 e = find_cli(argv, 0);
01360 if (e)
01361 e->inuse++;
01362 ast_mutex_unlock(&clilock);
01363 if (e) {
01364 switch(e->handler(fd, x, argv)) {
01365 case RESULT_SHOWUSAGE:
01366 if (e->usage)
01367 ast_cli(fd, "%s", e->usage);
01368 else
01369 ast_cli(fd, "%s", "Invalid usage, but no usage information available.\n");
01370 break;
01371 }
01372 } else
01373 ast_cli(fd, "No such command '%s' (type 'help' for help)\n", find_best(argv));
01374 if (e) {
01375 ast_mutex_lock(&clilock);
01376 e->inuse--;
01377 ast_mutex_unlock(&clilock);
01378 }
01379 }
01380 free(dup);
01381 } else {
01382 ast_log(LOG_WARNING, "Out of memory\n");
01383 return -1;
01384 }
01385 return 0;
01386 }