Sat Sep 16 05:47:49 2006

Asterisk developer's documentation


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.
static int macro_exec (struct ast_channel *chan, void *data)
static int macro_exit_exec (struct ast_channel *chan, void *data)
static 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

static char * app = "Macro"
static char * descrip
static char * exit_app = "MacroExit"
static char * exit_descrip
static char * exit_synopsis = "Exit From Macro"
static char * if_app = "MacroIf"
static char * if_descrip
static char * if_synopsis = "Conditional Macro Implementation"
 LOCAL_USER_DECL
 STANDARD_LOCAL_USER
static char * synopsis = "Macro Implementation"
static 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(), and macro_exit_exec().

#define MAX_ARGS   80

Definition at line 46 of file app_macro.c.

Referenced by agi_exec_full(), agi_handle_command(), 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 386 of file app_macro.c.

00387 {
00388    return tdesc;
00389 }

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 398 of file app_macro.c.

References ASTERISK_GPL_KEY.

00399 {
00400    return ASTERISK_GPL_KEY;
00401 }

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 375 of file app_macro.c.

References ast_register_application(), macro_exec(), macro_exit_exec(), and macroif_exec().

00376 {
00377    int res;
00378 
00379    res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip);
00380    res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip);
00381    res |= ast_register_application(app, macro_exec, synopsis, descrip);
00382 
00383    return res;
00384 }

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

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

Definition at line 357 of file app_macro.c.

References MACRO_EXIT_RESULT.

Referenced by load_module().

00358 {
00359    return MACRO_EXIT_RESULT;
00360 }

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

Definition at line 323 of file app_macro.c.

References ast_log(), ast_strdupa, localuser::chan, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, macro_exec(), and pbx_checkcondition().

Referenced by load_module().

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

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 362 of file app_macro.c.

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

00363 {
00364    int res;
00365 
00366    res = ast_unregister_application(if_app);
00367    res |= ast_unregister_application(exit_app);
00368    res |= ast_unregister_application(app);
00369 
00370    STANDARD_HANGUP_LOCALUSERS;
00371 
00372    return res;
00373 }

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 391 of file app_macro.c.

References STANDARD_USECOUNT.

00392 {
00393    int res;
00394    STANDARD_USECOUNT(res);
00395    return res;
00396 }


Variable Documentation

char* app = "Macro" [static]

Definition at line 78 of file app_macro.c.

char* descrip [static]

Definition at line 53 of file app_macro.c.

char* exit_app = "MacroExit" [static]

Definition at line 80 of file app_macro.c.

char* exit_descrip [static]

Definition at line 71 of file app_macro.c.

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

Definition at line 84 of file app_macro.c.

char* if_app = "MacroIf" [static]

Definition at line 79 of file app_macro.c.

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.

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

Definition at line 83 of file app_macro.c.

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.

char* tdesc = "Extension Macros" [static]

Definition at line 51 of file app_macro.c.


Generated on Sat Sep 16 05:47:49 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7