[asterisk-commits] jrose: trunk r402397 - in /trunk: ./ apps/ apps/confbridge/ apps/confbridge/i...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Nov 1 17:48:18 CDT 2013
Author: jrose
Date: Fri Nov 1 17:48:14 2013
New Revision: 402397
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=402397
Log:
app_confbridge: Make the CONFBRIDGE function be able to create dynamic menus
Also adds the ability to clear all profile items and makes behavior more
consistent with documentation as when choosing whether to use CONFBRIDGE
datastore profiles or the application arguments to the confbridge application.
(closes issue ASTERISK-22760)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2971/
Modified:
trunk/CHANGES
trunk/apps/app_confbridge.c
trunk/apps/confbridge/conf_config_parser.c
trunk/apps/confbridge/include/confbridge.h
Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=402397&r1=402396&r2=402397
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Fri Nov 1 17:48:14 2013
@@ -7,6 +7,19 @@
=== and the other UPGRADE files for older releases.
===
==============================================================================
+
+------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 12 to Asterisk 13 --------------------
+------------------------------------------------------------------------------
+
+ConfBridge
+--------------------------
+ * CONFBRIDGE dialplan function is now capable of creating/modifying dynamic
+ conference user menus.
+
+ * CONFBRIDGE dialplan function is now capable of removing dynamic conference
+ menus, bridge settings, and user settings that have been applied by the
+ CONFBRIDGE dialplan function.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 11 to Asterisk 12 --------------------
Modified: trunk/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_confbridge.c?view=diff&rev=402397&r1=402396&r2=402397
==============================================================================
--- trunk/apps/app_confbridge.c (original)
+++ trunk/apps/app_confbridge.c Fri Nov 1 17:48:14 2013
@@ -100,8 +100,10 @@
</parameter>
<parameter name="menu">
<para>The name of the DTMF menu in confbridge.conf to be applied to
- this channel. No menu is applied by default if this option is left
- blank.</para>
+ this channel. When left blank, a dynamically built menu profile
+ created by the CONFBRIDGE dialplan function is searched for on
+ the channel and used. If no dynamic profile is present, the
+ 'default_menu' profile found in confbridge.conf is used.</para>
</parameter>
</syntax>
<description>
@@ -116,14 +118,16 @@
</application>
<function name="CONFBRIDGE" language="en_US">
<synopsis>
- Set a custom dynamic bridge and user profile on a channel for the ConfBridge application using the same options defined in confbridge.conf.
+ Set a custom dynamic bridge, user, or menu profile on a channel for the ConfBridge application using the same options defined in confbridge.conf.
</synopsis>
<syntax>
<parameter name="type" required="true">
- <para>Type refers to which type of profile the option belongs too. Type can be <literal>bridge</literal> or <literal>user</literal>.</para>
+ <para>Type refers to which type of profile the option belongs too. Type can be <literal>bridge</literal>, <literal>user</literal>, or
+ <literal>menu</literal>.</para>
</parameter>
<parameter name="option" required="true">
- <para>Option refers to <filename>confbridge.conf</filename> option that is being set dynamically on this channel.</para>
+ <para>Option refers to <filename>confbridge.conf</filename> option that is being set dynamically on this channel, or
+ <literal>clear</literal> to remove already applied options from the channel.</para>
</parameter>
</syntax>
<description>
@@ -1504,8 +1508,9 @@
int res = 0, volume_adjustments[2];
int quiet = 0;
char *parse;
- const char *b_profile_name = DEFAULT_BRIDGE_PROFILE;
- const char *u_profile_name = DEFAULT_USER_PROFILE;
+ const char *b_profile_name = NULL;
+ const char *u_profile_name = NULL;
+ const char *menu_profile_name = NULL;
struct confbridge_conference *conference = NULL;
struct confbridge_user user = {
.chan = chan,
@@ -1517,7 +1522,7 @@
AST_APP_ARG(conf_name);
AST_APP_ARG(b_profile_name);
AST_APP_ARG(u_profile_name);
- AST_APP_ARG(menu_name);
+ AST_APP_ARG(menu_profile_name);
);
if (ast_channel_state(chan) != AST_STATE_UP) {
@@ -1545,7 +1550,8 @@
b_profile_name = args.b_profile_name;
}
if (!conf_find_bridge_profile(chan, b_profile_name, &user.b_profile)) {
- ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name);
+ ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name ?
+ b_profile_name : DEFAULT_BRIDGE_PROFILE);
res = -1;
goto confbridge_cleanup;
}
@@ -1555,7 +1561,8 @@
u_profile_name = args.u_profile_name;
}
if (!conf_find_user_profile(chan, u_profile_name, &user.u_profile)) {
- ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name);
+ ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name ?
+ u_profile_name : DEFAULT_USER_PROFILE);
res = -1;
goto confbridge_cleanup;
}
@@ -1577,14 +1584,15 @@
}
/* menu name */
- if (args.argc > 3 && !ast_strlen_zero(args.menu_name)) {
- ast_copy_string(user.menu_name, args.menu_name, sizeof(user.menu_name));
- if (conf_set_menu_to_user(user.menu_name, &user)) {
- ast_log(LOG_WARNING, "Conference menu %s does not exist and can not be applied to confbridge user.\n",
- args.menu_name);
- res = -1; /* invalid PIN */
- goto confbridge_cleanup;
- }
+ if (args.argc > 3 && !ast_strlen_zero(args.menu_profile_name)) {
+ menu_profile_name = args.menu_profile_name;
+ }
+
+ if (conf_set_menu_to_user(chan, &user, menu_profile_name)) {
+ ast_log(LOG_WARNING, "Conference menu profile %s does not exist\n", menu_profile_name ?
+ menu_profile_name : DEFAULT_MENU_PROFILE);
+ res = -1;
+ goto confbridge_cleanup;
}
/* Set if DTMF should pass through for this user or not */
Modified: trunk/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/confbridge/conf_config_parser.c?view=diff&rev=402397&r1=402396&r2=402397
==============================================================================
--- trunk/apps/confbridge/conf_config_parser.c (original)
+++ trunk/apps/confbridge/conf_config_parser.c Fri Nov 1 17:48:14 2013
@@ -418,6 +418,9 @@
<enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
</enumlist>
</description>
+ </configOption>
+ <configOption name="template">
+ <synopsis>When using the CONFBRIDGE dialplan function, use a menu profile as a template for creating a new temporary profile</synopsis>
</configOption>
<configOption name="^[0-9A-D*#]+$">
<synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
@@ -896,15 +899,25 @@
struct func_confbridge_data {
struct bridge_profile b_profile;
struct user_profile u_profile;
+ struct conf_menu *menu;
unsigned int b_usable:1; /*!< Tells if bridge profile is usable or not */
unsigned int u_usable:1; /*!< Tells if user profile is usable or not */
+ unsigned int m_usable:1; /*!< Tells if menu profile is usable or not */
};
+
+static void func_confbridge_data_destructor(struct func_confbridge_data *b_data)
+{
+ conf_bridge_profile_destroy(&b_data->b_profile);
+ ao2_cleanup(b_data->menu);
+ ast_free(b_data);
+}
+
static void func_confbridge_destroy_cb(void *data)
{
struct func_confbridge_data *b_data = data;
- conf_bridge_profile_destroy(&b_data->b_profile);
- ast_free(b_data);
+ func_confbridge_data_destructor(b_data);
};
+
static const struct ast_datastore_info confbridge_datastore = {
.type = "confbridge",
.destroy = func_confbridge_destroy_cb
@@ -944,14 +957,18 @@
ast_datastore_free(datastore);
return 0;
}
+ datastore->data = b_data;
b_data->b_profile.sounds = bridge_profile_sounds_alloc();
if (!b_data->b_profile.sounds) {
ast_channel_unlock(chan);
ast_datastore_free(datastore);
- ast_free(b_data);
return 0;
}
- datastore->data = b_data;
+ if (!(b_data->menu = menu_alloc("dialplan"))) {
+ ast_channel_unlock(chan);
+ ast_datastore_free(datastore);
+ return 0;
+ }
ast_channel_datastore_add(chan, datastore);
} else {
b_data = datastore->data;
@@ -966,13 +983,46 @@
tmpvar.value = value;
tmpvar.file = "CONFBRIDGE";
if (!strcasecmp(args.type, "bridge")) {
- if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
+ if (!strcasecmp(args.option, "clear")) {
+ b_data->b_usable = 0;
+ conf_bridge_profile_destroy(&b_data->b_profile);
+ memset(&b_data->b_profile, 0, sizeof(b_data->b_profile)) ;
+ if (!(b_data->b_profile.sounds = bridge_profile_sounds_alloc())) {
+ /* If this reallocation fails, the datastore has become unusable and must be destroyed. */
+ ast_channel_lock(chan);
+ ast_channel_datastore_remove(chan, datastore);
+ ast_channel_unlock(chan);
+ ast_datastore_free(datastore);
+ }
+ return 0;
+ } else if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
b_data->b_usable = 1;
return 0;
}
} else if (!strcasecmp(args.type, "user")) {
- if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
+ if (!strcasecmp(args.option, "clear")) {
+ b_data->u_usable = 0;
+ user_profile_destructor(&b_data->u_profile);
+ memset(&b_data->u_profile, 0, sizeof(b_data->u_profile));
+ return 0;
+ } else if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
b_data->u_usable = 1;
+ return 0;
+ }
+ } else if (!strcasecmp(args.type, "menu")) {
+ if (!strcasecmp(args.option, "clear")) {
+ b_data->m_usable = 0;
+ ao2_cleanup(b_data->menu);
+ if (!(b_data->menu = menu_alloc("dialplan"))) {
+ /* If this reallocation fails, the datastore has become unusable and must be destroyed */
+ ast_channel_lock(chan);
+ ast_channel_datastore_remove(chan, datastore);
+ ast_channel_unlock(chan);
+ ast_datastore_free(datastore);
+ }
+ return 0;
+ } else if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
+ b_data->m_usable = 1;
return 0;
}
}
@@ -1852,6 +1902,70 @@
return 0;
}
+static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
+{
+ struct conf_menu_action *menu_action;
+ struct conf_menu_action *new_menu_action;
+
+ ast_copy_string(dst->dtmf, src->dtmf, sizeof(dst->dtmf));
+ AST_LIST_HEAD_INIT_NOLOCK(&dst->actions);
+
+ AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
+ if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
+ return -1;
+ }
+ memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
+ AST_LIST_NEXT(new_menu_action, action) = NULL;
+ AST_LIST_INSERT_TAIL(&dst->actions, new_menu_action, action);
+ }
+
+ return 0;
+}
+
+static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
+{
+ /* Copy each menu item to the dst struct */
+ struct conf_menu_entry *cur;
+
+ AST_LIST_TRAVERSE(&src->entries, cur, entry) {
+ struct conf_menu_entry *cpy;
+
+ if (!(cpy = ast_calloc(1, sizeof(*cpy)))) {
+ return -1;
+ }
+
+ if (copy_menu_entry(cpy, cur)) {
+ conf_menu_entry_destroy(cpy);
+ ast_free(cpy);
+ return -1;
+ }
+ AST_LIST_INSERT_TAIL(&dst->entries, cpy, entry);
+ }
+
+ return 0;
+}
+
+static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct conf_menu *dst_menu = obj;
+ struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
+ RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup);
+
+ if (!cfg) {
+ return 0;
+ }
+
+ if (!(src_menu = ao2_find(cfg->menus, var->value, OBJ_KEY))) {
+ return -1;
+ }
+
+ if (conf_menu_profile_copy(dst_menu, src_menu)) {
+ return -1;
+ }
+
+ return 0;
+}
+
static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
set_sound(var->name, var->value, obj);
@@ -1868,6 +1982,7 @@
{
RAII_VAR(struct user_profile *, user_profile, NULL, ao2_cleanup);
RAII_VAR(struct bridge_profile *, bridge_profile, NULL, ao2_cleanup);
+ RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup);
struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
if (!cfg) {
@@ -1894,6 +2009,17 @@
ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_USER_PROFILE);
aco_set_defaults(&user_type, DEFAULT_USER_PROFILE, user_profile);
ao2_link(cfg->user_profiles, user_profile);
+ }
+
+ menu_profile = ao2_find(cfg->menus, DEFAULT_MENU_PROFILE, OBJ_KEY);
+ if (!menu_profile) {
+ menu_profile = menu_alloc(DEFAULT_MENU_PROFILE);
+ if (!menu_profile) {
+ return -1;
+ }
+ ast_log(AST_LOG_NOTICE, "Adding %s menu to app_confbridge\n", DEFAULT_MENU_PROFILE);
+ aco_set_defaults(&menu_type, DEFAULT_MENU_PROFILE, menu_profile);
+ ao2_link(cfg->menus, menu_profile);
}
return 0;
@@ -1951,6 +2077,7 @@
/* Menu options */
aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
+ aco_option_register_custom(&cfg_info, "template", ACO_EXACT, menu_types, NULL, menu_template_handler, 0);
aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
@@ -1988,11 +2115,7 @@
struct func_confbridge_data *b_data = NULL;
RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
- if (!cfg) {
- return NULL;
- }
-
- if (chan) {
+ if (chan && ast_strlen_zero(user_profile_name)) {
ast_channel_lock(chan);
datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
ast_channel_unlock(chan);
@@ -2005,6 +2128,9 @@
}
}
+ if (!cfg) {
+ return NULL;
+ }
if (ast_strlen_zero(user_profile_name)) {
user_profile_name = DEFAULT_USER_PROFILE;
}
@@ -2042,11 +2168,7 @@
struct func_confbridge_data *b_data = NULL;
RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
- if (!cfg) {
- return NULL;
- }
-
- if (chan) {
+ if (chan && ast_strlen_zero(bridge_profile_name)) {
ast_channel_lock(chan);
datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
ast_channel_unlock(chan);
@@ -2058,6 +2180,10 @@
}
}
}
+
+ if (!cfg) {
+ return NULL;
+ }
if (ast_strlen_zero(bridge_profile_name)) {
bridge_profile_name = DEFAULT_BRIDGE_PROFILE;
}
@@ -2083,7 +2209,7 @@
struct dtmf_menu_hook_pvt *pvt = hook_pvt;
struct conf_menu_action *action = NULL;
- ao2_ref(pvt->menu, -1);
+ ao2_cleanup(pvt->menu);
while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
ast_free(action);
@@ -2096,24 +2222,6 @@
struct dtmf_menu_hook_pvt *pvt = hook_pvt;
return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, pvt->menu);
-}
-
-static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
-{
- struct conf_menu_action *menu_action = NULL;
- struct conf_menu_action *new_menu_action = NULL;
-
- memcpy(dst, src, sizeof(*dst));
- AST_LIST_HEAD_INIT_NOLOCK(&dst->actions);
-
- AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
- if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
- return -1;
- }
- memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
- AST_LIST_INSERT_HEAD(&dst->actions, new_menu_action, action);
- }
- return 0;
}
void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry)
@@ -2141,37 +2249,24 @@
return 0;
}
-int conf_set_menu_to_user(const char *menu_name, struct confbridge_user *user)
-{
- struct conf_menu *menu;
- struct conf_menu_entry *menu_entry = NULL;
- RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
-
- if (!cfg) {
- return -1;
- }
-
- if (!(menu = menu_find(cfg->menus, menu_name))) {
- return -1;
- }
- ao2_lock(menu);
+static int apply_menu_hooks(struct confbridge_user *user, struct conf_menu *menu)
+{
+ struct conf_menu_entry *menu_entry;
+
+ SCOPED_AO2LOCK(menu_lock, menu);
AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
struct dtmf_menu_hook_pvt *pvt;
if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
- ao2_unlock(menu);
- ao2_ref(menu, -1);
return -1;
}
+ pvt->user = user;
+ pvt->menu = ao2_bump(menu);
+
if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
- ast_free(pvt);
- ao2_unlock(menu);
- ao2_ref(menu, -1);
+ menu_hook_destroy(pvt);
return -1;
}
- pvt->user = user;
- ao2_ref(menu, +1);
- pvt->menu = menu;
if (ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf,
menu_hook_callback, pvt, menu_hook_destroy, 0)) {
@@ -2179,10 +2274,45 @@
}
}
- ao2_unlock(menu);
- ao2_ref(menu, -1);
-
return 0;
+}
+
+int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
+{
+ RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
+ RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
+
+ if (chan && ast_strlen_zero(menu_profile_name)) {
+ struct ast_datastore *datastore;
+ struct func_confbridge_data *b_data;
+
+ ast_channel_lock(chan);
+ datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
+ ast_channel_unlock(chan);
+ if (datastore) {
+ /* If a menu exists in the CONFBRIDGE function datastore, use it. */
+ b_data = datastore->data;
+ if (b_data->m_usable) {
+ menu = ao2_bump(b_data->menu);
+ return apply_menu_hooks(user, menu);
+ }
+ }
+ }
+
+ /* Otherwise, we need to get whatever menu profile is specified to use (or default). */
+ if (!cfg) {
+ return -1;
+ }
+
+ if (ast_strlen_zero(menu_profile_name)) {
+ menu_profile_name = DEFAULT_MENU_PROFILE;
+ }
+
+ if (!(menu = ao2_find(cfg->menus, menu_profile_name, OBJ_KEY))) {
+ return -1;
+ }
+
+ return apply_menu_hooks(user, menu);
}
void conf_destroy_config(void)
Modified: trunk/apps/confbridge/include/confbridge.h
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/confbridge/include/confbridge.h?view=diff&rev=402397&r1=402396&r2=402397
==============================================================================
--- trunk/apps/confbridge/include/confbridge.h (original)
+++ trunk/apps/confbridge/include/confbridge.h Fri Nov 1 17:48:14 2013
@@ -37,6 +37,7 @@
#define DEFAULT_USER_PROFILE "default_user"
#define DEFAULT_BRIDGE_PROFILE "default_bridge"
+#define DEFAULT_MENU_PROFILE "default_menu"
#define DEFAULT_TALKING_THRESHOLD 160
#define DEFAULT_SILENCE_THRESHOLD 2500
@@ -260,30 +261,55 @@
* \brief find a user profile given a user profile's name and store
* that profile in result structure.
*
- * \details This function first attempts to find any custom user
- * profile that might exist on a channel datastore, if that doesn't
- * exist it looks up the provided user profile name, if that doesn't
- * exist either the default_user profile is used.
-
+ * \param chan channel the user profile is requested for
+ * \param user_profile_name name of the profile requested (optional)
+ * \param result data contained by the user profile will be copied to this struct pointer
+ *
+ * \details If user_profile_name is not provided, this function will
+ * check for the presence of a user profile set by the CONFBRIDGE
+ * function on a channel datastore. If that doesn't exist, the
+ * default_user profile is used.
+ *
* \retval user profile on success
* \retval NULL on failure
*/
const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result);
/*!
- * \brief Find a bridge profile
- *
- * \details Any bridge profile found using this function must be
- * destroyed using conf_bridge_profile_destroy. This function first
- * attempts to find any custom bridge profile that might exist on
- * a channel datastore, if that doesn't exist it looks up the
- * provided bridge profile name, if that doesn't exist either
- * the default_bridge profile is used.
- *
- * \retval Bridge profile on success
+ * \brief Find a bridge profile given a bridge profile's name and store
+ * that profile in result structure.
+ *
+ * \param chan channel the bridge profile is requested for
+ * \param bridge_profile_name name of the profile requested (optional)
+ * \param result data contained by the bridge profile will be copied to this struct pointer
+ *
+ * \details If bridge_profile_name is not provided, this function will
+ * check for the presence of a bridge profile set by the CONFBRIDGE
+ * function on a channel datastore. If that doesn't exist, the
+ * default_bridge profile is used.
+ *
+ * \retval bridge profile on success
* \retval NULL on failure
*/
const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result);
+
+/*!
+ * \brief find a menu profile given a menu profile's name and apply
+ * the menu in DTMF hooks.
+ *
+ * \param chan channel the menu profile is requested for
+ * \param user user profile the menu is being applied to
+ * \param menu_profile_name name of the profile requested (optional)
+ *
+ * \details If menu_profile_name is not provided, this function will
+ * check for the presence of a menu profile set by the CONFBRIDGE
+ * function on a channel datastore. If that doesn't exist, the
+ * default_menu profile is used.
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name);
/*!
* \brief Destroy a bridge profile found by 'conf_find_bridge_profile'
@@ -295,14 +321,6 @@
* \note conf_bridge_profile_destroy must be called on the dst structure
*/
void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src);
-
-/*!
- * \brief Set a DTMF menu to a conference user by menu name.
- *
- * \retval 0 on success, menu was found and set
- * \retval -1 on error, menu was not found
- */
-int conf_set_menu_to_user(const char *menu_name, struct confbridge_user *user);
/*!
* \brief Finds a menu_entry in a menu structure matched by DTMF sequence.
More information about the asterisk-commits
mailing list