]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Tested by: sergee, murf, chris-mac, andrew, KNK
authorSteve Murphy <murf@digium.com>
Fri, 12 Sep 2008 04:29:34 +0000 (04:29 +0000)
committerSteve Murphy <murf@digium.com>
Fri, 12 Sep 2008 04:29:34 +0000 (04:29 +0000)
This is a "second attempt" to restore the previous "endbeforeh" behavior
in 1.4 and up. In order to capture information concerning all the
legs of transfers in all their infinite combinations, I was forced
to this particular solution by a chain of logical necessities, the
first being that I was not allowed to rewrite the CDR mechanism from
the ground up!

This change basically leaves the original machinery alone, which allows
IVR and local channel type situations to generate CDR's as normal, but
a channel flag can be set to suppress the normal running of the h exten.
That flag would be set by the code that runs the h exten from the
ast_bridge_call routine, to prevent the h exten from being run twice.
Also, a flag in the ast_bridge_config struct passed into ast_bridge_call
can be used to suppress the running of the h exten in that routine. This
would happen, for instance, if you use the 'g' option in the Dial app.

Running this routine 'early' allows not only the CDR() func to be used
in the h extension for reading CDR variables, but also allows them to
be modified before the CDR is posted to the backends.

While I dearly hope that this patch overcomes all problems, and
introduces no new problems, reality suggests that surely someone
will have problems. In this case, please re-open 13251 (or 13289),
and we'll see if we can't fix any remaining issues.

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

apps/app_dial.c
include/asterisk/channel.h
main/pbx.c
res/res_features.c

index 540a74e89de281bb91df5e2c1bcac2ecb64f9c63..8eaacce9f433f6ec9c238c6a6e8f1107dee1e6e0 100644 (file)
@@ -1741,6 +1741,8 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
                                ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
                        if (ast_test_flag(peerflags, OPT_CALLER_PARK))
                                ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
+                       if (ast_test_flag(peerflags, OPT_GO_ON))
+                               ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN);
 
                        config.timelimit = timelimit;
                        config.play_warning = play_warning;
index d5acaf6e44d7033ba6a107e0bc7019b571c5447e..5e42953cb861728bcb26eec19240a9a95de73b46 100644 (file)
@@ -510,6 +510,10 @@ enum {
        /*! This flag indicates that on a masquerade, an active stream should not
         *  be carried over */
        AST_FLAG_MASQ_NOSTREAM = (1 << 15),
+       /*! This flag indicates that the hangup exten was run when the bridge terminated,
+        *  a message aimed at preventing a subsequent hangup exten being run at the pbx_run
+        *  level */
+       AST_FLAG_BRIDGE_HANGUP_RUN = (1 << 16),
 };
 
 /*! \brief ast_bridge_config flags */
@@ -520,6 +524,7 @@ enum {
        AST_FEATURE_ATXFER =       (1 << 3),
        AST_FEATURE_AUTOMON =      (1 << 4),
        AST_FEATURE_PARKCALL =     (1 << 5),
+       AST_FEATURE_NO_H_EXTEN =   (1 << 6),
 };
 
 struct ast_bridge_config {
index 9aa96118cae287c15dbfaef93f2fc8a0f4ab0611..b9bdc9ba5017e0e4b47f5473a3f3a2b68a3d3624 100644 (file)
@@ -2539,7 +2539,7 @@ static int __ast_pbx_run(struct ast_channel *c)
                ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
        if (res != AST_PBX_KEEPALIVE)
                ast_softhangup(c, c->hangupcause ? c->hangupcause : AST_CAUSE_NORMAL_CLEARING);
-       if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
+       if ((res != AST_PBX_KEEPALIVE) && !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
                set_ext_pri(c, "h", 1);
                while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
                        if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
@@ -2554,7 +2554,7 @@ static int __ast_pbx_run(struct ast_channel *c)
                }
        }
        ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
-
+       ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
        pbx_destroy(c->pbx);
        c->pbx = NULL;
        if (res != AST_PBX_KEEPALIVE)
index fa1dd39644e6aa69a61ae6875b49f4d2ed8a156d..210ec2f83aa65f8a3ecd113565d36463c9b827c4 100644 (file)
@@ -1682,6 +1682,51 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
 
        }
    before_you_go:
+       if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
+               struct ast_cdr *swapper;
+               char savelastapp[AST_MAX_EXTENSION];
+               char savelastdata[AST_MAX_EXTENSION];
+               char save_exten[AST_MAX_EXTENSION];
+               int  save_prio;
+               
+               if (chan->cdr && ast_opt_end_cdr_before_h_exten) {
+                       ast_cdr_end(bridge_cdr);
+               }
+               /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
+                  dialplan code operate on it */
+               swapper = chan->cdr;
+               ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
+               ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
+               ast_channel_lock(chan);
+               chan->cdr = bridge_cdr;
+               ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
+               ast_copy_string(chan->exten, "h", sizeof(chan->exten));
+               save_prio = chan->priority;
+               chan->priority = 1;
+               ast_channel_unlock(chan);
+               while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
+                       if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
+                               /* Something bad happened, or a hangup has been requested. */
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
+                               if (option_verbose > 1)
+                                       ast_verbose( VERBOSE_PREFIX_2 "Spawn h extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
+                               break;
+                       }
+                       chan->priority++;
+               }
+               /* swap it back */
+               ast_channel_lock(chan);
+               ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
+               chan->priority = save_prio;
+               chan->cdr = swapper;
+               ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
+               ast_channel_unlock(chan);
+               /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
+               ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
+               ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
+       }
+       
        /* obey the NoCDR() wishes. */
        if (chan_cdr && ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED) && peer_cdr && !ast_test_flag(peer_cdr, AST_CDR_FLAG_POST_DISABLED))
                ast_set_flag(peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */