From: Sipwise Development Team <support@sipwise.com>
Date: Thu, 26 Mar 2020 10:06:46 +0100
Subject: sca-line-seize

---
 src/modules/sca/sca.c            | 107 +++++++++++++++++++++-
 src/modules/sca/sca.h            |   6 ++
 src/modules/sca/sca_appearance.h |   2 +-
 src/modules/sca/sca_call_info.c  | 188 ++++++++++++++++++++++-----------------
 src/modules/sca/sca_call_info.h  |   6 +-
 src/modules/sca/sca_dialog.h     |   2 +-
 src/modules/sca/sca_subscribe.c  |  96 ++++++++++++--------
 src/modules/sca/sca_subscribe.h  |   6 +-
 src/modules/sca/sca_util.c       | 180 +++++++++++++++++++++++--------------
 src/modules/sca/sca_util.h       |  18 +++-
 10 files changed, 410 insertions(+), 201 deletions(-)

diff --git a/src/modules/sca/sca.c b/src/modules/sca/sca.c
index 07dac39..c2347bb 100644
--- a/src/modules/sca/sca.c
+++ b/src/modules/sca/sca.c
@@ -64,6 +64,12 @@ db_func_t dbf;		 // db api
 struct tm_binds tmb; // tm functions for sending messages
 sl_api_t slb;		 // sl callback, function for getting to-tag
 
+/* avps */
+unsigned short from_uri_avp_type;
+int_str from_uri_avp;
+unsigned short to_uri_avp_type;
+int_str to_uri_avp;
+
 /*
  * PROTOTYPES
  */
@@ -71,6 +77,11 @@ static int sca_mod_init(void);
 static int sca_child_init(int);
 static void sca_mod_destroy(void);
 static int sca_set_config(sca_mod *);
+static int sca_handle_subscribe_0_f(sip_msg_t *msg);
+static int sca_handle_subscribe_1_f(sip_msg_t *msg, char *);
+static int sca_handle_subscribe_2_f(sip_msg_t *msg, char *, char *);
+int fixup_hs(void **, int);
+int fixup_free_hs(void **param, int param_no);
 static int sca_call_info_update_0_f(sip_msg_t *msg, char *, char *);
 static int sca_call_info_update_1_f(sip_msg_t *msg, char *, char *);
 static int sca_call_info_update_2_f(sip_msg_t *msg, char *, char *);
@@ -82,8 +93,12 @@ int fixup_free_ciu(void **param, int param_no);
  * EXPORTED COMMANDS
  */
 static cmd_export_t cmds[] = {
-		{"sca_handle_subscribe", (cmd_function)sca_handle_subscribe, 0, NULL, 0,
-				REQUEST_ROUTE},
+		{"sca_handle_subscribe", (cmd_function)sca_handle_subscribe_0_f, 0,
+				NULL, NULL, REQUEST_ROUTE},
+		{"sca_handle_subscribe", (cmd_function)sca_handle_subscribe_1_f, 1,
+				fixup_hs, fixup_free_hs, REQUEST_ROUTE},
+		{"sca_handle_subscribe", (cmd_function)sca_handle_subscribe_2_f, 2,
+				fixup_hs, fixup_free_hs, REQUEST_ROUTE},
 		{"sca_call_info_update", (cmd_function)sca_call_info_update_0_f, 0,
 				NULL, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
 		{"sca_call_info_update", (cmd_function)sca_call_info_update_1_f, 1,
@@ -141,6 +156,8 @@ int line_seize_max_expires = 15;
 int purge_expired_interval = 120;
 int onhold_bflag = -1;
 str server_address = STR_NULL;
+str from_uri_avp_param = STR_NULL;
+str to_uri_avp_param = STR_NULL;
 
 static param_export_t params[] = {
 		{"outbound_proxy", PARAM_STR, &outbound_proxy},
@@ -154,6 +171,8 @@ static param_export_t params[] = {
 		{"purge_expired_interval", INT_PARAM, &purge_expired_interval},
 		{"onhold_bflag", INT_PARAM, &onhold_bflag},
 		{"server_address", PARAM_STR, &server_address},
+		{"from_uri_avp", PARAM_STR, &from_uri_avp_param},
+		{"to_uri_avp", PARAM_STR, &to_uri_avp_param},
 		{NULL, 0, NULL},
 };
 
@@ -329,6 +348,32 @@ static int sca_child_init(int rank)
 	return (0);
 }
 
+static int sca_process_avps(
+		str *avp_param, int_str *avp, unsigned short *avp_type)
+{
+	pv_spec_t *avp_spec;
+	unsigned short avp_flags;
+
+	if(avp_param && avp_param->len > 0) {
+		avp_spec = pv_cache_get(avp_param);
+		if(avp_spec == NULL || avp_spec->type != PVT_AVP) {
+			LM_ERR("malformed or non AVP definition <%.*s>\n",
+					STR_FMT(avp_param));
+			return -1;
+		}
+
+		if(pv_get_avp_name(0, &(avp_spec->pvp), avp, &avp_flags) != 0) {
+			LM_ERR("invalid AVP definition <%.*s>\n", STR_FMT(avp_param));
+			return -1;
+		}
+		*avp_type = avp_flags;
+	} else {
+		avp->s.s = NULL;
+		avp->s.len = 0;
+	}
+	return 0;
+}
+
 static int sca_mod_init(void)
 {
 	sca = (sca_mod *)shm_malloc(sizeof(sca_mod));
@@ -389,6 +434,14 @@ static int sca_mod_init(void)
 	// timer process forks in sca_child_init, above.
 	register_dummy_timers(1);
 
+	if(sca_process_avps(&from_uri_avp_param, &from_uri_avp, &from_uri_avp_type)
+					< 0
+			|| sca_process_avps(
+					   &to_uri_avp_param, &to_uri_avp, &to_uri_avp_type)
+					   < 0) {
+		goto error;
+	}
+
 	LM_INFO("SCA initialized \n");
 
 	return (0);
@@ -428,6 +481,56 @@ void sca_mod_destroy(void)
 	sca_db_disconnect();
 }
 
+static int sca_handle_subscribe_0_f(sip_msg_t *msg)
+{
+	return sca_handle_subscribe(msg, NULL, NULL);
+}
+static int sca_handle_subscribe_1_f(sip_msg_t *msg, char *p1)
+{
+	str uri_to = STR_NULL;
+	if(get_str_fparam(&uri_to, msg, (gparam_p)p1) != 0) {
+		LM_ERR("unable to get value from param pvar_to\n");
+		return -1;
+	}
+	return sca_handle_subscribe(msg, &uri_to, NULL);
+}
+static int sca_handle_subscribe_2_f(sip_msg_t *msg, char *p1, char *p2)
+{
+	str uri_to = STR_NULL;
+	str uri_from = STR_NULL;
+	if(get_str_fparam(&uri_to, msg, (gparam_p)p1) != 0) {
+		LM_ERR("unable to get value from param pvar_to\n");
+		return -1;
+	}
+	if(get_str_fparam(&uri_from, msg, (gparam_p)p2) != 0) {
+		LM_ERR("unable to get value from param pvar_from\n");
+		return -1;
+	}
+	return sca_handle_subscribe(msg, &uri_to, &uri_from);
+}
+
+int fixup_hs(void **param, int param_no)
+{
+	switch(param_no) {
+		case 1:
+		case 2:
+			return fixup_spve_null(param, 1);
+		default:
+			return E_UNSPEC;
+	}
+}
+
+int fixup_free_hs(void **param, int param_no)
+{
+	switch(param_no) {
+		case 1:
+		case 2:
+			return fixup_free_spve_null(param, 1);
+		default:
+			return E_UNSPEC;
+	}
+}
+
 static int sca_call_info_update_0_f(sip_msg_t *msg, char *p1, char *p2)
 {
 	return sca_call_info_update(msg, SCA_CALL_INFO_SHARED_BOTH, NULL, NULL);
diff --git a/src/modules/sca/sca.h b/src/modules/sca/sca.h
index cceae17..7a80847 100644
--- a/src/modules/sca/sca.h
+++ b/src/modules/sca/sca.h
@@ -57,4 +57,10 @@ typedef struct _sca_mod sca_mod;
 
 extern sca_mod *sca;
 
+/* avps */
+extern unsigned short from_uri_avp_type;
+extern int_str from_uri_avp;
+extern unsigned short to_uri_avp_type;
+extern int_str to_uri_avp;
+
 #endif // SCA_H
diff --git a/src/modules/sca/sca_appearance.h b/src/modules/sca/sca_appearance.h
index bd94e14..6ce3112 100644
--- a/src/modules/sca/sca_appearance.h
+++ b/src/modules/sca/sca_appearance.h
@@ -40,7 +40,7 @@ enum
 #define sca_appearance_is_held(app1)                       \
 	((app1)                                                \
 			&& ((app1)->state == SCA_APPEARANCE_STATE_HELD \
-					|| (app1)->state == SCA_APPEARANCE_STATE_HELD_PRIVATE))
+					   || (app1)->state == SCA_APPEARANCE_STATE_HELD_PRIVATE))
 
 enum
 {
diff --git a/src/modules/sca/sca_call_info.c b/src/modules/sca/sca_call_info.c
index c443f23..0617cea 100644
--- a/src/modules/sca/sca_call_info.c
+++ b/src/modules/sca/sca_call_info.c
@@ -842,44 +842,46 @@ static int sca_call_info_is_line_seize_reinvite(sip_msg_t *msg,
  */
 static void sca_call_info_local_error_reply_handler(sip_msg_t *msg, int status)
 {
-	struct to_body *from;
-	struct to_body *to;
+	sca_to_body_t from, to;
 	sca_appearance *app;
 	str aor = STR_NULL;
 	str contact_uri = STR_NULL;
 	int rc;
 
+	memset(&from, 0, sizeof(from));
+	memset(&to, 0, sizeof(to));
+
 	if(sca_get_msg_from_header(msg, &from) < 0) {
 		LM_ERR("sca_call_info_sl_reply_cb: failed to get From header from "
 			   "request before stateless reply with %d\n",
 				status);
-		return;
+		goto done;
 	}
-	if(sca_uri_extract_aor(&from->uri, &aor) < 0) {
+	if(sca_uri_extract_aor(&from.hdr->uri, &aor) < 0) {
 		LM_ERR("sca_call_info_sl_reply_cb: failed to extract AoR "
 			   "from URI %.*s\n",
-				STR_FMT(&from->uri));
-		return;
+				STR_FMT(&from.hdr->uri));
+		goto done;
 	}
 
 	if(!sca_uri_is_shared_appearance(sca, &aor)) {
 		// LM_DBG("sca_call_info_sl_reply_cb: ignoring non-shared appearance "
 		//		"%.*s\n", STR_FMT(&aor));
-		return;
+		goto done;
 	}
 
 	if(sca_get_msg_contact_uri(msg, &contact_uri) < 0) {
 		LM_ERR("sca_call_info_sl_reply_cb: failed to get Contact from "
 			   "request before stateless reply with %d\n",
 				status);
-		return;
+		goto done;
 	}
 
 	if(sca_get_msg_to_header(msg, &to) < 0) {
 		LM_ERR("sca_call_info_sl_reply_cb: failed to get To header from "
 			   "request before stateless reply with %d\n",
 				status);
-		return;
+		goto done;
 	}
 
 	// two typical cases to handle. in the first case, we haven't dropped
@@ -901,7 +903,7 @@ static void sca_call_info_local_error_reply_handler(sip_msg_t *msg, int status)
 	} else if(rc == 0) {
 		// no line-seize subscription found
 		app = sca_appearance_unlink_by_tags(sca, &aor, &msg->callid->body,
-				&from->tag_value, &to->tag_value);
+				&from.hdr->tag_value, &to.hdr->tag_value);
 		if(app) {
 			sca_appearance_free(app);
 			if(sca_notify_call_info_subscribers(sca, &aor) < 0) {
@@ -911,6 +913,14 @@ static void sca_call_info_local_error_reply_handler(sip_msg_t *msg, int status)
 			}
 		}
 	}
+
+done:
+	if(from.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(from.hdr);
+	}
+	if(to.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(to.hdr);
+	}
 }
 
 void sca_call_info_response_ready_cb(
@@ -1351,28 +1361,30 @@ static int sca_call_info_invite_reply_error_handler(sip_msg_t *msg,
 void sca_call_info_ack_from_handler(sip_msg_t *msg, str *from_aor, str *to_aor)
 {
 	sca_appearance *app;
-	struct to_body *from;
-	struct to_body *to;
+	sca_to_body_t from, to;
 	int slot_idx = -1;
 	int state = SCA_APPEARANCE_STATE_IDLE;
 
+	memset(&from, 0, sizeof(from));
+	memset(&to, 0, sizeof(to));
+
 	if(sca_get_msg_from_header(msg, &from) < 0) {
 		LM_ERR("sca_call_info_ack_cb: failed to get From-header\n");
-		return;
+		goto done;
 	}
 	if(sca_get_msg_to_header(msg, &to) < 0) {
 		LM_ERR("sca_call_info_ack_cb: failed to get To-header\n");
-		return;
+		goto done;
 	}
 
 	if(sca_uri_lock_if_shared_appearance(sca, from_aor, &slot_idx)) {
 		app = sca_appearance_for_tags_unsafe(sca, from_aor, &msg->callid->body,
-				&from->tag_value, NULL, slot_idx);
+				&from.hdr->tag_value, NULL, slot_idx);
 		if(app == NULL) {
 			LM_ERR("sca_call_info_ack_cb: No appearance for %.*s matching "
 				   "call-id <%.*s> and from-tag <%.*s>\n",
 					STR_FMT(from_aor), STR_FMT(&msg->callid->body),
-					STR_FMT(&from->tag_value));
+					STR_FMT(&from.hdr->tag_value));
 			goto done;
 		}
 
@@ -1406,17 +1418,25 @@ done:
 			}
 		}
 	}
+	if(from.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(from.hdr);
+	}
+	if(to.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(to.hdr);
+	}
 }
 
 /* XXX needs extract routines */
 void sca_call_info_ack_cb(struct cell *t, int type, struct tmcb_params *params)
 {
-	struct to_body *to;
+	sca_to_body_t to;
 	sca_appearance *app = NULL;
 	str from_aor = STR_NULL;
 	str to_aor = STR_NULL;
 	int slot_idx = -1;
 
+	memset(&to, 0, sizeof(to));
+
 	if(!(type & TMCB_E2EACK_IN)) {
 		return;
 	}
@@ -1429,9 +1449,9 @@ void sca_call_info_ack_cb(struct cell *t, int type, struct tmcb_params *params)
 		LM_ERR("sca_call_info_ack_cb: failed to get To-header\n");
 		goto done;
 	}
