asterisk/apps/app_exec.c
Luigi Rizzo e43bc6634d This rather large commit changes the way modules are loaded.
As partly documented in loader.c and include/asterisk/module.h,
modules are now expected to return all of their methods and flags
into a structure 'mod_data', and are normally loaded with RTLD_NOW
| RTLD_LOCAL, so symbols are resolved immediately and conflicts
should be less likely.  Only in a small number of cases (res_*,
typically) modules are loaded RTLD_GLOBAL, so they can export
symbols.
 
The core of the change is only the two files loader.c and
include/asterisk/module.h, all the rest is simply adaptation of the
existing modules to the new API, a rather mechanical (but believe
me, time and finger-consuming!) process whose detail you can figure
out by svn diff'ing any single module.

Expect some minor compilation issue after this change, please
report it on mantis http://bugs.digium.com/view.php?id=6968
so we collect all the feedback in one place.

I am just sorry that this change missed SVN version number 20000!



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@20003 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-04-14 14:08:19 +00:00

193 lines
5 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
* Portions copyright (c) 2006, Philipp Dunkel.
*
* Tilghman Lesher <app_exec__v002@the-tilghman.com>
*
* This code is released by the author with no restrictions on usage.
*
* 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.
*
*/
/*! \file
*
* \brief Exec application
*
* \author Tilghman Lesher <app_exec__v002@the-tilghman.com>
* \author Philipp Dunkel <philipp.dunkel@ebox.at>
*
* \ingroup applications
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
/* Maximum length of any variable */
#define MAXRESULT 1024
static char *tdesc = "Executes dialplan applications";
/*! Note
*
* The key difference between these two apps is exit status. In a
* nutshell, Exec tries to be transparent as possible, behaving
* in exactly the same way as if the application it calls was
* directly invoked from the dialplan.
*
* TryExec, on the other hand, provides a way to execute applications
* and catch any possible fatal error without actually fatally
* affecting the dialplan.
*/
static char *app_exec = "Exec";
static char *exec_synopsis = "Executes dialplan application";
static char *exec_descrip =
"Usage: Exec(appname(arguments))\n"
" Allows an arbitrary application to be invoked even when not\n"
"hardcoded into the dialplan. If the underlying application\n"
"terminates the dialplan, or if the application cannot be found,\n"
"Exec will terminate the dialplan.\n"
" To invoke external applications, see the application System.\n"
" If you would like to catch any error instead, see TryExec.\n";
static char *app_tryexec = "TryExec";
static char *tryexec_synopsis = "Executes dialplan application, always returning";
static char *tryexec_descrip =
"Usage: TryExec(appname(arguments))\n"
" Allows an arbitrary application to be invoked even when not\n"
"hardcoded into the dialplan. To invoke external applications\n"
"see the application System. Always returns to the dialplan.\n"
"The channel variable TRYSTATUS will be set to:\n"
" SUCCESS if the application returned zero\n"
" FAILED if the application returned non-zero\n"
" NOAPP if the application was not found or was not specified\n"
" NOMEMORY if there was not enough memory to execute.\n";
LOCAL_USER_DECL;
static int exec_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
char *s, *appname, *endargs, args[MAXRESULT] = "";
struct ast_app *app;
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data) {
if ((s = ast_strdupa(data))) {
appname = strsep(&s, "(");
if (s) {
endargs = strrchr(s, ')');
if (endargs)
*endargs = '\0';
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
}
if (appname) {
app = pbx_findapp(appname);
if (app) {
res = pbx_exec(chan, app, args);
} else {
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
res = -1;
}
}
} else
res = -1;
}
LOCAL_USER_REMOVE(u);
return res;
}
static int tryexec_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
char *s, *appname, *endargs, args[MAXRESULT] = "";
struct ast_app *app;
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data) {
if ((s = ast_strdupa(data))) {
appname = strsep(&s, "(");
if (s) {
endargs = strrchr(s, ')');
if (endargs)
*endargs = '\0';
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
}
if (appname) {
app = pbx_findapp(appname);
if (app) {
res = pbx_exec(chan, app, args);
pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
} else {
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
pbx_builtin_setvar_helper(chan, "TRYSTATUS", "NOAPP");
}
}
} else {
ast_log(LOG_ERROR, "Out of memory\n");
pbx_builtin_setvar_helper(chan, "TRYSTATUS", "NOMEMORY");
}
}
LOCAL_USER_REMOVE(u);
return 0;
}
static int unload_module(void *mod)
{
int res;
res = ast_unregister_application(app_exec);
res |= ast_unregister_application(app_tryexec);
STANDARD_HANGUP_LOCALUSERS;
return res;
}
static int load_module(void *mod)
{
int res = ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
res |= ast_register_application(app_tryexec, tryexec_exec, tryexec_synopsis, tryexec_descrip);
return res;
}
static const char *description(void)
{
return tdesc;
}
static const char *key(void)
{
return ASTERISK_GPL_KEY;
}
STD_MOD1;