Enhancements to connected line and redirecting work.
authorMark Michelson <mmichelson@digium.com>
Mon, 17 May 2010 15:36:31 +0000 (15:36 +0000)
committerMark Michelson <mmichelson@digium.com>
Mon, 17 May 2010 15:36:31 +0000 (15:36 +0000)
From reviewboard:

Digium has a commercial customer who has made extensive use of the connected party and
redirecting information present in later versions of Asterisk Business Edition and which
is to be in the upcoming 1.8 release. Through their use of the feature, new problems and solutions
have come about. This patch adds several enhancements to maximize usage of the connected party
and redirecting information functionality.

First, Asterisk trunk already had connected line interception macros. These macros allow you to
manipulate connected line information before it was sent out to its target. This patch adds the
same feature except for redirecting information instead.

Second, the ast_callerid and ast_party_id structures have been enhanced to provide a "tag." This
tag can be set with func_callerid, func_connectedline, func_redirecting, and in the case of DAHDI,
mISDN, and SIP channels, can be set in a configuration file. The idea behind the callerid tag is
that it can be set to whatever value the administrator likes. Later, when running connected line
and redirecting macros, the admin can read the tag off the appropriate structure to determine what
action to take. You can think of this sort of like a channel variable, except that instead of having
the variable associated with a channel, the variable is associated with a specific identity within
Asterisk.

Third, app_dial has two new options, s and u. The s option lets a dialplan writer force a specific
caller ID tag to be placed on the outgoing channel. The u option allows the dialplan writer to force
a specific calling presentation value on the outgoing channel.

Fourth, there is a new control frame subclass called AST_CONTROL_READ_ACTION added. This was added
to correct a very specific situation. In the case of SIP semi-attended (blond) transfers, the party
being transferred would not have the opportunity to run a connected line interception macro to
possibly alter the transfer target's connected line information. The issue here was that during a
blond transfer, the SIP transfer code has no bridged channel on which to queue the connected line
update. The way this was corrected was to add this new control frame subclass. Now, we queue an
AST_CONTROL_READ_ACTION frame on the channel on which the connected line interception macro should
be run. When ast_read is called to read the frame, ast_read responds by calling a callback function
associated with the specific read action the control frame describes. In this case, the action taken
is to run the connected line interception macro on the transferee's channel.

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

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

20 files changed:
apps/app_dial.c
apps/app_queue.c
channels/chan_dahdi.c
channels/chan_local.c
channels/chan_misdn.c
channels/chan_sip.c
channels/misdn/chan_misdn_config.h
channels/misdn/isdn_lib.h
channels/misdn_config.c
channels/sip/include/sip.h
configs/misdn.conf.sample
funcs/func_callerid.c
funcs/func_connectedline.c
funcs/func_redirecting.c
include/asterisk/channel.h
include/asterisk/frame.h
main/channel.c
main/dial.c
main/features.c
main/rtp_engine.c

index b1de21d..1a9ca89 100644 (file)
@@ -335,6 +335,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <para>Hang up the call <replaceable>x</replaceable> seconds <emphasis>after</emphasis> the called party has
                                        answered the call.</para>
                                </option>
+                               <option name="s">
+                                       <argument name="x" required="true" />
+                                       <para>Force the outgoing callerid tag parameter to be set to the string <replaceable>x</replaceable></para>
+                               </option>
                                <option name="t">
                                        <para>Allow the called party to transfer the calling party by sending the
                                        DTMF sequence defined in <filename>features.conf</filename>. This setting does not perform policy enforcement on
@@ -384,6 +388,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                                so you will not be able to set timeouts via the TIMEOUT() function in this routine.</para>
                                        </note>
                                </option>
+                               <option name="u">
+                                       <argument name = "x" required="true">
+                                               <para>Force the outgoing callerid presentation indicator parameter to be set
+                                               to one of the values passed in <replaceable>x</replaceable>:
+                                               <literal>allowed_not_screened</literal>
+                                               <literal>allowed_passed_screen</literal>
+                                               <literal>allowed_failed_screen</literal>
+                                               <literal>allowed</literal>
+                                               <literal>prohib_not_screened</literal>
+                                               <literal>prohib_passed_screen</literal>
+                                               <literal>prohib_failed_screen</literal>
+                                               <literal>prohib</literal>
+                                               <literal>unavailable</literal></para>
+                                       </argument>
+                               </option>
                                <option name="w">
                                        <para>Allow the called party to enable recording of the call by sending
                                        the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para>
@@ -537,6 +556,8 @@ enum {
 #define OPT_PEER_H           ((uint64_t)1 << 35)
 #define OPT_CALLEE_GO_ON     ((uint64_t)1 << 36)
 #define OPT_CANCEL_TIMEOUT   ((uint64_t)1 << 37)
+#define OPT_FORCE_CID_TAG    ((uint64_t)1 << 38)
+#define OPT_FORCE_CID_PRES   ((uint64_t)1 << 39)
 
 enum {
        OPT_ARG_ANNOUNCE = 0,
@@ -553,6 +574,8 @@ enum {
        OPT_ARG_OPERMODE,
        OPT_ARG_SCREEN_NOINTRO,
        OPT_ARG_FORCECLID,
+       OPT_ARG_FORCE_CID_TAG,
+       OPT_ARG_FORCE_CID_PRES,
        /* note: this entry _MUST_ be the last one in the enum */
        OPT_ARG_ARRAY_SIZE,
 };
@@ -586,6 +609,8 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
        AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
        AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
        AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+       AST_APP_OPTION_ARG('s', OPT_FORCE_CID_TAG, OPT_ARG_FORCE_CID_TAG),
+       AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
        AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
        AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
        AST_APP_OPTION_ARG('U', OPT_CALLEE_GOSUB, OPT_ARG_CALLEE_GOSUB),
@@ -854,8 +879,20 @@ static void do_forward(struct chanlist *o,
                        ast_string_field_set(c, accountcode, in->accountcode);
                }
                ast_party_connected_line_copy(&c->connected, &original->connected);
-
-               ast_channel_update_redirecting(in, &c->redirecting);
+               /*
+                * We must unlock c before calling ast_channel_redirecting_macro, because
+                * we put c into autoservice there. That is pretty much a guaranteed
+                * deadlock. This is why the handling of c's lock may seem a bit unusual
+                * here.
+                */
+               ast_channel_unlock(c);
+               if (ast_channel_redirecting_macro(c, in, &c->redirecting, 1, 0)) {
+                       while (ast_channel_trylock(c)) {
+                               CHANNEL_DEADLOCK_AVOIDANCE(in);
+                       }
+                       ast_channel_update_redirecting(in, &c->redirecting);
+                       ast_channel_unlock(c);
+               }
 
                ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
                if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
@@ -863,7 +900,6 @@ static void do_forward(struct chanlist *o,
                }
 
                ast_channel_unlock(in);
-               ast_channel_unlock(c);
 
                if (ast_call(c, tmpchan, 0)) {
                        ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
@@ -1194,7 +1230,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                                ast_verb(3, "Redirecting update to %s prevented.\n", in->name);
                                        } else {
                                                ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name);
-                                               ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+                                               if (ast_channel_redirecting_macro(c, in, f, 1, 1)) {
+                                                       ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+                                               }
                                                pa->sentringing = 0;
                                        }
                                        break;
@@ -1335,6 +1373,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                        if (ast_channel_connected_line_macro(in, outgoing->chan, f, 0, 1)) {
                                                ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
                                        }
+                               } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) {
+                                       if (ast_channel_redirecting_macro(in, outgoing->chan, f, 0, 1)) {
+                                               ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
+                                       }
                                }
                        }
                        ast_frfree(f);
