Asterisk - The Open Source Telephony Project GIT-master-5782b03
Macros | Functions | Variables
app_if.c File Reference

If Branch Implementation. More...

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

Go to the source code of this file.

Macros

#define VAR_SIZE   64
 

Functions

 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "If Branch and Conditional Execution")
 
static int else_exec (struct ast_channel *chan, const char *data)
 
static int elseif_exec (struct ast_channel *chan, const char *data)
 
static int end_exec (struct ast_channel *chan, const char *data)
 
static int exit_exec (struct ast_channel *chan, const char *data)
 
static int find_matching_endif (struct ast_channel *chan, const char *otherapp)
 
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 if_exec (struct ast_channel *chan, const char *data)
 
static int if_helper (struct ast_channel *chan, const char *data, int end)
 
static int load_module (void)
 
static int unload_module (void)
 

Variables

static char * else_app = "Else"
 
static char * elseif_app = "ElseIf"
 
static char * exit_app = "ExitIf"
 
static char * if_app = "If"
 
static char * stop_app = "EndIf"
 

Detailed Description

If Branch Implementation.

Author
Naveen Albert aster.nosp@m.isk@.nosp@m.phrea.nosp@m.knet.nosp@m..org

Definition in file app_if.c.

Macro Definition Documentation

◆ VAR_SIZE

#define VAR_SIZE   64

Definition at line 136 of file app_if.c.

Function Documentation

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"If Branch and Conditional Execution"   
)

◆ else_exec()

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

Definition at line 356 of file app_if.c.

356 {
357 return if_helper(chan, data, 3);
358}
static int if_helper(struct ast_channel *chan, const char *data, int end)
Definition: app_if.c:233

References ast_exten::data, and if_helper().

Referenced by load_module().

◆ elseif_exec()

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

Definition at line 348 of file app_if.c.

348 {
349 return if_helper(chan, data, 1);
350}

References ast_exten::data, and if_helper().

Referenced by load_module().

◆ end_exec()

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

Definition at line 352 of file app_if.c.

352 {
353 return if_helper(chan, data, 2);
354}

References ast_exten::data, and if_helper().

Referenced by load_module().

◆ exit_exec()

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

Definition at line 360 of file app_if.c.

360 {
361 return if_helper(chan, data, 4);
362}

References ast_exten::data, and if_helper().

Referenced by load_module().

◆ find_matching_endif()

static int find_matching_endif ( struct ast_channel chan,
const char *  otherapp 
)
static

Definition at line 183 of file app_if.c.

184{
185 struct ast_context *c;
186 int res = -1;
187
188 if (ast_rdlock_contexts()) {
189 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
190 return -1;
191 }
192
194 struct ast_exten *e;
195
196 if (!ast_rdlock_context(c)) {
197 if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
198 /* This is the matching context we want */
199
200 int cur_priority = ast_channel_priority(chan) + 1, level = 1;
201
202 for (e = find_matching_priority(c, ast_channel_exten(chan), cur_priority,
203 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
204 e;
205 e = find_matching_priority(c, ast_channel_exten(chan), ++cur_priority,
206 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
207
208 if (!strcasecmp(ast_get_extension_app(e), "IF")) {
209 level++;
210 } else if (!strcasecmp(ast_get_extension_app(e), "ENDIF")) {
211 level--;
212 }
213
214 if (!otherapp && level == 0) {
215 res = cur_priority;
216 break;
217 } else if (otherapp && level == 1 && !strcasecmp(ast_get_extension_app(e), otherapp)) {
218 res = cur_priority;
219 break;
220 }
221 }
222 }
224 if (res > 0) {
225 break;
226 }
227 }
228 }
230 return res;
231}
static struct ast_exten * find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
Definition: app_if.c:146
#define ast_log
Definition: astobj2.c:42
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)
const char * ast_channel_exten(const struct ast_channel *chan)
#define LOG_ERROR
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4024
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8557
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8491
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.
Definition: pbx.c:8468
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8473
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
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
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 if_helper().

◆ 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 146 of file app_if.c.

