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