aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authorrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2010-11-09 16:55:32 +0000
committerrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2010-11-09 16:55:32 +0000
commit89fdc4f316990d60c22d21f8fd5885a49d710c57 (patch)
tree85627bda8a8f48ade72ef64c8f71c74618258edc /channels
parent3f17f7ce08f9b3783e09ec2e23779f55803ffc4a (diff)
Analog lines do not transfer CONNECTED LINE or execute the interception macros.
Add connected line update for sig_analog transfers and simplify the corresponding sig_pri and chan_misdn transfer code. Note that if you create a three-way call in sig_analog before transferring the call, the distinction of the caller/callee interception macros make little sense. The interception macro writer needs to be prepared for either caller/callee macro to be executed. The current implementation swaps which caller/callee interception macro is executed after a three-way call is created. Review: https://reviewboard.asterisk.org/r/996/ JIRA ABE-2589 JIRA SWP-2372 git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.8@294349 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_misdn.c118
-rw-r--r--channels/sig_analog.c134
-rw-r--r--channels/sig_pri.c165
3 files changed, 96 insertions, 321 deletions
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index a47d1aa7d..fe8033383 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -8504,40 +8504,6 @@ static void release_chan_early(struct chan_list *ch)
/*!
* \internal
- * \brief Copy the source connected line information to the destination for a transfer.
- * \since 1.8
- *
- * \param dest Destination connected line
- * \param src Source connected line
- *
- * \return Nothing
- */
-static void misdn_connected_line_copy_transfer(struct ast_party_connected_line *dest, struct ast_party_connected_line *src)
-{
- struct ast_party_connected_line connected;
-
- connected = *src;
- connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-
- /* Make sure empty strings will be erased. */
- if (!connected.id.name.str) {
- connected.id.name.str = "";
- }
- if (!connected.id.number.str) {
- connected.id.number.str = "";
- }
- if (!connected.id.subaddress.str) {
- connected.id.subaddress.str = "";
- }
- if (!connected.id.tag) {
- connected.id.tag = "";
- }
-
- ast_party_connected_line_copy(dest, &connected);
-}
-
-/*!
- * \internal
* \brief Attempt to transfer the active channel party to the held channel party.
*
* \param active_ch Channel currently connected.
@@ -8585,95 +8551,35 @@ static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list
held_ch->ast->name, target->name);
ast_party_connected_line_init(&target_colp);
- misdn_connected_line_copy_transfer(&target_colp, &target->connected);
+ ast_party_connected_line_copy(&target_colp, &target->connected);
ast_party_connected_line_init(&transferee_colp);
- misdn_connected_line_copy_transfer(&transferee_colp, &held_ch->ast->connected);
+ ast_party_connected_line_copy(&transferee_colp, &held_ch->ast->connected);
held_ch->hold.state = MISDN_HOLD_TRANSFER;
/*
* Before starting a masquerade, all channel and pvt locks must
* be unlocked. Any recursive channel locks held before
- * ast_channel_masquerade() invalidates deadlock avoidance. Any
- * recursive channel locks held before ast_do_masquerade()
- * invalidates channel container locking order. Since we are
- * unlocking both the pvt and its owner channel it is possible
- * for "target" and "transferee" to be destroyed by their pbx
- * threads. To prevent this we must give "target" and
- * "transferee" a reference before any unlocking takes place.
+ * ast_channel_transfer_masquerade() invalidates deadlock
+ * avoidance. Since we are unlocking both the pvt and its owner
+ * channel it is possible for "target" and "transferee" to be
+ * destroyed by their pbx threads. To prevent this we must give
+ * "target" and "transferee" a reference before any unlocking
+ * takes place.
*/
ao2_ref(target, +1);
ao2_ref(transferee, +1);
ast_channel_unlock(held_ch->ast);
ast_channel_unlock(active_ch->ast);
- /* Release hold on the transferee channel. */
- ast_indicate(transferee, AST_CONTROL_UNHOLD);
-
/* Setup transfer masquerade. */
- retval = ast_channel_masquerade(target, transferee);
- if (retval) {
- /* Masquerade setup failed. */
- ast_party_connected_line_free(&target_colp);
- ast_party_connected_line_free(&transferee_colp);
- ao2_ref(target, -1);
- ao2_ref(transferee, -1);
- return -1;
- }
- ao2_ref(transferee, -1);
-
- /*
- * Make sure masquerade is complete.
- *
- * After the masquerade, the "target" channel pointer actually
- * points to the new transferee channel and the bridged channel
- * is still the intended target of the transfer.
- *
- * By manually completing the masquerade, we can send connected
- * line updates where they need to go.
- */
- ast_do_masquerade(target);
-
- /* Transfer COLP between target and transferee channels. */
- {
- /*
- * Since "target" may not actually be bridged to another
- * channel, there is no way for us to queue a frame so that its
- * connected line status will be updated. Instead, we use the
- * somewhat hackish approach of using a special control frame
- * type that instructs ast_read() to perform a specific action.
- * In this case, the frame we queue tells ast_read() to call the
- * connected line interception macro configured for "target".
- */
- struct ast_control_read_action_payload *frame_payload;
- int payload_size;
- int frame_size;
- unsigned char connected_line_data[1024];
-
- payload_size = ast_connected_line_build_data(connected_line_data,
- sizeof(connected_line_data), &target_colp, NULL);
- if (payload_size != -1) {
- frame_size = payload_size + sizeof(*frame_payload);
- frame_payload = alloca(frame_size);
- frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
- frame_payload->payload_size = payload_size;
- memcpy(frame_payload->payload, connected_line_data, payload_size);
- ast_queue_control_data(target, AST_CONTROL_READ_ACTION, frame_payload,
- frame_size);
- }
- /*
- * In addition to queueing the read action frame so that the
- * connected line info on "target" will be updated, we also
- * are going to queue a plain old connected line update on
- * "target" to update the target channel.
- */
- ast_channel_queue_connected_line_update(target, &transferee_colp, NULL);
- }
+ retval = ast_channel_transfer_masquerade(target, &target_colp, 0,
+ transferee, &transferee_colp, 1);
ast_party_connected_line_free(&target_colp);
ast_party_connected_line_free(&transferee_colp);
-
ao2_ref(target, -1);
- return 0;
+ ao2_ref(transferee, -1);
+ return retval;
}
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 30a1de47d..ac1723ebc 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -652,6 +652,7 @@ static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
* \brief Attempt to transfer 3-way call.
*
* \param p Analog private structure.
+ * \param inthreeway TRUE if the 3-way call is conferenced.
*
* \note
* On entry these locks are held: real-call, private, 3-way call.
@@ -661,74 +662,77 @@ static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
* \retval 0 Transfer successful. 3-way call is unlocked and subchannel is unalloced.
* \retval -1 on error. Caller must unlock 3-way call.
*/
-static int analog_attempt_transfer(struct analog_pvt *p)
-{
- /* In order to transfer, we need at least one of the channels to
- actually be in a call bridge. We can't conference two applications
- together (but then, why would we want to?) */
- if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
- /* The three-way person we're about to transfer to could still be in MOH, so
- stop it now if appropriate */
- if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
- ast_queue_control(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
- }
- if (p->subs[ANALOG_SUB_REAL].owner->_state == AST_STATE_RINGING) {
- /*
- * This may not be safe.
- * We currently hold the locks on the real-call, private, and 3-way call.
- * We could possibly avoid this here by using an ast_queue_control() instead.
- * However, the following ast_channel_masquerade() is going to be locking
- * the bridged channel again anyway.
- */
- ast_indicate(ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner), AST_CONTROL_RINGING);
- }
- if (p->subs[ANALOG_SUB_THREEWAY].owner->_state == AST_STATE_RING) {
- analog_play_tone(p, ANALOG_SUB_THREEWAY, ANALOG_TONE_RINGTONE);
- }
- if (!p->subs[ANALOG_SUB_THREEWAY].inthreeway) {
- ast_cel_report_event(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CEL_ATTENDEDTRANSFER, NULL, p->subs[ANALOG_SUB_THREEWAY].owner->linkedid, NULL);
- }
- if (ast_channel_masquerade(p->subs[ANALOG_SUB_THREEWAY].owner, ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner))) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)->name, p->subs[ANALOG_SUB_THREEWAY].owner->name);
- return -1;
- }
- /* Orphan the channel after releasing the lock */
- ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
- analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
- } else if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
- ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
- if (p->subs[ANALOG_SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
- /*
- * This may not be safe.
- * We currently hold the locks on the real-call, private, and 3-way call.
- * We could possibly avoid this here by using an ast_queue_control() instead.
- * However, the following ast_channel_masquerade() is going to be locking
- * the bridged channel again anyway.
- */
- ast_indicate(ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), AST_CONTROL_RINGING);
- }
- if (p->subs[ANALOG_SUB_REAL].owner->_state == AST_STATE_RING) {
- analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
- }
- ast_cel_report_event(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CEL_BLINDTRANSFER, NULL, p->subs[ANALOG_SUB_THREEWAY].owner->linkedid, NULL);
- if (ast_channel_masquerade(p->subs[ANALOG_SUB_REAL].owner, ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner))) {
+static int analog_attempt_transfer(struct analog_pvt *p, int inthreeway)
+{
+ struct ast_channel *owner_real;
+ struct ast_channel *owner_3way;
+ struct ast_channel *bridge_real;
+ struct ast_channel *bridge_3way;
+
+ owner_real = p->subs[ANALOG_SUB_REAL].owner;
+ owner_3way = p->subs[ANALOG_SUB_THREEWAY].owner;
+ bridge_real = ast_bridged_channel(owner_real);
+ bridge_3way = ast_bridged_channel(owner_3way);
+
+ /*
+ * In order to transfer, we need at least one of the channels to
+ * actually be in a call bridge. We can't conference two
+ * applications together. Why would we want to?
+ */
+ if (bridge_3way) {
+ ast_verb(3, "TRANSFERRING %s to %s\n", owner_3way->name, owner_real->name);
+ ast_cel_report_event(owner_3way,
+ (owner_real->_state == AST_STATE_RINGING
+ || owner_3way->_state == AST_STATE_RINGING)
+ ? AST_CEL_BLINDTRANSFER : AST_CEL_ATTENDEDTRANSFER,
+ NULL, owner_3way->linkedid, NULL);
+
+ /*
+ * The three-way party we're about to transfer is on hold if he
+ * is not in a three way conference.
+ */
+ if (ast_channel_transfer_masquerade(owner_real, &owner_real->connected, 0,
+ bridge_3way, &owner_3way->connected, !inthreeway)) {
ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)->name, p->subs[ANALOG_SUB_REAL].owner->name);
+ bridge_3way->name, owner_real->name);
return -1;
}
+
/* Three-way is now the REAL */
analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
- ast_channel_unlock(p->subs[ANALOG_SUB_REAL].owner); /* unlock REAL because THREEWAY has become REAL */
+ ast_channel_unlock(owner_3way);
analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
/* Tell the caller not to hangup */
return 1;
+ } else if (bridge_real) {
+ /* Try transferring the other way. */
+ ast_verb(3, "TRANSFERRING %s to %s\n", owner_real->name, owner_3way->name);
+ ast_cel_report_event(owner_3way,
+ (owner_real->_state == AST_STATE_RINGING
+ || owner_3way->_state == AST_STATE_RINGING)
+ ? AST_CEL_BLINDTRANSFER : AST_CEL_ATTENDEDTRANSFER,
+ NULL, owner_3way->linkedid, NULL);
+
+ /*
+ * The three-way party we're about to transfer is on hold if he
+ * is not in a three way conference.
+ */
+ if (ast_channel_transfer_masquerade(owner_3way, &owner_3way->connected,
+ !inthreeway, bridge_real, &owner_real->connected, 0)) {
+ ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
+ bridge_real->name, owner_3way->name);
+ return -1;
+ }
+
+ /* Orphan the channel after releasing the lock */
+ ast_channel_unlock(owner_3way);
+ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
+ return 0;
} else {
ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
- p->subs[ANALOG_SUB_REAL].owner->name, p->subs[ANALOG_SUB_THREEWAY].owner->name);
+ owner_real->name, owner_3way->name);
return -1;
}
- return 0;
}
static int analog_update_conf(struct analog_pvt *p)
@@ -2741,6 +2745,14 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
} else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
if (p->transfer) {
+ int inthreeway;
+
+ inthreeway = p->subs[ANALOG_SUB_THREEWAY].inthreeway;
+
+ /* In any case this isn't a threeway call anymore */
+ analog_set_inthreeway(p, ANALOG_SUB_REAL, 0);
+ analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
+
/* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
/* Swap subs and dis-own channel */
@@ -2751,29 +2763,21 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
/* Ring the phone */
analog_ring(p);
} else {
- res = analog_attempt_transfer(p);
+ res = analog_attempt_transfer(p, inthreeway);
if (res < 0) {
/* Transfer attempt failed. */
ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
} else if (res) {
- /* this isn't a threeway call anymore */
- analog_set_inthreeway(p, ANALOG_SUB_REAL, 0);
- analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
-
/* Don't actually hang up at this point */
break;
}
}
- /* this isn't a threeway call anymore */
- analog_set_inthreeway(p, ANALOG_SUB_REAL, 0);
- analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
} else {
ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
}
} else {
- ast_cel_report_event(ast, AST_CEL_BLINDTRANSFER, NULL, ast->linkedid, NULL);
/* Swap subs and dis-own channel */
analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
/* Unlock the 3-way call that we swapped to real-call. */
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index fa73ac209..176ab5093 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -1882,42 +1882,6 @@ static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd
}
#endif /* defined(HAVE_PRI_MCID) */
-#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
-/*!
- * \internal
- * \brief Copy the source connected line information to the destination for a transfer.
- * \since 1.8
- *
- * \param dest Destination connected line
- * \param src Source connected line
- *
- * \return Nothing
- */
-static void sig_pri_connected_line_copy_transfer(struct ast_party_connected_line *dest, struct ast_party_connected_line *src)
-{
- struct ast_party_connected_line connected;
-
- connected = *src;
- connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-
- /* Make sure empty strings will be erased. */
- if (!connected.id.name.str) {
- connected.id.name.str = "";
- }
- if (!connected.id.number.str) {
- connected.id.number.str = "";
- }
- if (!connected.id.subaddress.str) {
- connected.id.subaddress.str = "";
- }
- if (!connected.id.tag) {
- connected.id.tag = "";
- }
-
- ast_party_connected_line_copy(dest, &connected);
-}
-#endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
-
#if defined(HAVE_PRI_TRANSFER)
struct xfer_rsp_data {
struct sig_pri_span *pri;
@@ -1988,16 +1952,12 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
int chanpos;
};
int retval;
- int transferee_is_held;
struct ast_channel *transferee;
struct attempt_xfer_call *call_1;
struct attempt_xfer_call *call_2;
- struct attempt_xfer_call *target;
struct attempt_xfer_call *swap_call;
struct attempt_xfer_call c1;
struct attempt_xfer_call c2;
- struct ast_party_connected_line target_colp;
- struct ast_party_connected_line transferee_colp;
c1.pri = call_1_pri;
c1.held = call_1_held;
@@ -2083,20 +2043,13 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
return -1;
}
- target = call_2;
- ast_verb(3, "TRANSFERRING %s to %s\n", call_1->ast->name, target->ast->name);
-
- ast_party_connected_line_init(&target_colp);
- sig_pri_connected_line_copy_transfer(&target_colp, &target->ast->connected);
- ast_party_connected_line_init(&transferee_colp);
- sig_pri_connected_line_copy_transfer(&transferee_colp, &call_1->ast->connected);
- transferee_is_held = call_1->held;
+ ast_verb(3, "TRANSFERRING %s to %s\n", call_1->ast->name, call_2->ast->name);
/*
* Setup transfer masquerade.
*
* Note: There is an extremely nasty deadlock avoidance issue
- * with ast_channel_masquerade(). Deadlock may be possible if
+ * with ast_channel_transfer_masquerade(). Deadlock may be possible if
* the channels involved are proxies (chan_agent channels) and
* it is called with locks. Unfortunately, there is no simple
* or even merely difficult way to guarantee deadlock avoidance
@@ -2104,45 +2057,17 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
* possibility of the bridged channel hanging up on us.
*/
ast_mutex_unlock(&pri->lock);
- retval = ast_channel_masquerade(target->ast, transferee);
- if (retval) {
- /* Masquerade setup failed. */
- ast_party_connected_line_free(&target_colp);
- ast_party_connected_line_free(&transferee_colp);
-
- ast_mutex_lock(&pri->lock);
-
- ast_channel_unlock(call_1->ast);
- ast_channel_unlock(call_2->ast);
- sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
- sig_pri_unlock_private(pri->pvts[call_2->chanpos]);
-
- if (rsp_callback) {
- /* Transfer failed. */
- rsp_callback(data, 0);
- }
- return -1;
- }
-
- /*
- * Release any hold on the transferee channel before allowing
- * the masquerade to happen.
- */
- if (transferee_is_held) {
- ast_indicate(transferee, AST_CONTROL_UNHOLD);
- }
+ retval = ast_channel_transfer_masquerade(
+ call_2->ast,
+ &call_2->ast->connected,
+ call_2->held,
+ transferee,
+ &call_1->ast->connected,
+ call_1->held);
+
+ /* Reacquire the pri->lock to hold off completion of the transfer masquerade. */
ast_mutex_lock(&pri->lock);
- /*
- * Before manually completing a masquerade, all channel and pvt
- * locks must be unlocked. Any recursive channel locks held
- * before ast_do_masquerade() invalidates channel container
- * locking order. Since we are unlocking both the pvt and its
- * owner channel it is possible for "target" to be destroyed
- * in the pbx thread. To prevent this we must give "target"
- * a reference before any unlocking takes place.
- */
- ao2_ref(target->ast, +1);
ast_channel_unlock(call_1->ast);
ast_channel_unlock(call_2->ast);
sig_pri_unlock_private(pri->pvts[call_1->chanpos]);
@@ -2150,75 +2075,15 @@ static int sig_pri_attempt_transfer(struct sig_pri_span *pri, q931_call *call_1_
if (rsp_callback) {
/*
- * Transfer successful.
+ * Report transfer status.
*
- * Must do the callback before releasing the pri->lock to ensure
+ * Must do the callback before the masquerade completes to ensure
* that the protocol message goes out before the call leg is
* disconnected.
*/
- rsp_callback(data, 1);
- }
-
- /*
- * Make sure masquerade is complete.
- *
- * After the masquerade, the "target" channel pointer actually
- * points to the new transferee channel and the bridged channel
- * is still the intended target of the transfer.
- *
- * By manually completing the masquerade, we can send the unhold
- * and connected line updates where they need to go.
- */
- ast_mutex_unlock(&pri->lock);
- ast_do_masquerade(target->ast);
-
- /* Release any hold on the target. */
- if (target->held) {
- ast_queue_control(target->ast, AST_CONTROL_UNHOLD);
- }
-
- /* Transfer COLP between target and transferee channels. */
- {
- /*
- * Since "target" may not actually be bridged to another
- * channel, there is no way for us to queue a frame so that its
- * connected line status will be updated. Instead, we use the
- * somewhat hackish approach of using a special control frame
- * type that instructs ast_read() to perform a specific action.
- * In this case, the frame we queue tells ast_read() to call the
- * connected line interception macro configured for "target".
- */
- struct ast_control_read_action_payload *frame_payload;
- int payload_size;
- int frame_size;
- unsigned char connected_line_data[1024];
-
- payload_size = ast_connected_line_build_data(connected_line_data,
- sizeof(connected_line_data), &target_colp, NULL);
- if (payload_size != -1) {
- frame_size = payload_size + sizeof(*frame_payload);
- frame_payload = alloca(frame_size);
- frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
- frame_payload->payload_size = payload_size;
- memcpy(frame_payload->payload, connected_line_data, payload_size);
- ast_queue_control_data(target->ast, AST_CONTROL_READ_ACTION, frame_payload,
- frame_size);
- }
- /*
- * In addition to queueing the read action frame so that the
- * connected line info on "target" will be updated, we also
- * are going to queue a plain old connected line update on
- * "target" to update the target channel.
- */
- ast_channel_queue_connected_line_update(target->ast, &transferee_colp, NULL);
+ rsp_callback(data, retval ? 0 : 1);
}
-
- ast_party_connected_line_free(&target_colp);
- ast_party_connected_line_free(&transferee_colp);
-
- ao2_ref(target->ast, -1);
- ast_mutex_lock(&pri->lock);
- return 0;
+ return retval;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */