remove extraneous svn:executable properties
[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 static char *tdesc = "Loopback Switch";
56
57 /* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
58    the data passed to it to try to get a string of the form:
59
60         [exten]@context[:priority][/extramatch]
61    
62    Where exten, context, and priority are another extension, context, and priority
63    to lookup and "extramatch" is an extra match restriction the *original* number 
64    must fit if  specified.  The "extramatch" begins with _ like an exten pattern
65    if it is specified.  Note that the search context MUST be a different context
66    from the current context or the search will not succeed in an effort to reduce
67    the likelihood of loops (they're still possible if you try hard, so be careful!)
68
69 */
70
71
72 #define LOOPBACK_COMMON \
73         char buf[1024]; \
74         int res; \
75         char *newexten=(char *)exten, *newcontext=(char *)context; \
76         int newpriority=priority; \
77         char *newpattern=NULL; \
78         loopback_helper(buf, sizeof(buf), exten, context, priority, data); \
79         loopback_subst(&newexten, &newcontext, &newpriority, &newpattern, buf); \
80         ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
81         if (!strcasecmp(newcontext, context)) return -1
82
83
84 static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
85 {
86         struct ast_var_t *newvariable;
87         struct varshead headp;
88         char tmp[80];
89
90         snprintf(tmp, sizeof(tmp), "%d", priority);
91         memset(buf, 0, buflen);
92         AST_LIST_HEAD_INIT_NOLOCK(&headp);
93         newvariable = ast_var_assign("EXTEN", exten);
94         AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
95         newvariable = ast_var_assign("CONTEXT", context);
96         AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
97         newvariable = ast_var_assign("PRIORITY", tmp);
98         AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
99         pbx_substitute_variables_varshead(&headp, data, buf, buflen);
100         /* Substitute variables */
101         while (!AST_LIST_EMPTY(&headp)) {           /* List Deletion. */
102                 newvariable = AST_LIST_REMOVE_HEAD(&headp, entries);
103                 ast_var_delete(newvariable);
104         }
105         return buf;
106 }
107
108 static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
109 {
110         char *con;
111         char *pri;
112         *newpattern = strchr(buf, '/');
113         if (*newpattern) {
114                 *(*newpattern) = '\0';
115                 (*newpattern)++;
116         }
117         con = strchr(buf, '@');
118         if (con) {
119                 *con = '\0';
120                 con++;
121                 pri = strchr(con, ':');
122         } else
123                 pri = strchr(buf, ':');
124         if (!ast_strlen_zero(buf))
125                 *newexten = buf;
126         if (!ast_strlen_zero(con))
127                 *newcontext = con;
128         if (!ast_strlen_zero(pri))
129                 sscanf(pri, "%d", priority);
130 }
131
132 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
133 {
134         LOOPBACK_COMMON;
135         res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
136         if (newpattern && !ast_extension_match(newpattern, exten))
137                 res = 0;
138         return res;
139 }
140
141 static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
142 {
143         LOOPBACK_COMMON;
144         res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
145         if (newpattern && !ast_extension_match(newpattern, exten))
146                 res = 0;
147         return res;
148 }
149
150 static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, int newstack, const char *data)
151 {
152         LOOPBACK_COMMON;
153         if (newstack)
154                 res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid);
155         else
156                 res = ast_exec_extension(chan, newcontext, newexten, newpriority, callerid);
157         if (newpattern && !ast_extension_match(newpattern, exten))
158                 res = -1;
159         return res;
160 }
161
162 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
163 {
164         LOOPBACK_COMMON;
165         res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
166         if (newpattern && !ast_extension_match(newpattern, exten))
167                 res = 0;
168         return res;
169 }
170
171 static struct ast_switch loopback_switch =
172 {
173         name:                   "Loopback",
174         description:                    "Loopback Dialplan Switch",
175         exists:                 loopback_exists,
176         canmatch:               loopback_canmatch,
177         exec:                   loopback_exec,
178         matchmore:              loopback_matchmore,
179 };
180
181 char *description(void)
182 {
183         return tdesc;
184 }
185
186 int usecount(void)
187 {
188         return 1;
189 }
190
191 char *key()
192 {
193         return ASTERISK_GPL_KEY;
194 }
195
196 int unload_module(void)
197 {
198         ast_unregister_switch(&loopback_switch);
199         return 0;
200 }
201
202 int load_module(void)
203 {
204         ast_register_switch(&loopback_switch);
205         return 0;
206 }
207