-	if(sca_uri_extract_aor(&to->uri, &to_aor) < 0) {
+	if(sca_uri_extract_aor(&to.hdr->uri, &to_aor) < 0) {
 		LM_ERR("sca_call_info_ack_cb: failed to extract To AoR from %.*s\n",
-				STR_FMT(&to->uri));
+				STR_FMT(&to.hdr->uri));
 		goto done;
 	}
 
@@ -1445,7 +1465,7 @@ void sca_call_info_ack_cb(struct cell *t, int type, struct tmcb_params *params)
 
 	// on ACK, ensure SCA callee state is promoted to ACTIVE.
 	app = sca_appearance_for_tags_unsafe(sca, &to_aor,
-			&params->req->callid->body, &to->tag_value, NULL, slot_idx);
+			&params->req->callid->body, &to.hdr->tag_value, NULL, slot_idx);
 	if(app && app->state == SCA_APPEARANCE_STATE_ACTIVE_PENDING) {
 		LM_DBG("promoting %.*s appearance-index %d to active\n",
 				STR_FMT(&to_aor), app->index);
@@ -1467,6 +1487,9 @@ done:
 	if(from_aor.s != NULL) {
 		pkg_free(from_aor.s);
 	}
+	if(to.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(to.hdr);
+	}
 }
 
 static int sca_call_info_invite_handler(sip_msg_t *msg,
@@ -1736,11 +1759,13 @@ void sca_call_info_sl_reply_cb(void *cb_arg)
 {
 	sl_cbp_t *slcbp = (sl_cbp_t *)cb_arg;
 	sip_msg_t *msg;
-	struct to_body *from;
-	struct to_body *to;
+	sca_to_body_t from, to;
 	str aor = STR_NULL;
 	str contact_uri = STR_NULL;
 
+	memset(&from, 0, sizeof(from));
+	memset(&to, 0, sizeof(to));
+
 	if(slcbp == NULL) {
 		return;
 	}
@@ -1768,31 +1793,31 @@ void sca_call_info_sl_reply_cb(void *cb_arg)
 				slcbp->code, STR_FMT(slcbp->reason));
 		return;
 	}
-	if(sca_uri_extract_aor(&from->uri, &aor) < 0) {
+	if(sca_uri_extract_aor(&from.hdr->uri, &aor) < 0) {
 		LM_ERR("sca_call_info_sl_reply_cb: failed to extract AoR "
 			   "from URI %.*s\n",
-				STR_FMT(&from->uri));
-		return;
+				STR_FMT(&from.hdr->uri));
+		goto done;
 	}
 
 	if(!sca_uri_is_shared_appearance(sca, &aor)) {
 		// LM_DBG("sca_call_info_sl_reply_cb: ignoring non-shared appearance "
 		//		"%.*s", STR_FMT(&aor));
-		return;
+		goto done;
 	}
 
 	if(sca_get_msg_contact_uri(msg, &contact_uri) < 0) {
 		LM_ERR("sca_call_info_sl_reply_cb: failed to get Contact from "
 			   "request before stateless reply with %d %.*s\n",
 				slcbp->code, STR_FMT(slcbp->reason));
-		return;
+		goto done;
 	}
 
 	if(sca_get_msg_to_header(msg, &to) < 0) {
 		LM_ERR("sca_call_info_sl_reply_cb: failed to get To header from "
 			   "request before stateless reply with %d %.*s\n",
 				slcbp->code, STR_FMT(slcbp->reason));
-		return;
+		goto done;
 	}
 
 	if(sca_subscription_terminate(sca, &aor, SCA_EVENT_TYPE_LINE_SEIZE,
@@ -1802,7 +1827,15 @@ void sca_call_info_sl_reply_cb(void *cb_arg)
 		LM_ERR("sca_call_info_sl_reply_cb: failed to terminate "
 			   "line-seize subscription for %.*s\n",
 				STR_FMT(&contact_uri));
-		return;
+		goto done;
+	}
+
+done:
+	if(from.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(from.hdr);
+	}
+	if(to.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(to.hdr);
 	}
 }
 
