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: 276347 $")
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,
00167 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
00168 e;
00169 e = find_matching_priority(c, chan->exten, ++cur_priority,
00170 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00171 if (!strcasecmp(ast_get_extension_app(e), "WHILE")) {
00172 level++;
00173 } else if (!strcasecmp(ast_get_extension_app(e), "ENDWHILE")) {
00174 level--;
00175 }
00176
00177 if (level == 0) {
00178 res = cur_priority;
00179 break;
00180 }
00181 }
00182 }
00183 ast_unlock_context(c);
00184 if (res > 0) {
00185 break;
00186 }
00187 }
00188 }
00189 ast_unlock_contexts();
00190 return res;
00191 }
00192
00193 static int _while_exec(struct ast_channel *chan, const char *data, int end)
00194 {
00195 int res=0;
00196 const char *while_pri = NULL;
00197 char *my_name = NULL;
00198 const char *condition = NULL, *label = NULL;
00199 char varname[VAR_SIZE], end_varname[VAR_SIZE];
00200 const char *prefix = "WHILE";
00201 size_t size=0;
00202 int used_index_i = -1, x=0;
00203 char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
00204
00205 if (!chan) {
00206
00207 return -1;
00208 }
00209
00210 #if 0
00211
00212
00213
00214
00215
00216
00217 if (ast_waitfordigit(chan,1) < 0)
00218 return -1;
00219 #endif
00220
00221 for (x=0;;x++) {
00222 if (get_index(chan, prefix, x)) {
00223 used_index_i = x;
00224 } else
00225 break;
00226 }
00227
00228 snprintf(used_index, VAR_SIZE, "%d", used_index_i);
00229 snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
00230
00231 if (!end)
00232 condition = ast_strdupa(data);
00233
00234 size = strlen(chan->context) + strlen(chan->exten) + 32;
00235 my_name = alloca(size);
00236 memset(my_name, 0, size);
00237 snprintf(my_name, size, "%s_%s_%d", chan->context, chan->exten, chan->priority);
00238
00239 ast_channel_lock(chan);
00240 if (end) {
00241 label = used_index;
00242 } else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
00243 label = new_index;
00244 pbx_builtin_setvar_helper(chan, my_name, label);
00245 }
00246 snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
00247 if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
00248 while_pri = ast_strdupa(while_pri);
00249 snprintf(end_varname,VAR_SIZE,"END_%s",varname);
00250 }
00251 ast_channel_unlock(chan);
00252
00253
00254 if ((!end && !pbx_checkcondition(condition)) || (end == 2)) {
00255
00256 const char *goto_str;
00257 pbx_builtin_setvar_helper(chan, varname, NULL);
00258 pbx_builtin_setvar_helper(chan, my_name, NULL);
00259 snprintf(end_varname,VAR_SIZE,"END_%s",varname);
00260 ast_channel_lock(chan);
00261 if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
00262 ast_parseable_goto(chan, goto_str);
00263 pbx_builtin_setvar_helper(chan, end_varname, NULL);
00264 } else {
00265 int pri = find_matching_endwhile(chan);
00266 if (pri > 0) {
00267 ast_verb(3, "Jumping to priority %d\n", pri);
00268 chan->priority = pri;
00269 } else {
00270 ast_log(LOG_WARNING, "Couldn't find matching EndWhile? (While at %s@%s priority %d)\n", chan->context, chan->exten, chan->priority);
00271 }
00272 }
00273 ast_channel_unlock(chan);
00274 return res;
00275 }
00276
00277 if (!end && !while_pri) {
00278 char *goto_str;
00279 size = strlen(chan->context) + strlen(chan->exten) + 32;
00280 goto_str = alloca(size);
00281 memset(goto_str, 0, size);
00282 snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority);
00283 pbx_builtin_setvar_helper(chan, varname, goto_str);
00284 }
00285
00286 else if (end && while_pri) {
00287
00288 snprintf(end_varname, VAR_SIZE, "END_%s", varname);
00289 if (! pbx_builtin_getvar_helper(chan, end_varname)) {
00290 char *goto_str;
00291 size = strlen(chan->context) + strlen(chan->exten) + 32;
00292 goto_str = alloca(size);
00293 memset(goto_str, 0, size);
00294 snprintf(goto_str, size, "%s,%s,%d", chan->context, chan->exten, chan->priority+1);
00295 pbx_builtin_setvar_helper(chan, end_varname, goto_str);
00296 }
00297 ast_parseable_goto(chan, while_pri);
00298 }
00299
00300 return res;
00301 }
00302
00303 static int while_start_exec(struct ast_channel *chan, const char *data) {
00304 return _while_exec(chan, data, 0);
00305 }
00306
00307 static int while_end_exec(struct ast_channel *chan, const char *data) {
00308 return _while_exec(chan, data, 1);
00309 }
00310
00311 static int while_exit_exec(struct ast_channel *chan, const char *data) {
00312 return _while_exec(chan, data, 2);
00313 }
00314
00315 static int while_continue_exec(struct ast_channel *chan, const char *data)
00316 {
00317 int x;
00318 const char *prefix = "WHILE", *while_pri=NULL;
00319
00320 for (x = 0; ; x++) {
00321 const char *tmp = get_index(chan, prefix, x);
00322 if (tmp)
00323 while_pri = tmp;
00324 else
00325 break;
00326 }
00327
00328 if (while_pri)
00329 ast_parseable_goto(chan, while_pri);
00330
00331 return 0;
00332 }
00333
00334 static int unload_module(void)
00335 {
00336 int res;
00337
00338 res = ast_unregister_application(start_app);
00339 res |= ast_unregister_application(stop_app);
00340 res |= ast_unregister_application(exit_app);
00341 res |= ast_unregister_application(continue_app);
00342
00343 return res;
00344 }
00345
00346 static int load_module(void)
00347 {
00348 int res;
00349
00350 res = ast_register_application_xml(start_app, while_start_exec);
00351 res |= ast_register_application_xml(stop_app, while_end_exec);
00352 res |= ast_register_application_xml(exit_app, while_exit_exec);
00353 res |= ast_register_application_xml(continue_app, while_continue_exec);
00354
00355 return res;
00356 }
00357
00358 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "While Loops and Conditional Execution");