Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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 = AST_BUILDOPT_SUM, .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.

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.

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 }
static const char * get_index(struct ast_channel *chan, const char *prefix, int idx)
Definition: app_while.c:108
#define VAR_SIZE
Definition: app_while.c:105
static int find_matching_endwhile(struct ast_channel *chan)
Definition: app_while.c:152
#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
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3176
#define ast_channel_lock(chan)
Definition: channel.h:2922
const char * ast_channel_context(const struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
char * end
Definition: eagi_proxy.c:73
static char prefix[MAX_PREFIX]
Definition: http.c:144
#define ast_verb(level,...)
#define LOG_WARNING
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 * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int pbx_checkcondition(const char *condition)
Evaluate a condition.
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
#define NULL
Definition: resample.c:96

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(), ast_exten::data, end, 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().

◆ 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.

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 }
static struct ast_exten * find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
Definition: app_while.c:115
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define LOG_ERROR
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4025
const char * ast_get_extension_app(struct ast_exten *e)
int ast_unlock_context(struct ast_context *con)
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
int ast_rdlock_contexts(void)
Read locks the context list.
int ast_unlock_contexts(void)
Unlocks contexts.
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
#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
ast_context: An extension context - must remain in sync with fake_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
Number structure.
Definition: app_followme.c:154
static struct test_val 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().

◆ 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.

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 }
static int priority
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
int ast_get_extension_priority(struct ast_exten *exten)
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
int ast_get_extension_matchcid(struct ast_exten *e)
const char * ast_get_extension_name(struct ast_exten *exten)
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4062
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:4296
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: ael_main.c:427
int ast_context_includes_count(const struct ast_context *con)
const char * ast_get_extension_cidmatch(struct ast_exten *e)
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37

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(), c, exten, NULL, and priority.

Referenced by find_matching_endwhile().

◆ 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.

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 }

References pbx_builtin_getvar_helper(), prefix, and VAR_SIZE.

Referenced by _while_exec(), and while_continue_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 350 of file app_while.c.

351 {
352  int res;
353 
358 
359  return res;
360 }
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_start_exec(struct ast_channel *chan, const char *data)
Definition: app_while.c:307
static char * continue_app
Definition: app_while.c:103
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
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 338 of file app_while.c.

339 {
340  int res;
341 
346 
347  return res;
348 }
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

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

◆ 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.

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 int tmp()
Definition: bt_open.c:389

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

◆ 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.

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

References _while_exec(), and ast_exten::data.

◆ 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.

315  {
316  return _while_exec(chan, data, 2);
317 }

References _while_exec(), and ast_exten::data.

◆ 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.

307  {
308  return _while_exec(chan, data, 0);
309 }

References _while_exec(), and ast_exten::data.

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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 350 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 unload_module().

◆ exit_app

char* exit_app = "ExitWhile"
static

Definition at line 102 of file app_while.c.

Referenced by unload_module().

◆ start_app

char* start_app = "While"
static

Definition at line 100 of file app_while.c.

Referenced by unload_module().

◆ stop_app

char* stop_app = "EndWhile"
static

Definition at line 101 of file app_while.c.

Referenced by unload_module().