[libpri-commits] rmudgett: branch 1.4 r1723 - /branches/1.4/

SVN commits to the libpri project libpri-commits at lists.digium.com
Fri May 28 10:19:11 CDT 2010


Author: rmudgett
Date: Fri May 28 10:19:08 2010
New Revision: 1723

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1723
Log:
Added ETSI Explicit Call Transfer (ECT) support.

Added ability to send and receive ETSI ECT messages to eliminate tromboned
calls.

Added ETSI support to an existing API call to send ECT messages when the
upper level indicates to transfer specified calls.

The libpri API was extended to indicate to the upper layer that the far
end requests the transfer of the indicated calls.

Review:	https://reviewboard.asterisk.org/r/521/

Modified:
    branches/1.4/libpri.h
    branches/1.4/pri.c
    branches/1.4/pri_facility.c
    branches/1.4/pri_facility.h
    branches/1.4/pri_internal.h
    branches/1.4/q931.c

Modified: branches/1.4/libpri.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/libpri.h?view=diff&rev=1723&r1=1722&r2=1723
==============================================================================
--- branches/1.4/libpri.h (original)
+++ branches/1.4/libpri.h Fri May 28 10:19:08 2010
@@ -538,6 +538,7 @@
 #define PRI_SUBCMD_CC_CALL					14	/*!< Indicate that this call is a CC callback */
 #define PRI_SUBCMD_CC_CANCEL				15	/*!< Unsolicited indication that CC is canceled */
 #define PRI_SUBCMD_CC_STOP_ALERTING			16	/*!< Indicate that someone else has responed to remote user free */
+#define PRI_SUBCMD_TRANSFER_CALL			17	/*!< Request to transfer the specified calls together. */
 
 #if defined(STATUS_REQUEST_PLACE_HOLDER)
 struct pri_subcmd_status_request {
@@ -632,6 +633,19 @@
 	 * list it should search for the cc_id.
 	 */
 	int is_agent;
+};
+
+struct pri_subcmd_transfer {
+	/*! \brief Opaque call pointer for transfer with other call. */
+	q931_call *call_1;
+	/*! \brief Opaque call pointer for transfer with other call. */
+	q931_call *call_2;
+	/*! TRUE if call_1 is on hold. */
+	int is_call_1_held;
+	/*! TRUE if call_2 is on hold. */
+	int is_call_2_held;
+	/*! Invocation ID to use when sending a reply to the transfer request. */
+	int invoke_id;
 };
 
 struct pri_subcommand {
@@ -658,6 +672,7 @@
 		struct pri_subcmd_cc_status cc_status;
 		struct pri_subcmd_cc_id cc_call;
 		struct pri_subcmd_cc_cancel cc_cancel;
+		struct pri_subcmd_transfer transfer;
 	} u;
 };
 
@@ -1216,7 +1231,7 @@
 
 #define PRI_2BCT
 /* Attempt to pass the channels back to the NET side if compatable and
- * suscribed.  Sometimes called 2 bchannel transfer (2BCT) */
+ * subscribed.  Sometimes called 2 bchannel transfer (2BCT) */
 int pri_channel_bridge(q931_call *call1, q931_call *call2);
 
 /* Override message and error stuff */
@@ -1339,6 +1354,29 @@
  * \retval -1 on error.
  */
 int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code);
