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
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00035
00036 #include "asterisk/pbx.h"
00037 #include "asterisk/module.h"
00038 #include "asterisk/channel.h"
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 static char *start_app = "While";
00103 static char *stop_app = "EndWhile";
00104 static char *exit_app = "ExitWhile";
00105 static char *continue_app = "ContinueWhile";
00106
00107 #define VAR_SIZE 64
00108
00109
00110 static const char *get_index(struct ast_channel *chan, const char *prefix, int idx) {
00111 char varname[VAR_SIZE];
00112
00113 snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);
00114 return pbx_builtin_getvar_helper(chan, varname);
00115 }
00116
00117 static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
00118 {
00119 struct ast_exten *e;
00120 struct ast_include *i;
00121 struct ast_context *c2;
00122
00123 for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
00124 if (ast_extension_match(ast_get_extension_name(e), exten)) {
00125 int needmatch = ast_get_extension_matchcid(e);
00126 if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
00127 (!needmatch)) {
00128
00129 struct ast_exten *p;
00130 for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
00131 if (priority != ast_get_extension_priority(p))
00132 continue;
00133 return p;
00134 }
00135 }
00136 }
00137 }
00138
00139
00140 for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
00141 for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
00142 if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
00143 e = find_matching_priority(c2, exten, priority, callerid);
00144 if (e)
00145 return e;
00146 }
00147 }
00148 }
00149 return NULL;
00150 }
00151
00152 static int find_matching_endwhile(struct ast_channel *chan)
00153 {
00154 struct ast_context *c;
00155 int res=-1;
00156
00157 if (ast_rdlock_contexts()) {
00158 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
00159 return -1;
00160 }
00161
00162 for (c=ast_walk_contexts(NULL); c; c=ast_walk_contexts(c)) {
00163 struct ast_exten *e;
00164
00165 if (!ast_rdlock_context(c)) {
00166 if (!strcmp(ast_get_context_name(c), chan->context)) {
00167
00168 int cur_priority = chan->priority + 1, level=1;
00169
00170 for (e = find_matching_priority(c, chan->exten, cur_priority,
00171 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
00172 e;
00173 e = find_matching_priority(c, chan->exten, ++cur_priority,
00174 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00175 if (!strcasecmp(ast_get_extension_app(e), "WHILE")) {
00176 level++;
00177 } else if (!strcasecmp(ast_get_extension_app(e), "ENDWHILE")) {
00178 level--;
00179 }
00180
00181 if (level == 0) {
00182 res = cur_priority;
00183 break;
00184 }
00185 }
00186 }
00187 ast_unlock_context(c);
00188 if (res > 0) {
00189 break;
00190 }
00191 }
00192 }
00193 ast_unlock_contexts();
00194 return res;
00195 }
00196
00197 static int _while_exec(struct ast_channel *chan, const char *data, int end)
00198 {
00199 int res=0;
00200 const char *while_pri = NULL;
00201 char *my_name = NULL;
00202 const char *condition = NULL, *label = NULL;
00203 char varname[VAR_SIZE], end_varname[VAR_SIZE];
00204 const char *prefix = "WHILE";
00205 size_t size=0;
00206 int used_index_i = -1, x=0;
00207 char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
00208
00209 if (!chan) {
00210
00211 return -1;
00212 }
00213
00214 #if 0
00215
00216
00217
00218
00219
00220
00221 if (ast_waitfordigit(chan,1) < 0)
00222 return -1;
00223 #endif
00224
00225 for (x=0;;x++) {
00226 if (get_index(chan, prefix, x)) {
00227 used_index_i = x;
00228 } else
00229 break;
00230 }
00231
00232 snprintf(used_index, VAR_SIZE, "%d", used_index_i);
00233 snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
00234
00235 if (!end)
00236 condition = ast_strdupa(data);
00237
00238 size = strlen(chan->context) + strlen(chan->exten) + 32;
00239 my_name = alloca(size);
00240 memset(my_name, 0, size);
00241 snprintf(my_name, size, "%s_%s_%d", chan->context, chan->exten, chan->priority);
00242
00243 ast_channel_lock(chan);
00244 if (end) {
00245 label = used_index;
00246 } else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
00247 label = new_index;
00248 pbx_builtin_setvar_helper(chan, my_name, label);
00249 }
00250 snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
00251 if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
00252 while_pri = ast_strdupa(while_pri);
00253 snprintf(end_varname,VAR_SIZE,"END_%s",varname);
00254 }
00255 ast_channel_unlock(chan);
00256
00257
00258 if ((!end && !pbx_checkcondition(condition)) || (end == 2)) {
00259
00260 const char *goto_str;
00261 pbx_builtin_setvar_helper(chan, varname, NULL);
00262 pbx_builtin_setvar_helper(chan, my_name, NULL);
00263 snprintf(end_varname,VAR_SIZE,"END_%s",varname);
00264 ast_channel_lock(chan);
00265 if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
00266 ast_parseable_goto(chan, goto_str);
00267 pbx_builtin_setvar_helper(chan, end_varname, NULL);
00268 } else {
00269 int pri = find_matching_endwhile(chan);
00270 if (pri > 0) {
00271 ast_verb(3, "Jumping to priority %d\n", pri);
00272 chan->priority = pri;
00273 } else {
00274 ast_log(LOG_WARNING, "Couldn't find matching EndWhile? (While at %s@%s priority %d)\n", chan->context, chan->exten, chan->priority);
00275 }
00276 }
00277 ast_channel_unlock(chan);
00278 return res;
00279 }
00280
00281 if (!end && !while_pri) {
00282 char *goto_str;
00283 size = strlen(chan->context) + strlen(chan->exten) + 32;
00284 goto_str = alloca(size);
00285 memset(goto_str, 0, size);
00286 snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority);
00287 pbx_builtin_setvar_helper(chan, varname, goto_str);
00288 }
00289
00290 else if (end && while_pri) {
00291
00292 snprintf(end_varname, VAR_SIZE, "END_%s", varname);
00293 if (! pbx_builtin_getvar_helper(chan, end_varname)) {
00294 char *goto_str;
00295 size = strlen(chan->context) + strlen(chan->exten) + 32;
00296 goto_str = alloca(size);
00297 memset(goto_str, 0, size);
00298 snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority+1);
00299 pbx_builtin_setvar_helper(chan, end_varname, goto_str);
00300 }
00301 ast_parseable_goto(chan, while_pri);
00302 }
00303
00304 return res;
00305 }
00306
00307 static int while_start_exec(struct ast_channel *chan, const char *data) {
00308 return _while_exec(chan, data, 0);
00309 }
00310
00311 static int while_end_exec(struct ast_channel *chan, const char *data) {
00312 return _while_exec(chan, data, 1);
00313 }
00314
00315 static int while_exit_exec(struct ast_channel *chan, const char *data) {
00316 return _while_exec(chan, data, 2);
00317 }
00318
00319 static int while_continue_exec(struct ast_channel *chan, const char *data)
00320 {
00321 int x;
00322 const char *prefix = "WHILE", *while_pri=NULL;
00323
00324 for (x = 0; ; x++) {
00325 const char *tmp = get_index(chan, prefix, x);
00326 if (tmp)
00327 while_pri = tmp;
00328 else
00329 break;
00330 }
00331
00332 if (while_pri)
00333 ast_parseable_goto(chan, while_pri);
00334
00335 return 0;
00336 }
00337
00338 static int unload_module(void)
00339 {
00340 int res;
00341
00342 res = ast_unregister_application(start_app);
00343 res |= ast_unregister_application(stop_app);
00344 res |= ast_unregister_application(exit_app);
00345 res |= ast_unregister_application(continue_app);
00346
00347 return res;
00348 }
00349
00350 static int load_module(void)
00351 {
00352 int res;
00353
00354 res = ast_register_application_xml(start_app, while_start_exec);
00355 res |= ast_register_application_xml(stop_app, while_end_exec);
00356 res |= ast_register_application_xml(exit_app, while_exit_exec);
00357 res |= ast_register_application_xml(continue_app, while_continue_exec);
00358
00359 return res;
00360 }
00361
00362 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "While Loops and Conditional Execution");