Adds F option to Bridge application
authorJonathan Rose <jrose@digium.com>
Thu, 22 Mar 2012 21:25:22 +0000 (21:25 +0000)
committerJonathan Rose <jrose@digium.com>
Thu, 22 Mar 2012 21:25:22 +0000 (21:25 +0000)
Similar to dial and queue F option.

(Closes issue ASTERISK-19282)
Reported by: To
Patches:
bridge_f-v3.diff uploaded by To (license 6347)
Review: https://reviewboard.asterisk.org/r/1825/

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

CHANGES
apps/app_dial.c
apps/app_queue.c
include/asterisk/utils.h
main/features.c
main/utils.c

diff --git a/CHANGES b/CHANGES
index 9299077..d42be61 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -130,6 +130,10 @@ Applications
    when using multiple options (so that j option could be used without having to
    manually specify timezone and format) There are other beneftis eg. format can
    now be used without specifying time zone as well.
+ * Added 'F()' option to Queue and Bridge. Similar to the dial option, these can
+   be supplied with arguments indicating where the callee should go after the caller
+   is hung up, or without options specified, the priority after the Queue/Bridge
+   will be used.
 
 Parking
 ------------
index fbd4ef6..902b781 100644 (file)
@@ -1615,13 +1615,6 @@ static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str
        return 0;
 }
 
-static void replace_macro_delimiter(char *s)
-{
-       for (; *s; s++)
-               if (*s == '^')
-                       *s = ',';
-}
-
 /* returns true if there is a valid privacy reply */
 static int valid_priv_reply(struct ast_flags64 *opts, int res)
 {
@@ -2628,7 +2621,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                        ast_clear_flag(ast_channel_cdr(chan), AST_CDR_FLAG_DIALED);
                        ast_clear_flag(ast_channel_cdr(peer), AST_CDR_FLAG_DIALED);
 
-                       replace_macro_delimiter(opt_args[OPT_ARG_GOTO]);
+                       ast_replace_subargument_delimiter(opt_args[OPT_ARG_GOTO]);
                        ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
                        /* peer goes to the same context and extension as chan, so just copy info from chan*/
                        ast_channel_context_set(peer, ast_channel_context(chan));
@@ -2659,7 +2652,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                                ast_channel_context_set(peer, ast_channel_context(chan));
                                ast_channel_exten_set(peer, ast_channel_exten(chan));
 
-                               replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
+                               ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
                                res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]);
                                ast_debug(1, "Macro exited with status %d\n", res);
                                res = 0;
@@ -2699,7 +2692,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                                        res = -1;
                                        /* perform a transfer to a new extension */
                                        if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
-                                               replace_macro_delimiter(macro_transfer_dest);
+                                               ast_replace_subargument_delimiter(macro_transfer_dest);
                                                if (!ast_parseable_goto(chan, macro_transfer_dest))
                                                        ast_set_flag64(peerflags, OPT_GO_ON);
                                        }
@@ -2724,7 +2717,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                        theapp = pbx_findapp("Gosub");
 
                        if (theapp && !res9) {
-                               replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]);
+                               ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]);
 
                                /* Set where we came from */
                                ast_channel_context_set(peer, "app_dial_gosub_virtual_context");
@@ -2814,7 +2807,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                                        res = -1;
                                        /* perform a transfer to a new extension */
                                        if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/
-                                               replace_macro_delimiter(gosub_transfer_dest);
+                                               ast_replace_subargument_delimiter(gosub_transfer_dest);
                                                if (!ast_parseable_goto(chan, gosub_transfer_dest))
                                                        ast_set_flag64(peerflags, OPT_GO_ON);
                                        }
@@ -2928,7 +2921,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                }
                if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON)) {
                        if(!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
-                               replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+                               ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
                                ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
                        } else { /* F() */
                                int goto_res;
index d372a50..7a91384 100644 (file)
@@ -1305,21 +1305,6 @@ static void set_queue_result(struct ast_channel *chan, enum queue_result res)
        }
 }
 
