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: 120172 $")
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
00050 #define MODE_MATCH 0
00051 #define MODE_MATCHMORE 1
00052 #define MODE_CANMATCH 2
00053
00054 #define EXT_DATA_SIZE 256
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
00071 {
00072 struct ast_variable *var;
00073 struct ast_config *cfg;
00074 char pri[20];
00075 char *ematch;
00076 char rexten[AST_MAX_EXTENSION + 20]="";
00077 int match;
00078 snprintf(pri, sizeof(pri), "%d", priority);
00079 switch(mode) {
00080 case MODE_MATCHMORE:
00081 ematch = "exten LIKE";
00082 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
00083 break;
00084 case MODE_CANMATCH:
00085 ematch = "exten LIKE";
00086 snprintf(rexten, sizeof(rexten), "%s%%", exten);
00087 break;
00088 case MODE_MATCH:
00089 default:
00090 ematch = "exten";
00091 ast_copy_string(rexten, exten, sizeof(rexten));
00092 }
00093 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
00094 if (!var) {
00095 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);
00096 if (cfg) {
00097 char *cat = ast_category_browse(cfg, NULL);
00098
00099 while(cat) {
00100 switch(mode) {
00101 case MODE_MATCHMORE:
00102 match = ast_extension_close(cat, exten, 1);
00103 break;
00104 case MODE_CANMATCH:
00105 match = ast_extension_close(cat, exten, 0);
00106 break;
00107 case MODE_MATCH:
00108 default:
00109 match = ast_extension_match(cat, exten);
00110 }
00111 if (match) {
00112 var = ast_category_detach_variables(ast_category_get(cfg, cat));
00113 break;
00114 }
00115 cat = ast_category_browse(cfg, cat);
00116 }
00117 ast_config_destroy(cfg);
00118 }
00119 }
00120 return var;
00121 }
00122
00123 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
00124 {
00125 const char *ctx = NULL;
00126 char *table;
00127 struct ast_variable *var=NULL;
00128 char *buf = ast_strdupa(data);
00129 if (buf) {
00130 char *opts = strchr(buf, '/');
00131 if (opts)
00132 *opts++ = '\0';
00133 table = strchr(buf, '@');
00134 if (table) {
00135 *table++ = '\0';
00136 ctx = buf;
00137 }
00138 ctx = S_OR(ctx, context);
00139 table = S_OR(table, "extensions");
00140 var = realtime_switch_common(table, ctx, exten, priority, mode);
00141 }
00142 return var;
00143 }
00144
00145 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00146 {
00147 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
00148 if (var) {
00149 ast_variables_destroy(var);
00150 return 1;
00151 }
00152 return 0;
00153 }
00154
00155 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00156 {
00157 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
00158 if (var) {
00159 ast_variables_destroy(var);
00160 return 1;
00161 }
00162 return 0;
00163 }
00164
00165 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00166 {
00167 int res = -1;
00168 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
00169
00170 if (var) {
00171 char *tmp="";
00172 char *app = NULL;
00173 struct ast_variable *v;
00174
00175 for (v = var; v ; v = v->next) {
00176 if (!strcasecmp(v->name, "app"))
00177 app = ast_strdupa(v->value);
00178 else if (!strcasecmp(v->name, "appdata")) {
00179 if (ast_compat_pbx_realtime) {
00180 char *ptr;
00181 int in = 0;
00182 tmp = alloca(strlen(v->value) * 2 + 1);
00183 for (ptr = tmp; *v->value; v->value++) {
00184 if (*v->value == ',') {
00185 *ptr++ = '\\';
00186 *ptr++ = ',';
00187 } else if (*v->value == '|' && !in) {
00188 *ptr++ = ',';
00189 } else {
00190 *ptr++ = *v->value;
00191 }
00192
00193
00194 if (v->value[0] == '[' && v->value[-1] == '$') {
00195 in++;
00196 } else if (v->value[0] == ']' && in) {
00197 in--;
00198 }
00199 }
00200 *ptr = '\0';
00201 } else {
00202 tmp = ast_strdupa(v->value);
00203 }
00204 }
00205 }
00206 ast_variables_destroy(var);
00207 if (!ast_strlen_zero(app)) {
00208 struct ast_app *a = pbx_findapp(app);
00209 if (a) {
00210 char appdata[512];
00211 char tmp1[80];
00212 char tmp2[80];
00213 char tmp3[EXT_DATA_SIZE];
00214
00215 appdata[0] = 0;
00216 if(!ast_strlen_zero(tmp))
00217 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
00218 ast_verb(3, "Executing %s(\"%s\", \"%s\")\n",
00219 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
00220 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
00221 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
00222 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
00223 "Channel: %s\r\n"
00224 "Context: %s\r\n"
00225 "Extension: %s\r\n"
00226 "Priority: %d\r\n"
00227 "Application: %s\r\n"
00228 "AppData: %s\r\n"
00229 "Uniqueid: %s\r\n",
00230 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
00231
00232 res = pbx_exec(chan, a, appdata);
00233 } else
00234 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
00235 } else {
00236 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
00237 }
00238 }
00239 return res;
00240 }
00241
00242 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00243 {
00244 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
00245 if (var) {
00246 ast_variables_destroy(var);
00247 return 1;
00248 }
00249 return 0;
00250 }
00251
00252 static struct ast_switch realtime_switch =
00253 {
00254 name: "Realtime",
00255 description: "Realtime Dialplan Switch",
00256 exists: realtime_exists,
00257 canmatch: realtime_canmatch,
00258 exec: realtime_exec,
00259 matchmore: realtime_matchmore,
00260 };
00261
00262 static int unload_module(void)
00263 {
00264 ast_unregister_switch(&realtime_switch);
00265 return 0;
00266 }
00267
00268 static int load_module(void)
00269 {
00270 if (ast_register_switch(&realtime_switch))
00271 return AST_MODULE_LOAD_FAILURE;
00272 return AST_MODULE_LOAD_SUCCESS;
00273 }
00274
00275 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");