Asterisk - The Open Source Telephony Project  18.5.0
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 expresion.
76  </synopsis>
77  <syntax argsep="?">
78  <parameter name="expresion" 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  ***/
115 
116 static int isnull(struct ast_channel *chan, const char *cmd, char *data,
117  char *buf, size_t len)
118 {
119  strcpy(buf, data && *data ? "0" : "1");
120 
121  return 0;
122 }
123 
124 static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf,
125  size_t len)
126 {
127  strcpy(buf, data && *data ? "1" : "0");
128 
129  return 0;
130 }
131 
132 static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf,
133  size_t len)
134 {
135  struct ast_timing timing;
136  char *expr;
137  char *iftrue;
138  char *iffalse;
139 
140  data = ast_strip_quoted(data, "\"", "\"");
141  expr = strsep(&data, "?");
142  iftrue = strsep(&data, ":");
143  iffalse = data;
144 
145  if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
147  "Syntax IFTIME(<timespec>?[<true>][:<false>])\n");
148  return -1;
149  }
150 
151  if (!ast_build_timing(&timing, expr)) {
152  ast_log(LOG_WARNING, "Invalid Time Spec.\n");
153  ast_destroy_timing(&timing);
154  return -1;
155  }
156 
157  if (iftrue)
158  iftrue = ast_strip_quoted(iftrue, "\"", "\"");
159  if (iffalse)
160  iffalse = ast_strip_quoted(iffalse, "\"", "\"");
161 
162  ast_copy_string(buf, ast_check_timing(&timing) ? S_OR(iftrue, "") : S_OR(iffalse, ""), len);
163  ast_destroy_timing(&timing);
164 
165  return 0;
166 }
167 
168 static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf,
169  size_t len)
170 {
171  AST_DECLARE_APP_ARGS(args1,
172  AST_APP_ARG(expr);
173  AST_APP_ARG(remainder);
174  );
175  AST_DECLARE_APP_ARGS(args2,
176  AST_APP_ARG(iftrue);
177  AST_APP_ARG(iffalse);
178  );
179  args2.iftrue = args2.iffalse = NULL; /* you have to set these, because if there is nothing after the '?',
180  then args1.remainder will be NULL, not a pointer to a null string, and
181  then any garbage in args2.iffalse will not be cleared, and you'll crash.
182  -- and if you mod the ast_app_separate_args func instead, you'll really
183  mess things up badly, because the rest of everything depends on null args
184  for non-specified stuff. */
185 
186  AST_NONSTANDARD_APP_ARGS(args1, data, '?');
187  AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':');
188 
189  if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) {
190  ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>]) (expr must be non-null, and either <true> or <false> must be non-null)\n");
191  ast_log(LOG_WARNING, " In this case, <expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
192  return -1;
193  }
194 
195  args1.expr = ast_strip(args1.expr);
196  if (args2.iftrue)
197  args2.iftrue = ast_strip(args2.iftrue);
198  if (args2.iffalse)
199  args2.iffalse = ast_strip(args2.iffalse);
200 
201  ast_copy_string(buf, pbx_checkcondition(args1.expr) ? (S_OR(args2.iftrue, "")) : (S_OR(args2.iffalse, "")), len);
202 
203  return 0;
204 }
205 
206 static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf,
207  size_t len)
208 {
209  char *varname;
210  char *val;
211 
212  varname = strsep(&data, "=");
213  val = data;
214 
215  if (ast_strlen_zero(varname) || !val) {
216  ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n");
217  return -1;
218  }
219 
220  varname = ast_strip(varname);
221  val = ast_strip(val);
222  pbx_builtin_setvar_helper(chan, varname, val);
223  ast_copy_string(buf, val, len);
224 
225  return 0;
226 }
227 
228 static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
229 {
230  if (len > -1) {
231  ast_str_make_space(str, len == 0 ? strlen(data) : len);
232  }
233  return set(chan, cmd, data, ast_str_buffer(*str), ast_str_size(*str));
234 }
235 
236 static int import_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len)
237 {
240  AST_APP_ARG(varname);
241  );
243  if (buf) {
244  *buf = '\0';
245  }
246 
247  if (!ast_strlen_zero(args.varname)) {
248  struct ast_channel *chan2;
249 
250  if ((chan2 = ast_channel_get_by_name(args.channel))) {
251  char *s = ast_alloca(strlen(args.varname) + 4);
252  sprintf(s, "${%s}", args.varname);
253  ast_channel_lock(chan2);
254  if (buf) {
255  pbx_substitute_variables_helper(chan2, s, buf, len);
256  } else {
257  ast_str_substitute_variables(str, len, chan2, s);
258  }
259  ast_channel_unlock(chan2);
260  chan2 = ast_channel_unref(chan2);
261  }
262  }
263 
264  return 0;
265 }
266 
267 static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
268 {
269  return import_helper(chan, cmd, data, buf, NULL, len);
270 }
271 
272 static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
273 {
274  return import_helper(chan, cmd, data, NULL, str, len);
275 }
276 
278  .name = "ISNULL",
279  .read = isnull,
280  .read_max = 2,
281 };
282 
284  .name = "SET",
285  .read = set,
286  .read2 = set2,
287 };
288 
290  .name = "EXISTS",
291  .read = exists,
292  .read_max = 2,
293 };
294 
296  .name = "IF",
297  .read = acf_if,
298 };
299 
301  .name = "IFTIME",
302  .read = iftime,
303 };
304 
306  .name = "IMPORT",
307  .read = import_read,
308  .read2 = import_read2,
309 };
310 
311 static int unload_module(void)
312 {
313  int res = 0;
314 
315  res |= ast_custom_function_unregister(&isnull_function);
316  res |= ast_custom_function_unregister(&set_function);
317  res |= ast_custom_function_unregister(&exists_function);
318  res |= ast_custom_function_unregister(&if_function);
319  res |= ast_custom_function_unregister(&if_time_function);
320  res |= ast_custom_function_unregister(&import_function);
321 
322  return res;
323 }
324 
325 static int load_module(void)
326 {
327  int res = 0;
328 
329  res |= ast_custom_function_register(&isnull_function);
330  res |= ast_custom_function_register(&set_function);
331  res |= ast_custom_function_register(&exists_function);
332  res |= ast_custom_function_register(&if_function);
333  res |= ast_custom_function_register(&if_time_function);
334  res |= ast_custom_function_register(&import_function);
335 
336  return res;
337 }
338 
339 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions");
const char * name
Definition: pbx.h:119
static struct ast_custom_function set_function
Definition: func_logic.c:283
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
Definition: func_logic.c:272
Asterisk main include file. File version handling, generic pbx functions.
Definition: ast_expr2.c:325
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:124
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:699
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:168
static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
Definition: func_logic.c:228
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8321
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: muted.c:95
const char * str
Definition: app_jack.c:147
const char * args
#define NULL
Definition: resample.c:96
const char * data
static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:267
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
static struct ast_custom_function isnull_function
Definition: func_logic.c:277
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: main/utils.c:1639
#define ast_log
Definition: astobj2.c:42
General Asterisk PBX channel definitions.
static int unload_module(void)
Definition: func_logic.c:311
static struct ast_custom_function exists_function
Definition: func_logic.c:289
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:219
static struct ast_custom_function if_time_function
Definition: func_logic.c:300
static struct ast_custom_function import_function
Definition: func_logic.c:305
Core PBX routines and definitions.
static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:132
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
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:4002
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the &#39;nonstandard&#39; argument separation process for an application.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_destroy_timing(struct ast_timing *i)
Deallocates memory structures associated with a timing bitmap.
Definition: pbx_timing.c:285
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static int load_module(void)
Definition: func_logic.c:325
static struct ast_custom_function if_function
Definition: func_logic.c:295
int ast_build_timing(struct ast_timing *i, const char *info)
Construct a timing bitmap, for use in time-based conditionals.
Definition: extconf.c:3808
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...
char * strsep(char **str, const char *delims)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
static int isnull(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:116
#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&#39;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:1508
static int import_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len)
Definition: func_logic.c:236
#define AST_APP_ARG(name)
Define an application argument.