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$")
35 #include "asterisk/file.h"
36 #include "asterisk/logger.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/config.h"
39 #include "asterisk/options.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/module.h"
42 #include "asterisk/frame.h"
43 #include "asterisk/file.h"
44 #include "asterisk/cli.h"
45 #include "asterisk/lock.h"
46 #include "asterisk/md5.h"
47 #include "asterisk/linkedlists.h"
48 #include "asterisk/chanvars.h"
49 #include "asterisk/sched.h"
50 #include "asterisk/io.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/crypto.h"
53 #include "asterisk/astdb.h"
56 /* Loopback switch creates a 'tunnel' to another context. When extension
57 lookups pass through the 'tunnel', Asterisk expressions can be used
58 to modify the target extension, context, and priority in any way desired.
59 If there is a match at the far end, execution jumps through the 'tunnel'
60 to the matched context, extension, and priority.
62 Global variables as well as ${CONTEXT}, ${EXTEN}, and ${PRIORITY} are
63 available for substitution. After substitution Loopback expects to get
66 [exten]@context[:priority][/extramatch]
68 Where exten, context, and priority are another extension, context, and priority
69 to lookup and "extramatch" is a dialplan extension pattern which the *original*
70 number must match. If exten or priority are empty, the original values are
73 Note that the search context MUST be a different context from the current
74 context or the search will not succeed. This is intended to reduce the
75 likelihood of loops (they're still possible if you try hard, so be careful!)
80 #define LOOPBACK_COMMON \
83 char *newexten=(char *)exten, *newcontext=(char *)context; \
84 int newpriority=priority; \
85 char *newpattern=NULL; \
86 loopback_subst(buf, sizeof(buf), exten, context, priority, data); \
87 loopback_parse(&newexten, &newcontext, &newpriority, &newpattern, buf); \
88 ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
89 if (!strcasecmp(newcontext, context)) return -1
91 static char *loopback_subst(char *buf
, int buflen
, const char *exten
, const char *context
, int priority
, const char *data
)
93 struct ast_var_t
*newvariable
;
94 struct varshead headp
;
97 snprintf(tmp
, sizeof(tmp
), "%d", priority
);
98 memset(buf
, 0, buflen
);
99 AST_LIST_HEAD_INIT_NOLOCK(&headp
);
100 newvariable
= ast_var_assign("EXTEN", exten
);
101 AST_LIST_INSERT_HEAD(&headp
, newvariable
, entries
);
102 newvariable
= ast_var_assign("CONTEXT", context
);
103 AST_LIST_INSERT_HEAD(&headp
, newvariable
, entries
);
104 newvariable
= ast_var_assign("PRIORITY", tmp
);
105 AST_LIST_INSERT_HEAD(&headp
, newvariable
, entries
);
106 /* Substitute variables */
107 pbx_substitute_variables_varshead(&headp
, data
, buf
, buflen
);
109 while ((newvariable
= AST_LIST_REMOVE_HEAD(&headp
, entries
)))
110 ast_var_delete(newvariable
);
114 static void loopback_parse(char **newexten
, char **newcontext
, int *priority
, char **newpattern
, char *buf
)
118 *newpattern
= strchr(buf
, '/');
120 *(*newpattern
)++ = '\0';
121 con
= strchr(buf
, '@');
124 pri
= strchr(con
, ':');
126 pri
= strchr(buf
, ':');
127 if (!ast_strlen_zero(buf
))
129 if (!ast_strlen_zero(con
))
131 if (!ast_strlen_zero(pri
))
132 sscanf(pri
, "%d", priority
);
135 static int loopback_exists(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, const char *callerid
, const char *data
)
138 res
= ast_exists_extension(chan
, newcontext
, newexten
, newpriority
, callerid
);
139 if (newpattern
&& !ast_extension_match(newpattern
, exten
))
144 static int loopback_canmatch(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, const char *callerid
, const char *data
)
147 res
= ast_canmatch_extension(chan
, newcontext
, newexten
, newpriority
, callerid
);
148 if (newpattern
&& !ast_extension_match(newpattern
, exten
))
153 static int loopback_exec(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, const char *callerid
, const char *data
)
156 res
= ast_spawn_extension(chan
, newcontext
, newexten
, newpriority
, callerid
);
160 static int loopback_matchmore(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, const char *callerid
, const char *data
)
163 res
= ast_matchmore_extension(chan
, newcontext
, newexten
, newpriority
, callerid
);
164 if (newpattern
&& !ast_extension_match(newpattern
, exten
))
169 static struct ast_switch loopback_switch
=
172 description
: "Loopback Dialplan Switch",
173 exists
: loopback_exists
,
174 canmatch
: loopback_canmatch
,
176 matchmore
: loopback_matchmore
,
179 static int unload_module(void)
181 ast_unregister_switch(&loopback_switch
);
185 static int load_module(void)
187 ast_register_switch(&loopback_switch
);
191 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Loopback Switch");