diff --git a/apps/app_dial.c b/apps/app_dial.c index 249c0dcb81..92000abdef 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -937,7 +937,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_verb(3, "%s answered %s\n", c->name, in->name); if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { if (o->connected.id.number) { - ast_channel_update_connected_line(in, &o->connected); + if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { + ast_channel_update_connected_line(in, &o->connected); + } } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) { ast_channel_lock(c); ast_connected_line_copy_from_caller(&connected_caller, &c->cid); @@ -987,7 +989,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_verb(3, "%s answered %s\n", c->name, in->name); if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { if (o->connected.id.number) { - ast_channel_update_connected_line(in, &o->connected); + if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { + ast_channel_update_connected_line(in, &o->connected); + } } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) { ast_channel_lock(c); ast_connected_line_copy_from_caller(&connected_caller, &c->cid); @@ -1076,8 +1080,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_party_connected_line_set(&o->connected, &connected); ast_party_connected_line_free(&connected); } else { - ast_verb(3, "%s connected line has changed, passing it to %s\n", c->name, in->name); - ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); + if (ast_channel_connected_line_macro(c, in, f, 1, 1)) { + ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); + } } break; case AST_CONTROL_REDIRECTING: @@ -1198,15 +1203,19 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, if (ast_write(outgoing->chan, f)) ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n"); } - if (single && (f->frametype == AST_FRAME_CONTROL) && - ((f->subclass == AST_CONTROL_HOLD) || - (f->subclass == AST_CONTROL_UNHOLD) || - (f->subclass == AST_CONTROL_VIDUPDATE) || - (f->subclass == AST_CONTROL_SRCUPDATE) || - (f->subclass == AST_CONTROL_CONNECTED_LINE) || - (f->subclass == AST_CONTROL_REDIRECTING))) { - ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); - ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); + if (single && (f->frametype == AST_FRAME_CONTROL)) { + if ((f->subclass == AST_CONTROL_HOLD) || + (f->subclass == AST_CONTROL_UNHOLD) || + (f->subclass == AST_CONTROL_VIDUPDATE) || + (f->subclass == AST_CONTROL_SRCUPDATE) || + (f->subclass == AST_CONTROL_REDIRECTING)) { + ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); + ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); + } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) { + if (ast_channel_connected_line_macro(in, outgoing->chan, f, 0, 1)) { + ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); + } + } } ast_frfree(f); } diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c index 2696b44405..2e196a7d8f 100644 --- a/apps/app_directed_pickup.c +++ b/apps/app_directed_pickup.c @@ -98,7 +98,9 @@ static int pickup_do(struct ast_channel *chan, struct ast_channel *target) connected_caller = target->connected; connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; - ast_channel_update_connected_line(chan, &connected_caller); + if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { + ast_channel_update_connected_line(chan, &connected_caller); + } ast_channel_lock(chan); ast_connected_line_copy_from_caller(&connected_caller, &chan->cid); diff --git a/apps/app_macro.c b/apps/app_macro.c index 1db3b27a8d..f3a6b546e2 100644 --- a/apps/app_macro.c +++ b/apps/app_macro.c @@ -36,6 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/config.h" #include "asterisk/utils.h" #include "asterisk/lock.h" +#include "asterisk/app.h" /*** DOCUMENTATION diff --git a/apps/app_queue.c b/apps/app_queue.c index 3467947768..3d367f6630 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -3092,7 +3092,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); if (update_connectedline) { if (o->connected.id.number) { - ast_channel_update_connected_line(in, &o->connected); + if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { + ast_channel_update_connected_line(in, &o->connected); + } } else if (o->update_connectedline) { ast_channel_lock(o->chan); ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid); @@ -3192,7 +3194,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); if (update_connectedline) { if (o->connected.id.number) { - ast_channel_update_connected_line(in, &o->connected); + if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { + ast_channel_update_connected_line(in, &o->connected); + } } else if (o->update_connectedline) { ast_channel_lock(o->chan); ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid); @@ -3252,8 +3256,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_party_connected_line_set(&o->connected, &connected); ast_party_connected_line_free(&connected); } else { - ast_verb(3, "%s connected line has changed, passing it to %s\n", ochan_name, inchan_name); - ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); + if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { + ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); + } } break; case AST_CONTROL_REDIRECTING: diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 9de5626305..0913438d44 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -20407,6 +20407,8 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * /* Chan 2: Call from Asterisk to target */ int res = 0; struct sip_pvt *targetcall_pvt; + struct ast_party_connected_line connected_to_transferee; + struct ast_party_connected_line connected_to_target; /* Check if the call ID of the replaces header does exist locally */ if (!(targetcall_pvt = get_sip_pvt_byid_locked(transferer->refer->replaces_callid, transferer->refer->replaces_callid_totag, @@ -20474,6 +20476,13 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * transferer->callid, target.chan1->name, target.chan1->uniqueid); + ast_party_connected_line_init(&connected_to_transferee); + ast_party_connected_line_init(&connected_to_target); + /* No need to lock current->chan1 here since it was locked in sipsock_read */ + ast_party_connected_line_copy(&connected_to_transferee, ¤t->chan1->connected); + /* No need to lock target.chan1 here since it was locked in get_sip_pvt_byid_locked */ + ast_party_connected_line_copy(&connected_to_target, &target.chan1->connected); + connected_to_target.source = connected_to_transferee.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; res = attempt_transfer(current, &target); sip_pvt_unlock(targetcall_pvt); if (res) { @@ -20484,8 +20493,6 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * ast_channel_unlock(targetcall_pvt->owner); ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER); } else { - struct ast_party_connected_line connected_caller; - /* Transfer succeeded! */ const char *xfersound = pbx_builtin_getvar_helper(target.chan1, "ATTENDED_TRANSFER_COMPLETE_SOUND"); @@ -20501,45 +20508,29 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * ast_channel_unlock(targetcall_pvt->owner); } - ast_party_connected_line_init(&connected_caller); + /* By forcing the masquerade, we know that target.chan1 and target.chan2 are bridged. We then + * can queue connected line updates where they need to go. + * + * No need to lock target.chan1 here since it was previously locked in get_sip_pvt_byid_locked + */ + if (target.chan1->masq) { + /* If the channel thread already did the masquerade, then we don't need to do anything */ + ast_do_masquerade(target.chan1); + } if (target.chan2) { - if (current->chan2) { - /* Tell each of the other channels to whom they are now connected */ - ast_channel_lock(current->chan2); - ast_connected_line_copy_from_caller(&connected_caller, ¤t->chan2->cid); - ast_channel_unlock(current->chan2); - connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_update_connected_line(target.chan2, &connected_caller); - ast_channel_lock(target.chan2); - ast_connected_line_copy_from_caller(&connected_caller, &target.chan2->cid); - ast_channel_unlock(target.chan2); - connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_update_connected_line(current->chan2, &connected_caller); - ast_party_connected_line_free(&connected_caller); - } + ast_channel_queue_connected_line_update(target.chan1, &connected_to_transferee); + ast_channel_queue_connected_line_update(target.chan2, &connected_to_target); } else { - /* Notify the first other party that they are connected to someone else assuming that target.chan1 - has progressed far enough through the dialplan to have its called party information set. */ - if (current->chan2) { - ast_channel_lock(target.chan1); - ast_party_connected_line_copy(&connected_caller, &target.chan1->connected); - ast_channel_unlock(target.chan1); - connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_update_connected_line(current->chan2, &connected_caller); - ast_party_connected_line_free(&connected_caller); - } - - /* We can't indicate to the called channel directly so we force the masquerade to complete - and queue and update to be read and passed-through */ - ast_channel_lock(target.chan1); - ast_do_masquerade(target.chan1); - ast_channel_unlock(target.chan1); - - ast_party_connected_line_collect_caller(&connected_caller, &target.chan1->cid); - connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_queue_connected_line_update(target.chan1, &connected_caller); + /* Since target.chan1 isn't actually connected to another channel, there is no way for us + * to queue a frame so that its connected line status will be updated. Instead, we have to + * change it directly. Since we are not the channel thread, we cannot run a connected line + * interception macro on target.chan1 + */ + ast_channel_update_connected_line(target.chan1, &connected_to_target); } } + ast_party_connected_line_free(&connected_to_target); + ast_party_connected_line_free(&connected_to_transferee); if (targetcall_pvt) ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt"); return 1; diff --git a/doc/tex/channelvariables.tex b/doc/tex/channelvariables.tex index 0a7e810226..6b549ef9d4 100644 --- a/doc/tex/channelvariables.tex +++ b/doc/tex/channelvariables.tex @@ -1005,3 +1005,10 @@ ${OSPOUTTOKEN} OSP token to use for out_bound call ${OSPOUTTIMELIMIT} Duration limit for out_bound call ${OSPRESULTS} Number of remained destinations \end{verbatim} + +\subsection{Connected line digit manipulation} +\begin{verbatim} +${CONNECTED_LINE_SEND_CALLEE_MACRO} Macro to call before sending a connected line update to the callee +${CONNECTED_LINE_SEND_CALLEE_MACRO_ARGS} Arguments to pass to ${CONNECTED_LINE_SEND_CALLEE_MACRO} +${CONNECTED_LINE_SEND_CALLER_MACRO} Macro to call before sending a connected line update to the caller +${CONNECTED_LINE_SEND_CALLER_MACRO_ARGS} Arguments to pass to ${CONNECTED_LINE_SEND_CALLER_MACRO} diff --git a/include/asterisk/app.h b/include/asterisk/app.h index d442e5292f..da947b5d71 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -108,6 +108,26 @@ int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxl /*! \brief Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions */ int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd); +/*! + * \since 1.6.3 + * \brief Run a macro on a channel, placing a second channel into autoservice. + * + * This is a shorthand method that makes it very easy to run a macro on any given + * channel. It is perfectly reasonable to supply a NULL autoservice_chan here in case + * there is no channel to place into autoservice. It is very important that the + * autoservice_chan parameter is not locked prior to calling ast_app_run_macro. A + * deadlock could result, otherwise. + * + * \param autoservice_chan A channel to place into autoservice while the macro is run + * \param macro_chan The channel to run the macro on + * \param macro_name The name of the macro to run + * \param macro_args The arguments to pass to the macro + * \retval 0 success + * \retval -1 failure + */ +int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel + *macro_chan, const char * const macro_name, const char * const macro_args); + /*! * \brief Set voicemail function callbacks * \param[in] inboxcount2_func set function pointer diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 193d0ff34a..6bfb7b6d51 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -2550,6 +2550,34 @@ void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_p */ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting); +/*! + * \since 1.6.3 + * \brief Run a connected line interception macro and update a channel's connected line + * information + * + * Whenever we want to update a channel's connected line information, we may need to run + * a macro so that an administrator can manipulate the information before sending it + * out. This function both runs the macro and sends the update to the channel. + * + * \param autoservice_chan Channel to place into autoservice while the macro is running. + * It is perfectly safe for this to be NULL + * \param macro_chan The channel to run the macro on. Also the channel from which we + * determine which macro we need to run. + * \param connected_info Either an ast_party_connected_line or ast_frame pointer of type + * AST_CONTROL_CONNECTED_LINE + * \param caller If true, then run CONNECTED_LINE_CALLER_SEND_MACRO, otherwise run + * CONNECTED_LINE_CALLEE_SEND_MACRO + * \param frame If true, then connected_info is an ast_frame pointer, otherwise it is an + * ast_party_connected_line pointer. + * \retval 0 Success + * \retval -1 Either the macro does not exist, or there was an error while attempting to + * run the macro + * + * \todo Have multiple return codes based on the MACRO_RESULT + * \todo Make constants so that caller and frame can be more expressive than just '1' and + * '0' + */ +int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame); #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/app.c b/main/app.c index 72af3e085e..eacefabd06 100644 --- a/main/app.c +++ b/main/app.c @@ -203,6 +203,28 @@ int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int return res; } +int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char * const macro_name, const char * const macro_args) +{ + struct ast_app *macro_app; + int res; + char buf[1024]; + + macro_app = pbx_findapp("Macro"); + if (!macro_app) { + ast_log(LOG_WARNING, "Cannot run macro '%s' because the 'Macro' application in not available\n", macro_name); + return -1; + } + snprintf(buf, sizeof(buf), "%s%s%s", macro_name, ast_strlen_zero(macro_args) ? "" : ",", S_OR(macro_args, "")); + if (autoservice_chan) { + ast_autoservice_start(autoservice_chan); + } + res = pbx_exec(macro_chan, macro_app, buf); + if (autoservice_chan) { + ast_autoservice_stop(autoservice_chan); + } + return res; +} + static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL; static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL; static int (*ast_inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) = NULL; diff --git a/main/channel.c b/main/channel.c index bd997def62..d9ce2efbf4 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5008,13 +5008,19 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct int bridge_exit = 0; switch (f->subclass) { + case AST_CONTROL_REDIRECTING: + ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); + break; + case AST_CONTROL_CONNECTED_LINE: + if (ast_channel_connected_line_macro(who, other, f, other == c0, 1)) { + ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); + } + break; case AST_CONTROL_HOLD: case AST_CONTROL_UNHOLD: case AST_CONTROL_VIDUPDATE: case AST_CONTROL_T38: case AST_CONTROL_SRCUPDATE: - case AST_CONTROL_CONNECTED_LINE: - case AST_CONTROL_REDIRECTING: ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); if (jb_in_use) { ast_jb_empty_and_reset(c0, c1); @@ -6503,6 +6509,44 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen); } +int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame) +{ + const char *macro; + const char *macro_args; + union { + const struct ast_frame *frame; + const struct ast_party_connected_line *connected; + } pointer; + int retval; + + if (frame) { + pointer.frame = connected_info; + } else { + pointer.connected = connected_info; + } + + ast_channel_lock(macro_chan); + macro = ast_strdupa(S_OR(pbx_builtin_getvar_helper(macro_chan, caller ? "CONNECTED_LINE_CALLER_SEND_MACRO" : "CONNECTED_LINE_CALLEE_SEND_MACRO"), "")); + macro_args = ast_strdupa(S_OR(pbx_builtin_getvar_helper(macro_chan, caller ? "CONNECTED_LINE_CALLER_SEND_MACRO_ARGS" : "CONNECTED_LINE_CALLEE_SEND_MACRO_ARGS"), "")); + ast_channel_unlock(macro_chan); + + if (ast_strlen_zero(macro)) { + return -1; + } + + if (frame) { + ast_connected_line_parse_data(pointer.frame->data.ptr, pointer.frame->datalen, ¯o_chan->connected); + } else { + ast_party_connected_line_copy(¯o_chan->connected, pointer.connected); + } + + if (!(retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args))) { + ast_channel_update_connected_line(macro_chan, ¯o_chan->connected); + } + + return retval; +} + /* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY * * ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE diff --git a/main/dial.c b/main/dial.c index d38b4829d8..1f65f50c76 100644 --- a/main/dial.c +++ b/main/dial.c @@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/dial.h" #include "asterisk/pbx.h" #include "asterisk/musiconhold.h" +#include "asterisk/app.h" /*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */ struct ast_dial { @@ -430,7 +431,9 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel break; case AST_CONTROL_CONNECTED_LINE: ast_verb(3, "%s connected line has changed, passing it to %s\n", channel->owner->name, chan->name); - ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, fr->data.ptr, fr->datalen); + if (ast_channel_connected_line_macro(channel->owner, chan, fr, 1, 1)) { + ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, fr->data.ptr, fr->datalen); + } break; case AST_CONTROL_REDIRECTING: ast_verb(3, "%s redirecting info has changed, passing it to %s\n", channel->owner->name, chan->name); diff --git a/main/features.c b/main/features.c index 6e3570e633..6c15f258dc 100644 --- a/main/features.c +++ b/main/features.c @@ -1377,6 +1377,9 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p /* Set the channel's new extension, since it exists, using transferer context */ ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name); + if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) { + ast_channel_update_connected_line(transferee, &transferer->connected); + } set_c_e_p(transferee, transferer_real_context, xferto, 0); } check_goto_on_transfer(transferer); @@ -1635,13 +1638,43 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st /* Due to a limitation regarding when callerID is set on a Local channel, * we use the transferer's connected line information here. */ + + /* xferchan is transferee, and newchan is the transfer target + * So...in a transfer, who is the caller and who is the callee? + * + * When the call is originally made, it is clear who is caller and callee. + * When a transfer occurs, it is my humble opinion that the transferee becomes + * the caller, and the transfer target is the callee. + * + * The problem is that these macros were set with the intention of the original + * caller and callee taking those roles. A transfer can totally mess things up, + * to be technical. What sucks even more is that you can't effectively change + * the macros in the dialplan during the call from the transferer to the transfer + * target because the transferee is stuck with whatever role he originally had. + * + * I think the answer here is just to make sure that it is well documented that + * during a transfer, the transferee is the "caller" and the transfer target + * is the "callee." + * + * This means that if party A calls party B, and party A transfers party B to + * party C, then B has switched roles for the call. Now party B will have the + * caller macro called on his channel instead of the callee macro. + * + * Luckily, the method by which the bridge is launched here ensures that the + * transferee is the "chan" on the bridge and the transfer target is the "peer," + * so my idea for the roles post-transfer does not require extensive code changes. + */ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_update_connected_line(xferchan, &connected_line); + if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { + ast_channel_update_connected_line(xferchan, &connected_line); + } ast_channel_lock(xferchan); ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid); ast_channel_unlock(xferchan); connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_update_connected_line(newchan, &connected_line); + if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { + ast_channel_update_connected_line(newchan, &connected_line); + } ast_party_connected_line_free(&connected_line); if (ast_stream_and_wait(newchan, xfersound, "")) @@ -1749,12 +1782,16 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st ast_connected_line_copy_from_caller(&connected_line, &newchan->cid); ast_channel_unlock(newchan); connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_update_connected_line(xferchan, &connected_line); + if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { + ast_channel_update_connected_line(xferchan, &connected_line); + } ast_channel_lock(xferchan); ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid); ast_channel_unlock(xferchan); connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - ast_channel_update_connected_line(newchan, &connected_line); + if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { + ast_channel_update_connected_line(newchan, &connected_line); + } ast_party_connected_line_free(&connected_line); @@ -2370,7 +2407,9 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, ready=1; break; } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) { - ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); + if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { + ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); + } } else if (f->subclass != -1) { ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); } @@ -2766,9 +2805,13 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast case -1: ast_indicate(other, f->subclass); break; + case AST_CONTROL_CONNECTED_LINE: + if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { + break; + } + /* The implied "else" falls through purposely */ case AST_CONTROL_HOLD: case AST_CONTROL_UNHOLD: - case AST_CONTROL_CONNECTED_LINE: ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); break; case AST_CONTROL_OPTION: @@ -4546,7 +4589,9 @@ int ast_pickup_call(struct ast_channel *chan) connected_caller = cur->connected; connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; - ast_channel_update_connected_line(chan, &connected_caller); + if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { + ast_channel_update_connected_line(chan, &connected_caller); + } ast_party_connected_line_collect_caller(&connected_caller, &chan->cid); connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;