Thu Apr 28 2011 17:13:40

Asterisk developer's documentation


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.

Defines

#define VAR_SIZE   64

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int _while_exec (struct ast_channel *chan, void *data, int end)
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, void *data)
static int while_end_exec (struct ast_channel *chan, void *data)
static int while_exit_exec (struct ast_channel *chan, void *data)
static int while_start_exec (struct ast_channel *chan, void *data)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "While Loops and Conditional Execution" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static 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 <anthmct@yahoo.com>

Definition in file app_while.c.


Define Documentation

#define VAR_SIZE   64

Definition at line 103 of file app_while.c.

Referenced by _while_exec(), and get_index().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 354 of file app_while.c.

static void __unreg_module ( void  ) [static]

Definition at line 354 of file app_while.c.

static int _while_exec ( struct ast_channel chan,
void *  data,
int  end 
) [static]

Definition at line 189 of file app_while.c.

References ast_channel_lock, ast_channel_unlock, ast_log(), ast_parseable_goto(), ast_strdupa, ast_verb, ast_waitfordigit(), ast_channel::context, ast_channel::exten, find_matching_endwhile(), get_index(), ast_exten::label, LOG_WARNING, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_checkcondition(), prefix, ast_channel::priority, and VAR_SIZE.

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

{
   int res=0;
   const char *while_pri = NULL;
   char *my_name = NULL;
   const char *condition = NULL, *label = NULL;
   char varname[VAR_SIZE], end_varname[VAR_SIZE];
   const char *prefix = "WHILE";
   size_t size=0;
   int used_index_i = -1, x=0;
   char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";

   if (!chan) {
      /* huh ? */
      return -1;
   }

#if 0
   /* dont want run away loops if the chan isn't even up
      this is up for debate since it slows things down a tad ......

      Debate is over... this prevents While/EndWhile from working
      within the "h" extension.  Not good.
   */
   if (ast_waitfordigit(chan,1) < 0)
      return -1;
#endif

   for (x=0;;x++) {
      if (get_index(chan, prefix, x)) {
         used_index_i = x;
      } else 
         break;
   }
   
   snprintf(used_index, VAR_SIZE, "%d", used_index_i);
   snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
   
   if (!end)
      condition = ast_strdupa(data);

   size = strlen(chan->context) + strlen(chan->exten) + 32;
   my_name = alloca(size);
   memset(my_name, 0, size);
   snprintf(my_name, size, "%s_%s_%d", chan->context, chan->exten, chan->priority);
   
   ast_channel_lock(chan);
   if (end) {
      label = used_index;
   } else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
      label = new_index;
      pbx_builtin_setvar_helper(chan, my_name, label);
   }
   snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
   if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
      while_pri = ast_strdupa(while_pri);
      snprintf(end_varname,VAR_SIZE,"END_%s",varname);
   }
   ast_channel_unlock(chan);
   

   if ((!end && !pbx_checkcondition(condition)) || (end == 2)) {
      /* Condition Met (clean up helper vars) */
      const char *goto_str;
      pbx_builtin_setvar_helper(chan, varname, NULL);
      pbx_builtin_setvar_helper(chan, my_name, NULL);
      snprintf(end_varname,VAR_SIZE,"END_%s",varname);
      ast_channel_lock(chan);
      if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
         ast_parseable_goto(chan, goto_str);
         pbx_builtin_setvar_helper(chan, end_varname, NULL);
      } else {
         int pri = find_matching_endwhile(chan);
         if (pri > 0) {
            ast_verb(3, "Jumping to priority %d\n", pri);
            chan->priority = pri;
         } else {
            ast_log(LOG_WARNING, "Couldn't find matching EndWhile? (While at %s@%s priority %d)\n", chan->context, chan->exten, chan->priority);
         }
      }
      ast_channel_unlock(chan);
      return res;
   }

   if (!end && !while_pri) {
      char *goto_str;
      size = strlen(chan->context) + strlen(chan->exten) + 32;
      goto_str = alloca(size);
      memset(goto_str, 0, size);
      snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority);
      pbx_builtin_setvar_helper(chan, varname, goto_str);
   }

   else if (end && while_pri) {
      /* END of loop */
      snprintf(end_varname, VAR_SIZE, "END_%s", varname);
      if (! pbx_builtin_getvar_helper(chan, end_varname)) {
         char *goto_str;
         size = strlen(chan->context) + strlen(chan->exten) + 32;
         goto_str = alloca(size);
         memset(goto_str, 0, size);
         snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority+1);
         pbx_builtin_setvar_helper(chan, end_varname, goto_str);
      }
      ast_parseable_goto(chan, while_pri);
   }

   return res;
}
static int find_matching_endwhile ( struct ast_channel chan) [static]