+
+/*!
+ * \brief Set the call transfer feature enable flag.
+ *
+ * \param ctrl D channel controller.
+ * \param enable TRUE to enable call transfer feature.
+ *
+ * \return Nothing
+ */
+void pri_transfer_enable(struct pri *ctrl, int enable);
+
+/*!
+ * \brief Send the call transfer response message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Value given by the initiating request.
+ * \param is_successful TRUE if the transfer was successful.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_transfer_rsp(struct pri *ctrl, q931_call *call, int invoke_id, int is_successful);
 
 /*!
  * \brief Set the call hold feature enable flag.

Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=1723&r1=1722&r2=1723
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Fri May 28 10:19:08 2010
@@ -1016,47 +1016,64 @@
 
 int pri_channel_bridge(q931_call *call1, q931_call *call2)
 {
+	struct q931_call *winner;
+
 	if (!call1 || !call2)
 		return -1;
 
-	/* Make sure we have compatible switchtypes */
-	if (call1->pri->switchtype != call2->pri->switchtype)
-		return -1;
+	winner = q931_find_winning_call(call1);
+	if (!winner) {
+		/* Cannot transfer: Call 1 does not have a winner yet. */
+		return -1;
+	}
+	call1 = winner;
+
+	winner = q931_find_winning_call(call2);
+	if (!winner) {
+		/* Cannot transfer: Call 2 does not have a winner yet. */
+		return -1;
+	}
+	call2 = winner;
+
+	/* Check to see if we're on the same PRI */
+	if (call1->pri != call2->pri) {
+		return -1;
+	}
 
 	/* Check for bearer capability */
 	if (call1->bc.transcapability != call2->bc.transcapability)
 		return -1;
 
-	/* Check to see if we're on the same PRI */
-	if (call1->pri != call2->pri)
-		return -1;
-	
 	switch (call1->pri->switchtype) {
-		case PRI_SWITCH_NI2:
-		case PRI_SWITCH_LUCENT5E:
-		case PRI_SWITCH_ATT4ESS:
-			if (eect_initiate_transfer(call1->pri, call1, call2))
-				return -1;
-			else
-				return 0;
-			break;
-		case PRI_SWITCH_DMS100:
-			if (rlt_initiate_transfer(call1->pri, call1, call2))
-				return -1;
-			else
-				return 0;
-			break;
-		case PRI_SWITCH_QSIG:
-			call1->bridged_call = call2;
-			call2->bridged_call = call1;
-			if (anfpr_initiate_transfer(call1->pri, call1, call2))
-				return -1;
-			else
-				return 0;
-			break;
-		default:
+	case PRI_SWITCH_NI2:
+	case PRI_SWITCH_LUCENT5E:
+	case PRI_SWITCH_ATT4ESS:
+		if (eect_initiate_transfer(call1->pri, call1, call2)) {
 			return -1;
-	}
+		}
+		break;
+	case PRI_SWITCH_DMS100:
+		if (rlt_initiate_transfer(call1->pri, call1, call2)) {
+			return -1;
+		}
+		break;
+	case PRI_SWITCH_QSIG:
+		call1->bridged_call = call2;
+		call2->bridged_call = call1;
+		if (anfpr_initiate_transfer(call1->pri, call1, call2)) {
+			return -1;
+		}
+		break;
+	case PRI_SWITCH_EUROISDN_E1:
+	case PRI_SWITCH_EUROISDN_T1:
+		if (etsi_initiate_transfer(call1->pri, call1, call2)) {
+			return -1;
+		}
+		break;
+	default:
+		return -1;
+	}
+	return 0;
 }
 
 void pri_hangup_fix_enable(struct pri *ctrl, int enable)
@@ -1595,6 +1612,14 @@
 void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits)
 {
 	sr->keypad_digits = keypad_digits;
+}
+
+void pri_transfer_enable(struct pri *ctrl, int enable)
+{
+	if (ctrl) {
+		ctrl = PRI_MASTER(ctrl);
+		ctrl->transfer_support = enable ? 1 : 0;
+	}
 }
 
 void pri_hold_enable(struct pri *ctrl, int enable)

Modified: branches/1.4/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_facility.c?view=diff&rev=1723&r1=1722&r2=1723
==============================================================================
--- branches/1.4/pri_facility.c (original)
+++ branches/1.4/pri_facility.c Fri May 28 10:19:08 2010
@@ -2362,6 +2362,344 @@
 }
 /* End AFN-PR */
 
+/*!
+ * \internal
+ * \brief Encode ETSI ExplicitEctExecute message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param pos Starting position to encode the facility ie contents.
+ * \param end End of facility ie contents encoding data buffer.
+ * \param link_id Identifier of other call involved in transfer.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ect_explicit_execute(struct pri *ctrl, unsigned char *pos,
+	unsigned char *end, int link_id)
+{
+	struct rose_msg_invoke msg;
+
+	pos = facility_encode_header(ctrl, pos, end, NULL);
+	if (!pos) {
+		return NULL;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.invoke_id = get_invokeid(ctrl);
+	msg.operation = ROSE_ETSI_ExplicitEctExecute;
+
+	msg.args.etsi.ExplicitEctExecute.link_id = link_id;
+
+	pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \internal
+ * \brief ECT LinkId response callback function.
+ *
+ * \param reason Reason callback is called.
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param apdu APDU queued entry.  Do not change!
+ * \param msg APDU response message data.  (NULL if was not the reason called.)
+ *
+ * \return TRUE if no more responses are expected.
+ */
+static int etsi_ect_link_id_rsp(enum APDU_CALLBACK_REASON reason, struct pri *ctrl,
+	struct q931_call *call, struct apdu_event *apdu, const struct apdu_msg_data *msg)
+{
+	unsigned char buffer[256];
+	unsigned char *end;
+	q931_call *call_2;
+
+	switch (reason) {
+	case APDU_CALLBACK_REASON_MSG_RESULT:
+		call_2 = q931_find_call(ctrl, apdu->response.user.value);
+		if (!call_2) {
+			break;
+		}
+
+		end = enc_etsi_ect_explicit_execute(ctrl, buffer, buffer + sizeof(buffer),
+			msg->response.result->args.etsi.EctLinkIdRequest.link_id);
+		if (!end) {
+			break;
+		}
+
+		/* Remember that if we queue a facility IE for a facility message we
+		 * have to explicitly send the facility message ourselves */
+		if (pri_call_apdu_queue(call_2, Q931_FACILITY, buffer, end - buffer, NULL)
+			|| q931_facility(call_2->pri, call_2)) {
+			pri_message(ctrl, "Could not schedule facility message for call %d\n",
+				call_2->cr);
+		}
+		break;
+	default:
+		break;
+	}
+	return 1;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI ECT LinkId request message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param pos Starting position to encode the facility ie contents.
+ * \param end End of facility ie contents encoding data buffer.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ect_link_id_req(struct pri *ctrl, unsigned char *pos,
+	unsigned char *end)
+{
+	struct rose_msg_invoke msg;
+
+	pos = facility_encode_header(ctrl, pos, end, NULL);
+	if (!pos) {
+		return NULL;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.invoke_id = get_invokeid(ctrl);
+	msg.operation = ROSE_ETSI_EctLinkIdRequest;
+
+	pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \brief Start an Explicit Call Transfer (ECT) sequence between the two calls.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param call_1 Q.931 call leg 1
+ * \param call_2 Q.931 call leg 2
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int etsi_initiate_transfer(struct pri *ctrl, q931_call *call_1, q931_call *call_2)
+{
+	unsigned char buffer[256];
+	unsigned char *end;
+	struct apdu_callback_data response;
+
+	end = enc_etsi_ect_link_id_req(ctrl, buffer, buffer + sizeof(buffer));
+	if (!end) {
+		return -1;
+	}
+
+	memset(&response, 0, sizeof(response));
+	response.invoke_id = ctrl->last_invoke;
+	response.timeout_time = ctrl->timers[PRI_TIMER_T_RESPONSE];
+	response.callback = etsi_ect_link_id_rsp;
+	response.user.value = call_2->cr;
+
+	/* Remember that if we queue a facility IE for a facility message we
+	 * have to explicitly send the facility message ourselves */
+	if (pri_call_apdu_queue(call_1, Q931_FACILITY, buffer, end - buffer, &response)
+		|| q931_facility(call_1->pri, call_1)) {
+		pri_message(ctrl, "Could not schedule facility message for call %d\n",
+			call_1->cr);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Encode ETSI ECT LinkId result respnose message.
+ *
+ * \param ctrl D channel controller for diagnostic messages or global options.
+ * \param pos Starting position to encode the facility ie contents.
+ * \param end End of facility ie contents encoding data buffer.
+ * \param invoke_id Invoke id to put in result message.
+ * \param link_id Requested link id to put in result message.
+ *
+ * \retval Start of the next ASN.1 component to encode on success.
+ * \retval NULL on error.
+ */
+static unsigned char *enc_etsi_ect_link_id_rsp(struct pri *ctrl, unsigned char *pos,
+	unsigned char *end, int invoke_id, int link_id)
+{
+	struct rose_msg_result msg;
+
+	pos = facility_encode_header(ctrl, pos, end, NULL);
+	if (!pos) {
+		return NULL;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.invoke_id = invoke_id;
+	msg.operation = ROSE_ETSI_EctLinkIdRequest;
+
+	msg.args.etsi.EctLinkIdRequest.link_id = link_id;
+
+	pos = rose_encode_result(ctrl, pos, end, &msg);
+
+	return pos;
+}
+
+/*!
+ * \internal
+ * \brief Send EctLinkIdRequest result response message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Invoke id to put in result message.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int send_ect_link_id_rsp(struct pri *ctrl, q931_call *call, int invoke_id)
+{
+	unsigned char buffer[256];
+	unsigned char *end;
+
+	end = enc_etsi_ect_link_id_rsp(ctrl, buffer, buffer + sizeof(buffer), invoke_id,
+		call->link_id);
+	if (!end) {
+		return -1;
+	}
+
+	/* Remember that if we queue a facility IE for a facility message we
+	 * have to explicitly send the facility message ourselves */
+	if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
+		|| q931_facility(call->pri, call)) {
+		pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Process the received ETSI EctExecute message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Invoke id to put in response message.
+ *
+ * \details
+ * 1) Find the active call implied by the transfer request.
+ * 2) Create the PRI_SUBCMD_TRANSFER_CALL event.
+ *
+ * \retval ROSE_ERROR_None on success.
+ * \retval error_code on error.
+ */
+static enum rose_error_code etsi_ect_execute_transfer(struct pri *ctrl, q931_call *call, int invoke_id)
+{
+	enum rose_error_code error_code;
+	struct pri_subcommand *subcmd;
+	q931_call *call_active;
+
+	switch (call->ourcallstate) {
+	case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+	case Q931_CALL_STATE_CALL_DELIVERED:
+	case Q931_CALL_STATE_CALL_RECEIVED:
+	case Q931_CALL_STATE_CONNECT_REQUEST:
+	case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+	case Q931_CALL_STATE_ACTIVE:
+		if (call->master_call->hold_state != Q931_HOLD_STATE_CALL_HELD) {
+			/* EctExecute must be sent on the held call. */
+			error_code = ROSE_ERROR_Gen_InvalidCallState;
+			break;
+		}
+		/* Held call is being transferred. */
+		call_active = q931_find_held_active_call(ctrl, call);
+		if (!call_active) {
+			error_code = ROSE_ERROR_Gen_NotAvailable;
+			break;
+		}
+
+		/* Setup transfer subcommand */
+		subcmd = q931_alloc_subcommand(ctrl);
+		if (!subcmd) {
+			error_code = ROSE_ERROR_Gen_NotAvailable;
+			break;
+		}
+		subcmd->cmd = PRI_SUBCMD_TRANSFER_CALL;
+		subcmd->u.transfer.call_1 = call->master_call;
+		subcmd->u.transfer.call_2 = call_active;
+		subcmd->u.transfer.is_call_1_held = 1;
+		subcmd->u.transfer.is_call_2_held = 0;
+		subcmd->u.transfer.invoke_id = invoke_id;
+
+		error_code = ROSE_ERROR_None;
+		break;
+	default:
+		error_code = ROSE_ERROR_Gen_InvalidCallState;
+		break;
+	}
+
+	return error_code;
+}
+
+/*!
+ * \internal
+ * \brief Process the received ETSI ExplicitEctExecute message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param invoke_id Invoke id to put in response message.
+ * \param link_id Link id of the other call involved in the transfer.
+ *
+ * \details
+ * 1) Find the other call specified by the link_id in transfer request.
+ * 2) Create the PRI_SUBCMD_TRANSFER_CALL event.
+ *
+ * \retval ROSE_ERROR_None on success.
+ * \retval error_code on error.
+ */
+static enum rose_error_code etsi_explicit_ect_execute_transfer(struct pri *ctrl, q931_call *call, int invoke_id, int link_id)
+{
+	enum rose_error_code error_code;
+	struct pri_subcommand *subcmd;
+	q931_call *call_2;
+
+	switch (call->ourcallstate) {
+	case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+	case Q931_CALL_STATE_CALL_DELIVERED:
+	case Q931_CALL_STATE_CALL_RECEIVED:
+	case Q931_CALL_STATE_CONNECT_REQUEST:
+	case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+	case Q931_CALL_STATE_ACTIVE:
+		call_2 = q931_find_link_id_call(ctrl, link_id);
+		if (!call_2 || call_2 == call->master_call) {
+			error_code = ROSE_ERROR_Gen_NotAvailable;
+			break;
+		}
+
+		/* Setup transfer subcommand */
+		subcmd = q931_alloc_subcommand(ctrl);
+		if (!subcmd) {
+			error_code = ROSE_ERROR_Gen_NotAvailable;
+			break;
+		}
+		subcmd->cmd = PRI_SUBCMD_TRANSFER_CALL;
+		subcmd->u.transfer.call_1 = call->master_call;
+		subcmd->u.transfer.call_2 = call_2;
+		subcmd->u.transfer.is_call_1_held =
+			(call->master_call->hold_state == Q931_HOLD_STATE_CALL_HELD) ? 1 : 0;
+		subcmd->u.transfer.is_call_2_held =
+			(call_2->hold_state == Q931_HOLD_STATE_CALL_HELD) ? 1 : 0;
+		subcmd->u.transfer.invoke_id = invoke_id;
+
+		error_code = ROSE_ERROR_None;
+		break;
+	default:
+		error_code = ROSE_ERROR_Gen_InvalidCallState;
+		break;
+	}
+
+	return error_code;
+}
+
 /* AOC */
 /*!
  * \internal
@@ -3264,6 +3602,19 @@
 		break;
 	}
 	return send_facility_error(ctrl, call, invoke_id, rose_err);
+}
+
+int pri_transfer_rsp(struct pri *ctrl, q931_call *call, int invoke_id, int is_successful)
+{
+	if (!ctrl || !call) {
+		return -1;
+	}
+
+	if (is_successful) {
+		return rose_result_ok_encode(ctrl, call, Q931_DISCONNECT, invoke_id);
+	} else {
+		return send_facility_error(ctrl, call, invoke_id, ROSE_ERROR_Gen_NotAvailable);
+	}
 }
 
 /*!
@@ -3517,6 +3868,7 @@
 	struct q931_party_id party_id;
 	struct q931_party_address party_address;
 	struct q931_party_redirecting deflection;
+	enum rose_error_code error_code;
 
 	switch (invoke->operation) {
 #if 0	/* Not handled yet */
@@ -3816,21 +4168,46 @@
 	case ROSE_ITU_IdentificationOfCharge:
 		break;
 #endif	/* Not handled yet */
-#if 0	/* Not handled yet */
 	case ROSE_ETSI_EctExecute:
+		if (!PRI_MASTER(ctrl)->transfer_support) {
+			send_facility_error(ctrl, call, invoke->invoke_id,
+				ROSE_ERROR_Gen_NotSubscribed);
+			break;
+		}
+		error_code = etsi_ect_execute_transfer(ctrl, call, invoke->invoke_id);
+		if (error_code != ROSE_ERROR_None) {
+			send_facility_error(ctrl, call, invoke->invoke_id, error_code);
+		}
 		break;
 	case ROSE_ETSI_ExplicitEctExecute:
-		break;
-#endif	/* Not handled yet */
+		error_code = etsi_explicit_ect_execute_transfer(ctrl, call, invoke->invoke_id,
+			invoke->args.etsi.ExplicitEctExecute.link_id);
+		if (error_code != ROSE_ERROR_None) {
+			send_facility_error(ctrl, call, invoke->invoke_id, error_code);
+		}
+		break;
 	case ROSE_ETSI_RequestSubaddress:
 		/* Ignore since we are not handling subaddresses yet. */
 		break;
 #if 0	/* Not handled yet */
 	case ROSE_ETSI_SubaddressTransfer:
 		break;
+#endif	/* Not handled yet */
 	case ROSE_ETSI_EctLinkIdRequest:
-		break;
-#endif	/* Not handled yet */
+		if (!PRI_MASTER(ctrl)->transfer_support) {
+			send_facility_error(ctrl, call, invoke->invoke_id,
+				ROSE_ERROR_Gen_ResourceUnavailable);
+			break;
+		}
+		/*
+		 * Use the invoke_id sequence number as a link_id.
+		 * It should be safe enough to do this.  If not then we will have to search
+		 * the call pool to ensure that the link_id is not already in use.
+		 */
+		call->master_call->link_id = get_invokeid(ctrl);
+		call->master_call->is_link_id_valid = 1;
+		send_ect_link_id_rsp(ctrl, call, invoke->invoke_id);
+		break;
 	case ROSE_ETSI_EctInform:
 		/* redirectionNumber is put in remote_id.number */
 		if (invoke->args.etsi.EctInform.redirection_present) {
@@ -3844,10 +4221,13 @@
 			call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
 		}
 		break;
-#if 0	/* Not handled yet */
 	case ROSE_ETSI_EctLoopTest:
-		break;
-#endif	/* Not handled yet */
+		/*
+		 * The ETS 300 369 specification does a very poor job describing
+		 * how this message is used to detect loops.
+		 */
+		send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotAvailable);
+		break;
 #if defined(STATUS_REQUEST_PLACE_HOLDER)
 	case ROSE_ETSI_StatusRequest:
 		/* Not handled yet */

Modified: branches/1.4/pri_facility.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_facility.h?view=diff&rev=1723&r1=1722&r2=1723
==============================================================================
--- branches/1.4/pri_facility.h (original)
+++ branches/1.4/pri_facility.h Fri May 28 10:19:08 2010
@@ -206,11 +206,13 @@
 
 int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
 
+/* starts a QSIG Path Replacement */
+int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
+
+int etsi_initiate_transfer(struct pri *ctrl, q931_call *call_1, q931_call *call_2);
+
 int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason);
 int send_reroute_request(struct pri *ctrl, q931_call *call, const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, int subscription_option);
-
-/* starts a QSIG Path Replacement */
-int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
 
 int send_call_transfer_complete(struct pri *pri, q931_call *call, int call_status);
 

Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=1723&r1=1722&r2=1723
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Fri May 28 10:19:08 2010
@@ -106,6 +106,7 @@
 	unsigned int deflection_support:1;/* TRUE if upper layer supports call deflection/rerouting. */
 	unsigned int hangup_fix_enabled:1;/* TRUE if should follow Q.931 Section 5.3.2 instead of blindly sending RELEASE_COMPLETE for certain causes */
 	unsigned int cc_support:1;/* TRUE if upper layer supports call completion. */
+	unsigned int transfer_support:1;/* TRUE if the upper layer supports ECT */
 
 	/* MDL variables */
 	int mdl_error;
@@ -576,6 +577,11 @@
 
 	int transferable;			/* RLT call is transferable */
 	unsigned int rlt_call_id;	/* RLT call id */
+
+	/*! ETSI Explicit Call Transfer link id. */
+	int link_id;
+	/*! TRUE if link_id is valid. */
+	int is_link_id_valid;
 
 	/* Bridged call info */
 	q931_call *bridged_call;        /* Pointer to other leg of bridged call (Used by Q.SIG when eliminating tromboned calls) */
@@ -933,8 +939,12 @@
 const char *q931_call_state_str(enum Q931_CALL_STATE callstate);
 const char *msg2str(int msg);
 
+struct q931_call *q931_find_winning_call(struct q931_call *call);
 int q931_master_pass_event(struct pri *ctrl, struct q931_call *subcall, int msg_type);
 struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl);
+
+struct q931_call *q931_find_link_id_call(struct pri *ctrl, int link_id);
+struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call);
 
 int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
 

Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=1723&r1=1722&r2=1723
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Fri May 28 10:19:08 2010
@@ -3603,7 +3603,8 @@
  *
  * \param ctrl D channel controller.
  * \param call Q.931 call leg.
