Sat Nov 1 06:28:30 2008

Asterisk developer's documentation


cli.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Standard Command Line Interface
00022  *
00023  * \author Mark Spencer <markster@digium.com> 
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 135597 $")
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 /*! \brief Initial buffer size for resulting strings in ast_cli() */
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    /* "set verbose [atleast] N" */
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    /* "set debug [atleast] N" */
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    /* 'core set debug <level>'
00308     * 'core set debug <level> <fn>'
00309     * 'core set debug atleast <level>'
00310     * 'core set debug atleast <level> <fn>'
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    /* Comparing the like with the module */
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; /* the main part - years, weeks, etc. */
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")   /* plural suffix */
00508 #define NEEDCOMMA(x) ((x)? ",": "") /* define if we need a comma */
00509    if (timeval < 0)  /* invalid, nothing to show */
00510       return;
00511    if (printsec)  {  /* plain seconds output */
00512       ast_build_string(&s, &maxbytes, "%lu", (u_long)timeval);
00513       timeval = 0; /* bypass the other cases */
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    /* 'show uptime [seconds]' */
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    /* 'core show uptime [seconds]' */
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; /* global, protected by climodentrylock */
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, ""),   /* XXX different from verbose ? */
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, ""),   /* XXX different from verbose ? */
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                /* Memory allocation failure...  Just free old buffer and be done */
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    /* 'debug channel {all|chan_id}' */
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    /* 'core set debug channel {all|chan_id}' */
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,