[asterisk-commits] file: branch file/gulp_transfer r387780 - /team/file/gulp_transfer/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon May 6 15:01:53 CDT 2013


Author: file
Date: Mon May  6 15:01:51 2013
New Revision: 387780

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387780
Log:
Add Asterisk initiated blind transfer support.

Modified:
    team/file/gulp_transfer/channels/chan_gulp.c

Modified: team/file/gulp_transfer/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_transfer/channels/chan_gulp.c?view=diff&rev=387780&r1=387779&r2=387780
==============================================================================
--- team/file/gulp_transfer/channels/chan_gulp.c (original)
+++ team/file/gulp_transfer/channels/chan_gulp.c Mon May  6 15:01:51 2013
@@ -122,6 +122,7 @@
 static struct ast_frame *gulp_read(struct ast_channel *ast);
 static int gulp_write(struct ast_channel *ast, struct ast_frame *f);
 static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int gulp_transfer(struct ast_channel *ast, const char *target);
 static int gulp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 
 /*! \brief PBX interface structure for channel registration */
@@ -141,6 +142,7 @@
 	.write_video = gulp_write,
 	.exception = gulp_read,
 	.indicate = gulp_indicate,
+	.transfer = gulp_transfer,
 	.fixup = gulp_fixup,
 	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
 };
@@ -795,6 +797,127 @@
 	}
 
 	return res;
+}
+
+struct transfer_data {
+	struct ast_sip_session *session;
+	char *target;
+};
+
+static void transfer_data_destroy(void *obj)
+{
+	struct transfer_data *trnf_data = obj;
+
+	ast_free(trnf_data->target);
+	ao2_cleanup(trnf_data->session);
+}
+
+static struct transfer_data *transfer_data_alloc(struct ast_sip_session *session, const char *target)
+{
+	struct transfer_data *trnf_data = ao2_alloc(sizeof(*trnf_data), transfer_data_destroy);
+
+	if (!trnf_data) {
+		return NULL;
+	}
+
+	if (!(trnf_data->target = ast_strdup(target))) {
+		ao2_ref(trnf_data, -1);
+		return NULL;
+	}
+
+	ao2_ref(session, +1);
+	trnf_data->session = session;
+
+	return trnf_data;
+}
+
+static void transfer_redirect(struct ast_sip_session *session, const char *target)
+{
+	pjsip_tx_data *packet;
+	enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
+	pjsip_contact_hdr *contact;
+	pj_str_t tmp;
+
+	if (pjsip_inv_end_session(session->inv_session, 302, NULL, &packet) != PJ_SUCCESS) {
+		message = AST_TRANSFER_FAILED;
+		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+
+		return;
+	}
+
+	contact = pjsip_contact_hdr_create(packet->pool);
+	pj_strdup2(packet->pool, &tmp, target);
+	if (!(contact->uri = pjsip_parse_uri(packet->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR))) {
+		message = AST_TRANSFER_FAILED;
+		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+		pjsip_tx_data_dec_ref(packet);
+
+		return;
+	}
+	pjsip_msg_add_hdr(packet->msg, (pjsip_hdr *) contact);
+
+	ast_sip_session_send_response(session, packet);
+	ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+}
+
+static void transfer_refer(struct ast_sip_session *session, const char *target)
+{
+	pjsip_evsub *sub;
+	enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
+	pj_str_t tmp;
+	pjsip_tx_data *packet;
+
+	if (pjsip_xfer_create_uac(session->inv_session->dlg, NULL, &sub) != PJ_SUCCESS) {
+		message = AST_TRANSFER_FAILED;
+		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+
+		return;
+	}
+
+	if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) {
+		message = AST_TRANSFER_FAILED;
+		ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+		pjsip_evsub_terminate(sub, PJ_FALSE);
+
+		return;
+	}
+
+	pjsip_xfer_send_request(sub, packet);
+	ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+}
+
+static int transfer(void *data)
+{
+	struct transfer_data *trnf_data = data;
+
+	if (ast_channel_state(trnf_data->session->channel) == AST_STATE_RING) {
+		transfer_redirect(trnf_data->session, trnf_data->target);
+	} else {
+		transfer_refer(trnf_data->session, trnf_data->target);
+	}
+
+	ao2_ref(trnf_data, -1);
+	return 0;
+}
+
+/*! \brief Function called by core for Asterisk initiated transfer */
+static int gulp_transfer(struct ast_channel *chan, const char *target)
+{
+	struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+	struct ast_sip_session *session = pvt->session;
+	struct transfer_data *trnf_data = transfer_data_alloc(session, target);
+
+	if (!trnf_data) {
+		return -1;
+	}
+
+	if (ast_sip_push_task(session->serializer, transfer, trnf_data)) {
+		ast_log(LOG_WARNING, "Error requesting transfer\n");
+		ao2_cleanup(trnf_data);
+		return -1;
+	}
+
+	return 0;
 }
 
 /*! \brief Function called by core to start a DTMF digit */




More information about the asterisk-commits mailing list