Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


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 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370642 $")
34 
35 #include "asterisk/module.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/app.h"
40 
41 /*** DOCUMENTATION
42  <function name="ISNULL" language="en_US">
43  <synopsis>
44  Check if a value is NULL.
45  </synopsis>
46  <syntax>
47  <parameter name="data" required="true" />
48  </syntax>
49  <description>
50  <para>Returns <literal>1</literal> if NULL or <literal>0</literal> otherwise.</para>
51  </description>
52  </function>
53  <function name="SET" language="en_US">
54  <synopsis>
55  SET assigns a value to a channel variable.
56  </synopsis>
57  <syntax argsep="=">
58  <parameter name="varname" required="true" />
59  <parameter name="value" />
60  </syntax>
61  <description>
62  </description>
63  </function>
64  <function name="EXISTS" language="en_US">
65  <synopsis>
66  Test the existence of a value.
67  </synopsis>
68  <syntax>
69  <parameter name="data" required="true" />
70  </syntax>
71  <description>
72  <para>Returns <literal>1</literal> if exists, <literal>0</literal> otherwise.</para>
73  </description>
74  </function>
75  <function name="IF" language="en_US">
76  <synopsis>
77  Check for an expresion.
78  </synopsis>
79  <syntax argsep="?">
80  <parameter name="expresion" required="true" />
81  <parameter name="retvalue" argsep=":" required="true">
82  <argument name="true" />
83  <argument name="false" />
84  </parameter>
85  </syntax>
86  <description>
87  <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
88  </description>
89  </function>
90  <function name="IFTIME" language="en_US">
91  <synopsis>
92  Temporal Conditional.
93  </synopsis>
94  <syntax argsep="?">
95  <parameter name="timespec" required="true" />
96  <parameter name="retvalue" required="true" argsep=":">
97  <argument name="true" />
98  <argument name="false" />
99  </parameter>
100  </syntax>
101  <description>
102  <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
103  </description>
104  </function>
105  <function name="IMPORT" language="en_US">
106  <synopsis>
107  Retrieve the value of a variable from another channel.
108  </synopsis>
109  <syntax>
110  <parameter name="channel" required="true" />
111  <parameter name="variable" required="true" />
112  </syntax>
113  <description>
114  </description>
115  </function>
116  ***/
117 
118 static int isnull(struct ast_channel *chan, const char *cmd, char *data,
119  char *buf, size_t len)
120 {
121  strcpy(buf, data && *data ? "0" : "1");
122 
123  return 0;
124 }
125 
126 static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf,
127  size_t len)
128 {
129  strcpy(buf, data && *data ? "1" : "0");
130 
131  return 0;
132 }
133 
134 static int iftime(struct ast_channel *chan, const char *cmd, char *data, char *buf,
135  size_t len)
136 {
137  struct ast_timing timing;
138  char *expr;
139  char *iftrue;
140  char *iffalse;
141 
142  data = ast_strip_quoted(data, "\"", "\"");
143  expr = strsep(&data, "?");
144  iftrue = strsep(&data, ":");
145  iffalse = data;
146 
147  if (ast_strlen_zero(expr) || !(iftrue || iffalse)) {
149  "Syntax IFTIME(<timespec>?[<true>][:<false>])\n");
150  return -1;
151  }
152 
153  if (!ast_build_timing(&timing, expr)) {
154  ast_log(LOG_WARNING, "Invalid Time Spec.\n");
155  ast_destroy_timing(&timing);
156  return -1;
157  }
158 
159  if (iftrue)
160  iftrue = ast_strip_quoted(iftrue, "\"", "\"");
161  if (iffalse)
162  iffalse = ast_strip_quoted(iffalse, "\"", "\"");
163 
164  ast_copy_string(buf, ast_check_timing(&timing) ? S_OR(iftrue, "") : S_OR(iffalse, ""), len);
165  ast_destroy_timing(&timing);
166 
167  return 0;
168 }
169 
170 static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf,
171  size_t len)
172 {
173  AST_DECLARE_APP_ARGS(args1,
174  AST_APP_ARG(expr);
175  AST_APP_ARG(remainder);
176  );
177  AST_DECLARE_APP_ARGS(args2,
178  AST_APP_ARG(iftrue);
179  AST_APP_ARG(iffalse);
180  );
181  args2.iftrue = args2.iffalse = NULL; /* you have to set these, because if there is nothing after the '?',
182  then args1.remainder will be NULL, not a pointer to a null string, and
183  then any garbage in args2.iffalse will not be cleared, and you'll crash.
184  -- and if you mod the ast_app_separate_args func instead, you'll really
185  mess things up badly, because the rest of everything depends on null args
186  for non-specified stuff. */
187 
188  AST_NONSTANDARD_APP_ARGS(args1, data, '?');
189  AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':');
190 
191  if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) {
192  ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>]) (expr must be non-null, and either <true> or <false> must be non-null)\n");
193  ast_log(LOG_WARNING, " In this case, <expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
194  return -1;
195  }
196 
197  args1.expr = ast_strip(args1.expr);
198  if (args2.iftrue)
199  args2.iftrue = ast_strip(args2.iftrue);
200  if (args2.iffalse)
201  args2.iffalse = ast_strip(args2.iffalse);
202 
203  ast_copy_string(buf, pbx_checkcondition(args1.expr) ? (S_OR(args2.iftrue, "")) : (S_OR(args2.iffalse, "")), len);
204 
205  return 0;
206 }
207 
208 static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf,
209  size_t len)
210 {
211  char *varname;
212  char *val;
213 
214  varname = strsep(&data, "=");
215  val = data;
216 
217  if (ast_strlen_zero(varname) || !val) {
218  ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n");
219  return -1;
220  }
221 
222  varname = ast_strip(varname);
223  val = ast_strip(val);
224  pbx_builtin_setvar_helper(chan, varname, val);
225  ast_copy_string(buf, val, len);
226 
227  return 0;
228 }
229 
230 static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
231 {
232  if (len > -1) {
233  ast_str_make_space(str, len == 0 ? strlen(data) : len);
234  }
235  return set(chan, cmd, data, ast_str_buffer(*str), ast_str_size(*str));
236 }
237 
238 static int import_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len)
239 {
241  AST_APP_ARG(channel);
242  AST_APP_ARG(varname);
243  );
245  if (buf) {
246  *buf = '\0';
247  }
248 
249  if (!ast_strlen_zero(args.varname)) {
250  struct ast_channel *chan2;
251 
252  if ((chan2 = ast_channel_get_by_name(args.channel))) {
253  char *s = ast_alloca(strlen(args.varname) + 4);
254  sprintf(s, "${%s}", args.varname);
255  ast_channel_lock(chan2);
256  if (buf) {
257  pbx_substitute_variables_helper(chan2, s, buf, len);
258  } else {
259  ast_str_substitute_variables(str, len, chan2, s);
260  }
261  ast_channel_unlock(chan2);
262  chan2 = ast_channel_unref(chan2);
263  }
264  }
265 
266  return 0;
267 }
268 
269 static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
270 {
271  return import_helper(chan, cmd, data, buf, NULL, len);
272 }
273 
274 static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
275 {
276  return import_helper(chan, cmd, data, NULL, str, len);
277 }
278 
280  .name = "ISNULL",
281  .read = isnull,
282  .read_max = 2,
283 };
284 
286  .name = "SET",
287  .read = set,
288  .read2 = set2,
289 };
290 
292  .name = "EXISTS",
293  .read = exists,
294  .read_max = 2,
295 };
296 
298  .name = "IF",
299  .read = acf_if,
300 };
301 
303  .name = "IFTIME",
304  .read = iftime,
305 };
306 
308  .name = "IMPORT",
309  .read = import_read,
310  .read2 = import_read2,
311 };
312 
313 static int unload_module(void)
314 {
315  int res = 0;
316 
317  res |= ast_custom_function_unregister(&isnull_function);
318  res |= ast_custom_function_unregister(&set_function);
319  res |= ast_custom_function_unregister(&exists_function);
320  res |= ast_custom_function_unregister(&if_function);
321  res |= ast_custom_function_unregister(&if_time_function);
322  res |= ast_custom_function_unregister(&import_function);
323 
324  return res;
325 }
326 
327 static int load_module(void)
328 {
329  int res = 0;
330 
331  res |= ast_custom_function_register(&isnull_function);
332  res |= ast_custom_function_register(&set_function);
333  res |= ast_custom_function_register(&exists_function);
334  res |= ast_custom_function_register(&if_function);
335  res |= ast_custom_function_register(&if_time_function);
336  res |= ast_custom_function_register(&import_function);
337 
338  return res;
339 }
340 
341 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions");
static struct ast_custom_function set_function
Definition: func_logic.c:285
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: pbx.c:4676
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
Definition: func_logic.c:274
Asterisk main include file. File version handling, generic pbx functions.
char * strsep(char **str, const char *delims)
Definition: ast_expr2.c:325
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:126
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:482
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:170
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
Definition: func_logic.c:230
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:10719
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
const char * str
Definition: app_jack.c:144
const char * data
Definition: channel.h:755
static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:269
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
Utility functions.
static struct ast_custom_function isnull_function
Definition: func_logic.c:279
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:1431
General Asterisk PBX channel definitions.
static int unload_module(void)
Definition: func_logic.c:313
int ast_str_make_space(struct ast_str **buf, size_t new_len)
Definition: strings.h:588
static struct ast_custom_function exists_function
Definition: func_logic.c:291
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Data structure associated with a custom dialplan function.
Definition: pbx.h:95
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
static struct ast_custom_function if_time_function
Definition: func_logic.c:302
static struct ast_custom_function import_function
Definition: func_logic.c:307
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:134
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static struct @350 args
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: pbx.c:8357
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int ast_destroy_timing(struct ast_timing *i)
Deallocates memory structures associated with a timing bitmap.
Definition: pbx.c:8396
#define ast_channel_unlock(chan)
Definition: channel.h:2467
static int load_module(void)
Definition: func_logic.c:327
static struct ast_custom_function if_function
Definition: func_logic.c:297
int ast_build_timing(struct ast_timing *i, const char *info)
Construct a timing bitmap, for use in time-based conditionals.
Definition: pbx.c:8314
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...
Definition: pbx.c:10546
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:208
const char * name
Definition: pbx.h:96
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static int isnull(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:118
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the &#39;nonstandard&#39; argument separation process for an application.
Definition: app.h:619
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1803
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
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:238
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180