@@ -1702,7 +1744,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
        struct cause_args num = { chan, 0, 0, 0 };
        int cause;
        char numsubst[256];
-       char *cid_num = NULL, *cid_name = NULL;
+       char *cid_num = NULL, *cid_name = NULL, *cid_tag = NULL, *cid_pres = NULL;
 
        struct ast_bridge_config config = { { 0, } };
        struct timeval calldurationlimit = { 0, };
@@ -1805,6 +1847,10 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 
        if (ast_test_flag64(&opts, OPT_FORCECLID) && !ast_strlen_zero(opt_args[OPT_ARG_FORCECLID]))
                ast_callerid_parse(opt_args[OPT_ARG_FORCECLID], &cid_name, &cid_num);
+       if (ast_test_flag64(&opts, OPT_FORCE_CID_TAG) && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CID_TAG]))
+               cid_tag = ast_strdupa(opt_args[OPT_ARG_FORCE_CID_TAG]);
+       if (ast_test_flag64(&opts, OPT_FORCE_CID_PRES) && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CID_PRES]))
+               cid_pres = ast_strdupa(opt_args[OPT_ARG_FORCE_CID_PRES]);
        if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr)
                ast_cdr_reset(chan->cdr, NULL);
        if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
@@ -1993,11 +2039,20 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 
                if (ast_test_flag64(peerflags, OPT_FORCECLID) && !ast_strlen_zero(opt_args[OPT_ARG_FORCECLID])) {
                        struct ast_party_connected_line connected;
+                       int pres;
 
                        ast_party_connected_line_set_init(&connected, &tmp->chan->connected);
                        connected.id.number = cid_num;
                        connected.id.name = cid_name;
-                       connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+                       connected.id.tag = cid_tag;
+                       if (cid_pres) {
+                               pres = ast_parse_caller_presentation(cid_pres);
+                               if (pres >= 0) {
+                                       connected.id.number_presentation = pres;
+                               }
+                       } else {
+                               connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+                       }
                        ast_channel_set_connected_line(tmp->chan, &connected);
                } else {
                        ast_connected_line_copy_from_caller(&tc->connected, &chan->cid);
index 97eefe7..6a544de 100644 (file)
@@ -3204,6 +3204,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 {
        const char *queue = qe->parent->name;
        struct callattempt *o, *start = NULL, *prev = NULL;
+       int res;
        int status;
        int numbusies = prebusies;
        int numnochan = 0;
@@ -3373,7 +3374,21 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                ast_party_caller_copy(&o->chan->cid, &in->cid);
                                                ast_party_connected_line_copy(&o->chan->connected, &original->connected);
 
-                                               ast_channel_update_redirecting(in, &o->chan->redirecting);
+                                               /*
+                                                * We must unlock o->chan before calling
+                                                * ast_channel_redirecting_macro, because we put o->chan into
+                                                * autoservice there.  That is pretty much a guaranteed
+                                                * deadlock.  This is why the handling of o->chan's lock may
+                                                * seem a bit unusual here.
+                                                */
+                                               ast_channel_unlock(o->chan);
+                                               res = ast_channel_redirecting_macro(o->chan, in, &o->chan->redirecting, 1, 0);
+                                               while (ast_channel_trylock(o->chan)) {
+                                                       CHANNEL_DEADLOCK_AVOIDANCE(in);
+                                               }
+                                               if (res) {
+                                                       ast_channel_update_redirecting(in, &o->chan->redirecting);
+                                               }
 
                                                update_connectedline = 1;
 
@@ -3486,7 +3501,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                                ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
                                                        } else {
                                                                ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
-                                                               ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+                                                               if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
+                                                                       ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+                                                               }
                                                        }
                                                        break;
                                                default:
index b072d86..d8e7496 100644 (file)
@@ -1049,6 +1049,11 @@ struct dahdi_pvt {
        int cid_ani2;
        /*! \brief Caller ID number from an incoming call. */
        char cid_num[AST_MAX_EXTENSION];
+       /*!
+        * \brief Caller ID tag from incoming call
+        * \note the "cid_tag" string read in from chan_dahdi.conf
+        */
+       char cid_tag[AST_MAX_EXTENSION];
        /*! \brief Caller ID Q.931 TON/NPI field values.  Set by PRI. Zero otherwise. */
        int cid_ton;
        /*! \brief Caller ID name from an incoming call. */
@@ -1386,6 +1391,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
                        .context = "default",
                        .cid_num = "",
                        .cid_name = "",
+                       .cid_tag = "",
                        .mohinterpret = "default",
                        .mohsuggest = "",
                        .parkinglot = "",
@@ -9024,6 +9030,7 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
        tmp->cid.cid_pres = i->callingpres;
        tmp->cid.cid_ton = i->cid_ton;
        tmp->cid.cid_ani2 = i->cid_ani2;
+       tmp->cid.cid_tag = ast_strdup(i->cid_tag);
 #if defined(HAVE_SS7)
        tmp->transfercapability = transfercapability;
        pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
@@ -11995,6 +12002,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                        tmp->cid_num[0] = '\0';
                        tmp->cid_name[0] = '\0';
                }
+               ast_copy_string(tmp->cid_tag, conf->chan.cid_tag, sizeof(tmp->cid_tag));
                tmp->cid_subaddr[0] = '\0';
                ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
                if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
