Fix various spelling and grammatical issues in documentation
[asterisk/asterisk.git] / apps / app_exec.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (c) 2004 - 2005, Tilghman Lesher.  All rights reserved.
5  * Portions copyright (c) 2006, Philipp Dunkel.
6  *
7  * Tilghman Lesher <app_exec__v002@the-tilghman.com>
8  *
9  * This code is released by the author with no restrictions on usage.
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  */
18
19 /*! \file
20  *
21  * \brief Exec application
22  *
23  * \author Tilghman Lesher <app_exec__v002@the-tilghman.com>
24  * \author Philipp Dunkel <philipp.dunkel@ebox.at>
25  *
26  * \ingroup applications
27  */
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include "asterisk/file.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/module.h"
37 #include "asterisk/app.h"
38
39 /*** DOCUMENTATION
40         <application name="Exec" language="en_US">
41                 <synopsis>
42                         Executes dialplan application.
43                 </synopsis>
44                 <syntax>
45                         <parameter name="appname" required="true" hasparams="true">
46                                 <para>Application name and arguments of the dialplan application to execute.</para>
47                                 <argument name="arguments" required="true" />
48                         </parameter>
49                 </syntax>
50                 <description>
51                         <para>Allows an arbitrary application to be invoked even when not
52                         hard coded into the dialplan.  If the underlying application
53                         terminates the dialplan, or if the application cannot be found,
54                         Exec will terminate the dialplan.</para>
55                         <para>To invoke external applications, see the application System.
56                         If you would like to catch any error instead, see TryExec.</para>
57                 </description>
58         </application>
59         <application name="TryExec" language="en_US">
60                 <synopsis>
61                         Executes dialplan application, always returning.
62                 </synopsis>
63                 <syntax>
64                         <parameter name="appname" required="true" hasparams="true">
65                                 <argument name="arguments" required="true" />
66                         </parameter>
67                 </syntax>
68                 <description>
69                         <para>Allows an arbitrary application to be invoked even when not
70                         hard coded into the dialplan. To invoke external applications
71                         see the application System.  Always returns to the dialplan.
72                         The channel variable TRYSTATUS will be set to one of:
73                         </para>
74                         <variablelist>
75                                 <variable name="TRYSTATUS">
76                                         <value name="SUCCESS">
77                                                 If the application returned zero.
78                                         </value>
79                                         <value name="FAILED">
80                                                 If the application returned non-zero.
81                                         </value>
82                                         <value name="NOAPP">
83                                                 If the application was not found or was not specified.
84                                         </value>
85                                 </variable>
86                         </variablelist>
87                 </description>
88         </application>
89         <application name="ExecIf" language="en_US">
90                 <synopsis>
91                         Executes dialplan application, conditionally.
92                 </synopsis>
93                 <syntax argsep="?">
94                         <parameter name="expression" required="true" />
95                         <parameter name="execapp" required="true" argsep=":">
96                                 <argument name="appiftrue" required="true" hasparams="true">
97                                         <argument name="args" required="true" />
98                                 </argument>
99                                 <argument name="appiffalse" required="false" hasparams="true">
100                                         <argument name="args" required="true" />
101                                 </argument>
102                         </parameter>
103                 </syntax>
104                 <description>
105                         <para>If <replaceable>expr</replaceable> is true, execute and return the
106                         result of <replaceable>appiftrue(args)</replaceable>.</para>
107                         <para>If <replaceable>expr</replaceable> is true, but <replaceable>appiftrue</replaceable> is not found,
108                         then the application will return a non-zero value.</para>
109                 </description>
110         </application>
111  ***/
112
113 /* Maximum length of any variable */
114 #define MAXRESULT 1024
115
116 /*! Note
117  *
118  * The key difference between these two apps is exit status.  In a
119  * nutshell, Exec tries to be transparent as possible, behaving
120  * in exactly the same way as if the application it calls was
121  * directly invoked from the dialplan.
122  *
123  * TryExec, on the other hand, provides a way to execute applications
124  * and catch any possible fatal error without actually fatally
125  * affecting the dialplan.
126  */
127
128 static char *app_exec = "Exec";
129 static char *app_tryexec = "TryExec";
130 static char *app_execif = "ExecIf";
131
132 static int exec_exec(struct ast_channel *chan, void *data)
133 {
134         int res = 0;
135         char *s, *appname, *endargs, args[MAXRESULT];
136         struct ast_app *app;
137
138         if (ast_strlen_zero(data))
139                 return 0;
140
141         s = ast_strdupa(data);
142         args[0] = 0;
143         appname = strsep(&s, "(");
144         if (s) {
145                 endargs = strrchr(s, ')');
146                 if (endargs)
147                         *endargs = '\0';
148                 pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
149         }
150         if (appname) {
151                 app = pbx_findapp(appname);
152                 if (app) {
153                         res = pbx_exec(chan, app, args);
154                 } else {
155                         ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
156                         res = -1;
157                 }
158         }
159
160         return res;
161 }
162
163 static int tryexec_exec(struct ast_channel *chan, void *data)
164 {
165         int res = 0;
166         char *s, *appname, *endargs, args[MAXRESULT];
167         struct ast_app *app;
168
169         if (ast_strlen_zero(data))
170                 return 0;
171
172         s = ast_strdupa(data);
173         args[0] = 0;
174         appname = strsep(&s, "(");
175         if (s) {
176                 endargs = strrchr(s, ')');
177                 if (endargs)
178                         *endargs = '\0';
179                 pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
180         }
181         if (appname) {
182                 app = pbx_findapp(appname);
183                 if (app) {
184                         res = pbx_exec(chan, app, args);
185                         pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
186                 } else {
187                         ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
188                         pbx_builtin_setvar_helper(chan, "TRYSTATUS", "NOAPP");
189                 }
190         }
191
192         return 0;
193 }
194
195 static int execif_exec(struct ast_channel *chan, void *data)
196 {
197         int res = 0;
198         char *truedata = NULL, *falsedata = NULL, *end, *firstcomma, *firstquestion;
199         struct ast_app *app = NULL;
200         AST_DECLARE_APP_ARGS(expr,
201                 AST_APP_ARG(expr);
202                 AST_APP_ARG(remainder);
203         );
204         AST_DECLARE_APP_ARGS(apps,
205                 AST_APP_ARG(t);
206                 AST_APP_ARG(f);
207         );
208         char *parse = ast_strdupa(data);
209
210         firstcomma = strchr(parse, ',');
211         firstquestion = strchr(parse, '?');
212
213         if ((firstcomma != NULL && firstquestion != NULL && firstcomma < firstquestion) || (firstquestion == NULL)) {
214                 /* Deprecated syntax */
215                 AST_DECLARE_APP_ARGS(depr,
216                         AST_APP_ARG(expr);
217                         AST_APP_ARG(appname);
218                         AST_APP_ARG(appargs);
219                 );
220                 AST_STANDARD_APP_ARGS(depr, parse);
221
222                 ast_log(LOG_WARNING, "Deprecated syntax found.  Please upgrade to using ExecIf(<expr>?%s(%s))\n", depr.appname, depr.appargs);
223
224                 /* Make the two syntaxes look the same */
225                 expr.expr = depr.expr;
226                 apps.t = depr.appname;
227                 apps.f = NULL;
228                 truedata = depr.appargs;
229         } else {
230                 /* Preferred syntax */
231
232                 AST_NONSTANDARD_APP_ARGS(expr, parse, '?');
233                 if (ast_strlen_zero(expr.remainder)) {
234                         ast_log(LOG_ERROR, "Usage: ExecIf(<expr>?<appiftrue>(<args>)[:<appiffalse>(<args)])\n");
235                         return -1;
236                 }
237
238                 AST_NONSTANDARD_APP_ARGS(apps, expr.remainder, ':');
239
240                 if (apps.t && (truedata = strchr(apps.t, '('))) {
241                         *truedata++ = '\0';
242                         if ((end = strrchr(truedata, ')'))) {
243                                 *end = '\0';
244                         }
245                 }
246
247                 if (apps.f && (falsedata = strchr(apps.f, '('))) {
248                         *falsedata++ = '\0';
249                         if ((end = strrchr(falsedata, ')'))) {
250                                 *end = '\0';
251                         }
252                 }
253         }
254
255         if (pbx_checkcondition(expr.expr)) {
256                 if (!ast_strlen_zero(apps.t) && (app = pbx_findapp(apps.t))) {
257                         res = pbx_exec(chan, app, S_OR(truedata, ""));
258                 } else {
259                         ast_log(LOG_WARNING, "Could not find application! (%s)\n", apps.t);
260                         res = -1;
261                 }
262         } else if (!ast_strlen_zero(apps.f)) {
263                 if ((app = pbx_findapp(apps.f))) {
264                         res = pbx_exec(chan, app, S_OR(falsedata, ""));
265                 } else {
266                         ast_log(LOG_WARNING, "Could not find application! (%s)\n", apps.f);
267                         res = -1;
268                 }
269         }
270
271         return res;
272 }
273
274 static int unload_module(void)
275 {
276         int res;
277
278         res = ast_unregister_application(app_exec);
279         res |= ast_unregister_application(app_tryexec);
280         res |= ast_unregister_application(app_execif);
281
282         return res;
283 }
284
285 static int load_module(void)
286 {
287         int res = ast_register_application_xml(app_exec, exec_exec);
288         res |= ast_register_application_xml(app_tryexec, tryexec_exec);
289         res |= ast_register_application_xml(app_execif, execif_exec);
290         return res;
291 }
292
293 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Executes dialplan applications");