Commit fbac12b451 for freeswitch.com

commit fbac12b451a146fdac5104d25d337145be989e84
Author: Dmitry Verenitsin <morbit85@gmail.com>
Date:   Sat Aug 8 20:25:29 2026 +0500

    Merge commit from fork

    The nightmare-transfer path built its `switch_ivr_originate()` dial string by
    interpolating the raw `Refer-To` URI params/headers into a
    `{sip_invite_params=...}` brace block with `switch_core_sprintf()`.
    `switch_ivr_originate()` splits a brace block on commas into separate channel
    variables, so a comma in the remote-supplied URI params/headers was treated as a
    variable separator and could set additional channel variables on the originated
    leg.

    Set `sip_invite_params` on the originate `ovars` event
    (`nightmare_xfer_helper->vars`) instead. Values in that event are applied to the
    peer channel verbatim and are never parsed for separators, so a comma stays
    inside the single variable value. The composed value is unchanged
    (`url_params?url_headers` when headers are present, `url_params` otherwise) and
    `sofia_glue` reads `sip_invite_params` on the outbound leg as before, so a
    well-formed REFER yields an identical outbound INVITE.

    Drop the now-redundant `exten_with_params` helper field;
    `nightmare_xfer_thread_run()` and the log use the plain
    `nightmare_xfer_helper->exten` dial target directly.

diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 8d82e9d3fd..0451a4bdea 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -8779,7 +8779,6 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,

 typedef struct {
 	char *exten;
-	char *exten_with_params;
 	char *event;
 	char *reply_uuid;
 	char *bridge_to_uuid;
@@ -8806,7 +8805,7 @@ void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void
 			switch_channel_t *channel_a = switch_core_session_get_channel(session);
 			const char *session_id_header = sofia_glue_session_id_header(session, nhelper->profile);

-			if ((status = switch_ivr_originate(NULL, &tsession, &cause, nhelper->exten_with_params, timeout, NULL, NULL, NULL,
+			if ((status = switch_ivr_originate(NULL, &tsession, &cause, nhelper->exten, timeout, NULL, NULL, NULL,
 											   switch_channel_get_caller_profile(channel_a), nhelper->vars, SOF_NONE, NULL, NULL)) == SWITCH_STATUS_SUCCESS) {
 				if (switch_channel_up(channel_a)) {

@@ -9512,22 +9511,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
 						nightmare_xfer_helper = switch_core_alloc(npool, sizeof(*nightmare_xfer_helper));
 						nightmare_xfer_helper->exten = switch_core_strdup(npool, exten);

-						if (refer_to->r_url->url_params || refer_to->r_url->url_headers) {
-							if (refer_to->r_url->url_headers) {
-								nightmare_xfer_helper->exten_with_params = switch_core_sprintf(npool,
-																							   "{sip_invite_params=%s?%s}%s",
-																							   refer_to->r_url->url_params ? refer_to->r_url->
-																							   url_params : "", refer_to->r_url->url_headers, exten);
-							} else {
-								nightmare_xfer_helper->exten_with_params = switch_core_sprintf(npool,
-																							   "{sip_invite_params=%s}%s", refer_to->r_url->url_params,
-																							   exten);
-							}
-						} else {
-							nightmare_xfer_helper->exten_with_params = nightmare_xfer_helper->exten;
-						}
-
-						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Nightmare transfer to '%s'\n", nightmare_xfer_helper->exten_with_params);
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Nightmare transfer to '%s'\n", nightmare_xfer_helper->exten);

 						nightmare_xfer_helper->event = switch_core_strdup(npool, etmp);
 						nightmare_xfer_helper->reply_uuid = switch_core_strdup(npool, switch_core_session_get_uuid(session));
@@ -9564,6 +9548,22 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t

 						switch_event_create(&nightmare_xfer_helper->vars, SWITCH_EVENT_CHANNEL_DATA);

+						/* Pass the remote-supplied Refer-To params/headers as a verbatim ovars
+						   value so they are not parsed. */
+						if (refer_to->r_url->url_params || refer_to->r_url->url_headers) {
+							const char *invite_params;
+
+							if (refer_to->r_url->url_headers) {
+								invite_params = switch_core_sprintf(npool, "%s?%s",
+																	refer_to->r_url->url_params ? refer_to->r_url->url_params : "",
+																	refer_to->r_url->url_headers);
+							} else {
+								invite_params = refer_to->r_url->url_params;
+							}
+
+							switch_event_add_header_string(nightmare_xfer_helper->vars, SWITCH_STACK_BOTTOM, "sip_invite_params", invite_params);
+						}
+
 						rep_h = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
 						if (rep_h) {
 							switch_event_add_header_string(nightmare_xfer_helper->vars, SWITCH_STACK_BOTTOM, SOFIA_REPLACES_HEADER, rep_h);