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