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.
21 * \brief Realtime PBX Module
23 * \arg See also: \ref AstARA
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"
51 #define MODE_MATCHMORE 1
52 #define MODE_CANMATCH 2
54 #define EXT_DATA_SIZE 256
56 /* If set to 0, translate commas to "\," and pipes to "," */
57 static int compat16 = 1;
59 /* Realtime switch looks up extensions in the supplied realtime table.
61 [context@][realtimetable][/options]
63 If the realtimetable is omitted it is assumed to be "extensions". If no context is
64 specified the context is assumed to be whatever is the container.
66 The realtime table should have entries for context,exten,priority,app,args
68 The realtime table currently does not support callerid fields.
73 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
75 struct ast_variable *var;
76 struct ast_config *cfg;
79 char rexten[AST_MAX_EXTENSION + 20]="";
81 snprintf(pri, sizeof(pri), "%d", priority);
84 ematch = "exten LIKE";
85 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
88 ematch = "exten LIKE";
89 snprintf(rexten, sizeof(rexten), "%s%%", exten);
94 ast_copy_string(rexten, exten, sizeof(rexten));
96 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
98 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);
100 char *cat = ast_category_browse(cfg, NULL);
105 match = ast_extension_close(cat, exten, 1);
108 match = ast_extension_close(cat, exten, 0);
112 match = ast_extension_match(cat, exten);
115 var = ast_category_detach_variables(ast_category_get(cfg, cat));
118 cat = ast_category_browse(cfg, cat);
120 ast_config_destroy(cfg);
126 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
128 const char *ctx = NULL;
130 struct ast_variable *var=NULL;
131 char *buf = ast_strdupa(data);
133 char *opts = strchr(buf, '/');
136 table = strchr(buf, '@');
141 ctx = S_OR(ctx, context);
142 table = S_OR(table, "extensions");
143 var = realtime_switch_common(table, ctx, exten, priority, mode);
148 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
150 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
152 ast_variables_destroy(var);
158 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
160 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
162 ast_variables_destroy(var);
168 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
171 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
176 struct ast_variable *v;
178 for (v = var; v ; v = v->next) {
179 if (!strcasecmp(v->name, "app"))
180 app = ast_strdupa(v->value);
181 else if (!strcasecmp(v->name, "appdata")) {
184 tmp = alloca(strlen(v->value) * 2 + 1);
185 for (ptr = tmp; *v->value; v->value++) {
186 if (*v->value == ',') {
189 } else if (*v->value == '|') {
196 tmp = ast_strdupa(v->value);
200 ast_variables_destroy(var);
201 if (!ast_strlen_zero(app)) {
202 struct ast_app *a = pbx_findapp(app);
207 char tmp3[EXT_DATA_SIZE];
209 appdata[0] = 0; /* just in case the substitute var func isn't called */
210 if(!ast_strlen_zero(tmp))
211 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
212 ast_verb(3, "Executing %s(\"%s\", \"%s\")\n",
213 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
214 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
215 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
216 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
221 "Application: %s\r\n"
224 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
226 res = pbx_exec(chan, a, appdata);
228 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
230 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
236 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
238 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
240 ast_variables_destroy(var);
246 static struct ast_switch realtime_switch =
249 description: "Realtime Dialplan Switch",
250 exists: realtime_exists,
251 canmatch: realtime_canmatch,
253 matchmore: realtime_matchmore,
256 static int unload_module(void)
258 ast_unregister_switch(&realtime_switch);
262 static int load_module(void)
264 struct ast_flags flags = { 0 };
265 struct ast_config *cfg = ast_config_load("pbx_realtime.conf", flags);
267 const char *tmp = ast_variable_retrieve(cfg, "general", "compat");
268 if (tmp && strncmp(tmp, "1.6", 3)) {
273 ast_config_destroy(cfg);
276 if (ast_register_switch(&realtime_switch))
277 return AST_MODULE_LOAD_FAILURE;
278 return AST_MODULE_LOAD_SUCCESS;
281 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");