diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 2cc1000e2f..d9cd67332f 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1547,6 +1547,7 @@ typedef enum { CF_AWAITING_STREAM_CHANGE, CF_PROCESSING_STREAM_CHANGE, CF_STREAM_CHANGED, + CF_ADD_ENDPOINTS, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 758e8c9570..7b0add370e 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -4815,7 +4815,7 @@ SWITCH_STANDARD_API(pause_function) return SWITCH_STATUS_SUCCESS; } -#define ORIGINATE_SYNTAX " |&() [] [] [] [] []" +#define ORIGINATE_SYNTAX " |&() [] [] [] [] [] []" SWITCH_STANDARD_API(originate_function) { switch_channel_t *caller_channel; @@ -4841,7 +4841,7 @@ SWITCH_STANDARD_API(originate_function) switch_assert(mycmd); argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); - if (argc < 2 || argc > 7) { + if (argc < 2 || argc > 8) { stream->write_function(stream, "-USAGE: %s\n", ORIGINATE_SYNTAX); goto done; } @@ -4871,6 +4871,30 @@ SWITCH_STANDARD_API(originate_function) timeout = atoi(argv[6]); } + /* It is OK to use the caller_session and caller_channel variables instead of adding new ones, since this isn't a real originate */ + if (argv[7]) { + caller_session = switch_core_session_locate(argv[7]); + if (caller_session) { + caller_channel = switch_core_session_get_channel(caller_session); + if (caller_channel) { + if (switch_channel_test_flag(caller_channel, CF_ORIGINATOR) && switch_channel_test_flag(caller_channel, CF_ADD_ENDPOINTS) && + !switch_channel_get_variable(caller_channel, "originate_add_endpoints")) { + switch_channel_set_variable(caller_channel, "originate_add_endpoints", aleg); + stream->write_function(stream, "+OK %s\n", switch_core_session_get_uuid(caller_session)); + } else { + stream->write_function(stream, "-ERR originator is in the wrong state (originator: %d, add endpoints: %d, var: %s)\n", + switch_channel_test_flag(caller_channel, CF_ORIGINATOR), + switch_channel_test_flag(caller_channel, CF_ADD_ENDPOINTS), + switch_channel_get_variable(caller_channel, "originate_add_endpoints")); + } + } + switch_core_session_rwunlock(caller_session); + } else { + stream->write_function(stream, "-ERR originator session not found\n"); + } + goto done; + } + if (switch_ivr_originate(NULL, &caller_session, &cause, aleg, timeout, NULL, cid_name, cid_num, NULL, NULL, SOF_NONE, NULL) != SWITCH_STATUS_SUCCESS || !caller_session) { stream->write_function(stream, "-ERR %s\n", switch_channel_cause2str(cause)); diff --git a/src/switch_core_session.c b/src/switch_core_session.c index a810cc45cd..c81cbe969b 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -2153,6 +2153,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_xml(switch_e flags[CF_SIMPLIFY] = 0; flags[CF_VIDEO_READY] = 0; flags[CF_VIDEO_DECODED_READ] = 0; + flags[CF_ADD_ENDPOINTS] = 0; if (!(session = switch_core_session_request_uuid(endpoint_interface, direction, SOF_NO_LIMITS, pool, uuid))) { return NULL; diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index a8b9ddfb44..bcfa7ee18d 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1929,6 +1929,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess originate_status_t originate_status[MAX_PEERS] = { {0} }; switch_originate_flag_t dftflags = SOF_NONE, myflags = dftflags; char *pipe_names[MAX_PEERS] = { 0 }; + const char *newep = NULL; char *data = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; switch_channel_t *caller_channel = NULL; @@ -1941,7 +1942,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess time_t start, global_start; switch_time_t last_retry_start = 0; switch_frame_t *read_frame = NULL; - int r = 0, i, and_argc = 0, or_argc = 0; + int r = 0, i, and_argc = 0, or_argc = 0, and_argc_offset = 0; int32_t sleep_ms = 1000, try = 0, retries = 1, retry_timelimit_sec = 0; int32_t min_retry_period_ms = sleep_ms; switch_codec_t write_codec = { 0 }; @@ -2613,6 +2614,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess last_retry_start = switch_micro_time_now(); } + add_endpoints: p = pipe_names[r]; while (p && *p) { @@ -2646,20 +2648,20 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess p++; } - and_argc = switch_separate_string(pipe_names[r], ',', peer_names, (sizeof(peer_names) / sizeof(peer_names[0]))); + and_argc += switch_separate_string(pipe_names[r], ',', peer_names, (sizeof(peer_names) / sizeof(peer_names[0]))); if ((flags & SOF_NOBLOCK) && and_argc > 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Only calling the first element in the list in this mode.\n"); and_argc = 1; } - for (i = 0; i < and_argc; i++) { + for (i = and_argc_offset; i < and_argc; i++) { const char *current_variable; switch_event_t *local_var_event = NULL, *originate_var_event = NULL; end = NULL; - chan_type = peer_names[i]; + chan_type = peer_names[i-and_argc_offset]; /* strip leading spaces */ @@ -3055,7 +3057,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess for (;;) { uint32_t valid_channels = 0; - for (i = 0; i < and_argc; i++) { + for (i = and_argc_offset; i < and_argc; i++) { int state; time_t elapsed; @@ -3135,6 +3137,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess if (caller_channel) { soft_holding = switch_channel_get_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE); + switch_channel_set_flag(caller_channel, CF_ADD_ENDPOINTS); } while ((!caller_channel || switch_channel_ready(caller_channel) || switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) && @@ -3279,6 +3282,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess break; case SWITCH_STATUS_BREAK: status = SWITCH_STATUS_FALSE; + switch_channel_clear_flag(caller_channel, CF_ADD_ENDPOINTS); + switch_channel_set_variable(caller_channel, "originate_add_endpoints", NULL); goto done; break; default: @@ -3382,6 +3387,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess do_continue: + if(caller_channel) { + newep = switch_channel_get_variable(caller_channel, "originate_add_endpoints"); + if (newep) { + switch_channel_set_variable(caller_channel, "originate_add_endpoints", NULL); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Add new originate endpoint(s): %s\n", newep); + and_argc_offset = and_argc; + pipe_names[r] = strdup(newep); + goto add_endpoints; + } + } + if (!read_packet) { switch_yield(20000); } @@ -3390,6 +3406,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess notready: if (caller_channel) { + + switch_channel_clear_flag(caller_channel, CF_ADD_ENDPOINTS); + newep = switch_channel_get_variable(caller_channel, "originate_add_endpoints"); + if (newep) { + switch_channel_set_variable(caller_channel, "originate_add_endpoints", NULL); + + /* Only add new endpoints at this stage, if it's not originator cancel and if no outbound leg was aswered */ + if(oglobals.idx != IDX_CANCEL && oglobals.hups == and_argc) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Add new originate endpoints: %s\n", newep); + and_argc_offset = and_argc; + pipe_names[r] = strdup(newep); + goto add_endpoints; + } + } + holding = switch_channel_get_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE); switch_channel_set_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE, NULL);