Sat Nov 25 00:45:44 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 392 of file app_macro.c.

00393 {
00394    return tdesc;
00395 }

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

References ASTERISK_GPL_KEY.

00405 {
00406    return ASTERISK_GPL_KEY;
00407 }

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

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

00382 {
00383    int res;
00384 
00385    res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip);
00386    res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip);
00387    res |= ast_register_application(app, macro_exec, synopsis, descrip);
00388 
00389    return res;
00390 }

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

Definition at line 96 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_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().

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

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

Definition at line 363 of file app_macro.c.

References MACRO_EXIT_RESULT.

Referenced by load_module().

00364 {
00365    return MACRO_EXIT_RESULT;
00366 }

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

Definition at line 329 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().

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

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

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

00369 {
00370    int res;
00371 
00372    res = ast_unregister_application(if_app);
00373    res |= ast_unregister_application(exit_app);
00374    res |= ast_unregister_application(app);
00375 
00376    STANDARD_HANGUP_LOCALUSERS;
00377 
00378    return res;
00379 }

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

References STANDARD_USECOUNT.

00398 {
00399    int res;
00400    STANDARD_USECOUNT(res);
00401    return res;
00402 }


Variable Documentation

char* app = "Macro" [static]
 

Definition at line 84 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 86 of file app_macro.c.

char* exit_descrip [static]
 

Definition at line 77 of file app_macro.c.

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

Definition at line 90 of file app_macro.c.

char* if_app = "MacroIf" [static]
 

Definition at line 85 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 71 of file app_macro.c.

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

Definition at line 89 of file app_macro.c.

LOCAL_USER_DECL
 

Definition at line 94 of file app_macro.c.

STANDARD_LOCAL_USER
 

Definition at line 92 of file app_macro.c.

char* synopsis = "Macro Implementation" [static]
 

Definition at line 88 of file app_macro.c.

char* tdesc = "Extension Macros" [static]
 

Definition at line 51 of file app_macro.c.


Generated on Sat Nov 25 00:45:44 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6