- * 
+ * \param cr Call Reference identifier.
+ *
  * \note The call record is assumed to already be memset() to zero.
  *
  * \return Nothing
@@ -5193,7 +5194,6 @@
 }
 
 /*!
- * \internal
  * \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
  *
  * \param call Starting Q.931 call record of search.
@@ -5201,7 +5201,7 @@
  * \retval winning-call or given call if not outboundbroadcast.
  * \retval NULL if no winning call yet.
  */
-static struct q931_call *q931_find_winning_call(struct q931_call *call)
+struct q931_call *q931_find_winning_call(struct q931_call *call)
 {
 	struct q931_call *master;
 
@@ -6986,7 +6986,53 @@
 }
 
 /*!
- * \internal
+ * \brief Find the transfer call indicated by the given link_id.
+ *
+ * \param ctrl D channel controller.
+ * \param link_id Link id of the other call involved in the transfer.
+ *
+ * \retval found-master-call on success.
+ * \retval NULL on error.
+ */
+struct q931_call *q931_find_link_id_call(struct pri *ctrl, int link_id)
+{
+	struct pri *master;
+	struct q931_call *cur;
+	struct q931_call *winner;
+	struct q931_call *match;
+
+	match = NULL;
+	master = PRI_MASTER(ctrl);
+	for (cur = *master->callpool; cur; cur = cur->next) {
+		if (cur->is_link_id_valid && cur->link_id == link_id) {
+			/* Found the link_id call. */
+			winner = q931_find_winning_call(cur);
+			if (!winner) {
+				/* There is no winner. */
+				break;
+			}
+			switch (winner->ourcallstate) {
+			case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+			case Q931_CALL_STATE_CALL_DELIVERED:
+			case Q931_CALL_STATE_CALL_RECEIVED:
+			case Q931_CALL_STATE_CONNECT_REQUEST:
+			case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+			case Q931_CALL_STATE_ACTIVE:
+				/* The link_id call is in a state suitable for transfer. */
+				match = cur;
+				break;
+			default:
+				/* The link_id call is not in a good state to transfer. */
+				break;
+			}
+			break;
+		}
+	}
+
+	return match;
+}
+
+/*!
  * \brief Find the active call given the held call.
  *
  * \param ctrl D channel controller.
@@ -6995,7 +7041,7 @@
  * \retval master-active-call on success.
  * \retval NULL on error.
  */
-static struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call)
+struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call)
 {
 	struct pri *master;
 	struct q931_call *cur;




More information about the libpri-commits mailing list