2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Loopback PBX Module
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29 #include "asterisk/file.h"
30 #include "asterisk/logger.h"
31 #include "asterisk/channel.h"
32 #include "asterisk/config.h"
33 #include "asterisk/pbx.h"
34 #include "asterisk/module.h"
35 #include "asterisk/frame.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/lock.h"
38 #include "asterisk/md5.h"
39 #include "asterisk/linkedlists.h"
40 #include "asterisk/chanvars.h"
41 #include "asterisk/sched.h"
42 #include "asterisk/io.h"
43 #include "asterisk/utils.h"
44 #include "asterisk/crypto.h"
45 #include "asterisk/astdb.h"
48 /* Loopback switch creates a 'tunnel' to another context. When extension
49 lookups pass through the 'tunnel', Asterisk expressions can be used
50 to modify the target extension, context, and priority in any way desired.
51 If there is a match at the far end, execution jumps through the 'tunnel'
52 to the matched context, extension, and priority.
54 Global variables as well as ${CONTEXT}, ${EXTEN}, and ${PRIORITY} are
55 available for substitution. After substitution Loopback expects to get
58 [exten]@context[:priority][/extramatch]
60 Where exten, context, and priority are another extension, context, and priority
61 to lookup and "extramatch" is a dialplan extension pattern which the *original*
62 number must match. If exten or priority are empty, the original values are
65 Note that the search context MUST be a different context from the current
66 context or the search will not succeed. This is intended to reduce the
67 likelihood of loops (they're still possible if you try hard, so be careful!)
72 #define LOOPBACK_COMMON \
75 char *newexten=(char *)exten, *newcontext=(char *)context; \
76 int newpriority=priority; \
77 char *newpattern=NULL; \
78 loopback_subst(buf, sizeof(buf), exten, context, priority, data); \
79 loopback_parse(&newexten, &newcontext, &newpriority, &newpattern, buf); \
80 ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
81 if (!strcasecmp(newcontext, context)) return -1
83 static char *loopback_subst(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
85 struct ast_var_t *newvariable;
86 struct varshead headp;
89 snprintf(tmp, sizeof(tmp), "%d", priority);
90 AST_LIST_HEAD_INIT_NOLOCK(&headp);
91 newvariable = ast_var_assign("EXTEN", exten);
92 AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
93 newvariable = ast_var_assign("CONTEXT", context);
94 AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
95 newvariable = ast_var_assign("PRIORITY", tmp);
96 AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
97 /* Substitute variables */
98 pbx_substitute_variables_varshead(&headp, data, buf, buflen);
100 while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
101 ast_var_delete(newvariable);
105 static void loopback_parse(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
109 *newpattern = strchr(buf, '/');
111 *(*newpattern)++ = '\0';
112 con = strchr(buf, '@');
115 pri = strchr(con, ':');
117 pri = strchr(buf, ':');
118 if (!ast_strlen_zero(buf))
120 if (!ast_strlen_zero(con))
122 if (!ast_strlen_zero(pri))
123 sscanf(pri, "%d", priority);
126 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
129 res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
130 if (newpattern && !ast_extension_match(newpattern, exten))
135 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
138 res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
139 if (newpattern && !ast_extension_match(newpattern, exten))
144 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
148 res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0);
152 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
155 res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
156 if (newpattern && !ast_extension_match(newpattern, exten))
161 static struct ast_switch loopback_switch =
164 description: "Loopback Dialplan Switch",
165 exists: loopback_exists,
166 canmatch: loopback_canmatch,
168 matchmore: loopback_matchmore,
171 static int unload_module(void)
173 ast_unregister_switch(&loopback_switch);
177 static int load_module(void)
179 if (ast_register_switch(&loopback_switch))
180 return AST_MODULE_LOAD_FAILURE;
181 return AST_MODULE_LOAD_SUCCESS;
184 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");