Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Data Structures | Functions | Variables
app_stack.c File Reference

Stack applications Gosub, Return, etc. More...

#include "asterisk.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/channel.h"
#include "asterisk/agi.h"
#include "asterisk/stasis_channels.h"
Include dependency graph for app_stack.c:

Go to the source code of this file.

Data Structures

struct  gosub_stack_frame
 
struct  gosub_stack_list
 

Functions

static const char * expand_gosub_args (struct ast_channel *chan, const char *args)
 
static int frame_set_var (struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
 
static struct gosub_stack_framegosub_allocate_frame (const char *context, const char *extension, int priority, int in_subroutine, unsigned char arguments)
 
static int gosub_exec (struct ast_channel *chan, const char *data)
 
static void gosub_free (void *data)
 
static void gosub_release_frame (struct ast_channel *chan, struct gosub_stack_frame *frame)
 
static int pop_exec (struct ast_channel *chan, const char *data)
 
static int return_exec (struct ast_channel *chan, const char *data)
 

Variables

static const char app_gosub [] = "Gosub"
 
static const char app_gosubif [] = "GosubIf"
 
static const char app_pop [] = "StackPop"
 
static const char app_return [] = "Return"
 
static const struct ast_datastore_info stack_info
 

Detailed Description

Stack applications Gosub, Return, etc.

Author
Tilghman Lesher app_s.nosp@m.tack.nosp@m._v003.nosp@m.@the.nosp@m.-tilg.nosp@m.hman.nosp@m..com

Definition in file app_stack.c.

Function Documentation

◆ expand_gosub_args()

static const char* expand_gosub_args ( struct ast_channel chan,
const char *  args 
)
static

Definition at line 450 of file app_stack.c.

451 {
452  int len;
453  char *parse;
454  char *label;
455  char *new_args;
456  const char *context;
457  const char *exten;
458  const char *pri;
459 
460  /* Separate the context,exten,pri from the optional routine arguments. */
462  label = strsep(&parse, "(");
463  if (parse) {
464  char *endparen;
465 
466  endparen = strrchr(parse, ')');
467  if (endparen) {
468  *endparen = '\0';
469  } else {
470  ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", args);
471  }
472  }
473 
474  /* Split context,exten,pri */
475  context = strsep(&label, ",");
476  exten = strsep(&label, ",");
477  pri = strsep(&label, ",");
478  if (!exten) {
479  /* Only a priority in this one */
480  pri = context;
481  exten = NULL;
482  context = NULL;
483  } else if (!pri) {
484  /* Only an extension and priority in this one */
485  pri = exten;
486  exten = context;
487  context = NULL;
488  }
489 
490  ast_channel_lock(chan);
491  if (ast_strlen_zero(exten)) {
492  exten = ast_channel_exten(chan);
493  }
494  if (ast_strlen_zero(context)) {
496  }
497  len = strlen(context) + strlen(exten) + strlen(pri) + 3;
498  if (!ast_strlen_zero(parse)) {
499  len += 2 + strlen(parse);
500  }
501  new_args = ast_malloc(len);
502  if (new_args) {
503  if (ast_strlen_zero(parse)) {
504  snprintf(new_args, len, "%s,%s,%s", context, exten, pri);
505  } else {
506  snprintf(new_args, len, "%s,%s,%s(%s)", context, exten, pri, parse);
507  }
508  }
509  ast_channel_unlock(chan);
510 
511  ast_debug(4, "Gosub args:%s new_args:%s\n", args, new_args ? new_args : "");
512 
513  return new_args;
514 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
#define ast_channel_lock(chan)
Definition: channel.h:2922
const char * ast_channel_context(const struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * strsep(char **str, const char *delims)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
const char * args

References args, ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_log, ast_malloc, ast_strdupa, ast_strlen_zero(), context, exten, len(), LOG_WARNING, NULL, parse(), and strsep().

◆ frame_set_var()

static int frame_set_var ( struct ast_channel chan,
struct gosub_stack_frame frame,
const char *  var,
const char *  value 
)
static

Definition at line 260 of file app_stack.c.

261 {
262  struct ast_var_t *variables;
263  int found = 0;
264  int len;
265  RAII_VAR(char *, local_buffer, NULL, ast_free);
266 
267  /* Does this variable already exist? */
268  AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
269  if (!strcmp(var, ast_var_name(variables))) {
270  found = 1;
271  break;
272  }
273  }
274 
275  if (!found) {
276  if ((variables = ast_var_assign(var, ""))) {
277  AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
278  }
280  } else {
282  }
283 
284  len = 8 + strlen(var); /* LOCAL() + var */
285  local_buffer = ast_malloc(len);
286  if (!local_buffer) {
287  return 0;
288  }
289  sprintf(local_buffer, "LOCAL(%s)", var);
290  ast_channel_publish_varset(chan, local_buffer, value);
291  return 0;
292 }
#define var
Definition: ast_expr2f.c:614
#define ast_free(a)
Definition: astmm.h:180
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define ast_var_assign(name, value)
Definition: chanvars.h:40
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_publish_varset for a channel.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
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.
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value.
struct ast_var_t::@239 entries
struct varshead varshead
Definition: app_stack.c:248
int value
Definition: syslog.c:37
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:936

References ast_channel_publish_varset(), ast_free, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_malloc, ast_var_assign, ast_var_name(), ast_var_t::entries, len(), NULL, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), RAII_VAR, value, var, and gosub_stack_frame::varshead.

Referenced by gosub_exec().

◆ gosub_allocate_frame()

static struct gosub_stack_frame* gosub_allocate_frame ( const char *  context,
const char *  extension,
int  priority,
int  in_subroutine,
unsigned char  arguments 
)
static

Definition at line 313 of file app_stack.c.

314 {
315  struct gosub_stack_frame *new = NULL;
316  int len_extension = strlen(extension) + 1;
317  int len_context = strlen(context) + 1;
318 
319  if ((new = ast_calloc(1, sizeof(*new) + len_extension + len_context))) {
320  AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
321  ast_copy_string(new->extension, extension, len_extension);
322  new->context = new->extension + len_extension;
323  ast_copy_string(new->context, context, len_context);
324  new->priority = priority;
325  new->in_subroutine = in_subroutine ? 1 : 0;
326  new->arguments = arguments;
327  }
328  return new;
329 }
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static int priority
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
structure to hold extensions
unsigned char arguments
Definition: app_stack.c:247
unsigned int in_subroutine
Definition: app_stack.c:253

References gosub_stack_frame::arguments, ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, context, gosub_stack_frame::in_subroutine, NULL, and priority.

Referenced by gosub_exec().

◆ gosub_exec()

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

◆ gosub_free()

static void gosub_free ( void *  data)
static

Definition at line 331 of file app_stack.c.

332 {
333  struct gosub_stack_list *oldlist = data;
334  struct gosub_stack_frame *oldframe;
335 
336  AST_LIST_LOCK(oldlist);
337  while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
338  gosub_release_frame(NULL, oldframe);
339  }
340  AST_LIST_UNLOCK(oldlist);
341  AST_LIST_HEAD_DESTROY(oldlist);
342  ast_free(oldlist);
343 }
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:294
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
struct gosub_stack_frame::@76 entries

References ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, gosub_stack_frame::entries, gosub_release_frame(), and NULL.

◆ gosub_release_frame()

static void gosub_release_frame ( struct ast_channel chan,
struct gosub_stack_frame frame 
)
static

Definition at line 294 of file app_stack.c.

295 {
296  struct ast_var_t *vardata;
297 
298  /* If chan is not defined, then we're calling it as part of gosub_free,
299  * and the channel variables will be deallocated anyway. Otherwise, we're
300  * just releasing a single frame, so we need to clean up the arguments for
301  * that frame, so that we re-expose the variables from the previous frame
302  * that were hidden by this one.
303  */
304  while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
305  if (chan)
307  ast_var_delete(vardata);
308  }
309 
310  ast_free(frame);
311 }
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2472

References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), ast_var_t::entries, NULL, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.

Referenced by gosub_free(), pop_exec(), and return_exec().

◆ pop_exec()

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

Definition at line 345 of file app_stack.c.

346 {
347  struct ast_datastore *stack_store;
348  struct gosub_stack_frame *oldframe;
349  struct gosub_stack_list *oldlist;
350  int res = 0;
351 
352  ast_channel_lock(chan);
353  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
354  ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
355  ast_channel_unlock(chan);
356  return 0;
357  }
358 
359  oldlist = stack_store->data;
360  AST_LIST_LOCK(oldlist);
361  oldframe = AST_LIST_FIRST(oldlist);
362  if (oldframe) {
363  if (oldframe->is_special) {
364  ast_debug(1, "%s attempted to pop special return location.\n", app_pop);
365 
366  /* Abort the special routine dialplan execution. Dialplan programming error. */
367  res = -1;
368  } else {
369  AST_LIST_REMOVE_HEAD(oldlist, entries);
370  gosub_release_frame(chan, oldframe);
371  }
372  } else {
373  ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
374  }
375  AST_LIST_UNLOCK(oldlist);
376  ast_channel_unlock(chan);
377  return res;
378 }
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
static const char app_pop[]
Definition: app_stack.c:235
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2398
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
unsigned int is_special
Definition: app_stack.c:251

