Thu Apr 28 2011 16:56:39

Asterisk developer's documentation


app_exec.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (c) 2004 - 2005, Tilghman Lesher.  All rights reserved.
00005  * Portions copyright (c) 2006, Philipp Dunkel.
00006  *
00007  * Tilghman Lesher <app_exec__v002@the-tilghman.com>
00008  *
00009  * This code is released by the author with no restrictions on usage.
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Exec application
00022  *
00023  * \author Tilghman Lesher <app_exec__v002@the-tilghman.com>
00024  * \author Philipp Dunkel <philipp.dunkel@ebox.at>
00025  *
00026  * \ingroup applications
00027  */
00028 
00029 #include "asterisk.h"
00030 
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 251887 $")
00032 
00033 #include "asterisk/file.h"
00034 #include "asterisk/channel.h"
00035 #include "asterisk/pbx.h"
00036 #include "asterisk/module.h"
00037 #include "asterisk/app.h"
00038 
00039 /*** DOCUMENTATION
00040    <application name="Exec" language="en_US">
00041       <synopsis>
00042          Executes dialplan application.
00043       </synopsis>
00044       <syntax>
00045          <parameter name="appname" required="true" hasparams="true">
00046             <para>Application name and arguments of the dialplan application to execute.</para>
00047             <argument name="arguments" required="true" />
00048          </parameter>
00049       </syntax>
00050       <description>
00051          <para>Allows an arbitrary application to be invoked even when not
00052          hard coded into the dialplan.  If the underlying application
00053          terminates the dialplan, or if the application cannot be found,
00054          Exec will terminate the dialplan.</para>
00055          <para>To invoke external applications, see the application System.
00056          If you would like to catch any error instead, see TryExec.</para>
00057       </description>
00058    </application>
00059    <application name="TryExec" language="en_US">
00060       <synopsis>
00061          Executes dialplan application, always returning.
00062       </synopsis>
00063       <syntax>
00064          <parameter name="appname" required="true" hasparams="true">
00065             <argument name="arguments" required="true" />
00066          </parameter>
00067       </syntax>
00068       <description>
00069          <para>Allows an arbitrary application to be invoked even when not
00070          hard coded into the dialplan. To invoke external applications
00071          see the application System.  Always returns to the dialplan.
00072          The channel variable TRYSTATUS will be set to one of:
00073          </para>
00074          <variablelist>
00075             <variable name="TRYSTATUS">
00076                <value name="SUCCESS">
00077                   If the application returned zero.
00078                </value>
00079                <value name="FAILED">
00080                   If the application returned non-zero.
00081                </value>
00082                <value name="NOAPP">
00083                   If the application was not found or was not specified.
00084                </value>
00085             </variable>
00086          </variablelist>
00087       </description>
00088    </application>
00089    <application name="ExecIf" language="en_US">
00090       <synopsis>
00091          Executes dialplan application, conditionally.
00092       </synopsis>
00093       <syntax argsep="?">
00094          <parameter name="expression" required="true" />
00095          <parameter name="execapp" required="true" argsep=":">
00096             <argument name="appiftrue" required="true" hasparams="true">
00097                <argument name="args" required="true" />
00098             </argument>
00099             <argument name="appiffalse" required="false" hasparams="true">
00100                <argument name="args" required="true" />
00101             </argument>
00102          </parameter>
00103       </syntax>
00104       <description>
00105          <para>If <replaceable>expr</replaceable> is true, execute and return the
00106          result of <replaceable>appiftrue(args)</replaceable>.</para>
00107          <para>If <replaceable>expr</replaceable> is true, but <replaceable>appiftrue</replaceable> is not found,
00108          then the application will return a non-zero value.</para>
00109       </description>
00110    </application>
00111  ***/
00112 
00113 /* Maximum length of any variable */
00114 #define MAXRESULT 1024
00115 
00116 /*! Note
00117  *
00118  * The key difference between these two apps is exit status.  In a
00119  * nutshell, Exec tries to be transparent as possible, behaving
00120  * in exactly the same way as if the application it calls was
00121  * directly invoked from the dialplan.
00122  *
00123  * TryExec, on the other hand, provides a way to execute applications
00124  * and catch any possible fatal error without actually fatally
00125  * affecting the dialplan.
00126  */
00127 
00128 static char *app_exec = "Exec";
00129 static char *app_tryexec = "TryExec";
00130 static char *app_execif = "ExecIf";
00131 
00132 static int exec_exec(struct ast_channel *chan, void *data)
00133 {
00134    int res = 0;
00135    char *s, *appname, *endargs, args[MAXRESULT];
00136    struct ast_app *app;
00137 
00138    if (ast_strlen_zero(data))
00139       return 0;
00140 
00141    s = ast_strdupa(data);
00142    args[0] = 0;
00143    appname = strsep(&s, "(");
00144    if (s) {
00145       endargs = strrchr(s, ')');
00146       if (endargs)
00147          *endargs = '\0';
00148       pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
00149    }
00150    if (appname) {
00151       app = pbx_findapp(appname);
00152       if (app) {
00153          res = pbx_exec(chan, app, args);
00154       } else {
00155          ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
00156          res = -1;
00157       }
00158    }
00159 
00160    return res;
00161 }
00162 
00163 static int tryexec_exec(struct ast_channel *chan, void *data)
00164 {
00165    int res = 0;
00166    char *s, *appname, *endargs, args[MAXRESULT];
00167    struct ast_app *app;
00168 
00169    if (ast_strlen_zero(data))
00170       return 0;
00171 
00172    s = ast_strdupa(data);
00173    args[0] = 0;
00174    appname = strsep(&s, "(");
00175    if (s) {
00176       endargs = strrchr(s, ')');
00177       if (endargs)
00178          *endargs = '\0';
00179       pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
00180    }
00181    if (appname) {
00182       app = pbx_findapp(appname);
00183       if (app) {
00184          res = pbx_exec(chan, app, args);
00185          pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
00186       } else {
00187          ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
00188          pbx_builtin_setvar_helper(chan, "TRYSTATUS", "NOAPP");
00189       }
00190    }
00191 
00192    return 0;
00193 }
00194 
00195 static int execif_exec(struct ast_channel *chan, void *data)
00196 {
00197    int res = 0;
00198    char *truedata = NULL, *falsedata = NULL, *end, *firstcomma, *firstquestion;
00199    struct ast_app *app = NULL;
00200    AST_DECLARE_APP_ARGS(expr,
00201       AST_APP_ARG(expr);
00202       AST_APP_ARG(remainder);
00203    );
00204    AST_DECLARE_APP_ARGS(apps,
00205       AST_APP_ARG(t);
00206       AST_APP_ARG(f);
00207    );
00208    char *parse = ast_strdupa(data);
00209 
00210    firstcomma = strchr(parse, ',');
00211    firstquestion = strchr(parse, '?');
00212 
00213    if ((firstcomma != NULL && firstquestion != NULL && firstcomma < firstquestion) || (firstquestion == NULL)) {
00214       /* Deprecated syntax */
00215       AST_DECLARE_APP_ARGS(depr,
00216          AST_APP_ARG(expr);
00217          AST_APP_ARG(appname);
00218          AST_APP_ARG(appargs);
00219       );
00220       AST_STANDARD_APP_ARGS(depr, parse);
00221 
00222       ast_log(LOG_WARNING, "Deprecated syntax found.  Please upgrade to using ExecIf(<expr>?%s(%s))\n", depr.appname, depr.appargs);
00223 
00224       /* Make the two syntaxes look the same */
00225       expr.expr = depr.expr;
00226       apps.t = depr.appname;
00227       apps.f = NULL;
00228       truedata = depr.appargs;
00229    } else {
00230       /* Preferred syntax */
00231 
00232       AST_NONSTANDARD_RAW_ARGS(expr, parse, '?');
00233       if (ast_strlen_zero(expr.remainder)) {
00234          ast_log(LOG_ERROR, "Usage: ExecIf(<expr>?<appiftrue>(<args>)[:<appiffalse>(<args)])\n");
00235          return -1;
00236       }
00237 
00238       AST_NONSTANDARD_RAW_ARGS(apps, expr.remainder, ':');
00239 
00240       if (apps.t && (truedata = strchr(apps.t, '('))) {
00241          *truedata++ = '\0';
00242          if ((end = strrchr(truedata, ')'))) {
00243             *end = '\0';
00244          }
00245       }
00246 
00247       if (apps.f && (falsedata = strchr(apps.f, '('))) {
00248          *falsedata++ = '\0';
00249          if ((end = strrchr(falsedata, ')'))) {
00250             *end = '\0';
00251          }
00252       }
00253    }
00254 
00255    if (pbx_checkcondition(expr.expr)) {
00256       if (!ast_strlen_zero(apps.t) && (app = pbx_findapp(apps.t))) {
00257          res = pbx_exec(chan, app, S_OR(truedata, ""));
00258       } else {
00259          ast_log(LOG_WARNING, "Could not find application! (%s)\n", apps.t);
00260          res = -1;
00261       }
00262    } else if (!ast_strlen_zero(apps.f)) {
00263       if ((app = pbx_findapp(apps.f))) {
00264          res = pbx_exec(chan, app, S_OR(falsedata, ""));
00265       } else {
00266          ast_log(LOG_WARNING, "Could not find application! (%s)\n", apps.f);
00267          res = -1;
00268       }
00269    }
00270 
00271    return res;
00272 }
00273 
00274 static int unload_module(void)
00275 {
00276    int res;
00277 
00278    res = ast_unregister_application(app_exec);
00279    res |= ast_unregister_application(app_tryexec);
00280    res |= ast_unregister_application(app_execif);
00281 
00282    return res;
00283 }
00284 
00285 static int load_module(void)
00286 {
00287    int res = ast_register_application_xml(app_exec, exec_exec);
00288    res |= ast_register_application_xml(app_tryexec, tryexec_exec);
00289    res |= ast_register_application_xml(app_execif, execif_exec);
00290    return res;
00291 }
00292 
00293 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Executes dialplan applications");