Fixed meetme tab completion and command documentation.
authorRichard Mudgett <rmudgett@digium.com>
Wed, 26 Sep 2012 18:23:37 +0000 (18:23 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Wed, 26 Sep 2012 18:23:37 +0000 (18:23 +0000)
* 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

index 0cab44c..4669f36 100644 (file)
@@ -538,8 +538,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
        </manager>
  ***/
 
-#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};
-
+       struct ast_conference *cnf;
+       char *ret = NULL;
+       int which = 0;
        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;
-       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);
+
+       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] <confno> \n"
-                       "       List all or a specific conference.\n";
+                       "Usage: meetme list [<confno>] [" 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,93 +1602,49 @@ 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) {
-               ast_free(cmdline);
-               return CLI_SHOWUSAGE;
-       }
-
-       ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
-
-       admin_exec(NULL, ast_str_buffer(cmdline));
-       ast_free(cmdline);
-
-       return CLI_SUCCESS;
+       return CLI_SHOWUSAGE;
 }
 
 
-static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *meetme_cmd_helper(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->usage =
-                       "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
-                       "       Executes a command for the conference or on a conferee\n";
-               return NULL;
-       case CLI_GENERATE:
-               return complete_meetmecmd(a->line, 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");
-       }
+       struct ast_str *cmdline;
 
        /* Max confno length */
        if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
                return CLI_FAILURE;
        }
 
-       if (a->argc < 1) {
-               ast_free(cmdline);
-               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) {
+       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 (strstr(a->argv[1], "mute")) { 
-               if (a->argc < 4) {
-                       ast_free(cmdline);
-                       return CLI_SHOWUSAGE;
-               }
-               if (strcmp(a->argv[1], "mute") == 0) {
+       } else if (strcasestr(a->argv[1], "mute")) { 
+               if (strcasecmp(a->argv[1], "mute") == 0) {
                        /* Mute */
-                       if (strcmp(a->argv[3], "all") == 0) {
+                       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 (strcmp(a->argv[3], "all") == 0) {
+                       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 (strcmp(a->argv[1], "kick") == 0) {
-               if (a->argc < 4) {
-                       ast_free(cmdline);
-                       return CLI_SHOWUSAGE;
-               }
-               if (strcmp(a->argv[3], "all") == 0) {
+       } else if (strcasecmp(a->argv[1], "kick") == 0) {
+               if (strcasecmp(a->argv[3], "all") == 0) {
                        /* Kick all */
                        ast_str_append(&cmdline, 0, ",K");
                } else {
@@ -1639,6 +1652,10 @@ static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
                        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;
        }
@@ -1651,6 +1668,66 @@ static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
        return CLI_SUCCESS;
 }
 
+static char *meetme_lock_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "meetme {lock|unlock}";
+               e->usage =
+                       "Usage: meetme lock|unlock <confno>\n"
+                       "       Lock or unlock a conference to new users.\n";
+               return NULL;
+       case CLI_GENERATE:
+               return complete_meetmecmd_lock(a->word, a->pos, a->n);
+       }
+
+       if (a->argc != 3) {
+               return CLI_SHOWUSAGE;
+       }
+
+       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 <confno> all|<userno>\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;
+       }
+
+       return meetme_cmd_helper(a);
+}
+
+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 <confno> all|<userno>\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);
+       }
+
+       if (a->argc != 4) {
+               return CLI_SHOWUSAGE;
+       }
+
+       return meetme_cmd_helper(a);
+}
+
 static const char *sla_hold_str(unsigned int hold_access)
 {
        const char *hold = "Unknown";
@@ -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"),
 };