@@ -16781,6 +16789,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
                        ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
                } else if (!strcasecmp(v->name, "cid_number")) {
                        ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
+               } else if (!strcasecmp(v->name, "cid_tag")) {
+                       ast_copy_string(confp->chan.cid_tag, v->value, sizeof(confp->chan.cid_tag));
                } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
                        confp->chan.dahditrcallerid = ast_true(v->value);
                } else if (!strcasecmp(v->name, "restrictcid")) {
index 337aadc..1f09c9c 100644 (file)
@@ -433,6 +433,9 @@ static int local_indicate(struct ast_channel *ast, int condition, const void *da
                if (the_other_channel) {
                        unsigned char frame_data[1024];
                        if (condition == AST_CONTROL_CONNECTED_LINE) {
+                               if (isoutbound) {
+                                       ast_connected_line_copy_to_caller(&the_other_channel->cid, &this_channel->connected);
+                               }
                                f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected);
                        } else {
                                f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting);
index f363c7c..082373d 100644 (file)
@@ -5978,6 +5978,10 @@ static int read_config(struct chan_list *ch)
                ast_mutex_init(&ch->overlap_tv_lock);
        } /* ORIG MISDN END */
 
+       misdn_cfg_get(port, MISDN_CFG_INCOMING_CALLERID_TAG, bc->incoming_cid_tag, sizeof(bc->incoming_cid_tag));
+       if (!ast_strlen_zero(bc->incoming_cid_tag)) {
+               chan_misdn_log(1, port, " --> * Setting incoming caller id tag to \"%s\"\n", bc->incoming_cid_tag);
+       }
        ch->overlap_dial_task = -1;
 
        if (ch->faxdetect  || ch->ast_dsp) {
@@ -6003,10 +6007,11 @@ static int read_config(struct chan_list *ch)
  * \param ast Current Asterisk channel
  * \param id Party id information to send to the other side
  * \param source Why are we sending this update
+ * \param cid_tag Caller ID tag to set in the connected line
  *
  * \return Nothing
  */
-static void misdn_queue_connected_line_update(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source)
+static void misdn_queue_connected_line_update(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source, char *cid_tag)
 {
        struct ast_party_connected_line connected;
 
@@ -6016,6 +6021,7 @@ static void misdn_queue_connected_line_update(struct ast_channel *ast, const str
                | misdn_to_ast_plan(id->number_plan);
        connected.id.number_presentation = misdn_to_ast_pres(id->presentation)
                | misdn_to_ast_screen(id->screening);
+       connected.id.tag = cid_tag;
        connected.source = source;
        ast_channel_queue_connected_line_update(ast, &connected);
 }
@@ -6168,10 +6174,11 @@ static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct as
  *
  * \param ast Current Asterisk channel
  * \param redirect Associated B channel redirecting info
+ * \param tag Caller ID tag to set in the redirecting party fields
  *
  * \return Nothing
  */
-static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect)
+static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect, char *tag)
 {
        struct ast_party_redirecting redirecting;
 
@@ -6184,6 +6191,7 @@ static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct
        redirecting.from.number_presentation =
                misdn_to_ast_pres(redirect->from.presentation)
                | misdn_to_ast_screen(redirect->from.screening);
+       redirecting.from.tag = tag;
 
        redirecting.to.number = (char *) redirect->to.number;
        redirecting.to.number_type =
@@ -6192,6 +6200,7 @@ static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct
        redirecting.to.number_presentation =
                misdn_to_ast_pres(redirect->to.presentation)
                | misdn_to_ast_screen(redirect->to.screening);
+       redirecting.to.tag = tag;
 
        redirecting.reason = misdn_to_ast_reason(redirect->reason);
        redirecting.count = redirect->count;
@@ -6281,6 +6290,7 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
        struct chan_list *ch;
        struct misdn_bchannel *newbc;
        char *dest_cp;
+       int append_msn = 0;
 
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(intf);      /* The interface token is discarded. */
@@ -6392,6 +6402,14 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
                        chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
                }
 
+               misdn_cfg_get(port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
+               if (append_msn) {
+                       strncat(newbc->incoming_cid_tag, "_", sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
+                       strncat(newbc->incoming_cid_tag, newbc->caller.number, sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
+               }
+
+               ast->cid.cid_tag = ast_strdup(newbc->incoming_cid_tag);
+
                misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
                if (number_type < 0) {
                        newbc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type);
@@ -8791,7 +8809,7 @@ static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel
                                ++bc->redirecting.count;
                                bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
 
-                               misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+                               misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
                                ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
 
                                /* Send back positive ACK */
@@ -8855,7 +8873,7 @@ static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel
                                bc->redirecting.to.presentation = 1;/* restricted */
                                bc->redirecting.to.screening = 0;/* unscreened */
                        }
-                       misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+                       misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
                        bc->div_leg_3_rx_wanted = 1;
                }
                break;
@@ -8900,7 +8918,7 @@ static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel
                                        /* We have no place to put the OriginalCalled number */
                                }
 #endif
-                               misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+                               misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
                        }
                        break;
                default:
@@ -8950,7 +8968,7 @@ static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel
                        ++bc->redirecting.count;
                        bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
 
-                       misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+                       misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
                        ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
 
                        misdn_lib_send_event(bc, EVENT_DISCONNECT);
@@ -9072,7 +9090,8 @@ static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel
                        misdn_queue_connected_line_update(ch->ast, &party_id,
                                (bc->fac_in.u.EctInform.Status == 0 /* alerting */)
                                        ? AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
-                                       : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER);
+                                       : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
+                                       bc->incoming_cid_tag);
                }
                break;
 #if 0  /* We don't handle this yet */
@@ -9707,6 +9726,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                int exceed;
                int ai;
                int im;
+               int append_msn = 0;
 
                if (ch) {
                        switch (ch->state) {
@@ -9780,12 +9800,22 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 
                ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number);
 
+               misdn_cfg_get(bc->port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
+               if (append_msn) {
+                       strncat(bc->incoming_cid_tag, "_", sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
+                       strncat(bc->incoming_cid_tag, bc->dialed.number, sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
+               }
+
+               ast_channel_lock(chan);
+               chan->cid.cid_tag = ast_strdup(bc->incoming_cid_tag);
+               ast_channel_unlock(chan);
+
                if (!ast_strlen_zero(bc->redirecting.from.number)) {
                        /* Add configured prefix to redirecting.from.number */
                        misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
 
                        /* Update asterisk channel redirecting information */
-                       misdn_copy_redirecting_to_ast(chan, &bc->redirecting);
+                       misdn_copy_redirecting_to_ast(chan, &bc->redirecting, bc->incoming_cid_tag);
                }
 
                pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
@@ -10124,11 +10154,13 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                }
 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
 
-               /* Add configured prefix to connected.number */
-               misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
+               if (!ast_strlen_zero(bc->connected.number)) {
+                       /* Add configured prefix to connected.number */
+                       misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
 
-               /* Update the connected line information on the other channel */
-               misdn_queue_connected_line_update(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER);
+                       /* Update the connected line information on the other channel */
+                       misdn_queue_connected_line_update(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, bc->incoming_cid_tag);
+               }
 
                ch->l3id = bc->l3_id;
                ch->addr = bc->addr;
@@ -10511,7 +10543,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                                bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
                                                break;
                                        }
-                                       misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
+                                       misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
                                        ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting);
                                }
                        }
@@ -10530,7 +10562,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                bc->redirecting.to_changed = 0;
                                if (ch && ch->ast) {
                                        misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
-                                               AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING);
+                                               AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, bc->incoming_cid_tag);
                                }
                        }
                        break;
@@ -10539,7 +10571,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                                bc->redirecting.to_changed = 0;
                                if (ch && ch->ast) {
                                        misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
-                                               AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER);
+                                               AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
                                }
                        }
                        break;
index 6fe3e1c..d0a8766 100644 (file)
@@ -4741,6 +4741,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        ast_string_field_set(dialog, context, peer->context);
        ast_string_field_set(dialog, cid_num, peer->cid_num);
        ast_string_field_set(dialog, cid_name, peer->cid_name);
+       ast_string_field_set(dialog, cid_tag, peer->cid_tag);
        ast_string_field_set(dialog, mwi_from, peer->mwi_from);
        ast_string_field_set(dialog, parkinglot, peer->parkinglot);
        ast_string_field_set(dialog, engine, peer->engine);
@@ -6281,6 +6282,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
        ast_channel_lock(tmp);
        sip_pvt_lock(i);
        ast_channel_cc_params_init(tmp, i->cc_params);
