diff options
Diffstat (limited to 'main/manager.c')
-rw-r--r-- | main/manager.c | 207 |
1 files changed, 160 insertions, 47 deletions
diff --git a/main/manager.c b/main/manager.c index c9b2fbe1e..c28e6169b 100644 --- a/main/manager.c +++ b/main/manager.c @@ -94,6 +94,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stasis.h" #include "asterisk/test.h" #include "asterisk/json.h" +#include "asterisk/bridging.h" /*** DOCUMENTATION <manager name="Ping" language="en_US"> @@ -966,6 +967,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") manager.conf will be present upon starting a new session.</para> </description> </manager> + <manager name="BlindTransfer" language="en_US"> + <synopsis> + Blind transfer channel(s) to the given destination + </synopsis> + <syntax> + <parameter name="Channel" required="true"> + </parameter> + <parameter name="Context"> + </parameter> + <parameter name="Exten"> + </parameter> + </syntax> + <description> + <para>Redirect all channels currently bridged to the specified channel to the specified destination.</para> + </description> + <see-also> + <ref type="manager">Redirect</ref> + </see-also> + </manager> ***/ /*! \addtogroup Group_AMI AMI functions @@ -3538,7 +3558,8 @@ static int action_status(struct mansession *s, const struct message *m) const char *cvariables = astman_get_header(m, "Variables"); char *variables = ast_strdupa(S_OR(cvariables, "")); struct ast_channel *c; - char bridge[256]; + struct ast_bridge *bridge; + char bridge_text[256]; struct timeval now = ast_tvnow(); long elapsed_seconds = 0; int channels = 0; @@ -3607,44 +3628,52 @@ static int action_status(struct mansession *s, const struct message *m) } channels++; - if (ast_channel_internal_bridged_channel(c)) { - snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", ast_channel_name(ast_channel_internal_bridged_channel(c)), ast_channel_uniqueid(ast_channel_internal_bridged_channel(c))); + bridge = ast_channel_get_bridge(c); + if (bridge) { + snprintf(bridge_text, sizeof(bridge_text), "BridgeID: %s\r\n", + bridge->uniqueid); + ao2_ref(bridge, -1); } else { - bridge[0] = '\0'; + bridge_text[0] = '\0'; } if (ast_channel_pbx(c)) { if (ast_channel_cdr(c)) { elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec; } astman_append(s, - "Event: Status\r\n" - "Privilege: Call\r\n" - "Channel: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "ConnectedLineNum: %s\r\n" - "ConnectedLineName: %s\r\n" - "Accountcode: %s\r\n" - "ChannelState: %d\r\n" - "ChannelStateDesc: %s\r\n" - "Context: %s\r\n" - "Extension: %s\r\n" - "Priority: %d\r\n" - "Seconds: %ld\r\n" - "%s" - "Uniqueid: %s\r\n" - "%s" - "%s" - "\r\n", - ast_channel_name(c), - S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"), - S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"), - S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"), - S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"), - ast_channel_accountcode(c), - ast_channel_state(c), - ast_state2str(ast_channel_state(c)), ast_channel_context(c), - ast_channel_exten(c), ast_channel_priority(c), (long)elapsed_seconds, bridge, ast_channel_uniqueid(c), ast_str_buffer(str), idText); + "Event: Status\r\n" + "Privilege: Call\r\n" + "Channel: %s\r\n" + "CallerIDNum: %s\r\n" + "CallerIDName: %s\r\n" + "ConnectedLineNum: %s\r\n" + "ConnectedLineName: %s\r\n" + "Accountcode: %s\r\n" + "ChannelState: %d\r\n" + "ChannelStateDesc: %s\r\n" + "Context: %s\r\n" + "Extension: %s\r\n" + "Priority: %d\r\n" + "Seconds: %ld\r\n" + "%s" + "Uniqueid: %s\r\n" + "%s" + "%s" + "\r\n", + ast_channel_name(c), + S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "<unknown>"), + S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "<unknown>"), + S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"), + S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"), + ast_channel_accountcode(c), + ast_channel_state(c), + ast_state2str(ast_channel_state(c)), + ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), + (long) elapsed_seconds, + bridge_text, + ast_channel_uniqueid(c), + ast_str_buffer(str), + idText); } else { astman_append(s, "Event: Status\r\n" @@ -3667,8 +3696,11 @@ static int action_status(struct mansession *s, const struct message *m) S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "<unknown>"), S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "<unknown>"), ast_channel_accountcode(c), - ast_state2str(ast_channel_state(c)), bridge, ast_channel_uniqueid(c), - ast_str_buffer(str), idText); + ast_state2str(ast_channel_state(c)), + bridge_text, + ast_channel_uniqueid(c), + ast_str_buffer(str), + idText); } ast_channel_unlock(c); @@ -3804,12 +3836,6 @@ static int action_redirect(struct mansession *s, const struct message *m) if (ast_strlen_zero(name2)) { /* Single channel redirect in progress. */ - if (ast_channel_pbx(chan)) { - ast_channel_lock(chan); - /* don't let the after-bridge code run the h-exten */ - ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); - ast_channel_unlock(chan); - } res = ast_async_goto(chan, context, exten, pi); if (!res) { astman_send_ack(s, m, "Redirect successful"); @@ -3837,16 +3863,12 @@ static int action_redirect(struct mansession *s, const struct message *m) /* Dual channel redirect in progress. */ if (ast_channel_pbx(chan)) { ast_channel_lock(chan); - /* don't let the after-bridge code run the h-exten */ - ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT - | AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); + ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); ast_channel_unlock(chan); } if (ast_channel_pbx(chan2)) { ast_channel_lock(chan2); - /* don't let the after-bridge code run the h-exten */ - ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_HANGUP_DONT - | AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); + ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT); ast_channel_unlock(chan2); } res = ast_async_goto(chan, context, exten, pi); @@ -3882,6 +3904,51 @@ static int action_redirect(struct mansession *s, const struct message *m) return 0; } +static int action_blind_transfer(struct mansession *s, const struct message *m) +{ + const char *name = astman_get_header(m, "Channel"); + const char *exten = astman_get_header(m, "Exten"); + const char *context = astman_get_header(m, "Context"); + RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup); + + if (ast_strlen_zero(name)) { + astman_send_error(s, m, "No channel specified"); + return 0; + } + + if (ast_strlen_zero(exten)) { + astman_send_error(s, m, "No extension specified"); + return 0; + } + + chan = ast_channel_get_by_name(name); + if (!chan) { + astman_send_error(s, m, "Channel specified does not exist"); + return 0; + } + + if (ast_strlen_zero(context)) { + context = ast_channel_context(chan); + } + + switch (ast_bridge_transfer_blind(chan, exten, context, NULL, NULL)) { + case AST_BRIDGE_TRANSFER_NOT_PERMITTED: + astman_send_error(s, m, "Transfer not permitted"); + break; + case AST_BRIDGE_TRANSFER_INVALID: + astman_send_error(s, m, "Transfer invalid"); + break; + case AST_BRIDGE_TRANSFER_FAIL: + astman_send_error(s, m, "Transfer failed"); + break; + case AST_BRIDGE_TRANSFER_SUCCESS: + astman_send_ack(s, m, "Transfer succeeded"); + break; + } + + return 0; +} + static int action_atxfer(struct mansession *s, const struct message *m) { const char *name = astman_get_header(m, "Channel"); @@ -5683,7 +5750,7 @@ int __ast_manager_event_multichan(int category, const char *event, int chancount return -1; } - cat_str = authority_to_str (category, &auth); + cat_str = authority_to_str(category, &auth); ast_str_set(&buf, 0, "Event: %s\r\nPrivilege: %s\r\n", event, cat_str); @@ -7510,6 +7577,10 @@ static int __init_manager(int reload, int by_external_config) return -1; } + if (manager_bridging_init()) { + return -1; + } + if (!registered) { /* Register default actions */ ast_manager_register_xml_core("Ping", 0, action_ping); @@ -7547,6 +7618,7 @@ static int __init_manager(int reload, int by_external_config) ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck); ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage); ast_manager_register_xml_core("Filter", EVENT_FLAG_SYSTEM, action_filter); + ast_manager_register_xml_core("BlindTransfer", EVENT_FLAG_CALL, action_blind_transfer); #ifdef TEST_FRAMEWORK stasis_subscribe(ast_test_suite_topic(), test_suite_event_cb, NULL); @@ -8025,3 +8097,44 @@ struct ast_datastore *astman_datastore_find(struct mansession *s, const struct a return datastore; } + +static void manager_event_blob_dtor(void *obj) +{ + struct ast_manager_event_blob *ev = obj; + ast_string_field_free_memory(ev); +} + +struct ast_manager_event_blob * +__attribute__((format(printf, 3, 4))) +ast_manager_event_blob_create( + int event_flags, + const char *manager_event, + const char *extra_fields_fmt, + ...) +{ + RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup); + va_list argp; + + ast_assert(extra_fields_fmt != NULL); + ast_assert(manager_event != NULL); + + ev = ao2_alloc(sizeof(*ev), manager_event_blob_dtor); + if (!ev) { + return NULL; + } + + if (ast_string_field_init(ev, 20)) { + return NULL; + } + + ev->manager_event = manager_event; + ev->event_flags = event_flags; + + va_start(argp, extra_fields_fmt); + ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt, + argp); + va_end(argp); + + ao2_ref(ev, +1); + return ev; +} |