Skip to content
Snippets Groups Projects
features.c 38.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	char *tmp_data  = NULL;
    	struct ast_flags opts = { 0, };
    	struct ast_bridge_config bconfig = { { 0, }, };
    
    	char *opt_args[OPT_ARG_ARRAY_SIZE];
    	struct timeval calldurationlimit = { 0, };
    
    	const char *context;
    	const char *extension;
    	int priority;
    
    	struct ast_bridge_features chan_features;
    	struct ast_bridge_features *peer_features;
    	struct ast_bridge *bridge;
    
    	struct ast_features_xfer_config *xfer_cfg;
    
    
    	AST_DECLARE_APP_ARGS(args,
    		AST_APP_ARG(dest_chan);
    		AST_APP_ARG(options);
    	);
    
    	if (ast_strlen_zero(data)) {
    		ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
    		return -1;
    	}
    
    	tmp_data = ast_strdupa(data);
    	AST_STANDARD_APP_ARGS(args, tmp_data);
    	if (!ast_strlen_zero(args.options))
    
    		ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
    
    
    	/* make sure we have a valid end point */
    
    	current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
    		strlen(args.dest_chan));
    	if (!current_dest_chan) {
    
    		ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
    			args.dest_chan);
    
    		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
    
    	/* avoid bridge with ourselves */
    	if (chan == current_dest_chan) {
    
    		ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan));
    
    		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
    
    	if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
    		&& !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
    		&& ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
    		goto done;
    	}
    
    
    	if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
    		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
    	if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
    		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
    	if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
    		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
    	if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
    		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
    	if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
    		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
    
    	if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
    
    		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
    	if (ast_test_flag(&opts, OPT_CALLEE_PARK))
    		ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
    	if (ast_test_flag(&opts, OPT_CALLER_PARK))
    		ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
    
    	/* Setup after bridge goto location. */
    	if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
    		ast_channel_lock(chan);
    		context = ast_strdupa(ast_channel_context(chan));
    		extension = ast_strdupa(ast_channel_exten(chan));
    		priority = ast_channel_priority(chan);
    		ast_channel_unlock(chan);
    
    		ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority,
    
    			opt_args[OPT_ARG_CALLEE_GO_ON]);
    	} else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
    
    		ast_channel_lock(current_dest_chan);
    		context = ast_strdupa(ast_channel_context(current_dest_chan));
    		extension = ast_strdupa(ast_channel_exten(current_dest_chan));
    		priority = ast_channel_priority(current_dest_chan);
    		ast_channel_unlock(current_dest_chan);
    
    		ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority, NULL);
    
    	}
    
    	if (ast_bridge_features_init(&chan_features)) {
    		ast_bridge_features_cleanup(&chan_features);
    		goto done;
    
    	peer_features = ast_bridge_features_new();
    	if (!peer_features) {
    		ast_bridge_features_cleanup(&chan_features);
    		goto done;
    	}
    
    	if (pre_bridge_setup(chan, current_dest_chan, &bconfig, &chan_features, peer_features)) {
    		ast_bridge_features_destroy(peer_features);
    		ast_bridge_features_cleanup(&chan_features);
    		goto done;
    	}
    
    	bridge = ast_bridge_basic_new();
    	if (!bridge) {
    		ast_bridge_features_destroy(peer_features);
    		ast_bridge_features_cleanup(&chan_features);
    		goto done;
    	}
    
    
    	ast_channel_lock(current_dest_chan);
    
    	xfer_cfg = ast_get_chan_features_xfer_config(current_dest_chan);
    
    	ast_channel_unlock(current_dest_chan);
    
    	bridge_add_failed = ast_bridge_add_channel(bridge, current_dest_chan, peer_features,
    		ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE),
    		xfer_cfg ? xfer_cfg->xfersound : NULL);
    	ao2_cleanup(xfer_cfg);
    	if (bridge_add_failed) {
    
    	/* Don't keep the channel ref in case it was not already in a bridge. */
    	current_dest_chan = ast_channel_unref(current_dest_chan);
    
    
    	res = ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
    
    		AST_BRIDGE_JOIN_PASS_REFERENCE);
    
    	if (res == -1) {
    		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
    	} else {
    		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
    	}
    
    
    	ast_free((char *) bconfig.warning_sound);
    	ast_free((char *) bconfig.end_sound);
    	ast_free((char *) bconfig.start_sound);
    
    	ast_channel_cleanup(current_dest_chan);
    
    Richard Mudgett's avatar
    Richard Mudgett committed
    /*!
     * \internal
     * \brief Clean up resources on Asterisk shutdown
     */
    
    static void features_shutdown(void)
    {
    
    	ast_features_config_shutdown();
    
    
    	ast_manager_unregister("Bridge");
    
    	ast_unregister_application(app_bridge);
    
    }
    
    
    int ast_features_init(void)
    {
    	int res;
    
    	res = ast_features_config_init();
    
    	res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
    	res |= ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
    
    Olle Johansson's avatar
    Olle Johansson committed
    
    
    	if (res) {
    		features_shutdown();
    	} else {
    
    		ast_register_cleanup(features_shutdown);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }