Fri Jan 31 13:16:21 2014

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

Generated on 31 Jan 2014 for Asterisk - the Open Source PBX by  doxygen 1.6.1