]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Add the ability to execute connected line interception macros.
authorMark Michelson <mmichelson@digium.com>
Mon, 1 Jun 2009 20:57:31 +0000 (20:57 +0000)
committerMark Michelson <mmichelson@digium.com>
Mon, 1 Jun 2009 20:57:31 +0000 (20:57 +0000)
When connected line updates are received or generated in the middle
of an application call, it is now possible to execute a macro to
manipulate the connected line data. This way, phone numbers may be
manipulated to be more presentable to users, names may be changed
for...whatever reason, or whatever else needs to be done may be.

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

AST-165

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@198727 65c4cc65-6c06-0410-ace0-fbb531ad65f3

12 files changed:
apps/app_dial.c
apps/app_directed_pickup.c
apps/app_macro.c
apps/app_queue.c
channels/chan_sip.c
doc/tex/channelvariables.tex
include/asterisk/app.h
include/asterisk/channel.h
main/app.c
main/channel.c
main/dial.c
main/features.c

index 249c0dcb81ecbcbf95e61abf10f11d289535585f..92000abdef7931b8d583616d89829e4d12da0b3d 100644 (file)
@@ -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);
                }
index 2696b444053cb78a616c9c535bc7beb075320385..2e196a7d8f2a69b9cb651b064c74fe094cec4404 100644 (file)
@@ -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);
index 1db3b27a8da9de04542eef0ca9105450a75cf673..f3a6b546e23b8904366f99d6e8c68eea6542734c 100644 (file)
@@ -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
        <application name="Macro" language="en_US">
index 346794776808769cea9c36cecf66a695cc7624fe..3d367f6630a6ebe4b3e989e20d824cba77ec325a 100644 (file)
@@ -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:
index 9de5626305279835b2fa52e0cb911148783632cb..0913438d4483f4bffb58b1893a9ad5f7acad0dc4 100644 (file)
@@ -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, &current->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, &current->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;
index 0a7e81022614185e618dd3b4338cf6dca3101275..6b549ef9d46cef8c0fca52de0a90c9c9b2143ceb 100644 (file)
@@ -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}
index d442e5292f539596209ece60c2736f84f32db622..da947b5d7149a44a0fcaee87429fe28da26bb6f4 100644 (file)
@@ -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
index 193d0ff34afa6a2e97e0fc1c312c1dbdbd2e11aa..6bfb7b6d51359333ccd62cad67c8adbdf03bfb0b 100644 (file)
@@ -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
index 72af3e085e73fd957a82444ccea35af4eb16f71a..eacefabd06ca52040c23107d38b4fbbbdcf8aa1a 100644 (file)
@@ -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;
index bd997def62a1edcdf1b8b2227f205967272bb2a8..d9ce2efbf4b81b4da0d73d96c420c60f21f882aa 100644 (file)
@@ -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, &macro_chan->connected);
+       } else {
+               ast_party_connected_line_copy(&macro_chan->connected, pointer.connected);
+       }
+
+       if (!(retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args))) {
+               ast_channel_update_connected_line(macro_chan, &macro_chan->connected);
+       }
+
+       return retval;
+}
+
 /* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY
  *
  * ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE
index d38b4829d8566eaa0cc37f5056484026642cf5d6..1f65f50c76fb1a923d516f7ffecd9f1ace8233da 100644 (file)
@@ -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);
index 6e3570e6331e77b5bfd0f3a0bbd2e323beb38471..6c15f258dc35f399af5253e55dac87ad591bb8ef 100644 (file)
@@ -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;