]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_cliexec: Add dialplan exec CLI command.
authorNaveen Albert <asterisk@phreaknet.org>
Sat, 14 May 2022 21:25:04 +0000 (21:25 +0000)
committerKevin Harwell <kharwell@digium.com>
Fri, 8 Jul 2022 16:12:22 +0000 (11:12 -0500)
Adds a CLI command similar to "dialplan eval function" except for
applications: "dialplan exec application", useful for quickly
testing certain application behavior directly from the CLI
without writing any dialplan.

ASTERISK-30062 #close

Change-Id: I42e9fa9b60746c21450d40f99a026d48d2486dde

doc/CHANGES-staging/res_cliexec.txt [new file with mode: 0644]
res/res_cliexec.c [new file with mode: 0644]

diff --git a/doc/CHANGES-staging/res_cliexec.txt b/doc/CHANGES-staging/res_cliexec.txt
new file mode 100644 (file)
index 0000000..2b1fe76
--- /dev/null
@@ -0,0 +1,6 @@
+Subject: res_cliexec
+
+A new CLI command, dialplan exec application, has
+been added which allows dialplan applications to be
+executed at the CLI, useful for some quick testing
+without needing to write dialplan.
diff --git a/res/res_cliexec.c b/res/res_cliexec.c
new file mode 100644 (file)
index 0000000..b1e13f9
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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");