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
57 /* Realtime switch looks up extensions in the supplied realtime table.
59 [context@][realtimetable][/options]
61 If the realtimetable is omitted it is assumed to be "extensions". If no context is
62 specified the context is assumed to be whatever is the container.
64 The realtime table should have entries for context,exten,priority,app,args
66 The realtime table currently does not support callerid fields.
71 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
73 struct ast_variable *var;
74 struct ast_config *cfg;
77 char rexten[AST_MAX_EXTENSION + 20]="";
79 snprintf(pri, sizeof(pri), "%d", priority);
82 ematch = "exten LIKE";
83 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
86 ematch = "exten LIKE";
87 snprintf(rexten, sizeof(rexten), "%s%%", exten);
92 ast_copy_string(rexten, exten, sizeof(rexten));
94 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
96 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);
98 char *cat = ast_category_browse(cfg, NULL);
103 match = ast_extension_close(cat, exten, 1);
106 match = ast_extension_close(cat, exten, 0);
110 match = ast_extension_match(cat, exten);
113 var = ast_category_detach_variables(ast_category_get(cfg, cat));
116 cat = ast_category_browse(cfg, cat);
118 ast_config_destroy(cfg);
124 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
126 const char *ctx = NULL;
128 struct ast_variable *var=NULL;
129 char *buf = ast_strdupa(data);
131 char *opts = strchr(buf, '/');
134 table = strchr(buf, '@');
139 ctx = S_OR(ctx, context);
140 table = S_OR(table, "extensions");
141 var = realtime_switch_common(table, ctx, exten, priority, mode);
146 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
148 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
150 ast_variables_destroy(var);
156 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
158 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
160 ast_variables_destroy(var);
166 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
169 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
174 struct ast_variable *v;
176 for (v = var; v ; v = v->next) {
177 if (!strcasecmp(v->name, "app"))
178 app = ast_strdupa(v->value);
179 else if (!strcasecmp(v->name, "appdata"))
180 tmp = ast_strdupa(v->value);
182 ast_variables_destroy(var);
183 if (!ast_strlen_zero(app)) {
184 struct ast_app *a = pbx_findapp(app);
189 char tmp3[EXT_DATA_SIZE];
191 appdata[0] = 0; /* just in case the substitute var func isn't called */
192 if(!ast_strlen_zero(tmp))
193 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
194 ast_verb(3, "Executing %s(\"%s\", \"%s\")\n",
195 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
196 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
197 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
198 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
203 "Application: %s\r\n"
206 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
208 res = pbx_exec(chan, a, appdata);
210 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
212 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
218 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
220 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
222 ast_variables_destroy(var);
228 static struct ast_switch realtime_switch =
231 description: "Realtime Dialplan Switch",
232 exists: realtime_exists,
233 canmatch: realtime_canmatch,
235 matchmore: realtime_matchmore,
238 static int unload_module(void)
240 ast_unregister_switch(&realtime_switch);
244 static int load_module(void)
246 if (ast_register_switch(&realtime_switch))
247 return AST_MODULE_LOAD_FAILURE;
248 return AST_MODULE_LOAD_SUCCESS;
251 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");