From 0332f58f8f85f42f2a88210c48695064526a968e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Wed, 26 Sep 2012 18:23:37 +0000 Subject: [PATCH] Fixed meetme tab completion and command documentation. * Removed unnecessary case sensitivity in meetme list, lock, unlock, mute, unmute, and kick commands. * Separated meetme lock/unlock, mute/unmute, and kick commands into their own registered commands to simplify tab completion and parameter checking. meetme_lock_cmd(), meetme_mute_cmd(), and meetme_kick_cmd() * Simplified meetme_show_cmd() (closes issue AST-1006) Reported by: John Bigelow Tested by: rmudgett ........ Merged revisions 373815 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 373816 from http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged revisions 373818 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@373835 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_meetme.c | 397 +++++++++++++++++++++++++++------------------- 1 file changed, 238 insertions(+), 159 deletions(-) diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 0cab44c7c9..4669f36acb 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -538,8 +538,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") ***/ -#define CONFIG_FILE_NAME "meetme.conf" -#define SLA_CONFIG_FILE "sla.conf" +#define CONFIG_FILE_NAME "meetme.conf" +#define SLA_CONFIG_FILE "sla.conf" +#define STR_CONCISE "concise" /*! each buffer is 20ms, so this is 640ms total */ #define DEFAULT_AUDIO_BUFFERS 32 @@ -1336,71 +1337,131 @@ cnfout: return cnf; } -static char *complete_meetmecmd(const char *line, const char *word, int pos, int state) +static char *complete_confno(const char *word, int state) { - static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL}; - - int len = strlen(word); + struct ast_conference *cnf; + char *ret = NULL; int which = 0; - struct ast_conference *cnf = NULL; - struct ast_conf_user *usr = NULL; - char *confno = NULL; - char usrno[50] = ""; - char *myline, *ret = NULL; - - if (pos == 1) { /* Command */ - return ast_cli_complete(word, cmds, state); - } else if (pos == 2) { /* Conference Number */ + int len = strlen(word); + + AST_LIST_LOCK(&confs); + AST_LIST_TRAVERSE(&confs, cnf, list) { + if (!strncmp(word, cnf->confno, len) && ++which > state) { + /* dup before releasing the lock */ + ret = ast_strdup(cnf->confno); + break; + } + } + AST_LIST_UNLOCK(&confs); + return ret; +} + +static char *complete_userno(struct ast_conference *cnf, const char *word, int state) +{ + char usrno[50]; + struct ao2_iterator iter; + struct ast_conf_user *usr; + char *ret = NULL; + int which = 0; + int len = strlen(word); + + iter = ao2_iterator_init(cnf->usercontainer, 0); + for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) { + snprintf(usrno, sizeof(usrno), "%d", usr->user_no); + if (!strncmp(word, usrno, len) && ++which > state) { + ao2_ref(usr, -1); + ret = ast_strdup(usrno); + break; + } + } + ao2_iterator_destroy(&iter); + return ret; +} + +static char *complete_meetmecmd_mute_kick(const char *line, const char *word, int pos, int state) +{ + if (pos == 2) { + return complete_confno(word, state); + } + if (pos == 3) { + int len = strlen(word); + char *ret = NULL; + char *saved = NULL; + char *myline; + char *confno; + struct ast_conference *cnf; + + if (!strncasecmp(word, "all", len)) { + if (state == 0) { + return ast_strdup("all"); + } + --state; + } + + /* Extract the confno from the command line. */ + myline = ast_strdupa(line); + strtok_r(myline, " ", &saved); + strtok_r(NULL, " ", &saved); + confno = strtok_r(NULL, " ", &saved); + AST_LIST_LOCK(&confs); AST_LIST_TRAVERSE(&confs, cnf, list) { - if (!strncasecmp(word, cnf->confno, len) && ++which > state) { - ret = cnf->confno; + if (!strcmp(confno, cnf->confno)) { + ret = complete_userno(cnf, word, state); break; } } - ret = ast_strdup(ret); /* dup before releasing the lock */ AST_LIST_UNLOCK(&confs); + return ret; - } else if (pos == 3) { - /* User Number || Conf Command option*/ - if (strstr(line, "mute") || strstr(line, "kick")) { - if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len)) - return ast_strdup("all"); - which++; - AST_LIST_LOCK(&confs); + } + return NULL; +} - /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */ - myline = ast_strdupa(line); - if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) { - while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0)) - ; - } - - AST_LIST_TRAVERSE(&confs, cnf, list) { - if (!strcmp(confno, cnf->confno)) - break; - } +static char *complete_meetmecmd_lock(const char *word, int pos, int state) +{ + if (pos == 2) { + return complete_confno(word, state); + } + return NULL; +} - if (cnf) { - struct ao2_iterator user_iter; - user_iter = ao2_iterator_init(cnf->usercontainer, 0); +static char *complete_meetmecmd_list(const char *line, const char *word, int pos, int state) +{ + int len; - while((usr = ao2_iterator_next(&user_iter))) { - snprintf(usrno, sizeof(usrno), "%d", usr->user_no); - if (!strncasecmp(word, usrno, len) && ++which > state) { - ao2_ref(usr, -1); - break; - } - ao2_ref(usr, -1); - } - ao2_iterator_destroy(&user_iter); - AST_LIST_UNLOCK(&confs); - return usr ? ast_strdup(usrno) : NULL; + if (pos == 2) { + len = strlen(word); + if (!strncasecmp(word, STR_CONCISE, len)) { + if (state == 0) { + return ast_strdup(STR_CONCISE); } - AST_LIST_UNLOCK(&confs); + --state; + } + + return complete_confno(word, state); + } + if (pos == 3 && state == 0) { + char *saved = NULL; + char *myline; + char *confno; + + /* Extract the confno from the command line. */ + myline = ast_strdupa(line); + strtok_r(myline, " ", &saved); + strtok_r(NULL, " ", &saved); + confno = strtok_r(NULL, " ", &saved); + + if (!strcasecmp(confno, STR_CONCISE)) { + /* There is nothing valid in this position now. */ + return NULL; + } + + len = strlen(word); + if (!strncasecmp(word, STR_CONCISE, len)) { + return ast_strdup(STR_CONCISE); } } - return NULL; } @@ -1410,37 +1471,31 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar struct ast_conf_user *user; struct ast_conference *cnf; int hr, min, sec; - int i = 0, total = 0; + int total = 0; time_t now; - struct ast_str *cmdline = NULL; #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n" #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n" switch (cmd) { case CLI_INIT: - e->command = "meetme list [concise]"; + e->command = "meetme list"; e->usage = - "Usage: meetme list [concise] \n" - " List all or a specific conference.\n"; + "Usage: meetme list [] [" STR_CONCISE "]\n" + " List all conferences or a specific conference.\n"; return NULL; case CLI_GENERATE: - return complete_meetmecmd(a->line, a->word, a->pos, a->n); + return complete_meetmecmd_list(a->line, a->word, a->pos, a->n); } - /* Check for length so no buffer will overflow... */ - for (i = 0; i < a->argc; i++) { - if (strlen(a->argv[i]) > 100) - ast_cli(a->fd, "Invalid Arguments.\n"); - } + if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) { + /* List all the conferences */ + int concise = (a->argc == 3); + struct ast_str *marked_users; - /* Max confno length */ - if (!(cmdline = ast_str_create(MAX_CONFNUM))) { - return CLI_FAILURE; - } + if (!(marked_users = ast_str_create(30))) { + return CLI_FAILURE; + } - if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) { - /* List all the conferences */ - int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise")); now = time(NULL); AST_LIST_LOCK(&confs); if (AST_LIST_EMPTY(&confs)) { @@ -1448,23 +1503,25 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_cli(a->fd, "No active MeetMe conferences.\n"); } AST_LIST_UNLOCK(&confs); - ast_free(cmdline); + ast_free(marked_users); return CLI_SUCCESS; } if (!concise) { ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked"); } AST_LIST_TRAVERSE(&confs, cnf, list) { - if (cnf->markedusers == 0) { - ast_str_set(&cmdline, 0, "N/A "); - } else { - ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers); - } hr = (now - cnf->start) / 3600; min = ((now - cnf->start) % 3600) / 60; sec = (now - cnf->start) % 60; if (!concise) { - ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No"); + if (cnf->markedusers == 0) { + ast_str_set(&marked_users, 0, "N/A "); + } else { + ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers); + } + ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, + ast_str_buffer(marked_users), hr, min, sec, + cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No"); } else { ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n", cnf->confno, @@ -1481,18 +1538,19 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar if (!concise) { ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total); } - ast_free(cmdline); + ast_free(marked_users); return CLI_SUCCESS; - } else if (strcmp(a->argv[1], "list") == 0) { + } + if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) { struct ao2_iterator user_iter; - int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise"))); + int concise = (a->argc == 4); + /* List all the users in a conference */ if (AST_LIST_EMPTY(&confs)) { if (!concise) { ast_cli(a->fd, "No active MeetMe conferences.\n"); } - ast_free(cmdline); - return CLI_SUCCESS; + return CLI_SUCCESS; } /* Find the right conference */ AST_LIST_LOCK(&confs); @@ -1505,7 +1563,6 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar if (!concise) ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]); AST_LIST_UNLOCK(&confs); - ast_free(cmdline); return CLI_SUCCESS; } /* Show all the users */ @@ -1545,10 +1602,60 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_cli(a->fd, "%d users in that conference.\n", cnf->users); } AST_LIST_UNLOCK(&confs); - ast_free(cmdline); return CLI_SUCCESS; } - if (a->argc < 2) { + return CLI_SHOWUSAGE; +} + + +static char *meetme_cmd_helper(struct ast_cli_args *a) +{ + /* Process the command */ + struct ast_str *cmdline; + + /* Max confno length */ + if (!(cmdline = ast_str_create(MAX_CONFNUM))) { + return CLI_FAILURE; + } + + ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */ + if (strcasestr(a->argv[1], "lock")) { + if (strcasecmp(a->argv[1], "lock") == 0) { + /* Lock */ + ast_str_append(&cmdline, 0, ",L"); + } else { + /* Unlock */ + ast_str_append(&cmdline, 0, ",l"); + } + } else if (strcasestr(a->argv[1], "mute")) { + if (strcasecmp(a->argv[1], "mute") == 0) { + /* Mute */ + if (strcasecmp(a->argv[3], "all") == 0) { + ast_str_append(&cmdline, 0, ",N"); + } else { + ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]); + } + } else { + /* Unmute */ + if (strcasecmp(a->argv[3], "all") == 0) { + ast_str_append(&cmdline, 0, ",n"); + } else { + ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]); + } + } + } else if (strcasecmp(a->argv[1], "kick") == 0) { + if (strcasecmp(a->argv[3], "all") == 0) { + /* Kick all */ + ast_str_append(&cmdline, 0, ",K"); + } else { + /* Kick a single user */ + ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]); + } + } else { + /* + * Should never get here because it is already filtered by the + * callers. + */ ast_free(cmdline); return CLI_SHOWUSAGE; } @@ -1561,94 +1668,64 @@ static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar return CLI_SUCCESS; } - -static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +static char *meetme_lock_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - /* Process the command */ - struct ast_str *cmdline = NULL; - int i = 0; - switch (cmd) { case CLI_INIT: - e->command = "meetme {lock|unlock|mute|unmute|kick}"; + e->command = "meetme {lock|unlock}"; e->usage = - "Usage: meetme (un)lock|(un)mute|kick \n" - " Executes a command for the conference or on a conferee\n"; + "Usage: meetme lock|unlock \n" + " Lock or unlock a conference to new users.\n"; return NULL; case CLI_GENERATE: - return complete_meetmecmd(a->line, a->word, a->pos, a->n); + return complete_meetmecmd_lock(a->word, a->pos, a->n); } - if (a->argc > 8) - ast_cli(a->fd, "Invalid Arguments.\n"); - /* Check for length so no buffer will overflow... */ - for (i = 0; i < a->argc; i++) { - if (strlen(a->argv[i]) > 100) - ast_cli(a->fd, "Invalid Arguments.\n"); - } - - /* Max confno length */ - if (!(cmdline = ast_str_create(MAX_CONFNUM))) { - return CLI_FAILURE; - } - - if (a->argc < 1) { - ast_free(cmdline); + if (a->argc != 3) { return CLI_SHOWUSAGE; } - ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */ - if (strstr(a->argv[1], "lock")) { - if (strcmp(a->argv[1], "lock") == 0) { - /* Lock */ - ast_str_append(&cmdline, 0, ",L"); - } else { - /* Unlock */ - ast_str_append(&cmdline, 0, ",l"); - } - } else if (strstr(a->argv[1], "mute")) { - if (a->argc < 4) { - ast_free(cmdline); - return CLI_SHOWUSAGE; - } - if (strcmp(a->argv[1], "mute") == 0) { - /* Mute */ - if (strcmp(a->argv[3], "all") == 0) { - ast_str_append(&cmdline, 0, ",N"); - } else { - ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]); - } - } else { - /* Unmute */ - if (strcmp(a->argv[3], "all") == 0) { - ast_str_append(&cmdline, 0, ",n"); - } else { - ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]); - } - } - } else if (strcmp(a->argv[1], "kick") == 0) { - if (a->argc < 4) { - ast_free(cmdline); - return CLI_SHOWUSAGE; - } - if (strcmp(a->argv[3], "all") == 0) { - /* Kick all */ - ast_str_append(&cmdline, 0, ",K"); - } else { - /* Kick a single user */ - ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]); - } - } else { - ast_free(cmdline); + return meetme_cmd_helper(a); +} + +static char *meetme_kick_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: + e->command = "meetme kick"; + e->usage = + "Usage: meetme kick all|\n" + " Kick a conference or a user in a conference.\n"; + return NULL; + case CLI_GENERATE: + return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n); + } + + if (a->argc != 4) { return CLI_SHOWUSAGE; } - ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline)); + return meetme_cmd_helper(a); +} - admin_exec(NULL, ast_str_buffer(cmdline)); - ast_free(cmdline); +static char *meetme_mute_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: + e->command = "meetme {mute|unmute}"; + e->usage = + "Usage: meetme mute|unmute all|\n" + " Mute or unmute a conference or a user in a conference.\n"; + return NULL; + case CLI_GENERATE: + return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n); + } - return CLI_SUCCESS; + if (a->argc != 4) { + return CLI_SHOWUSAGE; + } + + return meetme_cmd_helper(a); } static const char *sla_hold_str(unsigned int hold_access) @@ -1810,8 +1887,10 @@ static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_ } static struct ast_cli_entry cli_meetme[] = { - AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"), - AST_CLI_DEFINE(meetme_show_cmd, "List all or one conference"), + AST_CLI_DEFINE(meetme_kick_cmd, "Kick a conference or a user in a conference."), + AST_CLI_DEFINE(meetme_show_cmd, "List all conferences or a specific conference."), + AST_CLI_DEFINE(meetme_lock_cmd, "Lock or unlock a conference to new users."), + AST_CLI_DEFINE(meetme_mute_cmd, "Mute or unmute a conference or a user in a conference."), AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"), AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"), };