Grammar hax from Qwell
[asterisk-bristuff.git] / pbx / pbx_realtime.c
blob536ed9d27e5350aa3d53f6a60df7264c21580b34
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
19 /*! \file
21 * \brief Realtime PBX Module
23 * \arg See also: \ref AstARA
26 #include "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include "asterisk/file.h"
31 #include "asterisk/logger.h"
32 #include "asterisk/channel.h"
33 #include "asterisk/config.h"
34 #include "asterisk/pbx.h"
35 #include "asterisk/module.h"
36 #include "asterisk/frame.h"
37 #include "asterisk/term.h"
38 #include "asterisk/manager.h"
39 #include "asterisk/cli.h"
40 #include "asterisk/lock.h"
41 #include "asterisk/md5.h"
42 #include "asterisk/linkedlists.h"
43 #include "asterisk/chanvars.h"
44 #include "asterisk/sched.h"
45 #include "asterisk/io.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/crypto.h"
48 #include "asterisk/astdb.h"
50 #define MODE_MATCH 0
51 #define MODE_MATCHMORE 1
52 #define MODE_CANMATCH 2
54 #define EXT_DATA_SIZE 256
56 /* Realtime switch looks up extensions in the supplied realtime table.
58 [context@][realtimetable][/options]
60 If the realtimetable is omitted it is assumed to be "extensions". If no context is
61 specified the context is assumed to be whatever is the container.
63 The realtime table should have entries for context,exten,priority,app,args
65 The realtime table currently does not support callerid fields.
70 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
72 struct ast_variable *var;
73 struct ast_config *cfg;
74 char pri[20];
75 char *ematch;
76 char rexten[AST_MAX_EXTENSION + 20]="";
77 int match;
78 snprintf(pri, sizeof(pri), "%d", priority);
79 switch(mode) {
80 case MODE_MATCHMORE:
81 ematch = "exten LIKE";
82 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
83 break;
84 case MODE_CANMATCH:
85 ematch = "exten LIKE";
86 snprintf(rexten, sizeof(rexten), "%s%%", exten);
87 break;
88 case MODE_MATCH:
89 default:
90 ematch = "exten";
91 ast_copy_string(rexten, exten, sizeof(rexten));
93 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL);
94 if (!var) {
95 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL);
96 if (cfg) {
97 char *cat = ast_category_browse(cfg, NULL);
99 while(cat) {
100 switch(mode) {
101 case MODE_MATCHMORE:
102 match = ast_extension_close(cat, exten, 1);
103 break;
104 case MODE_CANMATCH:
105 match = ast_extension_close(cat, exten, 0);
106 break;
107 case MODE_MATCH:
108 default:
109 match = ast_extension_match(cat, exten);
111 if (match) {
112 var = ast_category_detach_variables(ast_category_get(cfg, cat));
113 break;
115 cat = ast_category_browse(cfg, cat);
117 ast_config_destroy(cfg);
120 return var;
123 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
125 const char *ctx = NULL;
126 char *table;
127 struct ast_variable *var=NULL;
128 char *buf = ast_strdupa(data);
129 if (buf) {
130 char *opts = strchr(buf, '/');
131 if (opts)
132 *opts++ = '\0';
133 table = strchr(buf, '@');
134 if (table) {
135 *table++ = '\0';
136 ctx = buf;
138 ctx = S_OR(ctx, context);
139 table = S_OR(table, "extensions");
140 var = realtime_switch_common(table, ctx, exten, priority, mode);
142 return var;
145 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
147 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
148 if (var) {
149 ast_variables_destroy(var);
150 return 1;
152 return 0;
155 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
157 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
158 if (var) {
159 ast_variables_destroy(var);
160 return 1;
162 return 0;
165 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
167 int res = -1;
168 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
170 if (var) {
171 char *tmp="";
172 char *app = NULL;
173 struct ast_variable *v;
175 for (v = var; v ; v = v->next) {
176 if (!strcasecmp(v->name, "app"))
177 app = ast_strdupa(v->value);
178 else if (!strcasecmp(v->name, "appdata")) {
179 if (ast_compat_pbx_realtime) {
180 char *ptr;
181 int in = 0;
182 tmp = alloca(strlen(v->value) * 2 + 1);
183 for (ptr = tmp; *v->value; v->value++) {
184 if (*v->value == ',') {
185 *ptr++ = '\\';
186 *ptr++ = ',';
187 } else if (*v->value == '|' && !in) {
188 *ptr++ = ',';
189 } else {
190 *ptr++ = *v->value;
193 /* Don't escape '|', meaning 'or', inside expressions ($[ ]) */
194 if (v->value[0] == '[' && v->value[-1] == '$') {
195 in++;
196 } else if (v->value[0] == ']' && in) {
197 in--;
200 *ptr = '\0';
201 } else {
202 tmp = ast_strdupa(v->value);
206 ast_variables_destroy(var);
207 if (!ast_strlen_zero(app)) {
208 struct ast_app *a = pbx_findapp(app);
209 if (a) {
210 char appdata[512];
211 char tmp1[80];
212 char tmp2[80];
213 char tmp3[EXT_DATA_SIZE];
215 appdata[0] = 0; /* just in case the substitute var func isn't called */
216 if(!ast_strlen_zero(tmp))
217 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
218 ast_verb(3, "Executing %s(\"%s\", \"%s\")\n",
219 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
220 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
221 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
222 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
223 "Channel: %s\r\n"
224 "Context: %s\r\n"
225 "Extension: %s\r\n"
226 "Priority: %d\r\n"
227 "Application: %s\r\n"
228 "AppData: %s\r\n"
229 "Uniqueid: %s\r\n",
230 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
232 res = pbx_exec(chan, a, appdata);
233 } else
234 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
235 } else {
236 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
239 return res;
242 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
244 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
245 if (var) {
246 ast_variables_destroy(var);
247 return 1;
249 return 0;
252 static struct ast_switch realtime_switch =
254 name: "Realtime",
255 description: "Realtime Dialplan Switch",
256 exists: realtime_exists,
257 canmatch: realtime_canmatch,
258 exec: realtime_exec,
259 matchmore: realtime_matchmore,
262 static int unload_module(void)
264 ast_unregister_switch(&realtime_switch);
265 return 0;
268 static int load_module(void)
270 if (ast_register_switch(&realtime_switch))
271 return AST_MODULE_LOAD_FAILURE;
272 return AST_MODULE_LOAD_SUCCESS;
275 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");