[asterisk-commits] rmudgett: branch rmudgett/hangup_handlers r368992 - in /team/rmudgett/hangup_...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Jun 14 20:01:23 CDT 2012
Author: rmudgett
Date: Thu Jun 14 20:01:19 2012
New Revision: 368992
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=368992
Log:
Commit current hangup handler work.
* Base hangup handler execution code.
* CHANNEL(hangup_handler)
* CLI "core show hanguphandlers <channel>" and "core show hanguphandlers all"
* Dial supports hangup handlers.
Needs more testing and bridge peer calling hangup handlers where needed.
Modified:
team/rmudgett/hangup_handlers/.cleancount
team/rmudgett/hangup_handlers/apps/app_dial.c
team/rmudgett/hangup_handlers/channels/chan_local.c
team/rmudgett/hangup_handlers/funcs/func_channel.c
team/rmudgett/hangup_handlers/include/asterisk/channel.h
team/rmudgett/hangup_handlers/include/asterisk/pbx.h
team/rmudgett/hangup_handlers/main/channel.c
team/rmudgett/hangup_handlers/main/channel_internal_api.c
team/rmudgett/hangup_handlers/main/features.c
team/rmudgett/hangup_handlers/main/pbx.c
Modified: team/rmudgett/hangup_handlers/.cleancount
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/.cleancount?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/.cleancount (original)
+++ team/rmudgett/hangup_handlers/.cleancount Thu Jun 14 20:01:19 2012
@@ -1,3 +1,1 @@
-39
-
-
+40
Modified: team/rmudgett/hangup_handlers/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/apps/app_dial.c?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/apps/app_dial.c (original)
+++ team/rmudgett/hangup_handlers/apps/app_dial.c Thu Jun 14 20:01:19 2012
@@ -1728,6 +1728,28 @@
return 0;
}
+/*!
+ * \internal
+ * \brief Put chan into autoservice while hanging up peer.
+ * \since 11.0
+ *
+ * \param chan Chan to put into autoservice.
+ * \param peer Chan to run hangup handlers and hangup.
+ *
+ * \return Nothing
+ */
+static void autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
+{
+ if (chan) {
+ ast_autoservice_start(chan);
+ }
+ ast_pbx_hangup_handler_run(peer);
+ ast_hangup(peer);
+ if (chan) {
+ ast_autoservice_stop(chan);
+ }
+}
+
static int do_privacy(struct ast_channel *chan, struct ast_channel *peer,
struct ast_flags64 *opts, char **opt_args, struct privacy_args *pa)
{
@@ -1857,7 +1879,8 @@
}
return 0; /* the good exit path */
} else {
- ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
+ /* hang up on the callee -- he didn't want to talk anyway! */
+ autoservice_chan_hangup_peer(chan, peer);
return -1;
}
}
@@ -2750,7 +2773,7 @@
if (active_chan) {
struct ast_frame *fr = ast_read(active_chan);
if (!fr) {
- ast_hangup(peer);
+ autoservice_chan_hangup_peer(chan, peer);
res = -1;
goto done;
}
@@ -2766,7 +2789,7 @@
switch (fr->subclass.integer) {
case AST_CONTROL_HANGUP:
ast_frfree(fr);
- ast_hangup(peer);
+ autoservice_chan_hangup_peer(chan, peer);
res = -1;
goto done;
default:
@@ -2796,7 +2819,9 @@
ast_channel_context_set(peer, ast_channel_context(chan));
ast_channel_exten_set(peer, ast_channel_exten(chan));
ast_channel_priority_set(peer, ast_channel_priority(chan) + 2);
- ast_pbx_start(peer);
+ if (ast_pbx_start(peer)) {
+ autoservice_chan_hangup_peer(chan, peer);
+ }
hanguptree(&out_chans, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
if (continue_exec)
*continue_exec = 1;
@@ -3001,7 +3026,7 @@
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(chan), ast_channel_name(peer));
- ast_hangup(peer);
+ autoservice_chan_hangup_peer(chan, peer);
res = -1;
goto done;
}
@@ -3021,47 +3046,30 @@
if (ast_test_flag64(&opts, OPT_PEER_H)
&& ast_exists_extension(peer, ast_channel_context(peer), "h", 1,
S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
- int autoloopflag;
- int found;
- int res9;
-
- ast_channel_exten_set(peer, "h");
- ast_channel_priority_set(peer, 1);
- autoloopflag = ast_test_flag(ast_channel_flags(peer), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
- ast_set_flag(ast_channel_flags(peer), AST_FLAG_IN_AUTOLOOP);
-
- while ((res9 = ast_spawn_extension(peer, ast_channel_context(peer), ast_channel_exten(peer),
- ast_channel_priority(peer),
- S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL),
- &found, 1)) == 0) {
- ast_channel_priority_set(peer, ast_channel_priority(peer) + 1);
- }
-
- if (found && res9) {
- /* Something bad happened, or a hangup has been requested. */
- ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", ast_channel_context(peer), ast_channel_exten(peer), ast_channel_priority(peer), ast_channel_name(peer));
- ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", ast_channel_context(peer), ast_channel_exten(peer), ast_channel_priority(peer), ast_channel_name(peer));
- }
- ast_set2_flag(ast_channel_flags(peer), autoloopflag, AST_FLAG_IN_AUTOLOOP); /* set it back the way it was */
- }
- if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON)) {
- if(!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
- ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
- ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
- } else { /* F() */
+ ast_autoservice_start(chan);
+ ast_pbx_h_exten_run(peer, ast_channel_context(peer));
+ ast_autoservice_stop(chan);
+ }
+ if (!ast_check_hangup(peer)) {
+ if (ast_test_flag64(&opts, OPT_CALLEE_GO_ON)) {
int goto_res;
- goto_res = ast_goto_if_exists(peer, ast_channel_context(chan), ast_channel_exten(chan), (ast_channel_priority(chan)) + 1);
- if (goto_res == AST_PBX_GOTO_FAILED) {
- ast_hangup(peer);
+
+ if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
+ ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+ goto_res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
+ } else { /* F() */
+ goto_res = ast_goto_if_exists(peer, ast_channel_context(chan),
+ ast_channel_exten(chan), ast_channel_priority(chan) + 1);
+ }
+ if (!goto_res && !ast_pbx_start(peer)) {
+ /* The peer is now running its own PBX. */
goto out;
}
- }
- ast_pbx_start(peer);
- } else {
- if (!ast_check_hangup(chan))
+ } else {
ast_channel_hangupcause_set(chan, ast_channel_hangupcause(peer));
- ast_hangup(peer);
- }
+ }
+ }
+ autoservice_chan_hangup_peer(chan, peer);
}
out:
if (moh) {
Modified: team/rmudgett/hangup_handlers/channels/chan_local.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/channels/chan_local.c?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/channels/chan_local.c (original)
+++ team/rmudgett/hangup_handlers/channels/chan_local.c Thu Jun 14 20:01:19 2012
@@ -238,6 +238,12 @@
return -1;
}
+ if (!strcmp(write_info->function, "CHANNEL")
+ && !strcasecmp(write_info->data, "hangup_handler")) {
+ /* Block CHANNEL(hangup_handler) writes to the other local channel. */
+ return 0;
+ }
+
/* get the tech pvt */
if (!(p = ast_channel_tech_pvt(ast))) {
return -1;
Modified: team/rmudgett/hangup_handlers/funcs/func_channel.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/funcs/func_channel.c?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/funcs/func_channel.c (original)
+++ team/rmudgett/hangup_handlers/funcs/func_channel.c Thu Jun 14 20:01:19 2012
@@ -97,6 +97,13 @@
</enum>
<enum name="checkhangup">
<para>R/O Whether the channel is hanging up (1/0)</para>
+ </enum>
+ <enum name="hangup_handler">
+ <para>W/O Add a hangup handler to the channel. The
+ assigned string is passed to the Gosub application when
+ the channel is hung up. Any optionally omitted context
+ and exten are supplied by the channel adding the handler
+ before it is saved.</para>
</enum>
<enum name="language">
<para>R/W language for sounds played.</para>
@@ -523,6 +530,8 @@
break;
}
}
+ } else if (!strcasecmp(data, "hangup_handler")) {
+ ast_pbx_hangup_handler_add(chan, value);
} else if (!strncasecmp(data, "secure_bridge_", 14)) {
struct ast_datastore *ds;
struct ast_secure_call_store *store;
Modified: team/rmudgett/hangup_handlers/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/include/asterisk/channel.h?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/include/asterisk/channel.h (original)
+++ team/rmudgett/hangup_handlers/include/asterisk/channel.h Thu Jun 14 20:01:19 2012
@@ -731,6 +731,15 @@
T38_STATE_NEGOTIATED, /*!< T38 established */
};
+/*! Hangup handler instance node. */
+struct ast_hangup_handler {
+ /*! Next hangup handler node. */
+ AST_LIST_ENTRY(ast_hangup_handler) node;
+ /*! Hangup handler arg string passed to the Gosub application */
+ char args[0];
+};
+
+AST_LIST_HEAD_NOLOCK(ast_hangup_handler_list, ast_hangup_handler);
AST_LIST_HEAD_NOLOCK(ast_datastore_list, ast_datastore);
AST_LIST_HEAD_NOLOCK(ast_autochan_list, ast_autochan);
AST_LIST_HEAD_NOLOCK(ast_readq_list, ast_frame);
@@ -3739,6 +3748,7 @@
void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value);
/* List getters */
+struct ast_hangup_handler_list *ast_channel_hangup_handlers(struct ast_channel *chan);
struct ast_datastore_list *ast_channel_datastores(struct ast_channel *chan);
struct ast_autochan_list *ast_channel_autochans(struct ast_channel *chan);
struct ast_readq_list *ast_channel_readq(struct ast_channel *chan);
Modified: team/rmudgett/hangup_handlers/include/asterisk/pbx.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/include/asterisk/pbx.h?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/include/asterisk/pbx.h (original)
+++ team/rmudgett/hangup_handlers/include/asterisk/pbx.h Thu Jun 14 20:01:19 2012
@@ -368,6 +368,41 @@
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args);
/*!
+ * \brief Run the h exten from the given context.
+ * \since 11.0
+ *
+ * \param chan Channel to run the h exten on.
+ * \param context Context the h exten is in.
+ *
+ * \return Nothing
+ */
+void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context);
+
+/*!
+ * \brief Run all hangup handlers on the channel.
+ * \since 11.0
+ *
+ * \param chan Channel to run the hangup handlers on.
+ *
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
+ *
+ * \retval Zero if no hangup handlers run.
+ * \retval non-zero if hangup handlers were run.
+ */
+int ast_pbx_hangup_handler_run(struct ast_channel *chan);
+
+/*!
+ * \brief Add the given hangup handler to the channel.
+ * \since 11.0
+ *
+ * \param chan Channel to add the hangup handler to.
+ * \param handler Gosub application parameter string.
+ *
+ * \return Nothing
+ */
+void ast_pbx_hangup_handler_add(struct ast_channel *chan, const char *handler);
+
+/*!
* \brief Add and extension to an extension context.
*
* \param context context to add the extension to
Modified: team/rmudgett/hangup_handlers/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/main/channel.c?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/main/channel.c (original)
+++ team/rmudgett/hangup_handlers/main/channel.c Thu Jun 14 20:01:19 2012
@@ -1103,6 +1103,7 @@
headp = ast_channel_varshead(tmp);
AST_LIST_HEAD_INIT_NOLOCK(headp);
+ AST_LIST_HEAD_INIT_NOLOCK(ast_channel_hangup_handlers(tmp));
AST_LIST_HEAD_INIT_NOLOCK(ast_channel_datastores(tmp));
AST_LIST_HEAD_INIT_NOLOCK(ast_channel_autochans(tmp));
@@ -1179,6 +1180,9 @@
return NULL;
}
+ AST_LIST_HEAD_INIT_NOLOCK(ast_channel_hangup_handlers(tmp));
+ AST_LIST_HEAD_INIT_NOLOCK(ast_channel_datastores(tmp));
+
headp = ast_channel_varshead(tmp);
AST_LIST_HEAD_INIT_NOLOCK(headp);
@@ -2185,6 +2189,7 @@
struct ast_var_t *vardata;
struct ast_frame *f;
struct varshead *headp;
+ struct ast_hangup_handler *h_handler;
struct ast_datastore *datastore;
char device_name[AST_CHANNEL_NAME];
struct ast_callid *callid;
@@ -2194,8 +2199,14 @@
ast_cel_check_retire_linkedid(chan);
}
+ ast_channel_lock(chan);
+
+ /* Get rid of each of the hangup handlers on the channel */
+ while ((h_handler = AST_LIST_REMOVE_HEAD(ast_channel_hangup_handlers(chan), node))) {
+ ast_free(h_handler);
+ }
+
/* Get rid of each of the data stores on the channel */
- ast_channel_lock(chan);
while ((datastore = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry)))
/* Free the data store */
ast_datastore_free(datastore);
@@ -2312,10 +2323,21 @@
static void ast_dummy_channel_destructor(void *obj)
{
struct ast_channel *chan = obj;
+ struct ast_hangup_handler *h_handler;
+ struct ast_datastore *datastore;
struct ast_var_t *vardata;
struct varshead *headp;
- headp = ast_channel_varshead(chan);
+ /* Get rid of each of the hangup handlers on the channel (Just in case) */
+ while ((h_handler = AST_LIST_REMOVE_HEAD(ast_channel_hangup_handlers(chan), node))) {
+ ast_free(h_handler);
+ }
+
+ /* Get rid of each of the data stores on the channel */
+ while ((datastore = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry))) {
+ /* Free the data store */
+ ast_datastore_free(datastore);
+ }
ast_party_dialed_free(ast_channel_dialed(chan));
ast_party_caller_free(ast_channel_caller(chan));
@@ -2324,6 +2346,7 @@
/* loop over the variables list, freeing all data and deleting list items */
/* no need to lock the list, as the channel is already locked */
+ headp = ast_channel_varshead(chan);
while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
ast_var_delete(vardata);
@@ -6534,6 +6557,7 @@
const struct ast_channel_tech *t;
void *t_pvt;
union {
+ struct ast_hangup_handler_list handlers;
struct ast_party_dialed dialed;
struct ast_party_caller caller;
struct ast_party_connected_line connected;
@@ -6756,6 +6780,11 @@
}
ast_app_group_update(clonechan, original);
+
+ /* Swap hangup handlers. */
+ exchange.handlers = *ast_channel_hangup_handlers(original);
+ *ast_channel_hangup_handlers(original) = *ast_channel_hangup_handlers(clonechan);
+ *ast_channel_hangup_handlers(clonechan) = exchange.handlers;
/* Move data stores over */
if (AST_LIST_FIRST(ast_channel_datastores(clonechan))) {
Modified: team/rmudgett/hangup_handlers/main/channel_internal_api.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/main/channel_internal_api.c?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/main/channel_internal_api.c (original)
+++ team/rmudgett/hangup_handlers/main/channel_internal_api.c Thu Jun 14 20:01:19 2012
@@ -136,6 +136,7 @@
struct ast_readq_list readq;
struct ast_jb jb; /*!< The jitterbuffer state */
struct timeval dtmf_tv; /*!< The time that an in process digit began, or the last digit ended */
+ struct ast_hangup_handler_list hangup_handlers;/*!< Hangup handlers on the channel. */
struct ast_datastore_list datastores; /*!< Data stores on the channel */
struct ast_autochan_list autochans; /*!< Autochans on the channel */
unsigned long insmpl; /*!< Track the read/written samples for monitor use */
@@ -883,6 +884,10 @@
{
return &chan->writeformat;
}
+struct ast_hangup_handler_list *ast_channel_hangup_handlers(struct ast_channel *chan)
+{
+ return &chan->hangup_handlers;
+}
struct ast_datastore_list *ast_channel_datastores(struct ast_channel *chan)
{
return &chan->datastores;
Modified: team/rmudgett/hangup_handlers/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/main/features.c?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/main/features.c (original)
+++ team/rmudgett/hangup_handlers/main/features.c Thu Jun 14 20:01:19 2012
@@ -4166,7 +4166,6 @@
int diff;
int hasfeatures=0;
int hadfeatures=0;
- int autoloopflag;
int sendingdtmfdigit = 0;
int we_disabled_peer_cdr = 0;
struct ast_option_header *aoh;
@@ -4176,7 +4175,8 @@
struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
struct ast_silence_generator *silgen = NULL;
- const char *h_context;
+ /*! TRUE if h-exten or hangup handlers run. */
+ int hangup_run = 0;
pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
@@ -4608,105 +4608,80 @@
config->end_bridge_callback(config->end_bridge_callback_data);
}
- /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation
- * if it were, then chan belongs to a different thread now, and might have been hung up long
- * ago.
- */
- if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
- h_context = NULL;
- } else if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1,
- S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
- h_context = ast_channel_context(chan);
- } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
- && ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1,
- S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
- h_context = ast_channel_macrocontext(chan);
- } else {
- h_context = NULL;
- }
- if (h_context) {
+ if (!ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
struct ast_cdr *swapper = NULL;
char savelastapp[AST_MAX_EXTENSION];
char savelastdata[AST_MAX_EXTENSION];
char save_context[AST_MAX_CONTEXT];
char save_exten[AST_MAX_EXTENSION];
int save_prio;
- int found = 0; /* set if we find at least one match */
- int spawn_error = 0;
-
- /*
- * Make sure that the channel is marked as hungup since we are
- * going to run the "h" exten on it.
- */
- ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD);
-
- autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
- ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
- if (bridge_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 */
+
ast_channel_lock(chan);
if (bridge_cdr) {
+ /*
+ * Swap the bridge_cdr and the chan cdr for a moment, and let
+ * the hangup dialplan code operate on it.
+ */
swapper = ast_channel_cdr(chan);
+ ast_channel_cdr_set(chan, bridge_cdr);
+
+ /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
- ast_channel_cdr_set(chan, bridge_cdr);
}
ast_copy_string(save_context, ast_channel_context(chan), sizeof(save_context));
ast_copy_string(save_exten, ast_channel_exten(chan), sizeof(save_exten));
save_prio = ast_channel_priority(chan);
- if (h_context != ast_channel_context(chan)) {
- ast_channel_context_set(chan, h_context);
- }
- ast_channel_exten_set(chan, "h");
- ast_channel_priority_set(chan, 1);
ast_channel_unlock(chan);
- while ((spawn_error = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
- ast_channel_priority(chan),
- S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
- &found, 1)) == 0) {
- ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
- }
- if (found && spawn_error) {
- /* Something bad happened, or a hangup has been requested. */
- ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan));
- ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan));
- }
+ if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1,
+ S_COR(ast_channel_caller(chan)->id.number.valid,
+ ast_channel_caller(chan)->id.number.str, NULL))) {
+ ast_pbx_h_exten_run(chan, ast_channel_context(chan));
+ hangup_run = 1;
+ } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
+ && ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1,
+ S_COR(ast_channel_caller(chan)->id.number.valid,
+ ast_channel_caller(chan)->id.number.str, NULL))) {
+ ast_pbx_h_exten_run(chan, ast_channel_macrocontext(chan));
+ hangup_run = 1;
+ }
+ if (ast_pbx_hangup_handler_run(chan)) {
+ /* Indicate hangup handlers were run. */
+ hangup_run = 1;
+ }
+
+ ast_channel_lock(chan);
/* swap it back */
- ast_channel_lock(chan);
ast_channel_context_set(chan, save_context);
ast_channel_exten_set(chan, save_exten);
ast_channel_priority_set(chan, save_prio);
if (bridge_cdr) {
if (ast_channel_cdr(chan) == bridge_cdr) {
ast_channel_cdr_set(chan, swapper);
+
+ /* Restore the lastapp/lastdata */
+ ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
+ ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
} else {
bridge_cdr = NULL;
}
}
- /* An "h" exten has been run, so indicate that one has been run. */
- ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN);
ast_channel_unlock(chan);
-
- /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
- if (bridge_cdr) {
- ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
- ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
- }
- ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
}
/* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
new_chan_cdr = pick_unlocked_cdr(ast_channel_cdr(chan)); /* the proper chan cdr, if there are forked cdrs */
- /* If the channel CDR has been modified during the call, record the changes in the bridge cdr,
- * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite
- * what was done in the h extension. What a mess. This is why you never touch CDR code. */
- if (new_chan_cdr && bridge_cdr && !h_context) {
+
+ /*
+ * If the channel CDR has been modified during the call, record
+ * the changes in the bridge cdr, BUT, if hangup_run, the CDR
+ * got swapped so don't overwrite what was done in the
+ * h-extension or hangup handlers. What a mess. This is why
+ * you never touch CDR code.
+ */
+ if (new_chan_cdr && bridge_cdr && !hangup_run) {
ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
bridge_cdr->amaflags = new_chan_cdr->amaflags;
Modified: team/rmudgett/hangup_handlers/main/pbx.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/main/pbx.c?view=diff&rev=368992&r1=368991&r2=368992
==============================================================================
--- team/rmudgett/hangup_handlers/main/pbx.c (original)
+++ team/rmudgett/hangup_handlers/main/pbx.c Thu Jun 14 20:01:19 2012
@@ -5337,6 +5337,267 @@
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
}
+void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
+{
+ int autoloopflag;
+ int found;
+ int spawn_error;
+
+ ast_channel_lock(chan);
+
+ if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
+ ast_cdr_end(ast_channel_cdr(chan));
+ }
+
+ /* Set h exten location */
+ if (context != ast_channel_context(chan)) {
+ ast_channel_context_set(chan, context);
+ }
+ ast_channel_exten_set(chan, "h");
+ ast_channel_priority_set(chan, 1);
+
+ /*
+ * Make sure that the channel is marked as hungup since we are
+ * going to run the h exten on it.
+ */
+ ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
+
+ /* Save autoloop flag */
+ autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
+ ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
+ ast_channel_unlock(chan);
+
+ for (;;) {
+ spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
+ ast_channel_exten(chan), ast_channel_priority(chan),
+ S_COR(ast_channel_caller(chan)->id.number.valid,
+ ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
+
+ ast_channel_lock(chan);
+ if (spawn_error) {
+ break;
+ }
+ ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
+ ast_channel_unlock(chan);
+ }
+ if (found && spawn_error) {
+ /* Something bad happened, or a hangup has been requested. */
+ ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
+ ast_channel_context(chan), ast_channel_exten(chan),
+ ast_channel_priority(chan), ast_channel_name(chan));
+ ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
+ ast_channel_context(chan), ast_channel_exten(chan),
+ ast_channel_priority(chan), ast_channel_name(chan));
+ }
+
+ /* An "h" exten has been run, so indicate that one has been run. */
+ ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN);
+
+ /* Restore autoloop flag */
+ ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
+ ast_channel_unlock(chan);
+}
+
+/* BUGBUG need to examine all ast_bridge_call() to see about calling ast_pbx_hangup_handler_run(). */
+int ast_pbx_hangup_handler_run(struct ast_channel *chan)
+{
+ struct ast_hangup_handler_list *list;
+ struct ast_hangup_handler *h_handler;
+
+ ast_channel_lock(chan);
+ list = ast_channel_hangup_handlers(chan);
+ if (AST_LIST_EMPTY(list)) {
+ ast_channel_unlock(chan);
+ return 0;
+ }
+
+ if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
+ ast_cdr_end(ast_channel_cdr(chan));
+ }
+
+ /*
+ * Make sure that the channel is marked as hungup since we are
+ * going to run the hangup handlers on it.
+ */
+ ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
+
+ for (;;) {
+ list = ast_channel_hangup_handlers(chan);
+ h_handler = AST_LIST_REMOVE_HEAD(list, node);
+ if (!h_handler) {
+ ast_channel_unlock(chan);
+ break;
+ }
+
+ manager_event(EVENT_FLAG_CALL, "HangupHandlerRun",
+ "Channel: %s\r\n"
+ "Uniqueid: %s\r\n"
+ "Handler: %s\r\n",
+ ast_channel_name(chan),
+ ast_channel_uniqueid(chan),
+ h_handler->args);
+ ast_channel_unlock(chan);
+
+ ast_app_exec_sub(NULL, chan, h_handler->args, 1);
+ ast_free(h_handler);
+
+ ast_channel_lock(chan);
+ }
+ return 1;
+}
+
+void ast_pbx_hangup_handler_add(struct ast_channel *chan, const char *handler)
+{
+ struct ast_hangup_handler_list *list;
+ struct ast_hangup_handler *h_handler;
+ const char *expanded_handler;
+
+ if (ast_strlen_zero(handler)) {
+ return;
+ }
+
+ expanded_handler = ast_app_expand_sub_args(chan, handler);
+ if (!expanded_handler) {
+ return;
+ }
+ h_handler = ast_malloc(sizeof(*h_handler) + 1 + strlen(expanded_handler));
+ if (!h_handler) {
+ ast_free((char *) expanded_handler);
+ return;
+ }
+ strcpy(h_handler->args, expanded_handler);/* Safe */
+ ast_free((char *) expanded_handler);
+
+ ast_channel_lock(chan);
+
+ list = ast_channel_hangup_handlers(chan);
+ AST_LIST_INSERT_HEAD(list, h_handler, node);
+
+ manager_event(EVENT_FLAG_CALL, "HangupHandlerAdd",
+ "Channel: %s\r\n"
+ "Uniqueid: %s\r\n"
+ "Handler: %s\r\n",
+ ast_channel_name(chan),
+ ast_channel_uniqueid(chan),
+ h_handler->args);
+
+ ast_channel_unlock(chan);
+}
+
+#define HANDLER_FORMAT "%-30s %s\n"
+
+/*!
+ * \internal
+ * \brief CLI output the hangup handler headers.
+ * \since 11.0
+ *
+ * \param fd CLI file descriptor to use.
+ *
+ * \return Nothing
+ */
+static void ast_pbx_hangup_handler_headers(int fd)
+{
+ ast_cli(fd, HANDLER_FORMAT, "Channel", "Handler");
+}
+
+/*!
+ * \internal
+ * \brief CLI output the channel hangup handlers.
+ * \since 11.0
+ *
+ * \param fd CLI file descriptor to use.
+ * \param chan Channel to show hangup handlers.
+ *
+ * \return Nothing
+ */
+static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
+{
+ struct ast_hangup_handler_list *list;
+ struct ast_hangup_handler *h_handler;
+ int first = 1;
+
+ ast_channel_lock(chan);
+ list = ast_channel_hangup_handlers(chan);
+ AST_LIST_TRAVERSE(list, h_handler, node) {
+ ast_cli(fd, HANDLER_FORMAT, first ? ast_channel_name(chan) : "", h_handler->args);
+ first = 0;
+ }
+ ast_channel_unlock(chan);
+}
+
+/*
+ * \brief 'show hanguphandlers <channel>' CLI command implementation function...
+ */
+static char *handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_channel *chan;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core show hanguphandlers";
+ e->usage =
+ "Usage: core show hanguphandlers <channel>\n"
+ " Show hangup handlers of a specified channel.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
+ }
+
+ if (a->argc < 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ chan = ast_channel_get_by_name(a->argv[3]);
+ if (!chan) {
+ ast_cli(a->fd, "Channel does not exist.\n");
+ return CLI_FAILURE;
+ }
+
+ ast_pbx_hangup_handler_headers(a->fd);
+ ast_pbx_hangup_handler_show(a->fd, chan);
+
+ ast_channel_unref(chan);
+
+ return CLI_SUCCESS;
+}
+
+/*
+ * \brief 'show hanguphandlers all' CLI command implementation function...
+ */
+static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ast_channel_iterator *iter;
+ struct ast_channel *chan;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core show hanguphandlers all";
+ e->usage =
+ "Usage: core show hanguphandlers all\n"
+ " Show hangup handlers for all channels.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
+ }
+
+ if (a->argc < 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ iter = ast_channel_iterator_all_new();
+ if (!iter) {
+ return CLI_FAILURE;
+ }
+
+ ast_pbx_hangup_handler_headers(a->fd);
+ for (; (chan = ast_channel_iterator_next(iter)); ast_channel_unref(chan)) {
+ ast_pbx_hangup_handler_show(a->fd, chan);
+ }
+ ast_channel_iterator_destroy(iter);
+
+ return CLI_SUCCESS;
+}
+
/*! helper function to set extension and priority */
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
{
@@ -5675,27 +5936,15 @@
if (!args || !args->no_hangup_chan) {
ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
- }
-
- if ((!args || !args->no_hangup_chan)
- && !ast_test_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN)
- && ast_exists_extension(c, ast_channel_context(c), "h", 1,
- S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
- set_ext_pri(c, "h", 1);
- if (ast_channel_cdr(c) && ast_opt_end_cdr_before_h_exten) {
- ast_cdr_end(ast_channel_cdr(c));
- }
- while ((res = ast_spawn_extension(c, ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c),
- S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL),
- &found, 1)) == 0) {
- ast_channel_priority_set(c, ast_channel_priority(c) + 1);
- }
- if (found && res) {
- /* Something bad happened, or a hangup has been requested. */
- ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
- ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_name(c));
- }
- }
+ if (!ast_test_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN)
+ && ast_exists_extension(c, ast_channel_context(c), "h", 1,
+ S_COR(ast_channel_caller(c)->id.number.valid,
+ ast_channel_caller(c)->id.number.str, NULL))) {
+ ast_pbx_h_exten_run(c, ast_channel_context(c));
+ }
+ ast_pbx_hangup_handler_run(c);
+ }
+
ast_set2_flag(ast_channel_flags(c), autoloopflag, AST_FLAG_IN_AUTOLOOP);
ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
pbx_destroy(ast_channel_pbx(c));
@@ -7585,6 +7834,8 @@
#endif
AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
+ AST_CLI_DEFINE(handle_show_hangup_all, "Show hangup handlers of all channels"),
+ AST_CLI_DEFINE(handle_show_hangup_channel, "Show hangup handlers of a specified channel"),
AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
More information about the asterisk-commits
mailing list