00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 164485 $")
00029
00030 #include "asterisk/file.h"
00031 #include "asterisk/logger.h"
00032 #include "asterisk/channel.h"
00033 #include "asterisk/config.h"
00034 #include "asterisk/pbx.h"
00035 #include "asterisk/module.h"
00036 #include "asterisk/frame.h"
00037 #include "asterisk/term.h"
00038 #include "asterisk/manager.h"
00039 #include "asterisk/cli.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/md5.h"
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/chanvars.h"
00044 #include "asterisk/sched.h"
00045 #include "asterisk/io.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/crypto.h"
00048 #include "asterisk/astdb.h"
00049 #include "asterisk/app.h"
00050
00051 #define MODE_MATCH 0
00052 #define MODE_MATCHMORE 1
00053 #define MODE_CANMATCH 2
00054
00055 #define EXT_DATA_SIZE 256
00056
00057 enum {
00058 OPTION_PATTERNS_DISABLED = (1 << 0),
00059 } option_flags;
00060
00061 AST_APP_OPTIONS(switch_opts, {
00062 AST_APP_OPTION('p', OPTION_PATTERNS_DISABLED),
00063 });
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode, struct ast_flags flags)
00080 {
00081 struct ast_variable *var;
00082 struct ast_config *cfg;
00083 char pri[20];
00084 char *ematch;
00085 char rexten[AST_MAX_EXTENSION + 20]="";
00086 int match;
00087
00088
00089
00090 if (priority < 0) {
00091 return NULL;
00092 }
00093 snprintf(pri, sizeof(pri), "%d", priority);
00094 switch(mode) {
00095 case MODE_MATCHMORE:
00096 ematch = "exten LIKE";
00097 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
00098 break;
00099 case MODE_CANMATCH:
00100 ematch = "exten LIKE";
00101 snprintf(rexten, sizeof(rexten), "%s%%", exten);
00102 break;
00103 case MODE_MATCH:
00104 default:
00105 ematch = "exten";
00106 ast_copy_string(rexten, exten, sizeof(rexten));
00107 }
00108 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL);
00109 if (!var && !ast_test_flag(&flags, OPTION_PATTERNS_DISABLED)) {
00110 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL);
00111 if (cfg) {
00112 char *cat = ast_category_browse(cfg, NULL);
00113
00114 while(cat) {
00115 switch(mode) {
00116 case MODE_MATCHMORE:
00117 match = ast_extension_close(cat, exten, 1);
00118 break;
00119 case MODE_CANMATCH:
00120 match = ast_extension_close(cat, exten, 0);
00121 break;
00122 case MODE_MATCH:
00123 default:
00124 match = ast_extension_match(cat, exten);
00125 }
00126 if (match) {
00127 var = ast_category_detach_variables(ast_category_get(cfg, cat));
00128 break;
00129 }
00130 cat = ast_category_browse(cfg, cat);
00131 }
00132 ast_config_destroy(cfg);
00133 }
00134 }
00135 return var;
00136 }
00137
00138 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
00139 {
00140 const char *ctx = NULL;
00141 char *table;
00142 struct ast_variable *var=NULL;
00143 struct ast_flags flags = { 0, };
00144 char *buf = ast_strdupa(data);
00145 if (buf) {
00146
00147
00148 char *opts = strchr(buf, '/');
00149 if (opts)
00150 *opts++ = '\0';
00151 table = strchr(buf, '@');
00152 if (table) {
00153 *table++ = '\0';
00154 ctx = buf;
00155 }
00156 ctx = S_OR(ctx, context);
00157 table = S_OR(table, "extensions");
00158 if (!ast_strlen_zero(opts)) {
00159 ast_app_parse_options(switch_opts, &flags, NULL, opts);
00160 }
00161 var = realtime_switch_common(table, ctx, exten, priority, mode, flags);
00162 }
00163 return var;
00164 }
00165
00166 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00167 {
00168 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
00169 if (var) {
00170 ast_variables_destroy(var);
00171 return 1;
00172 }
00173 return 0;
00174 }
00175
00176 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00177 {
00178 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
00179 if (var) {
00180 ast_variables_destroy(var);
00181 return 1;
00182 }
00183 return 0;
00184 }
00185
00186 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00187 {
00188 int res = -1;
00189 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
00190
00191 if (var) {
00192 char *tmp="";
00193 char *app = NULL;
00194 struct ast_variable *v;
00195
00196 for (v = var; v ; v = v->next) {
00197 if (!strcasecmp(v->name, "app"))
00198 app = ast_strdupa(v->value);
00199 else if (!strcasecmp(v->name, "appdata")) {
00200 if (ast_compat_pbx_realtime) {
00201 char *ptr;
00202 int in = 0;
00203 tmp = alloca(strlen(v->value) * 2 + 1);
00204 for (ptr = tmp; *v->value; v->value++) {
00205 if (*v->value == ',') {
00206 *ptr++ = '\\';
00207 *ptr++ = ',';
00208 } else if (*v->value == '|' && !in) {
00209 *ptr++ = ',';
00210 } else {
00211 *ptr++ = *v->value;
00212 }
00213
00214
00215 if (v->value[0] == '[' && v->value[-1] == '$') {
00216 in++;
00217 } else if (v->value[0] == ']' && in) {
00218 in--;
00219 }
00220 }
00221 *ptr = '\0';
00222 } else {
00223 tmp = ast_strdupa(v->value);
00224 }
00225 }
00226 }
00227 ast_variables_destroy(var);
00228 if (!ast_strlen_zero(app)) {
00229 struct ast_app *a = pbx_findapp(app);
00230 if (a) {
00231 char appdata[512];
00232 char tmp1[80];
00233 char tmp2[80];
00234 char tmp3[EXT_DATA_SIZE];
00235
00236 appdata[0] = 0;
00237 if(!ast_strlen_zero(tmp))
00238 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
00239 ast_verb(3, "Executing %s(\"%s\", \"%s\")\n",
00240 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
00241 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
00242 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
00243 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
00244 "Channel: %s\r\n"
00245 "Context: %s\r\n"
00246 "Extension: %s\r\n"
00247 "Priority: %d\r\n"
00248 "Application: %s\r\n"
00249 "AppData: %s\r\n"
00250 "Uniqueid: %s\r\n",
00251 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
00252
00253 res = pbx_exec(chan, a, appdata);
00254 } else
00255 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
00256 } else {
00257 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
00258 }
00259 }
00260 return res;
00261 }
00262
00263 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00264 {
00265 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
00266 if (var) {
00267 ast_variables_destroy(var);
00268 return 1;
00269 }
00270 return 0;
00271 }
00272
00273 static struct ast_switch realtime_switch =
00274 {
00275 name: "Realtime",
00276 description: "Realtime Dialplan Switch",
00277 exists: realtime_exists,
00278 canmatch: realtime_canmatch,
00279 exec: realtime_exec,
00280 matchmore: realtime_matchmore,
00281 };
00282
00283 static int unload_module(void)
00284 {
00285 ast_unregister_switch(&realtime_switch);
00286 return 0;
00287 }
00288
00289 static int load_module(void)
00290 {
00291 if (ast_register_switch(&realtime_switch))
00292 return AST_MODULE_LOAD_FAILURE;
00293 return AST_MODULE_LOAD_SUCCESS;
00294 }
00295
00296 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");