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$")
31 #include "asterisk/file.h"
32 #include "asterisk/logger.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/config.h"
35 #include "asterisk/options.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/module.h"
38 #include "asterisk/frame.h"
39 #include "asterisk/cli.h"
40 #include "asterisk/lock.h"
41 #include "asterisk/md5.h"
42 #include "asterisk/linkedlists.h"
43 #include "asterisk/chanvars.h"
44 #include "asterisk/sched.h"
45 #include "asterisk/io.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/crypto.h"
48 #include "asterisk/astdb.h"
51 /* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
52 the data passed to it to try to get a string of the form:
54 [exten]@context[:priority][/extramatch]
56 Where exten, context, and priority are another extension, context, and priority
57 to lookup and "extramatch" is an extra match restriction the *original* number
58 must fit if specified. The "extramatch" begins with _ like an exten pattern
59 if it is specified. Note that the search context MUST be a different context
60 from the current context or the search will not succeed in an effort to reduce
61 the likelihood of loops (they're still possible if you try hard, so be careful!)
66 #define LOOPBACK_COMMON \
69 char *newexten=(char *)exten, *newcontext=(char *)context; \
70 int newpriority=priority; \
71 char *newpattern=NULL; \
72 loopback_helper(buf, sizeof(buf), exten, context, priority, data); \
73 loopback_subst(&newexten, &newcontext, &newpriority, &newpattern, buf); \
74 ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
75 if (!strcasecmp(newcontext, context)) return -1
78 static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
80 struct ast_var_t *newvariable;
81 struct varshead headp;
84 snprintf(tmp, sizeof(tmp), "%d", priority);
85 AST_LIST_HEAD_INIT_NOLOCK(&headp);
86 AST_LIST_INSERT_HEAD(&headp, ast_var_assign("EXTEN", exten), entries);
87 AST_LIST_INSERT_HEAD(&headp, ast_var_assign("CONTEXT", context), entries);
88 AST_LIST_INSERT_HEAD(&headp, ast_var_assign("PRIORITY", tmp), entries);
89 /* Substitute variables */
90 pbx_substitute_variables_varshead(&headp, data, buf, buflen);
92 while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
93 ast_var_delete(newvariable);
97 static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
101 *newpattern = strchr(buf, '/');
103 *(*newpattern)++ = '\0';
104 con = strchr(buf, '@');
107 pri = strchr(con, ':');
109 pri = strchr(buf, ':');
110 if (!ast_strlen_zero(buf))
112 if (!ast_strlen_zero(con))
114 if (!ast_strlen_zero(pri))
115 sscanf(pri, "%d", priority);
118 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
121 res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
122 if (newpattern && !ast_extension_match(newpattern, exten))
127 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
130 res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
131 if (newpattern && !ast_extension_match(newpattern, exten))
136 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
140 res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0);
141 /* XXX hmmm... res is overridden ? */
142 if (newpattern && !ast_extension_match(newpattern, exten))
147 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
150 res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
151 if (newpattern && !ast_extension_match(newpattern, exten))
156 static struct ast_switch loopback_switch =
159 description: "Loopback Dialplan Switch",
160 exists: loopback_exists,
161 canmatch: loopback_canmatch,
163 matchmore: loopback_matchmore,
166 static int unload_module(void)
168 ast_unregister_switch(&loopback_switch);
172 static int load_module(void)
174 ast_register_switch(&loopback_switch);
178 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");