-/*!
- * \internal
- * \brief Converts delimited '^' characters in a target priority/extension/context string
- *  to commas so that they can be used with ast_parseable_goto.
- * \param s string that '^' characters are being replaced in.
- */
-static void replace_macro_delimiter(char *s)
-{
-       for (; *s; s++) {
-               if (*s == '^') {
-                       *s = ',';
-               }
-       }
-}
-
 static const char *int2strat(int strategy)
 {
        int x;
@@ -5326,7 +5311,7 @@ static int try_calling(struct queue_ent *qe, const struct ast_flags opts, char *
 
                if (!ast_check_hangup(peer) && ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
                        if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
-                               replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+                               ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
 
                                if (ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]) == AST_PBX_SUCCESS) {
                                        ast_pbx_start(peer);
index e3b9843..c33f423 100644 (file)
@@ -429,6 +429,12 @@ int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, v
 /* End of thread management support */
 
 /*!
+       \brief Replace '^' in a string with ','
+       \param s String within which to replace characters
+*/
+void ast_replace_subargument_delimiter(char *s);
+
+/*!
        \brief Process a string to find and replace characters
        \param start The string to analyze
        \param find The character to find
index 96c528d..71be7d3 100644 (file)
@@ -127,6 +127,36 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <option name="p">
                                                <para>Play a courtesy tone to <replaceable>channel</replaceable>.</para>
                                        </option>
+                                       <option name="F" argsep="^">
+                                               <argument name="context" required="false" />
+                                               <argument name="exten" required="false" />
+                                               <argument name="priority" required="true" />
+                                               <para>When the bridger hangs up, transfer the <emphasis>bridged</emphasis> party
+                                               to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
+                                               <note>
+                                                       <para>Any channel variables you want the called channel to inherit from the caller channel must be
+                                                       prefixed with one or two underbars ('_').</para>
+                                               </note>
+                                               <note>
+                                                       <para>This option will override the 'x' option</para>
+                                               </note>
+                                       </option>
+                                       <option name="F">
+                                               <para>When the bridger hangs up, transfer the <emphasis>bridged</emphasis> party
+                                               to the next priority of the current extension and <emphasis>start</emphasis> execution
+                                               at that location.</para>
+                                               <note>
+                                                       <para>Any channel variables you want the called channel to inherit from the caller channel must be
+                                                       prefixed with one or two underbars ('_').</para>
+                                               </note>
+                                               <note>
+                                                       <para>Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
+                                               </note>
+                                               <note>
+                                                       <para>This option will override the 'x' option</para>
+                                               </note>
+                                       </option>
+
                                        <option name="h">
                                                <para>Allow the called party to hang up by sending the
                                                <replaceable>*</replaceable> DTMF digit.</para>
@@ -7397,17 +7427,20 @@ enum {
        OPT_CALLEE_PARK = (1 << 9),
        OPT_CALLER_PARK = (1 << 10),
        OPT_CALLEE_KILL = (1 << 11),
+       OPT_CALLEE_GO_ON = (1 << 12),
 };
 
 enum {
        OPT_ARG_DURATION_LIMIT = 0,
        OPT_ARG_DURATION_STOP,
+       OPT_ARG_CALLEE_GO_ON,
        /* note: this entry _MUST_ be the last one in the enum */
        OPT_ARG_ARRAY_SIZE,
 };
 
 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
        AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE),
+       AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
        AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
        AST_APP_OPTION('H', OPT_CALLER_HANGUP),
        AST_APP_OPTION('k', OPT_CALLEE_PARK),
@@ -7668,18 +7701,43 @@ static int bridge_exec(struct ast_channel *chan, const char *data)
 
        /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
        pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
-       if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
-               ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
-                       ast_channel_context(final_dest_chan), ast_channel_exten(final_dest_chan),
-                       ast_channel_priority(final_dest_chan), ast_channel_name(final_dest_chan));
-
-               if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
-                       ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan));
-                       ast_hangup(final_dest_chan);
-               } else
-                       ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan));
+       if (!ast_check_hangup(final_dest_chan)) {
+               if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
+                       char *caller_context = ast_strdupa(ast_channel_context(chan));
+                       char *caller_extension = ast_strdupa(ast_channel_exten(chan));
+                       int caller_priority = ast_channel_priority(chan);
+
+                       if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
+                               ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+                               /* Set current dialplan position to bridger dialplan position */
+                               ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority);
+                               /* Then perform the goto */
+                               if (ast_parseable_goto(final_dest_chan, opt_args[OPT_ARG_CALLEE_GO_ON]) == AST_PBX_SUCCESS) {
+                                       ast_pbx_start(final_dest_chan);
+                               } else {
+                                       ast_hangup(final_dest_chan);
+                               }
+                       } else { /* F() */
+                               if (ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority + 1) == AST_PBX_GOTO_FAILED) {
+                                       ast_hangup(final_dest_chan);
+                               } else {
+                                       ast_pbx_start(final_dest_chan);
+                               }
+                       }
+               } else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
+                       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
+                               ast_channel_context(final_dest_chan), ast_channel_exten(final_dest_chan),
+                               ast_channel_priority(final_dest_chan), ast_channel_name(final_dest_chan));
+
+                       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
+                               ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan));
+                               ast_hangup(final_dest_chan);
+                       } else {
+                               ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan));
+                       }
+               }
        } else {
-               ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", ast_channel_name(final_dest_chan));
+                       ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", ast_channel_name(final_dest_chan));
                ast_hangup(final_dest_chan);
        }
 done:
index 050200b..ffcd37c 100644 (file)
@@ -1464,6 +1464,15 @@ long int ast_random(void)
        return res;
 }
 
+void ast_replace_subargument_delimiter(char *s)
+{
+       for (; *s; s++) {
+               if (*s == '^') {
+                       *s = ',';
+               }
+       }
+}
+
 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
 {
        char *dataPut = start;