Commit 19e2a84c authored by Richard Mudgett's avatar Richard Mudgett

Add call transfer exchange of subaddresses support and fix PTMP call transfer signaling.

* Add the ability to exchange subaddresses for ETSI PTMP, ETSI PTP, and
Q.SIG for call transfer.

* Fix ETSI PTMP to send the correct messages depending on the call state
for call transfer.  NOTE: Some ISDN phones only handle the NOTIFY message
that the EN 300-369 spec says should be sent only if the call has not
connected yet.

JIRA LIBPRI-47
JIRA SWP-2363

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


git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2172 2fbb986a-6c06-0410-b554-c9c1f0a7f128
parent 4faa2935
......@@ -949,6 +949,9 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
{
struct q931_party_id party_id;
unsigned idx;
unsigned new_name;
unsigned new_number;
unsigned new_subaddress;
struct q931_call *subcall;
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
......@@ -957,13 +960,14 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
pri_copy_party_id_to_q931(&party_id, &connected->id);
q931_party_id_fixup(ctrl, &party_id);
if (!q931_party_id_cmp(&party_id, &call->local_id)) {
/* The local party information did not change so do nothing. */
return 0;
}
call->local_id = party_id;
/* Update all subcalls with new local_id. */
new_name = q931_party_name_cmp(&party_id.name, &call->local_id.name);
new_number = q931_party_number_cmp(&party_id.number, &call->local_id.number);
new_subaddress = party_id.subaddress.valid
&& q931_party_subaddress_cmp(&party_id.subaddress, &call->local_id.subaddress);
/* Update the call and all subcalls with new local_id. */
call->local_id = party_id;
if (call->outboundbroadcast && call->master_call == call) {
for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) {
subcall = call->subcalls[idx];
......@@ -982,23 +986,100 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
* The local party transferred to someone else before
* the remote end answered.
*/
case Q931_CALL_STATE_ACTIVE:
switch (ctrl->switchtype) {
case PRI_SWITCH_EUROISDN_E1:
case PRI_SWITCH_EUROISDN_T1:
if (PTMP_MODE(ctrl)) {
/* PTMP mode */
q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
&call->local_id.number);
} else {
if (BRI_NT_PTMP(ctrl)) {
/*
* NT PTMP mode
*
* We should not send these messages to the network if we are
* the CPE side since phones do not transfer calls within
* themselves. Well... If you consider handing the handset to
* someone else a transfer then how is the network to know?
*/
if (new_number) {
q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
&party_id.number);
}
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
q931_subaddress_transfer(ctrl, call);
}
} else if (PTP_MODE(ctrl)) {
/* PTP mode */
/* Immediately send EctInform APDU, callStatus=answered(0) */
if (new_number) {
/* Immediately send EctInform APDU, callStatus=answered(0) */
send_call_transfer_complete(ctrl, call, 0);
}
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
q931_subaddress_transfer(ctrl, call);
}
}
break;
case PRI_SWITCH_QSIG:
if (new_name || new_number) {
/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
send_call_transfer_complete(ctrl, call, 0);
}
if (new_subaddress
|| (party_id.subaddress.valid && (new_name || new_number))) {
q931_subaddress_transfer(ctrl, call);
}
break;
default:
break;
}
break;
case Q931_CALL_STATE_ACTIVE:
switch (ctrl->switchtype) {
case PRI_SWITCH_EUROISDN_E1:
case PRI_SWITCH_EUROISDN_T1:
if (BRI_NT_PTMP(ctrl)) {
/*
* NT PTMP mode
*
* We should not send these messages to the network if we are
* the CPE side since phones do not transfer calls within
* themselves. Well... If you consider handing the handset to
* someone else a transfer then how is the network to know?
*/
if (new_number) {
#if defined(USE_NOTIFY_FOR_ECT)
/*
* Some ISDN phones only handle the NOTIFY message that the
* EN 300-369 spec says should be sent only if the call has not
* connected yet.
*/
q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
&party_id.number);
#else
q931_request_subaddress(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
&party_id.number);
#endif /* defined(USE_NOTIFY_FOR_ECT) */
}
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
q931_subaddress_transfer(ctrl, call);
}
} else if (PTP_MODE(ctrl)) {
/* PTP mode */
if (new_number) {
/* Immediately send EctInform APDU, callStatus=answered(0) */
send_call_transfer_complete(ctrl, call, 0);
}
if (new_subaddress || (party_id.subaddress.valid && new_number)) {
q931_subaddress_transfer(ctrl, call);
}
}
break;
case PRI_SWITCH_QSIG:
/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
send_call_transfer_complete(ctrl, call, 0);
if (new_name || new_number) {
/* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
send_call_transfer_complete(ctrl, call, 0);
}
if (new_subaddress
|| (party_id.subaddress.valid && (new_name || new_number))) {
q931_subaddress_transfer(ctrl, call);
}
break;
default:
break;
......
This diff is collapsed.
......@@ -221,6 +221,8 @@ int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const
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);
int send_call_transfer_complete(struct pri *pri, q931_call *call, int call_status);
int rose_request_subaddress_encode(struct pri *ctrl, struct q931_call *call);
int send_subaddress_transfer(struct pri *ctrl, struct q931_call *call);
int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call);
int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype);
......
......@@ -950,6 +950,8 @@ 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_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number);
int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call);
int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
struct pri_cc_record *pri_cc_find_by_reference(struct pri *ctrl, unsigned reference_id);
......
......@@ -935,6 +935,31 @@ int q931_party_id_presentation(const struct q931_party_id *id)
return number_value | number_screening;
}
/*!
* \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
*
* \param call Starting Q.931 call record of search.
*
* \retval winning-call or given call if not outboundbroadcast.
* \retval NULL if no winning call yet.
*/
struct q931_call *q931_find_winning_call(struct q931_call *call)
{
struct q931_call *master;
master = call->master_call;
if (master->outboundbroadcast) {
/* We have potential subcalls. Now get the winning call if declared yet. */
if (master->pri_winner < 0) {
/* Winner not declared yet.*/
call = NULL;
} else {
call = master->subcalls[master->pri_winner];
}
}
return call;
}
/*!
* \internal
* \brief Append the given ie contents to the save ie location.
......@@ -4733,6 +4758,88 @@ int q931_facility(struct pri*ctrl, q931_call *c)
return send_message(ctrl, c, Q931_FACILITY, facility_ies);
}
static int facility_notify_ies[] = {
Q931_IE_FACILITY,
Q931_IE_NOTIFY_IND,
Q931_IE_REDIRECTION_NUMBER,
-1
};
/*!
* \brief Send a FACILITY RequestSubaddress with optional redirection number.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg
* \param notify Notification indicator
* \param number Redirection number to send if not NULL.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int q931_request_subaddress(struct pri *ctrl, struct q931_call *call, int notify, const struct q931_party_number *number)
{
struct q931_call *winner;
winner = q931_find_winning_call(call);
if (!winner) {
return -1;
}
if (number) {
winner->redirection_number = *number;
} else {
q931_party_number_init(&winner->redirection_number);
}
winner->notify = notify;
if (rose_request_subaddress_encode(ctrl, winner)
|| send_message(ctrl, winner, Q931_FACILITY, facility_notify_ies)) {
pri_message(ctrl,
"Could not schedule facility message for request subaddress.\n");
return -1;
}
return 0;
}
/*!
* \brief Send a FACILITY SubaddressTransfer to all parties.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg
*
* \retval 0 on success.
* \retval -1 on error.
*/
int q931_subaddress_transfer(struct pri *ctrl, struct q931_call *call)
{
int status;
unsigned idx;
struct q931_call *subcall;
if (call->outboundbroadcast && call->master_call == call) {
status = 0;
for (idx = 0; idx < ARRAY_LEN(call->subcalls); ++idx) {
subcall = call->subcalls[idx];
if (subcall) {
/* Send to all subcalls that have given a positive response. */
switch (subcall->ourcallstate) {
case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
case Q931_CALL_STATE_CALL_DELIVERED:
case Q931_CALL_STATE_ACTIVE:
if (send_subaddress_transfer(ctrl, subcall)) {
status = -1;
}
break;
default:
break;
}
}
}
} else {
status = send_subaddress_transfer(ctrl, call);
}
return status;
}
static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_IE_REDIRECTION_NUMBER, -1 };
/*!
......@@ -5493,31 +5600,6 @@ static int q931_release_complete(struct pri *ctrl, q931_call *c, int cause)
return res;
}
/*!
* \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
*
* \param call Starting Q.931 call record of search.
*
* \retval winning-call or given call if not outboundbroadcast.
* \retval NULL if no winning call yet.
*/
struct q931_call *q931_find_winning_call(struct q931_call *call)
{
struct q931_call *master;
master = call->master_call;
if (master->outboundbroadcast) {
/* We have potential subcalls. Now get the winning call if declared yet. */
if (master->pri_winner < 0) {
/* Winner not declared yet.*/
call = NULL;
} else {
call = master->subcalls[master->pri_winner];
}
}
return call;
}
static int connect_ack_ies[] = { -1 };
static int connect_ack_w_chan_id_ies[] = { Q931_CHANNEL_IDENT, -1 };
static int gr303_connect_ack_ies[] = { Q931_CHANNEL_IDENT, -1 };
......@@ -6312,6 +6394,8 @@ static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_ca
c->ri = -1;
break;
case Q931_FACILITY:
c->notify = -1;
q931_party_number_init(&c->redirection_number);
if (q931_is_dummy_call(c)) {
q931_party_address_init(&c->called);
}
......@@ -6412,6 +6496,7 @@ static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_ca
case Q931_SETUP_ACKNOWLEDGE:
break;
case Q931_NOTIFY:
c->notify = -1;
q931_party_number_init(&c->redirection_number);
break;
case Q931_HOLD:
......@@ -7551,6 +7636,7 @@ static struct q931_call *q931_find_held_call(struct pri *ctrl, struct q931_call
static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand)
{
int res;
int changed;
struct apdu_event *cur = NULL;
struct pri_subcommand *subcmd;
struct q931_call *master_call;
......@@ -8127,6 +8213,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
return Q931_RES_HAVEEVENT;
case Q931_NOTIFY:
res = 0;
changed = 0;
switch (c->notify) {
case PRI_NOTIFY_CALL_DIVERTING:
if (c->redirection_number.valid) {
......@@ -8159,13 +8246,29 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
res = Q931_RES_HAVEEVENT;
}
break;
case PRI_NOTIFY_TRANSFER_ALERTING:
case PRI_NOTIFY_TRANSFER_ACTIVE:
if (q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) {
/* The remote party number information changed. */
c->remote_id.number = c->redirection_number;
changed = 1;
}
/* Fall through */
case PRI_NOTIFY_TRANSFER_ALERTING:
if (c->redirection_number.valid
&& q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) {
/* The remote party information changed. */
/* The remote party number information changed. */
c->remote_id.number = c->redirection_number;
changed = 1;
}
if (c->remote_id.subaddress.valid) {
/*
* Clear the subaddress as the remote party has been changed.
* Any new subaddress will arrive later.
*/
q931_party_subaddress_init(&c->remote_id.subaddress);
changed = 1;
}
if (changed) {
/* Setup connected line subcommand */
subcmd = q931_alloc_subcommand(ctrl);
if (subcmd) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment