This rather large commit changes the way modules are loaded.
[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 <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
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"
54
55
56 /* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
57    the data passed to it to try to get a string of the form:
58
59         [exten]@context[:priority][/extramatch]
60    
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!)
67
68 */
69
70
71 #define LOOPBACK_COMMON \
72         char buf[1024]; \
73         int res; \
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
81
82
83 static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
84 {
85         struct ast_var_t *newvariable;
86         struct varshead headp;
87         char tmp[80];
88
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);
97         /* free the list */
98         while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
99                 ast_var_delete(newvariable);
100         return buf;
101 }
102
103 static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
104 {
105         char *con;
106         char *pri;
107         *newpattern = strchr(buf, '/');
108         if (*newpattern)
109                 *(*newpattern)++ = '\0';
110         con = strchr(buf, '@');
111         if (con) {
112                 *con++ = '\0';
113                 pri = strchr(con, ':');
114         } else
115                 pri = strchr(buf, ':');
116         if (!ast_strlen_zero(buf))
117                 *newexten = buf;
118         if (!ast_strlen_zero(con))
119                 *newcontext = con;
120         if (!ast_strlen_zero(pri))
121                 sscanf(pri, "%d", priority);
122 }
123
124 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
125 {
126         LOOPBACK_COMMON;
127         res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
128         if (newpattern && !ast_extension_match(newpattern, exten))
129                 res = 0;
130         return res;
131 }
132
133 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
134 {
135         LOOPBACK_COMMON;
136         res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
137         if (newpattern && !ast_extension_match(newpattern, exten))
138                 res = 0;
139         return res;
140 }
141
142 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
143 {
144         LOOPBACK_COMMON;
145         res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid);
146         /* XXX hmmm... res is overridden ? */
147         if (newpattern && !ast_extension_match(newpattern, exten))
148                 res = -1;
149         return res;
150 }
151
152 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
153 {
154         LOOPBACK_COMMON;
155         res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
156         if (newpattern && !ast_extension_match(newpattern, exten))
157                 res = 0;
158         return res;
159 }
160
161 static struct ast_switch loopback_switch =
162 {
163         name:                   "Loopback",
164         description:                    "Loopback Dialplan Switch",
165         exists:                 loopback_exists,
166         canmatch:               loopback_canmatch,
167         exec:                   loopback_exec,
168         matchmore:              loopback_matchmore,
169 };
170
171 static const char *description(void)
172 {
173         return "Loopback Switch";
174 }
175
176 static const char *key(void)
177 {
178         return ASTERISK_GPL_KEY;
179 }
180
181 static int unload_module(void *mod)
182 {
183         ast_unregister_switch(&loopback_switch);
184         return 0;
185 }
186
187 static int load_module(void *mod)
188 {
189         ast_register_switch(&loopback_switch);
190         return 0;
191 }
192
193 /* XXX really no unload ? */
194 STD_MOD(MOD_1 | NO_USECOUNT | NO_UNLOAD, NULL, NULL, NULL);