mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	Clean up ConfBridge commands to account for wait_marked users
When ConfBridge was refactored to better handle the concept of marked, wait_marked, and normal users co-existing in a conference (thereby implementing a state machine for the conference), the wait_marked users were put into their own list of conference participants, separate from the active users. This list is used for wait_marked users when they are waiting in a conference but no marked user has joined; normal users may have joined at this point however. There are several AMI/CLI commands that affect conference users that were not checking the wait_marked users list: * CLI/AMI commands that mute/unmute a participant. In this case, wait_marked users have to remain in their particular state and should not be affected - however, the commands would return "Channel not found" as opposed to the appropriate error condition. * CLI/AMI commands that kick a participant. An admin should always be able to kick a participant out of the conference. This patch fixes both sets of commands, and cleans up the CLI commands slightly by allowing them to complete a participant name (this was supposed to have been added, but the function call was commented out and wasn't implemented). Review: https://reviewboard.asterisk.org/r/2346/ (closes issue AST-1114) Reported by: John Bigelow Tested by: John Bigelow ........ Merged revisions 382068 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@382070 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -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 (kick_conference_participant(bridge, a->argv[3])) { | ||||
| 		ast_cli(a->fd, "No participant named '%s' found!\n", a->argv[3]); | ||||
| 		return CLI_SUCCESS; | ||||
| 	} | ||||
| 	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); | ||||
| 	} | ||||
| 	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 <conference> <channel>\n"; | ||||
| 			"Usage: confbridge mute <conference> <channel>\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 <conference> <channel>\n"; | ||||
| 			"Usage: confbridge unmute <conference> <channel>\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 <conference>\n"; | ||||
| 			"Usage: confbridge lock <conference>\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 <conference>\n"; | ||||
| 			"Usage: confbridge unlock <conference>\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 <conference>\n"; | ||||
| 			"Usage: confbridge record stop <conference>\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)) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user