Automatically create new buddy upon reception of a presence stanza of
[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 "asterisk/module.h"
32 #include "asterisk/channel.h"
33 #include "asterisk/pbx.h"
34 #include "asterisk/utils.h"
35 #include "asterisk/app.h"
36
37 static int isnull(struct ast_channel *chan, const char *cmd, char *data,
38                   char *buf, size_t len)
39 {
40         strcpy(buf, data && *data ? "0" : "1");
41
42         return 0;
43 }
44
45 static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf,
46                   size_t len)
47 {
48         strcpy(buf, data && *data ? "1" : "0");
49
50         return 0;
51 }
52
53 static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf,
54                   size_t len)
55 {
56         struct ast_timing timing;
57         char *expr;
58         char *iftrue;
59         char *iffalse;
60
61         data = ast_strip_quoted(data, "\"", "\"");
62         expr = strsep(&data, "?");
63         iftrue = strsep(&data, ":");
64         iffalse = data;
65
66         if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
67                 ast_log(LOG_WARNING,
68                                 "Syntax IFTIME(<timespec>?[<true>][:<false>])\n");
69                 return -1;
70         }
71
72         if (!ast_build_timing(&timing, expr)) {
73                 ast_log(LOG_WARNING, "Invalid Time Spec.\n");
74                 return -1;
75         }
76
77         if (iftrue)
78                 iftrue = ast_strip_quoted(iftrue, "\"", "\"");
79         if (iffalse)
80                 iffalse = ast_strip_quoted(iffalse, "\"", "\"");
81
82         ast_copy_string(buf, ast_check_timing(&timing) ? iftrue : iffalse, len);
83
84         return 0;
85 }
86
87 static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf,
88                   size_t len)
89 {
90         AST_DECLARE_APP_ARGS(args1,
91                 AST_APP_ARG(expr);
92                 AST_APP_ARG(remainder);
93         );
94         AST_DECLARE_APP_ARGS(args2,
95                 AST_APP_ARG(iftrue);
96                 AST_APP_ARG(iffalse);
97         );
98         args2.iftrue = args2.iffalse = NULL; /* you have to set these, because if there is nothing after the '?',
99                                                                                         then args1.remainder will be NULL, not a pointer to a null string, and
100                                                                                         then any garbage in args2.iffalse will not be cleared, and you'll crash.
101                                                                                     -- and if you mod the ast_app_separate_args func instead, you'll really
102                                                                                         mess things up badly, because the rest of everything depends on null args
103                                                                                         for non-specified stuff. */
104         
105         AST_NONSTANDARD_APP_ARGS(args1, data, '?');
106         AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':');
107
108         if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) {
109                 ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>])  (expr must be non-null, and either <true> or <false> must be non-null)\n");
110                 ast_log(LOG_WARNING, "      In this case, <expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
111                 return -1;
112         }
113
114         args1.expr = ast_strip(args1.expr);
115         if (args2.iftrue)
116                 args2.iftrue = ast_strip(args2.iftrue);
117         if (args2.iffalse)
118                 args2.iffalse = ast_strip(args2.iffalse);
119
120         ast_copy_string(buf, pbx_checkcondition(args1.expr) ? (S_OR(args2.iftrue, "")) : (S_OR(args2.iffalse, "")), len);
121
122         return 0;
123 }
124
125 static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf,
126                size_t len)
127 {
128         char *varname;
129         char *val;
130
131         varname = strsep(&data, "=");
132         val = data;
133
134         if (ast_strlen_zero(varname) || !val) {
135                 ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n");
136                 return -1;
137         }
138
139         varname = ast_strip(varname);
140         val = ast_strip(val);
141         pbx_builtin_setvar_helper(chan, varname, val);
142         ast_copy_string(buf, val, len);
143
144         return 0;
145 }
146
147 static int acf_import(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
148 {
149         AST_DECLARE_APP_ARGS(args,
150                 AST_APP_ARG(channel);
151                 AST_APP_ARG(varname);
152         );
153         AST_STANDARD_APP_ARGS(args, data);
154         buf[0] = 0;
155         if (!ast_strlen_zero(args.varname)) {
156                 struct ast_channel *chan2 = ast_get_channel_by_name_locked(args.channel);
157                 if (chan2) {
158                         char *s = alloca(strlen(args.varname) + 4);
159                         if (s) {
160                                 sprintf(s, "${%s}", args.varname);
161                                 pbx_substitute_variables_helper(chan2, s, buf, len);
162                         }
163                         ast_channel_unlock(chan2);
164                 }
165         }
166         return 0;
167 }
168
169 static struct ast_custom_function isnull_function = {
170         .name = "ISNULL",
171         .synopsis = "NULL Test: Returns 1 if NULL or 0 otherwise",
172         .syntax = "ISNULL(<data>)",
173         .read = isnull,
174 };
175
176 static struct ast_custom_function set_function = {
177         .name = "SET",
178         .synopsis = "SET assigns a value to a channel variable",
179         .syntax = "SET(<varname>=[<value>])",
180         .read = set,
181 };
182
183 static struct ast_custom_function exists_function = {
184         .name = "EXISTS",
185         .synopsis = "Existence Test: Returns 1 if exists, 0 otherwise",
186         .syntax = "EXISTS(<data>)",
187         .read = exists,
188 };
189
190 static struct ast_custom_function if_function = {
191         .name = "IF",
192         .synopsis =
193                 "Conditional: Returns the data following '?' if true, else the data following ':'",
194         .syntax = "IF(<expr>?[<true>][:<false>])",
195         .read = acf_if,
196 };
197
198 static struct ast_custom_function if_time_function = {
199         .name = "IFTIME",
200         .synopsis =
201                 "Temporal Conditional: Returns the data following '?' if true, else the data following ':'",
202         .syntax = "IFTIME(<timespec>?[<true>][:<false>])",
203         .read = iftime,
204 };
205
206 static struct ast_custom_function import_function = {
207         .name = "IMPORT",
208         .synopsis =
209                 "Retrieve the value of a variable from another channel\n",
210         .syntax = "IMPORT(channel,variable)",
211         .read = acf_import,
212 };
213
214 static int unload_module(void)
215 {
216         int res = 0;
217
218         res |= ast_custom_function_unregister(&isnull_function);
219         res |= ast_custom_function_unregister(&set_function);
220         res |= ast_custom_function_unregister(&exists_function);
221         res |= ast_custom_function_unregister(&if_function);
222         res |= ast_custom_function_unregister(&if_time_function);
223         res |= ast_custom_function_unregister(&import_function);
224
225         return res;
226 }
227
228 static int load_module(void)
229 {
230         int res = 0;
231
232         res |= ast_custom_function_register(&isnull_function);
233         res |= ast_custom_function_register(&set_function);
234         res |= ast_custom_function_register(&exists_function);
235         res |= ast_custom_function_register(&if_function);
236         res |= ast_custom_function_register(&if_time_function);
237         res |= ast_custom_function_register(&import_function);
238
239         return res;
240 }
241
242 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions");