#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"
Include dependency graph for app_macro.c:
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" |
Definition in file app_macro.c.
#define MACRO_EXIT_RESULT 1024 |
#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().
char* description | ( | void | ) |
Provides a description of the 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; }
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.
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).
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.
Definition at line 391 of file app_macro.c.
References STANDARD_USECOUNT.
00392 { 00393 int res; 00394 STANDARD_USECOUNT(res); 00395 return res; 00396 }
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.
Definition at line 88 of file app_macro.c.
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.