Wed Mar 4 19:57:58 2009

Asterisk developer's documentation


app_macro.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Dial plan macro Implementation
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  * 
00025  * \ingroup applications
00026  */
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 165317 $")
00031 
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <unistd.h>
00036 #include <sys/types.h>
00037 
00038 #include "asterisk/file.h"
00039 #include "asterisk/logger.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/options.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/lock.h"
00047 
00048 #define MAX_ARGS 80
00049 
00050 /* special result value used to force macro exit */
00051 #define MACRO_EXIT_RESULT 1024
00052 
00053 static char *descrip =
00054 "  Macro(macroname|arg1|arg2...): Executes a macro using the context\n"
00055 "'macro-<macroname>', jumping to the 's' extension of that context and\n"
00056 "executing each step, then returning when the steps end. \n"
00057 "The calling extension, context, and priority are stored in ${MACRO_EXTEN}, \n"
00058 "${MACRO_CONTEXT} and ${MACRO_PRIORITY} respectively.  Arguments become\n"
00059 "${ARG1}, ${ARG2}, etc in the macro context.\n"
00060 "If you Goto out of the Macro context, the Macro will terminate and control\n"
00061 "will be returned at the location of the Goto.\n"
00062 "If ${MACRO_OFFSET} is set at termination, Macro will attempt to continue\n"
00063 "at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.\n"
00064 "Extensions: While a macro is being executed, it becomes the current context.\n"
00065 "            This means that if a hangup occurs, for instance, that the macro\n"
00066 "            will be searched for an 'h' extension, NOT the context from which\n"
00067 "            the macro was called. So, make sure to define all appropriate\n"
00068 "            extensions in your macro! (you can use 'catch' in AEL) \n"
00069 "WARNING: Because of the way Macro is implemented (it executes the priorities\n"
00070 "         contained within it via sub-engine), and a fixed per-thread\n"
00071 "         memory stack allowance, macros are limited to 7 levels\n"
00072 "         of nesting (macro calling macro calling macro, etc.); It\n"
00073 "         may be possible that stack-intensive applications in deeply nested macros\n"
00074 "         could cause asterisk to crash earlier than this limit.\n";
00075 
00076 static char *if_descrip =
00077 "  MacroIf(<expr>?macroname_a[|arg1][:macroname_b[|arg1]])\n"
00078 "Executes macro defined in <macroname_a> if <expr> is true\n"
00079 "(otherwise <macroname_b> if provided)\n"
00080 "Arguments and return values as in application macro()\n";
00081 
00082 static char *exclusive_descrip =
00083 "  MacroExclusive(macroname|arg1|arg2...):\n"
00084 "Executes macro defined in the context 'macro-macroname'\n"
00085 "Only one call at a time may run the macro.\n"
00086 "(we'll wait if another call is busy executing in the Macro)\n"
00087 "Arguments and return values as in application Macro()\n";
00088 
00089 static char *exit_descrip =
00090 "  MacroExit():\n"
00091 "Causes the currently running macro to exit as if it had\n"
00092 "ended normally by running out of priorities to execute.\n"
00093 "If used outside a macro, will likely cause unexpected\n"
00094 "behavior.\n";
00095 
00096 static char *app = "Macro";
00097 static char *if_app = "MacroIf";
00098 static char *exclusive_app = "MacroExclusive";
00099 static char *exit_app = "MacroExit";
00100 
00101 static char *synopsis = "Macro Implementation";
00102 static char *if_synopsis = "Conditional Macro Implementation";
00103 static char *exclusive_synopsis = "Exclusive Macro Implementation";
00104 static char *exit_synopsis = "Exit From Macro";
00105 
00106 static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
00107 
00108 struct ast_datastore_info macro_ds_info = {
00109    .type = "MACRO",
00110    .chan_fixup = macro_fixup,
00111 };
00112 
00113 static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00114 {
00115    int i;
00116    char varname[10];
00117    pbx_builtin_setvar_helper(new_chan, "MACRO_DEPTH", "0");
00118    pbx_builtin_setvar_helper(new_chan, "MACRO_CONTEXT", NULL);
00119    pbx_builtin_setvar_helper(new_chan, "MACRO_EXTEN", NULL);
00120    pbx_builtin_setvar_helper(new_chan, "MACRO_PRIORITY", NULL);
00121    pbx_builtin_setvar_helper(new_chan, "MACRO_OFFSET", NULL);
00122    for (i = 1; i < 100; i++) {
00123       snprintf(varname, sizeof(varname), "ARG%d", i);
00124       while (pbx_builtin_getvar_helper(new_chan, varname)) {
00125          /* Kill all levels of arguments */
00126          pbx_builtin_setvar_helper(new_chan, varname, NULL);
00127       }
00128    }
00129 }
00130 
00131 static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
00132 {
00133    struct ast_exten *e;
00134    struct ast_include *i;
00135    struct ast_context *c2;
00136 
00137    for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
00138       if (ast_extension_match(ast_get_extension_name(e), exten)) {
00139          int needmatch = ast_get_extension_matchcid(e);
00140          if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
00141             (!needmatch)) {
00142             /* This is the matching extension we want */
00143             struct ast_exten *p;
00144             for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
00145                if (priority != ast_get_extension_priority(p))
00146                   continue;
00147                return p;
00148             }
00149          }
00150       }
00151    }
00152 
00153    /* No match; run through includes */
00154    for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
00155       for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
00156          if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
00157             e = find_matching_priority(c2, exten, priority, callerid);
00158             if (e)
00159                return e;
00160          }
00161       }
00162    }
00163    return NULL;
00164 }
00165 
00166 static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
00167 {
00168    const char *s;
00169    char *tmp;
00170    char *cur, *rest;
00171    char *macro;
00172    char fullmacro[80];
00173    char varname[80];
00174    char runningapp[80], runningdata[1024];
00175    char *oldargs[MAX_ARGS + 1] = { NULL, };
00176    int argc, x;
00177    int res=0;
00178    char oldexten[256]="";
00179    int oldpriority, gosub_level = 0;
00180    char pc[80], depthc[12];
00181    char oldcontext[AST_MAX_CONTEXT] = "";
00182    const char *inhangupc;
00183    int offset, depth = 0, maxdepth = 7;
00184    int setmacrocontext=0;
00185    int autoloopflag, inhangup = 0;
00186   
00187    char *save_macro_exten;
00188    char *save_macro_context;
00189    char *save_macro_priority;
00190    char *save_macro_offset;
00191    struct ast_module_user *u;
00192    struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
00193  
00194    if (ast_strlen_zero(data)) {
00195       ast_log(LOG_WARNING, "Macro() requires arguments. See \"show application macro\" for help.\n");
00196       return -1;
00197    }
00198 
00199    u = ast_module_user_add(chan);
00200 
00201    do {
00202       if (macro_store) {
00203          break;
00204       }
00205       if (!(macro_store = ast_channel_datastore_alloc(&macro_ds_info, NULL))) {
00206          ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
00207          break;
00208       }
00209       /* Just the existence of this datastore is enough. */
00210       macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
00211       ast_channel_datastore_add(chan, macro_store);
00212    } while (0);
00213 
00214    /* does the user want a deeper rabbit hole? */
00215    s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION");
00216    if (s)
00217       sscanf(s, "%d", &maxdepth);
00218 
00219    /* Count how many levels deep the rabbit hole goes */
00220    s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH");
00221    if (s)
00222       sscanf(s, "%d", &depth);
00223    /* Used for detecting whether to return when a Macro is called from another Macro after hangup */
00224    if (strcmp(chan->exten, "h") == 0)
00225       pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
00226    inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP");
00227    if (!ast_strlen_zero(inhangupc))
00228       sscanf(inhangupc, "%d", &inhangup);
00229 
00230    if (depth >= maxdepth) {
00231       ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
00232       ast_module_user_remove(u);
00233       return 0;
00234    }
00235    snprintf(depthc, sizeof(depthc), "%d", depth + 1);
00236    pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
00237 
00238    tmp = ast_strdupa(data);
00239    rest = tmp;
00240    macro = strsep(&rest, "|");
00241    if (ast_strlen_zero(macro)) {
00242       ast_log(LOG_WARNING, "Invalid macro name specified\n");
00243       ast_module_user_remove(u);
00244       return 0;
00245    }
00246 
00247    snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
00248    if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->cid.cid_num)) {
00249       if (!ast_context_find(fullmacro)) 
00250          ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
00251       else
00252          ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
00253       ast_module_user_remove(u);
00254       return 0;
00255    }
00256 
00257    /* If we are to run the macro exclusively, take the mutex */
00258    if (exclusive) {
00259       ast_log(LOG_DEBUG, "Locking macrolock for '%s'\n", fullmacro);
00260       ast_autoservice_start(chan);
00261       if (ast_context_lockmacro(fullmacro)) {
00262          ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
00263          ast_autoservice_stop(chan);
00264          ast_module_user_remove(u);
00265 
00266          return 0;
00267       }
00268       ast_autoservice_stop(chan);
00269    }
00270    
00271    /* Save old info */
00272    oldpriority = chan->priority;
00273    ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
00274    ast_copy_string(oldcontext, chan->context, sizeof(oldcontext));
00275    if (ast_strlen_zero(chan->macrocontext)) {
00276       ast_copy_string(chan->macrocontext, chan->context, sizeof(chan->macrocontext));
00277       ast_copy_string(chan->macroexten, chan->exten, sizeof(chan->macroexten));
00278       chan->macropriority = chan->priority;
00279       setmacrocontext=1;
00280    }
00281    argc = 1;
00282    /* Save old macro variables */
00283    save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
00284    pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
00285 
00286    save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
00287    pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
00288 
00289    save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
00290    snprintf(pc, sizeof(pc), "%d", oldpriority);
00291    pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
00292   
00293    save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
00294    pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
00295 
00296    /* Setup environment for new run */
00297    chan->exten[0] = 's';
00298    chan->exten[1] = '\0';
00299    ast_copy_string(chan->context, fullmacro, sizeof(chan->context));
00300    chan->priority = 1;
00301 
00302    while((cur = strsep(&rest, "|")) && (argc < MAX_ARGS)) {
00303       const char *s;
00304       /* Save copy of old arguments if we're overwriting some, otherwise
00305          let them pass through to the other macro */
00306       snprintf(varname, sizeof(varname), "ARG%d", argc);
00307       s = pbx_builtin_getvar_helper(chan, varname);
00308       if (s)
00309          oldargs[argc] = ast_strdup(s);
00310       pbx_builtin_setvar_helper(chan, varname, cur);
00311       argc++;
00312    }
00313    autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
00314    ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
00315    while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
00316       struct ast_context *c;
00317       struct ast_exten *e;
00318       runningapp[0] = '\0';
00319       runningdata[0] = '\0';
00320 
00321       /* What application will execute? */
00322       if (ast_rdlock_contexts()) {
00323          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
00324       } else {
00325          for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
00326             if (!strcmp(ast_get_context_name(c), chan->context)) {
00327                if (ast_lock_context(c)) {
00328                   ast_log(LOG_WARNING, "Unable to lock context?\n");
00329                } else {
00330                   e = find_matching_priority(c, chan->exten, chan->priority, chan->cid.cid_num);
00331                   if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
00332                      ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
00333                      ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
00334                   }
00335                   ast_unlock_context(c);
00336                }
00337                break;
00338             }
00339          }
00340       }
00341       ast_unlock_contexts();
00342 
00343       /* Reset the macro depth, if it was changed in the last iteration */
00344       pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
00345 
00346       if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
00347          /* Something bad happened, or a hangup has been requested. */
00348          if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
00349             (res == '*') || (res == '#')) {
00350             /* Just return result as to the previous application as if it had been dialed */
00351             ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
00352             break;
00353          }
00354          switch(res) {
00355          case MACRO_EXIT_RESULT:
00356             res = 0;
00357             goto out;
00358          case AST_PBX_KEEPALIVE:
00359             if (option_debug)
00360                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);
00361             else if (option_verbose > 1)
00362                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);
00363             goto out;
00364          default:
00365             if (option_debug)
00366                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);
00367             else if (option_verbose > 1)
00368                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);
00369             goto out;
00370          }
00371       }
00372 
00373       ast_log(LOG_DEBUG, "Executed application: %s\n", runningapp);
00374 
00375       if (!strcasecmp(runningapp, "GOSUB")) {
00376          gosub_level++;
00377          ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
00378       } else if (!strcasecmp(runningapp, "GOSUBIF")) {
00379          char tmp2[1024] = "", *cond, *app, *app2 = tmp2;
00380          pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
00381          cond = strsep(&app2, "?");
00382          app = strsep(&app2, ":");
00383          if (pbx_checkcondition(cond)) {
00384             if (!ast_strlen_zero(app)) {
00385                gosub_level++;
00386                ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
00387             }
00388          } else {
00389             if (!ast_strlen_zero(app2)) {
00390                gosub_level++;
00391                ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
00392             }
00393          }
00394       } else if (!strcasecmp(runningapp, "RETURN")) {
00395          gosub_level--;
00396          ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
00397       } else if (!strcasecmp(runningapp, "STACKPOP")) {
00398          gosub_level--;
00399          ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
00400       } else if (!strncasecmp(runningapp, "EXEC", 4)) {
00401          /* Must evaluate args to find actual app */
00402          char tmp2[1024] = "", *tmp3 = NULL;
00403          pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
00404          if (!strcasecmp(runningapp, "EXECIF")) {
00405             tmp3 = strchr(tmp2, '|');
00406             if (tmp3)
00407                *tmp3++ = '\0';
00408             if (!pbx_checkcondition(tmp2))
00409                tmp3 = NULL;
00410          } else
00411             tmp3 = tmp2;
00412 
00413          if (tmp3)
00414             ast_log(LOG_DEBUG, "Last app: %s\n", tmp3);
00415 
00416          if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
00417             gosub_level++;
00418             ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
00419          } else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
00420             gosub_level--;
00421             ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
00422          } else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
00423             gosub_level--;
00424             ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
00425          }
00426       }
00427 
00428       if (gosub_level == 0 && strcasecmp(chan->context, fullmacro)) {
00429          if (option_verbose > 1)
00430             ast_verbose(VERBOSE_PREFIX_2 "Channel '%s' jumping out of macro '%s'\n", chan->name, macro);
00431          break;
00432       }
00433 
00434       /* don't stop executing extensions when we're in "h" */
00435       if (chan->_softhangup && !inhangup) {
00436          ast_log(LOG_DEBUG, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n",
00437             chan->exten, chan->macroexten, chan->priority);
00438          goto out;
00439       }
00440       chan->priority++;
00441    }
00442    out:
00443 
00444    /* Don't let the channel change now. */
00445    ast_channel_lock(chan);
00446 
00447    /* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
00448    snprintf(depthc, sizeof(depthc), "%d", depth);
00449    pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
00450    ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
00451 
00452    for (x = 1; x < argc; x++) {
00453       /* Restore old arguments and delete ours */
00454       snprintf(varname, sizeof(varname), "ARG%d", x);
00455       if (oldargs[x]) {
00456          pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
00457          free(oldargs[x]);
00458       } else {
00459          pbx_builtin_setvar_helper(chan, varname, NULL);
00460       }
00461    }
00462 
00463    /* Restore macro variables */
00464    pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
00465    pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
00466    pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
00467    if (save_macro_exten)
00468       free(save_macro_exten);
00469    if (save_macro_context)
00470       free(save_macro_context);
00471    if (save_macro_priority)
00472       free(save_macro_priority);
00473 
00474    if (setmacrocontext) {
00475       chan->macrocontext[0] = '\0';
00476       chan->macroexten[0] = '\0';
00477       chan->macropriority = 0;
00478    }
00479 
00480    if (!strcasecmp(chan->context, fullmacro)) {
00481       /* If we're leaving the macro normally, restore original information */
00482       chan->priority = oldpriority;
00483       ast_copy_string(chan->context, oldcontext, sizeof(chan->context));
00484       if (!(chan->_softhangup & AST_SOFTHANGUP_ASYNCGOTO)) {
00485          /* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
00486          const char *offsets;
00487          ast_copy_string(chan->exten, oldexten, sizeof(chan->exten));
00488          if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
00489             /* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
00490                normally if there is any problem */
00491             if (sscanf(offsets, "%d", &offset) == 1) {
00492                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->cid.cid_num)) {
00493                   chan->priority += offset;
00494                }
00495             }
00496          }
00497       }
00498    }
00499 
00500    pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
00501    if (save_macro_offset)
00502       free(save_macro_offset);
00503 
00504    /* Unlock the macro */
00505    if (exclusive) {
00506       ast_log(LOG_DEBUG, "Unlocking macrolock for '%s'\n", fullmacro);
00507       if (ast_context_unlockmacro(fullmacro)) {
00508          ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
00509          res = 0;
00510       }
00511    }
00512    ast_channel_unlock(chan);
00513    
00514    ast_module_user_remove(u);
00515 
00516    return res;
00517 }
00518 
00519 static int macro_exec(struct ast_channel *chan, void *data)
00520 {
00521    return _macro_exec(chan, data, 0);
00522 }
00523 
00524 static int macroexclusive_exec(struct ast_channel *chan, void *data)
00525 {
00526    return _macro_exec(chan, data, 1);
00527 }
00528 
00529 static int macroif_exec(struct ast_channel *chan, void *data) 
00530 {
00531    char *expr = NULL, *label_a = NULL, *label_b = NULL;
00532    int res = 0;
00533    struct ast_module_user *u;
00534 
00535    u = ast_module_user_add(chan);
00536 
00537    if (!(expr = ast_strdupa(data))) {
00538       ast_module_user_remove(u);
00539       return -1;
00540    }
00541 
00542    if ((label_a = strchr(expr, '?'))) {
00543       *label_a = '\0';
00544       label_a++;
00545       if ((label_b = strchr(label_a, ':'))) {
00546          *label_b = '\0';
00547          label_b++;
00548       }
00549       if (pbx_checkcondition(expr))
00550          res = macro_exec(chan, label_a);
00551       else if (label_b) 
00552          res = macro_exec(chan, label_b);
00553    } else
00554       ast_log(LOG_WARNING, "Invalid Syntax.\n");
00555 
00556    ast_module_user_remove(u);
00557 
00558    return res;
00559 }
00560          
00561 static int macro_exit_exec(struct ast_channel *chan, void *data)
00562 {
00563    return MACRO_EXIT_RESULT;
00564 }
00565 
00566 static int unload_module(void)
00567 {
00568    int res;
00569 
00570    res = ast_unregister_application(if_app);
00571    res |= ast_unregister_application(exit_app);
00572    res |= ast_unregister_application(app);
00573    res |= ast_unregister_application(exclusive_app);
00574 
00575    ast_module_user_hangup_all();
00576 
00577    return res;
00578 }
00579 
00580 static int load_module(void)
00581 {
00582    int res;
00583 
00584    res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip);
00585    res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip);
00586    res |= ast_register_application(exclusive_app, macroexclusive_exec, exclusive_synopsis, exclusive_descrip);
00587    res |= ast_register_application(app, macro_exec, synopsis, descrip);
00588 
00589    return res;
00590 }
00591 
00592 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Macros");

Generated on Wed Mar 4 19:57:58 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7