6b1c4511a6e4c7bc63b4754bf9a54378cafbeb74
[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 <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/term.h"
44 #include "asterisk/manager.h"
45 #include "asterisk/file.h"
46 #include "asterisk/cli.h"
47 #include "asterisk/lock.h"
48 #include "asterisk/md5.h"
49 #include "asterisk/linkedlists.h"
50 #include "asterisk/chanvars.h"
51 #include "asterisk/sched.h"
52 #include "asterisk/io.h"
53 #include "asterisk/utils.h"
54 #include "asterisk/crypto.h"
55 #include "asterisk/astdb.h"
56
57 #define MODE_MATCH              0
58 #define MODE_MATCHMORE  1
59 #define MODE_CANMATCH   2
60
61 #define EXT_DATA_SIZE 256
62
63 static char *tdesc = "Realtime Switch";
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         char *buf; \
81         char *opts; \
82         const char *cxt; \
83         char *table; \
84         int res=-1; \
85         struct ast_variable *var=NULL; \
86         buf = ast_strdupa(data); \
87         if (buf) { \
88                 opts = strchr(buf, '/'); \
89                 if (opts) { \
90                         *opts='\0'; \
91                         opts++; \
92                 } else \
93                         opts=""; \
94                 table = strchr(buf, '@'); \
95                 if (table) { \
96                         *table = '\0'; \
97                         table++;\
98                         cxt = buf; \
99                 } else cxt = NULL; \
100                 if (ast_strlen_zero(cxt)) \
101                         cxt = context;\
102                 if (ast_strlen_zero(table)) \
103                         table = "extensions"; \
104                 var = realtime_switch_common(table, cxt, exten, priority, mode); \
105         } else \
106                 res = -1; 
107
108 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
109 {
110         struct ast_variable *var;
111         struct ast_config *cfg;
112         char pri[20];
113         char *ematch;
114         char rexten[AST_MAX_EXTENSION + 20]="";
115         int match;
116         snprintf(pri, sizeof(pri), "%d", priority);
117         switch(mode) {
118         case MODE_MATCHMORE:
119                 ematch = "exten LIKE";
120                 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
121                 break;
122         case MODE_CANMATCH:
123                 ematch = "exten LIKE";
124                 snprintf(rexten, sizeof(rexten), "%s%%", exten);
125                 break;
126         case MODE_MATCH:
127         default:
128                 ematch = "exten";
129                 strncpy(rexten, exten, sizeof(rexten) - 1);
130         }
131         var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
132         if (!var) {
133                 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);     
134                 if (cfg) {
135                         char *cat = ast_category_browse(cfg, NULL);
136
137                         while(cat) {
138                                 switch(mode) {
139                                 case MODE_MATCHMORE:
140                                         match = ast_extension_close(cat, exten, 1);
141                                         break;
142                                 case MODE_CANMATCH:
143                                         match = ast_extension_close(cat, exten, 0);
144                                         break;
145                                 case MODE_MATCH:
146                                 default:
147                                         match = ast_extension_match(cat, exten);
148                                 }
149                                 if (match) {
150                                         var = ast_category_detach_variables(ast_category_get(cfg, cat));
151                                         break;
152                                 }
153                                 cat = ast_category_browse(cfg, cat);
154                         }
155                         ast_config_destroy(cfg);
156                 }
157         }
158         return var;
159 }
160
161 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
162 {
163         REALTIME_COMMON(MODE_MATCH);
164         if (var) ast_variables_destroy(var);
165         if (var)
166                 res = 1;
167         return res > 0 ? res : 0;
168 }
169
170 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
171 {
172         REALTIME_COMMON(MODE_CANMATCH);
173         if (var) ast_variables_destroy(var);
174         if (var)
175                 res = 1;
176         return res > 0 ? res : 0;
177 }
178
179 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, int newstack, const char *data)
180 {
181         char app[256];
182         char appdata[512]="";
183         char *tmp="";
184     char tmp1[80];
185     char tmp2[80];
186     char tmp3[EXT_DATA_SIZE];
187         struct ast_app *a;
188         struct ast_variable *v;
189         REALTIME_COMMON(MODE_MATCH);
190         if (var) {
191                 v = var;
192                 while(v) {
193                         if (!strcasecmp(v->name, "app"))
194                                 strncpy(app, v->value, sizeof(app) -1 );
195                         else if (!strcasecmp(v->name, "appdata"))
196                                 tmp = ast_strdupa(v->value);
197                         v = v->next;
198                 }
199                 ast_variables_destroy(var);
200                 if (!ast_strlen_zero(app)) {
201                         a = pbx_findapp(app);
202                         if (a) {
203                                 if(!ast_strlen_zero(tmp))
204                                    pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
205                 if (option_verbose > 2)
206                                         ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\")\n",
207                                                                  term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
208                                                                  term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
209                                                                  term_color(tmp3, (!ast_strlen_zero(appdata) ? (char *)appdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
210                 manager_event(EVENT_FLAG_CALL, "Newexten",
211                                                           "Channel: %s\r\n"
212                                                           "Context: %s\r\n"
213                                                           "Extension: %s\r\n"
214                                                           "Priority: %d\r\n"
215                                                           "Application: %s\r\n"
216                                                           "AppData: %s\r\n"
217                                                           "Uniqueid: %s\r\n",
218                                                           chan->name, chan->context, chan->exten, chan->priority, app, appdata ? appdata : "(NULL)", chan->uniqueid);
219                                 
220                                 res = pbx_exec(chan, a, appdata, newstack);
221                         } else
222                                 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
223                 }
224         }
225         return res;
226 }
227
228 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
229 {
230         REALTIME_COMMON(MODE_MATCHMORE);
231         if (var) ast_variables_destroy(var);
232         if (var)
233                 res = 1;
234         return res > 0 ? res : 0;
235 }
236
237 static struct ast_switch realtime_switch =
238 {
239         name:                   "Realtime",
240         description:                    "Realtime Dialplan Switch",
241         exists:                 realtime_exists,
242         canmatch:               realtime_canmatch,
243         exec:                   realtime_exec,
244         matchmore:              realtime_matchmore,
245 };
246
247 char *description(void)
248 {
249         return tdesc;
250 }
251
252 int usecount(void)
253 {
254         return 1;
255 }
256
257 char *key()
258 {
259         return ASTERISK_GPL_KEY;
260 }
261
262 int unload_module(void)
263 {
264         ast_unregister_switch(&realtime_switch);
265         return 0;
266 }
267
268 int load_module(void)
269 {
270         ast_register_switch(&realtime_switch);
271         return 0;
272 }
273