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

Generated on Thu Apr 16 06:27:09 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6