Mon Mar 20 08:25:46 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

app_macro.c File Reference

Dial plan macro Implementation. More...

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"

Go to the source code of this file.

Defines

#define MACRO_EXIT_RESULT   1024
#define MAX_ARGS   80

Functions

char * description (void)
 Provides a description of the module.
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
int macro_exec (struct ast_channel *chan, void *data)
int macro_exit_exec (struct ast_channel *chan, void *data)
int macroif_exec (struct ast_channel *chan, void *data)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

char * app = "Macro"
char * descrip
char * exit_app = "MacroExit"
char * exit_descrip
char * exit_synopsis = "Exit From Macro"
char * if_app = "MacroIf"
char * if_descrip
char * if_synopsis = "Conditional Macro Implementation"
 LOCAL_USER_DECL
 STANDARD_LOCAL_USER
char * synopsis = "Macro Implementation"
char * tdesc = "Extension Macros"


Detailed Description

Dial plan macro Implementation.

Definition in file app_macro.c.


Define Documentation

#define MACRO_EXIT_RESULT   1024
 

Definition at line 49 of file app_macro.c.

Referenced by macro_exec().

#define MAX_ARGS   80
 

Definition at line 46 of file app_macro.c.

Referenced by agi_exec_full(), macro_exec(), and parse_args().


Function Documentation

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 381 of file app_macro.c.

00382 {
00383    return tdesc;
00384 }

char* key void   ) 
 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 393 of file app_macro.c.

00394 {
00395    return ASTERISK_GPL_KEY;
00396 }

int load_module void   ) 
 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 370 of file app_macro.c.

References app, ast_register_application(), descrip, exit_app, exit_descrip, exit_synopsis, if_app, if_descrip, if_synopsis, macro_exec(), macro_exit_exec(), macroif_exec(), and synopsis.

00371 {
00372    int res;
00373 
00374    res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip);
00375    res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip);
00376    res |= ast_register_application(app, macro_exec, synopsis, descrip);
00377 
00378    return res;
00379 }

int macro_exec struct ast_channel chan,
void *  data
[static]
 

Definition at line 90 of file app_macro.c.