+       tmp->cid.cid_tag = ast_strdup(i->cid_tag);
        ast_channel_unlock(tmp);
 
        tmp->tech = ( ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO || ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_SHORTINFO) ?  &sip_tech_info : &sip_tech;
@@ -13395,7 +13397,11 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
                        params++;
                /* Check if we have a reason parameter */
                if ((reason_param = strcasestr(params, "reason="))) {
+                       char *end;
                        reason_param+=7;
+                       if ((end = strchr(reason_param, ';'))) {
+                               *end = '\0';
+                       }
                        /* Remove enclosing double-quotes */
                        if (*reason_param == '"')
                                ast_strip_quoted(reason_param, "\"", "\"");
@@ -14118,6 +14124,8 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
                        }
                        if (!ast_strlen_zero(peer->cid_name))
                                ast_string_field_set(p, cid_name, peer->cid_name);
+                       if (!ast_strlen_zero(peer->cid_tag))
+                               ast_string_field_set(p, cid_tag, peer->cid_tag);
                        if (peer->callingpres)
                                p->callingpres = peer->callingpres;
                }
@@ -17527,6 +17535,7 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
                ast_debug(3, "Got redirecting from name %s\n", redirecting_from_name);
                redirecting->from.name = redirecting_from_name;
        }
+       redirecting->from.tag = (char *) p->cid_tag;
        if (!ast_strlen_zero(redirecting_to_number)) {
                if (redirecting->to.number) {
                        ast_free(redirecting->to.number);
@@ -17541,6 +17550,7 @@ static void change_redirecting_information(struct sip_pvt *p, struct sip_request
                ast_debug(3, "Got redirecting to name %s\n", redirecting_from_number);
                redirecting->to.name = redirecting_to_name;
        }
+       redirecting->to.tag = (char *) p->cid_tag;
        redirecting->reason = reason;
 }
 
@@ -17888,6 +17898,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                                ast_party_connected_line_init(&connected);
                                connected.id.number = (char *) p->cid_num;
                                connected.id.name = (char *) p->cid_name;
+                               connected.id.tag = (char *) p->cid_tag;
                                connected.id.number_presentation = p->callingpres;
                                connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
                                ast_channel_queue_connected_line_update(p->owner, &connected);
@@ -17932,6 +17943,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                                ast_party_connected_line_init(&connected);
                                connected.id.number = (char *) p->cid_num;
                                connected.id.name = (char *) p->cid_name;
+                               connected.id.tag = (char *) p->cid_tag;
                                connected.id.number_presentation = p->callingpres;
                                connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
                                ast_channel_queue_connected_line_update(p->owner, &connected);
@@ -17977,6 +17989,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
                        ast_party_connected_line_init(&connected);
                        connected.id.number = (char *) p->cid_num;
                        connected.id.name = (char *) p->cid_name;
+                       connected.id.tag = (char *) p->cid_tag;
                        connected.id.number_presentation = p->callingpres;
                        connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
                        ast_channel_queue_connected_line_update(p->owner, &connected);
@@ -20121,6 +20134,7 @@ static int handle_request_update(struct sip_pvt *p, struct sip_request *req)
                ast_party_connected_line_init(&connected);
                connected.id.number = (char *) p->cid_num;
                connected.id.name = (char *) p->cid_name;
+               connected.id.tag = (char *) p->cid_tag;
                connected.id.number_presentation = p->callingpres;
                connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
                ast_channel_queue_connected_line_update(p->owner, &connected);
@@ -20448,6 +20462,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                ast_party_connected_line_init(&connected);
                                connected.id.number = (char *) p->cid_num;
                                connected.id.name = (char *) p->cid_name;
+                               connected.id.tag = (char *) p->cid_tag;
                                connected.id.number_presentation = p->callingpres;
                                connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
                                ast_channel_queue_connected_line_update(p->owner, &connected);
@@ -21073,11 +21088,30 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *
                        ast_channel_queue_connected_line_update(target.chan2, &connected_to_target);
                } else {
                        /* 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
+                        * 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.chan1.
+                        */
+                       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), &connected_to_target);
+                       frame_size = payload_size + sizeof(*frame_payload);
+                       if (payload_size != -1 && (frame_payload = alloca(frame_size))) {
+                               frame_payload->payload_size = payload_size;
+                               memcpy(frame_payload->payload, connected_line_data, payload_size);
+                               frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
+                               ast_queue_control_data(target.chan1, AST_CONTROL_READ_ACTION, frame_payload, frame_size);
+                       }
+                       /* In addition to queueing the read action frame so that target.chan1's connected line info
+                        * will be updated, we also are going to queue a plain old connected line update on target.chan1. This
+                        * way, either Dial or Queue can apply this connected line update to the outgoing ringing channel.
                         */
-                       ast_channel_update_connected_line(target.chan1, &connected_to_target);
+                       ast_channel_queue_connected_line_update(target.chan1, &connected_to_transferee);
+
                }
                ast_channel_unref(current->chan1);
        }
@@ -24718,6 +24752,7 @@ static void set_peer_defaults(struct sip_peer *peer)
        ast_string_field_set(peer, md5secret, "");
        ast_string_field_set(peer, cid_num, "");
        ast_string_field_set(peer, cid_name, "");
+       ast_string_field_set(peer, cid_tag, "");
        ast_string_field_set(peer, fromdomain, "");
        ast_string_field_set(peer, fromuser, "");
        ast_string_field_set(peer, regexten, "");
