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