References ast_channel::_softhangup, ast_context_find(), ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, ast_log(), AST_PBX_KEEPALIVE, ast_set2_flag, ast_set_flag, ast_spawn_extension(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, free, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, LOG_ERROR, LOG_WARNING, MACRO_EXIT_RESULT, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, MAX_ARGS, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, strdup, strsep(), and VERBOSE_PREFIX_2.

Referenced by load_module(), and macroif_exec().

00091 {
00092    char *tmp;
00093    char *cur, *rest;
00094    char *macro;
00095    char fullmacro[80];
00096    char varname[80];
00097    char *oldargs[MAX_ARGS + 1] = { NULL, };
00098    int argc, x;
00099    int res=0;
00100    char oldexten[256]="";
00101    int oldpriority;
00102    char pc[80], depthc[12];
00103    char oldcontext[AST_MAX_CONTEXT] = "";
00104    char *offsets;
00105    int offset, depth;
00106    int setmacrocontext=0;
00107    int autoloopflag, dead = 0;
00108   
00109    char *save_macro_exten;
00110    char *save_macro_context;
00111    char *save_macro_priority;
00112    char *save_macro_offset;
00113    struct localuser *u;
00114  
00115    if (ast_strlen_zero(data)) {
00116       ast_log(LOG_WARNING, "Macro() requires arguments. See \"show application macro\" for help.\n");
00117       return -1;
00118    }
00119 
00120    LOCAL_USER_ADD(u);
00121 
00122    /* Count how many levels deep the rabbit hole goes */
00123    tmp = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH");
00124    if (tmp) {
00125       sscanf(tmp, "%d", &depth);
00126    } else {
00127       depth = 0;
00128    }
00129 
00130    if (depth >= 7) {
00131       ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
00132       LOCAL_USER_REMOVE(u);
00133       return 0;
00134    }
00135    snprintf(depthc, sizeof(depthc), "%d", depth + 1);
00136    pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
00137 
00138    tmp = ast_strdupa(data);
00139    rest = tmp;
00140    macro = strsep(&rest, "|");
00141    if (ast_strlen_zero(macro)) {
00142       ast_log(LOG_WARNING, "Invalid macro name specified\n");
00143       LOCAL_USER_REMOVE(u);
00144       return 0;
00145    }
00146    snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
00147    if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->cid.cid_num)) {
00148       if (!ast_context_find(fullmacro)) 
00149          ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
00150       else
00151          ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
00152       LOCAL_USER_REMOVE(u);
00153       return 0;
00154    }
00155    
00156    /* Save old info */
00157    oldpriority = chan->priority;
00158    ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
00159    ast_copy_string(oldcontext, chan->context, sizeof(oldcontext));
00160    if (ast_strlen_zero(chan->macrocontext)) {
00161       ast_copy_string(chan->macrocontext, chan->context, sizeof(chan->macrocontext));
00162       ast_copy_string(chan->macroexten, chan->exten, sizeof(chan->macroexten));
00163       chan->macropriority = chan->priority;
00164       setmacrocontext=1;
00165    }
00166    argc = 1;
00167    /* Save old macro variables */
00168    save_macro_exten = pbx_builtin_getvar_helper(chan, "MACRO_EXTEN");
00169    if (save_macro_exten) 
00170       save_macro_exten = strdup(save_macro_exten);
00171    pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
00172 
00173    save_macro_context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT");
00174    if (save_macro_context)
00175       save_macro_context = strdup(save_macro_context);
00176    pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
00177 
00178    save_macro_priority = pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY");
00179    if (save_macro_priority) 
00180       save_macro_priority = strdup(save_macro_priority);
00181    snprintf(pc, sizeof(pc), "%d", oldpriority);
00182    pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
00183   
00184    save_macro_offset = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET");
00185    if (save_macro_offset) 
00186       save_macro_offset = strdup(save_macro_offset);
00187    pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
00188 
00189    /* Setup environment for new run */
00190    chan->exten[0] = 's';
00191    chan->exten[1] = '\0';
00192    ast_copy_string(chan->context, fullmacro, sizeof(chan->context));
00193    chan->priority = 1;
00194 
00195    while((cur = strsep(&rest, "|")) && (argc < MAX_ARGS)) {
00196       /* Save copy of old arguments if we're overwriting some, otherwise
00197          let them pass through to the other macro */
00198       snprintf(varname, sizeof(varname), "ARG%d", argc);
00199       oldargs[argc] = pbx_builtin_getvar_helper(chan, varname);
00200       if (oldargs[argc])
00201          oldargs[argc] = strdup(oldargs[argc]);
00202       pbx_builtin_setvar_helper(chan, varname, cur);
00203       argc++;
00204    }
00205    autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
00206    ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
00207    while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
00208       /* Reset the macro depth, if it was changed in the last iteration */
00209       pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
00210       if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
00211          /* Something bad happened, or a hangup has been requested. */
00212          if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
00213             (res == '*') || (res == '#')) {
00214             /* Just return result as to the previous application as if it had been dialed */
00215             ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
00216             break;
00217          }
00218          switch(res) {
00219          case MACRO_EXIT_RESULT:
00220             res = 0;
00221             goto out;
00222          case AST_PBX_KEEPALIVE:
00223             if (option_debug)
00224                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE in macro %s on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
00225             else if (option_verbose > 1)
00226                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE in macro '%s' on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
00227             goto out;
00228             break;
00229          default:
00230             if (option_debug)
00231                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
00232             else if (option_verbose > 1)
00233                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
00234             dead = 1;
00235             goto out;
00236          }
00237       }
00238       if (strcasecmp(chan->context, fullmacro)) {
00239          if (option_verbose > 1)
00240             ast_verbose(VERBOSE_PREFIX_2 "Channel '%s' jumping out of macro '%s'\n", chan->name, macro);
00241          break;
00242       }
00243       /* don't stop executing extensions when we're in "h" */
00244       if (chan->_softhangup && strcasecmp(oldexten,"h")) {
00245          ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
00246             chan->exten, chan->priority);
00247          goto out;
00248       }
00249       chan->priority++;
00250    }
00251    out:
00252    /* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
00253    snprintf(depthc, sizeof(depthc), "%d", depth);
00254    if (!dead) {
00255       pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
00256 
00257       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
00258    }
00259 
00260    for (x = 1; x < argc; x++) {
00261       /* Restore old arguments and delete ours */
00262       snprintf(varname, sizeof(varname), "ARG%d", x);
00263       if (oldargs[x]) {
00264          if (!dead)
00265             pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
00266          free(oldargs[x]);
00267       } else if (!dead) {
00268          pbx_builtin_setvar_helper(chan, varname, NULL);
00269       }
00270    }
00271 
00272    /* Restore macro variables */
00273    if (!dead) {
00274       pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
00275       pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
00276       pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
00277    }
00278    if (save_macro_exten)
00279       free(save_macro_exten);
00280    if (save_macro_context)
00281       free(save_macro_context);
00282    if (save_macro_priority)
00283       free(save_macro_priority);
00284 
00285    if (!dead && setmacrocontext) {
00286       chan->macrocontext[0] = '\0';
00287       chan->macroexten[0] = '\0';
00288       chan->macropriority = 0;
00289    }
00290 
00291    if (!dead && !strcasecmp(chan->context, fullmacro)) {
00292       /* If we're leaving the macro normally, restore original information */
00293       chan->priority = oldpriority;
00294       ast_copy_string(chan->context, oldcontext, sizeof(chan->context));
00295       if (!(chan->_softhangup & AST_SOFTHANGUP_ASYNCGOTO)) {
00296          /* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
00297          ast_copy_string(chan->exten, oldexten, sizeof(chan->exten));
00298          if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
00299             /* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
00300                normally if there is any problem */
00301             if (sscanf(offsets, "%d", &offset) == 1) {
00302                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->cid.cid_num)) {
00303                   chan->priority += offset;
00304                }
00305             }
00306          }
00307       }
00308    }
00309 
00310    if (!dead)
00311       pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
00312    if (save_macro_offset)
00313       free(save_macro_offset);
00314    LOCAL_USER_REMOVE(u);
00315    return res;
00316 }

