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: 85515 $")
00029
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <unistd.h>
00033 #include <string.h>
00034 #include <errno.h>
00035
00036 #include "asterisk/file.h"
00037 #include "asterisk/logger.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/config.h"
00040 #include "asterisk/options.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/frame.h"
00044 #include "asterisk/term.h"
00045 #include "asterisk/manager.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/cli.h"
00048 #include "asterisk/lock.h"
00049 #include "asterisk/md5.h"
00050 #include "asterisk/linkedlists.h"
00051 #include "asterisk/chanvars.h"
00052 #include "asterisk/sched.h"
00053 #include "asterisk/io.h"
00054 #include "asterisk/utils.h"
00055 #include "asterisk/crypto.h"
00056 #include "asterisk/astdb.h"
00057
00058 #define MODE_MATCH 0
00059 #define MODE_MATCHMORE 1
00060 #define MODE_CANMATCH 2
00061
00062 #define EXT_DATA_SIZE 256
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)
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 snprintf(pri, sizeof(pri), "%d", priority);
00088 switch(mode) {
00089 case MODE_MATCHMORE:
00090 ematch = "exten LIKE";
00091 snprintf(rexten, sizeof(rexten), "%s_%%", exten);
00092 break;
00093 case MODE_CANMATCH:
00094 ematch = "exten LIKE";
00095 snprintf(rexten, sizeof(rexten), "%s%%", exten);
00096 break;
00097 case MODE_MATCH:
00098 default:
00099 ematch = "exten";
00100 ast_copy_string(rexten, exten, sizeof(rexten));
00101 }
00102 var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
00103 if (!var) {
00104 cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);
00105 if (cfg) {
00106 char *cat = ast_category_browse(cfg, NULL);
00107
00108 while(cat) {
00109 switch(mode) {
00110 case MODE_MATCHMORE:
00111 match = ast_extension_close(cat, exten, 1);
00112 break;
00113 case MODE_CANMATCH:
00114 match = ast_extension_close(cat, exten, 0);
00115 break;
00116 case MODE_MATCH:
00117 default:
00118 match = ast_extension_match(cat, exten);
00119 }
00120 if (match) {
00121 var = ast_category_detach_variables(ast_category_get(cfg, cat));
00122 break;
00123 }
00124 cat = ast_category_browse(cfg, cat);
00125 }
00126 ast_config_destroy(cfg);
00127 }
00128 }
00129 return var;
00130 }
00131
00132 static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
00133 {
00134 const char *ctx = NULL;
00135 char *table;
00136 struct ast_variable *var=NULL;
00137 char *buf = ast_strdupa(data);
00138 if (buf) {
00139 char *opts = strchr(buf, '/');
00140 if (opts)
00141 *opts++ = '\0';
00142 table = strchr(buf, '@');
00143 if (table) {
00144 *table++ = '\0';
00145 ctx = buf;
00146 }
00147 ctx = S_OR(ctx, context);
00148 table = S_OR(table, "extensions");
00149 var = realtime_switch_common(table, ctx, exten, priority, mode);
00150 }
00151 return var;
00152 }
00153
00154 static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00155 {
00156 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
00157 if (var) {
00158 ast_variables_destroy(var);
00159 return 1;
00160 }
00161 return 0;
00162 }
00163
00164 static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00165 {
00166 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
00167 if (var) {
00168 ast_variables_destroy(var);
00169 return 1;
00170 }
00171 return 0;
00172 }
00173
00174 static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00175 {
00176 int res = -1;
00177 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
00178
00179 if (var) {
00180 char *tmp="";
00181 char *app = NULL;
00182 struct ast_variable *v;
00183
00184 for (v = var; v ; v = v->next) {
00185 if (!strcasecmp(v->name, "app"))
00186 app = ast_strdupa(v->value);
00187 else if (!strcasecmp(v->name, "appdata"))
00188 tmp = ast_strdupa(v->value);
00189 }
00190 ast_variables_destroy(var);
00191 if (!ast_strlen_zero(app)) {
00192 struct ast_app *a = pbx_findapp(app);
00193 if (a) {
00194 char appdata[512]="";
00195 char tmp1[80];
00196 char tmp2[80];
00197 char tmp3[EXT_DATA_SIZE];
00198
00199 if(!ast_strlen_zero(tmp))
00200 pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
00201 if (option_verbose > 2)
00202 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\")\n",
00203 term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
00204 term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
00205 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
00206 manager_event(EVENT_FLAG_CALL, "Newexten",
00207 "Channel: %s\r\n"
00208 "Context: %s\r\n"
00209 "Extension: %s\r\n"
00210 "Priority: %d\r\n"
00211 "Application: %s\r\n"
00212 "AppData: %s\r\n"
00213 "Uniqueid: %s\r\n",
00214 chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
00215
00216 res = pbx_exec(chan, a, appdata);
00217 } else
00218 ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
00219 } else {
00220 ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
00221 }
00222 }
00223 return res;
00224 }
00225
00226 static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
00227 {
00228 struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
00229 if (var) {
00230 ast_variables_destroy(var);
00231 return 1;
00232 }
00233 return 0;
00234 }
00235
00236 static struct ast_switch realtime_switch =
00237 {
00238 name: "Realtime",
00239 description: "Realtime Dialplan Switch",
00240 exists: realtime_exists,
00241 canmatch: realtime_canmatch,
00242 exec: realtime_exec,
00243 matchmore: realtime_matchmore,
00244 };
00245
00246 static int unload_module(void)
00247 {
00248 ast_unregister_switch(&realtime_switch);
00249 return 0;
00250 }
00251
00252 static int load_module(void)
00253 {
00254 ast_register_switch(&realtime_switch);
00255 return 0;
00256 }
00257
00258 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");