more errno.h removal
[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 "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"
47
48
49 /* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
50    the data passed to it to try to get a string of the form:
51
52         [exten]@context[:priority][/extramatch]
53    
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!)
60
61 */
62
63
64 #define LOOPBACK_COMMON \
65         char buf[1024]; \
66         int res; \
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
74
75
76 static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
77 {
78         struct ast_var_t *newvariable;
79         struct varshead headp;
80         char tmp[80];
81
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);
89         /* free the list */
90         while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
91                 ast_var_delete(newvariable);
92         return buf;
93 }
94
95 static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
96 {
97         char *con;
98         char *pri;
99         *newpattern = strchr(buf, '/');
100         if (*newpattern)
101                 *(*newpattern)++ = '\0';
102         con = strchr(buf, '@');
103         if (con) {
104                 *con++ = '\0';
105                 pri = strchr(con, ':');
106         } else
107                 pri = strchr(buf, ':');
108         if (!ast_strlen_zero(buf))
109                 *newexten = buf;
110         if (!ast_strlen_zero(con))
111                 *newcontext = con;
112         if (!ast_strlen_zero(pri))
113                 sscanf(pri, "%d", priority);
114 }
115
116 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
117 {
118         LOOPBACK_COMMON;
119         res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
120         if (newpattern && !ast_extension_match(newpattern, exten))
121                 res = 0;
122         return res;
123 }
124
125 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
126 {
127         LOOPBACK_COMMON;
128         res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
129         if (newpattern && !ast_extension_match(newpattern, exten))
130                 res = 0;
131         return res;
132 }
133
134 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
135 {
136         int found;
137         LOOPBACK_COMMON;
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))
141                 res = -1;
142         return res;
143 }
144
145 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
146 {
147         LOOPBACK_COMMON;
148         res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
149         if (newpattern && !ast_extension_match(newpattern, exten))
150                 res = 0;
151         return res;
152 }
153
154 static struct ast_switch loopback_switch =
155 {
156         name:                   "Loopback",
157         description:            "Loopback Dialplan Switch",
158         exists:                 loopback_exists,
159         canmatch:               loopback_canmatch,
160         exec:                   loopback_exec,
161         matchmore:              loopback_matchmore,
162 };
163
164 static int unload_module(void)
165 {
166         ast_unregister_switch(&loopback_switch);
167         return 0;
168 }
169
170 static int load_module(void)
171 {
172         ast_register_switch(&loopback_switch);
173         return 0;
174 }
175
176 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");