Wed Aug 18 22:33:41 2010

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

Generated on Wed Aug 18 22:33:41 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7