Merge "pbx: Reduce verbosity while loading extensions"
[asterisk/asterisk.git] / main / pbx_variables.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2016, CFWare, LLC
5  *
6  * Corey Farrell <git@cfware.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief PBX variables routines.
22  *
23  * \author Corey Farrell <git@cfware.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/_private.h"
33 #include "asterisk/app.h"
34 #include "asterisk/ast_expr.h"
35 #include "asterisk/chanvars.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/linkedlists.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/module.h"
40 #include "asterisk/paths.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/stasis_channels.h"
43 #include "pbx_private.h"
44
45 /*** DOCUMENTATION
46         <application name="Set" language="en_US">
47                 <synopsis>
48                         Set channel variable or function value.
49                 </synopsis>
50                 <syntax argsep="=">
51                         <parameter name="name" required="true" />
52                         <parameter name="value" required="true" />
53                 </syntax>
54                 <description>
55                         <para>This function can be used to set the value of channel variables or dialplan functions.
56                         When setting variables, if the variable name is prefixed with <literal>_</literal>,
57                         the variable will be inherited into channels created from the current channel.
58                         If the variable name is prefixed with <literal>__</literal>, the variable will be
59                         inherited into channels created from the current channel and all children channels.</para>
60                         <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
61                         a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
62                         the behavior of this app changes, and strips surrounding quotes from the right hand side as
63                         it did previously in 1.4.
64                         The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
65                         were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
66                         protect separators and quotes in various database access strings has been greatly
67                         reduced by these changes.</para></note>
68                 </description>
69                 <see-also>
70                         <ref type="application">MSet</ref>
71                         <ref type="function">GLOBAL</ref>
72                         <ref type="function">SET</ref>
73                         <ref type="function">ENV</ref>
74                 </see-also>
75         </application>
76         <application name="MSet" language="en_US">
77                 <synopsis>
78                         Set channel variable(s) or function value(s).
79                 </synopsis>
80                 <syntax>
81                         <parameter name="set1" required="true" argsep="=">
82                                 <argument name="name1" required="true" />
83                                 <argument name="value1" required="true" />
84                         </parameter>
85                         <parameter name="set2" multiple="true" argsep="=">
86                                 <argument name="name2" required="true" />
87                                 <argument name="value2" required="true" />
88                         </parameter>
89                 </syntax>
90                 <description>
91                         <para>This function can be used to set the value of channel variables or dialplan functions.
92                         When setting variables, if the variable name is prefixed with <literal>_</literal>,
93                         the variable will be inherited into channels created from the current channel
94                         If the variable name is prefixed with <literal>__</literal>, the variable will be
95                         inherited into channels created from the current channel and all children channels.
96                         MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
97                         prone to doing things that you may not expect. For example, it strips surrounding
98                         double-quotes from the right-hand side (value). If you need to put a separator
99                         character (comma or vert-bar), you will need to escape them by inserting a backslash
100                         before them. Avoid its use if possible.</para>
101                 </description>
102                 <see-also>
103                         <ref type="application">Set</ref>
104                 </see-also>
105         </application>
106  ***/
107
108 AST_RWLOCK_DEFINE_STATIC(globalslock);
109 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
110
111 /*!
112  * \brief extract offset:length from variable name.
113  * \return 1 if there is a offset:length part, which is
114  * trimmed off (values go into variables)
115  */
116 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
117 {
118         int parens = 0;
119
120         *offset = 0;
121         *length = INT_MAX;
122         *isfunc = 0;
123         for (; *var; var++) {
124                 if (*var == '(') {
125                         (*isfunc)++;
126                         parens++;
127                 } else if (*var == ')') {
128                         parens--;
129                 } else if (*var == ':' && parens == 0) {
130                         *var++ = '\0';
131                         sscanf(var, "%30d:%30d", offset, length);
132                         return 1; /* offset:length valid */
133                 }
134         }
135         return 0;
136 }
137
138 /*!
139  *\brief takes a substring. It is ok to call with value == workspace.
140  * \param value
141  * \param offset < 0 means start from the end of the string and set the beginning
142  *   to be that many characters back.
143  * \param length is the length of the substring, a value less than 0 means to leave
144  * that many off the end.
145  * \param workspace
146  * \param workspace_len
147  * Always return a copy in workspace.
148  */
149 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
150 {
151         char *ret = workspace;
152         int lr; /* length of the input string after the copy */
153
154         ast_copy_string(workspace, value, workspace_len); /* always make a copy */
155
156         lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
157
158         /* Quick check if no need to do anything */
159         if (offset == 0 && length >= lr)        /* take the whole string */
160                 return ret;
161
162         if (offset < 0) {       /* translate negative offset into positive ones */
163                 offset = lr + offset;
164                 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
165                         offset = 0;
166         }
167
168         /* too large offset result in empty string so we know what to return */
169         if (offset >= lr)
170                 return ret + lr;        /* the final '\0' */
171
172         ret += offset;          /* move to the start position */
173         if (length >= 0 && length < lr - offset)        /* truncate if necessary */
174                 ret[length] = '\0';
175         else if (length < 0) {
176                 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
177                         ret[lr + length - offset] = '\0';
178                 else
179                         ret[0] = '\0';
180         }
181
182         return ret;
183 }
184
185 static const char *ast_str_substring(struct ast_str *value, int offset, int length)
186 {
187         int lr; /* length of the input string after the copy */
188
189         lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
190
191         /* Quick check if no need to do anything */
192         if (offset == 0 && length >= lr)        /* take the whole string */
193                 return ast_str_buffer(value);
194
195         if (offset < 0) {       /* translate negative offset into positive ones */
196                 offset = lr + offset;
197                 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
198                         offset = 0;
199         }
200
201         /* too large offset result in empty string so we know what to return */
202         if (offset >= lr) {
203                 ast_str_reset(value);
204                 return ast_str_buffer(value);
205         }
206
207         if (offset > 0) {
208                 /* Go ahead and chop off the beginning */
209                 memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
210                 lr -= offset;
211         }
212
213         if (length >= 0 && length < lr) {       /* truncate if necessary */
214                 char *tmp = ast_str_buffer(value);
215                 tmp[length] = '\0';
216                 ast_str_update(value);
217         } else if (length < 0) {
218                 if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
219                         char *tmp = ast_str_buffer(value);
220                         tmp[lr + length] = '\0';
221                         ast_str_update(value);
222                 } else {
223                         ast_str_reset(value);
224                 }
225         } else {
226                 /* Nothing to do, but update the buffer length */
227                 ast_str_update(value);
228         }
229
230         return ast_str_buffer(value);
231 }
232
233 /*! \brief  Support for Asterisk built-in variables in the dialplan
234
235 \note   See also
236         - \ref AstVar   Channel variables
237         - \ref AstCauses The HANGUPCAUSE variable
238  */
239 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
240 {
241         struct ast_str *str = ast_str_create(16);
242         const char *cret;
243
244         cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
245         ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
246         *ret = cret ? workspace : NULL;
247         ast_free(str);
248 }
249
250 const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
251 {
252         const char not_found = '\0';
253         char *tmpvar;
254         const char *ret;
255         const char *s;  /* the result */
256         int offset, length;
257         int i, need_substring;
258         struct varshead *places[2] = { headp, &globals };       /* list of places where we may look */
259         char workspace[20];
260
261         if (c) {
262                 ast_channel_lock(c);
263                 places[0] = ast_channel_varshead(c);
264         }
265         /*
266          * Make a copy of var because parse_variable_name() modifies the string.
267          * Then if called directly, we might need to run substring() on the result;
268          * remember this for later in 'need_substring', 'offset' and 'length'
269          */
270         tmpvar = ast_strdupa(var);      /* parse_variable_name modifies the string */
271         need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
272
273         /*
274          * Look first into predefined variables, then into variable lists.
275          * Variable 's' points to the result, according to the following rules:
276          * s == &not_found (set at the beginning) means that we did not find a
277          *      matching variable and need to look into more places.
278          * If s != &not_found, s is a valid result string as follows:
279          * s = NULL if the variable does not have a value;
280          *      you typically do this when looking for an unset predefined variable.
281          * s = workspace if the result has been assembled there;
282          *      typically done when the result is built e.g. with an snprintf(),
283          *      so we don't need to do an additional copy.
284          * s != workspace in case we have a string, that needs to be copied
285          *      (the ast_copy_string is done once for all at the end).
286          *      Typically done when the result is already available in some string.
287          */
288         s = &not_found; /* default value */
289         if (c) {        /* This group requires a valid channel */
290                 /* Names with common parts are looked up a piece at a time using strncmp. */
291                 if (!strncmp(var, "CALL", 4)) {
292                         if (!strncmp(var + 4, "ING", 3)) {
293                                 if (!strcmp(var + 7, "PRES")) {                 /* CALLINGPRES */
294                                         ast_str_set(str, maxlen, "%d",
295                                                 ast_party_id_presentation(&ast_channel_caller(c)->id));
296                                         s = ast_str_buffer(*str);
297                                 } else if (!strcmp(var + 7, "ANI2")) {          /* CALLINGANI2 */
298                                         ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
299                                         s = ast_str_buffer(*str);
300                                 } else if (!strcmp(var + 7, "TON")) {           /* CALLINGTON */
301                                         ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
302                                         s = ast_str_buffer(*str);
303                                 } else if (!strcmp(var + 7, "TNS")) {           /* CALLINGTNS */
304                                         ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
305                                         s = ast_str_buffer(*str);
306                                 }
307                         }
308                 } else if (!strcmp(var, "HINT")) {
309                         s = ast_str_get_hint(str, maxlen, NULL, 0, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
310                 } else if (!strcmp(var, "HINTNAME")) {
311                         s = ast_str_get_hint(NULL, 0, str, maxlen, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
312                 } else if (!strcmp(var, "EXTEN")) {
313                         s = ast_channel_exten(c);
314                 } else if (!strcmp(var, "CONTEXT")) {
315                         s = ast_channel_context(c);
316                 } else if (!strcmp(var, "PRIORITY")) {
317                         ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
318                         s = ast_str_buffer(*str);
319                 } else if (!strcmp(var, "CHANNEL")) {
320                         s = ast_channel_name(c);
321                 } else if (!strcmp(var, "UNIQUEID")) {
322                         s = ast_channel_uniqueid(c);
323                 } else if (!strcmp(var, "HANGUPCAUSE")) {
324                         ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
325                         s = ast_str_buffer(*str);
326                 }
327         }
328         if (s == &not_found) { /* look for more */
329                 if (!strcmp(var, "EPOCH")) {
330                         ast_str_set(str, maxlen, "%d", (int) time(NULL));
331                         s = ast_str_buffer(*str);
332                 } else if (!strcmp(var, "SYSTEMNAME")) {
333                         s = ast_config_AST_SYSTEM_NAME;
334                 } else if (!strcmp(var, "ASTETCDIR")) {
335                         s = ast_config_AST_CONFIG_DIR;
336                 } else if (!strcmp(var, "ASTMODDIR")) {
337                         s = ast_config_AST_MODULE_DIR;
338                 } else if (!strcmp(var, "ASTVARLIBDIR")) {
339                         s = ast_config_AST_VAR_DIR;
340                 } else if (!strcmp(var, "ASTDBDIR")) {
341                         s = ast_config_AST_DB;
342                 } else if (!strcmp(var, "ASTKEYDIR")) {
343                         s = ast_config_AST_KEY_DIR;
344                 } else if (!strcmp(var, "ASTDATADIR")) {
345                         s = ast_config_AST_DATA_DIR;
346                 } else if (!strcmp(var, "ASTAGIDIR")) {
347                         s = ast_config_AST_AGI_DIR;
348                 } else if (!strcmp(var, "ASTSPOOLDIR")) {
349                         s = ast_config_AST_SPOOL_DIR;
350                 } else if (!strcmp(var, "ASTRUNDIR")) {
351                         s = ast_config_AST_RUN_DIR;
352                 } else if (!strcmp(var, "ASTLOGDIR")) {
353                         s = ast_config_AST_LOG_DIR;
354                 } else if (!strcmp(var, "ENTITYID")) {
355                         ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
356                         s = workspace;
357                 }
358         }
359         /* if not found, look into chanvars or global vars */
360         for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
361                 struct ast_var_t *variables;
362                 if (!places[i])
363                         continue;
364                 if (places[i] == &globals)
365                         ast_rwlock_rdlock(&globalslock);
366                 AST_LIST_TRAVERSE(places[i], variables, entries) {
367                         if (!strcmp(ast_var_name(variables), var)) {
368                                 s = ast_var_value(variables);
369                                 break;
370                         }
371                 }
372                 if (places[i] == &globals)
373                         ast_rwlock_unlock(&globalslock);
374         }
375         if (s == &not_found || s == NULL) {
376                 ast_debug(5, "Result of '%s' is NULL\n", var);
377                 ret = NULL;
378         } else {
379                 ast_debug(5, "Result of '%s' is '%s'\n", var, s);
380                 if (s != ast_str_buffer(*str)) {
381                         ast_str_set(str, maxlen, "%s", s);
382                 }
383                 ret = ast_str_buffer(*str);
384                 if (need_substring) {
385                         ret = ast_str_substring(*str, offset, length);
386                         ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
387                 }
388         }
389
390         if (c) {
391                 ast_channel_unlock(c);
392         }
393         return ret;
394 }
395
396 void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
397 {
398         /* Substitutes variables into buf, based on string templ */
399         char *cp4 = NULL;
400         const char *whereweare;
401         int orig_size = 0;
402         int offset, offset2, isfunction;
403         const char *nextvar, *nextexp, *nextthing;
404         const char *vars, *vare;
405         char *finalvars;
406         int pos, brackets, needsub, len;
407         struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16);
408
409         ast_str_reset(*buf);
410         whereweare = templ;
411         while (!ast_strlen_zero(whereweare)) {
412                 /* reset our buffer */
413                 ast_str_reset(substr3);
414
415                 /* Assume we're copying the whole remaining string */
416                 pos = strlen(whereweare);
417                 nextvar = NULL;
418                 nextexp = NULL;
419                 nextthing = strchr(whereweare, '$');
420                 if (nextthing) {
421                         switch (nextthing[1]) {
422                         case '{':
423                                 nextvar = nextthing;
424                                 pos = nextvar - whereweare;
425                                 break;
426                         case '[':
427                                 nextexp = nextthing;
428                                 pos = nextexp - whereweare;
429                                 break;
430                         default:
431                                 pos = 1;
432                         }
433                 }
434
435                 if (pos) {
436                         /* Copy that many bytes */
437                         ast_str_append_substr(buf, maxlen, whereweare, pos);
438
439                         templ += pos;
440                         whereweare += pos;
441                 }
442
443                 if (nextvar) {
444                         /* We have a variable.  Find the start and end, and determine
445                            if we are going to have to recursively call ourselves on the
446                            contents */
447                         vars = vare = nextvar + 2;
448                         brackets = 1;
449                         needsub = 0;
450
451                         /* Find the end of it */
452                         while (brackets && *vare) {
453                                 if ((vare[0] == '$') && (vare[1] == '{')) {
454                                         needsub++;
455                                 } else if (vare[0] == '{') {
456                                         brackets++;
457                                 } else if (vare[0] == '}') {
458                                         brackets--;
459                                 } else if ((vare[0] == '$') && (vare[1] == '['))
460                                         needsub++;
461                                 vare++;
462                         }
463                         if (brackets)
464                                 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
465                         len = vare - vars - 1;
466
467                         /* Skip totally over variable string */
468                         whereweare += (len + 3);
469
470                         /* Store variable name (and truncate) */
471                         ast_str_set_substr(&substr1, 0, vars, len);
472                         ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
473
474                         /* Substitute if necessary */
475                         if (needsub) {
476                                 size_t my_used;
477
478                                 if (!substr2) {
479                                         substr2 = ast_str_create(16);
480                                 }
481                                 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
482                                 finalvars = ast_str_buffer(substr2);
483                         } else {
484                                 finalvars = ast_str_buffer(substr1);
485                         }
486
487                         parse_variable_name(finalvars, &offset, &offset2, &isfunction);
488                         if (isfunction) {
489                                 /* Evaluate function */
490                                 if (c || !headp) {
491                                         cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
492                                 } else {
493                                         struct varshead old;
494                                         struct ast_channel *bogus = ast_dummy_channel_alloc();
495                                         if (bogus) {
496                                                 memcpy(&old, ast_channel_varshead(bogus), sizeof(old));
497                                                 memcpy(ast_channel_varshead(bogus), headp, sizeof(*ast_channel_varshead(bogus)));
498                                                 cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
499                                                 /* Don't deallocate the varshead that was passed in */
500                                                 memcpy(ast_channel_varshead(bogus), &old, sizeof(*ast_channel_varshead(bogus)));
501                                                 ast_channel_unref(bogus);
502                                         } else {
503                                                 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
504                                         }
505                                 }
506                                 ast_debug(2, "Function %s result is '%s'\n", finalvars, cp4 ? cp4 : "(null)");
507                         } else {
508                                 /* Retrieve variable value */
509                                 ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
510                                 cp4 = ast_str_buffer(substr3);
511                         }
512                         if (cp4) {
513                                 ast_str_substring(substr3, offset, offset2);
514                                 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
515                         }
516                 } else if (nextexp) {
517                         /* We have an expression.  Find the start and end, and determine
518                            if we are going to have to recursively call ourselves on the
519                            contents */
520                         vars = vare = nextexp + 2;
521                         brackets = 1;
522                         needsub = 0;
523
524                         /* Find the end of it */
525                         while (brackets && *vare) {
526                                 if ((vare[0] == '$') && (vare[1] == '[')) {
527                                         needsub++;
528                                         brackets++;
529                                         vare++;
530                                 } else if (vare[0] == '[') {
531                                         brackets++;
532                                 } else if (vare[0] == ']') {
533                                         brackets--;
534                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
535                                         needsub++;
536                                         vare++;
537                                 }
538                                 vare++;
539                         }
540                         if (brackets)
541                                 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
542                         len = vare - vars - 1;
543
544                         /* Skip totally over expression */
545                         whereweare += (len + 3);
546
547                         /* Store variable name (and truncate) */
548                         ast_str_set_substr(&substr1, 0, vars, len);
549
550                         /* Substitute if necessary */
551                         if (needsub) {
552                                 size_t my_used;
553
554                                 if (!substr2) {
555                                         substr2 = ast_str_create(16);
556                                 }
557                                 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
558                                 finalvars = ast_str_buffer(substr2);
559                         } else {
560                                 finalvars = ast_str_buffer(substr1);
561                         }
562
563                         if (ast_str_expr(&substr3, 0, c, finalvars)) {
564                                 ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
565                         }
566                         ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
567                 }
568         }
569         *used = ast_str_strlen(*buf) - orig_size;
570         ast_free(substr1);
571         ast_free(substr2);
572         ast_free(substr3);
573 }
574
575 void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
576 {
577         size_t used;
578         ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used);
579 }
580
581 void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
582 {
583         size_t used;
584         ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used);
585 }
586
587 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
588 {
589         /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
590         char *cp4 = NULL;
591         const char *whereweare, *orig_cp2 = cp2;
592         int length, offset, offset2, isfunction;
593         char *workspace = NULL;
594         char *ltmp = NULL, *var = NULL;
595         char *nextvar, *nextexp, *nextthing;
596         char *vars, *vare;
597         int pos, brackets, needsub, len;
598
599         *cp2 = 0; /* just in case nothing ends up there */
600         whereweare = cp1;
601         while (!ast_strlen_zero(whereweare) && count) {
602                 /* Assume we're copying the whole remaining string */
603                 pos = strlen(whereweare);
604                 nextvar = NULL;
605                 nextexp = NULL;
606                 nextthing = strchr(whereweare, '$');
607                 if (nextthing) {
608                         switch (nextthing[1]) {
609                         case '{':
610                                 nextvar = nextthing;
611                                 pos = nextvar - whereweare;
612                                 break;
613                         case '[':
614                                 nextexp = nextthing;
615                                 pos = nextexp - whereweare;
616                                 break;
617                         default:
618                                 pos = 1;
619                         }
620                 }
621
622                 if (pos) {
623                         /* Can't copy more than 'count' bytes */
624                         if (pos > count)
625                                 pos = count;
626
627                         /* Copy that many bytes */
628                         memcpy(cp2, whereweare, pos);
629
630                         count -= pos;
631                         cp2 += pos;
632                         whereweare += pos;
633                         *cp2 = 0;
634                 }
635
636                 if (nextvar) {
637                         /* We have a variable.  Find the start and end, and determine
638                            if we are going to have to recursively call ourselves on the
639                            contents */
640                         vars = vare = nextvar + 2;
641                         brackets = 1;
642                         needsub = 0;
643
644                         /* Find the end of it */
645                         while (brackets && *vare) {
646                                 if ((vare[0] == '$') && (vare[1] == '{')) {
647                                         needsub++;
648                                 } else if (vare[0] == '{') {
649                                         brackets++;
650                                 } else if (vare[0] == '}') {
651                                         brackets--;
652                                 } else if ((vare[0] == '$') && (vare[1] == '['))
653                                         needsub++;
654                                 vare++;
655                         }
656                         if (brackets)
657                                 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
658                         len = vare - vars - 1;
659
660                         /* Skip totally over variable string */
661                         whereweare += (len + 3);
662
663                         if (!var)
664                                 var = ast_alloca(VAR_BUF_SIZE);
665
666                         /* Store variable name (and truncate) */
667                         ast_copy_string(var, vars, len + 1);
668
669                         /* Substitute if necessary */
670                         if (needsub) {
671                                 size_t my_used;
672
673                                 if (!ltmp) {
674                                         ltmp = ast_alloca(VAR_BUF_SIZE);
675                                 }
676                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
677                                 vars = ltmp;
678                         } else {
679                                 vars = var;
680                         }
681
682                         if (!workspace)
683                                 workspace = ast_alloca(VAR_BUF_SIZE);
684
685                         workspace[0] = '\0';
686
687                         parse_variable_name(vars, &offset, &offset2, &isfunction);
688                         if (isfunction) {
689                                 /* Evaluate function */
690                                 if (c || !headp)
691                                         cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
692                                 else {
693                                         struct varshead old;
694                                         struct ast_channel *c = ast_dummy_channel_alloc();
695                                         if (c) {
696                                                 memcpy(&old, ast_channel_varshead(c), sizeof(old));
697                                                 memcpy(ast_channel_varshead(c), headp, sizeof(*ast_channel_varshead(c)));
698                                                 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
699                                                 /* Don't deallocate the varshead that was passed in */
700                                                 memcpy(ast_channel_varshead(c), &old, sizeof(*ast_channel_varshead(c)));
701                                                 c = ast_channel_unref(c);
702                                         } else {
703                                                 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
704                                         }
705                                 }
706                                 ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
707                         } else {
708                                 /* Retrieve variable value */
709                                 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
710                         }
711                         if (cp4) {
712                                 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
713
714                                 length = strlen(cp4);
715                                 if (length > count)
716                                         length = count;
717                                 memcpy(cp2, cp4, length);
718                                 count -= length;
719                                 cp2 += length;
720                                 *cp2 = 0;
721                         }
722                 } else if (nextexp) {
723                         /* We have an expression.  Find the start and end, and determine
724                            if we are going to have to recursively call ourselves on the
725                            contents */
726                         vars = vare = nextexp + 2;
727                         brackets = 1;
728                         needsub = 0;
729
730                         /* Find the end of it */
731                         while (brackets && *vare) {
732                                 if ((vare[0] == '$') && (vare[1] == '[')) {
733                                         needsub++;
734                                         brackets++;
735                                         vare++;
736                                 } else if (vare[0] == '[') {
737                                         brackets++;
738                                 } else if (vare[0] == ']') {
739                                         brackets--;
740                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
741                                         needsub++;
742                                         vare++;
743                                 }
744                                 vare++;
745                         }
746                         if (brackets)
747                                 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
748                         len = vare - vars - 1;
749
750                         /* Skip totally over expression */
751                         whereweare += (len + 3);
752
753                         if (!var)
754                                 var = ast_alloca(VAR_BUF_SIZE);
755
756                         /* Store variable name (and truncate) */
757                         ast_copy_string(var, vars, len + 1);
758
759                         /* Substitute if necessary */
760                         if (needsub) {
761                                 size_t my_used;
762
763                                 if (!ltmp) {
764                                         ltmp = ast_alloca(VAR_BUF_SIZE);
765                                 }
766                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
767                                 vars = ltmp;
768                         } else {
769                                 vars = var;
770                         }
771
772                         length = ast_expr(vars, cp2, count, c);
773
774                         if (length) {
775                                 ast_debug(1, "Expression result is '%s'\n", cp2);
776                                 count -= length;
777                                 cp2 += length;
778                                 *cp2 = 0;
779                         }
780                 }
781         }
782         *used = cp2 - orig_cp2;
783 }
784
785 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
786 {
787         size_t used;
788         pbx_substitute_variables_helper_full(c, (c) ? ast_channel_varshead(c) : NULL, cp1, cp2, count, &used);
789 }
790
791 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
792 {
793         size_t used;
794         pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
795 }
796
797 /*! \brief CLI support for listing global variables in a parseable way */
798 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
799 {
800         int i = 0;
801         struct ast_var_t *newvariable;
802
803         switch (cmd) {
804         case CLI_INIT:
805                 e->command = "dialplan show globals";
806                 e->usage =
807                         "Usage: dialplan show globals\n"
808                         "       List current global dialplan variables and their values\n";
809                 return NULL;
810         case CLI_GENERATE:
811                 return NULL;
812         }
813
814         ast_rwlock_rdlock(&globalslock);
815         AST_LIST_TRAVERSE (&globals, newvariable, entries) {
816                 i++;
817                 ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
818         }
819         ast_rwlock_unlock(&globalslock);
820         ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
821
822         return CLI_SUCCESS;
823 }
824
825 /*! \brief CLI support for listing chanvar's variables in a parseable way */
826 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
827 {
828         struct ast_channel *chan;
829         struct ast_var_t *var;
830
831         switch (cmd) {
832         case CLI_INIT:
833                 e->command = "dialplan show chanvar";
834                 e->usage =
835                         "Usage: dialplan show chanvar <channel>\n"
836                         "       List current channel variables and their values\n";
837                 return NULL;
838         case CLI_GENERATE:
839                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
840         }
841
842         if (a->argc != e->args + 1) {
843                 return CLI_SHOWUSAGE;
844         }
845
846         chan = ast_channel_get_by_name(a->argv[e->args]);
847         if (!chan) {
848                 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
849                 return CLI_FAILURE;
850         }
851
852         ast_channel_lock(chan);
853         AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
854                 ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
855         }
856         ast_channel_unlock(chan);
857
858         ast_channel_unref(chan);
859         return CLI_SUCCESS;
860 }
861
862 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
863 {
864         switch (cmd) {
865         case CLI_INIT:
866                 e->command = "dialplan set global";
867                 e->usage =
868                         "Usage: dialplan set global <name> <value>\n"
869                         "       Set global dialplan variable <name> to <value>\n";
870                 return NULL;
871         case CLI_GENERATE:
872                 return NULL;
873         }
874
875         if (a->argc != e->args + 2)
876                 return CLI_SHOWUSAGE;
877
878         pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
879         ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
880
881         return CLI_SUCCESS;
882 }
883
884 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
885 {
886         struct ast_channel *chan;
887         const char *chan_name, *var_name, *var_value;
888
889         switch (cmd) {
890         case CLI_INIT:
891                 e->command = "dialplan set chanvar";
892                 e->usage =
893                         "Usage: dialplan set chanvar <channel> <varname> <value>\n"
894                         "       Set channel variable <varname> to <value>\n";
895                 return NULL;
896         case CLI_GENERATE:
897                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
898         }
899
900         if (a->argc != e->args + 3)
901                 return CLI_SHOWUSAGE;
902
903         chan_name = a->argv[e->args];
904         var_name = a->argv[e->args + 1];
905         var_value = a->argv[e->args + 2];
906
907         if (!(chan = ast_channel_get_by_name(chan_name))) {
908                 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
909                 return CLI_FAILURE;
910         }
911
912         pbx_builtin_setvar_helper(chan, var_name, var_value);
913
914         chan = ast_channel_unref(chan);
915
916         ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
917
918         return CLI_SUCCESS;
919 }
920
921 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
922 {
923         struct ast_var_t *variables;
924         const char *var, *val;
925         int total = 0;
926
927         if (!chan)
928                 return 0;
929
930         ast_str_reset(*buf);
931
932         ast_channel_lock(chan);
933
934         AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
935                 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
936                    /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
937                    ) {
938                         if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
939                                 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
940                                 break;
941                         } else
942                                 total++;
943                 } else
944                         break;
945         }
946
947         ast_channel_unlock(chan);
948
949         return total;
950 }
951
952 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
953 {
954         struct ast_var_t *variables;
955         const char *ret = NULL;
956         int i;
957         struct varshead *places[2] = { NULL, &globals };
958
959         if (!name)
960                 return NULL;
961
962         if (chan) {
963                 ast_channel_lock(chan);
964                 places[0] = ast_channel_varshead(chan);
965         }
966
967         for (i = 0; i < 2; i++) {
968                 if (!places[i])
969                         continue;
970                 if (places[i] == &globals)
971                         ast_rwlock_rdlock(&globalslock);
972                 AST_LIST_TRAVERSE(places[i], variables, entries) {
973                         if (!strcmp(name, ast_var_name(variables))) {
974                                 ret = ast_var_value(variables);
975                                 break;
976                         }
977                 }
978                 if (places[i] == &globals)
979                         ast_rwlock_unlock(&globalslock);
980                 if (ret)
981                         break;
982         }
983
984         if (chan)
985                 ast_channel_unlock(chan);
986
987         return ret;
988 }
989
990 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
991 {
992         struct ast_var_t *newvariable;
993         struct varshead *headp;
994
995         if (name[strlen(name)-1] == ')') {
996                 char *function = ast_strdupa(name);
997
998                 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
999                 ast_func_write(chan, function, value);
1000                 return;
1001         }
1002
1003         if (chan) {
1004                 ast_channel_lock(chan);
1005                 headp = ast_channel_varshead(chan);
1006         } else {
1007                 ast_rwlock_wrlock(&globalslock);
1008                 headp = &globals;
1009         }
1010
1011         if (value && (newvariable = ast_var_assign(name, value))) {
1012                 if (headp == &globals)
1013                         ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1014                 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1015         }
1016
1017         if (chan)
1018                 ast_channel_unlock(chan);
1019         else
1020                 ast_rwlock_unlock(&globalslock);
1021 }
1022
1023 int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
1024 {
1025         struct ast_var_t *newvariable;
1026         struct varshead *headp;
1027         const char *nametail = name;
1028         /*! True if the old value was not an empty string. */
1029         int old_value_existed = 0;
1030
1031         if (name[strlen(name) - 1] == ')') {
1032                 char *function = ast_strdupa(name);
1033
1034                 return ast_func_write(chan, function, value);
1035         }
1036
1037         if (chan) {
1038                 ast_channel_lock(chan);
1039                 headp = ast_channel_varshead(chan);
1040         } else {
1041                 ast_rwlock_wrlock(&globalslock);
1042                 headp = &globals;
1043         }
1044
1045         /* For comparison purposes, we have to strip leading underscores */
1046         if (*nametail == '_') {
1047                 nametail++;
1048                 if (*nametail == '_')
1049                         nametail++;
1050         }
1051
1052         AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1053                 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1054                         /* there is already such a variable, delete it */
1055                         AST_LIST_REMOVE_CURRENT(entries);
1056                         old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1057                         ast_var_delete(newvariable);
1058                         break;
1059                 }
1060         }
1061         AST_LIST_TRAVERSE_SAFE_END;
1062
1063         if (value && (newvariable = ast_var_assign(name, value))) {
1064                 if (headp == &globals) {
1065                         ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1066                 }
1067                 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1068                 ast_channel_publish_varset(chan, name, value);
1069         } else if (old_value_existed) {
1070                 /* We just deleted a non-empty dialplan variable. */
1071                 ast_channel_publish_varset(chan, name, "");
1072         }
1073
1074         if (chan)
1075                 ast_channel_unlock(chan);
1076         else
1077                 ast_rwlock_unlock(&globalslock);
1078         return 0;
1079 }
1080
1081 int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
1082 {
1083         char *name, *value, *mydata;
1084
1085         if (ast_strlen_zero(data)) {
1086                 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1087                 return 0;
1088         }
1089
1090         mydata = ast_strdupa(data);
1091         name = strsep(&mydata, "=");
1092         value = mydata;
1093         if (!value) {
1094                 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1095                 return 0;
1096         }
1097
1098         if (strchr(name, ' ')) {
1099                 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1100         }
1101
1102         pbx_builtin_setvar_helper(chan, name, value);
1103
1104         return 0;
1105 }
1106
1107 int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
1108 {
1109         char *data;
1110         int x;
1111         AST_DECLARE_APP_ARGS(args,
1112                 AST_APP_ARG(pair)[24];
1113         );
1114         AST_DECLARE_APP_ARGS(pair,
1115                 AST_APP_ARG(name);
1116                 AST_APP_ARG(value);
1117         );
1118
1119         if (ast_strlen_zero(vdata)) {
1120                 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1121                 return 0;
1122         }
1123
1124         data = ast_strdupa(vdata);
1125         AST_STANDARD_APP_ARGS(args, data);
1126
1127         for (x = 0; x < args.argc; x++) {
1128                 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1129                 if (pair.argc == 2) {
1130                         pbx_builtin_setvar_helper(chan, pair.name, pair.value);
1131                         if (strchr(pair.name, ' '))
1132                                 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
1133                 } else if (!chan) {
1134                         ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1135                 } else {
1136                         ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan));
1137                 }
1138         }
1139
1140         return 0;
1141 }
1142
1143 void pbx_builtin_clear_globals(void)
1144 {
1145         struct ast_var_t *vardata;
1146
1147         ast_rwlock_wrlock(&globalslock);
1148         while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1149                 ast_var_delete(vardata);
1150         ast_rwlock_unlock(&globalslock);
1151 }
1152
1153 static struct ast_cli_entry vars_cli[] = {
1154         AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
1155         AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
1156         AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
1157         AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
1158 };
1159
1160 static void unload_pbx_variables(void)
1161 {
1162         ast_cli_unregister_multiple(vars_cli, ARRAY_LEN(vars_cli));
1163         ast_unregister_application("Set");
1164         ast_unregister_application("MSet");
1165         pbx_builtin_clear_globals();
1166 }
1167
1168 int load_pbx_variables(void)
1169 {
1170         int res = 0;
1171
1172         res |= ast_cli_register_multiple(vars_cli, ARRAY_LEN(vars_cli));
1173         res |= ast_register_application2("Set", pbx_builtin_setvar, NULL, NULL, NULL);
1174         res |= ast_register_application2("MSet", pbx_builtin_setvar_multiple, NULL, NULL, NULL);
1175         ast_register_cleanup(unload_pbx_variables);
1176
1177         return res;
1178 }