@@ -1844,20 +1877,21 @@ int sca_call_info_update(
 {
 	sca_call_info call_info;
 	hdr_field_t *call_info_hdr;
-	struct to_body *from;
-	struct to_body *to;
+	sca_to_body_t from, to;
 	sip_uri_t c_uri;
 	str from_aor = STR_NULL;
 	str to_aor = STR_NULL;
 	str contact_uri = STR_NULL;
 	int aor_flags = SCA_CALL_INFO_UPDATE_FLAG_DEFAULT;
-	int to_body_flags = SCA_CALL_INFO_UPDATE_FLAG_DEFAULT;
 	int n_dispatch;
 	int i;
 	int method;
 	int rc = -1;
+	int_str val;
 
 	method = sca_get_msg_method(msg);
+	memset(&from, 0, sizeof(from));
+	memset(&to, 0, sizeof(to));
 
 	n_dispatch = sizeof(call_info_dispatch) / sizeof(call_info_dispatch[0]);
 	for(i = 0; i < n_dispatch; i++) {
@@ -1868,7 +1902,7 @@ int sca_call_info_update(
 	if(i >= n_dispatch) {
 		if(msg->cseq == NULL
 				&& ((parse_headers(msg, HDR_CSEQ_F, 0) == -1)
-						|| (msg->cseq == NULL))) {
+						   || (msg->cseq == NULL))) {
 			LM_ERR("no CSEQ header\n");
 			return (1);
 		}
@@ -1900,6 +1934,9 @@ int sca_call_info_update(
 		}
 	}
 
+	delete_avp(from_uri_avp_type | AVP_VAL_STR, from_uri_avp);
+	delete_avp(to_uri_avp_type | AVP_VAL_STR, to_uri_avp);
+
 	memset(&call_info, 0, sizeof(sca_call_info));
 	call_info_hdr = get_hdr(msg, HDR_CALLINFO_T);
 	if(!SCA_HEADER_EMPTY(call_info_hdr)) {
@@ -1912,34 +1949,22 @@ int sca_call_info_update(
 	}
 
 	if(uri_from != NULL) {
-		if(sca_build_to_body_from_uri(msg, &from, uri_from) < 0) {
-			LM_ERR("Bad From uri from param\n");
-			return (-1);
-		}
+		val.s.s = uri_from->s;
+		val.s.len = uri_from->len;
+		add_avp(from_uri_avp_type | AVP_VAL_STR, from_uri_avp, val);
 		LM_DBG("from[%.*s] param\n", STR_FMT(uri_from));
-		to_body_flags |= SCA_CALL_INFO_UPDATE_FLAG_FROM_ALLOC;
-		if(sca_uri_extract_aor(&from->uri, &from_aor) < 0) {
-			LM_ERR("Failed to extract AoR from From URI %.*s\n",
-					STR_FMT(&from->uri));
-			goto done;
-		}
-	} else if(sca_get_msg_from_header(msg, &from) < 0) {
-		LM_ERR("Bad From header\n");
+	}
+	if(sca_get_msg_from_header(msg, &from) < 0) {
+		LM_ERR("Bad From header");
 		return (-1);
 	}
 	if(uri_to != NULL) {
-		if(sca_build_to_body_from_uri(msg, &to, uri_to) < 0) {
-			LM_ERR("Bad From uri to param\n");
-			goto done;
-		}
+		val.s.s = uri_to->s;
+		val.s.len = uri_to->len;
+		add_avp(to_uri_avp_type | AVP_VAL_STR, to_uri_avp, val);
 		LM_DBG("to[%.*s] param\n", STR_FMT(uri_to));
-		to_body_flags |= SCA_CALL_INFO_UPDATE_FLAG_TO_ALLOC;
-		if(sca_uri_extract_aor(&to->uri, &to_aor) < 0) {
-			LM_ERR("Failed to extract AoR from To URI %.*s\n",
-					STR_FMT(&to->uri));
-			goto done;
-		}
-	} else if(sca_get_msg_to_header(msg, &to) < 0) {
+	}
+	if(sca_get_msg_to_header(msg, &to) < 0) {
 		LM_ERR("Bad To header\n");
 		goto done;
 	}
@@ -1967,27 +1992,35 @@ int sca_call_info_update(
 				goto done;
 			}
 			aor_flags |= SCA_CALL_INFO_UPDATE_FLAG_FROM_ALLOC;
-		}
-		if(uri_to == NULL) {
-			if(sca_uri_extract_aor(&to->uri, &to_aor) < 0) {
-				LM_ERR("Failed to extract AoR from To URI %.*s\n",
-						STR_FMT(&to->uri));
+		} else {
+			if(sca_uri_extract_aor(&from.hdr->uri, &from_aor) < 0) {
+				LM_ERR("Failed to extract AoR from From URI %.*s\n",
+						STR_FMT(&from.hdr->uri));
 				goto done;
 			}
 		}
+		if(sca_uri_extract_aor(&to.hdr->uri, &to_aor) < 0) {
+			LM_ERR("Failed to extract AoR from To URI %.*s",
+					STR_FMT(&to.hdr->uri));
+			goto done;
+		}
 	} else {
-		if(uri_from == NULL) {
-			if(sca_uri_extract_aor(&from->uri, &from_aor) < 0) {
-				LM_ERR("Failed to extract AoR from From URI %.*s\n",
-						STR_FMT(&from->uri));
-				goto done;
-			}
+		if(sca_uri_extract_aor(&from.hdr->uri, &from_aor) < 0) {
+			LM_ERR("Failed to extract AoR from From URI %.*s",
+					STR_FMT(&from.hdr->uri));
+			goto done;
 		}
 		if(uri_to == NULL) {
 			if(sca_create_canonical_aor(msg, &to_aor) < 0) {
 				goto done;
 			}
 			aor_flags |= SCA_CALL_INFO_UPDATE_FLAG_TO_ALLOC;
+		} else {
+			if(sca_uri_extract_aor(&to.hdr->uri, &to_aor) < 0) {
+				LM_ERR("Failed to extract AoR from To URI %.*s",
+						STR_FMT(&to.hdr->uri));
+				goto done;
+			}
 		}
 	}
 
@@ -2037,11 +2070,11 @@ int sca_call_info_update(
 
 	LM_DBG("Calling Dispatch Id: %d handler with From-AOR: %.*s To-AOR: %.*s "
 		   "From-URI: <%.*s> To-URI: <%.*s> Contact-URI: <%.*s>\n",
-			i, STR_FMT(&from_aor), STR_FMT(&to_aor), STR_FMT(&from->uri),
-			STR_FMT(&to->uri), STR_FMT(&contact_uri));
+			i, STR_FMT(&from_aor), STR_FMT(&to_aor), STR_FMT(&from.hdr->uri),
+			STR_FMT(&to.hdr->uri), STR_FMT(&contact_uri));
 
-	rc = call_info_dispatch[i].handler(
-			msg, &call_info, from, to, &from_aor, &to_aor, &contact_uri);
+	rc = call_info_dispatch[i].handler(msg, &call_info, from.hdr, to.hdr,
+			&from_aor, &to_aor, &contact_uri);
 	if(rc < 0) {
 		LM_ERR("Failed to update Call-Info state for %.*s\n",
 				STR_FMT(&contact_uri));
@@ -2058,16 +2091,11 @@ done:
 			pkg_free(to_aor.s);
 		}
 	}
-	if((to_body_flags & SCA_CALL_INFO_UPDATE_FLAG_FROM_ALLOC)) {
-		if(from != NULL) {
-			free_to(from);
-		}
+	if(from.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(from.hdr);
 	}
-	if((to_body_flags & SCA_CALL_INFO_UPDATE_FLAG_TO_ALLOC)) {
-		if(to != NULL) {
-			free_to(to);
-		}
+	if(to.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(to.hdr);
 	}
-
 	return (rc);
 }
diff --git a/src/modules/sca/sca_call_info.h b/src/modules/sca/sca_call_info.h
index 914f36f..0f2d53c 100644
--- a/src/modules/sca/sca_call_info.h
+++ b/src/modules/sca/sca_call_info.h
@@ -49,17 +49,17 @@ typedef struct _sca_call_info sca_call_info;
 #define SCA_CALL_INFO_EMPTY(ci1)                                   \
 	((void *)(ci1) == NULL                                         \
 			|| ((ci1)->index == SCA_CALL_INFO_APPEARANCE_INDEX_ANY \
-					&& (ci1)->state == SCA_APPEARANCE_STATE_UNKNOWN))
+					   && (ci1)->state == SCA_APPEARANCE_STATE_UNKNOWN))
 
 #define SCA_CALL_INFO_IS_SHARED_CALLER(ci1)         \
 	(!SCA_CALL_INFO_EMPTY((ci1))                    \
 			&& (((sca_call_info *)(ci1))->ua_shared \
-					& SCA_CALL_INFO_SHARED_CALLER))
+					   & SCA_CALL_INFO_SHARED_CALLER))
 
 #define SCA_CALL_INFO_IS_SHARED_CALLEE(ci1)         \
 	(!SCA_CALL_INFO_EMPTY((ci1))                    \
 			&& (((sca_call_info *)(ci1))->ua_shared \
-					& SCA_CALL_INFO_SHARED_CALLEE))
+					   & SCA_CALL_INFO_SHARED_CALLEE))
 
 extern const str SCA_CALL_INFO_HEADER_STR;
 
