Merge "res_rtp_asterisk: Always return provided DTLS packet length."
[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         const char *whereweare;
400         struct ast_str *substr1 = ast_str_create(16);
401         struct ast_str *substr2 = NULL;
402         struct ast_str *substr3 = ast_str_create(16);
403
404         ast_str_reset(*buf);
405
406         if (!substr1 || !substr3) {
407                 if (used) {
408                         *used = ast_str_strlen(*buf);
409                 }
410                 ast_free(substr1);
411                 ast_free(substr3);
412                 return;
413         }
414
415         whereweare = templ;
416         while (!ast_strlen_zero(whereweare)) {
417                 const char *nextvar = NULL;
418                 const char *nextexp = NULL;
419                 const char *nextthing;
420                 const char *vars;
421                 const char *vare;
422                 char *finalvars;
423                 int pos;
424                 int brackets;
425                 int needsub;
426                 int len;
427
428                 /* reset our buffer */
429                 ast_str_reset(substr3);
430
431                 /* Determine how much simply needs to be copied to the output buf. */
432                 nextthing = strchr(whereweare, '$');
433                 if (nextthing) {
434                         pos = nextthing - whereweare;
435                         switch (nextthing[1]) {
436                         case '{':
437                                 /* Variable substitution */
438                                 nextvar = nextthing;
439                                 break;
440                         case '[':
441                                 /* Expression substitution */
442                                 nextexp = nextthing;
443                                 break;
444                         default:
445                                 /* '$' is not part of a substitution so include it too. */
446                                 ++pos;
447                                 break;
448                         }
449                 } else {
450                         /* We're copying the whole remaining string */
451                         pos = strlen(whereweare);
452                 }
453
454                 if (pos) {
455                         /* Copy that many bytes */
456                         ast_str_append_substr(buf, maxlen, whereweare, pos);
457
458                         whereweare += pos;
459                 }
460
461                 if (nextvar) {
462                         int offset;
463                         int offset2;
464                         int isfunction;
465                         int res;
466
467                         /* We have a variable.  Find the start and end, and determine
468                            if we are going to have to recursively call ourselves on the
469                            contents */
470                         vars = vare = nextvar + 2;
471                         brackets = 1;
472                         needsub = 0;
473
474                         /* Find the end of it */
475                         while (brackets && *vare) {
476                                 if ((vare[0] == '$') && (vare[1] == '{')) {
477                                         needsub++;
478                                         brackets++;
479                                         vare++;
480                                 } else if (vare[0] == '{') {
481                                         brackets++;
482                                 } else if (vare[0] == '}') {
483                                         brackets--;
484                                 } else if ((vare[0] == '$') && (vare[1] == '[')) {
485                                         needsub++;
486                                         vare++;
487                                 }
488                                 vare++;
489                         }
490                         len = vare - vars;
491                         if (brackets) {
492                                 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
493                         } else {
494                                 /* Don't count the closing '}' in the length. */
495                                 --len;
496                         }
497
498                         /* Skip totally over variable string */
499                         whereweare = vare;
500
501                         /* Store variable name expression to lookup. */
502                         ast_str_set_substr(&substr1, 0, vars, len);
503                         ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
504
505                         /* Substitute if necessary */
506                         if (needsub) {
507                                 if (!substr2) {
508                                         substr2 = ast_str_create(16);
509                                         if (!substr2) {
510                                                 continue;
511                                         }
512                                 }
513                                 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);
514                                 finalvars = ast_str_buffer(substr2);
515                         } else {
516                                 finalvars = ast_str_buffer(substr1);
517                         }
518
519                         parse_variable_name(finalvars, &offset, &offset2, &isfunction);
520                         if (isfunction) {
521                                 /* Evaluate function */
522                                 if (c || !headp) {
523                                         res = ast_func_read2(c, finalvars, &substr3, 0);
524                                 } else {
525                                         struct varshead old;
526                                         struct ast_channel *bogus;
527
528                                         bogus = ast_dummy_channel_alloc();
529                                         if (bogus) {
530                                                 old = *ast_channel_varshead(bogus);
531                                                 *ast_channel_varshead(bogus) = *headp;
532                                                 res = ast_func_read2(bogus, finalvars, &substr3, 0);
533                                                 /* Don't deallocate the varshead that was passed in */
534                                                 *ast_channel_varshead(bogus) = old;
535                                                 ast_channel_unref(bogus);
536                                         } else {
537                                                 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
538                                                 res = -1;
539                                         }
540                                 }
541                                 ast_debug(2, "Function %s result is '%s'\n",
542                                         finalvars, res ? "" : ast_str_buffer(substr3));
543                         } else {
544                                 /* Retrieve variable value */
545                                 ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
546                                 res = 0;
547                         }
548                         if (!res) {
549                                 ast_str_substring(substr3, offset, offset2);
550                                 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
551                         }
552                 } else if (nextexp) {
553                         /* We have an expression.  Find the start and end, and determine
554                            if we are going to have to recursively call ourselves on the
555                            contents */
556                         vars = vare = nextexp + 2;
557                         brackets = 1;
558                         needsub = 0;
559
560                         /* Find the end of it */
561                         while (brackets && *vare) {
562                                 if ((vare[0] == '$') && (vare[1] == '[')) {
563                                         needsub++;
564                                         brackets++;
565                                         vare++;
566                                 } else if (vare[0] == '[') {
567                                         brackets++;
568                                 } else if (vare[0] == ']') {
569                                         brackets--;
570                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
571                                         needsub++;
572                                         vare++;
573                                 }
574                                 vare++;
575                         }
576                         len = vare - vars;
577                         if (brackets) {
578                                 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
579                         } else {
580                                 /* Don't count the closing ']' in the length. */
581                                 --len;
582                         }
583
584                         /* Skip totally over expression */
585                         whereweare = vare;
586
587                         /* Store expression to evaluate. */
588                         ast_str_set_substr(&substr1, 0, vars, len);
589
590                         /* Substitute if necessary */
591                         if (needsub) {
592                                 if (!substr2) {
593                                         substr2 = ast_str_create(16);
594                                         if (!substr2) {
595                                                 continue;
596                                         }
597                                 }
598                                 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);
599                                 finalvars = ast_str_buffer(substr2);
600                         } else {
601                                 finalvars = ast_str_buffer(substr1);
602                         }
603
604                         if (ast_str_expr(&substr3, 0, c, finalvars)) {
605                                 ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
606                         }
607                         ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
608                 }
609         }
610         if (used) {
611                 *used = ast_str_strlen(*buf);
612         }
613         ast_free(substr1);
614         ast_free(substr2);
615         ast_free(substr3);
616 }
617
618 void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
619 {
620         ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
621 }
622
623 void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
624 {
625         ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, NULL);
626 }
627
628 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
629 {
630         /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
631         const char *whereweare;
632         const char *orig_cp2 = cp2;
633         char ltmp[VAR_BUF_SIZE];
634         char var[VAR_BUF_SIZE];
635
636         *cp2 = 0; /* just in case nothing ends up there */
637         whereweare = cp1;
638         while (!ast_strlen_zero(whereweare) && count) {
639                 char *nextvar = NULL;
640                 char *nextexp = NULL;
641                 char *nextthing;
642                 char *vars;
643                 char *vare;
644                 int length;
645                 int pos;
646                 int brackets;
647                 int needsub;
648                 int len;
649
650                 /* Determine how much simply needs to be copied to the output buf. */
651                 nextthing = strchr(whereweare, '$');
652                 if (nextthing) {
653                         pos = nextthing - whereweare;
654                         switch (nextthing[1]) {
655                         case '{':
656                                 /* Variable substitution */
657                                 nextvar = nextthing;
658                                 break;
659                         case '[':
660                                 /* Expression substitution */
661                                 nextexp = nextthing;
662                                 break;
663                         default:
664                                 /* '$' is not part of a substitution so include it too. */
665                                 ++pos;
666                                 break;
667                         }
668                 } else {
669                         /* We're copying the whole remaining string */
670                         pos = strlen(whereweare);
671                 }
672
673                 if (pos) {
674                         /* Can't copy more than 'count' bytes */
675                         if (pos > count)
676                                 pos = count;
677
678                         /* Copy that many bytes */
679                         memcpy(cp2, whereweare, pos);
680
681                         count -= pos;
682                         cp2 += pos;
683                         whereweare += pos;
684                         *cp2 = 0;
685                 }
686
687                 if (nextvar) {
688                         int offset;
689                         int offset2;
690                         int isfunction;
691                         char *cp4;
692                         char workspace[VAR_BUF_SIZE] = "";
693
694                         /* We have a variable.  Find the start and end, and determine
695                            if we are going to have to recursively call ourselves on the
696                            contents */
697                         vars = vare = nextvar + 2;
698                         brackets = 1;
699                         needsub = 0;
700
701                         /* Find the end of it */
702                         while (brackets && *vare) {
703                                 if ((vare[0] == '$') && (vare[1] == '{')) {
704                                         needsub++;
705                                         brackets++;
706                                         vare++;
707                                 } else if (vare[0] == '{') {
708                                         brackets++;
709                                 } else if (vare[0] == '}') {
710                                         brackets--;
711                                 } else if ((vare[0] == '$') && (vare[1] == '[')) {
712                                         needsub++;
713                                         vare++;
714                                 }
715                                 vare++;
716                         }
717                         len = vare - vars;
718                         if (brackets) {
719                                 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
720                         } else {
721                                 /* Don't count the closing '}' in the length. */
722                                 --len;
723                         }
724
725                         /* Skip totally over variable string */
726                         whereweare = vare;
727
728                         /* Store variable name expression to lookup (and truncate). */
729                         ast_copy_string(var, vars, len + 1);
730
731                         /* Substitute if necessary */
732                         if (needsub) {
733                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, NULL);
734                                 vars = ltmp;
735                         } else {
736                                 vars = var;
737                         }
738
739                         parse_variable_name(vars, &offset, &offset2, &isfunction);
740                         if (isfunction) {
741                                 /* Evaluate function */
742                                 if (c || !headp)
743                                         cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
744                                 else {
745                                         struct varshead old;
746                                         struct ast_channel *bogus;
747
748                                         bogus = ast_dummy_channel_alloc();
749                                         if (bogus) {
750                                                 old = *ast_channel_varshead(bogus);
751                                                 *ast_channel_varshead(bogus) = *headp;
752                                                 cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
753                                                 /* Don't deallocate the varshead that was passed in */
754                                                 *ast_channel_varshead(bogus) = old;
755                                                 ast_channel_unref(bogus);
756                                         } else {
757                                                 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
758                                                 cp4 = NULL;
759                                         }
760                                 }
761                                 ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
762                         } else {
763                                 /* Retrieve variable value */
764                                 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
765                         }
766                         if (cp4) {
767                                 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
768
769                                 length = strlen(cp4);
770                                 if (length > count)
771                                         length = count;
772                                 memcpy(cp2, cp4, length);
773                                 count -= length;
774                                 cp2 += length;
775                                 *cp2 = 0;
776                         }
777                 } else if (nextexp) {
778                         /* We have an expression.  Find the start and end, and determine
779                            if we are going to have to recursively call ourselves on the
780                            contents */
781                         vars = vare = nextexp + 2;
782                         brackets = 1;
783                         needsub = 0;
784
785                         /* Find the end of it */
786                         while (brackets && *vare) {
787                                 if ((vare[0] == '$') && (vare[1] == '[')) {
788                                         needsub++;
789                                         brackets++;
790                                         vare++;
791                                 } else if (vare[0] == '[') {
792                                         brackets++;
793                                 } else if (vare[0] == ']') {
794                                         brackets--;
795                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
796                                         needsub++;
797                                         vare++;
798                                 }
799                                 vare++;
800                         }
801                         len = vare - vars;
802                         if (brackets) {
803                                 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
804                         } else {
805                                 /* Don't count the closing ']' in the length. */
806                                 --len;
807                         }
808
809                         /* Skip totally over expression */
810                         whereweare = vare;
811
812                         /* Store expression to evaluate (and truncate). */
813                         ast_copy_string(var, vars, len + 1);
814
815                         /* Substitute if necessary */
816                         if (needsub) {
817                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, NULL);
818                                 vars = ltmp;
819                         } else {
820                                 vars = var;
821                         }
822
823                         length = ast_expr(vars, cp2, count, c);
824                         if (length) {
825                                 ast_debug(1, "Expression result is '%s'\n", cp2);
826                                 count -= length;
827                                 cp2 += length;
828                                 *cp2 = 0;
829                         }
830                 }
831         }
832         if (used) {
833                 *used = cp2 - orig_cp2;
834         }
835 }
836
837 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
838 {
839         pbx_substitute_variables_helper_full(c, (c) ? ast_channel_varshead(c) : NULL, cp1, cp2, count, NULL);
840 }
841
842 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
843 {
844         pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, NULL);
845 }
846
847 /*! \brief CLI support for listing global variables in a parseable way */
848 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
849 {
850         int i = 0;
851         struct ast_var_t *newvariable;
852
853         switch (cmd) {
854         case CLI_INIT:
855                 e->command = "dialplan show globals";
856                 e->usage =
857                         "Usage: dialplan show globals\n"
858                         "       List current global dialplan variables and their values\n";
859                 return NULL;
860         case CLI_GENERATE:
861                 return NULL;
862         }
863
864         ast_rwlock_rdlock(&globalslock);
865         AST_LIST_TRAVERSE (&globals, newvariable, entries) {
866                 i++;
867                 ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
868         }
869         ast_rwlock_unlock(&globalslock);
870         ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
871
872         return CLI_SUCCESS;
873 }
874
875 /*! \brief CLI support for listing chanvar's variables in a parseable way */
876 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
877 {
878         struct ast_channel *chan;
879         struct ast_var_t *var;
880
881         switch (cmd) {
882         case CLI_INIT:
883                 e->command = "dialplan show chanvar";
884                 e->usage =
885                         "Usage: dialplan show chanvar <channel>\n"
886                         "       List current channel variables and their values\n";
887                 return NULL;
888         case CLI_GENERATE:
889                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
890         }
891
892         if (a->argc != e->args + 1) {
893                 return CLI_SHOWUSAGE;
894         }
895
896         chan = ast_channel_get_by_name(a->argv[e->args]);
897         if (!chan) {
898                 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
899                 return CLI_FAILURE;
900         }
901
902         ast_channel_lock(chan);
903         AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
904                 ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
905         }
906         ast_channel_unlock(chan);
907
908         ast_channel_unref(chan);
909         return CLI_SUCCESS;
910 }
911
912 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
913 {
914         switch (cmd) {
915         case CLI_INIT:
916                 e->command = "dialplan set global";
917                 e->usage =
918                         "Usage: dialplan set global <name> <value>\n"
919                         "       Set global dialplan variable <name> to <value>\n";
920                 return NULL;
921         case CLI_GENERATE:
922                 return NULL;
923         }
924
925         if (a->argc != e->args + 2)
926                 return CLI_SHOWUSAGE;
927
928         pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
929         ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
930
931         return CLI_SUCCESS;
932 }
933
934 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
935 {
936         struct ast_channel *chan;
937         const char *chan_name, *var_name, *var_value;
938
939         switch (cmd) {
940         case CLI_INIT:
941                 e->command = "dialplan set chanvar";
942                 e->usage =
943                         "Usage: dialplan set chanvar <channel> <varname> <value>\n"
944                         "       Set channel variable <varname> to <value>\n";
945                 return NULL;
946         case CLI_GENERATE:
947                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
948         }
949
950         if (a->argc != e->args + 3)
951                 return CLI_SHOWUSAGE;
952
953         chan_name = a->argv[e->args];
954         var_name = a->argv[e->args + 1];
955         var_value = a->argv[e->args + 2];
956
957         if (!(chan = ast_channel_get_by_name(chan_name))) {
958                 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
959                 return CLI_FAILURE;
960         }
961
962         pbx_builtin_setvar_helper(chan, var_name, var_value);
963
964         chan = ast_channel_unref(chan);
965
966         ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
967
968         return CLI_SUCCESS;
969 }
970
971 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
972 {
973         struct ast_var_t *variables;
974         const char *var, *val;
975         int total = 0;
976
977         if (!chan)
978                 return 0;
979
980         ast_str_reset(*buf);
981
982         ast_channel_lock(chan);
983
984         AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
985                 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
986                    /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
987                    ) {
988                         if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
989                                 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
990                                 break;
991                         } else
992                                 total++;
993                 } else
994                         break;
995         }
996
997         ast_channel_unlock(chan);
998
999         return total;
1000 }
1001
1002 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
1003 {
1004         struct ast_var_t *variables;
1005         const char *ret = NULL;
1006         int i;
1007         struct varshead *places[2] = { NULL, &globals };
1008
1009         if (!name)
1010                 return NULL;
1011
1012         if (chan) {
1013                 ast_channel_lock(chan);
1014                 places[0] = ast_channel_varshead(chan);
1015         }
1016
1017         for (i = 0; i < 2; i++) {
1018                 if (!places[i])
1019                         continue;
1020                 if (places[i] == &globals)
1021                         ast_rwlock_rdlock(&globalslock);
1022                 AST_LIST_TRAVERSE(places[i], variables, entries) {
1023                         if (!strcmp(name, ast_var_name(variables))) {
1024                                 ret = ast_var_value(variables);
1025                                 break;
1026                         }
1027                 }
1028                 if (places[i] == &globals)
1029                         ast_rwlock_unlock(&globalslock);
1030                 if (ret)
1031                         break;
1032         }
1033
1034         if (chan)
1035                 ast_channel_unlock(chan);
1036
1037         return ret;
1038 }
1039
1040 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
1041 {
1042         struct ast_var_t *newvariable;
1043         struct varshead *headp;
1044
1045         if (name[strlen(name)-1] == ')') {
1046                 char *function = ast_strdupa(name);
1047
1048                 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1049                 ast_func_write(chan, function, value);
1050                 return;
1051         }
1052
1053         if (chan) {
1054                 ast_channel_lock(chan);
1055                 headp = ast_channel_varshead(chan);
1056         } else {
1057                 ast_rwlock_wrlock(&globalslock);
1058                 headp = &globals;
1059         }
1060
1061         if (value && (newvariable = ast_var_assign(name, value))) {
1062                 if (headp == &globals)
1063                         ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1064                 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1065         }
1066
1067         if (chan)
1068                 ast_channel_unlock(chan);
1069         else
1070                 ast_rwlock_unlock(&globalslock);
1071 }
1072
1073 int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
1074 {
1075         struct ast_var_t *newvariable;
1076         struct varshead *headp;
1077         const char *nametail = name;
1078         /*! True if the old value was not an empty string. */
1079         int old_value_existed = 0;
1080
1081         if (name[strlen(name) - 1] == ')') {
1082                 char *function = ast_strdupa(name);
1083
1084                 return ast_func_write(chan, function, value);
1085         }
1086
1087         if (chan) {
1088                 ast_channel_lock(chan);
1089                 headp = ast_channel_varshead(chan);
1090         } else {
1091                 ast_rwlock_wrlock(&globalslock);
1092                 headp = &globals;
1093         }
1094
1095         /* For comparison purposes, we have to strip leading underscores */
1096         if (*nametail == '_') {
1097                 nametail++;
1098                 if (*nametail == '_')
1099                         nametail++;
1100         }
1101
1102         AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1103                 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1104                         /* there is already such a variable, delete it */
1105                         AST_LIST_REMOVE_CURRENT(entries);
1106                         old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1107                         ast_var_delete(newvariable);
1108                         break;
1109                 }
1110         }
1111         AST_LIST_TRAVERSE_SAFE_END;
1112
1113         if (value && (newvariable = ast_var_assign(name, value))) {
1114                 if (headp == &globals) {
1115                         ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1116                 }
1117                 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1118                 ast_channel_publish_varset(chan, name, value);
1119         } else if (old_value_existed) {
1120                 /* We just deleted a non-empty dialplan variable. */
1121                 ast_channel_publish_varset(chan, name, "");
1122         }
1123
1124         if (chan)
1125                 ast_channel_unlock(chan);
1126         else
1127                 ast_rwlock_unlock(&globalslock);
1128         return 0;
1129 }
1130
1131 int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
1132 {
1133         char *name, *value, *mydata;
1134
1135         if (ast_strlen_zero(data)) {
1136                 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1137                 return 0;
1138         }
1139
1140         mydata = ast_strdupa(data);
1141         name = strsep(&mydata, "=");
1142         value = mydata;
1143         if (!value) {
1144                 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1145                 return 0;
1146         }
1147
1148         if (strchr(name, ' ')) {
1149                 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1150         }
1151
1152         pbx_builtin_setvar_helper(chan, name, value);
1153
1154         return 0;
1155 }
1156
1157 int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
1158 {
1159         char *data;
1160         int x;
1161         AST_DECLARE_APP_ARGS(args,
1162                 AST_APP_ARG(pair)[24];
1163         );
1164         AST_DECLARE_APP_ARGS(pair,
1165                 AST_APP_ARG(name);
1166                 AST_APP_ARG(value);
1167         );
1168
1169         if (ast_strlen_zero(vdata)) {
1170                 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1171                 return 0;
1172         }
1173
1174         data = ast_strdupa(vdata);
1175         AST_STANDARD_APP_ARGS(args, data);
1176
1177         for (x = 0; x < args.argc; x++) {
1178                 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1179                 if (pair.argc == 2) {
1180                         pbx_builtin_setvar_helper(chan, pair.name, pair.value);
1181                         if (strchr(pair.name, ' '))
1182                                 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);
1183                 } else if (!chan) {
1184                         ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1185                 } else {
1186                         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));
1187                 }
1188         }
1189
1190         return 0;
1191 }
1192
1193 void pbx_builtin_clear_globals(void)
1194 {
1195         struct ast_var_t *vardata;
1196
1197         ast_rwlock_wrlock(&globalslock);
1198         while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1199                 ast_var_delete(vardata);
1200         ast_rwlock_unlock(&globalslock);
1201 }
1202
1203 static struct ast_cli_entry vars_cli[] = {
1204         AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
1205         AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
1206         AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
1207         AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
1208 };
1209
1210 static void unload_pbx_variables(void)
1211 {
1212         ast_cli_unregister_multiple(vars_cli, ARRAY_LEN(vars_cli));
1213         ast_unregister_application("Set");
1214         ast_unregister_application("MSet");
1215         pbx_builtin_clear_globals();
1216 }
1217
1218 int load_pbx_variables(void)
1219 {
1220         int res = 0;
1221
1222         res |= ast_cli_register_multiple(vars_cli, ARRAY_LEN(vars_cli));
1223         res |= ast_register_application2("Set", pbx_builtin_setvar, NULL, NULL, NULL);
1224         res |= ast_register_application2("MSet", pbx_builtin_setvar_multiple, NULL, NULL, NULL);
1225         ast_register_cleanup(unload_pbx_variables);
1226
1227         return res;
1228 }