config: Allow ConfBridge DTMF menus to have '#' as the first digit.
authorRichard Mudgett <rmudgett@digium.com>
Sat, 2 Nov 2013 01:15:11 +0000 (01:15 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Sat, 2 Nov 2013 01:15:11 +0000 (01:15 +0000)
ConfBridge allows custom DTMF menus to be created in the confbridge.conf
file by assigning a DTMF key sequence to a sequence of actions as follows:

DTMF-sequence = action,action...

Unfortunately, the normal config file processing code interprets an
initial '#' character as starting a directive such as #include.

* Add the ability to escape the first non-blank character in a config line
so the '#' character can be used without triggering the directive
processing code.

(closes issue AFS-2)
(closes issue ASTERISK-22478)
Reported by: Nicolas Tanski
Patches:
      jira_asterisk_22478_v11.patch (license #5621) patch uploaded by rmudgett (modified)

Review: https://reviewboard.asterisk.org/r/2969/
........

Merged revisions 402407 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 402416 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402417 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/confbridge/conf_config_parser.c
configs/confbridge.conf.sample
main/config.c

index 5c430ea..e7a1873 100644 (file)
@@ -430,6 +430,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        is passed in to ConfBridge as an argument in the dialplan.</para>
                                        <para>Below is a list of menu actions that can be assigned to a DTMF sequence.</para>
                                        <note><para>
+                                               To have the first DTMF digit in a sequence be the '#' character, you need to
+                                               escape it.  If it is not escaped then normal config file processing will
+                                               think it is a directive like #include.  For example: The mute setting is
+                                               toggled when <literal>#1</literal> is pressed.</para>
+                                               <para><literal>\#1=toggle_mute</literal></para>
+                                       </note>
+                                       <note><para>
                                        A single DTMF sequence can have multiple actions associated with it. This is
                                        accomplished by stringing the actions together and using a <literal>,</literal> as the
                                        delimiter.  Example:  Both listening and talking volume is reset when <literal>5</literal> is
@@ -453,7 +460,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                                <enum name="toggle_mute"><para>
                                                        Toggle turning on and off mute.  Mute will make the user silent
                                                        to everyone else, but the user will still be able to listen in.
-                                                       continue to collect the dtmf sequence.</para></enum>
+                                                       </para></enum>
                                                <enum name="no_op"><para>
                                                        This action does nothing (No Operation). Its only real purpose exists for
                                                        being able to reserve a sequence in the config as a menu exit sequence.</para></enum>
index a4f829a..94739a6 100644 (file)
@@ -62,7 +62,7 @@ type=user
                             ;    loose the user will hear themselves briefly each
                             ;    time they begin talking until the dsp has time to
                             ;    establish that they are in fact talking.
-                            ; 2. When talk detection AMI events are enabled, this value 
+                            ; 2. When talk detection AMI events are enabled, this value
                             ;    determines when talking has begun which results in
                             ;    an AMI event to fire.  If this value is set too tight
                             ;    AMI events may be falsely triggered by variants in
@@ -248,6 +248,11 @@ type=bridge
 ; Below is a list of menu actions that can be assigned
 ; to a DTMF sequence.
 ;
+; To have the first DTMF digit in a sequence be the '#' character, you need to
+; escape it.  If it is not escaped then normal config file processing will
+; think it is a directive like #include.  For example:
+; \#1=toggle_mute                      ; Pressing #1 will toggle the mute setting.
+;
 ; A single DTMF sequence can have multiple actions associated with it. This is
 ; accomplished by stringing the actions together and using a ',' as the delimiter.
 ; Example:  Both listening and talking volume is reset when '5' is pressed.
@@ -270,7 +275,7 @@ type=bridge
                                        ; using the '&' character as a delimiter.
 ; toggle_mute      ; Toggle turning on and off mute.  Mute will make the user silent
                    ; to everyone else, but the user will still be able to listen in.
-                   ; continue to collect the dtmf sequence.
+
 ; no_op ; This action does nothing (No Operation). Its only real purpose exists for
         ; being able to reserve a sequence in the config as a menu exit sequence.
 ; decrease_listening_volume ; Decreases the channel's listening volume.
index 1126231..b8356a9 100644 (file)
@@ -1419,14 +1419,26 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
        } else {
                /* Just a line (variable = value) */
                int object = 0;
+               int is_escaped;
+
                if (!(*cat)) {
                        ast_log(LOG_WARNING,
                                "parse error: No category context for line %d of %s\n", lineno, configfile);
                        return -1;
                }
-               c = strchr(cur, '=');
 
-               if (c && c > cur && (*(c - 1) == '+')) {
+               is_escaped = cur[0] == '\\';
+               if (is_escaped) {
+                       /* First character is escaped. */
+                       ++cur;
+                       if (cur[0] < 33) {
+                               ast_log(LOG_ERROR, "Invalid escape in line %d of %s\n", lineno, configfile);
+                               return -1;
+                       }
+               }
+               c = strchr(cur + is_escaped, '=');
+
+               if (c && c > cur + is_escaped && (*(c - 1) == '+')) {
                        struct ast_variable *var, *replace = NULL;
                        struct ast_str **str = ast_threadstorage_get(&appendbuf, sizeof(*str));
 
@@ -1462,8 +1474,11 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                object = 1;
                                c++;
                        }
+                       cur = ast_strip(cur);
 set_new_variable:
-                       if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {
+                       if (ast_strlen_zero(cur)) {
+                               ast_log(LOG_WARNING, "No variable name in line %d of %s\n", lineno, configfile);
+                       } else if ((v = ast_variable_new(cur, ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {
                                v->lineno = lineno;
                                v->object = object;
                                *last_cat = 0;