(closes issue #12362) [redo of 113012]
[asterisk-bristuff.git] / pbx / pbx_realtime.c
blobb9be0d456f307facaf3200edf94fff7559b58c68
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 <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
36 #include "asterisk/file.h"
37 #include "asterisk/logger.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/config.h"
40 #include "asterisk/options.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/module.h"
43 #include "asterisk/frame.h"
44 #include "asterisk/term.h"
45 #include "asterisk/manager.h"
46 #include "asterisk/file.h"
47 #include "asterisk/cli.h"
48 #include "asterisk/lock.h"
49 #include "asterisk/md5.h"
50 #include "asterisk/linkedlists.h"
51 #include "asterisk/chanvars.h"
52 #include "asterisk/sched.h"
53 #include "asterisk/io.h"
54 #include "asterisk/utils.h"
55 #include "asterisk/crypto.h"
56 #include "asterisk/astdb.h"
58 #define MODE_MATCH 0
59 #define MODE_MATCHMORE 1
60 #define MODE_CANMATCH 2
62 #define EXT_DATA_SIZE 256
65 /* Realtime switch looks up extensions in the supplied realtime table.
67 [context@][realtimetable][/options]
69 If the realtimetable is omitted it is assumed to be "extensions". If no context is
70 specified the context is assumed to be whatever is the container.
72 The realtime table should have entries for context,exten,priority,app,args
74 The realtime table currently does not support callerid fields.
79 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
81 struct ast_variable *var;
82 struct ast_config *cfg;
83 char pri[20];
84 char *ematch;
85 char rexten[AST_MAX_EXTENSION + 20]="";
86 int match;
87 snprintf(pri, sizeof(pri), "%d", priority);
88 switch(mode) {
89 case MODE_MATCHMORE:
90 ematch = "exten LIKE";
91 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
92 break;
93 case MODE_CANMATCH:
94 ematch = "exten LIKE";
95 snprintf(rexten, sizeof(rexten), "%s%%", exten);
96 break;
97 case MODE_MATCH:
98 default:
99 ematch = "exten";
100 ast_copy_string(rexten, exten, sizeof(rexten));
102 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
103 if (!var) {
104 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);
105 if (cfg) {
106 char *cat = ast_category_browse(cfg, NULL);
108 while(cat) {
109 switch(mode) {
110 case MODE_MATCHMORE:
111 match = ast_extension_close(cat, exten, 1);
112 break;
113 case MODE_CANMATCH:
114 match = ast_extension_close(cat, exten, 0);
115 break;
116 case MODE_MATCH:
117 default:
118 match = ast_extension_match(cat, exten);
120 if (match) {
121 var = ast_category_detach_variables(ast_category_get(cfg, cat));
122 break;
124 cat = ast_category_browse(cfg, cat);
126 ast_config_destroy(cfg);
129 return var;
132 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
134 const char *ctx = NULL;
135 char *table;
136 struct ast_variable *var=NULL;
137 char *buf = ast_strdupa(data);
138 if (buf) {
139 char *opts = strchr(buf, '/');
140 if (opts)
141 *opts++ = '\0';
142 table = strchr(buf, '@');
143 if (table) {
144 *table++ = '\0';
145 ctx = buf;
147 ctx = S_OR(ctx, context);
148 table = S_OR(table, "extensions");
149 var = realtime_switch_common(table, ctx, exten, priority, mode);
151 return var;
154 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
156 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
157 if (var) {
158 ast_variables_destroy(var);
159 return 1;
161 return 0;
164 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
166 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
167 if (var) {
168 ast_variables_destroy(var);
169 return 1;
171 return 0;
174 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
176 int res = -1;
177 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
179 if (var) {
180 char *tmp="";
181 char *app = NULL;
182 struct ast_variable *v;
184 for (v = var; v ; v = v->next) {
185 if (!strcasecmp(v->name, "app"))
186 app = ast_strdupa(v->value);
187 else if (!strcasecmp(v->name, "appdata"))
188 tmp = ast_strdupa(v->value);
190 ast_variables_destroy(var);
191 if (!ast_strlen_zero(app)) {
192 struct ast_app *a = pbx_findapp(app);
193 if (a) {
194 char appdata[512]="";
195 char tmp1[80];
196 char tmp2[80];
197 char tmp3[EXT_DATA_SIZE];
199 if(!ast_strlen_zero(tmp))
200 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
201 if (option_verbose > 2)
202 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\")\n",
203 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
204 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
205 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
206 manager_event(EVENT_FLAG_CALL, "Newexten",
207 "Channel: %s\r\n"
208 "Context: %s\r\n"
209 "Extension: %s\r\n"
210 "Priority: %d\r\n"
211 "Application: %s\r\n"
212 "AppData: %s\r\n"
213 "Uniqueid: %s\r\n",
214 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
216 res = pbx_exec(chan, a, appdata);
217 } else
218 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
219 } else {
220 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
223 return res;
226 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
228 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
229 if (var) {
230 ast_variables_destroy(var);
231 return 1;
233 return 0;
236 static struct ast_switch realtime_switch =
238 name: "Realtime",
239 description: "Realtime Dialplan Switch",
240 exists: realtime_exists,
241 canmatch: realtime_canmatch,
242 exec: realtime_exec,
243 matchmore: realtime_matchmore,
246 static int unload_module(void)
248 ast_unregister_switch(&realtime_switch);
249 return 0;
252 static int load_module(void)
254 ast_register_switch(&realtime_switch);
255 return 0;
258 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");