Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
5  *
6  * Anthony Minessale <[email protected]>
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 <[email protected]>
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 
100 static char *start_app = "While";
101 static char *stop_app = "EndWhile";
102 static char *exit_app = "ExitWhile";
103 static char *continue_app = "ContinueWhile";
104 
105 #define VAR_SIZE 64
106 
107 
108 static 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 
115 static 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;
129  if (priority != ast_get_extension_priority(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 
152 static 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 
162  for (c=ast_walk_contexts(NULL); c; c=ast_walk_contexts(c)) {
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 
197 static 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 
307 static int while_start_exec(struct ast_channel *chan, const char *data) {
308  return _while_exec(chan, data, 0);
309 }
310 
311 static int while_end_exec(struct ast_channel *chan, const char *data) {
312  return _while_exec(chan, data, 1);
313 }
314 
315 static int while_exit_exec(struct ast_channel *chan, const char *data) {
316  return _while_exec(chan, data, 2);
317 }
318 
319 static 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 
338 static int unload_module(void)
339 {
340  int res;
341 
346 
347  return res;
348 }
349 
350 static int load_module(void)
351 {
352  int res;
353 
358 
359  return res;
360 }
361 
362 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "While Loops and Conditional Execution");
const char * label
Definition: pbx.c:244
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8558
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
static char * exit_app
Definition: app_while.c:102
Asterisk main include file. File version handling, generic pbx functions.
static const char * get_index(struct ast_channel *chan, const char *prefix, int idx)
Definition: app_while.c:108
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
static int while_start_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:307
static char * continue_app
Definition: app_while.c:103
#define LOG_WARNING
Definition: logger.h:274
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8596
static int load_module(void)
Definition: app_while.c:350
static int tmp()
Definition: bt_open.c:389
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8321
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: conf2ael.c:618
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8507
static struct test_val c
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
static int priority
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_channel_priority(const struct ast_channel *chan)
#define ast_verb(level,...)
Definition: logger.h:463
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Number structure.
Definition: app_followme.c:154
#define ast_log
Definition: astobj2.c:42
static char * stop_app
Definition: app_while.c:101
General Asterisk PBX channel definitions.
static int while_continue_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:319
#define VAR_SIZE
Definition: app_while.c:105
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8859
static int unload_module(void)
Definition: app_while.c:338
#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:85
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8591
const char * ast_channel_exten(const struct ast_channel *chan)
Core PBX routines and definitions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8697
#define LOG_ERROR
Definition: logger.h:285
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8548
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: ael_main.c:427
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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:4297
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...
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3184
static int while_exit_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:315
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4063
static int _while_exec(struct ast_channel *chan, const char *data, int end)
Definition: app_while.c:197
static int while_end_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:311
const char * ast_channel_context(const struct ast_channel *chan)
void * data
Definition: pbx.c:248
static int find_matching_endwhile(struct ast_channel *chan)
Definition: app_while.c:152
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
void ast_channel_priority_set(struct ast_channel *chan, int value)
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8586
Asterisk module definitions.
static struct ast_exten * find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
Definition: app_while.c:115
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8702
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition: pbx.c:8525
static char * start_app
Definition: app_while.c:100
static char prefix[MAX_PREFIX]
Definition: http.c:141