References app_pop, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_debug, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_datastore::data, gosub_release_frame(), gosub_stack_frame::is_special, LOG_WARNING, NULL, and stack_info.

◆ return_exec()

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

Definition at line 380 of file app_stack.c.

381 {
382  struct ast_datastore *stack_store;
383  struct gosub_stack_frame *oldframe;
384  struct gosub_stack_list *oldlist;
385  const char *retval = data;
386  int res = 0;
387 
388  ast_channel_lock(chan);
389  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
390  ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
391  ast_channel_unlock(chan);
392  return -1;
393  }
394 
395  oldlist = stack_store->data;
396  AST_LIST_LOCK(oldlist);
397  oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
398  AST_LIST_UNLOCK(oldlist);
399 
400  if (!oldframe) {
401  ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
402  ast_channel_unlock(chan);
403  return -1;
404  }
405  if (oldframe->is_special) {
406  /* Exit from special routine. */
407  res = -1;
408  }
409 
410  /*
411  * We cannot use ast_explicit_goto() because we MUST restore
412  * what was there before. Channels that do not have a PBX may
413  * not have the context or exten set.
414  */
415  ast_channel_context_set(chan, oldframe->context);
416  ast_channel_exten_set(chan, oldframe->extension);
418  --oldframe->priority;
419  }
420  ast_channel_priority_set(chan, oldframe->priority);
422 
423  gosub_release_frame(chan, oldframe);
424 
425  /* Set a return value, if any */
426  pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
427  ast_channel_unlock(chan);
428  return res;
429 }
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
@ AST_FLAG_IN_AUTOLOOP
Definition: channel.h:997
@ AST_FLAG_SUBROUTINE_EXEC
Definition: channel.h:1058
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_channel_priority_set(struct ast_channel *chan, int value)
static ENTRY retval
Definition: hsearch.c:50
#define LOG_ERROR
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
char extension[0]
Definition: app_stack.c:255
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94

References ast_channel_context_set(), ast_channel_datastore_find(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_priority_set(), ast_channel_unlock, AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_set2_flag, ast_test_flag, gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::extension, gosub_release_frame(), gosub_stack_frame::in_subroutine, gosub_stack_frame::is_special, LOG_ERROR, NULL, pbx_builtin_setvar_helper(), gosub_stack_frame::priority, retval, S_OR, and stack_info.

Variable Documentation

◆ app_gosub

const char app_gosub[] = "Gosub"
static

Definition at line 232 of file app_stack.c.

Referenced by gosub_exec().

◆ app_gosubif

const char app_gosubif[] = "GosubIf"
static

Definition at line 233 of file app_stack.c.

◆ app_pop

const char app_pop[] = "StackPop"
static

Definition at line 235 of file app_stack.c.

Referenced by pop_exec().

◆ app_return

const char app_return[] = "Return"
static

Definition at line 234 of file app_stack.c.

◆ stack_info

const struct ast_datastore_info stack_info
static
Initial value:
= {
.type = "GOSUB",
.destroy = gosub_free,
}
static void gosub_free(void *data)
Definition: app_stack.c:331

Definition at line 237 of file app_stack.c.

Referenced by gosub_exec(), pop_exec(), and return_exec().