147{
148 struct ast_exten *e;
149 struct ast_context *c2;
150 int idx;
151
154 int needmatch = ast_get_extension_matchcid(e);
155 if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
156 (!needmatch)) {
157 /* This is the matching extension we want */
158 struct ast_exten *p;
161 continue;
162 return p;
163 }
164 }
165 }
166 }
167
168 /* No match; run through includes */
169 for (idx = 0; idx < ast_context_includes_count(c); idx++) {
170 const struct ast_include *i = ast_context_includes_get(c, idx);
171
172 for (c2 = ast_walk_contexts(NULL); c2; c2 = ast_walk_contexts(c2)) {
173 if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
174 e = find_matching_priority(c2, exten, priority, callerid);
175 if (e)
176 return e;
177 }
178 }
179 }
180 return NULL;
181}
static int priority
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_cidmatch(struct ast_exten *e)
Definition: pbx.c:8552
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:4061
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
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 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
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, find_matching_priority(), NULL, and priority.

Referenced by find_matching_endif(), and find_matching_priority().

◆ get_index()

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

Definition at line 138 of file app_if.c.

139{
140 char varname[VAR_SIZE];
141
142 snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);
143 return pbx_builtin_getvar_helper(chan, varname);
144}
#define VAR_SIZE
Definition: app_if.c:136
static char prefix[MAX_PREFIX]
Definition: http.c:144
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.

References pbx_builtin_getvar_helper(), prefix, and VAR_SIZE.

Referenced by if_helper().

◆ if_exec()

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

Definition at line 344 of file app_if.c.

344 {
345 return if_helper(chan, data, 0);
346}

References ast_exten::data, and if_helper().

Referenced by load_module().

◆ if_helper()

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

Definition at line 233 of file app_if.c.

234{
235 int res = 0;
236 const char *if_pri = NULL;
237 char *my_name = NULL;
238 const char *label = NULL;
239 char varname[VAR_SIZE + 3]; /* + IF_ */
240 char end_varname[sizeof(varname) + 4]; /* + END_ + sizeof(varname) */
241 const char *prefix = "IF";
242 size_t size = 0;
243 int used_index_i = -1, x = 0;
244 char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
245
246 if (!chan) {
247 return -1;
248 }
249
250 for (x = 0 ;; x++) {
251 if (get_index(chan, prefix, x)) {
252 used_index_i = x;
253 } else {
254 break;
255 }
256 }
257
258 snprintf(used_index, sizeof(used_index), "%d", used_index_i);
259 snprintf(new_index, sizeof(new_index), "%d", used_index_i + 1);
260
261 size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
262 my_name = ast_alloca(size);
263 memset(my_name, 0, size);
264 snprintf(my_name, size, "%s_%s_%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
265
266 ast_channel_lock(chan);
267 if (end > 1) {
268 label = used_index;
269 } else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
270 label = new_index;
271 pbx_builtin_setvar_helper(chan, my_name, label);
272 }
273 snprintf(varname, sizeof(varname), "%s_%s", prefix, label);
274 if ((if_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
275 if_pri = ast_strdupa(if_pri);
276 snprintf(end_varname,sizeof(end_varname),"END_%s",varname);
277 }
278 ast_channel_unlock(chan);
279
280 if ((end <= 1 && !pbx_checkcondition(ast_strdupa(data))) || (end > 1)) {
281 /* Condition Met (clean up helper vars) */
282 const char *goto_str;
283 int pri, endifpri;
284 pbx_builtin_setvar_helper(chan, varname, NULL);
285 pbx_builtin_setvar_helper(chan, my_name, NULL);
286 snprintf(end_varname,sizeof(end_varname),"END_%s",varname);
287 ast_channel_lock(chan);
288 /* For EndIf, simply go to the next priority.
289 * We do not add 1 to ast_channel_priority because the dialplan will
290 * auto-increment the priority when we return, so just keep the priority as is.
291 * For ExitIf or false If() condition, we need to find the end of the current
292 * If branch (at same indentation) and branch there. */
293 endifpri = end == 2 ? ast_channel_priority(chan) : find_matching_endif(chan, NULL);
294 if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
295 ast_parseable_goto(chan, goto_str);
296 pbx_builtin_setvar_helper(chan, end_varname, NULL);
297 } else if (end <= 1 && (pri = find_matching_endif(chan, "ElseIf")) > 0 && pri < endifpri) {
298 pri--; /* back up a priority, since it returned the priority after the ElseIf */
299 /* If is false, and ElseIf exists, so jump to ElseIf */
300 ast_verb(3, "Taking conditional false branch, jumping to priority %d\n", pri);
301 ast_channel_priority_set(chan, pri);
302 } else if (end <= 1 && (pri = find_matching_endif(chan, "Else")) > 0 && pri < endifpri) {
303 /* don't need to back up a priority, because we don't actually need to execute Else, just jump to the priority after. Directly executing Else will exit the conditional. */
304 /* If is false, and Else exists, so jump to Else */
305 ast_verb(3, "Taking absolute false branch, jumping to priority %d\n", pri);
306 ast_channel_priority_set(chan, pri);
307 } else {
308 pri = endifpri;
309 if (pri > 0) {
310 ast_verb(3, "Exiting conditional, jumping to priority %d\n", pri);
311 ast_channel_priority_set(chan, pri);
312 } else if (end == 4) { /* Condition added because of end > 0 instead of end == 4 */
313 ast_log(LOG_WARNING, "Couldn't find matching EndIf? (If at %s@%s priority %d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
314 }
315 }
316 ast_channel_unlock(chan);
317 return res;
318 }
319
320 if (end <= 1 && !if_pri) {
321 char *goto_str;
322 size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
323 goto_str = ast_alloca(size);
324 memset(goto_str, 0, size);
325 snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
326 pbx_builtin_setvar_helper(chan, varname, goto_str);
327 } else if (end > 1 && if_pri) {
328 /* END of branch */
329 snprintf(end_varname, sizeof(end_varname), "END_%s", varname);
330 if (!pbx_builtin_getvar_helper(chan, end_varname)) {
331 char *goto_str;
332 size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
333 goto_str = ast_alloca(size);
334 memset(goto_str, 0, size);
335 snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan)+1);
336 pbx_builtin_setvar_helper(chan, end_varname, goto_str);
337 }
338 ast_parseable_goto(chan, if_pri);
339 }
340
341 return res;
342}
static const char * get_index(struct ast_channel *chan, const char *prefix, int idx)
Definition: app_if.c:138
static int find_matching_endif(struct ast_channel *chan, const char *otherapp)
Definition: app_if.c:183
#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_channel_lock(chan)
Definition: channel.h:2968
void ast_channel_priority_set(struct ast_channel *chan, int value)
#define ast_channel_unlock(chan)
Definition: channel.h:2969
char * end
Definition: eagi_proxy.c:73
#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.
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8282
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8866

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_exten::data, end, find_matching_endif(), get_index(), ast_exten::label, LOG_WARNING, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_checkcondition(), prefix, and VAR_SIZE.

