d819233aeca15fcd89d63c89a9c210af30871e30
[asterisk/asterisk.git] / pbx / pbx_realtime.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 Realtime PBX Module
22  *
23  * \arg See also: \ref AstARA
24  */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/file.h"
37 #include "asterisk/logger.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/config.h"
40 #include "asterisk/options.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/module.h"
43 #include "asterisk/frame.h"
44 #include "asterisk/term.h"
45 #include "asterisk/manager.h"
46 #include "asterisk/file.h"
47 #include "asterisk/cli.h"
48 #include "asterisk/lock.h"
49 #include "asterisk/md5.h"
50 #include "asterisk/linkedlists.h"
51 #include "asterisk/chanvars.h"
52 #include "asterisk/sched.h"
53 #include "asterisk/io.h"
54 #include "asterisk/utils.h"
55 #include "asterisk/crypto.h"
56 #include "asterisk/astdb.h"
57
58 #define MODE_MATCH              0
59 #define MODE_MATCHMORE  1
60 #define MODE_CANMATCH   2
61
62 #define EXT_DATA_SIZE 256
63
64
65 /* Realtime switch looks up extensions in the supplied realtime table.
66
67         [context@][realtimetable][/options]
68
69         If the realtimetable is omitted it is assumed to be "extensions".  If no context is 
70         specified the context is assumed to be whatever is the container.
71
72         The realtime table should have entries for context,exten,priority,app,args
73         
74         The realtime table currently does not support callerid fields.
75
76 */
77
78
79 #define REALTIME_COMMON(mode)                           \
80         const char *ctx = NULL;                         \
81         char *table;                                    \
82         int res = -1;                                   \
83         struct ast_variable *var=NULL;                  \
84         char *buf = ast_strdupa(data);                  \
85         if (buf) {                                      \
86                 char *opts = strchr(buf, '/');          \
87                 if (opts)                               \
88                         *opts++ = '\0';                 \
89                 else                                    \
90                         opts="";                        \
91                 table = strchr(buf, '@');               \
92                 if (table) {                            \
93                         *table++ = '\0';                \
94                         ctx = buf;                      \
95                 }                                       \
96                 ctx = S_OR(ctx, context);               \
97                 table = S_OR(table, "extensions");      \
98                 var = realtime_switch_common(table, ctx, exten, priority, mode); \
99         }
100
101 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
102 {
103         struct ast_variable *var;
104         struct ast_config *cfg;
105         char pri[20];
106         char *ematch;
107         char rexten[AST_MAX_EXTENSION + 20]="";
108         int match;
109         snprintf(pri, sizeof(pri), "%d", priority);
110         switch(mode) {
111         case MODE_MATCHMORE:
112                 ematch = "exten LIKE";
113                 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
114                 break;
115         case MODE_CANMATCH:
116                 ematch = "exten LIKE";
117                 snprintf(rexten, sizeof(rexten), "%s%%", exten);
118                 break;
119         case MODE_MATCH:
120         default:
121                 ematch = "exten";
122                 strncpy(rexten, exten, sizeof(rexten) - 1);
123         }
124         var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
125         if (!var) {
126                 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);     
127                 if (cfg) {
128                         char *cat = ast_category_browse(cfg, NULL);
129
130                         while(cat) {
131                                 switch(mode) {
132                                 case MODE_MATCHMORE:
133                                         match = ast_extension_close(cat, exten, 1);
134                                         break;
135                                 case MODE_CANMATCH:
136                                         match = ast_extension_close(cat, exten, 0);
137                                         break;
138                                 case MODE_MATCH:
139                                 default:
140                                         match = ast_extension_match(cat, exten);
141                                 }
142                                 if (match) {
143                                         var = ast_category_detach_variables(ast_category_get(cfg, cat));
144                                         break;
145                                 }
146                                 cat = ast_category_browse(cfg, cat);
147                         }
148                         ast_config_destroy(cfg);
149                 }
150         }
151         return var;
152 }
153
154 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
155 {
156         REALTIME_COMMON(MODE_MATCH);
157         if (var)
158                 ast_variables_destroy(var);
159         if (var)
160                 res = 1;
161         return res > 0 ? res : 0;
162 }
163
164 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
165 {
166         REALTIME_COMMON(MODE_CANMATCH);
167         if (var)
168                 ast_variables_destroy(var);
169         if (var)
170                 res = 1;
171         return res > 0 ? res : 0;
172 }
173
174 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
175 {
176         char app[256];
177         char appdata[512]="";
178         char *tmp="";
179         char tmp1[80];
180         char tmp2[80];
181         char tmp3[EXT_DATA_SIZE];
182         struct ast_app *a;
183         struct ast_variable *v;
184         REALTIME_COMMON(MODE_MATCH);
185         if (var) {
186                 for (v = var; v ; v = v->next) {
187                         if (!strcasecmp(v->name, "app"))
188                                 strncpy(app, v->value, sizeof(app) -1 );
189                         else if (!strcasecmp(v->name, "appdata"))
190                                 tmp = ast_strdupa(v->value);
191                 }
192                 ast_variables_destroy(var);
193                 if (!ast_strlen_zero(app)) {
194                         a = pbx_findapp(app);
195                         if (a) {
196                                 if(!ast_strlen_zero(tmp))
197                                    pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
198                 if (option_verbose > 2)
199                                         ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\")\n",
200                                                                  term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
201                                                                  term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
202                                                                  term_color(tmp3, (!ast_strlen_zero(appdata) ? (char *)appdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
203                 manager_event(EVENT_FLAG_CALL, "Newexten",
204                                                           "Channel: %s\r\n"
205                                                           "Context: %s\r\n"
206                                                           "Extension: %s\r\n"
207                                                           "Priority: %d\r\n"
208                                                           "Application: %s\r\n"
209                                                           "AppData: %s\r\n"
210                                                           "Uniqueid: %s\r\n",
211                                                           chan->name, chan->context, chan->exten, chan->priority, app, appdata ? appdata : "(NULL)", chan->uniqueid);
212                                 
213                                 res = pbx_exec(chan, a, appdata);
214                         } else
215                                 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
216                 }
217         }
218         return res;
219 }
220
221 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
222 {
223         REALTIME_COMMON(MODE_MATCHMORE);
224         if (var)
225                 ast_variables_destroy(var);
226         if (var)
227                 res = 1;
228         return res > 0 ? res : 0;
229 }
230
231 static struct ast_switch realtime_switch =
232 {
233         name:                   "Realtime",
234         description:                    "Realtime Dialplan Switch",
235         exists:                 realtime_exists,
236         canmatch:               realtime_canmatch,
237         exec:                   realtime_exec,
238         matchmore:              realtime_matchmore,
239 };
240
241 static const char *description(void)
242 {
243         return "Realtime Switch";
244 }
245
246 static const char *key(void)
247 {
248         return ASTERISK_GPL_KEY;
249 }
250
251 static int unload_module(void *mod)
252 {
253         ast_unregister_switch(&realtime_switch);
254         return 0;
255 }
256
257 static int load_module(void *mod)
258 {
259         ast_register_switch(&realtime_switch);
260         return 0;
261 }
262
263 STD_MOD(MOD_1 | NO_USECOUNT | NO_UNLOAD, NULL, NULL, NULL);