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