#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" |
Definition in file app_macro.c.
|
Definition at line 49 of file app_macro.c. Referenced by macro_exec(), and macro_exit_exec(). |
|
Definition at line 46 of file app_macro.c. Referenced by agi_exec_full(), agi_handle_command(), macro_exec(), and parse_args(). |
|
Provides a description of the module.
Definition at line 392 of file app_macro.c. 00393 { 00394 return tdesc; 00395 }
|
|
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 404 of file app_macro.c. References ASTERISK_GPL_KEY. 00405 { 00406 return ASTERISK_GPL_KEY; 00407 }
|
|
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 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 }
|
|
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 }
|
|
Definition at line 363 of file app_macro.c. References MACRO_EXIT_RESULT. Referenced by load_module(). 00364 { 00365 return MACRO_EXIT_RESULT; 00366 }
|
|
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 }
|
|
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 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 }
|
|
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 397 of file app_macro.c. References STANDARD_USECOUNT. 00398 { 00399 int res; 00400 STANDARD_USECOUNT(res); 00401 return res; 00402 }
|
|
Definition at line 84 of file app_macro.c. |
|
Definition at line 53 of file app_macro.c. |
|
Definition at line 86 of file app_macro.c. |
|
Definition at line 77 of file app_macro.c. |
|
Definition at line 90 of file app_macro.c. |
|
Definition at line 85 of file app_macro.c. |
|
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. |
|
Definition at line 89 of file app_macro.c. |
|
Definition at line 94 of file app_macro.c. |
|
Definition at line 92 of file app_macro.c. |
|
Definition at line 88 of file app_macro.c. |
|
Definition at line 51 of file app_macro.c. |