Thu Apr 28 2011 16:56:48

Asterisk developer's documentation


pbx_loopback.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 Loopback PBX Module
00022  *
00023  */
00024 
00025 #include "asterisk.h"
00026 
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211580 $")
00028 
00029 #include "asterisk/file.h"
00030 #include "asterisk/logger.h"
00031 #include "asterisk/channel.h"
00032 #include "asterisk/config.h"
00033 #include "asterisk/pbx.h"
00034 #include "asterisk/module.h"
00035 #include "asterisk/frame.h"
00036 #include "asterisk/cli.h"
00037 #include "asterisk/lock.h"
00038 #include "asterisk/md5.h"
00039 #include "asterisk/linkedlists.h"
00040 #include "asterisk/chanvars.h"
00041 #include "asterisk/sched.h"
00042 #include "asterisk/io.h"
00043 #include "asterisk/utils.h"
00044 #include "asterisk/crypto.h"
00045 #include "asterisk/astdb.h"
00046 
00047 
00048 /* Loopback switch creates a 'tunnel' to another context.  When extension
00049    lookups pass through the 'tunnel', Asterisk expressions can be used
00050    to modify the target extension, context, and priority in any way desired.
00051    If there is a match at the far end, execution jumps through the 'tunnel'
00052    to the matched context, extension, and priority.
00053  
00054    Global variables as well as ${CONTEXT}, ${EXTEN}, and ${PRIORITY} are 
00055    available for substitution.  After substitution Loopback expects to get
00056    a string of the form:
00057 
00058    [exten]@context[:priority][/extramatch]
00059    
00060    Where exten, context, and priority are another extension, context, and priority
00061    to lookup and "extramatch" is a dialplan extension pattern which the *original*
00062    number must match.  If exten or priority are empty, the original values are 
00063    used.
00064 
00065    Note that the search context MUST be a different context from the current
00066    context or the search will not succeed.  This is intended to reduce the
00067    likelihood of loops (they're still possible if you try hard, so be careful!)
00068 
00069 */
00070 
00071 
00072 #define LOOPBACK_COMMON \
00073    char buf[1024]; \
00074    int res; \
00075    char *newexten=(char *)exten, *newcontext=(char *)context; \
00076    int newpriority=priority; \
00077    char *newpattern=NULL; \
00078    loopback_subst(buf, sizeof(buf), exten, context, priority, data); \
00079    loopback_parse(&newexten, &newcontext, &newpriority, &newpattern, buf); \
00080    ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
00081    if (!strcasecmp(newcontext, context)) return -1
00082 
00083 static char *loopback_subst(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
00084 {
00085    struct ast_var_t *newvariable;
00086    struct varshead headp;
00087    char tmp[80];
00088 
00089    snprintf(tmp, sizeof(tmp), "%d", priority);
00090    AST_LIST_HEAD_INIT_NOLOCK(&headp);
00091    newvariable = ast_var_assign("EXTEN", exten);
00092    AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00093    newvariable = ast_var_assign("CONTEXT", context);
00094    AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00095    newvariable = ast_var_assign("PRIORITY", tmp);
00096    AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00097    /* Substitute variables */
00098    pbx_substitute_variables_varshead(&headp, data, buf, buflen);
00099    /* free the list */
00100    while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00101                 ast_var_delete(newvariable);
00102    return buf;
00103 }
00104 
00105 static void loopback_parse(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
00106 {
00107    char *con;
00108    char *pri;
00109    *newpattern = strchr(buf, '/');
00110    if (*newpattern)
00111       *(*newpattern)++ = '\0';
00112    con = strchr(buf, '@');
00113    if (con) {
00114       *con++ = '\0';
00115       pri = strchr(con, ':');
00116    } else
00117       pri = strchr(buf, ':');
00118    if (!ast_strlen_zero(buf))
00119       *newexten = buf;
00120    if (!ast_strlen_zero(con))
00121       *newcontext = con;
00122    if (!ast_strlen_zero(pri))
00123       sscanf(pri, "%30d", priority);
00124 }
00125 
00126 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00127 {
00128    LOOPBACK_COMMON;
00129    res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
00130    if (newpattern && !ast_extension_match(newpattern, exten))
00131       res = 0;
00132    return res;
00133 }
00134 
00135 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00136 {
00137    LOOPBACK_COMMON;
00138    res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
00139    if (newpattern && !ast_extension_match(newpattern, exten))
00140       res = 0;
00141    return res;
00142 }
00143 
00144 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00145 {
00146    int found;
00147    LOOPBACK_COMMON;
00148    res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0);
00149    return res;
00150 }
00151 
00152 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00153 {
00154    LOOPBACK_COMMON;
00155    res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
00156    if (newpattern && !ast_extension_match(newpattern, exten))
00157       res = 0;
00158    return res;
00159 }
00160 
00161 static struct ast_switch loopback_switch =
00162 {
00163         name:                   "Loopback",
00164         description:       "Loopback Dialplan Switch",
00165         exists:                 loopback_exists,
00166         canmatch:               loopback_canmatch,
00167         exec:                   loopback_exec,
00168         matchmore:              loopback_matchmore,
00169 };
00170 
00171 static int unload_module(void)
00172 {
00173    ast_unregister_switch(&loopback_switch);
00174    return 0;
00175 }
00176 
00177 static int load_module(void)
00178 {
00179    if (ast_register_switch(&loopback_switch))
00180       return AST_MODULE_LOAD_FAILURE;
00181    return AST_MODULE_LOAD_SUCCESS;
00182 }
00183 
00184 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");