[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