diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
index d365075560..ae17bcab6f 100644
--- a/apps/app_confbridge.c
+++ b/apps/app_confbridge.c
@@ -128,6 +128,7 @@
[ConfKick]
[CONFBRIDGE]
[CONFBRIDGE_INFO]
+ [CONFBRIDGE_CHANNELS]
@@ -164,6 +165,7 @@
[ConfBridge]
[CONFBRIDGE]
[CONFBRIDGE_INFO]
+ [CONFBRIDGE_CHANNELS]
@@ -248,6 +250,50 @@
This function returns a non-negative integer for valid conference
names and an empty string for invalid conference names.
+
+ [CONFBRIDGE_CHANNELS]
+
+
+
+
+ 16.26.0
+ 18.12.0
+ 19.4.0
+
+
+ Get a list of channels in a ConfBridge conference.
+
+
+
+ What conference information is requested.
+
+
+ Get the number of admin users in the conference.
+
+
+ Get the number of marked users in the conference.
+
+
+ Get the number of total users in the conference.
+
+
+ Get the number of active users in the conference.
+
+
+ Get the number of waiting users in the conference.
+
+
+
+
+ The name of the conference being referenced.
+
+
+
+ This function returns a comma-separated list of channels in a ConfBridge conference, optionally filtered by a type of participant.
+
+
+ [CONFBRIDGE_INFO]
+
@@ -3829,6 +3875,90 @@ static struct ast_custom_function confbridge_info_function = {
.read = func_confbridge_info,
};
+static int func_confbridge_channels(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ char *parse, *outbuf;
+ struct confbridge_conference *conference;
+ struct confbridge_user *user;
+ int bytes, count = 0;
+ size_t outlen;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(type);
+ AST_APP_ARG(confno);
+ );
+
+ /* parse all the required arguments and make sure they exist. */
+ if (ast_strlen_zero(data)) {
+ return -1;
+ }
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+ if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
+ ast_log(LOG_WARNING, "Usage: %s(category,confno)", cmd);
+ return -1;
+ }
+ conference = ao2_find(conference_bridges, args.confno, OBJ_KEY);
+ if (!conference) {
+ ast_debug(1, "No such conference: %s\n", args.confno);
+ return -1;
+ }
+
+ outbuf = buf;
+ outlen = len;
+
+ ao2_lock(conference);
+ if (!strcasecmp(args.type, "parties")) {
+ AST_LIST_TRAVERSE(&conference->active_list, user, list) {
+ bytes = snprintf(outbuf, outlen, "%s%s", count++ ? "," : "", ast_channel_name(user->chan));
+ outbuf += bytes;
+ outlen -= bytes;
+ }
+ AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
+ bytes = snprintf(outbuf, outlen, "%s%s", count++ ? "," : "", ast_channel_name(user->chan));
+ outbuf += bytes;
+ outlen -= bytes;
+ }
+ } else if (!strcasecmp(args.type, "active")) {
+ AST_LIST_TRAVERSE(&conference->active_list, user, list) {
+ bytes = snprintf(outbuf, outlen, "%s%s", count++ ? "," : "", ast_channel_name(user->chan));
+ outbuf += bytes;
+ outlen -= bytes;
+ }
+ } else if (!strcasecmp(args.type, "waiting")) {
+ AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
+ bytes = snprintf(outbuf, outlen, "%s%s", count++ ? "," : "", ast_channel_name(user->chan));
+ outbuf += bytes;
+ outlen -= bytes;
+ }
+ } else if (!strcasecmp(args.type, "admins")) {
+ AST_LIST_TRAVERSE(&conference->active_list, user, list) {
+ if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
+ bytes = snprintf(outbuf, outlen, "%s%s", count++ ? "," : "", ast_channel_name(user->chan));
+ outbuf += bytes;
+ outlen -= bytes;
+ }
+ }
+ } else if (!strcasecmp(args.type, "marked")) {
+ AST_LIST_TRAVERSE(&conference->active_list, user, list) {
+ if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
+ bytes = snprintf(outbuf, outlen, "%s%s", count++ ? "," : "", ast_channel_name(user->chan));
+ outbuf += bytes;
+ outlen -= bytes;
+ }
+ }
+ } else {
+ ast_log(LOG_ERROR, "Invalid keyword '%s' passed to %s.\n", args.type, cmd);
+ }
+ ao2_unlock(conference);
+ ao2_ref(conference, -1);
+ return 0;
+}
+
+static struct ast_custom_function confbridge_channels_function = {
+ .name = "CONFBRIDGE_CHANNELS",
+ .read = func_confbridge_channels,
+};
+
static int action_confbridgelist_item(struct mansession *s, const char *id_text, struct confbridge_conference *conference, struct confbridge_user *user, int waiting)
{
struct ast_channel_snapshot *snapshot;
@@ -4406,6 +4536,7 @@ static int unload_module(void)
ast_custom_function_unregister(&confbridge_function);
ast_custom_function_unregister(&confbridge_info_function);
+ ast_custom_function_unregister(&confbridge_channels_function);
ast_cli_unregister_multiple(cli_confbridge, ARRAY_LEN(cli_confbridge));
@@ -4477,6 +4608,7 @@ static int load_module(void)
res |= ast_custom_function_register_escalating(&confbridge_function, AST_CFE_WRITE);
res |= ast_custom_function_register(&confbridge_info_function);
+ res |= ast_custom_function_register(&confbridge_channels_function);
res |= ast_cli_register_multiple(cli_confbridge, ARRAY_LEN(cli_confbridge));
diff --git a/doc/CHANGES-staging/app_confbridge_channels.txt b/doc/CHANGES-staging/app_confbridge_channels.txt
new file mode 100644
index 0000000000..485f664268
--- /dev/null
+++ b/doc/CHANGES-staging/app_confbridge_channels.txt
@@ -0,0 +1,7 @@
+Subject: app_confbridge
+
+Adds the CONFBRIDGE_CHANNELS function which can
+be used to retrieve a list of channels in a ConfBridge,
+optionally filtered by a particular category. This
+list can then be used with functions like SHIFT, POP,
+UNSHIFT, etc.