func_channel: Read/Write after_bridge_goto option
authorJonathan Rose <jrose@digium.com>
Wed, 26 Jun 2013 20:59:14 +0000 (20:59 +0000)
committerJonathan Rose <jrose@digium.com>
Wed, 26 Jun 2013 20:59:14 +0000 (20:59 +0000)
Allows reading and setting of a channel's after_bridge_goto datastore

(closes issue ASTERISK-21875)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2628/

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

funcs/func_channel.c
include/asterisk/bridging.h
main/bridging.c

index 4327fd2..9dd210c 100644 (file)
@@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/module.h"
 #include "asterisk/channel.h"
+#include "asterisk/bridging.h"
 #include "asterisk/pbx.h"
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
@@ -118,6 +119,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <enum name="checkhangup">
                                                <para>R/O Whether the channel is hanging up (1/0)</para>
                                        </enum>
+                                       <enum name="after_bridge_goto">
+                                               <para>R/W the parseable goto string indicating where the channel is
+                                               expected to return to in the PBX after exiting the next bridge it joins
+                                               on the condition that it doesn't hang up. The parseable goto string uses
+                                               the same syntax as the <literal>Goto</literal> application.</para>
+                                       </enum>
                                        <enum name="hangup_handler_pop">
                                                <para>W/O Replace the most recently added hangup handler
                                                with a new hangup handler on the channel if supplied.  The
@@ -475,6 +482,8 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
                struct ast_str *tmp_str = ast_str_alloca(1024);
 
                locked_copy_string(chan, buf,  ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len);
+       } else if (!strcasecmp(data, "after_bridge_goto")) {
+               ast_after_bridge_goto_read(chan, buf, len);
        } else if (!strcasecmp(data, "amaflags")) {
                ast_channel_lock(chan);
                snprintf(buf, len, "%d", ast_channel_amaflags(chan));
@@ -516,7 +525,13 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio
                locked_string_field_set(chan, accountcode, value);
        else if (!strcasecmp(data, "userfield"))
                locked_string_field_set(chan, userfield, value);
-       else if (!strcasecmp(data, "amaflags")) {
+       else if (!strcasecmp(data, "after_bridge_goto")) {
+               if (ast_strlen_zero(value)) {
+                       ast_after_bridge_goto_discard(chan);
+               } else {
+                       ast_after_bridge_set_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value);
+               }
+       } else if (!strcasecmp(data, "amaflags")) {
                ast_channel_lock(chan);
                if (isdigit(*value)) {
                        int amaflags;
index 6e6d73b..eac4b49 100644 (file)
@@ -1634,6 +1634,16 @@ void ast_after_bridge_goto_run(struct ast_channel *chan);
  */
 void ast_after_bridge_goto_discard(struct ast_channel *chan);
 
+/*!
+ * \brief Read after bridge goto if it exists
+ * \since 12.0.0
+ *
+ * \param chan Channel to read the after bridge goto parseable goto string from
+ * \param buffer Buffer to write the after bridge goto data to
+ * \param buf_size size of the buffer being written to
+ */
+void ast_after_bridge_goto_read(struct ast_channel *chan, char *buffer, size_t buf_size);
+
 /*! Reason the the after bridge callback will not be called. */
 enum ast_after_bridge_cb_reason {
        /*! The datastore is being destroyed.  Likely due to hangup. */
index a4a1339..feefcbe 100644 (file)
@@ -3414,6 +3414,47 @@ void ast_after_bridge_goto_discard(struct ast_channel *chan)
        }
 }
 
+void ast_after_bridge_goto_read(struct ast_channel *chan, char *buffer, size_t buf_size)
+{
+       struct ast_datastore *datastore;
+       struct after_bridge_goto_ds *after_bridge;
+       char *current_pos = buffer;
+       size_t remaining_size = buf_size;
+
+       SCOPED_CHANNELLOCK(lock, chan);
+
+       datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
+       if (!datastore) {
+               buffer[0] = '\0';
+               return;
+       }
+
+       after_bridge = datastore->data;
+
+       if (after_bridge->parseable_goto) {
+               snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
+               return;
+       }
+
+       if (!ast_strlen_zero(after_bridge->context)) {
+               snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
+               remaining_size = remaining_size - strlen(current_pos);
+               current_pos += strlen(current_pos);
+       }
+
+       if (after_bridge->run_h_exten) {
+               snprintf(current_pos, remaining_size, "h,");
+               remaining_size = remaining_size - strlen(current_pos);
+               current_pos += strlen(current_pos);
+       } else if (!ast_strlen_zero(after_bridge->exten)) {
+               snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
+               remaining_size = remaining_size - strlen(current_pos);
+               current_pos += strlen(current_pos);
+       }
+
+       snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
+}
+
 int ast_after_bridge_goto_setup(struct ast_channel *chan)
 {
        struct ast_datastore *datastore;
@@ -3479,6 +3520,10 @@ int ast_after_bridge_goto_setup(struct ast_channel *chan)
                                after_bridge->exten, after_bridge->priority + 1);
                }
                if (!goto_failed) {
+                       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
+                               ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
+                       }
+
                        ast_debug(1, "Setup after bridge goto location to %s,%s,%d.\n",
                                ast_channel_context(chan),
                                ast_channel_exten(chan),