Asterisk - The Open Source Telephony Project  18.5.0
Macros | Functions | Variables
app_while.c File Reference

While Loop Implementation. More...

#include "asterisk.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
Include dependency graph for app_while.c:

Go to the source code of this file.

Macros

#define VAR_SIZE   64
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int _while_exec (struct ast_channel *chan, const char *data, int end)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int find_matching_endwhile (struct ast_channel *chan)
 
static struct ast_extenfind_matching_priority (struct ast_context *c, const char *exten, int priority, const char *callerid)
 
static const char * get_index (struct ast_channel *chan, const char *prefix, int idx)
 
static int load_module (void)
 
static int unload_module (void)
 
static int while_continue_exec (struct ast_channel *chan, const char *data)
 
static int while_end_exec (struct ast_channel *chan, const char *data)
 
static int while_exit_exec (struct ast_channel *chan, const char *data)
 
static int while_start_exec (struct ast_channel *chan, const char *data)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "While Loops and Conditional Execution" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static char * continue_app = "ContinueWhile"
 
static char * exit_app = "ExitWhile"
 
static char * start_app = "While"
 
static char * stop_app = "EndWhile"
 

Detailed Description

While Loop Implementation.

Author
Anthony Minessale anthm.nosp@m.ct@y.nosp@m.ahoo..nosp@m.com

Definition in file app_while.c.

Macro Definition Documentation

◆ VAR_SIZE

#define VAR_SIZE   64

Definition at line 105 of file app_while.c.

Referenced by _while_exec(), and get_index().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 362 of file app_while.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 362 of file app_while.c.

◆ _while_exec()

static int _while_exec ( struct ast_channel chan,
const char *  data,
int  end 
)
static

Definition at line 197 of file app_while.c.

References ast_alloca, ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_priority(), ast_channel_priority_set(), ast_channel_unlock, ast_log, ast_parseable_goto(), ast_strdupa, ast_verb, ast_waitfordigit(), find_matching_endwhile(), get_index(), ast_exten::label, LOG_WARNING, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_checkcondition(), prefix, and VAR_SIZE.

Referenced by while_end_exec(), while_exit_exec(), and while_start_exec().

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 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
static const char * get_index(struct ast_channel *chan, const char *prefix, int idx)
Definition: app_while.c:108
#define LOG_WARNING
Definition: logger.h:274
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8321
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
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.
#define ast_log
Definition: astobj2.c:42
#define VAR_SIZE
Definition: app_while.c:105
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8859
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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
const char * ast_channel_context(const struct ast_channel *chan)
static int find_matching_endwhile(struct ast_channel *chan)
Definition: app_while.c:152
void ast_channel_priority_set(struct ast_channel *chan, int value)
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 362 of file app_while.c.

◆ find_matching_endwhile()

static int find_matching_endwhile ( struct ast_channel chan)
static

Definition at line 152 of file app_while.c.

References ast_channel_caller(), ast_channel_context(), ast_channel_exten(), ast_channel_priority(), ast_get_context_name(), ast_get_extension_app(), ast_log, ast_rdlock_context(), ast_rdlock_contexts(), ast_unlock_context(), ast_unlock_contexts(), ast_walk_contexts(), c, find_matching_priority(), LOG_ERROR, NULL, and S_COR.

Referenced by _while_exec().

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 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
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
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8596
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
int ast_channel_priority(const struct ast_channel *chan)
Number structure.
Definition: app_followme.c:154
#define ast_log
Definition: astobj2.c:42
#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
const char * ast_channel_exten(const struct ast_channel *chan)
#define LOG_ERROR
Definition: logger.h:285
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
const char * ast_channel_context(const struct ast_channel *chan)
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
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition: pbx.c:8525

◆ find_matching_priority()

static struct ast_exten* find_matching_priority ( struct ast_context c,
const char *  exten,
int  priority,
const char *  callerid 
)
static

Definition at line 115 of file app_while.c.