Definition at line 148 of file app_while.c.

References 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(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, find_matching_priority(), LOG_ERROR, and ast_channel::priority.

Referenced by _while_exec().

{
   struct ast_context *c;
   int res=-1;

   if (ast_rdlock_contexts()) {
      ast_log(LOG_ERROR, "Failed to lock contexts list\n");
      return -1;
   }

   for (c=ast_walk_contexts(NULL); c; c=ast_walk_contexts(c)) {
      struct ast_exten *e;

      if (!ast_rdlock_context(c)) {
         if (!strcmp(ast_get_context_name(c), chan->context)) {
            /* This is the matching context we want */
            int cur_priority = chan->priority + 1, level=1;

            for (e = find_matching_priority(c, chan->exten, cur_priority, chan->cid.cid_num); e; e = find_matching_priority(c, chan->exten, ++cur_priority, chan->cid.cid_num)) {
               if (!strcasecmp(ast_get_extension_app(e), "WHILE")) {
                  level++;
               } else if (!strcasecmp(ast_get_extension_app(e), "ENDWHILE")) {
                  level--;
               }

               if (level == 0) {
                  res = cur_priority;
                  break;
               }
            }
         }
         ast_unlock_context(c);
         if (res > 0) {
            break;
         }
      }
   }
   ast_unlock_contexts();
   return res;
}
static struct ast_exten* find_matching_priority ( struct ast_context c,
const char *  exten,
int  priority,
const char *  callerid 
) [static, read]

Definition at line 113 of file app_while.c.

References 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_context_includes(), ast_walk_contexts(), and ast_walk_extension_priorities().

Referenced by find_matching_endwhile().

{
   struct ast_exten *e;
   struct ast_include *i;
   struct ast_context *c2;

   for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
      if (ast_extension_match(ast_get_extension_name(e), exten)) {
         int needmatch = ast_get_extension_matchcid(e);
         if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
            (!needmatch)) {
            /* This is the matching extension we want */
            struct ast_exten *p;
            for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
               if (priority != ast_get_extension_priority(p))
                  continue;
               return p;
            }
         }
      }
   }

   /* No match; run through includes */
   for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
      for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
         if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
            e = find_matching_priority(c2, exten, priority, callerid);
            if (e)
               return e;
         }
      }
   }
   return NULL;
}
static const char* get_index ( struct ast_channel chan,
const char *  prefix,
int  idx 
) [static]

Definition at line 106 of file app_while.c.

References pbx_builtin_getvar_helper(), and VAR_SIZE.

Referenced by _while_exec(), and while_continue_exec().

                                                                                    {
   char varname[VAR_SIZE];

   snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);
   return pbx_builtin_getvar_helper(chan, varname);
}
static int unload_module ( void  ) [static]
static int while_continue_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 311 of file app_while.c.

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

Referenced by load_module().

{
   int x;
   const char *prefix = "WHILE", *while_pri=NULL;

   for (x = 0; ; x++) {
      const char *tmp = get_index(chan, prefix, x);
      if (tmp)
         while_pri = tmp;
      else
         break;
   }

   if (while_pri)
      ast_parseable_goto(chan, while_pri);

   return 0;
}
static int while_end_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 303 of file app_while.c.

References _while_exec().

Referenced by load_module().

                                                                {
   return _while_exec(chan, data, 1);
}
static int while_exit_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 307 of file app_while.c.

References _while_exec().

Referenced by load_module().

                                                                 {
   return _while_exec(chan, data, 2);
}
static int while_start_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 299 of file app_while.c.

References _while_exec().

Referenced by load_module().

                                                                  {
   return _while_exec(chan, data, 0);
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "While Loops and Conditional Execution" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 354 of file app_while.c.

Definition at line 354 of file app_while.c.

char* continue_app = "ContinueWhile" [static]

Definition at line 101 of file app_while.c.

char* exit_app = "ExitWhile" [static]

Definition at line 100 of file app_while.c.

char* start_app = "While" [static]

Definition at line 98 of file app_while.c.

char* stop_app = "EndWhile" [static]

Definition at line 99 of file app_while.c.