diff --git a/src/modules/sca/sca_dialog.h b/src/modules/sca/sca_dialog.h
index d308954..dee234c 100644
--- a/src/modules/sca/sca_dialog.h
+++ b/src/modules/sca/sca_dialog.h
@@ -35,7 +35,7 @@ typedef struct _sca_dialog sca_dialog;
 #define SCA_DIALOG_EMPTY(d)                                                   \
 	((d) == NULL                                                              \
 			|| (SCA_STR_EMPTY(&(d)->call_id) && SCA_STR_EMPTY(&(d)->from_tag) \
-					&& SCA_STR_EMPTY(&(d)->to_tag)))
+					   && SCA_STR_EMPTY(&(d)->to_tag)))
 
 int sca_dialog_build_from_tags(sca_dialog *, int, str *, str *, str *);
 int sca_dialog_create_replaces_header(sca_dialog *, str *);
diff --git a/src/modules/sca/sca_subscribe.c b/src/modules/sca/sca_subscribe.c
index dc33f00..14c6062 100644
--- a/src/modules/sca/sca_subscribe.c
+++ b/src/modules/sca/sca_subscribe.c
@@ -844,8 +844,8 @@ static int sca_subscription_update_unsafe(sca_mod *scam,
 		// this is allocated separately from the rest of the subscription
 		len = sizeof(char *)
 			  * (update_sub->dialog.call_id.len
-					  + update_sub->dialog.from_tag.len
-					  + update_sub->dialog.to_tag.len);
+						+ update_sub->dialog.from_tag.len
+						+ update_sub->dialog.to_tag.len);
 
 		dlg_id_tmp = (char *)shm_malloc(len);
 		if(dlg_id_tmp == NULL) {
@@ -986,17 +986,19 @@ int sca_subscription_delete_subscriber_for_event(
 int sca_subscription_from_request(sca_mod *scam, sip_msg_t *msg, int event_type,
 		sca_subscription *req_sub)
 {
-	struct to_body tmp_to = {0};
-	struct to_body *to, *from;
+	sca_to_body_t to, from;
 	str contact_uri;
 	str to_tag = STR_NULL;
 	unsigned int expires = 0, max_expires;
 	unsigned int cseq;
 	str *ruri = NULL;
+	int rc = 1;
 
 	assert(req_sub != NULL);
 
 	memset(req_sub, 0, sizeof(sca_subscription));
+	memset(&from, 0, sizeof(from));
+	memset(&to, 0, sizeof(to));
 
 	// parse required info first
 	if(!SCA_HEADER_EMPTY(msg->expires)) {
@@ -1023,10 +1025,6 @@ int sca_subscription_from_request(sca_mod *scam, sip_msg_t *msg, int event_type,
 		expires = max_expires;
 	}
 
-	if(SCA_HEADER_EMPTY(msg->to)) {
-		LM_ERR("Empty To header\n");
-		goto error;
-	}
 	if(SCA_HEADER_EMPTY(msg->callid)) {
 		LM_ERR("Empty Call-ID header\n");
 		goto error;
@@ -1048,30 +1046,18 @@ int sca_subscription_from_request(sca_mod *scam, sip_msg_t *msg, int event_type,
 		goto error;
 	}
 
-	if(SCA_HEADER_EMPTY(msg->from)) {
-		LM_ERR("Empty From header\n");
-		goto error;
-	}
-	if(parse_from_header(msg) < 0) {
+	if(sca_get_msg_from_header(msg, &from) < 0) {
 		LM_ERR("Bad From header\n");
 		goto error;
 	}
-	from = (struct to_body *)msg->from->parsed;
-	if(SCA_STR_EMPTY(&from->tag_value)) {
+	if(SCA_STR_EMPTY(&from.hdr->tag_value)) {
 		LM_ERR("No from-tag in From header\n");
 		goto error;
 	}
 
-	if((to = (struct to_body *)msg->to->parsed) == NULL) {
-		parse_to(msg->to->body.s,
-				msg->to->body.s + msg->to->body.len + 1, // end of buffer
-				&tmp_to);
-
-		if(tmp_to.error != PARSE_OK) {
-			LM_ERR("Bad To header\n");
-			goto error;
-		}
-		to = &tmp_to;
+	if(sca_get_msg_to_header(msg, &to) < 0) {
+		LM_ERR("Bad To header");
+		goto error;
 	}
 
 	if(parse_sip_msg_uri(msg) < 0) {
@@ -1080,7 +1066,7 @@ int sca_subscription_from_request(sca_mod *scam, sip_msg_t *msg, int event_type,
 	}
 	ruri = GET_RURI(msg);
 
-	to_tag = to->tag_value;
+	to_tag = to.hdr->tag_value;
 	if(to_tag.s == NULL) {
 		// XXX need hook to detect when we have a subscription and the
 		// subscriber sends an out-of-dialog SUBSCRIBE, which indicates the
@@ -1106,7 +1092,7 @@ int sca_subscription_from_request(sca_mod *scam, sip_msg_t *msg, int event_type,
 		}
 	} else {
 		/* we are in-dialog */
-		req_sub->target_aor = to->uri;
+		req_sub->target_aor = to.hdr->uri;
 	}
 
 	req_sub->subscriber = contact_uri;
@@ -1124,7 +1110,7 @@ int sca_subscription_from_request(sca_mod *scam, sip_msg_t *msg, int event_type,
 	req_sub->dialog.id.s = NULL;
 	req_sub->dialog.id.len = 0;
 	req_sub->dialog.call_id = msg->callid->body;
-	req_sub->dialog.from_tag = from->tag_value;
+	req_sub->dialog.from_tag = from.hdr->tag_value;
 
 	req_sub->dialog.to_tag.s = pkg_malloc(to_tag.len);
 	if(req_sub->dialog.to_tag.s == NULL) {
@@ -1138,22 +1124,26 @@ int sca_subscription_from_request(sca_mod *scam, sip_msg_t *msg, int event_type,
 	req_sub->dialog.notify_cseq = 0;
 	req_sub->server_id = server_id;
 
-	free_to_params(&tmp_to);
-
-	return (1);
+	goto done;
 
 error:
-	free_to_params(&tmp_to);
-
+	rc = -1;
 	if(!SCA_STR_EMPTY(&req_sub->rr)) {
 		pkg_free(req_sub->rr.s);
 		req_sub->rr.s = NULL;
 	}
+done:
+	if(from.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(from.hdr);
+	}
+	if(to.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(to.hdr);
+	}
 
-	return (-1);
+	return rc;
 }
 
-int ki_sca_handle_subscribe(sip_msg_t *msg)
+int ki_sca_handle_subscribe(sip_msg_t *msg, str *uri_to, str *uri_from)
 {
 	sca_subscription req_sub;
 	sca_subscription *sub = NULL;
@@ -1168,7 +1158,10 @@ int ki_sca_handle_subscribe(sip_msg_t *msg)
 	int idx = -1;
 	int rc = -1;
 	int released = 0;
+	int_str val;
+	sca_to_body_t tmp_to;
 
+	memset(&tmp_to, 0, sizeof(tmp_to));
 	if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
 		LM_ERR("header parsing failed: bad request\n");
 		SCA_SUB_REPLY_ERROR(sca, 400, "Bad Request", msg);
@@ -1192,6 +1185,21 @@ int ki_sca_handle_subscribe(sip_msg_t *msg)
 		return (-1);
 	}
 
+	delete_avp(from_uri_avp_type | AVP_VAL_STR, from_uri_avp);
+	delete_avp(to_uri_avp_type | AVP_VAL_STR, to_uri_avp);
+	if(uri_from != NULL) {
+		val.s.s = uri_from->s;
+		val.s.len = uri_from->len;
+		add_avp(from_uri_avp_type | AVP_VAL_STR, from_uri_avp, val);
+		LM_DBG("from[%.*s] param\n", STR_FMT(uri_from));
+	}
+	if(uri_to != NULL) {
+		val.s.s = uri_to->s;
+		val.s.len = uri_to->len;
+		add_avp(to_uri_avp_type | AVP_VAL_STR, to_uri_avp, val);
+		LM_DBG("to[%.*s] param\n", STR_FMT(uri_to));
+	}
+
 	if(sca_subscription_from_request(sca, msg, event_type, &req_sub) < 0) {
 		SCA_SUB_REPLY_ERROR(
 				sca, 400, "Bad Shared Call Appearance Request", msg);
@@ -1207,7 +1215,15 @@ int ki_sca_handle_subscribe(sip_msg_t *msg)
 	sca_subscription_print(&req_sub);
 
 	// check to see if the message has a to-tag
-	to_tag = &(get_to(msg)->tag_value);
+	if(uri_to != NULL) {
+		if(sca_get_msg_to_header(msg, &tmp_to) < 0) {
+			LM_ERR("Bad To header");
+			return (-1);
+		}
+		to_tag = &(tmp_to.hdr->tag_value);
+	} else {
+		to_tag = &(get_to(msg)->tag_value);
+	}
 
 	// XXX should lock starting here and use unsafe methods below?
 
@@ -1387,13 +1403,15 @@ done:
 	if(req_sub.rr.s != NULL) {
 		pkg_free(req_sub.rr.s);
 	}
-
+	if(tmp_to.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(tmp_to.hdr);
+	}
 	return (rc);
 }
 
-int sca_handle_subscribe(sip_msg_t *msg, char *p1, char *p2)
+int sca_handle_subscribe(sip_msg_t *msg, str *uri_to, str *uri_from)
 {
-	return ki_sca_handle_subscribe(msg);
+	return ki_sca_handle_subscribe(msg, uri_to, uri_from);
 }
 
 int sca_subscription_reply(sca_mod *scam, int status_code, char *status_msg,
diff --git a/src/modules/sca/sca_subscribe.h b/src/modules/sca/sca_subscribe.h
index e27883e..44f93b7 100644
--- a/src/modules/sca/sca_subscribe.h
+++ b/src/modules/sca/sca_subscribe.h
@@ -50,7 +50,7 @@ struct _sca_subscription
 	str rr; // Record-Route header values
 
 	int db_cmd_flag; // track whether to INSERT or UPDATE
-	int server_id;	 // server
+	int server_id;   // server
 };
 typedef struct _sca_subscription sca_subscription;
 
@@ -79,7 +79,7 @@ extern const str SCA_METHOD_SUBSCRIBE;
 	sca_subscription_reply(                           \
 			(mod), (scode), (smsg), SCA_EVENT_TYPE_CALL_INFO, -1, (sreply))
 
-int sca_handle_subscribe(sip_msg_t *, char *, char *);
+int sca_handle_subscribe(sip_msg_t *, str *, str *);
 int sca_subscription_reply(sca_mod *, int, char *, int, int, sip_msg_t *);
 
 int sca_subscription_from_db_result(db1_res_t *, sca_subscription *);
@@ -93,6 +93,6 @@ int sca_subscription_aor_has_subscribers(int, str *);
 int sca_subscription_delete_subscriber_for_event(
 		sca_mod *, str *, str *, str *);
 int sca_subscription_terminate(sca_mod *, str *, int, str *, int, int);
-int ki_sca_handle_subscribe(sip_msg_t *msg);
+int ki_sca_handle_subscribe(sip_msg_t *msg, str *, str *);
 
 #endif // SCA_SUBSCRIBE_H
diff --git a/src/modules/sca/sca_util.c b/src/modules/sca/sca_util.c
index 4ab4c6f..685cf8d 100644
--- a/src/modules/sca/sca_util.c
+++ b/src/modules/sca/sca_util.c
@@ -112,94 +112,134 @@ int sca_get_msg_cseq_method(sip_msg_t *msg)
 	return (get_cseq(msg)->method_id);
 }
 
-int sca_get_msg_from_header(sip_msg_t *msg, struct to_body **from)
+int sca_get_avp_value(unsigned short avp_type, int_str avp, str *result)
 {
-	struct to_body *f;
+	int_str val;
+	struct usr_avp *_avp;
 
-	assert(msg != NULL);
-	assert(from != NULL);
+	assert(result != NULL);
 
-	if(SCA_HEADER_EMPTY(msg->from)) {
-		LM_ERR("Empty From header\n");
-		return (-1);
-	}
-	if(parse_from_header(msg) < 0) {
-		LM_ERR("Bad From header\n");
-		return (-1);
+	if(avp.s.len > 0) {
+		_avp = search_first_avp(avp_type, avp, &val, 0);
+		if(_avp) {
+			result->s = val.s.s;
+			result->len = val.s.len;
+			return 0;
+		}
 	}
-	f = get_from(msg);
-	if(SCA_STR_EMPTY(&f->tag_value)) {
-		LM_ERR("Bad From header: no tag parameter\n");
+	return -1;
+}
+
+/*
+ * caller needs to call free_to for *body
+ */
+int sca_parse_uri(struct to_body *body, str *uri)
+{
+	assert(body != NULL);
+	assert(uri != NULL);
+
+	parse_to(uri->s, uri->s + uri->len + 1, body);
+	if(body->error != PARSE_OK) {
+		LM_ERR("Bad uri value[%.*s]\n", STR_FMT(uri));
 		return (-1);
 	}
-
-	// ensure the URI is parsed for future use
-	if(parse_uri(f->uri.s, f->uri.len, GET_FROM_PURI(msg)) < 0) {
-		LM_ERR("Failed to parse From URI %.*s\n", STR_FMT(&f->uri));
+	/* ensure the URI is parsed for future use */
+	if(parse_uri(body->uri.s, body->uri.len, &body->parsed_uri) < 0) {
+		LM_ERR("Failed to parse URI %.*s", STR_FMT(&body->uri));
 		return (-1);
 	}
-
-	*from = f;
-
 	return (0);
 }
 
-int sca_get_msg_to_header(sip_msg_t *msg, struct to_body **to)
+int sca_get_msg_from_header(sip_msg_t *msg, sca_to_body_t *from)
 {
-	struct to_body parsed_to;
-	struct to_body *t = NULL;
-
-	assert(msg != NULL);
-	assert(to != NULL);
+	struct to_body *f;
+	str uri = STR_NULL;
 
-	if(SCA_HEADER_EMPTY(msg->to)) {
-		LM_ERR("Empty To header\n");
-		return (-1);
-	}
-	t = get_to(msg);
-	if(t == NULL) {
-		parse_to(msg->to->body.s,
-				msg->to->body.s + msg->to->body.len + 1, // end of buffer
-				&parsed_to);
-		if(parsed_to.error != PARSE_OK) {
-			LM_ERR("Bad To header\n");
+	assert(from != NULL);
+	memset(from, 0, sizeof(sca_to_body_t));
+	if(sca_get_avp_value(from_uri_avp_type, from_uri_avp, &uri) < 0) {
+		assert(msg != NULL);
+		if(SCA_HEADER_EMPTY(msg->from)) {
+			LM_ERR("Empty From header\n");
+			return (-1);
+		}
+		if(parse_from_header(msg) < 0) {
+			LM_ERR("Bad From header\n");
+			return (-1);
+		}
+		from->flags = SCA_UTIL_FLAG_TO_BODY_MSG;
+		f = get_from(msg);
+		if(SCA_STR_EMPTY(&f->tag_value)) {
+			LM_ERR("Bad From header: no tag parameter\n");
 			return (-1);
 		}
-		t = &parsed_to;
-	}
 
-	// ensure the URI is parsed for future use
-	if(parse_uri(t->uri.s, t->uri.len, GET_TO_PURI(msg)) < 0) {
-		LM_ERR("Failed to parse To URI %.*s\n", STR_FMT(&t->uri));
-		return (-1);
+		// ensure the URI is parsed for future use
+		if(parse_uri(f->uri.s, f->uri.len, GET_FROM_PURI(msg)) < 0) {
+			LM_ERR("Failed to parse From URI %.*s\n", STR_FMT(&f->uri));
+			return (-1);
+		}
+		from->hdr = f;
+	} else {
+		LM_DBG("using $avp(%.*s)[%.*s] as from uri\n", STR_FMT(&from_uri_avp.s),
+				STR_FMT(&uri));
+		from->flags = SCA_UTIL_FLAG_TO_BODY_ALLOC;
+		from->hdr = pkg_malloc(sizeof(struct to_body));
+		if(from->hdr == NULL) {
+			PKG_MEM_ERROR;
+			return -1;
+		}
+		if(sca_parse_uri(from->hdr, &uri) < 0)
+			return -1;
 	}
 
-	*to = t;
-
 	return (0);
 }
 
-/*
- * caller needs to call free_to for *body
- */
-int sca_build_to_body_from_uri(sip_msg_t *msg, struct to_body **body, str *uri)
+int sca_get_msg_to_header(sip_msg_t *msg, sca_to_body_t *to)
 {
-	assert(msg != NULL);
-	assert(body != NULL);
-	assert(uri != NULL);
+	str uri = STR_NULL;
 
-	*body = pkg_malloc(sizeof(struct to_body));
-	if(*body == NULL) {
-		LM_ERR("cannot allocate pkg memory\n");
-		return (-1);
-	}
+	assert(to != NULL);
+	memset(to, 0, sizeof(sca_to_body_t));
+	if(sca_get_avp_value(to_uri_avp_type, to_uri_avp, &uri) < 0) {
+		assert(msg != NULL);
 
-	parse_to(uri->s, uri->s + uri->len + 1, *body);
-	if((*body)->error != PARSE_OK) {
-		LM_ERR("Bad uri value[%.*s]\n", STR_FMT(uri));
-		free_to(*body);
-		return (-1);
+		if(SCA_HEADER_EMPTY(msg->to)) {
+			LM_ERR("Empty To header\n");
+			return (-1);
+		}
+		to->flags = SCA_UTIL_FLAG_TO_BODY_MSG;
+		to->hdr = get_to(msg);
+		if(to->hdr == NULL) {
+			parse_to(msg->to->body.s,
+					msg->to->body.s + msg->to->body.len + 1, // end of buffer
+					to->hdr);
+			if(to->hdr->error != PARSE_OK) {
+				LM_ERR("Bad To header\n");
+				return (-1);
+			}
+		}
+
+		// ensure the URI is parsed for future use
+		if(parse_uri(to->hdr->uri.s, to->hdr->uri.len, GET_TO_PURI(msg)) < 0) {
+			LM_ERR("Failed to parse To URI %.*s\n", STR_FMT(&to->hdr->uri));
+			return (-1);
+		}
+	} else {
+		LM_DBG("using $avp(%.*s)[%.*s] as to uri\n", STR_FMT(&to_uri_avp.s),
+				STR_FMT(&uri));
+		to->hdr = pkg_malloc(sizeof(struct to_body));
+		if(to->hdr == NULL) {
+			PKG_MEM_ERROR;
+			return -1;
+		}
+		to->flags = SCA_UTIL_FLAG_TO_BODY_ALLOC;
+		if(sca_parse_uri(to->hdr, &uri) < 0)
+			return -1;
 	}
+
 	return (0);
 }
 
@@ -354,7 +394,7 @@ int sca_aor_create_from_info(
 
 int sca_create_canonical_aor_for_ua(sip_msg_t *msg, str *c_aor, int ua_opts)
 {
-	struct to_body *tf = NULL;
+	sca_to_body_t tf;
 	sip_uri_t c_uri;
 	str tf_aor = STR_NULL;
 	str contact_uri = STR_NULL;
@@ -364,6 +404,7 @@ int sca_create_canonical_aor_for_ua(sip_msg_t *msg, str *c_aor, int ua_opts)
 	assert(c_aor != NULL);
 
 	memset(c_aor, 0, sizeof(str));
+	memset(&tf, 0, sizeof(sca_to_body_t));
 
 	if((ua_opts & SCA_AOR_TYPE_AUTO)) {
 		if(msg->first_line.type == SIP_REQUEST) {
@@ -385,10 +426,10 @@ int sca_create_canonical_aor_for_ua(sip_msg_t *msg, str *c_aor, int ua_opts)
 		}
 	}
 
-	if(sca_uri_extract_aor(&tf->uri, &tf_aor) < 0) {
+	if(sca_uri_extract_aor(&tf.hdr->uri, &tf_aor) < 0) {
 		LM_ERR("sca_create_canonical_aor: failed to extract AoR from "
 			   "URI <%.*s>\n",
-				STR_FMT(&tf->uri));
+				STR_FMT(&tf.hdr->uri));
 		goto done;
 	}
 
@@ -410,7 +451,7 @@ int sca_create_canonical_aor_for_ua(sip_msg_t *msg, str *c_aor, int ua_opts)
 	}
 
 	if(SCA_STR_EMPTY(&c_uri.user)
-			|| SCA_STR_EQ(&c_uri.user, &tf->parsed_uri.user)) {
+			|| SCA_STR_EQ(&c_uri.user, &tf.hdr->parsed_uri.user)) {
 		// empty contact header or Contact user matches To/From AoR
 		c_aor->s = (char *)pkg_malloc(tf_aor.len);
 		c_aor->len = tf_aor.len;
@@ -418,7 +459,7 @@ int sca_create_canonical_aor_for_ua(sip_msg_t *msg, str *c_aor, int ua_opts)
 	} else {
 		// Contact user and To/From user mismatch
 		if(sca_aor_create_from_info(c_aor, c_uri.type, &c_uri.user,
-				   &tf->parsed_uri.host, &tf->parsed_uri.port)
+				   &tf.hdr->parsed_uri.host, &tf.hdr->parsed_uri.port)
 				< 0) {
 			LM_ERR("sca_create_canonical_aor: failed to create AoR from "
 				   "Contact <%.*s> and URI <%.*s>\n",
@@ -430,6 +471,9 @@ int sca_create_canonical_aor_for_ua(sip_msg_t *msg, str *c_aor, int ua_opts)
 	rc = 1;
 
 done:
+	if(tf.flags & SCA_UTIL_FLAG_TO_BODY_ALLOC) {
+		free_to(tf.hdr);
+	}
 	return (rc);
 }
 
diff --git a/src/modules/sca/sca_util.h b/src/modules/sca/sca_util.h
index c191083..563dedc 100644
--- a/src/modules/sca/sca_util.h
+++ b/src/modules/sca/sca_util.h
@@ -29,6 +29,18 @@ enum
 	SCA_AOR_TYPE_UAS = (1 << 2),
 };
 
+enum
+{
+	SCA_UTIL_FLAG_TO_BODY_MSG = (1 << 0),
+	SCA_UTIL_FLAG_TO_BODY_ALLOC = (1 << 1),
+};
+
+typedef struct sca_to_body
+{
+	struct to_body *hdr;
+	unsigned int flags;
+} sca_to_body_t;
+
 // get method, regardless of whether message is a request or response
 int sca_get_msg_method(sip_msg_t *);
 
@@ -42,12 +54,10 @@ int sca_get_msg_cseq_number(sip_msg_t *);
 int sca_get_msg_cseq_method(sip_msg_t *);
 
 // convenient From header parsing and extraction
-int sca_get_msg_from_header(sip_msg_t *, struct to_body **);
+int sca_get_msg_from_header(sip_msg_t *, sca_to_body_t *);
 
 // convenient To header parsing and extraction
-int sca_get_msg_to_header(sip_msg_t *, struct to_body **);
-
-int sca_build_to_body_from_uri(sip_msg_t *, struct to_body **, str *);
+int sca_get_msg_to_header(sip_msg_t *, sca_to_body_t *);
 
 // count number of characters requiring escape as defined by escape_common
 int sca_uri_display_escapes_count(str *);
