Adding support for "urgent" voicemail messages. Messages which are
[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/pbx.h"
34 #include "asterisk/module.h"
35 #include "asterisk/frame.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/lock.h"
38 #include "asterisk/md5.h"
39 #include "asterisk/linkedlists.h"
40 #include "asterisk/chanvars.h"
41 #include "asterisk/sched.h"
42 #include "asterisk/io.h"
43 #include "asterisk/utils.h"
44 #include "asterisk/crypto.h"
45 #include "asterisk/astdb.h"
46
47
48 /* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
49    the data passed to it to try to get a string of the form:
50
51         [exten]@context[:priority][/extramatch]
52    
53    Where exten, context, and priority are another extension, context, and priority
54    to lookup and "extramatch" is an extra match restriction the *original* number 
55    must fit if  specified.  The "extramatch" begins with _ like an exten pattern
56    if it is specified.  Note that the search context MUST be a different context
57    from the current context or the search will not succeed in an effort to reduce
58    the likelihood of loops (they're still possible if you try hard, so be careful!)
59
60 */
61
62
63 #define LOOPBACK_COMMON \
64         char buf[1024]; \
65         int res; \
66         char *newexten=(char *)exten, *newcontext=(char *)context; \
67         int newpriority=priority; \
68         char *newpattern=NULL; \
69         loopback_helper(buf, sizeof(buf), exten, context, priority, data); \
70         loopback_subst(&newexten, &newcontext, &newpriority, &newpattern, buf); \
71         ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
72         if (!strcasecmp(newcontext, context)) return -1
73
74
75 static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
76 {
77         struct ast_var_t *newvariable;
78         struct varshead headp;
79         char tmp[80];
80
81         snprintf(tmp, sizeof(tmp), "%d", priority);
82         AST_LIST_HEAD_INIT_NOLOCK(&headp);
83         AST_LIST_INSERT_HEAD(&headp, ast_var_assign("EXTEN", exten), entries);
84         AST_LIST_INSERT_HEAD(&headp, ast_var_assign("CONTEXT", context), entries);
85         AST_LIST_INSERT_HEAD(&headp, ast_var_assign("PRIORITY", tmp), entries);
86         /* Substitute variables */
87         pbx_substitute_variables_varshead(&headp, data, buf, buflen);
88         /* free the list */
89         while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
90                 ast_var_delete(newvariable);
91         return buf;
92 }
93
94 static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
95 {
96         char *con;
97         char *pri;
98         *newpattern = strchr(buf, '/');
99         if (*newpattern)
100                 *(*newpattern)++ = '\0';
101         con = strchr(buf, '@');
102         if (con) {
103                 *con++ = '\0';
104                 pri = strchr(con, ':');
105         } else
106                 pri = strchr(buf, ':');
107         if (!ast_strlen_zero(buf))
108                 *newexten = buf;
109         if (!ast_strlen_zero(con))
110                 *newcontext = con;
111         if (!ast_strlen_zero(pri))
112                 sscanf(pri, "%d", priority);
113 }
114
115 static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
116 {
117         LOOPBACK_COMMON;
118         res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
119         if (newpattern && !ast_extension_match(newpattern, exten))
120                 res = 0;
121         return res;
122 }
123
124 static int loopback_canmatch(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_canmatch_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_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
134 {
135         int found;
136         LOOPBACK_COMMON;
137         res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0);
138         /* XXX hmmm... res is overridden ? */
139         if (newpattern && !ast_extension_match(newpattern, exten))
140                 res = -1;
141         return res;
142 }
143
144 static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
145 {
146         LOOPBACK_COMMON;
147         res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
148         if (newpattern && !ast_extension_match(newpattern, exten))
149                 res = 0;
150         return res;
151 }
152
153 static struct ast_switch loopback_switch =
154 {
155         name:                   "Loopback",
156         description:            "Loopback Dialplan Switch",
157         exists:                 loopback_exists,
158         canmatch:               loopback_canmatch,
159         exec:                   loopback_exec,
160         matchmore:              loopback_matchmore,
161 };
162
163 static int unload_module(void)
164 {
165         ast_unregister_switch(&loopback_switch);
166         return 0;
167 }
168
169 static int load_module(void)
170 {
171         if (ast_register_switch(&loopback_switch))
172                 return AST_MODULE_LOAD_FAILURE;
173         return AST_MODULE_LOAD_SUCCESS;
174 }
175
176 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");