help text cleanups (bug #4072, with mods)
[asterisk/asterisk.git] / apps / app_while.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * While Loop and ExecIf Implementations
5  * 
6  * Copyright 2004 - 2005, Anthony Minessale <anthmct@yahoo.com>
7  *
8  * Anthony Minessale <anthmct@yahoo.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14
15 #include "asterisk/file.h"
16 #include "asterisk/logger.h"
17 #include "asterisk/channel.h"
18 #include "asterisk/utils.h"
19 #include "asterisk/config.h"
20 #include "asterisk/pbx.h"
21 #include "asterisk/module.h"
22 #include "asterisk/lock.h"
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <string.h>
26
27 #define ALL_DONE(u,ret) {LOCAL_USER_REMOVE(u); return ret;}
28
29
30 static char *exec_app = "ExecIf";
31 static char *exec_desc = 
32 "Usage:  ExecIF (<expr>|<app>|<data>)\n"
33 "If <expr> is true, execute and return the result of <app>(<data>).\n"
34 "If <expr> is true, but <app> is not found, then the application\n"
35 "will return a non-zero value.";
36 static char *exec_synopsis = "Conditional exec";
37
38 static char *start_app = "While";
39 static char *start_desc = 
40 "Usage:  While(<expr>)\n"
41 "Start a While Loop.  Execution will return to this point when\n"
42 "EndWhile is called until expr is no longer true.\n";
43
44 static char *start_synopsis = "Start A While Loop";
45
46
47 static char *stop_app = "EndWhile";
48 static char *stop_desc = 
49 "Usage:  EndWhile()\n"
50 "Return to the previous called While\n\n";
51
52 static char *stop_synopsis = "End A While Loop";
53
54 static char *tdesc = "While Loops and Conditional Execution";
55
56
57
58 STANDARD_LOCAL_USER;
59
60 LOCAL_USER_DECL;
61
62 static int execif_exec(struct ast_channel *chan, void *data) {
63         int res=0;
64         struct localuser *u;
65         char *myapp = NULL;
66         char *mydata = NULL;
67         char *expr = NULL;
68         struct ast_app *app = NULL;
69
70         LOCAL_USER_ADD(u);
71         expr = ast_strdupa((char *) data);
72         if ((myapp = strchr(expr,'|'))) {
73                 *myapp = '\0';
74                 myapp++;
75                 if ((mydata = strchr(myapp,'|'))) {
76                         *mydata = '\0';
77                         mydata++;
78                 } else
79                         mydata = "";
80
81                 if (ast_true(expr)) { 
82                         if ((app = pbx_findapp(myapp))) {
83                                 res = pbx_exec(chan, app, mydata, 1);
84                         } else {
85                                 ast_log(LOG_WARNING, "Count not find application! (%s)\n", myapp);
86                                 res = -1;
87                         }
88                 }
89         } else {
90                 ast_log(LOG_ERROR,"Invalid Syntax.\n");
91                 res = -1;
92         }
93                 
94         ALL_DONE(u,res);
95 }
96
97 #define VAR_SIZE 64
98
99
100 static char *get_index(struct ast_channel *chan, const char *prefix, int index) {
101         char varname[VAR_SIZE];
102
103         snprintf(varname, VAR_SIZE, "%s_%d", prefix, index);
104         return pbx_builtin_getvar_helper(chan, varname);
105 }
106
107
108 static int _while_exec(struct ast_channel *chan, void *data, int end)
109 {
110         int res=0;
111         struct localuser *u;
112         char *while_pri = NULL;
113         char *goto_str = NULL, *my_name = NULL;
114         char *condition = NULL, *label = NULL;
115         char varname[VAR_SIZE], end_varname[VAR_SIZE];
116         const char *prefix = "WHILE";
117         size_t size=0;
118         int used_index_i = -1, x=0;
119         char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
120         
121         if (!chan) {
122                 /* huh ? */
123                 return -1;
124         }
125
126         LOCAL_USER_ADD(u);
127
128         /* dont want run away loops if the chan isn't even up
129            this is up for debate since it slows things down a tad ......
130         */
131         if (ast_waitfordigit(chan,1) < 0)
132                 ALL_DONE(u,-1);
133
134
135         for (x=0;;x++) {
136                 if (get_index(chan, prefix, x)) {
137                         used_index_i = x;
138                 } else 
139                         break;
140         }
141         
142         snprintf(used_index, VAR_SIZE, "%d", used_index_i);
143         snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);
144         
145         if (!end) {
146                 condition = ast_strdupa((char *) data);
147         }
148
149         size = strlen(chan->context) + strlen(chan->exten) + 32;
150         my_name = alloca(size);
151         memset(my_name, 0, size);
152         snprintf(my_name, size, "%s_%s_%d", chan->context, chan->exten, chan->priority);
153         
154         if (!label || ast_strlen_zero(label)) {
155                 if (end) 
156                         label = used_index;
157                 else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
158                         label = new_index;
159                         pbx_builtin_setvar_helper(chan, my_name, label);
160                 }
161                 
162         }
163         
164         snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);
165         while_pri = pbx_builtin_getvar_helper(chan, varname);
166         
167         if ((while_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
168                 snprintf(end_varname,VAR_SIZE,"END_%s",varname);
169         }
170         
171
172         if (!end && !ast_true(condition)) {
173                 /* Condition Met (clean up helper vars) */
174                 pbx_builtin_setvar_helper(chan, varname, NULL);
175                 pbx_builtin_setvar_helper(chan, my_name, NULL);
176         snprintf(end_varname,VAR_SIZE,"END_%s",varname);
177                 if ((goto_str=pbx_builtin_getvar_helper(chan, end_varname))) {
178                         pbx_builtin_setvar_helper(chan, end_varname, NULL);
179                         ast_parseable_goto(chan, goto_str);
180                 }
181                 ALL_DONE(u,res);
182         }
183
184         if (!end && !while_pri) {
185                 size = strlen(chan->context) + strlen(chan->exten) + 32;
186                 goto_str = alloca(size);
187                 memset(goto_str, 0, size);
188                 snprintf(goto_str, size, "%s|%s|%d", chan->context, chan->exten, chan->priority);
189                 pbx_builtin_setvar_helper(chan, varname, goto_str);
190         } 
191
192         else if (end && while_pri) {
193                 /* END of loop */
194                 snprintf(end_varname, VAR_SIZE, "END_%s", varname);
195                 if (! pbx_builtin_getvar_helper(chan, end_varname)) {
196                         size = strlen(chan->context) + strlen(chan->exten) + 32;
197                         goto_str = alloca(size);
198                         memset(goto_str, 0, size);
199                         snprintf(goto_str, size, "%s|%s|%d", chan->context, chan->exten, chan->priority+1);
200                         pbx_builtin_setvar_helper(chan, end_varname, goto_str);
201                 }
202                 ast_parseable_goto(chan, while_pri);
203         }
204         
205
206
207
208         ALL_DONE(u, res);
209 }
210
211 static int while_start_exec(struct ast_channel *chan, void *data) {
212         return _while_exec(chan, data, 0);
213 }
214
215 static int while_end_exec(struct ast_channel *chan, void *data) {
216         return _while_exec(chan, data, 1);
217 }
218
219
220 int unload_module(void)
221 {
222         STANDARD_HANGUP_LOCALUSERS;
223         ast_unregister_application(start_app);
224         ast_unregister_application(exec_app);
225         return ast_unregister_application(stop_app);
226 }
227
228 int load_module(void)
229 {
230         ast_register_application(start_app, while_start_exec, start_synopsis, start_desc);
231         ast_register_application(exec_app, execif_exec, exec_synopsis, exec_desc);
232         return ast_register_application(stop_app, while_end_exec, stop_synopsis, stop_desc);
233 }
234
235 char *description(void)
236 {
237         return tdesc;
238 }
239
240 int usecount(void)
241 {
242         int res;
243         STANDARD_USECOUNT(res);
244         return res;
245 }
246
247 char *key()
248 {
249         return ASTERISK_GPL_KEY;
250 }
251