[asterisk-commits] file: branch file/gulp_transfer r387926 - /team/file/gulp_transfer/res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed May 8 06:00:33 CDT 2013


Author: file
Date: Wed May  8 06:00:31 2013
New Revision: 387926

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387926
Log:
Expose Replaces information to the dialplan for INVITE w/ Replaces when the dialog does not exist locally.

Modified:
    team/file/gulp_transfer/res/res_sip_refer.c

Modified: team/file/gulp_transfer/res/res_sip_refer.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_transfer/res/res_sip_refer.c?view=diff&rev=387926&r1=387925&r2=387926
==============================================================================
--- team/file/gulp_transfer/res/res_sip_refer.c (original)
+++ team/file/gulp_transfer/res/res_sip_refer.c Wed May  8 06:00:31 2013
@@ -368,52 +368,6 @@
 	return 0;
 }
 
-static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_param *replaces_param,
-	struct refer_progress *progress)
-{
-	const pj_str_t str_replaces = { "Replaces", 8 };
-	pj_str_t replaces_content;
-	pjsip_replaces_hdr *replaces;
-	int parsed_len;
-	pjsip_dialog *dlg;
-
-	pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
-
-	/* Parsing the parameter as a Replaces header easily grabs the needed information */
-	if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
-		pj_strlen(&replaces_content), &parsed_len))) {
-		return 400;
-	}
-
-	/* See if the dialog is local, or remote */
-	if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
-		RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
-		struct refer_attended *attended;
-
-		pjsip_dlg_dec_lock(dlg);
-
-		if (!other_session) {
-			return 603;
-		}
-
-		/* We defer actually doing the attended transfer to the other session so no deadlock can occur */
-		if (!(attended = refer_attended_alloc(session, other_session, progress))) {
-			return 500;
-		}
-
-		/* Push it to the other session, which will have both channels with minimal locking */
-		if (ast_sip_push_task(other_session->serializer, refer_attended, attended)) {
-			ao2_cleanup(attended);
-			return 500;
-		}
-
-		return 200;
-	} else {
-	}
-
-	return 0;
-}
-
 /*! \brief Structure for blind transfer callback details */
 struct refer_blind {
 	/*! \brief Context being used for transfer */
@@ -422,6 +376,10 @@
 	struct refer_progress *progress;
 	/*! \brief REFER message */
 	pjsip_rx_data *rdata;
+	/*! \brief Optional Replaces header */
+	pjsip_replaces_hdr *replaces;
+	/*! \brief Optional Refer-To header */
+	pjsip_sip_uri *refer_to;
 };
 
 /*! \brief Blind transfer callback function */
@@ -430,6 +388,8 @@
 	struct refer_blind *refer = user_data;
 	const pj_str_t str_referred_by = { "Referred-By", 11 };
 	pjsip_generic_string_hdr *referred_by = pjsip_msg_find_hdr_by_name(refer->rdata->msg_info.msg, &str_referred_by, NULL);
+
+	pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
 
 	/* If progress monitoring is being done attach a frame hook so we can monitor it */
 	if (refer->progress) {
@@ -466,6 +426,96 @@
 		uri[referred_by->hvalue.slen] = '\0';
 		pbx_builtin_setvar_helper(chan, "SIPREFERREDBYHDR", uri);
 	}
+
+	if (refer->replaces) {
+		char replaces[512];
+
+		pjsip_hdr_print_on(refer->replaces, replaces, sizeof(replaces));
+		pbx_builtin_setvar_helper(chan, "SIPREPLACESHDR", replaces);
+	}
+
+	if (refer->refer_to) {
+		char refer_to[PJSIP_MAX_URL_SIZE];
+
+		pjsip_uri_print(PJSIP_URI_IN_REQ_URI, refer->refer_to, refer_to, sizeof(refer_to));
+		pbx_builtin_setvar_helper(chan, "SIPREFERTOHDR", refer_to);
+	}
+}
+
+static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
+	pjsip_param *replaces_param, struct refer_progress *progress)
+{
+	const pj_str_t str_replaces = { "Replaces", 8 };
+	pj_str_t replaces_content;
+	pjsip_replaces_hdr *replaces;
+	int parsed_len;
+	pjsip_dialog *dlg;
+
+	pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
+
+	/* Parsing the parameter as a Replaces header easily grabs the needed information */
+	if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
+		pj_strlen(&replaces_content), &parsed_len))) {
+		return 400;
+	}
+
+	/* See if the dialog is local, or remote */
+	if ((dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE))) {
+		RAII_VAR(struct ast_sip_session *, other_session, ast_sip_dialog_get_session(dlg), ao2_cleanup);
+		struct refer_attended *attended;
+
+		pjsip_dlg_dec_lock(dlg);
+
+		if (!other_session) {
+			return 603;
+		}
+
+		/* We defer actually doing the attended transfer to the other session so no deadlock can occur */
+		if (!(attended = refer_attended_alloc(session, other_session, progress))) {
+			return 500;
+		}
+
+		/* Push it to the other session, which will have both channels with minimal locking */
+		if (ast_sip_push_task(other_session->serializer, refer_attended, attended)) {
+			ao2_cleanup(attended);
+			return 500;
+		}
+
+		return 200;
+	} else {
+		const char *context = (session->channel ? pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT") : "");
+		struct refer_blind refer;
+
+		if (ast_strlen_zero(context)) {
+			context = session->endpoint->context;
+		}
+
+		if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
+			return 404;
+		}
+
+		refer.context = context;
+		refer.progress = progress;
+		refer.rdata = rdata;
+		refer.replaces = replaces;
+		refer.refer_to = target_uri;
+
+		switch (ast_bridge_transfer_blind(session->channel, "external_replaces", context, refer_blind_callback, &refer)) {
+			case AST_BRIDGE_TRANSFER_INVALID:
+				return 503;
+			case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
+				return 403;
+			case AST_BRIDGE_TRANSFER_FAIL:
+				return 500;
+			case AST_BRIDGE_TRANSFER_SUCCESS:
+				session->defer_terminate = 1;
+				return 200;
+		}
+
+		return 503;
+	}
+
+	return 0;
 }
 
 static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
@@ -518,6 +568,10 @@
 	pjsip_param *replaces;
 	int response;
 
+	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_refer_method())) {
+		return 0;
+	}
+
 	/* A Refer-To header is required */
 	if (!(refer_to = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL))) {
 		pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
@@ -546,7 +600,7 @@
 	/* Determine if this is an attended or blind transfer */
 	if ((replaces = pjsip_param_find(&target_uri->header_param, &str_replaces)) ||
 		(replaces = pjsip_param_find(&target_uri->other_param, &str_replaces))) {
-		response = refer_incoming_attended_request(session, rdata, replaces, progress);
+		response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
 	} else {
 		response = refer_incoming_blind_request(session, rdata, target_uri, progress);
 	}
@@ -580,9 +634,23 @@
 	return 0;
 }
 
+static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
+{
+	const char *replaces;
+
+	if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method) ||
+		!session->channel ||
+		(ast_channel_state(session->channel) != AST_STATE_DOWN) ||
+		!(replaces = pbx_builtin_getvar_helper(session->channel, "SIPREPLACESHDR"))) {
+		return;
+	}
+
+	ast_sip_add_header(tdata, "Replaces", replaces);
+}
+
 static struct ast_sip_session_supplement refer_supplement = {
-	.method = "REFER",
 	.incoming_request = refer_incoming_request,
+	.outgoing_request = refer_outgoing_request,
 };
 
 static int load_module(void)




More information about the asterisk-commits mailing list