diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index edae7b1548..dfa4a0a958 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -2180,6 +2180,29 @@ int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel, return 0; } +static int kick_conference_participant(struct conference_bridge *bridge, const char *channel) +{ + struct conference_bridge_user *participant = NULL; + + SCOPED_AO2LOCK(bridge_lock, bridge); + AST_LIST_TRAVERSE(&bridge->active_list, participant, list) { + if (!strcasecmp(ast_channel_name(participant->chan), channel)) { + participant->kicked = 1; + ast_bridge_remove(bridge->bridge, participant->chan); + return 0; + } + } + AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) { + if (!strcasecmp(ast_channel_name(participant->chan), channel)) { + participant->kicked = 1; + ast_bridge_remove(bridge->bridge, participant->chan); + return 0; + } + } + + return -1; +} + static char *complete_confbridge_name(const char *line, const char *word, int pos, int state) { int which = 0; @@ -2202,11 +2225,44 @@ static char *complete_confbridge_name(const char *line, const char *word, int po return res; } +static char *complete_confbridge_participant(const char *bridge_name, const char *line, const char *word, int pos, int state) +{ + int which = 0; + RAII_VAR(struct conference_bridge *, bridge, NULL, ao2_cleanup); + struct conference_bridge tmp; + struct conference_bridge_user *participant; + char *res = NULL; + int wordlen = strlen(word); + + ast_copy_string(tmp.name, bridge_name, sizeof(tmp.name)); + bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER); + if (!bridge) { + return NULL; + } + + { + SCOPED_AO2LOCK(bridge_lock, bridge); + AST_LIST_TRAVERSE(&bridge->active_list, participant, list) { + if (!strncasecmp(ast_channel_name(participant->chan), word, wordlen) && ++which > state) { + res = ast_strdup(ast_channel_name(participant->chan)); + return res; + } + } + AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) { + if (!strncasecmp(ast_channel_name(participant->chan), word, wordlen) && ++which > state) { + res = ast_strdup(ast_channel_name(participant->chan)); + return res; + } + } + } + + return NULL; +} + static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct conference_bridge *bridge = NULL; struct conference_bridge tmp; - struct conference_bridge_user *participant = NULL; switch (cmd) { case CLI_INIT: @@ -2219,11 +2275,9 @@ static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct if (a->pos == 2) { return complete_confbridge_name(a->line, a->word, a->pos, a->n); } - /* if (a->pos == 3) { - return complete_confbridge_channel(a->line, a->word, a->pos, a->n); + return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n); } - */ return NULL; } @@ -2237,19 +2291,12 @@ static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]); return CLI_SUCCESS; } - ao2_lock(bridge); - AST_LIST_TRAVERSE(&bridge->active_list, participant, list) { - if (!strncmp(a->argv[3], ast_channel_name(participant->chan), strlen(ast_channel_name(participant->chan)))) { - break; - } - } - if (participant) { - ast_cli(a->fd, "Kicking %s from confbridge %s\n", ast_channel_name(participant->chan), bridge->name); - participant->kicked = 1; - ast_bridge_remove(bridge->bridge, participant->chan); + if (kick_conference_participant(bridge, a->argv[3])) { + ast_cli(a->fd, "No participant named '%s' found!\n", a->argv[3]); + return CLI_SUCCESS; } - ao2_unlock(bridge); ao2_ref(bridge, -1); + ast_cli(a->fd, "Participant '%s' kicked out of conference '%s'\n", a->argv[3], a->argv[2]); return CLI_SUCCESS; } @@ -2437,12 +2484,16 @@ static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct case CLI_INIT: e->command = "confbridge mute"; e->usage = - "Usage: confbridge mute \n"; + "Usage: confbridge mute \n" + " Mute a channel in a conference.\n"; return NULL; case CLI_GENERATE: if (a->pos == 2) { return complete_confbridge_name(a->line, a->word, a->pos, a->n); } + if (a->pos == 3) { + return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n); + } return NULL; } if (a->argc != 4) { @@ -2460,12 +2511,16 @@ static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, stru case CLI_INIT: e->command = "confbridge unmute"; e->usage = - "Usage: confbridge unmute \n"; + "Usage: confbridge unmute \n" + " Unmute a channel in a conference.\n"; return NULL; case CLI_GENERATE: if (a->pos == 2) { return complete_confbridge_name(a->line, a->word, a->pos, a->n); } + if (a->pos == 3) { + return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n); + } return NULL; } if (a->argc != 4) { @@ -2483,7 +2538,9 @@ static char *handle_cli_confbridge_lock(struct ast_cli_entry *e, int cmd, struct case CLI_INIT: e->command = "confbridge lock"; e->usage = - "Usage: confbridge lock \n"; + "Usage: confbridge lock \n" + " Lock a conference. While locked, no new non-admins\n" + " may join the conference.\n"; return NULL; case CLI_GENERATE: if (a->pos == 2) { @@ -2508,7 +2565,8 @@ static char *handle_cli_confbridge_unlock(struct ast_cli_entry *e, int cmd, stru case CLI_INIT: e->command = "confbridge unlock"; e->usage = - "Usage: confbridge unlock \n"; + "Usage: confbridge unlock \n" + " Unlock a previously locked conference.\n"; return NULL; case CLI_GENERATE: if (a->pos == 2) { @@ -2596,7 +2654,8 @@ static char *handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd, case CLI_INIT: e->command = "confbridge record stop"; e->usage = - "Usage: confbridge record stop \n"; + "Usage: confbridge record stop \n" + " Stop a previously started recording.\n"; return NULL; case CLI_GENERATE: if (a->pos == 3) { @@ -2852,7 +2911,6 @@ static int action_confbridgekick(struct mansession *s, const struct message *m) { const char *conference = astman_get_header(m, "Conference"); const char *channel = astman_get_header(m, "Channel"); - struct conference_bridge_user *participant = NULL; struct conference_bridge *bridge = NULL; struct conference_bridge tmp; int found = 0; @@ -2865,6 +2923,7 @@ static int action_confbridgekick(struct mansession *s, const struct message *m) astman_send_error(s, m, "No active conferences."); return 0; } + ast_copy_string(tmp.name, conference, sizeof(tmp.name)); bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER); if (!bridge) { @@ -2872,16 +2931,7 @@ static int action_confbridgekick(struct mansession *s, const struct message *m) return 0; } - ao2_lock(bridge); - AST_LIST_TRAVERSE(&bridge->active_list, participant, list) { - if (!strcasecmp(ast_channel_name(participant->chan), channel)) { - participant->kicked = 1; - ast_bridge_remove(bridge->bridge, participant->chan); - found = 1; - break; - } - } - ao2_unlock(bridge); + found = !kick_conference_participant(bridge, channel); ao2_ref(bridge, -1); if (found) { @@ -3062,6 +3112,9 @@ static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char AST_LIST_TRAVERSE(&bridge->active_list, participant, list) { count++; } + AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) { + count++; + } } else if (!strncasecmp(args.type, "admins", 6)) { AST_LIST_TRAVERSE(&bridge->active_list, participant, list) { if (ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {