Merge "res_calendar: Specialized calendars depend on symbols of general calendar."
[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 *workspace = NULL;
634         char *ltmp = NULL;
635         char *var = NULL;
636
637         *cp2 = 0; /* just in case nothing ends up there */
638         whereweare = cp1;
639         while (!ast_strlen_zero(whereweare) && count) {
640                 char *nextvar = NULL;
641                 char *nextexp = NULL;
642                 char *nextthing;
643                 char *vars;
644                 char *vare;
645                 int length;
646                 int pos;
647                 int brackets;
648                 int needsub;
649                 int len;
650
651                 /* Determine how much simply needs to be copied to the output buf. */
652                 nextthing = strchr(whereweare, '$');
653                 if (nextthing) {
654                         pos = nextthing - whereweare;
655                         switch (nextthing[1]) {
656                         case '{':
657                                 /* Variable substitution */
658                                 nextvar = nextthing;
659                                 break;
660                         case '[':
661                                 /* Expression substitution */
662                                 nextexp = nextthing;
663                                 break;
664                         default:
665                                 /* '$' is not part of a substitution so include it too. */
666                                 ++pos;
667                                 break;
668                         }
669                 } else {
670                         /* We're copying the whole remaining string */
671                         pos = strlen(whereweare);
672                 }
673
674                 if (pos) {
675                         /* Can't copy more than 'count' bytes */
676                         if (pos > count)
677                                 pos = count;
678
679                         /* Copy that many bytes */
680                         memcpy(cp2, whereweare, pos);
681
682                         count -= pos;
683                         cp2 += pos;
684                         whereweare += pos;
685                         *cp2 = 0;
686                 }
687
688                 if (nextvar) {
689                         int offset;
690                         int offset2;
691                         int isfunction;
692                         char *cp4;
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                         if (!var)
729                                 var = ast_alloca(VAR_BUF_SIZE);
730
731                         /* Store variable name expression to lookup (and truncate). */
732                         ast_copy_string(var, vars, len + 1);
733
734                         /* Substitute if necessary */
735                         if (needsub) {
736                                 if (!ltmp) {
737                                         ltmp = ast_alloca(VAR_BUF_SIZE);
738                                 }
739                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, NULL);
740                                 vars = ltmp;
741                         } else {
742                                 vars = var;
743                         }
744
745                         if (!workspace)
746                                 workspace = ast_alloca(VAR_BUF_SIZE);
747
748                         workspace[0] = '\0';
749
750                         parse_variable_name(vars, &offset, &offset2, &isfunction);
751                         if (isfunction) {
752                                 /* Evaluate function */
753                                 if (c || !headp)
754                                         cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
755                                 else {
756                                         struct varshead old;
757                                         struct ast_channel *bogus;
758
759                                         bogus = ast_dummy_channel_alloc();
760                                         if (bogus) {
761                                                 old = *ast_channel_varshead(bogus);
762                                                 *ast_channel_varshead(bogus) = *headp;
763                                                 cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
764                                                 /* Don't deallocate the varshead that was passed in */
765                                                 *ast_channel_varshead(bogus) = old;
766                                                 ast_channel_unref(bogus);
767                                         } else {
768                                                 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
769                                                 cp4 = NULL;
770                                         }
771                                 }
772                                 ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
773                         } else {
774                                 /* Retrieve variable value */
775                                 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
776                         }
777                         if (cp4) {
778                                 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
779
780                                 length = strlen(cp4);
781                                 if (length > count)
782                                         length = count;
783                                 memcpy(cp2, cp4, length);
784                                 count -= length;
785                                 cp2 += length;
786                                 *cp2 = 0;
787                         }
788                 } else if (nextexp) {
789                         /* We have an expression.  Find the start and end, and determine
790                            if we are going to have to recursively call ourselves on the
791                            contents */
792                         vars = vare = nextexp + 2;
793                         brackets = 1;
794                         needsub = 0;
795
796                         /* Find the end of it */
797                         while (brackets && *vare) {
798                                 if ((vare[0] == '$') && (vare[1] == '[')) {
799                                         needsub++;
800                                         brackets++;
801                                         vare++;
802                                 } else if (vare[0] == '[') {
803                                         brackets++;
804                                 } else if (vare[0] == ']') {
805                                         brackets--;
806                                 } else if ((vare[0] == '$') && (vare[1] == '{')) {
807                                         needsub++;
808                                         vare++;
809                                 }
810                                 vare++;
811                         }
812                         len = vare - vars;
813                         if (brackets) {
814                                 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
815                         } else {
816                                 /* Don't count the closing ']' in the length. */
817                                 --len;
818                         }
819
820                         /* Skip totally over expression */
821                         whereweare = vare;
822
823                         if (!var)
824                                 var = ast_alloca(VAR_BUF_SIZE);
825
826                         /* Store expression to evaluate (and truncate). */
827                         ast_copy_string(var, vars, len + 1);
828
829                         /* Substitute if necessary */
830                         if (needsub) {
831                                 if (!ltmp) {
832                                         ltmp = ast_alloca(VAR_BUF_SIZE);
833                                 }
834                                 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, NULL);
835                                 vars = ltmp;
836                         } else {
837                                 vars = var;
838                         }
839
840                         length = ast_expr(vars, cp2, count, c);
841                         if (length) {
842                                 ast_debug(1, "Expression result is '%s'\n", cp2);
843                                 count -= length;
844                                 cp2 += length;
845                                 *cp2 = 0;
846                         }
847                 }
848         }
849         if (used) {
850                 *used = cp2 - orig_cp2;
851         }
852 }
853
854 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
855 {
856         pbx_substitute_variables_helper_full(c, (c) ? ast_channel_varshead(c) : NULL, cp1, cp2, count, NULL);
857 }
858
859 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
860 {
861         pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, NULL);
862 }
863
864 /*! \brief CLI support for listing global variables in a parseable way */
865 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
866 {
867         int i = 0;
868         struct ast_var_t *newvariable;
869
870         switch (cmd) {
871         case CLI_INIT:
872                 e->command = "dialplan show globals";
873                 e->usage =
874                         "Usage: dialplan show globals\n"
875                         "       List current global dialplan variables and their values\n";
876                 return NULL;
877         case CLI_GENERATE:
878                 return NULL;
879         }
880
881         ast_rwlock_rdlock(&globalslock);
882         AST_LIST_TRAVERSE (&globals, newvariable, entries) {
883                 i++;
884                 ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
885         }
886         ast_rwlock_unlock(&globalslock);
887         ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
888
889         return CLI_SUCCESS;
890 }
891
892 /*! \brief CLI support for listing chanvar's variables in a parseable way */
893 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
894 {
895         struct ast_channel *chan;
896         struct ast_var_t *var;
897
898         switch (cmd) {
899         case CLI_INIT:
900                 e->command = "dialplan show chanvar";
901                 e->usage =
902                         "Usage: dialplan show chanvar <channel>\n"
903                         "       List current channel variables and their values\n";
904                 return NULL;
905         case CLI_GENERATE:
906                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
907         }
908
909         if (a->argc != e->args + 1) {
910                 return CLI_SHOWUSAGE;
911         }
912
913         chan = ast_channel_get_by_name(a->argv[e->args]);
914         if (!chan) {
915                 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
916                 return CLI_FAILURE;
917         }
918
919         ast_channel_lock(chan);
920         AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
921                 ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
922         }
923         ast_channel_unlock(chan);
924
925         ast_channel_unref(chan);
926         return CLI_SUCCESS;
927 }
928
929 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
930 {
931         switch (cmd) {
932         case CLI_INIT:
933                 e->command = "dialplan set global";
934                 e->usage =
935                         "Usage: dialplan set global <name> <value>\n"
936                         "       Set global dialplan variable <name> to <value>\n";
937                 return NULL;
938         case CLI_GENERATE:
939                 return NULL;
940         }
941
942         if (a->argc != e->args + 2)
943                 return CLI_SHOWUSAGE;
944
945         pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
946         ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
947
948         return CLI_SUCCESS;
949 }
950
951 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
952 {
953         struct ast_channel *chan;
954         const char *chan_name, *var_name, *var_value;
955
956         switch (cmd) {
957         case CLI_INIT:
958                 e->command = "dialplan set chanvar";
959                 e->usage =
960                         "Usage: dialplan set chanvar <channel> <varname> <value>\n"
961                         "       Set channel variable <varname> to <value>\n";
962                 return NULL;
963         case CLI_GENERATE:
964                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
965         }
966
967         if (a->argc != e->args + 3)
968                 return CLI_SHOWUSAGE;
969
970         chan_name = a->argv[e->args];
971         var_name = a->argv[e->args + 1];
972         var_value = a->argv[e->args + 2];
973
974         if (!(chan = ast_channel_get_by_name(chan_name))) {
975                 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
976                 return CLI_FAILURE;
977         }
978
979         pbx_builtin_setvar_helper(chan, var_name, var_value);
980
981         chan = ast_channel_unref(chan);
982
983         ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
984
985         return CLI_SUCCESS;
986 }
987
988 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
989 {
990         struct ast_var_t *variables;
991         const char *var, *val;
992         int total = 0;
993
994         if (!chan)
995                 return 0;
996
997         ast_str_reset(*buf);
998
999         ast_channel_lock(chan);
1000
1001         AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
1002                 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
1003                    /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
1004                    ) {
1005                         if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
1006                                 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
1007                                 break;
1008                         } else
1009                                 total++;
1010                 } else
1011                         break;
1012         }
1013
1014         ast_channel_unlock(chan);
1015
1016         return total;
1017 }
1018
1019 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
1020 {
1021         struct ast_var_t *variables;
1022         const char *ret = NULL;
1023         int i;
1024         struct varshead *places[2] = { NULL, &globals };
1025
1026         if (!name)
1027                 return NULL;
1028
1029         if (chan) {
1030                 ast_channel_lock(chan);
1031                 places[0] = ast_channel_varshead(chan);
1032         }
1033
1034         for (i = 0; i < 2; i++) {
1035                 if (!places[i])
1036                         continue;
1037                 if (places[i] == &globals)
1038                         ast_rwlock_rdlock(&globalslock);
1039                 AST_LIST_TRAVERSE(places[i], variables, entries) {
1040                         if (!strcmp(name, ast_var_name(variables))) {
1041                                 ret = ast_var_value(variables);
1042                                 break;
1043                         }
1044                 }
1045                 if (places[i] == &globals)
1046                         ast_rwlock_unlock(&globalslock);
1047                 if (ret)
1048                         break;
1049         }
1050
1051         if (chan)
1052                 ast_channel_unlock(chan);
1053
1054         return ret;
1055 }
1056
1057 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
1058 {
1059         struct ast_var_t *newvariable;
1060         struct varshead *headp;
1061
1062         if (name[strlen(name)-1] == ')') {
1063                 char *function = ast_strdupa(name);
1064
1065                 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1066                 ast_func_write(chan, function, value);
1067                 return;
1068         }
1069
1070         if (chan) {
1071                 ast_channel_lock(chan);
1072                 headp = ast_channel_varshead(chan);
1073         } else {
1074                 ast_rwlock_wrlock(&globalslock);
1075                 headp = &globals;
1076         }
1077
1078         if (value && (newvariable = ast_var_assign(name, value))) {
1079                 if (headp == &globals)
1080                         ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1081                 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1082         }
1083
1084         if (chan)
1085                 ast_channel_unlock(chan);
1086         else
1087                 ast_rwlock_unlock(&globalslock);
1088 }
1089
1090 int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
1091 {
1092         struct ast_var_t *newvariable;
1093         struct varshead *headp;
1094         const char *nametail = name;
1095         /*! True if the old value was not an empty string. */
1096         int old_value_existed = 0;
1097
1098         if (name[strlen(name) - 1] == ')') {
1099                 char *function = ast_strdupa(name);
1100
1101                 return ast_func_write(chan, function, value);
1102         }
1103
1104         if (chan) {
1105                 ast_channel_lock(chan);
1106                 headp = ast_channel_varshead(chan);
1107         } else {
1108                 ast_rwlock_wrlock(&globalslock);
1109                 headp = &globals;
1110         }
1111
1112         /* For comparison purposes, we have to strip leading underscores */
1113         if (*nametail == '_') {
1114                 nametail++;
1115                 if (*nametail == '_')
1116                         nametail++;
1117         }
1118
1119         AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1120                 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1121                         /* there is already such a variable, delete it */
1122                         AST_LIST_REMOVE_CURRENT(entries);
1123                         old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1124                         ast_var_delete(newvariable);
1125                         break;
1126                 }
1127         }
1128         AST_LIST_TRAVERSE_SAFE_END;
1129
1130         if (value && (newvariable = ast_var_assign(name, value))) {
1131                 if (headp == &globals) {
1132                         ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1133                 }
1134                 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1135                 ast_channel_publish_varset(chan, name, value);
1136         } else if (old_value_existed) {
1137                 /* We just deleted a non-empty dialplan variable. */
1138                 ast_channel_publish_varset(chan, name, "");
1139         }
1140
1141         if (chan)
1142                 ast_channel_unlock(chan);
1143         else
1144                 ast_rwlock_unlock(&globalslock);
1145         return 0;
1146 }
1147
1148 int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
1149 {
1150         char *name, *value, *mydata;
1151
1152         if (ast_strlen_zero(data)) {
1153                 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1154                 return 0;
1155         }
1156
1157         mydata = ast_strdupa(data);
1158         name = strsep(&mydata, "=");
1159         value = mydata;
1160         if (!value) {
1161                 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1162                 return 0;
1163         }
1164
1165         if (strchr(name, ' ')) {
1166                 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1167         }
1168
1169         pbx_builtin_setvar_helper(chan, name, value);
1170
1171         return 0;
1172 }
1173
1174 int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
1175 {
1176         char *data;
1177         int x;
1178         AST_DECLARE_APP_ARGS(args,
1179                 AST_APP_ARG(pair)[24];
1180         );
1181         AST_DECLARE_APP_ARGS(pair,
1182                 AST_APP_ARG(name);
1183                 AST_APP_ARG(value);
1184         );
1185
1186         if (ast_strlen_zero(vdata)) {
1187                 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1188                 return 0;
1189         }
1190
1191         data = ast_strdupa(vdata);
1192         AST_STANDARD_APP_ARGS(args, data);
1193
1194         for (x = 0; x < args.argc; x++) {
1195                 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1196                 if (pair.argc == 2) {
1197                         pbx_builtin_setvar_helper(chan, pair.name, pair.value);
1198                         if (strchr(pair.name, ' '))
1199                                 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);
1200                 } else if (!chan) {
1201                         ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1202                 } else {
1203                         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));
1204                 }
1205         }
1206
1207         return 0;
1208 }
1209
1210 void pbx_builtin_clear_globals(void)
1211 {
1212         struct ast_var_t *vardata;
1213
1214         ast_rwlock_wrlock(&globalslock);
1215         while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1216                 ast_var_delete(vardata);
1217         ast_rwlock_unlock(&globalslock);
1218 }
1219
1220 static struct ast_cli_entry vars_cli[] = {
1221         AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
1222         AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
1223         AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
1224         AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
1225 };
1226
1227 static void unload_pbx_variables(void)
1228 {
1229         ast_cli_unregister_multiple(vars_cli, ARRAY_LEN(vars_cli));
1230         ast_unregister_application("Set");
1231         ast_unregister_application("MSet");
1232         pbx_builtin_clear_globals();
1233 }
1234
1235 int load_pbx_variables(void)
1236 {
1237         int res = 0;
1238
1239         res |= ast_cli_register_multiple(vars_cli, ARRAY_LEN(vars_cli));
1240         res |= ast_register_application2("Set", pbx_builtin_setvar, NULL, NULL, NULL);
1241         res |= ast_register_application2("MSet", pbx_builtin_setvar_multiple, NULL, NULL, NULL);
1242         ast_register_cleanup(unload_pbx_variables);
1243
1244         return res;
1245 }