Referenced by else_exec(), elseif_exec(), end_exec(), exit_exec(), and if_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 377 of file app_if.c.

378{
379 int res;
380
386
387 return res;
388}
static char * else_app
Definition: app_if.c:132
static int if_exec(struct ast_channel *chan, const char *data)
Definition: app_if.c:344
static char * stop_app
Definition: app_if.c:133
static char * if_app
Definition: app_if.c:130
static char * exit_app
Definition: app_if.c:134
static int elseif_exec(struct ast_channel *chan, const char *data)
Definition: app_if.c:348
static char * elseif_app
Definition: app_if.c:131
static int end_exec(struct ast_channel *chan, const char *data)
Definition: app_if.c:352
static int else_exec(struct ast_channel *chan, const char *data)
Definition: app_if.c:356
static int exit_exec(struct ast_channel *chan, const char *data)
Definition: app_if.c:360
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640

References ast_register_application_xml, else_app, else_exec(), elseif_app, elseif_exec(), end_exec(), exit_app, exit_exec(), if_app, if_exec(), and stop_app.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 364 of file app_if.c.

365{
366 int res;
367
373
374 return res;
375}
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References ast_unregister_application(), else_app, elseif_app, exit_app, if_app, and stop_app.

Variable Documentation

◆ else_app

char* else_app = "Else"
static

Definition at line 132 of file app_if.c.

Referenced by load_module(), and unload_module().

◆ elseif_app

char* elseif_app = "ElseIf"
static

Definition at line 131 of file app_if.c.

Referenced by load_module(), and unload_module().

◆ exit_app

char* exit_app = "ExitIf"
static

Definition at line 134 of file app_if.c.

Referenced by load_module(), and unload_module().

◆ if_app

char* if_app = "If"
static

Definition at line 130 of file app_if.c.

Referenced by load_module(), and unload_module().

◆ stop_app

char* stop_app = "EndIf"
static

Definition at line 133 of file app_if.c.

Referenced by load_module(), and unload_module().