@@ -24933,6 +24968,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                ast_string_field_set(peer, cid_name, "");
                        } else if (!strcasecmp(v->name, "cid_number")) {
                                ast_string_field_set(peer, cid_num, v->value);
+                       } else if (!strcasecmp(v->name, "cid_tag")) {
+                               ast_string_field_set(peer, cid_tag, v->value);
                        } else if (!strcasecmp(v->name, "context")) {
                                ast_string_field_set(peer, context, v->value);
                                ast_set_flag(&peer->flags[1], SIP_PAGE2_HAVEPEERCONTEXT);
index e1fe167..270b505 100644 (file)
@@ -42,6 +42,8 @@ enum misdn_cfg_elements {
        MISDN_CFG_LANGUAGE,            /* char[] */
        MISDN_CFG_MUSICCLASS,            /* char[] */
        MISDN_CFG_CALLERID,            /* char[] */
+       MISDN_CFG_INCOMING_CALLERID_TAG, /* char[] */
+       MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, /* int (bool) */
        MISDN_CFG_METHOD,              /* char[] */
        MISDN_CFG_DIALPLAN,            /* int */
        MISDN_CFG_LOCALDIALPLAN,       /* int */
index 8956532..a044760 100644 (file)
@@ -349,6 +349,11 @@ struct misdn_bchannel {
         */
        struct misdn_party_id caller;
 
+       /*! \brief  Incoming Caller ID string tag for special purpose
+        * \note The element can be set to "incoming_cid_tag" in /etc/asterisk/misdn.conf for incoming calls
+        */
+       char incoming_cid_tag[MISDN_MAX_NAME_LEN];
+
        /*! \brief Connected-Party/Connected-Line ID information struct
         * \note The number_type element can be set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls
         */
index 82d3547..e14f2ad 100644 (file)
@@ -134,6 +134,13 @@ static const struct misdn_cfg_spec port_spec[] = {
                "Sets the musiconhold class." },
        { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE,
                "Set the outgoing caller id to the value." },
+       { "incoming_cid_tag", MISDN_CFG_INCOMING_CALLERID_TAG, MISDN_CTYPE_STR, "", NONE,
+               "Set the incoming caller id string tag to the value." },
+       { "append_msn_to_cid_tag", MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, MISDN_CTYPE_BOOL, "no", NONE,
+               "Automatically appends incoming or outgoing MSN to the incoming caller\n"
+               "\tid string tag. An underscore '_' is used as delimiter. Incoming calls\n"
+               "\twill have the dialed number appended, and outgoing calls will have the\n"
+               "\tcaller number appended to the tag." },
        { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE,
                "Set the method to use for channel selection:\n"
                "\t  standard     - Use the first free channel starting from the lowest number.\n"
index 2ee19b6..ade534e 100644 (file)
@@ -926,6 +926,7 @@ struct sip_pvt {
                AST_STRING_FIELD(peermd5secret);
                AST_STRING_FIELD(cid_num);      /*!< Caller*ID number */
                AST_STRING_FIELD(cid_name);     /*!< Caller*ID name */
+               AST_STRING_FIELD(cid_tag);      /*!< Caller*ID tag */
                AST_STRING_FIELD(mwi_from);     /*!< Name to place in the From header in outgoing NOTIFY requests */
                AST_STRING_FIELD(fullcontact);  /*!< The Contact: that the UA registers with us */
                                                /* we only store the part in <brackets> in this field. */
@@ -1130,6 +1131,7 @@ struct sip_peer {
                AST_STRING_FIELD(fullcontact);  /*!< Contact registered with us (not in sip.conf) */
                AST_STRING_FIELD(cid_num);      /*!< Caller ID num */
                AST_STRING_FIELD(cid_name);     /*!< Caller ID name */
+               AST_STRING_FIELD(cid_tag);      /*!< Caller ID tag */
                AST_STRING_FIELD(vmexten);      /*!< Dialplan extension for MWI notify message*/
                AST_STRING_FIELD(language);     /*!<  Default language for prompts */
                AST_STRING_FIELD(mohinterpret); /*!<  Music on Hold class */
index 9de874e..bd51686 100644 (file)
@@ -404,6 +404,19 @@ nodialtone=no
 presentation=-1
 screen=-1
 
+; Incoming calls will have a caller ID tag set to this value
+;
+;incoming_cid_tag = "asterisk"
+
+; With this set, you can automatically append the MSN of a party
+; to the cid_tag. Incoming calls have the dialed number appended
+; to the tag, and outgoing calls have the caller number appended
+; to the tag. An '_' is used to separate the tag from the
+; MSN.
+; Default is no.
+;
+;append_msn_to_cid_tag = no
+
 ; Select what to do with outgoing COLP information on this port.
 ;
 ; 0 - Send out COLP information unaltered. (default)
index 3de6995..357055c 100644 (file)
@@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <enum name="all" />
                                        <enum name="num" />
                                        <enum name="name" />
+                                       <enum name="tag" />
                                        <enum name="ANI" />
                                        <enum name="DNID" />
                                        <enum name="RDNIS" />
@@ -161,6 +162,10 @@ static int callerid_read(struct ast_channel *chan, const char *cmd, char *data,
                        if (chan->cid.cid_name) {
                                ast_copy_string(buf, chan->cid.cid_name, len);
                        }
+               } else if (!strncasecmp("tag", data, 3)) {
+                       if (chan->cid.cid_tag) {
+                               ast_copy_string(buf, chan->cid.cid_tag, len);
+                       }
                } else if (!strncasecmp("num", data, 3)) {
                        /* also matches "number" */
                        if (chan->cid.cid_num) {
@@ -254,6 +259,13 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data,
                if (chan->cdr) {
                        ast_cdr_setcid(chan->cdr, chan);
                }
+       } else if (!strncasecmp("tag", data, 3)) {
+               ast_channel_lock(chan);
+               if (chan->cid.cid_tag) {
+                       ast_free(chan->cid.cid_tag);
+               }
+               chan->cid.cid_tag = ast_strdup(value);
+               ast_channel_unlock(chan);
        } else if (!strncasecmp("ani", data, 3)) {
                if (!strncasecmp(data + 3, "2", 1)) {
                        chan->cid.cid_ani2 = atoi(value);
index 936d490..95bcb23 100644 (file)
@@ -58,6 +58,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <enum name = "all" />
                                        <enum name = "num" />
                                        <enum name = "name" />
+                                       <enum name = "tag" />
                                        <enum name = "ton" />
                                        <enum name = "pres" />
                                        <enum name = "subaddr[-valid]|[-type]|[-odd]">
@@ -99,6 +100,10 @@ static int connectedline_read(struct ast_channel *chan, const char *cmd, char *d
                if (chan->connected.id.number) {
                        ast_copy_string(buf, chan->connected.id.number, len);
                }
+       } else if (!strncasecmp("tag", data, 3)) {
+               if (chan->connected.id.tag) {
+                       ast_copy_string(buf, chan->connected.id.tag, len);
+               }
        } else if (!strncasecmp("ton", data, 3)) {
                snprintf(buf, len, "%d", chan->connected.id.number_type);
        } else if (!strncasecmp("pres", data, 4)) {
@@ -179,6 +184,10 @@ static int connectedline_write(struct ast_channel *chan, const char *cmd, char *
                connected.id.number = ast_strdupa(value);
                ast_trim_blanks(connected.id.number);
                set_it(chan, &connected);
+       } else if (!strncasecmp("tag", data, 3)) {
+               connected.id.tag = ast_strdupa(value);
+               ast_trim_blanks(connected.id.tag);
+               set_it(chan, &connected);
        } else if (!strncasecmp("ton", data, 3)) {
                val = ast_strdupa(value);
                ast_trim_blanks(val);
index 87fc41a..2f38c2f 100644 (file)
@@ -68,11 +68,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <enum name = "from-all" />
                                        <enum name = "from-num" />
                                        <enum name = "from-name" />
+                                       <enum name = "from-tag" />
                                        <enum name = "from-ton" />
                                        <enum name = "from-pres" />
                                        <enum name = "to-all" />
                                        <enum name = "to-num" />
                                        <enum name = "to-name" />
+                                       <enum name = "to-tag" />
                                        <enum name = "to-ton" />
                                        <enum name = "to-pres" />
                                        <enum name = "reason" />
@@ -144,6 +146,10 @@ static enum ID_FIELD_STATUS redirecting_id_read(char *buf, size_t len, char *dat
                if (id->number) {
                        ast_copy_string(buf, id->number, len);
                }
+       } else if (!strncasecmp("tag", data, 3)) {
+               if (id->tag) {
+                       ast_copy_string(buf, id->tag, len);
+               }
        } else if (!strncasecmp("ton", data, 3)) {
                snprintf(buf, len, "%d", id->number_type);
        } else if (!strncasecmp("pres", data, 4)) {
@@ -257,6 +263,9 @@ static enum ID_FIELD_STATUS redirecting_id_write(struct ast_party_id *id, char *
        } else if (!strncasecmp("num", data, 3)) {
                id->number = ast_strdup(value);
                ast_trim_blanks(id->number);
+       } else if (!strncasecmp("tag", data, 3)) {
+               id->tag = ast_strdup(value);
+               ast_trim_blanks(id->tag);
        } else if (!strncasecmp("ton", data, 3)) {
                val = ast_strdupa(value);
                ast_trim_blanks(val);
@@ -347,7 +356,6 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da
                switch (redirecting_id_write(&redirecting.from, data + 5, value)) {
                case ID_FIELD_VALID:
                        set_it(chan, &redirecting);
-                       ast_party_redirecting_free(&redirecting);
                        break;
 
                case ID_FIELD_INVALID:
@@ -357,11 +365,11 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da
                        ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
                        break;
                }
+               ast_party_redirecting_free(&redirecting);
        } else if (!strncasecmp("to-", data, 3)) {
                switch (redirecting_id_write(&redirecting.to, data + 3, value)) {
                case ID_FIELD_VALID:
                        set_it(chan, &redirecting);
-                       ast_party_redirecting_free(&redirecting);
                        break;
 
                case ID_FIELD_INVALID:
@@ -371,6 +379,7 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da
                        ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data);
                        break;
                }
+               ast_party_redirecting_free(&redirecting);
        } else if (!strncasecmp("pres", data, 4)) {
                int pres;
 
index b2cb8e5..5aa5f1f 100644 (file)
@@ -288,6 +288,17 @@ struct ast_callerid {
         * (Field will eventually move to struct ast_channel.dialed.transit_network_select)
         */
        int cid_tns;
+
+       /*!
+        * \brief Callerid "Tag"
+        * A user-settable field used to help associate some extrinsic information
+        * about the channel or user of the channel to the caller ID. This information
+        * is not transmitted over the wire and so is only useful within an Asterisk
+        * environment.
+        * (Field will eventually move to struct ast_channel.caller.id.tag)
+        */
+       char *cid_tag;
+
        /*!
         * \brief Caller id subaddress.
         * (Field will eventually move to struct ast_channel.caller.id.subaddress)
@@ -314,6 +325,9 @@ struct ast_party_id {
        /*! \brief Subscriber name (Malloced) */
        char *name;
 
+       /*! \brief User-set "tag" */
+       char *tag;
+
        /*! \brief Subscriber subaddress. */
        struct ast_party_subaddress subaddress;
 
@@ -2779,6 +2793,36 @@ int ast_channel_data_add_structure(struct ast_data *tree, struct ast_channel *ch
 int ast_channel_data_cmp_structure(const struct ast_data_search *tree, struct ast_channel *chan,
        const char *structure_name);
 
+/*!
+ * \since 1.8
+ * \brief Run a redirecting interception macro and update a channel's redirecting information
+ *
+ * \details
+ * Whenever we want to update a channel's redirecting 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 redirecting_info Either an ast_party_redirecting or ast_frame pointer of type
+ * AST_CONTROL_REDIRECTING
+ * \param is_caller If true, then run REDIRECTING_CALLER_SEND_MACRO, otherwise run
+ * REDIRECTING_CALLEE_SEND_MACRO
+ * \param is_frame If true, then redirecting_info is an ast_frame pointer, otherwise it is an
+ * ast_party_redirecting 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_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame);
+
 #include "asterisk/ccss.h"
 
 /*!
index 0d8d557..4198fad 100644 (file)
@@ -326,6 +326,24 @@ enum ast_control_frame_type {
        AST_CONTROL_T38_PARAMETERS = 24, /*! T38 state change request/notification with parameters */
        AST_CONTROL_CC = 25, /*!< Indication that Call completion service is possible */
        AST_CONTROL_SRCCHANGE = 26,  /*!< Media source has changed and requires a new RTP SSRC */
+       AST_CONTROL_READ_ACTION = 27, /*!< Tell ast_read to take a specific action */
+};
+
+enum ast_frame_read_action {
+       AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO,
+};
+
+struct ast_control_read_action_payload {
+       /* An indicator to ast_read of what action to
+        * take with the frame;
+        */
+       enum ast_frame_read_action action;
+       /* The size of the frame's payload
+        */
+       size_t payload_size;
+       /* A payload for the frame.
+        */
+       unsigned char payload[0];
 };
 
 enum ast_control_t38 {
index c91d602..5850c89 100644 (file)
@@ -1528,6 +1528,8 @@ static void free_cid(struct ast_callerid *cid)
                ast_free(cid->cid_name);        
        if (cid->cid_ani)
                ast_free(cid->cid_ani);
+       if (cid->cid_tag)
+               ast_free(cid->cid_tag);
        cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = NULL;
        ast_party_subaddress_free(&cid->subaddress);
        ast_party_subaddress_free(&cid->dialed_subaddress);
@@ -1611,6 +1613,7 @@ static void ast_party_id_init(struct ast_party_id *init)
 {
        init->number = NULL;
        init->name = NULL;
+       init->tag = NULL;
        init->number_type = 0;  /* Unknown */
        init->number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
        ast_party_subaddress_init(&init->subaddress);
@@ -1642,6 +1645,11 @@ static void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_
        }
        dest->name = ast_strdup(src->name);
 
+       if (dest->tag) {
+               ast_free(dest->tag);
+       }
+       dest->tag = ast_strdup(src->tag);
+
        dest->number_type = src->number_type;
        dest->number_presentation = src->number_presentation;
        ast_party_subaddress_copy(&dest->subaddress, &src->subaddress);
@@ -1668,6 +1676,7 @@ static void ast_party_id_set_init(struct ast_party_id *init, const struct ast_pa
 {
        init->number = NULL;
        init->name = NULL;
+       init->tag = NULL;
        init->number_type = guide->number_type;
        init->number_presentation = guide->number_presentation;
        ast_party_subaddress_set_init(&init->subaddress, &guide->subaddress);
@@ -1703,6 +1712,13 @@ static void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_i
                dest->number = ast_strdup(src->number);
        }
 
+       if (src->tag && src->tag != dest->tag) {
+               if (dest->tag) {
+                       ast_free(dest->tag);
+               }
+               dest->tag = ast_strdup(src->tag);
+       }
+
        dest->number_type = src->number_type;
        dest->number_presentation = src->number_presentation;
        ast_party_subaddress_set(&dest->subaddress, &src->subaddress);
@@ -1727,6 +1743,11 @@ static void ast_party_id_free(struct ast_party_id *doomed)
                ast_free(doomed->name);
                doomed->name = NULL;
        }
+
+       if (doomed->tag) {
+               ast_free(doomed->tag);
+               doomed->tag = NULL;
+       }
        ast_party_subaddress_free(&doomed->subaddress);
 }
 
@@ -1758,6 +1779,11 @@ void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid
        }
        dest->cid_name = ast_strdup(src->cid_name);
 
+       if (dest->cid_tag) {
+               ast_free(dest->cid_tag);
+       }
+       dest->cid_tag = ast_strdup(src->cid_tag);
+
        dest->cid_ton = src->cid_ton;
        dest->cid_pres = src->cid_pres;
 
@@ -1843,6 +1869,7 @@ void ast_party_connected_line_collect_caller(struct ast_party_connected_line *co
        connected->id.name = cid->cid_name;
        connected->id.number_type = cid->cid_ton;
        connected->id.number_presentation = cid->cid_pres;
+       connected->id.tag = cid->cid_tag;
        connected->id.subaddress = cid->subaddress;
 
        connected->ani = cid->cid_ani;
@@ -3354,6 +3381,8 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 
        if (f) {
                struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);
+               struct ast_control_read_action_payload *read_action_payload;
+               struct ast_party_connected_line connected;
 
                /* if the channel driver returned more than one frame, stuff the excess
                   into the readq for the next ast_read call
@@ -3381,6 +3410,23 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                        /* removed a call to ast_cdr_answer(chan->cdr) from here. */
                                        ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
                                }
+                       } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) {
+                               ast_party_connected_line_init(&connected);
+                               read_action_payload = f->data.ptr;
+                               switch (read_action_payload->action) {
+                               case AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO:
+                                       if (ast_connected_line_parse_data(read_action_payload->payload,
+                                                               read_action_payload->payload_size, &connected)) {
+                                               break;
+                                       }
+                                       if (ast_channel_connected_line_macro(NULL, chan, &connected, 1, 0)) {
+                                               ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE,
+                                                               read_action_payload->payload, read_action_payload->payload_size);
+                                       }
+                                       break;
+                               }
+                               ast_frfree(f);
+                               f = &ast_null_frame;
                        }
                        break;
                case AST_FRAME_DTMF_END:
@@ -3606,6 +3652,25 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                * and synchronous generation of outgoing frames is necessary       */
                                ast_read_generator_actions(chan, f);
                        }
+                       break;
+               case AST_CONTROL_READ_ACTION:
+                       ast_log(LOG_NOTICE, "Read a read action frame\n");
+                       read_action_payload = f->data.ptr;
+                       switch (read_action_payload->action) {
+                       case AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO:
+                               if (ast_connected_line_parse_data(read_action_payload->payload,
+                                                       read_action_payload->payload_size, &connected)) {
+                                       break;
+                               }
+                               if (ast_channel_connected_line_macro(NULL, chan, &connected, 1, 0)) {
+                                       ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE,
+                                                       read_action_payload->payload, read_action_payload->payload_size);
+                               }
+                               break;
+                       }
+                       ast_frfree(f);
+                       f = &ast_null_frame;
+                       break;
                default:
                        /* Just pass it on! */
                        break;
@@ -3679,6 +3744,7 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
        case AST_CONTROL_T38_PARAMETERS:
        case _XXX_AST_CONTROL_T38:
        case AST_CONTROL_CC:
+       case AST_CONTROL_READ_ACTION:
                break;
 
        case AST_CONTROL_CONGESTION:
@@ -3823,6 +3889,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
        case AST_CONTROL_CONNECTED_LINE:
        case AST_CONTROL_REDIRECTING:
        case AST_CONTROL_CC:
+       case AST_CONTROL_READ_ACTION:
                /* Nothing left to do for these. */
                res = 0;
                break;
@@ -5794,7 +5861,9 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
 
                        switch (f->subclass.integer) {
                        case AST_CONTROL_REDIRECTING:
-                               ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+                               if (ast_channel_redirecting_macro(who, other, f, other == c0, 1)) {
+                                       ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+                               }
                                break;
                        case AST_CONTROL_CONNECTED_LINE:
                                if (ast_channel_connected_line_macro(who, other, f, other == c0, 1)) {
@@ -6781,6 +6850,11 @@ void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest,
        }
        dest->id.name = ast_strdup(src->cid_name);
 
+       if (dest->id.tag) {
+               ast_free(dest->id.tag);
+       }
+       dest->id.tag = ast_strdup(src->cid_tag);
+
        dest->id.number_type = src->cid_ton;
        dest->id.number_presentation = src->cid_pres;
 
@@ -6823,6 +6897,11 @@ void ast_connected_line_copy_to_caller(struct ast_callerid *dest, const struct a
        }
        dest->cid_name = ast_strdup(src->id.name);
 
+       if (dest->cid_tag) {
+               ast_free(dest->cid_tag);
+       }
+       dest->cid_tag = ast_strdup(src->id.tag);
+
        dest->cid_ton = src->id.number_type;
        dest->cid_pres = src->id.number_presentation;
 
@@ -6876,7 +6955,8 @@ enum {
        AST_CONNECTED_LINE_SUBADDRESS,
        AST_CONNECTED_LINE_SUBADDRESS_TYPE,
        AST_CONNECTED_LINE_SUBADDRESS_ODD_EVEN,
-       AST_CONNECTED_LINE_SUBADDRESS_VALID
+       AST_CONNECTED_LINE_SUBADDRESS_VALID,
+       AST_CONNECTED_LINE_TAG,
 };
 
 int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected)
@@ -6915,6 +6995,18 @@ int ast_connected_line_build_data(unsigned char *data, size_t datalen, const str
                pos += length;
        }
 
+       if (connected->id.tag) {
+               length = strlen(connected->id.tag);
+               if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+                       ast_log(LOG_WARNING, "No space left for connected line tag\n");
+                       return -1;
+               }
+               data[pos++] = AST_CONNECTED_LINE_TAG;
+               data[pos++] = length;
+               memcpy(data + pos, connected->id.tag, length);
+               pos += length;
+       }
+
        if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
                ast_log(LOG_WARNING, "No space left for connected line type of number\n");
                return -1;
@@ -7025,6 +7117,16 @@ int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, str
                                connected->id.name[ie_len] = 0;
                        }
                        break;
+               case AST_CONNECTED_LINE_TAG:
+                       if (connected->id.tag) {
+                               ast_free(connected->id.tag);
+                       }
+                       connected->id.tag = ast_malloc(ie_len + 1);
+                       if (connected->id.tag) {
+                               memcpy(connected->id.tag, data + pos, ie_len);
+                               connected->id.tag[ie_len] = 0;
+                       }
+                       break;
                case AST_CONNECTED_LINE_NUMBER_TYPE:
                        if (ie_len != 1) {
                                ast_log(LOG_WARNING, "Invalid connected line type of number (%u)\n", (unsigned) ie_len);
@@ -7156,7 +7258,9 @@ enum {
        AST_REDIRECTING_TO_SUBADDRESS,
        AST_REDIRECTING_TO_SUBADDRESS_TYPE,
        AST_REDIRECTING_TO_SUBADDRESS_ODD_EVEN,
-       AST_REDIRECTING_TO_SUBADDRESS_VALID
+       AST_REDIRECTING_TO_SUBADDRESS_VALID,
+       AST_REDIRECTING_FROM_TAG,
+       AST_REDIRECTING_TO_TAG,
 };
 
 int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting)
@@ -7195,6 +7299,18 @@ int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct
                pos += length;
        }
 
+       if (redirecting->from.tag) {
+               length = strlen(redirecting->from.tag);
+               if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+                       ast_log(LOG_WARNING, "No space left for redirecting from name\n");
+                       return -1;
+               }
+               data[pos++] = AST_REDIRECTING_FROM_TAG;
+               data[pos++] = length;
+               memcpy(data + pos, redirecting->from.tag, length);
+               pos += length;
+       }
+
        if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
                ast_log(LOG_WARNING, "No space left for redirecting from type of number\n");
                return -1;
@@ -7274,6 +7390,18 @@ int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct
                pos += length;
        }
 
+       if (redirecting->to.tag) {
+               length = strlen(redirecting->to.tag);
+               if (datalen < pos + (sizeof(data[0]) * 2) + length) {
+                       ast_log(LOG_WARNING, "No space left for redirecting to name\n");
+                       return -1;
+               }
+               data[pos++] = AST_REDIRECTING_TO_TAG;
+               data[pos++] = length;
+               memcpy(data + pos, redirecting->to.tag, length);
+               pos += length;
+       }
+
        if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
                ast_log(LOG_WARNING, "No space left for redirecting to type of number\n");
                return -1;
@@ -7393,6 +7521,16 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct
                                redirecting->from.name[ie_len] = 0;
                        }
                        break;
+               case AST_REDIRECTING_FROM_TAG:
+                       if (redirecting->from.tag) {
+                               ast_free(redirecting->from.tag);
+                       }
+                       redirecting->from.tag = ast_malloc(ie_len + 1);
+                       if (redirecting->from.tag) {
+                               memcpy(redirecting->from.tag, data + pos, ie_len);
+                               redirecting->from.tag[ie_len] = 0;
+                       }
+                       break;
                case AST_REDIRECTING_FROM_NUMBER_TYPE:
                        if (ie_len != 1) {
                                ast_log(LOG_WARNING, "Invalid redirecting from type of number (%u)\n", (unsigned) ie_len);
@@ -7462,6 +7600,16 @@ int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct
                                redirecting->to.name[ie_len] = 0;
                        }
                        break;
+               case AST_REDIRECTING_TO_TAG:
+                       if (redirecting->to.tag) {
+                               ast_free(redirecting->to.tag);
+                       }
+                       redirecting->to.tag = ast_malloc(ie_len + 1);
+                       if (redirecting->to.tag) {
+                               memcpy(redirecting->to.tag, data + pos, ie_len);
+                               redirecting->to.tag[ie_len] = 0;
+                       }
+                       break;
                case AST_REDIRECTING_TO_NUMBER_TYPE:
                        if (ie_len != 1) {
                                ast_log(LOG_WARNING, "Invalid redirecting to type of number (%u)\n", (unsigned) ie_len);
@@ -7562,39 +7710,72 @@ 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)
+int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int is_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;
+       ast_channel_lock(macro_chan);
+       macro = pbx_builtin_getvar_helper(macro_chan, is_caller
+                       ? "CONNECTED_LINE_CALLER_SEND_MACRO" : "CONNECTED_LINE_CALLEE_SEND_MACRO");
+       macro = ast_strdupa(S_OR(macro, ""));
+       macro_args = pbx_builtin_getvar_helper(macro_chan, is_caller
+                       ? "CONNECTED_LINE_CALLER_SEND_MACRO_ARSG" : "CONNECTED_LINE_CALLEE_SEND_MACRO_ARGS");
+       macro_args = ast_strdupa(S_OR(macro_args, ""));
+       ast_channel_unlock(macro_chan);
+
+       if (ast_strlen_zero(macro)) {
+               return -1;
+       }
+
+       if (is_frame) {
+               const struct ast_frame *frame = connected_info;
+               ast_connected_line_parse_data(frame->data.ptr, frame->datalen, &macro_chan->connected);
        } else {
-               pointer.connected = connected_info;
+               const struct ast_party_connected_line *connected = connected_info;
+               ast_party_connected_line_copy(&macro_chan->connected, 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;
+}
+
+int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame)
+{
+       const char *macro;
+       const char *macro_args;
+       int retval;
+
        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"), ""));
+       macro = pbx_builtin_getvar_helper(macro_chan, is_caller
+               ? "REDIRECTING_CALLER_SEND_MACRO" : "REDIRECTING_CALLEE_SEND_MACRO");
+       macro = ast_strdupa(S_OR(macro, ""));
+       macro_args = pbx_builtin_getvar_helper(macro_chan, is_caller
+               ? "REDIRECTING_CALLER_SEND_MACRO_ARGS" : "REDIRECTING_CALLEE_SEND_MACRO_ARGS");
+       macro_args = ast_strdupa(S_OR(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);
+       if (is_frame) {
+               const struct ast_frame *frame = redirecting_info;
+
+               ast_redirecting_parse_data(frame->data.ptr, frame->datalen, &macro_chan->redirecting);
        } else {
-               ast_party_connected_line_copy(&macro_chan->connected, pointer.connected);
+               const struct ast_party_redirecting *redirecting = redirecting_info;
+
+               ast_party_redirecting_copy(&macro_chan->redirecting, redirecting);
        }
 
-       if (!(retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args))) {
-               ast_channel_update_connected_line(macro_chan, &macro_chan->connected);
+       retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
+       if (!retval) {
+               ast_channel_update_redirecting(macro_chan, &macro_chan->redirecting);
        }
 
        return retval;
index 7435d92..bfd0c44 100644 (file)
@@ -426,7 +426,9 @@ static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel
                        break;
                case AST_CONTROL_REDIRECTING:
                        ast_verb(3, "%s redirecting info has changed, passing it to %s\n", channel->owner->name, chan->name);
-                       ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
+                       if (ast_channel_redirecting_macro(channel->owner, chan, fr, 1, 1)) {
+                               ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
+                       }
                        break;
                case AST_CONTROL_PROCEEDING:
                        ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name);
index 0a26ad1..72a626e 100644 (file)
@@ -2728,6 +2728,10 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller,
                                        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.integer == AST_CONTROL_REDIRECTING) {
+                                       if (ast_channel_redirecting_macro(chan, caller, f, 1, 1)) {
+                                               ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+                                       }
                                } else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) {
                                        ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer);
                                }
@@ -3196,7 +3200,14 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
                                if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
                                        break;
                                }
-                               /* The implied "else" falls through purposely */
+                               ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+                               break;
+                       case AST_CONTROL_REDIRECTING:
+                               if (!ast_channel_redirecting_macro(who, other, f, who != chan, 1)) {
+                                       break;
+                               }
+                               ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
+                               break;
                        case AST_CONTROL_HOLD:
                        case AST_CONTROL_UNHOLD:
                                ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen);
index 88f5346..0027b04 100644 (file)
@@ -887,6 +887,16 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a
                                }
                                ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
                                ast_frfree(fr);
+                       } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+                               if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
+                                       ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+                               }
+                               ast_frfree(fr);
+                       } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
+                               if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
+                                       ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+                               }
+                               ast_frfree(fr);
                        } else {
                                *fo = fr;
                                *rc = who;
@@ -1113,6 +1123,16 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
                                }
                                ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
                                ast_frfree(fr);
+                       } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) {
+                               if (ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) {
+                                       ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+                               }
+                               ast_frfree(fr);
+                       } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) {
+                               if (ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) {
+                                       ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen);
+                               }
+                               ast_frfree(fr);
                        } else {
                                *fo = fr;
                                *rc = who;