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 /* 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;
76 char rexten[AST_MAX_EXTENSION + 20]="";
78 snprintf(pri, sizeof(pri), "%d", priority);
81 ematch = "exten LIKE";
82 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
85 ematch = "exten LIKE";
86 snprintf(rexten, sizeof(rexten), "%s%%", exten);
91 ast_copy_string(rexten, exten, sizeof(rexten));
93 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL);
95 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL);
97 char *cat = ast_category_browse(cfg, NULL);
102 match = ast_extension_close(cat, exten, 1);
105 match = ast_extension_close(cat, exten, 0);
109 match = ast_extension_match(cat, exten);
112 var = ast_category_detach_variables(ast_category_get(cfg, cat));
115 cat = ast_category_browse(cfg, cat);
117 ast_config_destroy(cfg);
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;
127 struct ast_variable *var=NULL;
128 char *buf = ast_strdupa(data);
130 char *opts = strchr(buf, '/');
133 table = strchr(buf, '@');
138 ctx = S_OR(ctx, context);
139 table = S_OR(table, "extensions");
140 var = realtime_switch_common(table, ctx, exten, priority, mode);
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);
149 ast_variables_destroy(var);
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);
159 ast_variables_destroy(var);
165 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
168 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
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) {
182 tmp = alloca(strlen(v->value) * 2 + 1);
183 for (ptr = tmp; *v->value; v->value++) {
184 if (*v->value == ',') {
187 } else if (*v->value == '|' && !in) {
193 /* Don't escape '|', meaning 'or', inside expressions ($[ ]) */
194 if (v->value[0] == '[' && v->value[-1] == '$') {
196 } else if (v->value[0] == ']' && in) {
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);
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",
227 "Application: %s\r\n"
231 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid, agi_state(chan));
233 res = pbx_exec(chan, a, appdata);
235 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
237 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
243 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
245 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
247 ast_variables_destroy(var);
253 static struct ast_switch realtime_switch =
256 description: "Realtime Dialplan Switch",
257 exists: realtime_exists,
258 canmatch: realtime_canmatch,
260 matchmore: realtime_matchmore,
263 static int unload_module(void)
265 ast_unregister_switch(&realtime_switch);
269 static int load_module(void)
271 if (ast_register_switch(&realtime_switch))
272 return AST_MODULE_LOAD_FAILURE;
273 return AST_MODULE_LOAD_SUCCESS;
276 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");