remove a bunch of duplicate includes
[asterisk/asterisk.git] / pbx / pbx_loopback.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Loopback PBX Module
22  *
23  */
24
25 #include "asterisk.h"
26
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
29 #include <errno.h>
30
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"
49
50
51 /* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
52    the data passed to it to try to get a string of the form:
53
54         [exten]@context[:priority][/extramatch]
55    
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!)
62
63 */
64
65
66 #define LOOPBACK_COMMON \
67         char buf[1024]; \
68         int res; \
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
76
77
78 static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
79 {
80         struct ast_var_t *newvariable;
81         struct varshead headp;
82         char tmp[80];
83
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);
91         /* free the list */
92         while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
93                 ast_var_delete(newvariable);
94         return buf;
95 }
96
97 static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
98 {
99         char *con;
100         char *pri;
101         *newpattern = strchr(buf, '/');
102         if (*newpattern)
103                 *(*newpattern)++ = '\0';
104         con = strchr(buf, '@');
105         if (con) {
106                 *con++ = '\0';
107                 pri = strchr(con, ':');
108         } else
109                 pri = strchr(buf, ':');
110         if (!ast_strlen_zero(buf))
111                 *newexten = buf;
112         if (!ast_strlen_zero(con))
113                 *newcontext = con;
114         if (!ast_strlen_zero(pri))
115                 sscanf(pri, "%d", priority);
116 }
117
118 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
119 {
120         LOOPBACK_COMMON;
121         res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
122         if (newpattern && !ast_extension_match(newpattern, exten))
123                 res = 0;
124         return res;
125 }
126
127 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
128 {
129         LOOPBACK_COMMON;
130         res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
131         if (newpattern && !ast_extension_match(newpattern, exten))
132                 res = 0;
133         return res;
134 }
135
136 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
137 {
138         int found;
139         LOOPBACK_COMMON;
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))
143                 res = -1;
144         return res;
145 }
146
147 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
148 {
149         LOOPBACK_COMMON;
150         res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
151         if (newpattern && !ast_extension_match(newpattern, exten))
152                 res = 0;
153         return res;
154 }
155
156 static struct ast_switch loopback_switch =
157 {
158         name:                   "Loopback",
159         description:            "Loopback Dialplan Switch",
160         exists:                 loopback_exists,
161         canmatch:               loopback_canmatch,
162         exec:                   loopback_exec,
163         matchmore:              loopback_matchmore,
164 };
165
166 static int unload_module(void)
167 {
168         ast_unregister_switch(&loopback_switch);
169         return 0;
170 }
171
172 static int load_module(void)
173 {
174         ast_register_switch(&loopback_switch);
175         return 0;
176 }
177
178 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");