app_while.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright 2004 - 2005, Anthony Minessale <anthmct@yahoo.com>
  5. *
  6. * Anthony Minessale <anthmct@yahoo.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief While Loop and ExecIf Implementations
  21. *
  22. * \ingroup applications
  23. */
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. #include "asterisk.h"
  29. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  30. #include "asterisk/file.h"
  31. #include "asterisk/logger.h"
  32. #include "asterisk/channel.h"
  33. #include "asterisk/utils.h"
  34. #include "asterisk/config.h"
  35. #include "asterisk/pbx.h"
  36. #include "asterisk/module.h"
  37. #include "asterisk/lock.h"
  38. #include "asterisk/options.h"
  39. #define ALL_DONE(u,ret) {LOCAL_USER_REMOVE(u); return ret;}
  40. static char *exec_app = "ExecIf";
  41. static char *exec_desc =
  42. "Usage: ExecIF (<expr>|<app>|<data>)\n"
  43. "If <expr> is true, execute and return the result of <app>(<data>).\n"
  44. "If <expr> is true, but <app> is not found, then the application\n"
  45. "will return a non-zero value.";
  46. static char *exec_synopsis = "Conditional exec";
  47. static char *start_app = "While";
  48. static char *start_desc =
  49. "Usage: While(<expr>)\n"
  50. "Start a While Loop. Execution will return to this point when\n"
  51. "EndWhile is called until expr is no longer true.\n";
  52. static char *start_synopsis = "Start A While Loop";
  53. static char *stop_app = "EndWhile";
  54. static char *stop_desc =
  55. "Usage: EndWhile()\n"
  56. "Return to the previous called While\n\n";
  57. static char *stop_synopsis = "End A While Loop";
  58. static char *tdesc = "While Loops and Conditional Execution";
  59. STANDARD_LOCAL_USER;
  60. LOCAL_USER_DECL;
  61. static int execif_exec(struct ast_channel *chan, void *data) {
  62. int res=0;
  63. struct localuser *u;
  64. char *myapp = NULL;
  65. char *mydata = NULL;
  66. char *expr = NULL;
  67. struct ast_app *app = NULL;
  68. LOCAL_USER_ADD(u);
  69. expr = ast_strdupa(data);
  70. if (!expr) {
  71. ast_log(LOG_ERROR, "Out of memory\n");
  72. LOCAL_USER_REMOVE(u);
  73. return -1;
  74. }
  75. if ((myapp = strchr(expr,'|'))) {
  76. *myapp = '\0';
  77. myapp++;
  78. if ((mydata = strchr(myapp,'|'))) {
  79. *mydata = '\0';
  80. mydata++;
  81. } else
  82. mydata = "";
  83. if (ast_true(expr)) {
  84. if ((app = pbx_findapp(myapp))) {
  85. res = pbx_exec(chan, app, mydata, 1);
  86. } else {
  87. ast_log(LOG_WARNING, "Count not find application! (%s)\n", myapp);
  88. res = -1;
  89. }
  90. }
  91. } else {
  92. ast_log(LOG_ERROR,"Invalid Syntax.\n");
  93. res = -1;
  94. }
  95. ALL_DONE(u,res);
  96. }
  97. #define VAR_SIZE 64
  98. static char *get_index(struct ast_channel *chan, const char *prefix, int index) {
  99. char varname[VAR_SIZE];
  100. snprintf(varname, VAR_SIZE, "%s_%d", prefix, index);
  101. return pbx_builtin_getvar_helper(chan, varname);
  102. }
  103. static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
  104. {
  105. struct ast_exten *e;
  106. struct ast_include *i;
  107. struct ast_context *c2;
  108. for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
  109. if (ast_extension_match(ast_get_extension_name(e), exten)) {
  110. int needmatch = ast_get_extension_matchcid(e);
  111. if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
  112. (!needmatch)) {
  113. /* This is the matching extension we want */
  114. struct ast_exten *p;
  115. for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
  116. if (priority != ast_get_extension_priority(p))
  117. continue;
  118. return p;
  119. }
  120. }
  121. }
  122. }
  123. /* No match; run through includes */
  124. for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
  125. for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
  126. if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
  127. e = find_matching_priority(c2, exten, priority, callerid);
  128. if (e)
  129. return e;
  130. }
  131. }
  132. }
  133. return NULL;
  134. }
  135. static int find_matching_endwhile(struct ast_channel *chan)
  136. {
  137. struct ast_context *c;
  138. int res=-1;
  139. if (ast_lock_contexts()) {
  140. ast_log(LOG_ERROR, "Failed to lock contexts list\n");
  141. return -1;
  142. }
  143. for (c=ast_walk_contexts(NULL); c; c=ast_walk_contexts(c)) {
  144. struct ast_exten *e;
  145. if (!ast_lock_context(c)) {
  146. if (!strcmp(ast_get_context_name(c), chan->context)) {
  147. /* This is the matching context we want */
  148. int cur_priority = chan->priority + 1, level=1;
  149. 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)) {
  150. if (!strcasecmp(ast_get_extension_app(e), "WHILE")) {
  151. level++;
  152. } else if (!strcasecmp(ast_get_extension_app(e), "ENDWHILE")) {
  153. level--;
  154. }
  155. if (level == 0) {
  156. res = cur_priority;
  157. break;
  158. }
  159. }
  160. }
  161. ast_unlock_context(c);
  162. if (res > 0) {
  163. break;
  164. }
  165. }
  166. }
  167. ast_unlock_contexts();
  168. return res;
  169. }
  170. static int _while_exec(struct ast_channel *chan, void *data, int end)
  171. {
  172. int res=0;
  173. struct localuser *u;
  174. char *while_pri = NULL;
  175. char *goto_str = NULL, *my_name = NULL;
  176. char *condition = NULL, *label = NULL;
  177. char varname[VAR_SIZE], end_varname[VAR_SIZE];
  178. const char *prefix = "WHILE";
  179. size_t size=0;
  180. int used_index_i = -1, x=0;
  181. char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
  182. if (!chan) {
  183. /* huh ? */
  184. return -1;
  185. }
  186. LOCAL_USER_ADD(u);
  187. /* dont want run away loops if the chan isn't even up
  188. this is up for debate since it slows things down a tad ......
  189. */
  190. if (ast_waitfordigit(chan,1) < 0)
  191. ALL_DONE(u,-1);
  192. for (x=0;;x++) {
  193. if (get_index(chan, prefix, x)) {
  194. used_index_i = x;
  195. } else
  196. break;
  197. }
  198. snprintf(used_index, VAR_SIZE, "%d", used_index_i);
  199. snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
  200. if (!end) {
  201. condition = ast_strdupa((char *) data);
  202. }
  203. size = strlen(chan->context) + strlen(chan->exten) + 32;
  204. my_name = alloca(size);
  205. memset(my_name, 0, size);
  206. snprintf(my_name, size, "%s_%s_%d", chan->context, chan->exten, chan->priority);
  207. if (ast_strlen_zero(label)) {
  208. if (end)
  209. label = used_index;
  210. else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
  211. label = new_index;
  212. pbx_builtin_setvar_helper(chan, my_name, label);
  213. }
  214. }
  215. snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
  216. while_pri = pbx_builtin_getvar_helper(chan, varname);
  217. if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
  218. snprintf(end_varname,VAR_SIZE,"END_%s",varname);
  219. }
  220. if (!end && !ast_true(condition)) {
  221. /* Condition Met (clean up helper vars) */
  222. pbx_builtin_setvar_helper(chan, varname, NULL);
  223. pbx_builtin_setvar_helper(chan, my_name, NULL);
  224. snprintf(end_varname,VAR_SIZE,"END_%s",varname);
  225. if ((goto_str=pbx_builtin_getvar_helper(chan, end_varname))) {
  226. pbx_builtin_setvar_helper(chan, end_varname, NULL);
  227. ast_parseable_goto(chan, goto_str);
  228. } else {
  229. int pri = find_matching_endwhile(chan);
  230. if (pri > 0) {
  231. if (option_verbose > 2)
  232. ast_verbose(VERBOSE_PREFIX_3 "Jumping to priority %d\n", pri);
  233. chan->priority = pri;
  234. } else {
  235. ast_log(LOG_WARNING, "Couldn't find matching EndWhile? (While at %s@%s priority %d)\n", chan->context, chan->exten, chan->priority);
  236. }
  237. }
  238. ALL_DONE(u,res);
  239. }
  240. if (!end && !while_pri) {
  241. size = strlen(chan->context) + strlen(chan->exten) + 32;
  242. goto_str = alloca(size);
  243. memset(goto_str, 0, size);
  244. snprintf(goto_str, size, "%s|%s|%d", chan->context, chan->exten, chan->priority);
  245. pbx_builtin_setvar_helper(chan, varname, goto_str);
  246. }
  247. else if (end && while_pri) {
  248. /* END of loop */
  249. snprintf(end_varname, VAR_SIZE, "END_%s", varname);
  250. if (! pbx_builtin_getvar_helper(chan, end_varname)) {
  251. size = strlen(chan->context) + strlen(chan->exten) + 32;
  252. goto_str = alloca(size);
  253. memset(goto_str, 0, size);
  254. snprintf(goto_str, size, "%s|%s|%d", chan->context, chan->exten, chan->priority+1);
  255. pbx_builtin_setvar_helper(chan, end_varname, goto_str);
  256. }
  257. ast_parseable_goto(chan, while_pri);
  258. }
  259. ALL_DONE(u, res);
  260. }
  261. static int while_start_exec(struct ast_channel *chan, void *data) {
  262. return _while_exec(chan, data, 0);
  263. }
  264. static int while_end_exec(struct ast_channel *chan, void *data) {
  265. return _while_exec(chan, data, 1);
  266. }
  267. int unload_module(void)
  268. {
  269. int res;
  270. res = ast_unregister_application(start_app);
  271. res |= ast_unregister_application(exec_app);
  272. res |= ast_unregister_application(stop_app);
  273. STANDARD_HANGUP_LOCALUSERS;
  274. return res;
  275. }
  276. int load_module(void)
  277. {
  278. int res;
  279. res = ast_register_application(start_app, while_start_exec, start_synopsis, start_desc);
  280. res |= ast_register_application(exec_app, execif_exec, exec_synopsis, exec_desc);
  281. res |= ast_register_application(stop_app, while_end_exec, stop_synopsis, stop_desc);
  282. return res;
  283. }
  284. char *description(void)
  285. {
  286. return tdesc;
  287. }
  288. int usecount(void)
  289. {
  290. int res;
  291. STANDARD_USECOUNT(res);
  292. return res;
  293. }
  294. char *key()
  295. {
  296. return ASTERISK_GPL_KEY;
  297. }