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/options.h"
34 #include "asterisk/pbx.h"
35 #include "asterisk/module.h"
36 #include "asterisk/frame.h"
37 #include "asterisk/cli.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/md5.h"
40 #include "asterisk/linkedlists.h"
41 #include "asterisk/chanvars.h"
42 #include "asterisk/sched.h"
43 #include "asterisk/io.h"
44 #include "asterisk/utils.h"
45 #include "asterisk/crypto.h"
46 #include "asterisk/astdb.h"
49 /* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
50 the data passed to it to try to get a string of the form:
52 [exten]@context[:priority][/extramatch]
54 Where exten, context, and priority are another extension, context, and priority
55 to lookup and "extramatch" is an extra match restriction the *original* number
56 must fit if specified. The "extramatch" begins with _ like an exten pattern
57 if it is specified. Note that the search context MUST be a different context
58 from the current context or the search will not succeed in an effort to reduce
59 the likelihood of loops (they're still possible if you try hard, so be careful!)
64 #define LOOPBACK_COMMON \
67 char *newexten=(char *)exten, *newcontext=(char *)context; \
68 int newpriority=priority; \
69 char *newpattern=NULL; \
70 loopback_helper(buf, sizeof(buf), exten, context, priority, data); \
71 loopback_subst(&newexten, &newcontext, &newpriority, &newpattern, buf); \
72 ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
73 if (!strcasecmp(newcontext, context)) return -1
76 static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
78 struct ast_var_t *newvariable;
79 struct varshead headp;
82 snprintf(tmp, sizeof(tmp), "%d", priority);
83 AST_LIST_HEAD_INIT_NOLOCK(&headp);
84 AST_LIST_INSERT_HEAD(&headp, ast_var_assign("EXTEN", exten), entries);
85 AST_LIST_INSERT_HEAD(&headp, ast_var_assign("CONTEXT", context), entries);
86 AST_LIST_INSERT_HEAD(&headp, ast_var_assign("PRIORITY", tmp), entries);
87 /* Substitute variables */
88 pbx_substitute_variables_varshead(&headp, data, buf, buflen);
90 while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
91 ast_var_delete(newvariable);
95 static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
99 *newpattern = strchr(buf, '/');
101 *(*newpattern)++ = '\0';
102 con = strchr(buf, '@');
105 pri = strchr(con, ':');
107 pri = strchr(buf, ':');
108 if (!ast_strlen_zero(buf))
110 if (!ast_strlen_zero(con))
112 if (!ast_strlen_zero(pri))
113 sscanf(pri, "%d", priority);
116 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
119 res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
120 if (newpattern && !ast_extension_match(newpattern, exten))
125 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
128 res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
129 if (newpattern && !ast_extension_match(newpattern, exten))
134 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
138 res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0);
139 /* XXX hmmm... res is overridden ? */
140 if (newpattern && !ast_extension_match(newpattern, exten))
145 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
148 res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
149 if (newpattern && !ast_extension_match(newpattern, exten))
154 static struct ast_switch loopback_switch =
157 description: "Loopback Dialplan Switch",
158 exists: loopback_exists,
159 canmatch: loopback_canmatch,
161 matchmore: loopback_matchmore,
164 static int unload_module(void)
166 ast_unregister_switch(&loopback_switch);
170 static int load_module(void)
172 ast_register_switch(&loopback_switch);
176 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");