Asterisk - The Open Source Telephony Project GIT-master-f36a736
app_while.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright 2004 - 2005, Anthony Minessale <anthmct@yahoo.com>
5 *
6 * Anthony Minessale <anthmct@yahoo.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief While Loop Implementation
22 *
23 * \author Anthony Minessale <anthmct@yahoo.com>
24 *
25 * \ingroup applications
26 */
27
28/*** MODULEINFO
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/pbx.h"
35#include "asterisk/module.h"
36#include "asterisk/channel.h"
37
38/*** DOCUMENTATION
39 <application name="While" language="en_US">
40 <synopsis>
41 Start a while loop.
42 </synopsis>
43 <syntax>
44 <parameter name="expr" required="true" />
45 </syntax>
46 <description>
47 <para>Start a While Loop. Execution will return to this point when
48 <literal>EndWhile()</literal> is called until expr is no longer true.</para>
49 </description>
50 <see-also>
51 <ref type="application">EndWhile</ref>
52 <ref type="application">ExitWhile</ref>
53 <ref type="application">ContinueWhile</ref>
54 </see-also>
55 </application>
56 <application name="EndWhile" language="en_US">
57 <synopsis>
58 End a while loop.
59 </synopsis>
60 <syntax />
61 <description>
62 <para>Return to the previous called <literal>While()</literal>.</para>
63 </description>
64 <see-also>
65 <ref type="application">While</ref>
66 <ref type="application">ExitWhile</ref>
67 <ref type="application">ContinueWhile</ref>
68 </see-also>
69 </application>
70 <application name="ExitWhile" language="en_US">
71 <synopsis>
72 End a While loop.
73 </synopsis>
74 <syntax />
75 <description>
76 <para>Exits a <literal>While()</literal> loop, whether or not the conditional has been satisfied.</para>
77 </description>
78 <see-also>
79 <ref type="application">While</ref>
80 <ref type="application">EndWhile</ref>
81 <ref type="application">ContinueWhile</ref>
82 </see-also>
83 </application>
84 <application name="ContinueWhile" language="en_US">
85 <synopsis>
86 Restart a While loop.
87 </synopsis>
88 <syntax />
89 <description>
90 <para>Returns to the top of the while loop and re-evaluates the conditional.</para>
91 </description>
92 <see-also>
93 <ref type="application">While</ref>
94 <ref type="application">EndWhile</ref>
95 <ref type="application">ExitWhile</ref>
96 </see-also>
97 </application>
98 ***/
99
100static char *start_app = "While";
101static char *stop_app = "EndWhile";
102static char *exit_app = "ExitWhile";
103static char *continue_app = "ContinueWhile";
104
105#define VAR_SIZE 64
106
107
108static const char *get_index(struct ast_channel *chan, const char *prefix, int idx) {
109 char varname[VAR_SIZE];
110
111 snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);
112 return pbx_builtin_getvar_helper(chan, varname);
113}
114
115static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
116{
117 struct ast_exten *e;
118 struct ast_context *c2;
119 int idx;
120
123 int needmatch = ast_get_extension_matchcid(e);
124 if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
125 (!needmatch)) {
126 /* This is the matching extension we want */
127 struct ast_exten *p;
130 continue;
131 return p;
132 }
133 }
134 }
135 }
136
137 /* No match; run through includes */
138 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
139 const struct ast_include *i = ast_context_includes_get(c, idx);
140
141 for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
142 if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
143 e = find_matching_priority(c2, exten, priority, callerid);
144 if (e)
145 return e;
146 }
147 }
148 }
149 return NULL;
150}
151
152static int find_matching_endwhile(struct ast_channel *chan)
153{
154 struct ast_context *c;
155 int res=-1;
156
157 if (ast_rdlock_contexts()) {
158 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
159 return -1;
160 }
161
163 struct ast_exten *e;
164
165 if (!ast_rdlock_context(c)) {
166 if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
167 /* This is the matching context we want */
168 int cur_priority = ast_channel_priority(chan) + 1, level=1;
169
170 for (e = find_matching_priority(c, ast_channel_exten(chan), cur_priority,
171 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
172 e;
173 e = find_matching_priority(c, ast_channel_exten(chan), ++cur_priority,
174 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
175 if (!strcasecmp(ast_get_extension_app(e), "WHILE")) {
176 level++;
177 } else if (!strcasecmp(ast_get_extension_app(e), "ENDWHILE")) {
178 level--;
179 }
180
181 if (level == 0) {
182 res = cur_priority;
183 break;
184 }
185 }
186 }
188 if (res > 0) {
189 break;
190 }
191 }
192 }
194 return res;
195}
196
197static int _while_exec(struct ast_channel *chan, const char *data, int end)
198{
199 int res=0;
200 const char *while_pri = NULL;
201 char *my_name = NULL;
202 const char *condition = NULL, *label = NULL;
203 char varname[VAR_SIZE], end_varname[VAR_SIZE];
204 const char *prefix = "WHILE";
205 size_t size=0;
206 int used_index_i = -1, x=0;
207 char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
208
209 if (!chan) {
210 /* huh ? */
211 return -1;
212 }
213
214#if 0
215 /* don't want run away loops if the chan isn't even up
216 this is up for debate since it slows things down a tad ......
217
218 Debate is over... this prevents While/EndWhile from working
219 within the "h" extension. Not good.
220 */
221 if (ast_waitfordigit(chan,1) < 0)
222 return -1;
223#endif
224
225 for (x=0;;x++) {
226 if (get_index(chan, prefix, x)) {
227 used_index_i = x;
228 } else
229 break;
230 }
231
232 snprintf(used_index, VAR_SIZE, "%d", used_index_i);
233 snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
234
235 if (!end)
236 condition = ast_strdupa(data);
237
238 size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
239 my_name = ast_alloca(size);
240 memset(my_name, 0, size);
241 snprintf(my_name, size, "%s_%s_%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
242
243 ast_channel_lock(chan);
244 if (end) {
245 label = used_index;
246 } else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
247 label = new_index;
248 pbx_builtin_setvar_helper(chan, my_name, label);
249 }
250 snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
251 if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
252 while_pri = ast_strdupa(while_pri);
253 snprintf(end_varname,VAR_SIZE,"END_%s",varname);
254 }
255 ast_channel_unlock(chan);
256
257
258 if ((!end && !pbx_checkcondition(condition)) || (end == 2)) {
259 /* Condition Met (clean up helper vars) */
260 const char *goto_str;
261 pbx_builtin_setvar_helper(chan, varname, NULL);
262 pbx_builtin_setvar_helper(chan, my_name, NULL);
263 snprintf(end_varname,VAR_SIZE,"END_%s",varname);
264 ast_channel_lock(chan);
265 if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
266 ast_parseable_goto(chan, goto_str);
267 pbx_builtin_setvar_helper(chan, end_varname, NULL);
268 } else {
269 int pri = find_matching_endwhile(chan);
270 if (pri > 0) {
271 ast_verb(3, "Jumping to priority %d\n", pri);
272 ast_channel_priority_set(chan, pri);
273 } else {
274 ast_log(LOG_WARNING, "Couldn't find matching EndWhile? (While at %s@%s priority %d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
275 }
276 }
277 ast_channel_unlock(chan);
278 return res;
279 }
280
281 if (!end && !while_pri) {
282 char *goto_str;
283 size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
284 goto_str = ast_alloca(size);
285 memset(goto_str, 0, size);
286 snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
287 pbx_builtin_setvar_helper(chan, varname, goto_str);
288 }
289
290 else if (end && while_pri) {
291 /* END of loop */
292 snprintf(end_varname, VAR_SIZE, "END_%s", varname);
293 if (! pbx_builtin_getvar_helper(chan, end_varname)) {
294 char *goto_str;
295 size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
296 goto_str = ast_alloca(size);
297 memset(goto_str, 0, size);
298 snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan)+1);
299 pbx_builtin_setvar_helper(chan, end_varname, goto_str);
300 }
301 ast_parseable_goto(chan, while_pri);
302 }
303
304 return res;
305}
306
307static int while_start_exec(struct ast_channel *chan, const char *data) {
308 return _while_exec(chan, data, 0);
309}
310
311static int while_end_exec(struct ast_channel *chan, const char *data) {
312 return _while_exec(chan, data, 1);
313}
314
315static int while_exit_exec(struct ast_channel *chan, const char *data) {
316 return _while_exec(chan, data, 2);
317}
318
319static int while_continue_exec(struct ast_channel *chan, const char *data)
320{
321 int x;
322 const char *prefix = "WHILE", *while_pri=NULL;
323
324 for (x = 0; ; x++) {
325 const char *tmp = get_index(chan, prefix, x);
326 if (tmp)
327 while_pri = tmp;
328 else
329 break;
330 }
331
332 if (while_pri)
333 ast_parseable_goto(chan, while_pri);
334
335 return 0;
336}
337
338static int unload_module(void)
339{
340 int res;
341
346
347 return res;
348}
349
350static int load_module(void)
351{
352 int res;
353
358
359 return res;
360}
361
362AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "While Loops and Conditional Execution");
static const char * get_index(struct ast_channel *chan, const char *prefix, int idx)
Definition: app_while.c:108
static struct ast_exten * find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
Definition: app_while.c:115
static char * stop_app
Definition: app_while.c:101
static int while_end_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:311
static int while_exit_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:315
static char * exit_app
Definition: app_while.c:102
static int _while_exec(struct ast_channel *chan, const char *data, int end)
Definition: app_while.c:197
static int while_start_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:307
#define VAR_SIZE
Definition: app_while.c:105
static int find_matching_endwhile(struct ast_channel *chan)
Definition: app_while.c:152
static char * continue_app
Definition: app_while.c:103
static int load_module(void)
Definition: app_while.c:350
static int unload_module(void)
Definition: app_while.c:338
static int while_continue_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:319
static char * start_app
Definition: app_while.c:100
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
static int priority
General Asterisk PBX channel definitions.
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3194
#define ast_channel_lock(chan)
Definition: channel.h:2968
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2969
char * end
Definition: eagi_proxy.c:73
static char prefix[MAX_PREFIX]
Definition: http.c:144
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
Core PBX routines and definitions.
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4024
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8519
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8547
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8557
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8552
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8491
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4061
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Definition: extconf.c:4295
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8468
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8684
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: ael_main.c:427
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8282
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8473
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8866
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8679
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8509
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition: pbx.c:8486
#define NULL
Definition: resample.c:96
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
Main Channel structure associated with a channel.
ast_context: An extension context
Definition: pbx.c:284
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition: pbx.c:237
char * exten
Definition: pbx.c:238
void * data
Definition: pbx.c:248
const char * label
Definition: pbx.c:244
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
Number structure.
Definition: app_followme.c:154
static struct test_val c