Merged revisions 80044 via svnmerge from
[asterisk/asterisk.git] / funcs / func_logic.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  * Portions Copyright (C) 2005, Anthony Minessale II
6  *
7  * See http://www.asterisk.org for more information about
8  * the Asterisk project. Please do not directly contact
9  * any of the maintainers of this project for assistance;
10  * the project provides a web site, mailing lists and IRC
11  * channels for your use.
12  *
13  * This program is free software, distributed under the terms of
14  * the GNU General Public License Version 2. See the LICENSE file
15  * at the top of the source tree.
16  */
17
18 /*! \file
19  * 
20  * \brief Conditional logic dialplan functions
21  * 
22  * \author Anthony Minessale II
23  *
24  * \ingroup functions
25  */
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35
36 #include "asterisk/module.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/app.h"
42
43 static int isnull(struct ast_channel *chan, const char *cmd, char *data,
44                   char *buf, size_t len)
45 {
46         strcpy(buf, data && *data ? "0" : "1");
47
48         return 0;
49 }
50
51 static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf,
52                   size_t len)
53 {
54         strcpy(buf, data && *data ? "1" : "0");
55
56         return 0;
57 }
58
59 static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf,
60                   size_t len)
61 {
62         struct ast_timing timing;
63         char *expr;
64         char *iftrue;
65         char *iffalse;
66
67         data = ast_strip_quoted(data, "\"", "\"");
68         expr = strsep(&data, "?");
69         iftrue = strsep(&data, ":");
70         iffalse = data;
71
72         if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
73                 ast_log(LOG_WARNING,
74                                 "Syntax IFTIME(<timespec>?[<true>][:<false>])\n");
75                 return -1;
76         }
77
78         if (!ast_build_timing(&timing, expr)) {
79                 ast_log(LOG_WARNING, "Invalid Time Spec.\n");
80                 return -1;
81         }
82
83         if (iftrue)
84                 iftrue = ast_strip_quoted(iftrue, "\"", "\"");
85         if (iffalse)
86                 iffalse = ast_strip_quoted(iffalse, "\"", "\"");
87
88         ast_copy_string(buf, ast_check_timing(&timing) ? iftrue : iffalse, len);
89
90         return 0;
91 }
92
93 static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf,
94                   size_t len)
95 {
96         char *expr;
97         char *iftrue;
98         char *iffalse;
99
100         data = ast_strip_quoted(data, "\"", "\"");
101         expr = strsep(&data, "?");
102         iftrue = strsep(&data, ":");
103         iffalse = data;
104
105         if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
106                 ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>])\n");
107                 return -1;
108         }
109
110         expr = ast_strip(expr);
111         if (iftrue)
112                 iftrue = ast_strip_quoted(iftrue, "\"", "\"");
113         if (iffalse)
114                 iffalse = ast_strip_quoted(iffalse, "\"", "\"");
115
116         ast_copy_string(buf, pbx_checkcondition(expr) ? (S_OR(iftrue, "")) : (S_OR(iffalse, "")), len);
117
118         return 0;
119 }
120
121 static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf,
122                size_t len)
123 {
124         char *varname;
125         char *val;
126
127         varname = strsep(&data, "=");
128         val = data;
129
130         if (ast_strlen_zero(varname) || !val) {
131                 ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n");
132                 return -1;
133         }
134
135         varname = ast_strip(varname);
136         val = ast_strip(val);
137         pbx_builtin_setvar_helper(chan, varname, val);
138         ast_copy_string(buf, val, len);
139
140         return 0;
141 }
142
143 static int acf_import(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
144 {
145         AST_DECLARE_APP_ARGS(args,
146                 AST_APP_ARG(channel);
147                 AST_APP_ARG(varname);
148         );
149         AST_STANDARD_APP_ARGS(args, data);
150         memset(buf, 0, len);
151
152         if (!ast_strlen_zero(args.varname)) {
153                 struct ast_channel *chan2 = ast_get_channel_by_name_locked(args.channel);
154                 if (chan2) {
155                         char *s = alloca(strlen(args.varname) + 4);
156                         if (s) {
157                                 sprintf(s, "${%s}", args.varname);
158                                 pbx_substitute_variables_helper(chan2, s, buf, len);
159                         }
160                         ast_channel_unlock(chan2);
161                 }
162         }
163         return 0;
164 }
165
166 static struct ast_custom_function isnull_function = {
167         .name = "ISNULL",
168         .synopsis = "NULL Test: Returns 1 if NULL or 0 otherwise",
169         .syntax = "ISNULL(<data>)",
170         .read = isnull,
171 };
172
173 static struct ast_custom_function set_function = {
174         .name = "SET",
175         .synopsis = "SET assigns a value to a channel variable",
176         .syntax = "SET(<varname>=[<value>])",
177         .read = set,
178 };
179
180 static struct ast_custom_function exists_function = {
181         .name = "EXISTS",
182         .synopsis = "Existence Test: Returns 1 if exists, 0 otherwise",
183         .syntax = "EXISTS(<data>)",
184         .read = exists,
185 };
186
187 static struct ast_custom_function if_function = {
188         .name = "IF",
189         .synopsis =
190                 "Conditional: Returns the data following '?' if true, else the data following ':'",
191         .syntax = "IF(<expr>?[<true>][:<false>])",
192         .read = acf_if,
193 };
194
195 static struct ast_custom_function if_time_function = {
196         .name = "IFTIME",
197         .synopsis =
198                 "Temporal Conditional: Returns the data following '?' if true, else the data following ':'",
199         .syntax = "IFTIME(<timespec>?[<true>][:<false>])",
200         .read = iftime,
201 };
202
203 static struct ast_custom_function import_function = {
204         .name = "IMPORT",
205         .synopsis =
206                 "Retrieve the value of a variable from another channel\n",
207         .syntax = "IMPORT(channel,variable)",
208         .read = acf_import,
209 };
210
211 static int unload_module(void)
212 {
213         int res = 0;
214
215         res |= ast_custom_function_unregister(&isnull_function);
216         res |= ast_custom_function_unregister(&set_function);
217         res |= ast_custom_function_unregister(&exists_function);
218         res |= ast_custom_function_unregister(&if_function);
219         res |= ast_custom_function_unregister(&if_time_function);
220         res |= ast_custom_function_unregister(&import_function);
221
222         return res;
223 }
224
225 static int load_module(void)
226 {
227         int res = 0;
228
229         res |= ast_custom_function_register(&isnull_function);
230         res |= ast_custom_function_register(&set_function);
231         res |= ast_custom_function_register(&exists_function);
232         res |= ast_custom_function_register(&if_function);
233         res |= ast_custom_function_register(&if_time_function);
234         res |= ast_custom_function_register(&import_function);
235
236         return res;
237 }
238
239 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions");