Asterisk - The Open Source Telephony Project  21.4.1
func_logic.c
Go to the documentation of this file.
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 /*** MODULEINFO
28  <support_level>core</support_level>
29  ***/
30 
31 #include "asterisk.h"
32 
33 #include "asterisk/module.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/utils.h"
37 #include "asterisk/app.h"
38 
39 /*** DOCUMENTATION
40  <function name="ISNULL" language="en_US">
41  <synopsis>
42  Check if a value is NULL.
43  </synopsis>
44  <syntax>
45  <parameter name="data" required="true" />
46  </syntax>
47  <description>
48  <para>Returns <literal>1</literal> if NULL or <literal>0</literal> otherwise.</para>
49  </description>
50  </function>
51  <function name="SET" language="en_US">
52  <synopsis>
53  SET assigns a value to a channel variable.
54  </synopsis>
55  <syntax argsep="=">
56  <parameter name="varname" required="true" />
57  <parameter name="value" />
58  </syntax>
59  <description>
60  </description>
61  </function>
62  <function name="EXISTS" language="en_US">
63  <synopsis>
64  Test the existence of a value.
65  </synopsis>
66  <syntax>
67  <parameter name="data" required="true" />
68  </syntax>
69  <description>
70  <para>Returns <literal>1</literal> if exists, <literal>0</literal> otherwise.</para>
71  </description>
72  </function>
73  <function name="IF" language="en_US">
74  <synopsis>
75  Check for an expression.
76  </synopsis>
77  <syntax argsep="?">
78  <parameter name="expression" required="true" />
79  <parameter name="retvalue" argsep=":" required="true">
80  <argument name="true" />
81  <argument name="false" />
82  </parameter>
83  </syntax>
84  <description>
85  <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
86  </description>
87  </function>
88  <function name="IFTIME" language="en_US">
89  <synopsis>
90  Temporal Conditional.
91  </synopsis>
92  <syntax argsep="?">
93  <parameter name="timespec" required="true" />
94  <parameter name="retvalue" required="true" argsep=":">
95  <argument name="true" />
96  <argument name="false" />
97  </parameter>
98  </syntax>
99  <description>
100  <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
101  </description>
102  </function>
103  <function name="IMPORT" language="en_US">
104  <synopsis>
105  Retrieve the value of a variable from another channel.
106  </synopsis>
107  <syntax>
108  <parameter name="channel" required="true" />
109  <parameter name="variable" required="true" />
110  </syntax>
111  <description>
112  </description>
113  </function>
114  <function name="DELETE" language="en_US">
115  <synopsis>
116  Deletes a specified channel variable.
117  </synopsis>
118  <syntax>
119  <parameter name="varname" required="true">
120  <para>Channel variable name</para>
121  </parameter>
122  </syntax>
123  <description>
124  <para>Delete the channel variable specified in <replaceable>varname</replaceable>.
125  Will succeed if the channel variable exists or not.</para>
126  </description>
127  <see-also>
128  <ref type="function">GLOBAL_DELETE</ref>
129  </see-also>
130  </function>
131  <function name="VARIABLE_EXISTS" language="en_US">
132  <synopsis>
133  Check if a dialplan variable exists or not.
134  </synopsis>
135  <syntax>
136  <parameter name="varname" required="true">
137  <para>Channel variable name</para>
138  </parameter>
139  </syntax>
140  <description>
141  <para>Returns <literal>1</literal> if channel variable exists or <literal>0</literal> otherwise.</para>
142  </description>
143  <see-also>
144  <ref type="function">GLOBAL_EXISTS</ref>
145  </see-also>
146  </function>
147  ***/
148 
149 static int isnull(struct ast_channel *chan, const char *cmd, char *data,
150  char *buf, size_t len)
151 {
152  strcpy(buf, data && *data ? "0" : "1");
153 
154  return 0;
155 }
156 
157 static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf,
158  size_t len)
159 {
160  strcpy(buf, data && *data ? "1" : "0");
161 
162  return 0;
163 }
164 
165 static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf,
166  size_t len)
167 {
168  struct ast_timing timing;
169  char *expr;
170  char *iftrue;
171  char *iffalse;
172 
173  data = ast_strip_quoted(data, "\"", "\"");
174  expr = strsep(&data, "?");
175  iftrue = strsep(&data, ":");
176  iffalse = data;
177 
178  if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
179  ast_log(LOG_WARNING,
180  "Syntax IFTIME(<timespec>?[<true>][:<false>])\n");
181  return -1;
182  }
183 
184  if (!ast_build_timing(&timing, expr)) {
185  ast_log(LOG_WARNING, "Invalid Time Spec.\n");
186  ast_destroy_timing(&timing);
187  return -1;
188  }
189 
190  if (iftrue)
191  iftrue = ast_strip_quoted(iftrue, "\"", "\"");
192  if (iffalse)
193  iffalse = ast_strip_quoted(iffalse, "\"", "\"");
194 
195  ast_copy_string(buf, ast_check_timing(&timing) ? S_OR(iftrue, "") : S_OR(iffalse, ""), len);
196  ast_destroy_timing(&timing);
197 
198  return 0;
199 }
200 
201 static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf,
202  size_t len)
203 {
204  AST_DECLARE_APP_ARGS(args1,
205  AST_APP_ARG(expr);
206  AST_APP_ARG(remainder);
207  );
208  AST_DECLARE_APP_ARGS(args2,
209  AST_APP_ARG(iftrue);
210  AST_APP_ARG(iffalse);
211  );
212  args2.iftrue = args2.iffalse = NULL; /* you have to set these, because if there is nothing after the '?',
213  then args1.remainder will be NULL, not a pointer to a null string, and
214  then any garbage in args2.iffalse will not be cleared, and you'll crash.
215  -- and if you mod the ast_app_separate_args func instead, you'll really
216  mess things up badly, because the rest of everything depends on null args
217  for non-specified stuff. */
218 
219  AST_NONSTANDARD_APP_ARGS(args1, data, '?');
220  AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':');
221 
222  if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) {
223  ast_debug(1, "<expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
224  return -1;
225  }
226 
227  args1.expr = ast_strip(args1.expr);
228  if (args2.iftrue)
229  args2.iftrue = ast_strip(args2.iftrue);
230  if (args2.iffalse)
231  args2.iffalse = ast_strip(args2.iffalse);
232 
233  ast_copy_string(buf, pbx_checkcondition(args1.expr) ? (S_OR(args2.iftrue, "")) : (S_OR(args2.iffalse, "")), len);
234 
235  return 0;
236 }
237 
238 static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf,
239  size_t len)
240 {
241  char *varname;
242  char *val;
243 
244  varname = strsep(&data, "=");
245  val = data;
246 
247  if (ast_strlen_zero(varname) || !val) {
248  ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n");
249  return -1;
250  }
251 
252  varname = ast_strip(varname);
253  val = ast_strip(val);
254  pbx_builtin_setvar_helper(chan, varname, val);
255  ast_copy_string(buf, val, len);
256 
257  return 0;
258 }
259 
260 static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
261 {
262  if (len > -1) {
263  ast_str_make_space(str, len == 0 ? strlen(data) : len);
264  }
265  return set(chan, cmd, data, ast_str_buffer(*str), ast_str_size(*str));
266 }
267 
268 static int import_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len)
269 {
271  AST_APP_ARG(channel);
272  AST_APP_ARG(varname);
273  );
274  AST_STANDARD_APP_ARGS(args, data);
275  if (buf) {
276  *buf = '\0';
277  }
278 
279  if (!ast_strlen_zero(args.varname)) {
280  struct ast_channel *chan2;
281 
282  if ((chan2 = ast_channel_get_by_name(args.channel))) {
283  char *s = ast_alloca(strlen(args.varname) + 4);
284  sprintf(s, "${%s}", args.varname);
285  ast_channel_lock(chan2);
286  if (buf) {
287  pbx_substitute_variables_helper(chan2, s, buf, len);
288  } else {
289  ast_str_substitute_variables(str, len, chan2, s);
290  }
291  ast_channel_unlock(chan2);
292  chan2 = ast_channel_unref(chan2);
293  }
294  }
295 
296  return 0;
297 }
298 
299 static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
300 {
301  return import_helper(chan, cmd, data, buf, NULL, len);
302 }
303 
304 static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
305 {
306  return import_helper(chan, cmd, data, NULL, str, len);
307 }
308 
309 static int delete_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
310 {
311  pbx_builtin_setvar_helper(chan, data, NULL);
312 
313  return 0;
314 }
315 
316 static int variable_exists_read(struct ast_channel *chan, const char *cmd, char *data,
317  char *buf, size_t len)
318 {
319  const char *var = pbx_builtin_getvar_helper(chan, data);
320 
321  strcpy(buf, var ? "1" : "0");
322 
323  return 0;
324 }
325 
326 static struct ast_custom_function isnull_function = {
327  .name = "ISNULL",
328  .read = isnull,
329  .read_max = 2,
330 };
331 
332 static struct ast_custom_function set_function = {
333  .name = "SET",
334  .read = set,
335  .read2 = set2,
336 };
337 
338 static struct ast_custom_function exists_function = {
339  .name = "EXISTS",
340  .read = exists,
341  .read_max = 2,
342 };
343 
344 static struct ast_custom_function if_function = {
345  .name = "IF",
346  .read = acf_if,
347 };
348 
349 static struct ast_custom_function if_time_function = {
350  .name = "IFTIME",
351  .read = iftime,
352 };
353 
354 static struct ast_custom_function import_function = {
355  .name = "IMPORT",
356  .read = import_read,
357  .read2 = import_read2,
358 };
359 
360 static struct ast_custom_function delete_function = {
361  .name = "DELETE",
362  .write = delete_write,
363 };
364 
365 static struct ast_custom_function variable_exists_function = {
366  .name = "VARIABLE_EXISTS",
367  .read = variable_exists_read,
368 };
369 
370 static int unload_module(void)
371 {
372  int res = 0;
373 
374  res |= ast_custom_function_unregister(&isnull_function);
375  res |= ast_custom_function_unregister(&set_function);
376  res |= ast_custom_function_unregister(&exists_function);
377  res |= ast_custom_function_unregister(&if_function);
378  res |= ast_custom_function_unregister(&if_time_function);
379  res |= ast_custom_function_unregister(&import_function);
380  res |= ast_custom_function_unregister(&delete_function);
381  res |= ast_custom_function_unregister(&variable_exists_function);
382 
383  return res;
384 }
385 
386 static int load_module(void)
387 {
388  int res = 0;
389 
390  res |= ast_custom_function_register(&isnull_function);
391  res |= ast_custom_function_register(&set_function);
392  res |= ast_custom_function_register(&exists_function);
393  res |= ast_custom_function_register(&if_function);
394  res |= ast_custom_function_register(&if_time_function);
395  res |= ast_custom_function_register(&import_function);
396  res |= ast_custom_function_register(&delete_function);
397  res |= ast_custom_function_register(&variable_exists_function);
398 
399  return res;
400 }
401 
402 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions");
const char * name
Definition: pbx.h:119
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
int ast_build_timing(struct ast_timing *i, const char *info_in)
Construct a timing bitmap, for use in time-based conditionals.
Definition: extconf.c:3806
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:742
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8282
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Utility functions.
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: utils.c:1818
General Asterisk PBX channel definitions.
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
#define ast_debug(level,...)
Log a DEBUG message.
Core PBX routines and definitions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
Support for dynamic strings.
Definition: strings.h:623
int ast_check_timing(const struct ast_timing *i)
Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified...
Definition: extconf.c:4000
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
int ast_destroy_timing(struct ast_timing *i)
Deallocates memory structures associated with a timing bitmap.
Definition: pbx_timing.c:279
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define AST_APP_ARG(name)
Define an application argument.