Skip to content

Commit

Permalink
app.c: Allow ampersands in playback lists to be escaped.
Browse files Browse the repository at this point in the history
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 asterisk#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`.
  • Loading branch information
seanbright authored and asterisk-org-access-app[bot] committed Nov 28, 2023
1 parent 31c44d0 commit ca931c9
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 19 deletions.
13 changes: 11 additions & 2 deletions apps/app_authenticate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
4 changes: 2 additions & 2 deletions apps/app_confbridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
9 changes: 8 additions & 1 deletion apps/app_playback.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@
</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>
Expand Down Expand Up @@ -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){
Expand Down
19 changes: 13 additions & 6 deletions apps/app_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,18 @@
<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
Expand Down Expand Up @@ -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));
}
Expand Down
12 changes: 9 additions & 3 deletions apps/app_read.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,15 @@
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">
Expand Down
3 changes: 2 additions & 1 deletion apps/app_skel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
17 changes: 15 additions & 2 deletions apps/app_speech_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,17 @@
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>
Expand Down Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion main/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 8 additions & 1 deletion main/pbx_builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@
</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>
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit ca931c9

Please sign in to comment.