]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
app.c: Allow ampersands in playback lists to be escaped.
authorSean Bright <sean@seanbright.com>
Tue, 7 Nov 2023 20:03:53 +0000 (15:03 -0500)
committerSean Bright <sean@seanbright.com>
Tue, 28 Nov 2023 19:52:00 +0000 (19:52 +0000)
Any function or application that accepts a `&`-separated list of
filenames can now include a literal `&` in a filename by wrapping the
entire filename in single quotes, e.g.:

```
exten = _X.,n,Playback('https://example.com/sound.cgi?a=b&c=d'&hello-world)
```

Fixes #172

UpgradeNote: Ampersands in URLs passed to the `Playback()`,
`Background()`, `SpeechBackground()`, `Read()`, `Authenticate()`, or
`Queue()` applications as filename arguments can now be escaped by
single quoting the filename. Additionally, this is also possible when
using the `CONFBRIDGE` dialplan function, or configuring various
features in `confbridge.conf` and `queues.conf`.

apps/app_authenticate.c
apps/app_confbridge.c
apps/app_playback.c
apps/app_queue.c
apps/app_read.c
apps/app_skel.c
apps/app_speech_utils.c
main/app.c
main/pbx_builtins.c

index 3ec04b72f9b11e03e191935d88d8929dc2deabfd..ef63b9e50c5cda03d87e5ab344d33b6292f0a371 100644 (file)
@@ -95,8 +95,17 @@ static const char app[] = "Authenticate";
                                maxdigits have been entered (without requiring the user to press the <literal>#</literal> key).
                                Defaults to 0 - no limit - wait for the user press the <literal>#</literal> key.</para>
                        </parameter>
-                       <parameter name="prompt" required="false">
-                               <para>Override the agent-pass prompt file.</para>
+                       <parameter name="prompt" required="false" argsep="&amp;">
+                               <para>Override the &quot;agent-pass&quot; sound file. Can be
+                               an ampersand separated list of filenames. If the filename
+                               is a relative filename (it does not begin with a slash), it
+                               will be searched for in the Asterisk sounds directory. If the
+                               filename is able to be parsed as a URL, Asterisk will
+                               download the file and then begin playback on it. To include a
+                               literal <literal>&amp;</literal> in the URL you can enclose
+                               the URL in single quotes.</para>
+                               <argument name="prompt" required="true" />
+                               <argument name="prompt2" multiple="true" />
                        </parameter>
                </syntax>
                <description>
index dd683d35c62cbbe56f2a453660a57617e94e6677..046cd42b290eeb96216b85243db53583be56bbeb 100644 (file)
@@ -3035,7 +3035,7 @@ static int action_playback(struct ast_bridge_channel *bridge_channel, const char
        char *file_copy = ast_strdupa(playback_file);
        char *file = NULL;
 
-       while ((file = strsep(&file_copy, "&"))) {
+       while ((file = ast_strsep(&file_copy, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
                if (ast_stream_and_wait(bridge_channel->chan, file, "")) {
                        ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
                        return -1;
@@ -3059,7 +3059,7 @@ static int action_playback_and_continue(struct confbridge_conference *conference
        char *file_copy = ast_strdupa(playback_file);
        char *file = NULL;
 
-       while ((file = strsep(&file_copy, "&"))) {
+       while ((file = ast_strsep(&file_copy, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
                if (ast_streamfile(bridge_channel->chan, file, ast_channel_language(bridge_channel->chan))) {
                        ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
                        return -1;
index afa959be00582553b94d868f86b29ae6c4f1347a..8b83f53a04c8e81f579fcd736cf5e197e3fa6186 100644 (file)
                </synopsis>
                <syntax>
                        <parameter name="filenames" required="true" argsep="&amp;">
+                               <para>Ampersand separated list of filenames. If the filename
+                               is a relative filename (it does not begin with a slash), it
+                               will be searched for in the Asterisk sounds directory. If the
+                               filename is able to be parsed as a URL, Asterisk will
+                               download the file and then begin playback on it. To include a
+                               literal <literal>&amp;</literal> in the URL you can enclose
+                               the URL in single quotes.</para>
                                <argument name="filename" required="true" />
                                <argument name="filename2" multiple="true" />
                        </parameter>
@@ -492,7 +499,7 @@ static int playback_exec(struct ast_channel *chan, const char *data)
                char *front;
 
                ast_stopstream(chan);
-               while (!res && (front = strsep(&back, "&"))) {
+               while (!res && (front = ast_strsep(&back, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
                        if (option_say)
                                res = say_full(chan, front, "", ast_channel_language(chan), NULL, -1, -1);
                        else if (option_mix){
index b42a06681dd6b8237b710ad11e63df23c9de242e..0f9289db372c5ec6f7a9baf3300b3ab29643efd4 100644 (file)
                                <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
                        </parameter>
                        <parameter name="announceoverride" argsep="&amp;">
-                               <argument name="filename" required="true">
-                                       <para>Announcement file(s) to play to agent before bridging call, overriding the announcement(s)
-                                       configured in <filename>queues.conf</filename>, if any.</para>
-                               </argument>
-                               <argument name="filename2" multiple="true" />
+                               <para>Announcement file(s) to play to agent before bridging
+                               call, overriding the announcement(s) configured in
+                               <filename>queues.conf</filename>, if any.</para>
+                               <para>Ampersand separated list of filenames. If the filename
+                               is a relative filename (it does not begin with a slash), it
+                               will be searched for in the Asterisk sounds directory. If the
+                               filename is able to be parsed as a URL, Asterisk will
+                               download the file and then begin playback on it. To include a
+                               literal <literal>&amp;</literal> in the URL you can enclose
+                               the URL in single quotes.</para>
+                               <argument name="announceoverride" required="true" />
+                               <argument name="announceoverride2" multiple="true" />
                        </parameter>
                        <parameter name="timeout">
                                <para>Will cause the queue to fail out after a specified number of
@@ -7195,7 +7202,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
                                if (!res2 && announce) {
                                        char *front;
                                        char *announcefiles = ast_strdupa(announce);
-                                       while ((front = strsep(&announcefiles, "&"))) {
+                                       while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
                                                if (play_file(peer, front) < 0) {
                                                        ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
                                                }
index e2ac60cc96a1ef33511309b688df275a609ae980..9a64941d5260cb2a960c65a45fcfb6fc220a61ba 100644 (file)
                                name.</para>
                        </parameter>
                        <parameter name="filenames" argsep="&amp;">
-                               <argument name="filename" required="true">
-                                       <para>file(s) to play before reading digits or tone with option i</para>
-                               </argument>
+                               <para>Ampersand separated list of filenames to play before
+                               reading digits or tone with option <literal>i</literal>. If
+                               the filename is a relative filename (it does not begin with a
+                               slash), it will be searched for in the Asterisk sounds
+                               directory. If the filename is able to be parsed as a URL,
+                               Asterisk will download the file and then begin playback on
+                               it. To include a literal <literal>&amp;</literal> in the URL
+                               you can enclose the URL in single quotes.</para>
+                               <argument name="filename" required="true" />
                                <argument name="filename2" multiple="true" />
                        </parameter>
                        <parameter name="maxdigits">
index e0b8bca7bc52d92db5256ae7b3bbd8be64b9f845..b59ebe56bd833404c69603d28ca7463bbfa8c1ed 100644 (file)
@@ -371,7 +371,8 @@ static void play_files_helper(struct ast_channel *chan, const char *prompts)
        char *prompt, *rest = ast_strdupa(prompts);
 
        ast_stopstream(chan);
-       while ((prompt = strsep(&rest, "&")) && !ast_stream_and_wait(chan, prompt, "")) {
+       while ((prompt = ast_strsep(&rest, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))
+               && !ast_stream_and_wait(chan, prompt, "")) {
                ast_stopstream(chan);
        }
 }
index 9af8d2aee2455dbceb822ac64fa9ad79dbb7db4d..fa4a75a1488159e2dc99b5199b10f7727a845f25 100644 (file)
                        Play a sound file and wait for speech to be recognized.
                </synopsis>
                <syntax>
-                       <parameter name="sound_file" required="true" />
+                       <parameter name="sound_file" required="true" argsep="&amp;">
+                               <para>Ampersand separated list of filenames. If the filename
+                               is a relative filename (it does not begin with a slash), it
+                               will be searched for in the Asterisk sounds directory. If the
+                               filename is able to be parsed as a URL, Asterisk will
+                               download the file and then begin playback on it. To include a
+                               literal <literal>&amp;</literal> in the URL you can enclose
+                               the URL in single quotes.</para>
+                               <argument name="sound_file" required="true" />
+                               <argument name="sound_file2" multiple="true" />
+                       </parameter>
                        <parameter name="timeout">
                                <para>Timeout integer in seconds. Note the timeout will only start
                                once the sound file has stopped playing.</para>
@@ -776,7 +786,10 @@ static int speech_background(struct ast_channel *chan, const char *data)
        /* Okay it's streaming so go into a loop grabbing frames! */
        while (done == 0) {
                /* If the filename is null and stream is not running, start up a new sound file */
-               if (!quieted && (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL) && (filename = strsep(&filename_tmp, "&"))) {
+               if (!quieted
+                       && ast_channel_streamid(chan) == -1
+                       && ast_channel_timingfunc(chan) == NULL
+                       && (filename = ast_strsep(&filename_tmp, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
                        /* Discard old stream information */
                        ast_stopstream(chan);
                        /* Start new stream */
index 5f5590afa91fcece20f858e2a57392ed680d73ee..c03d6733e153214a53bdbc942bc686cf1a3eb469 100644 (file)
@@ -205,7 +205,7 @@ enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const
                prompt = "";
 
        filename = ast_strdupa(prompt);
-       while ((front = strsep(&filename, "&"))) {
+       while ((front = ast_strsep(&filename, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
                if (!ast_strlen_zero(front)) {
                        res = ast_streamfile(c, front, ast_channel_language(c));
                        if (res)
index d1548c7df6bb6ac9ca2d06159d9508b9eeea2ba3..17869ad12e900d49a5fb5043f8ca7de13f761389 100644 (file)
                </synopsis>
                <syntax>
                        <parameter name="filenames" required="true" argsep="&amp;">
+                               <para>Ampersand separated list of filenames. If the filename
+                               is a relative filename (it does not begin with a slash), it
+                               will be searched for in the Asterisk sounds directory. If the
+                               filename is able to be parsed as a URL, Asterisk will
+                               download the file and then begin playback on it. To include a
+                               literal <literal>&amp;</literal> in the URL you can enclose
+                               the URL in single quotes.</para>
                                <argument name="filename1" required="true" />
                                <argument name="filename2" multiple="true" />
                        </parameter>
@@ -1172,7 +1179,7 @@ static int pbx_builtin_background(struct ast_channel *chan, const char *data)
 
                ast_stopstream(chan);           /* Stop anything playing */
                /* Stream the list of files */
-               while (!res && (front = strsep(&back, "&")) ) {
+               while (!res && (front = ast_strsep(&back, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
                        if ( (res = ast_streamfile(chan, front, args.lang)) ) {
                                ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char*)data);
                                res = 0;