Summary:ASTERISK-20163: Variables evaluated in dialplan are case insensitive, whereas channel variables/system variables are not
Reporter:Matt Jordan (mjordan)Labels:
Date Opened:2012-07-23 14:38:42Date Closed:2012-11-02 07:32:46
Versions:Frequency of
Description:We were all a little taken aback by this one.

Variables are documented on wiki.asterisk.org as being case sensitive.  Some ancient documentation on voip-info makes the following note:

"A variable name may be any alphanumeric string beginning with a letter. User-defined variable names are not case sensitive — ${FOO} and ${Foo} refer to the same variable — but Asterisk-defined variables are case-sensitive — ${EXTEN} works, but ${exten} doesn't."

That seems... odd?  And yet, it is somewhat accidentally correct, per the current implementation.  Consider a user defined variable "FOO".  Evaluating ${Foo} will yield the same value as evaluating ${FOO}.  So will ${FoO}.  This works for both channel variables, as well as global variables.

On the other hand, if that variable is something known to an application or is evaluated outside of dialplan execution, then that variable is treated as case sensitive.  So if a user sets variable ${MiXMONITOR_FILENAME}, the MixMonitor application will not receive the intended value, as it evaluates (case sensitive) variable ${MIXMONITOR_FILENAME}.  If a user later checks variable ${MIXMONITOR_FILENAME} in the dialplan, it will evaluate to the same variable name as ${MiXMONITOR_FILENAME}.

From the perspective of the user, the fact that variables are evaluated both sensitive to case and insensitive to case has got to be unexpected.  The proposal is to make it consistent - which probably means matching the documentation on wiki.asterisk.org and making it case sensitive.  If done in 1.8, this needs to be noted in the UPGRADE file.

At the minimum, the would entail making the code in ast_str_retrieve_variable should be made to be case sensitive:

/* if not found, look into chanvars or global vars */
for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
struct ast_var_t *variables;
if (!places[i])
if (places[i] == &globals)
AST_LIST_TRAVERSE(places[i], variables, entries) {
if (!strcasecmp(ast_var_name(variables), var)) {
s = ast_var_value(variables);
if (places[i] == &globals)

There are potentially other areas where variables are evaluated however, and all of those should be checked.