mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 18:55:19 +00:00 
			
		
		
		
	
		
			
	
	
		
			161 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			161 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * Asterisk -- An open source telephony toolkit. | ||
|  |  * | ||
|  |  * Copyright (C) 2022, Naveen Albert | ||
|  |  * | ||
|  |  * Naveen Albert <asterisk@phreaknet.org> | ||
|  |  * | ||
|  |  * See http://www.asterisk.org for more information about
 | ||
|  |  * the Asterisk project. Please do not directly contact | ||
|  |  * any of the maintainers of this project for assistance; | ||
|  |  * the project provides a web site, mailing lists and IRC | ||
|  |  * channels for your use. | ||
|  |  * | ||
|  |  * This program is free software, distributed under the terms of | ||
|  |  * the GNU General Public License Version 2. See the LICENSE file | ||
|  |  * at the top of the source tree. | ||
|  |  */ | ||
|  | 
 | ||
|  | /*!
 | ||
|  |  * \file | ||
|  |  * \author Naveen Albert <asterisk@phreaknet.org> | ||
|  |  * | ||
|  |  * \brief Execute dialplan applications from the CLI | ||
|  |  * | ||
|  |  */ | ||
|  | 
 | ||
|  | /*** MODULEINFO
 | ||
|  | 	<defaultenabled>no</defaultenabled> | ||
|  | 	<support_level>extended</support_level> | ||
|  |  ***/ | ||
|  | 
 | ||
|  | #include "asterisk.h"
 | ||
|  | 
 | ||
|  | #include "asterisk/channel.h"
 | ||
|  | #include "asterisk/pbx.h"
 | ||
|  | #include "asterisk/module.h"
 | ||
|  | #include "asterisk/cli.h"
 | ||
|  | #include "asterisk/utils.h"
 | ||
|  | #include "asterisk/frame.h"
 | ||
|  | #include "asterisk/format_cache.h"
 | ||
|  | 
 | ||
|  | static const struct ast_channel_tech mock_channel_tech = { | ||
|  | }; | ||
|  | 
 | ||
|  | static int cli_chan = 0; | ||
|  | 
 | ||
|  | /*! \brief CLI support for executing application */ | ||
|  | static char *handle_exec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | ||
|  | { | ||
|  | 	struct ast_channel *c = NULL; | ||
|  | 	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); | ||
|  | 	char *app_name, *app_args; | ||
|  | 	int ret = 0; | ||
|  | 	struct ast_app *app; | ||
|  | 
 | ||
|  | 	switch (cmd) { | ||
|  | 	case CLI_INIT: | ||
|  | 		e->command = "dialplan exec application"; | ||
|  | 		e->usage = | ||
|  | 			"Usage: dialplan exec application <appname> [<args>]\n" | ||
|  | 			"       Execute a single dialplan application call for\n" | ||
|  | 			"       testing. A mock channel is used to execute\n" | ||
|  | 			"       the application, so it may not make\n" | ||
|  | 			"       sense to use all applications, and only\n" | ||
|  | 			"       global variables should be used.\n" | ||
|  | 			"       The ulaw, alaw, and h264 codecs are available.\n"; | ||
|  | 		return NULL; | ||
|  | 	case CLI_GENERATE: | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (a->argc != e->args + 1 && a->argc != e->args + 2) { | ||
|  | 		return CLI_SHOWUSAGE; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	app_name = (char *) a->argv[3]; | ||
|  | 	app_args = a->argc == e->args + 2 ? (char *) a->argv[4] : NULL; | ||
|  | 
 | ||
|  | 	if (!app_name) { | ||
|  | 		return CLI_FAILURE; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); | ||
|  | 	if (!caps) { | ||
|  | 		ast_log(LOG_WARNING, "Could not allocate an empty format capabilities structure\n"); | ||
|  | 		return CLI_FAILURE; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (ast_format_cap_append(caps, ast_format_ulaw, 0)) { | ||
|  | 		ast_log(LOG_WARNING, "Failed to append a ulaw format to capabilities for channel nativeformats\n"); | ||
|  | 		return CLI_FAILURE; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (ast_format_cap_append(caps, ast_format_alaw, 0)) { | ||
|  | 		ast_log(LOG_WARNING, "Failed to append an alaw format to capabilities for channel nativeformats\n"); | ||
|  | 		return CLI_FAILURE; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (ast_format_cap_append(caps, ast_format_h264, 0)) { | ||
|  | 		ast_log(LOG_WARNING, "Failed to append an h264 format to capabilities for channel nativeformats\n"); | ||
|  | 		return CLI_FAILURE; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	c = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CLIExec/%d", ++cli_chan); | ||
|  | 	if (!c) { | ||
|  | 		ast_cli(a->fd, "Unable to allocate mock channel for application execution.\n"); | ||
|  | 		return CLI_FAILURE; | ||
|  | 	} | ||
|  | 	ast_channel_tech_set(c, &mock_channel_tech); | ||
|  | 	ast_channel_nativeformats_set(c, caps); | ||
|  | 	ast_channel_set_writeformat(c, ast_format_slin); | ||
|  | 	ast_channel_set_rawwriteformat(c, ast_format_slin); | ||
|  | 	ast_channel_set_readformat(c, ast_format_slin); | ||
|  | 	ast_channel_set_rawreadformat(c, ast_format_slin); | ||
|  | 	ast_channel_unlock(c); | ||
|  | 
 | ||
|  | 	app = pbx_findapp(app_name); | ||
|  | 	if (!app) { | ||
|  | 		ast_log(LOG_WARNING, "Could not find application (%s)\n", app_name); | ||
|  | 		ast_hangup(c); | ||
|  | 		return CLI_FAILURE; | ||
|  | 	} else { | ||
|  | 		struct ast_str *substituted_args = ast_str_create(16); | ||
|  | 
 | ||
|  | 		if (substituted_args) { | ||
|  | 			ast_str_substitute_variables(&substituted_args, 0, c, app_args); | ||
|  | 			ast_cli(a->fd, "Executing: %s(%s)\n", app_name, ast_str_buffer(substituted_args)); | ||
|  | 			ret = pbx_exec(c, app, ast_str_buffer(substituted_args)); | ||
|  | 			ast_free(substituted_args); | ||
|  | 		} else { | ||
|  | 			ast_log(LOG_WARNING, "Could not substitute application argument variables for %s\n", app_name); | ||
|  | 			ast_cli(a->fd, "Executing: %s(%s)\n", app_name, app_args); | ||
|  | 			ret = pbx_exec(c, app, app_args); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	ast_hangup(c); /* no need to unref separately */ | ||
|  | 
 | ||
|  | 	ast_cli(a->fd, "Return Value: %s (%d)\n", ret ? "Failure" : "Success", ret); | ||
|  | 
 | ||
|  | 	return CLI_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | static struct ast_cli_entry cli_cliorig[] = { | ||
|  | 	AST_CLI_DEFINE(handle_exec, "Execute a dialplan application"), | ||
|  | }; | ||
|  | 
 | ||
|  | static int unload_module(void) | ||
|  | { | ||
|  | 	return ast_cli_unregister_multiple(cli_cliorig, ARRAY_LEN(cli_cliorig)); | ||
|  | } | ||
|  | 
 | ||
|  | static int load_module(void) | ||
|  | { | ||
|  | 	int res; | ||
|  | 	res = ast_cli_register_multiple(cli_cliorig, ARRAY_LEN(cli_cliorig)); | ||
|  | 	return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; | ||
|  | } | ||
|  | 
 | ||
|  | AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Simple dialplan execution from the CLI"); |