int macro_exit_exec struct ast_channel chan,
void *  data
[static]
 

Definition at line 352 of file app_macro.c.

Referenced by load_module().

00353 {
00354    return MACRO_EXIT_RESULT;
00355 }

int macroif_exec struct ast_channel chan,
void *  data
[static]
 

Definition at line 318 of file app_macro.c.

References ast_log(), ast_strdupa, ast_true(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, and macro_exec().

Referenced by load_module().

00319 {
00320    char *expr = NULL, *label_a = NULL, *label_b = NULL;
00321    int res = 0;
00322    struct localuser *u;
00323 
00324    LOCAL_USER_ADD(u);
00325 
00326    expr = ast_strdupa(data);
00327    if (!expr) {
00328       ast_log(LOG_ERROR, "Out of Memory!\n");
00329       LOCAL_USER_REMOVE(u);
00330       return -1;
00331    }
00332 
00333    if ((label_a = strchr(expr, '?'))) {
00334       *label_a = '\0';
00335       label_a++;
00336       if ((label_b = strchr(label_a, ':'))) {
00337          *label_b = '\0';
00338          label_b++;
00339       }
00340       if (ast_true(expr))
00341          macro_exec(chan, label_a);
00342       else if (label_b) 
00343          macro_exec(chan, label_b);
00344    } else
00345       ast_log(LOG_WARNING, "Invalid Syntax.\n");
00346 
00347    LOCAL_USER_REMOVE(u);
00348 
00349    return res;
00350 }

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 357 of file app_macro.c.

References app, ast_unregister_application(), exit_app, and if_app.

00358 {
00359    int res;
00360 
00361    res = ast_unregister_application(if_app);
00362    res |= ast_unregister_application(exit_app);
00363    res |= ast_unregister_application(app);
00364 
00365    STANDARD_HANGUP_LOCALUSERS;
00366 
00367    return res;
00368 }

int usecount void   ) 
 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 386 of file app_macro.c.

References STANDARD_USECOUNT.

00387 {
00388    int res;
00389    STANDARD_USECOUNT(res);
00390    return res;
00391 }


Variable Documentation

char* app = "Macro" [static]
 

Definition at line 78 of file app_macro.c.

Referenced by load_module(), and unload_module().

char* descrip [static]
 

Definition at line 53 of file app_macro.c.

Referenced by load_module().

char* exit_app = "MacroExit" [static]
 

Definition at line 80 of file app_macro.c.

Referenced by load_module(), and unload_module().

char* exit_descrip [static]
 

Definition at line 71 of file app_macro.c.

Referenced by load_module().

char* exit_synopsis = "Exit From Macro" [static]
 

Definition at line 84 of file app_macro.c.

Referenced by load_module().

char* if_app = "MacroIf" [static]
 

Definition at line 79 of file app_macro.c.

Referenced by load_module(), and unload_module().

char* if_descrip [static]
 

Initial value:

"  MacroIf(<expr>?macroname_a[|arg1][:macroname_b[|arg1]])\n"
"Executes macro defined in <macroname_a> if <expr> is true\n"
"(otherwise <macroname_b> if provided)\n"
"Arguments and return values as in application macro()\n"

Definition at line 65 of file app_macro.c.

Referenced by load_module().

char* if_synopsis = "Conditional Macro Implementation" [static]
 

Definition at line 83 of file app_macro.c.

Referenced by load_module().

LOCAL_USER_DECL
 

Definition at line 88 of file app_macro.c.

STANDARD_LOCAL_USER
 

Definition at line 86 of file app_macro.c.

char* synopsis = "Macro Implementation" [static]
 

Definition at line 82 of file app_macro.c.

Referenced by load_module().

char* tdesc = "Extension Macros" [static]
 

Definition at line 51 of file app_macro.c.


Generated on Mon Mar 20 08:25:46 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1