31abe065f4a0eb2332355eb8924788b0b1ce874d
[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 "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
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 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
80 {
81         struct ast_variable *var;
82         struct ast_config *cfg;
83         char pri[20];
84         char *ematch;
85         char rexten[AST_MAX_EXTENSION + 20]="";
86         int match;
87         snprintf(pri, sizeof(pri), "%d", priority);
88         switch(mode) {
89         case MODE_MATCHMORE:
90                 ematch = "exten LIKE";
91                 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
92                 break;
93         case MODE_CANMATCH:
94                 ematch = "exten LIKE";
95                 snprintf(rexten, sizeof(rexten), "%s%%", exten);
96                 break;
97         case MODE_MATCH:
98         default:
99                 ematch = "exten";
100                 strncpy(rexten, exten, sizeof(rexten) - 1);
101         }
102         var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
103         if (!var) {
104                 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);     
105                 if (cfg) {
106                         char *cat = ast_category_browse(cfg, NULL);
107
108                         while(cat) {
109                                 switch(mode) {
110                                 case MODE_MATCHMORE:
111                                         match = ast_extension_close(cat, exten, 1);
112                                         break;
113                                 case MODE_CANMATCH:
114                                         match = ast_extension_close(cat, exten, 0);
115                                         break;
116                                 case MODE_MATCH:
117                                 default:
118                                         match = ast_extension_match(cat, exten);
119                                 }
120                                 if (match) {
121                                         var = ast_category_detach_variables(ast_category_get(cfg, cat));
122                                         break;
123                                 }
124                                 cat = ast_category_browse(cfg, cat);
125                         }
126                         ast_config_destroy(cfg);
127                 }
128         }
129         return var;
130 }
131
132 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
133 {
134         const char *ctx = NULL;
135         char *table;
136         struct ast_variable *var=NULL;
137         char *buf = ast_strdupa(data);
138         if (buf) {
139                 char *opts = strchr(buf, '/');
140                 if (opts)
141                         *opts++ = '\0';
142                 table = strchr(buf, '@');
143                 if (table) {
144                         *table++ = '\0';
145                         ctx = buf;
146                 }
147                 ctx = S_OR(ctx, context);
148                 table = S_OR(table, "extensions");
149                 var = realtime_switch_common(table, ctx, exten, priority, mode);
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         struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
157         if (var) {
158                 ast_variables_destroy(var);
159                 return 1;
160         }
161         return 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         struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
167         if (var) {
168                 ast_variables_destroy(var);
169                 return 1;
170         }
171         return 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         int res = -1;
177         struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
178
179         if (var) {
180                 char *tmp="";
181                 char app[256];
182                 struct ast_variable *v;
183
184                 for (v = var; v ; v = v->next) {
185                         if (!strcasecmp(v->name, "app"))
186                                 strncpy(app, v->value, sizeof(app) -1 );
187                         else if (!strcasecmp(v->name, "appdata"))
188                                 tmp = ast_strdupa(v->value);
189                 }
190                 ast_variables_destroy(var);
191                 if (!ast_strlen_zero(app)) {
192                         struct ast_app *a = pbx_findapp(app);
193                         if (a) {
194                                 char appdata[512]="";
195                                 char tmp1[80];
196                                 char tmp2[80];
197                                 char tmp3[EXT_DATA_SIZE];
198
199                                 if(!ast_strlen_zero(tmp))
200                                         pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
201                                 if (option_verbose > 2)
202                                         ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\")\n",
203                                                  term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
204                                                  term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
205                                                  term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
206                                 manager_event(EVENT_FLAG_CALL, "Newexten",
207                                                           "Channel: %s\r\n"
208                                                           "Context: %s\r\n"
209                                                           "Extension: %s\r\n"
210                                                           "Priority: %d\r\n"
211                                                           "Application: %s\r\n"
212                                                           "AppData: %s\r\n"
213                                                           "Uniqueid: %s\r\n",
214                                                           chan->name, chan->context, chan->exten, chan->priority, app, appdata ? appdata : "(NULL)", chan->uniqueid);
215                                 
216                                 res = pbx_exec(chan, a, appdata);
217                         } else
218                                 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
219                 }
220         }
221         return res;
222 }
223
224 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
225 {
226         struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
227         if (var) {
228                 ast_variables_destroy(var);
229                 return 1;
230         }
231         return 0;
232 }
233
234 static struct ast_switch realtime_switch =
235 {
236         name:                   "Realtime",
237         description:            "Realtime Dialplan Switch",
238         exists:                 realtime_exists,
239         canmatch:               realtime_canmatch,
240         exec:                   realtime_exec,
241         matchmore:              realtime_matchmore,
242 };
243
244 static int unload_module(void)
245 {
246         ast_unregister_switch(&realtime_switch);
247         return 0;
248 }
249
250 static int load_module(void)
251 {
252         ast_register_switch(&realtime_switch);
253         return 0;
254 }
255
256 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");