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 substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
57 the data passed to it to try to get a string of the form:
59 [exten]@context[:priority][/extramatch]
61 Where exten, context, and priority are another extension, context, and priority
62 to lookup and "extramatch" is an extra match restriction the *original* number
63 must fit if specified. The "extramatch" begins with _ like an exten pattern
64 if it is specified. Note that the search context MUST be a different context
65 from the current context or the search will not succeed in an effort to reduce
66 the likelihood of loops (they're still possible if you try hard, so be careful!)
71 #define LOOPBACK_COMMON \
74 char *newexten=(char *)exten, *newcontext=(char *)context; \
75 int newpriority=priority; \
76 char *newpattern=NULL; \
77 loopback_helper(buf, sizeof(buf), exten, context, priority, data); \
78 loopback_subst(&newexten, &newcontext, &newpriority, &newpattern, buf); \
79 ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
80 if (!strcasecmp(newcontext, context)) return -1
83 static char *loopback_helper(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 memset(buf
, 0, buflen
);
91 AST_LIST_HEAD_INIT_NOLOCK(&headp
);
92 AST_LIST_INSERT_HEAD(&headp
, ast_var_assign("EXTEN", exten
), entries
);
93 AST_LIST_INSERT_HEAD(&headp
, ast_var_assign("CONTEXT", context
), entries
);
94 AST_LIST_INSERT_HEAD(&headp
, ast_var_assign("PRIORITY", tmp
), entries
);
95 /* Substitute variables */
96 pbx_substitute_variables_varshead(&headp
, data
, buf
, buflen
);
98 while ((newvariable
= AST_LIST_REMOVE_HEAD(&headp
, entries
)))
99 ast_var_delete(newvariable
);
103 static void loopback_subst(char **newexten
, char **newcontext
, int *priority
, char **newpattern
, char *buf
)
107 *newpattern
= strchr(buf
, '/');
109 *(*newpattern
)++ = '\0';
110 con
= strchr(buf
, '@');
113 pri
= strchr(con
, ':');
115 pri
= strchr(buf
, ':');
116 if (!ast_strlen_zero(buf
))
118 if (!ast_strlen_zero(con
))
120 if (!ast_strlen_zero(pri
))
121 sscanf(pri
, "%d", priority
);
124 static int loopback_exists(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, const char *callerid
, const char *data
)
127 res
= ast_exists_extension(chan
, newcontext
, newexten
, newpriority
, callerid
);
128 if (newpattern
&& !ast_extension_match(newpattern
, exten
))
133 static int loopback_canmatch(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, const char *callerid
, const char *data
)
136 res
= ast_canmatch_extension(chan
, newcontext
, newexten
, newpriority
, callerid
);
137 if (newpattern
&& !ast_extension_match(newpattern
, exten
))
142 static int loopback_exec(struct ast_channel
*chan
, const char *context
, const char *exten
, int priority
, const char *callerid
, const char *data
)
145 res
= ast_spawn_extension(chan
, newcontext
, newexten
, newpriority
, callerid
);
146 /* XXX hmmm... res is overridden ? */
147 if (newpattern
&& !ast_extension_match(newpattern
, exten
))
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 ast_register_switch(&loopback_switch
);
183 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Loopback Switch");