diff options
Diffstat (limited to 'main/features.c')
-rw-r--r-- | main/features.c | 148 |
1 files changed, 103 insertions, 45 deletions
diff --git a/main/features.c b/main/features.c index e0c6548a9..c71e73710 100644 --- a/main/features.c +++ b/main/features.c @@ -3289,9 +3289,46 @@ static int setup_bridge_features_builtin(struct ast_bridge_features *features, s #endif } -struct dtmf_hook_run_app { +struct dynamic_dtmf_hook_run { + /*! Offset into app_name[] where the channel name that activated the hook starts. */ + int activated_offset; + /*! Offset into app_name[] where the dynamic feature name starts. */ + int feature_offset; + /*! Offset into app_name[] where the MOH class name starts. (zero if no MOH) */ + int moh_offset; + /*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */ + int app_args_offset; + /*! Application name to run. */ + char app_name[0]; +}; + +static void dynamic_dtmf_hook_callback(struct ast_bridge_channel *bridge_channel, + const void *payload, size_t payload_size) +{ + struct ast_channel *chan = bridge_channel->chan; + const struct dynamic_dtmf_hook_run *run_data = payload; + + pbx_builtin_setvar_helper(chan, "DYNAMIC_FEATURENAME", + &run_data->app_name[run_data->feature_offset]); + pbx_builtin_setvar_helper(chan, "DYNAMIC_WHO_ACTIVATED", + &run_data->app_name[run_data->activated_offset]); + + ast_bridge_channel_run_app(bridge_channel, run_data->app_name, + run_data->app_args_offset ? &run_data->app_name[run_data->app_args_offset] : NULL, + run_data->moh_offset ? &run_data->app_name[run_data->moh_offset] : NULL); +} + +static void dynamic_dtmf_hook_run_callback(struct ast_bridge_channel *bridge_channel, + ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size) +{ + callback(bridge_channel, payload, payload_size); +} + +struct dynamic_dtmf_hook_data { /*! Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER) */ unsigned int flags; + /*! Offset into app_name[] where the dynamic feature name starts. */ + int feature_offset; /*! Offset into app_name[] where the MOH class name starts. (zero if no MOH) */ int moh_offset; /*! Offset into app_name[] where the application argument string starts. (zero if no arguments) */ @@ -3302,7 +3339,7 @@ struct dtmf_hook_run_app { /*! * \internal - * \brief Setup bridge dynamic features. + * \brief Activated dynamic DTMF feature hook. * \since 12.0.0 * * \param bridge The bridge that the channel is part of @@ -3312,27 +3349,55 @@ struct dtmf_hook_run_app { * \retval 0 Keep the callback hook. * \retval -1 Remove the callback hook. */ -static int app_dtmf_feature_hook(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int dynamic_dtmf_hook_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) { - struct dtmf_hook_run_app *pvt = hook_pvt; - void (*run_it)(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class); + struct dynamic_dtmf_hook_data *pvt = hook_pvt; + void (*run_it)(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size); + struct dynamic_dtmf_hook_run *run_data; + const char *activated_name; + size_t len_name; + size_t len_args; + size_t len_moh; + size_t len_feature; + size_t len_activated; + size_t len_data; + + /* Determine lengths of things. */ + len_name = strlen(pvt->app_name) + 1; + len_args = pvt->app_args_offset ? strlen(&pvt->app_name[pvt->app_args_offset]) + 1 : 0; + len_moh = pvt->moh_offset ? strlen(&pvt->app_name[pvt->moh_offset]) + 1 : 0; + len_feature = strlen(&pvt->app_name[pvt->feature_offset]) + 1; + ast_channel_lock(bridge_channel->chan); + activated_name = ast_strdupa(ast_channel_name(bridge_channel->chan)); + ast_channel_unlock(bridge_channel->chan); + len_activated = strlen(activated_name) + 1; + len_data = sizeof(*run_data) + len_name + len_args + len_moh + len_feature + len_activated; + + /* Fill in dynamic feature run hook data. */ + run_data = ast_alloca(len_data); + run_data->app_args_offset = len_args ? len_name : 0; + run_data->moh_offset = len_moh ? len_name + len_args : 0; + run_data->feature_offset = len_name + len_args + len_moh; + run_data->activated_offset = len_name + len_args + len_moh + len_feature; + strcpy(run_data->app_name, pvt->app_name);/* Safe */ + if (len_args) { + strcpy(&run_data->app_name[run_data->app_args_offset], + &pvt->app_name[pvt->app_args_offset]);/* Safe */ + } + if (len_moh) { + strcpy(&run_data->app_name[run_data->moh_offset], + &pvt->app_name[pvt->moh_offset]);/* Safe */ + } + strcpy(&run_data->app_name[run_data->feature_offset], + &pvt->app_name[pvt->feature_offset]);/* Safe */ + strcpy(&run_data->app_name[run_data->activated_offset], activated_name);/* Safe */ if (ast_test_flag(pvt, AST_FEATURE_FLAG_ONPEER)) { - run_it = ast_bridge_channel_write_app; + run_it = ast_bridge_channel_write_callback; } else { - run_it = ast_bridge_channel_run_app; + run_it = dynamic_dtmf_hook_run_callback; } - -/* - * BUGBUG need to pass to run_it the triggering channel name so DYNAMIC_WHO_TRIGGERED can be set on the channel when it is run. - * - * This would replace DYNAMIC_PEERNAME which is redundant with - * BRIDGEPEER anyway. The value of DYNAMIC_WHO_TRIGGERED is - * really useful in the case of a multi-party bridge. - */ - run_it(bridge_channel, pvt->app_name, - pvt->app_args_offset ? &pvt->app_name[pvt->app_args_offset] : NULL, - pvt->moh_offset ? &pvt->app_name[pvt->moh_offset] : NULL); + run_it(bridge_channel, dynamic_dtmf_hook_callback, run_data, len_data); return 0; } @@ -3344,6 +3409,7 @@ static int app_dtmf_feature_hook(struct ast_bridge *bridge, struct ast_bridge_ch * \param features Bridge features to setup. * \param flags Which side of bridge to run app (AST_FEATURE_FLAG_ONSELF/AST_FEATURE_FLAG_ONPEER). * \param dtmf DTMF trigger sequence. + * \param feature_name Name of the dynamic feature. * \param app_name Dialplan application name to run. * \param app_args Dialplan application arguments. (Empty or NULL if no arguments) * \param moh_class MOH class to play to peer. (Empty or NULL if no MOH played) @@ -3351,32 +3417,35 @@ static int app_dtmf_feature_hook(struct ast_bridge *bridge, struct ast_bridge_ch * \retval 0 on success. * \retval -1 on error. */ -static int add_dynamic_dtmf_hook(struct ast_bridge_features *features, unsigned int flags, const char *dtmf, const char *app_name, const char *app_args, const char *moh_class) +static int dynamic_dtmf_hook_add(struct ast_bridge_features *features, unsigned int flags, const char *dtmf, const char *feature_name, const char *app_name, const char *app_args, const char *moh_class) { - struct dtmf_hook_run_app *app_data; + struct dynamic_dtmf_hook_data *hook_data; size_t len_name = strlen(app_name) + 1; size_t len_args = ast_strlen_zero(app_args) ? 0 : strlen(app_args) + 1; size_t len_moh = ast_strlen_zero(moh_class) ? 0 : strlen(moh_class) + 1; - size_t len_data = sizeof(*app_data) + len_name + len_args + len_moh; + size_t len_feature = strlen(feature_name) + 1; + size_t len_data = sizeof(*hook_data) + len_name + len_args + len_moh + len_feature; /* Fill in application run hook data. */ - app_data = ast_malloc(len_data); - if (!app_data) { + hook_data = ast_malloc(len_data); + if (!hook_data) { return -1; } - app_data->flags = flags; - app_data->app_args_offset = len_args ? len_name : 0; - app_data->moh_offset = len_moh ? len_name + len_args : 0; - strcpy(app_data->app_name, app_name);/* Safe */ + hook_data->flags = flags; + hook_data->app_args_offset = len_args ? len_name : 0; + hook_data->moh_offset = len_moh ? len_name + len_args : 0; + hook_data->feature_offset = len_name + len_args + len_moh; + strcpy(hook_data->app_name, app_name);/* Safe */ if (len_args) { - strcpy(&app_data->app_name[app_data->app_args_offset], app_args);/* Safe */ + strcpy(&hook_data->app_name[hook_data->app_args_offset], app_args);/* Safe */ } if (len_moh) { - strcpy(&app_data->app_name[app_data->moh_offset], moh_class);/* Safe */ + strcpy(&hook_data->app_name[hook_data->moh_offset], moh_class);/* Safe */ } + strcpy(&hook_data->app_name[hook_data->feature_offset], feature_name);/* Safe */ - return ast_bridge_dtmf_hook(features, dtmf, app_dtmf_feature_hook, - app_data, ast_free_ptr, AST_BRIDGE_HOOK_REMOVE_ON_PULL); + return ast_bridge_dtmf_hook(features, dtmf, dynamic_dtmf_hook_trip, hook_data, + ast_free_ptr, AST_BRIDGE_HOOK_REMOVE_ON_PULL); } static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags) @@ -3385,10 +3454,9 @@ static int setup_dynamic_feature(void *obj, void *arg, void *data, int flags) struct ast_bridge_features *features = arg; int *res = data; - /* BUGBUG need to pass to add_dynamic_dtmf_hook the applicationmap name (item->name) so the DYNAMIC_FEATURENAME can be set on the channel when it is run. */ - *res |= add_dynamic_dtmf_hook(features, item->activate_on_self ? AST_FEATURE_FLAG_ONSELF : - AST_FEATURE_FLAG_ONPEER, item->dtmf, item->app, item->app_data, - item->moh_class); + *res |= dynamic_dtmf_hook_add(features, + item->activate_on_self ? AST_FEATURE_FLAG_ONSELF : AST_FEATURE_FLAG_ONPEER, + item->dtmf, item->name, item->app, item->app_data, item->moh_class); return 0; } @@ -3421,7 +3489,6 @@ static int setup_bridge_features_dynamic(struct ast_bridge_features *features, s return res; } -/* BUGBUG struct ast_call_feature needs to be made an ao2 object so the basic bridge class can own the code setting up it's DTMF hooks. */ /* BUGBUG this really should be made a private function of bridging_basic.c after struct ast_call_feature is made an ao2 object. */ int ast_bridge_channel_setup_features(struct ast_bridge_channel *bridge_channel) { @@ -3540,15 +3607,6 @@ static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer, { int res; -/* BUGBUG these channel vars may need to be made dynamic so they update when transfers happen. */ - pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer)); - pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan)); - -/* BUGBUG revisit how BLINDTRANSFER operates with the new bridging model. */ - /* Clear any BLINDTRANSFER since the transfer has completed. */ - pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); - pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL); - set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); add_features_datastores(chan, peer, config); |