add 'exit context' and 'only stop on match' options to Background app (bug #4511)
authorKevin P. Fleming <kpfleming@digium.com>
Tue, 12 Jul 2005 01:34:06 +0000 (01:34 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Tue, 12 Jul 2005 01:34:06 +0000 (01:34 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6093 65c4cc65-6c06-0410-ace0-fbb531ad65f3

file.c
include/asterisk/file.h
pbx.c

diff --git a/file.c b/file.c
index ce24fa0..9cb6d23 100755 (executable)
--- a/file.c
+++ b/file.c
@@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/utils.h"
 #include "asterisk/lock.h"
 #include "asterisk/app.h"
+#include "asterisk/pbx.h"
 
 struct ast_format {
        /* Name of format */
@@ -1140,6 +1141,67 @@ int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd,
        return (c->_softhangup ? -1 : 0);
 }
 
+int ast_waitstream_exten(struct ast_channel *c, const char *context)
+{
+       /* Waitstream, with return in the case of a valid 1 digit extension */
+       /* in the current or specified context being pressed */
+       /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
+       int res;
+       struct ast_frame *fr;
+       char exten[AST_MAX_EXTENSION] = "";
+
+       if (!context) context = c->context;
+       while(c->stream) {
+               res = ast_sched_wait(c->sched);
+               if ((res < 0) && !c->timingfunc) {
+                       ast_stopstream(c);
+                       break;
+               }
+               if (res < 0)
+                       res = 1000;
+               res = ast_waitfor(c, res);
+               if (res < 0) {
+                       ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
+                       return res;
+               } else if (res > 0) {
+                       fr = ast_read(c);
+                       if (!fr) {
+#if 0
+                               ast_log(LOG_DEBUG, "Got hung up\n");
+#endif
+                               return -1;
+                       }
+                       
+                       switch(fr->frametype) {
+                       case AST_FRAME_DTMF:
+                               res = fr->subclass;
+                               snprintf(exten, sizeof(exten), "%c", res);
+                               if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
+                                       ast_frfree(fr);
+                                       return res;
+                               }
+                               break;
+                       case AST_FRAME_CONTROL:
+                               switch(fr->subclass) {
+                               case AST_CONTROL_HANGUP:
+                                       ast_frfree(fr);
+                                       return -1;
+                               case AST_CONTROL_RINGING:
+                               case AST_CONTROL_ANSWER:
+                                       /* Unimportant */
+                                       break;
+                               default:
+                                       ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
+                               }
+                       }
+                       /* Ignore */
+                       ast_frfree(fr);
+               }
+               ast_sched_runq(c->sched);
+       }
+       return (c->_softhangup ? -1 : 0);
+}
+
 static int show_file_formats(int fd, int argc, char *argv[])
 {
 #define FORMAT "%-10s %-10s %-20s\n"
index 8b6104d..7c4442f 100755 (executable)
@@ -124,6 +124,16 @@ int ast_filecopy(const char *oldname, const char *newname, const char *fmt);
  */
 int ast_waitstream(struct ast_channel *c, const char *breakon);
 
+/*! Waits for a stream to stop or digit matching a valid one digit exten to be pressed */
+/*!
+ * \param c channel to waitstram on
+ * \param context string of context to match digits to break upon
+ * Begins playback of a stream...
+ * Wait for a stream to stop or for any one of a valid extension digit to arrive,  Returns 0 
+ * if the stream finishes, the character if it was interrupted, and -1 on error 
+ */
+int ast_waitstream_exten(struct ast_channel *c, const char *context);
+
 /*! Same as waitstream but allows stream to be forwarded or rewound */
 /*!
  * \param c channel to waitstram on
diff --git a/pbx.c b/pbx.c
index d872bd2..423d1e4 100755 (executable)
--- a/pbx.c
+++ b/pbx.c
@@ -72,10 +72,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define BACKGROUND_SKIP                (1 << 0)
 #define BACKGROUND_NOANSWER    (1 << 1)
+#define BACKGROUND_MATCHEXTEN  (1 << 2)
+#define BACKGROUND_PLAYBACK    (1 << 3)
 
 AST_DECLARE_OPTIONS(background_opts,{
        ['s'] = { BACKGROUND_SKIP },
        ['n'] = { BACKGROUND_NOANSWER },
+       ['m'] = { BACKGROUND_MATCHEXTEN },
+       ['p'] = { BACKGROUND_PLAYBACK },
 });
 
 #define WAITEXTEN_MOH          (1 << 0)
@@ -243,19 +247,23 @@ static struct pbx_builtin {
 
        { "BackGround", pbx_builtin_background,
        "Play a file while awaiting extension",
-       "  Background(filename1[&filename2...][|options[|langoverride]]): Plays\n"
-       "given files, while simultaneously waiting for the user to begin typing\n"
+       "  Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
+       "Plays given files, while simultaneously waiting for the user to begin typing\n"
        "an extension. The timeouts do not count until the last BackGround\n"
        "application has ended. Options may also be included following a pipe \n"
        "symbol. The 'langoverride' may be a language to use for playing the prompt\n"
-       "which differs from the current language of the channel. Returns -1 if \n"
-       "the channel was hung up, or if the file does not exist. Returns 0 otherwise.\n\n"
+       "which differs from the current language of the channel.  The optional\n"
+       "'context' can be used to specify an optional context to exit into.\n"
+       "Returns -1 if thhe channel was hung up, or if the file does not exist./n"
+       "Returns 0 otherwise.\n\n"
        "  Options:\n"
        "    's' - causes the playback of the message to be skipped\n"
        "          if the channel is not in the 'up' state (i.e. it\n"
        "          hasn't been answered yet.) If this happens, the\n"
        "          application will return immediately.\n"
        "    'n' - don't answer the channel before playing the files\n"
+       "    'm' - only break if a digit hit matches a one digit\n"
+       "                extension in the destination context\n"
        },
 
        { "Busy", pbx_builtin_busy,
@@ -5440,11 +5448,12 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
        int res = 0;
        int argc;
        char *args;
-       char *argv[3];
+       char *argv[4];
        char *options = NULL; 
        char *filename = NULL;
        char *front = NULL, *back = NULL;
        char *lang = NULL;
+       char *context = NULL;
        struct ast_flags flags = {0};
 
        args = ast_strdupa(data);
@@ -5456,6 +5465,8 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
                                options = argv[1];
                        if (argc > 2)
                                lang = argv[2];
+                       if (argc > 3)
+                               context = argv[3];
                } else {
                        ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
                }
@@ -5464,6 +5475,9 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
        if (!lang)
                lang = chan->language;
 
+       if (!context)
+               context = chan->context;
+
        if (options) {
                if (!strcasecmp(options, "skip"))
                        flags.flags = BACKGROUND_SKIP;
@@ -5494,7 +5508,15 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
                        }
                        res = ast_streamfile(chan, front, lang);
                        if (!res) {
-                               res = ast_waitstream(chan, AST_DIGIT_ANY);
+                               if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
+                                       res = ast_waitstream(chan, "");
+                               } else {
+                                       if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
+                                               res = ast_waitstream_exten(chan, context);
+                                       } else {
+                                               res = ast_waitstream(chan, AST_DIGIT_ANY);
+                                       }
+                               }
                                ast_stopstream(chan);
                        } else {
                                ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
@@ -5504,7 +5526,14 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
                        front = back;
                }
        }
-       return res;
+       if (context != chan->context && res) {
+               snprintf(chan->exten, sizeof(chan->exten), "%c", res);
+               ast_copy_string(chan->context, context, sizeof(chan->context));
+               chan->priority = 0;
+               return 0;
+       } else {
+               return res;
+       }
 }
 
 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)