References ast_context_includes_count(), ast_context_includes_get(), ast_extension_match(), ast_get_context_name(), ast_get_extension_cidmatch(), ast_get_extension_matchcid(), ast_get_extension_name(), ast_get_extension_priority(), ast_get_include_name(), ast_walk_context_extensions(), ast_walk_contexts(), ast_walk_extension_priorities(), and NULL.

Referenced by find_matching_endwhile().

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 }
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8558
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
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: conf2ael.c:618
#define NULL
Definition: resample.c:96
static int priority
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8591
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8697
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
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
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
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8586
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

◆ get_index()

static const char* get_index ( struct ast_channel chan,
const char *  prefix,
int  idx 
)
static

Definition at line 108 of file app_while.c.

References pbx_builtin_getvar_helper(), and VAR_SIZE.

Referenced by _while_exec(), and while_continue_exec().

108  {
109  char varname[VAR_SIZE];
110 
111  snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);
112  return pbx_builtin_getvar_helper(chan, varname);
113 }
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define VAR_SIZE
Definition: app_while.c:105
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ load_module()

static int load_module ( void  )
static

Definition at line 350 of file app_while.c.

References ast_register_application_xml, continue_app, exit_app, start_app, stop_app, while_continue_exec(), while_end_exec(), while_exit_exec(), and while_start_exec().

351 {
352  int res;
353 
358 
359  return res;
360 }
static char * exit_app
Definition: app_while.c:102
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
static char * stop_app
Definition: app_while.c:101
static int while_continue_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:319
static int while_exit_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:315
static int while_end_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:311
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
static char * start_app
Definition: app_while.c:100

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 338 of file app_while.c.

References ast_unregister_application(), continue_app, exit_app, start_app, and stop_app.

339 {
340  int res;
341 
346 
347  return res;
348 }
static char * exit_app
Definition: app_while.c:102
static char * continue_app
Definition: app_while.c:103
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static char * stop_app
Definition: app_while.c:101
static char * start_app
Definition: app_while.c:100

◆ while_continue_exec()

static int while_continue_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 319 of file app_while.c.

References ast_parseable_goto(), get_index(), NULL, prefix, and tmp().

Referenced by load_module().

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 }
static const char * get_index(struct ast_channel *chan, const char *prefix, int idx)
Definition: app_while.c:108
static int tmp()
Definition: bt_open.c:389
#define NULL
Definition: resample.c:96
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8859
static char prefix[MAX_PREFIX]
Definition: http.c:141

◆ while_end_exec()

static int while_end_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 311 of file app_while.c.

References _while_exec().

Referenced by load_module().

311  {
312  return _while_exec(chan, data, 1);
313 }
static int _while_exec(struct ast_channel *chan, const char *data, int end)
Definition: app_while.c:197

◆ while_exit_exec()

static int while_exit_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 315 of file app_while.c.

References _while_exec().

Referenced by load_module().

315  {
316  return _while_exec(chan, data, 2);
317 }
static int _while_exec(struct ast_channel *chan, const char *data, int end)
Definition: app_while.c:197

◆ while_start_exec()

static int while_start_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 307 of file app_while.c.

References _while_exec().

Referenced by load_module().

307  {
308  return _while_exec(chan, data, 0);
309 }
static int _while_exec(struct ast_channel *chan, const char *data, int end)
Definition: app_while.c:197

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "While Loops and Conditional Execution" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 362 of file app_while.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 362 of file app_while.c.

◆ continue_app

char* continue_app = "ContinueWhile"
static

Definition at line 103 of file app_while.c.

Referenced by load_module(), and unload_module().

◆ exit_app

char* exit_app = "ExitWhile"
static

Definition at line 102 of file app_while.c.

Referenced by load_module(), and unload_module().

◆ start_app

char* start_app = "While"
static

Definition at line 100 of file app_while.c.

Referenced by load_module(), and unload_module().

◆ stop_app

char* stop_app = "EndWhile"
static

Definition at line 101 of file app_while.c.

Referenced by load_module(), and unload_module().