From d014ad2261b1a4ffb590edcd7b7b4d6c31a74457 Mon Sep 17 00:00:00 2001 From: Jonathan Rose Date: Wed, 26 Jun 2013 20:59:14 +0000 Subject: [PATCH] func_channel: Read/Write after_bridge_goto option 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 | 17 +++++++++++++- include/asterisk/bridging.h | 10 +++++++++ main/bridging.c | 45 +++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 4327fd257b..9dd210c4e3 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -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$") R/O Whether the channel is hanging up (1/0) + + 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 Goto application. + 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; diff --git a/include/asterisk/bridging.h b/include/asterisk/bridging.h index 6e6d73b4a6..eac4b499c9 100644 --- a/include/asterisk/bridging.h +++ b/include/asterisk/bridging.h @@ -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. */ diff --git a/main/bridging.c b/main/bridging.c index a4a1339a34..feefcbee44 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -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),