00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
#include <unistd.h>
00015
#include <stdlib.h>
00016
#include <asterisk/logger.h>
00017
#include <asterisk/options.h>
00018
#include <asterisk/cli.h>
00019
#include <asterisk/module.h>
00020
#include <asterisk/channel.h>
00021
#include <asterisk/channel_pvt.h>
00022
#include <asterisk/manager.h>
00023
#include <asterisk/utils.h>
00024
#include <asterisk/lock.h>
00025
#include <sys/signal.h>
00026
#include <stdio.h>
00027
#include <signal.h>
00028
#include <string.h>
00029
00030
#include "readline/readline.h"
00031
00032
#include "asterisk.h"
00033
#include "build.h"
00034
#include "astconf.h"
00035
00036 #define VERSION_INFO "Asterisk " ASTERISK_VERSION " built by " BUILD_USER "@" BUILD_HOSTNAME \
" on a " BUILD_MACHINE " running " BUILD_OS
00037
00038
void ast_cli(
int fd,
char *fmt, ...)
00039 {
00040
char *stuff;
00041
int res = 0;
00042
00043 va_list ap;
00044 va_start(ap, fmt);
00045 res =
vasprintf(&stuff, fmt, ap);
00046 va_end(ap);
00047
if (res == -1) {
00048
ast_log(
LOG_ERROR,
"Out of memory\n");
00049 }
else {
00050
ast_carefulwrite(fd, stuff, strlen(stuff), 100);
00051
free(stuff);
00052 }
00053 }
00054
00055
AST_MUTEX_DEFINE_STATIC(clilock);
00056
00057
struct ast_cli_entry *
helpers = NULL;
00058
00059
static char load_help[] =
00060
"Usage: load <module name>\n"
00061
" Loads the specified module into Asterisk.\n";
00062
00063
static char unload_help[] =
00064
"Usage: unload [-f|-h] <module name>\n"
00065
" Unloads the specified module from Asterisk. The -f\n"
00066
" option causes the module to be unloaded even if it is\n"
00067
" in use (may cause a crash) and the -h module causes the\n"
00068
" module to be unloaded even if the module says it cannot, \n"
00069
" which almost always will cause a crash.\n";
00070
00071
static char help_help[] =
00072
"Usage: help [topic]\n"
00073
" When called with a topic as an argument, displays usage\n"
00074
" information on the given command. If called without a\n"
00075
" topic, it provides a list of commands.\n";
00076
00077
static char chanlist_help[] =
00078
"Usage: show channels [concise]\n"
00079
" Lists currently defined channels and some information about\n"
00080
" them. If 'concise' is specified, format is abridged and in\n"
00081
" a more easily machine parsable format\n";
00082
00083
static char reload_help[] =
00084
"Usage: reload\n"
00085
" Reloads configuration files for all modules which support\n"
00086
" reloading.\n";
00087
00088
static char set_verbose_help[] =
00089
"Usage: set verbose <level>\n"
00090
" Sets level of verbose messages to be displayed. 0 means\n"
00091
" no messages should be displayed.\n";
00092
00093
static char softhangup_help[] =
00094
"Usage: soft hangup <channel>\n"
00095
" Request that a channel be hung up. The hangup takes effect\n"
00096
" the next time the driver reads or writes from the channel\n";
00097
00098
static int handle_load(
int fd,
int argc,
char *argv[])
00099 {
00100
if (argc != 2)
00101
return RESULT_SHOWUSAGE;
00102
if (
ast_load_resource(argv[1])) {
00103
ast_cli(fd,
"Unable to load module %s\n", argv[1]);
00104
return RESULT_FAILURE;
00105 }
00106
return RESULT_SUCCESS;
00107 }
00108
00109
static int handle_reload(
int fd,
int argc,
char *argv[])
00110 {
00111
if (argc != 1)
00112
return RESULT_SHOWUSAGE;
00113
ast_module_reload();
00114
return RESULT_SUCCESS;
00115 }
00116
00117
static int handle_set_verbose(
int fd,
int argc,
char *argv[])
00118 {
00119
int val;
00120
00121
if ((argc != 3) && (argc != 4))
00122
return RESULT_SHOWUSAGE;
00123
if ((argc == 4) && strcasecmp(argv[2],
"atleast"))
00124
return RESULT_SHOWUSAGE;
00125
if (argc == 3)
00126
option_verbose = atoi(argv[2]);
00127
else {
00128 val = atoi(argv[3]);
00129
if (val >
option_verbose)
00130
option_verbose = val;
00131 }
00132
return RESULT_SUCCESS;
00133 }
00134
00135
static int handle_unload(
int fd,
int argc,
char *argv[])
00136 {
00137
int x;
00138
int force=
AST_FORCE_SOFT;
00139
if (argc < 2)
00140
return RESULT_SHOWUSAGE;
00141
for (x=1;x<argc;x++) {
00142
if (argv[x][0] ==
'-') {
00143
switch(argv[x][1]) {
00144
case 'f':
00145 force =
AST_FORCE_FIRM;
00146
break;
00147
case 'h':
00148 force =
AST_FORCE_HARD;
00149
break;
00150
default:
00151
return RESULT_SHOWUSAGE;
00152 }
00153 }
else if (x != argc - 1)
00154
return RESULT_SHOWUSAGE;
00155
else if (
ast_unload_resource(argv[x], force)) {
00156
ast_cli(fd,
"Unable to unload resource %s\n", argv[x]);
00157
return RESULT_FAILURE;
00158 }
00159 }
00160
return RESULT_SUCCESS;
00161 }
00162
00163
#define MODLIST_FORMAT "%-25s %-40.40s %-10d\n"
00164 #define MODLIST_FORMAT2 "%-25s %-40.40s %-10s\n"
00165
00166
AST_MUTEX_DEFINE_STATIC(climodentrylock);
00167
static int climodentryfd = -1;
00168
00169
static int modlist_modentry(
char *
module,
char *description,
int usecnt)
00170 {
00171
ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
00172
return 0;
00173 }
00174
00175
static char modlist_help[] =
00176
"Usage: show modules\n"
00177
" Shows Asterisk modules currently in use, and usage "
00178
"statistics.\n";
00179
00180
static char version_help[] =
00181
"Usage: show version\n"
00182
" Shows Asterisk version information.\n ";
00183
00184
static char *format_uptimestr(time_t timeval)
00185 {
00186
int years = 0, weeks = 0, days = 0, hours = 0, mins = 0, secs = 0;
00187
char timestr[256]=
"";
00188
int bytes = 0;
00189
int maxbytes = 0;
00190
int offset = 0;
00191
#define SECOND (1)
00192
#define MINUTE (SECOND*60)
00193
#define HOUR (MINUTE*60)
00194
#define DAY (HOUR*24)
00195
#define WEEK (DAY*7)
00196
#define YEAR (DAY*365)
00197
#define ESS(x) ((x == 1) ? "" : "s")
00198
00199 maxbytes =
sizeof(timestr);
00200
if (timeval < 0)
00201
return NULL;
00202
if (timeval >
YEAR) {
00203 years = (timeval /
YEAR);
00204 timeval -= (years *
YEAR);
00205
if (years > 0) {
00206 snprintf(timestr + offset, maxbytes,
"%d year%s, ", years,
ESS(years));
00207 bytes = strlen(timestr + offset);
00208 offset += bytes;
00209 maxbytes -= bytes;
00210 }
00211 }
00212
if (timeval >
WEEK) {
00213 weeks = (timeval /
WEEK);
00214 timeval -= (weeks *
WEEK);
00215
if (weeks > 0) {
00216 snprintf(timestr + offset, maxbytes,
"%d week%s, ", weeks,
ESS(weeks));
00217 bytes = strlen(timestr + offset);
00218 offset += bytes;
00219 maxbytes -= bytes;
00220 }
00221 }
00222
if (timeval >
DAY) {
00223 days = (timeval /
DAY);
00224 timeval -= (days *
DAY);
00225
if (days > 0) {
00226 snprintf(timestr + offset, maxbytes,
"%d day%s, ", days,
ESS(days));
00227 bytes = strlen(timestr + offset);
00228 offset += bytes;
00229 maxbytes -= bytes;
00230 }
00231 }
00232
if (timeval >
HOUR) {
00233 hours = (timeval /
HOUR);
00234 timeval -= (hours *
HOUR);
00235
if (hours > 0) {
00236 snprintf(timestr + offset, maxbytes,
"%d hour%s, ", hours,
ESS(hours));
00237 bytes = strlen(timestr + offset);
00238 offset += bytes;
00239 maxbytes -= bytes;
00240 }
00241 }
00242
if (timeval >
MINUTE) {
00243 mins = (timeval /
MINUTE);
00244 timeval -= (mins *
MINUTE);
00245
if (mins > 0) {
00246 snprintf(timestr + offset, maxbytes,
"%d minute%s, ", mins,
ESS(mins));
00247 bytes = strlen(timestr + offset);
00248 offset += bytes;
00249 maxbytes -= bytes;
00250 }
00251 }
00252 secs = timeval;
00253
00254
if (secs > 0) {
00255 snprintf(timestr + offset, maxbytes,
"%d second%s", secs,
ESS(secs));
00256 }
00257
00258
return timestr ?
strdup(timestr) : NULL;
00259 }
00260
00261
static int handle_showuptime(
int fd,
int argc,
char *argv[])
00262 {
00263 time_t curtime, tmptime;
00264
char *timestr;
00265
00266 time(&curtime);
00267
if (
ast_startuptime) {
00268 tmptime = curtime -
ast_startuptime;
00269 timestr = format_uptimestr(tmptime);
00270
if (timestr) {
00271
ast_cli(fd,
"System uptime: %s\n", timestr);
00272
free(timestr);
00273 }
00274 }
00275
if (
ast_lastreloadtime) {
00276 tmptime = curtime -
ast_lastreloadtime;
00277 timestr = format_uptimestr(tmptime);
00278
if (timestr) {
00279
ast_cli(fd,
"Last reload: %s\n", timestr);
00280
free(timestr);
00281 }
00282 }
00283
return RESULT_SUCCESS;
00284 }
00285
00286
static int handle_modlist(
int fd,
int argc,
char *argv[])
00287 {
00288
if (argc != 2)
00289
return RESULT_SHOWUSAGE;
00290
ast_mutex_lock(&climodentrylock);
00291 climodentryfd = fd;
00292
ast_cli(fd, MODLIST_FORMAT2,
"Module",
"Description",
"Use Count");
00293
ast_update_module_list(modlist_modentry);
00294 climodentryfd = -1;
00295
ast_mutex_unlock(&climodentrylock);
00296
return RESULT_SUCCESS;
00297 }
00298
00299
static int handle_version(
int fd,
int argc,
char *argv[])
00300 {
00301
if (argc != 2)
00302
return RESULT_SHOWUSAGE;
00303
ast_cli(fd,
"%s\n", VERSION_INFO);
00304
return RESULT_SUCCESS;
00305 }
00306
static int handle_chanlist(
int fd,
int argc,
char *argv[])
00307 {
00308
#define FORMAT_STRING "%15s (%-10s %-12s %-4d) %7s %-12s %-15s\n"
00309
#define FORMAT_STRING2 "%15s (%-10s %-12s %-4s) %7s %-12s %-15s\n"
00310
#define CONCISE_FORMAT_STRING "%s:%s:%s:%d:%s:%s:%s:%s:%s:%d\n"
00311
00312
struct ast_channel *c=NULL;
00313
int numchans = 0;
00314
int concise = 0;
00315
if (argc < 2 || argc > 3)
00316
return RESULT_SHOWUSAGE;
00317
00318 concise = (argc == 3 && (!strcasecmp(argv[2],
"concise")));
00319 c =
ast_channel_walk_locked(NULL);
00320
if(!concise)
00321
ast_cli(fd, FORMAT_STRING2,
"Channel",
"Context",
"Extension",
"Pri",
"State",
"Appl.",
"Data");
00322
while(c) {
00323
if(concise)
00324
ast_cli(fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority,
ast_state2str(c->_state),
00325 c->appl ? c->appl :
"(None)", c->data ? ( !ast_strlen_zero(c->data) ? c->data :
"" ):
"",
00326 (c->callerid && !ast_strlen_zero(c->callerid)) ? c->callerid :
"",
00327 (c->accountcode && !ast_strlen_zero(c->accountcode)) ? c->accountcode :
"",c->amaflags);
00328
else
00329
ast_cli(fd, FORMAT_STRING, c->name, c->context, c->exten, c->priority,
ast_state2str(c->_state),
00330 c->appl ? c->appl :
"(None)", c->data ? ( !ast_strlen_zero(c->data) ? c->data :
"(Empty)" ):
"(None)");
00331
00332 numchans++;
00333
ast_mutex_unlock(&c->lock);
00334 c =
ast_channel_walk_locked(c);
00335 }
00336
if(!concise)
00337
ast_cli(fd,
"%d active channel(s)\n", numchans);
00338
return RESULT_SUCCESS;
00339 }
00340
00341
static char showchan_help[] =
00342
"Usage: show channel <channel>\n"
00343
" Shows lots of information about the specified channel.\n";
00344
00345
static char debugchan_help[] =
00346
"Usage: debug channel <channel>\n"
00347
" Enables debugging on a specific channel.\n";
00348
00349
static char nodebugchan_help[] =
00350
"Usage: no debug channel <channel>\n"
00351
" Disables debugging on a specific channel.\n";
00352
00353
static char commandcomplete_help[] =
00354
"Usage: _command complete \"<line>\" text state\n"
00355
" This function is used internally to help with command completion and should.\n"
00356
" never be called by the user directly.\n";
00357
00358
static char commandnummatches_help[] =
00359
"Usage: _command nummatches \"<line>\" text \n"
00360
" This function is used internally to help with command completion and should.\n"
00361
" never be called by the user directly.\n";
00362
00363
static char commandmatchesarray_help[] =
00364
"Usage: _command matchesarray \"<line>\" text \n"
00365
" This function is used internally to help with command completion and should.\n"
00366
" never be called by the user directly.\n";
00367
00368
static int handle_softhangup(
int fd,
int argc,
char *argv[])
00369 {
00370
struct ast_channel *c=NULL;
00371
if (argc != 3)
00372
return RESULT_SHOWUSAGE;
00373 c =
ast_channel_walk_locked(NULL);
00374
while(c) {
00375
if (!strcasecmp(c->name, argv[2])) {
00376
ast_cli(fd,
"Requested Hangup on channel '%s'\n", c->name);
00377
ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
00378
ast_mutex_unlock(&c->lock);
00379
break;
00380 }
00381
ast_mutex_unlock(&c->lock);
00382 c =
ast_channel_walk_locked(c);
00383 }
00384
if (!c)
00385
ast_cli(fd,
"%s is not a known channel\n", argv[2]);
00386
return RESULT_SUCCESS;
00387 }
00388
00389
static char *__ast_cli_generator(
char *text,
char *word,
int state,
int lock);
00390
00391
static int handle_commandmatchesarray(
int fd,
int argc,
char *argv[])
00392 {
00393
char *buf;
00394
int buflen = 2048;
00395
int len = 0;
00396
char **matches;
00397
int x;
00398
00399
if (argc != 4)
00400
return RESULT_SHOWUSAGE;
00401 buf =
malloc(buflen);
00402
if (!buf)
00403
return RESULT_FAILURE;
00404 buf[len] =
'\0';
00405 matches =
ast_cli_completion_matches(argv[2], argv[3]);
00406
if (matches) {
00407
for (x=0; matches[x]; x++) {
00408
#if 0
00409
printf(
"command matchesarray for '%s' %s got '%s'\n", argv[2], argv[3], matches[x]);
00410
#endif
00411
if (len + strlen(matches[x]) >= buflen) {
00412 buflen += strlen(matches[x]) * 3;
00413 buf =
realloc(buf, buflen);
00414 }
00415 len += sprintf( buf + len,
"%s ", matches[x]);
00416
free(matches[x]);
00417 matches[x] = NULL;
00418 }
00419
free(matches);
00420 }
00421
#if 0
00422
printf(
"array for '%s' %s got '%s'\n", argv[2], argv[3], buf);
00423
#endif
00424
00425
if (buf) {
00426
ast_cli(fd,
"%s%s",buf, AST_CLI_COMPLETE_EOF);
00427
free(buf);
00428 }
else
00429
ast_cli(fd,
"NULL\n");
00430
00431
return RESULT_SUCCESS;
00432 }
00433
00434
00435
00436
static int handle_commandnummatches(
int fd,
int argc,
char *argv[])
00437 {
00438
int matches = 0;
00439
00440
if (argc != 4)
00441
return RESULT_SHOWUSAGE;
00442
00443 matches =
ast_cli_generatornummatches(argv[2], argv[3]);
00444
00445
#if 0
00446
printf(
"Search for '%s' %s got '%d'\n", argv[2], argv[3], matches);
00447
#endif
00448
ast_cli(fd,
"%d", matches);
00449
00450
return RESULT_SUCCESS;
00451 }
00452
00453
static int handle_commandcomplete(
int fd,
int argc,
char *argv[])
00454 {
00455
char *buf;
00456
#if 0
00457
printf(
"Search for %d args: '%s', '%s', '%s', '%s'\n", argc, argv[0], argv[1], argv[2], argv[3]);
00458
#endif
00459
if (argc != 5)
00460
return RESULT_SHOWUSAGE;
00461 buf = __ast_cli_generator(argv[2], argv[3], atoi(argv[4]), 0);
00462
#if 0
00463
printf(
"Search for '%s' %s %d got '%s'\n", argv[2], argv[3], atoi(argv[4]), buf);
00464
#endif
00465
if (buf) {
00466
ast_cli(fd, buf);
00467
free(buf);
00468 }
else
00469
ast_cli(fd,
"NULL\n");
00470
return RESULT_SUCCESS;
00471 }
00472
00473
static int handle_debugchan(
int fd,
int argc,
char *argv[])
00474 {
00475
struct ast_channel *c=NULL;
00476
if (argc != 3)
00477
return RESULT_SHOWUSAGE;
00478 c =
ast_channel_walk_locked(NULL);
00479
while(c) {
00480
if (!strcasecmp(c->name, argv[2])) {
00481 c->fin |= 0x80000000;
00482 c->fout |= 0x80000000;
00483
break;
00484 }
00485
ast_mutex_unlock(&c->lock);
00486 c =
ast_channel_walk_locked(c);
00487 }
00488
if (c) {
00489
ast_cli(fd,
"Debugging enabled on channel %s\n", c->name);
00490
ast_mutex_unlock(&c->lock);
00491 }
00492
else
00493
ast_cli(fd,
"No such channel %s\n", argv[2]);
00494
return RESULT_SUCCESS;
00495 }
00496
00497
static int handle_nodebugchan(
int fd,
int argc,
char *argv[])
00498 {
00499
struct ast_channel *c=NULL;
00500
if (argc != 4)
00501
return RESULT_SHOWUSAGE;
00502 c =
ast_channel_walk_locked(NULL);
00503
while(c) {
00504
if (!strcasecmp(c->name, argv[3])) {
00505 c->fin &= 0x7fffffff;
00506 c->fout &= 0x7fffffff;
00507
break;
00508 }
00509
ast_mutex_unlock(&c->lock);
00510 c =
ast_channel_walk_locked(c);
00511 }
00512
if (c) {
00513
ast_cli(fd,
"Debugging disabled on channel %s\n", c->name);
00514
ast_mutex_unlock(&c->lock);
00515 }
else
00516
ast_cli(fd,
"No such channel %s\n", argv[2]);
00517
return RESULT_SUCCESS;
00518 }
00519
00520
00521
00522
static int handle_showchan(
int fd,
int argc,
char *argv[])
00523 {
00524
struct ast_channel *c=NULL;
00525
if (argc != 3)
00526
return RESULT_SHOWUSAGE;
00527 c =
ast_channel_walk_locked(NULL);
00528
while(c) {
00529
if (!strcasecmp(c->name, argv[2])) {
00530
ast_cli(fd,
00531
" -- General --\n"
00532
" Name: %s\n"
00533
" Type: %s\n"
00534
" UniqueID: %s\n"
00535
" Caller ID: %s\n"
00536
" DNID Digits: %s\n"
00537
" State: %s (%d)\n"
00538
" Rings: %d\n"
00539
" NativeFormat: %d\n"
00540
" WriteFormat: %d\n"
00541
" ReadFormat: %d\n"
00542
"1st File Descriptor: %d\n"
00543
" Frames in: %d%s\n"
00544
" Frames out: %d%s\n"
00545
" Time to Hangup: %ld\n"
00546
" -- PBX --\n"
00547
" Context: %s\n"
00548
" Extension: %s\n"
00549
" Priority: %d\n"
00550
" Call Group: %d\n"
00551
" Pickup Group: %d\n"
00552
" Application: %s\n"
00553
" Data: %s\n"
00554
" Stack: %d\n"
00555
" Blocking in: %s\n",
00556 c->name, c->type, c->uniqueid,
00557 (c->callerid ? c->callerid :
"(N/A)"),
00558 (c->dnid ? c->dnid :
"(N/A)" ),
ast_state2str(c->_state), c->_state, c->rings, c->nativeformats, c->writeformat, c->readformat,
00559 c->fds[0], c->fin & 0x7fffffff, (c->fin & 0x80000000) ?
" (DEBUGGED)" :
"",
00560 c->fout & 0x7fffffff, (c->fout & 0x80000000) ?
" (DEBUGGED)" :
"", (
long)c->whentohangup,
00561 c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl :
"(N/A)" ),
00562 ( c-> data ? (!ast_strlen_zero(c->data) ? c->data :
"(Empty)") :
"(None)"),
00563 c->stack, (c->blocking ? c->blockproc :
"(Not Blocking)"));
00564
ast_mutex_unlock(&c->lock);
00565
break;
00566 }
00567
ast_mutex_unlock(&c->lock);
00568 c =
ast_channel_walk_locked(c);
00569 }
00570
if (!c)
00571
ast_cli(fd,
"%s is not a known channel\n", argv[2]);
00572
return RESULT_SUCCESS;
00573 }
00574
00575
static char *complete_ch(
char *line,
char *word,
int pos,
int state)
00576 {
00577
struct ast_channel *c;
00578
int which=0;
00579
char *ret;
00580 c =
ast_channel_walk_locked(NULL);
00581
while(c) {
00582
if (!strncasecmp(word, c->name, strlen(word))) {
00583
if (++which > state)
00584
break;
00585 }
00586
ast_mutex_unlock(&c->lock);
00587 c =
ast_channel_walk_locked(c);
00588 }
00589
if (c) {
00590 ret =
strdup(c->name);
00591
ast_mutex_unlock(&c->lock);
00592 }
else
00593 ret = NULL;
00594
return ret;
00595 }
00596
00597
static char *complete_fn(
char *line,
char *word,
int pos,
int state)
00598 {
00599
char *c;
00600
char filename[256];
00601
if (pos != 1)
00602
return NULL;
00603
if (word[0] ==
'/')
00604 strncpy(filename, word,
sizeof(filename)-1);
00605
else
00606 snprintf(filename,
sizeof(filename),
"%s/%s", (
char *)ast_config_AST_MODULE_DIR, word);
00607 c = (
char*)filename_completion_function(filename, state);
00608
if (c && word[0] !=
'/')
00609 c += (strlen((
char*)ast_config_AST_MODULE_DIR) + 1);
00610
return c ?
strdup(c) : c;
00611 }
00612
00613
static int handle_help(
int fd,
int argc,
char *argv[]);
00614
00615
static struct ast_cli_entry builtins[] = {
00616
00617 { {
"_command",
"complete", NULL }, handle_commandcomplete,
"Command complete", commandcomplete_help },
00618 { {
"_command",
"nummatches", NULL }, handle_commandnummatches,
"Returns number of command matches", commandnummatches_help },
00619 { {
"_command",
"matchesarray", NULL }, handle_commandmatchesarray,
"Returns command matches array", commandmatchesarray_help },
00620 { {
"debug",
"channel", NULL }, handle_debugchan,
"Enable debugging on a channel", debugchan_help, complete_ch },
00621 { {
"help", NULL }, handle_help,
"Display help list, or specific help on a command", help_help },
00622 { {
"load", NULL }, handle_load,
"Load a dynamic module by name", load_help, complete_fn },
00623 { {
"no",
"debug",
"channel", NULL }, handle_nodebugchan,
"Disable debugging on a channel", nodebugchan_help, complete_ch },
00624 { {
"reload", NULL }, handle_reload,
"Reload configuration", reload_help },
00625 { {
"set",
"verbose", NULL }, handle_set_verbose,
"Set level of verboseness", set_verbose_help },
00626 { {
"show",
"channels", NULL }, handle_chanlist,
"Display information on channels", chanlist_help },
00627 { {
"show",
"channel", NULL }, handle_showchan,
"Display information on a specific channel", showchan_help, complete_ch },
00628 { {
"show",
"modules", NULL }, handle_modlist,
"List modules and info", modlist_help },
00629 { {
"show",
"uptime", NULL }, handle_showuptime,
"Show uptime information", modlist_help },
00630 { {
"show",
"version", NULL }, handle_version,
"Display version info", version_help },
00631 { {
"soft",
"hangup", NULL }, handle_softhangup,
"Request a hangup on a given channel", softhangup_help, complete_ch },
00632 { {
"unload", NULL }, handle_unload,
"Unload a dynamic module by name", unload_help, complete_fn },
00633 { { NULL }, NULL, NULL, NULL }
00634 };
00635
00636
static struct ast_cli_entry *find_cli(
char *cmds[],
int exact)
00637 {
00638
int x;
00639
int y;
00640
int match;
00641
struct ast_cli_entry *e=NULL;
00642
for (x=0;builtins[x].
cmda[0];x++) {
00643
00644 match = 1;
00645
for (y=0;match && cmds[y]; y++) {
00646
00647
00648
if (!builtins[x].
cmda[y] && !exact)
00649
break;
00650
00651
00652
00653
if (!builtins[x].
cmda[y] || strcasecmp(builtins[x].cmda[y], cmds[y]))
00654 match = 0;
00655 }
00656
00657
00658
if ((exact > -1) && builtins[x].
cmda[y])
00659 match = 0;
00660
if (match)
00661
return &builtins[x];
00662 }
00663
for (e=
helpers;e;e=e->
next) {
00664 match = 1;
00665
for (y=0;match && cmds[y]; y++) {
00666
if (!e->cmda[y] && !exact)
00667
break;
00668
if (!e->cmda[y] || strcasecmp(e->cmda[y], cmds[y]))
00669 match = 0;
00670 }
00671
if ((exact > -1) && e->cmda[y])
00672 match = 0;
00673
if (match)
00674
break;
00675 }
00676
return e;
00677 }
00678
00679
static void join(
char *dest, size_t destsize,
char *w[])
00680 {
00681
int x;
00682
00683
if (!dest || destsize < 1) {
00684
return;
00685 }
00686 dest[0] =
'\0';
00687
for (x=0;w[x];x++) {
00688
if (x)
00689 strncat(dest,
" ", destsize - strlen(dest) - 1);
00690 strncat(dest, w[x], destsize - strlen(dest) - 1);
00691 }
00692 }
00693
00694
static void join2(
char *dest, size_t destsize,
char *w[])
00695 {
00696
int x;
00697
00698
if (!dest || destsize < 1) {
00699
return;
00700 }
00701 dest[0] =
'\0';
00702
for (x=0;w[x];x++) {
00703 strncat(dest, w[x], destsize - strlen(dest) - 1);
00704 }
00705 }
00706
00707
static char *find_best(
char *argv[])
00708 {
00709
static char cmdline[80];
00710
int x;
00711
00712
char *myargv[
AST_MAX_CMD_LEN];
00713
for (x=0;x<
AST_MAX_CMD_LEN;x++)
00714 myargv[x]=NULL;
00715
for (x=0;argv[x];x++) {
00716 myargv[x] = argv[x];
00717
if (!find_cli(myargv, -1))
00718
break;
00719 }
00720 join(cmdline,
sizeof(cmdline), myargv);
00721
return cmdline;
00722 }
00723
00724
int ast_cli_unregister(
struct ast_cli_entry *e)
00725 {
00726
struct ast_cli_entry *cur, *l=NULL;
00727
ast_mutex_lock(&clilock);
00728 cur =
helpers;
00729
while(cur) {
00730
if (e == cur) {
00731
if (e->
inuse) {
00732
ast_log(
LOG_WARNING,
"Can't remove command that is in use\n");
00733 }
else {
00734
00735
if (l)
00736 l->next = e->
next;
00737
else
00738
helpers = e->
next;
00739 e->
next = NULL;
00740
break;
00741 }
00742 }
00743 l = cur;
00744 cur = cur->
next;
00745 }
00746
ast_mutex_unlock(&clilock);
00747
return 0;
00748 }
00749
00750
int ast_cli_register(
struct ast_cli_entry *e)
00751 {
00752
struct ast_cli_entry *cur, *l=NULL;
00753
char fulle[80] =
"", fulltst[80] =
"";
00754
static int len;
00755
ast_mutex_lock(&clilock);
00756 join2(fulle,
sizeof(fulle), e->
cmda);
00757
if (find_cli(e->
cmda, -1)) {
00758
ast_mutex_unlock(&clilock);
00759
ast_log(
LOG_WARNING,
"Command '%s' already registered (or something close enough)\n", fulle);
00760
return -1;
00761 }
00762 cur =
helpers;
00763
while(cur) {
00764 join2(fulltst,
sizeof(fulltst), cur->cmda);
00765 len = strlen(fulltst);
00766
if (strlen(fulle) < len)
00767 len = strlen(fulle);
00768
if (strncasecmp(fulle, fulltst, len) < 0) {
00769
if (l) {
00770 e->
next = l->
next;
00771 l->
next = e;
00772 }
else {
00773 e->
next =
helpers;
00774
helpers = e;
00775 }
00776
break;
00777 }
00778 l = cur;
00779 cur = cur->
next;
00780 }
00781
if (!cur) {
00782
if (l)
00783 l->
next = e;
00784
else
00785
helpers = e;
00786 e->
next = NULL;
00787 }
00788
ast_mutex_unlock(&clilock);
00789
return 0;
00790 }
00791
00792
static int help_workhorse(
int fd,
char *match[])
00793 {
00794
char fullcmd1[80];
00795
char fullcmd2[80];
00796
char matchstr[80];
00797
char *fullcmd;
00798
struct ast_cli_entry *e, *e1, *e2;
00799 e1 = builtins;
00800 e2 =
helpers;
00801
if (match)
00802 join(matchstr,
sizeof(matchstr), match);
00803
while(e1->cmda[0] || e2) {
00804
if (e2)
00805 join(fullcmd2,
sizeof(fullcmd2), e2->cmda);
00806
if (e1->cmda[0])
00807 join(fullcmd1,
sizeof(fullcmd1), e1->cmda);
00808
if (!e1->cmda[0] ||
00809 (e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
00810
00811 e = e2;
00812 fullcmd = fullcmd2;
00813
00814 e2 = e2->next;
00815 }
else {
00816
00817 e = e1;
00818 fullcmd = fullcmd1;
00819 e1++;
00820 }
00821
00822
if (fullcmd[0] ==
'_')
00823
continue;
00824
if (match) {
00825
if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
00826
continue;
00827 }
00828 }
00829
ast_cli(fd,
"%25.25s %s\n", fullcmd, e->summary);
00830 }
00831
return 0;
00832 }
00833
00834
static int handle_help(
int fd,
int argc,
char *argv[]) {
00835
struct ast_cli_entry *e;
00836
char fullcmd[80];
00837
if ((argc < 1))
00838
return RESULT_SHOWUSAGE;
00839
if (argc > 1) {
00840 e = find_cli(argv + 1, 1);
00841
if (e)
00842
ast_cli(fd, e->usage);
00843
else {
00844
if (find_cli(argv + 1, -1)) {
00845
return help_workhorse(fd, argv + 1);
00846 }
else {
00847 join(fullcmd,
sizeof(fullcmd), argv+1);
00848
ast_cli(fd,
"No such command '%s'.\n", fullcmd);
00849 }
00850 }
00851 }
else {
00852
return help_workhorse(fd, NULL);
00853 }
00854
return RESULT_SUCCESS;
00855 }
00856
00857
static char *parse_args(
char *s,
int *max,
char *argv[])
00858 {
00859
char *dup, *cur;
00860
int x=0;
00861
int quoted=0;
00862
int escaped=0;
00863
int whitespace=1;
00864
00865 dup =
strdup(s);
00866
if (dup) {
00867 cur = dup;
00868
while(*s) {
00869
switch(*s) {
00870
case '"':
00871
00872
if (escaped)
00873
goto normal;
00874
else
00875 quoted = !quoted;
00876
if (quoted && whitespace) {
00877
00878 argv[x++] = cur;
00879 whitespace=0;
00880 }
00881 escaped = 0;
00882
break;
00883
case ' ':
00884
case '\t':
00885
if (!quoted && !escaped) {
00886
00887
00888 whitespace = 1;
00889 *(cur++) =
'\0';
00890 }
else
00891
00892
goto normal;
00893
break;
00894
case '\\':
00895
00896
if (escaped) {
00897
goto normal;
00898 }
else {
00899 escaped=1;
00900 }
00901
break;
00902
default:
00903 normal:
00904
if (whitespace) {
00905
if (x >=
AST_MAX_ARGS -1) {
00906
ast_log(LOG_WARNING,
"Too many arguments, truncating\n");
00907
break;
00908 }
00909
00910 argv[x++] = cur;
00911 whitespace=0;
00912 }
00913 *(cur++) = *
s;
00914 escaped=0;
00915 }
00916
s++;
00917 }
00918
00919 *(cur++) =
'\0';
00920 argv[x] = NULL;
00921 *max = x;
00922 }
00923
return dup;
00924 }
00925
00926
00927
int ast_cli_generatornummatches(
char *text,
char *word)
00928 {
00929
int matches = 0, i = 0;
00930
char *buf, *oldbuf = NULL;
00931
00932
00933
while ( (buf =
ast_cli_generator(text, word, i)) ) {
00934
if (++i > 1 && strcmp(buf,oldbuf) == 0) {
00935
continue;
00936 }
00937 oldbuf = buf;
00938 matches++;
00939 }
00940
00941
return matches;
00942 }
00943
00944
char **
ast_cli_completion_matches(
char *text,
char *word)
00945 {
00946
char **match_list = NULL, *retstr, *prevstr;
00947 size_t match_list_len, max_equal, which, i;
00948
int matches = 0;
00949
00950 match_list_len = 1;
00951
while ((retstr =
ast_cli_generator(text, word, matches)) != NULL) {
00952
if (matches + 1 >= match_list_len) {
00953 match_list_len <<= 1;
00954 match_list =
realloc(match_list, match_list_len *
sizeof(
char *));
00955 }
00956 match_list[++matches] = retstr;
00957 }
00958
00959
if (!match_list)
00960
return (
char **) NULL;
00961
00962 which = 2;
00963 prevstr = match_list[1];
00964 max_equal = strlen(prevstr);
00965
for (; which <= matches; which++) {
00966
for (i = 0; i < max_equal && prevstr[i] == match_list[which][i]; i++)
00967
continue;
00968 max_equal = i;
00969 }
00970
00971 retstr =
malloc(max_equal + 1);
00972 (
void) strncpy(retstr, match_list[1], max_equal);
00973 retstr[max_equal] =
'\0';
00974 match_list[0] = retstr;
00975
00976
if (matches + 1 >= match_list_len)
00977 match_list =
realloc(match_list, (match_list_len + 1) *
sizeof(
char *));
00978 match_list[matches + 1] = (
char *) NULL;
00979
00980
return (match_list);
00981 }
00982
00983
static char *__ast_cli_generator(
char *text,
char *word,
int state,
int lock)
00984 {
00985
char *argv[
AST_MAX_ARGS];
00986
struct ast_cli_entry *e, *e1, *e2;
00987
int x;
00988
int matchnum=0;
00989
char *dup, *res;
00990
char fullcmd1[80];
00991
char fullcmd2[80];
00992
char matchstr[80];
00993
char *fullcmd;
00994
00995
if ((dup = parse_args(text, &x, argv))) {
00996 join(matchstr,
sizeof(matchstr), argv);
00997
if (lock)
00998
ast_mutex_lock(&clilock);
00999 e1 = builtins;
01000 e2 =
helpers;
01001
while(e1->cmda[0] || e2) {
01002
if (e2)
01003 join(fullcmd2,
sizeof(fullcmd2), e2->cmda);
01004
if (e1->cmda[0])
01005 join(fullcmd1,
sizeof(fullcmd1), e1->cmda);
01006
if (!e1->cmda[0] ||
01007 (e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
01008
01009 e = e2;
01010 fullcmd = fullcmd2;
01011
01012 e2 = e2->next;
01013 }
else {
01014
01015 e = e1;
01016 fullcmd = fullcmd1;
01017 e1++;
01018 }
01019
if ((fullcmd[0] !=
'_') && !strncasecmp(text, fullcmd, strlen(text))) {
01020
01021 matchnum++;
01022
if (matchnum > state) {
01023
01024
if (!ast_strlen_zero(word) && x>0) {
01025 res = e->cmda[x-1];
01026 }
else {
01027 res = e->cmda[x];
01028 }
01029
if (res) {
01030
if (lock)
01031
ast_mutex_unlock(&clilock);
01032
free(dup);
01033
return res ?
strdup(res) : NULL;
01034 }
01035 }
01036 }
01037
if (e->generator && !strncasecmp(matchstr, fullcmd, strlen(fullcmd))) {
01038
01039
01040 fullcmd = e->generator(text, word, (!ast_strlen_zero(word) ? (x - 1) : (x)), state);
01041
if (lock)
01042
ast_mutex_unlock(&clilock);
01043
free(dup);
01044
return fullcmd;
01045 }
01046
01047 }
01048
if (lock)
01049
ast_mutex_unlock(&clilock);
01050
free(dup);
01051 }
01052
return NULL;
01053 }
01054
01055
char *
ast_cli_generator(
char *text,
char *word,
int state)
01056 {
01057
return __ast_cli_generator(text, word, state, 1);
01058 }
01059
01060
int ast_cli_command(
int fd,
char *s)
01061 {
01062
char *argv[
AST_MAX_ARGS];
01063
struct ast_cli_entry *e;
01064
int x;
01065
char *dup;
01066 x =
AST_MAX_ARGS;
01067
if ((dup = parse_args(
s, &x, argv))) {
01068
01069
if (x > 0) {
01070
ast_mutex_lock(&clilock);
01071 e = find_cli(argv, 0);
01072
if (e)
01073 e->inuse++;
01074
ast_mutex_unlock(&clilock);
01075
if (e) {
01076
switch(e->handler(fd, x, argv)) {
01077
case RESULT_SHOWUSAGE:
01078
ast_cli(fd, e->usage);
01079
break;
01080 }
01081 }
else
01082
ast_cli(fd,
"No such command '%s' (type 'help' for help)\n", find_best(argv));
01083
if (e) {
01084
ast_mutex_lock(&clilock);
01085 e->inuse--;
01086
ast_mutex_unlock(&clilock);
01087 }
01088 }
01089
free(dup);
01090 }
else {
01091
ast_log(
LOG_WARNING,
"Out of memory\n");
01092
return -1;
01093 }
01094
return 0;
01095 }
01096