No subject


Fri Sep 2 03:59:05 CDT 2011


* Make non-normal dialplan execution routines be able to run on a hung up
channel.  This is preparation work for hangup handler routines.

* Fixes non-normal execution routines like connected line interception and
predial leaving the dialplan execution stack unbalanced.  Errors like
missing Return statements, popping too many stack frames using StackPop,
or an application returning non-zero could leave the dialplan stack
unbalanced.

* Make Hangup set a softhangup flag.  The Hangup application used to just
return -1 to cause normal dialplan execution to hangup a channel.  For the
non-normal execution routines like predial and connected-line interception
routines, the hangup request would be ignored.

Modified:
    team/rmudgett/hangup_handlers/apps/app_dial.c
    team/rmudgett/hangup_handlers/apps/app_followme.c
    team/rmudgett/hangup_handlers/apps/app_queue.c
    team/rmudgett/hangup_handlers/apps/app_stack.c
    team/rmudgett/hangup_handlers/include/asterisk/app.h
    team/rmudgett/hangup_handlers/main/app.c
    team/rmudgett/hangup_handlers/main/ccss.c
    team/rmudgett/hangup_handlers/main/channel.c
    team/rmudgett/hangup_handlers/main/pbx.c

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=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/apps/app_dial.c (original)
+++ team/rmudgett/hangup_handlers/apps/app_dial.c Mon Jun 11 14:02:19 2012
@@ -2280,7 +2280,7 @@
 	if (ast_test_flag64(&opts, OPT_PREDIAL_CALLER)
 		&& !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
 		ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]);
-		ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER]);
+		ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
 	}
 
 	/* loop through the list of dial destinations */
@@ -2884,7 +2884,7 @@
 				}
 			}
 			if (gosub_args) {
-				res9 = ast_app_exec_sub(chan, peer, gosub_args);
+				res9 = ast_app_exec_sub(chan, peer, gosub_args, 0);
 				ast_free(gosub_args);
 			} else {
 				ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");

Modified: team/rmudgett/hangup_handlers/apps/app_followme.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/apps/app_followme.c?view=diff&rev=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/apps/app_followme.c (original)
+++ team/rmudgett/hangup_handlers/apps/app_followme.c Mon Jun 11 14:02:19 2012
@@ -1393,7 +1393,7 @@
 	if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_PREDIAL_CALLER)
 		&& !ast_strlen_zero(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER])) {
 		ast_replace_subargument_delimiter(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER]);
-		ast_app_exec_sub(NULL, chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER]);
+		ast_app_exec_sub(NULL, chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER], 0);
 	}
 
 	/* Forget the 'N' option if the call is already up. */

Modified: team/rmudgett/hangup_handlers/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/apps/app_queue.c?view=diff&rev=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/apps/app_queue.c (original)
+++ team/rmudgett/hangup_handlers/apps/app_queue.c Mon Jun 11 14:02:19 2012
@@ -5352,7 +5352,7 @@
 				}
 			}
 			if (gosub_args) {
-				ast_app_exec_sub(qe->chan, peer, gosub_args);
+				ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
 				ast_free(gosub_args);
 			} else {
 				ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");

Modified: team/rmudgett/hangup_handlers/apps/app_stack.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/apps/app_stack.c?view=diff&rev=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/apps/app_stack.c (original)
+++ team/rmudgett/hangup_handlers/apps/app_stack.c Mon Jun 11 14:02:19 2012
@@ -200,10 +200,16 @@
 	</agi>
  ***/
 
-static const char * const app_gosub = "Gosub";
-static const char * const app_gosubif = "GosubIf";
-static const char * const app_return = "Return";
-static const char * const app_pop = "StackPop";
+static const char app_gosub[] = "Gosub";
+static const char app_gosubif[] = "GosubIf";
+static const char app_return[] = "Return";
+static const char app_pop[] = "StackPop";
+static const char mod_name[] = "app_stack";
+
+/*! gosub_run() return context */
+static const char ret_context[] = "gosub_virtual_context";
+/*! gosub_run() return exten */
+static const char ret_exten[] = "s";
 
 static void gosub_free(void *data);
 
@@ -306,6 +312,7 @@
 	struct ast_datastore *stack_store;
 	struct gosub_stack_frame *oldframe;
 	AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
+	int res = 0;
 
 	ast_channel_lock(chan);
 	if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
@@ -316,16 +323,25 @@
 
 	oldlist = stack_store->data;
 	AST_LIST_LOCK(oldlist);
-	oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
-	AST_LIST_UNLOCK(oldlist);
-
+	oldframe = AST_LIST_FIRST(oldlist);
 	if (oldframe) {
-		gosub_release_frame(chan, oldframe);
+		if (oldframe->priority == 1
+			&& !strcmp(oldframe->context, ret_context)
+			&& !strcmp(oldframe->extension, ret_exten)) {
+			ast_debug(1, "%s attempted to pop gosub_run() return location.\n", app_pop);
+
+			/* Abort the gosub_run() dialplan execution.  Dialplan programming error. */
+			res = -1;
+		} else {
+			AST_LIST_REMOVE_HEAD(oldlist, entries);
+			gosub_release_frame(chan, oldframe);
+		}
 	} else {
 		ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
 	}
+	AST_LIST_UNLOCK(oldlist);
 	ast_channel_unlock(chan);
-	return 0;
+	return res;
 }
 
 static int return_exec(struct ast_channel *chan, const char *data)
@@ -742,6 +758,193 @@
 	.read2 = stackpeek_read,
 };
 
+/*!
+ * \internal
+ * \brief Helper function removes stack frames until remove an expected return location.
+ * \since 11.0
+ *
+ * \param chan Channel to balance stack on.
+ *
+ * \details
+ * Pop stack frames until find a gosub_run() return location.
+ *
+ * \note The channel is already locked when called.
+ *
+ * \return Nothing
+ */
+static void balance_stack(struct ast_channel *chan)
+{
+	struct ast_datastore *stack_store;
+	AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
+	struct gosub_stack_frame *oldframe;
+	int found;
+
+	stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
+	if (!stack_store) {
+		ast_log(LOG_WARNING, "No gosub stack allocated.\n");
+		return;
+	}
+
+	oldlist = stack_store->data;
+	AST_LIST_LOCK(oldlist);
+	found = 0;
+	do {
+		oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
+		if (!oldframe) {
+			break;
+		}
+		if (oldframe->priority == 1
+			&& !strcmp(oldframe->context, ret_context)
+			&& !strcmp(oldframe->extension, ret_exten)) {
+			found = 1;
+		}
+		gosub_release_frame(chan, oldframe);
+	} while (!found);
+	AST_LIST_UNLOCK(oldlist);
+}
+
+/*!
+ * \internal
+ * \brief Run a subroutine on a channel.
+ * \since 11.0
+ *
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
+ *
+ * \param chan Channel to execute subroutine on.
+ * \param sub_args Gosub application argument string.
+ * \param ignore_hangup TRUE if a hangup does not stop execution of the routine.
+ *
+ * \retval 0 success
+ * \retval -1 on error
+ */
+static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_hangup)
+{
+	const char *saved_context;
+	const char *saved_exten;
+	int saved_priority;
+	int saved_hangup_flags;
+	int saved_autoloopflag;
+	int res;
+
+	ast_channel_lock(chan);
+
+	/* Save non-hangup softhangup flags. */
+	saved_hangup_flags = ast_channel_softhangup_internal_flag(chan)
+		& (AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE);
+	if (saved_hangup_flags) {
+		ast_channel_clear_softhangup(chan,
+			AST_SOFTHANGUP_ASYNCGOTO | AST_SOFTHANGUP_UNBRIDGE);
+	}
+
+	/* Save current dialplan location */
+	saved_context = ast_strdupa(ast_channel_context(chan));
+	saved_exten = ast_strdupa(ast_channel_exten(chan));
+	saved_priority = ast_channel_priority(chan);
+
+	/* Set known location for Gosub to return - 1 */
+	ast_channel_context_set(chan, ret_context);
+	ast_channel_exten_set(chan, ret_exten);
+	ast_channel_priority_set(chan, 1 - 1);
+
+	/* Save autoloop flag */
+	saved_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
+	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
+
+	ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
+		saved_context, saved_exten, saved_priority);
+
+	ast_channel_unlock(chan);
+	res = gosub_exec(chan, sub_args);
+	ast_debug(4, "%s exited with status %d\n", app_gosub, res);
+	ast_channel_lock(chan);
+	if (!res) {
+		int found = 0;	/* set if we find at least one match */
+		int sub_returned = 0;
+
+		/*
+		 * Run gosub body autoloop.
+		 *
+		 * Note that this loop is inverted from the normal execution
+		 * loop because we just executed the Gosub application as the
+		 * first extension of the autoloop.
+		 */
+		do {
+			/* Check for hangup. */
+			if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_UNBRIDGE) {
+				saved_hangup_flags |= AST_SOFTHANGUP_UNBRIDGE;
+				ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_UNBRIDGE);
+			}
+			if (ast_check_hangup(chan)) {
+				if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
+					ast_log(LOG_ERROR, "An async goto just messed up our execution location.\n");
+					break;
+				}
+				if (!ignore_hangup) {
+					break;
+				}
+			}
+
+			/* Next dialplan priority. */
+			ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
+
+			ast_channel_unlock(chan);
+			res = 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);
+
+			/* Did the routine return? */
+			if (ast_channel_priority(chan) == 1 - 1
+				&& !strcmp(ast_channel_context(chan), ret_context)
+				&& !strcmp(ast_channel_exten(chan), ret_exten)) {
+				sub_returned = 1;
+			}
+		} while (!res);
+		if (found && res) {
+			/* Something bad happened, or a hangup has been requested. */
+			ast_debug(1, "Spawn extension (%s,%s,%d) exited with %d on '%s'\n",
+				ast_channel_context(chan), ast_channel_exten(chan),
+				ast_channel_priority(chan), res, 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 (!sub_returned) {
+			ast_log(LOG_NOTICE, "Abnormal '%s(%s)' exit.  Popping routine return locations.\n",
+				app_gosub, sub_args);
+			balance_stack(chan);
+		}
+
+		/* We executed the requested subroutine to the best of our ability. */
+		res = 0;
+	}
+
+	ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
+		ast_channel_context(chan), ast_channel_exten(chan),
+		ast_channel_priority(chan));
+
+	/* Restore autoloop flag */
+	ast_set2_flag(ast_channel_flags(chan), saved_autoloopflag, AST_FLAG_IN_AUTOLOOP);
+
+	/* Restore dialplan location */
+	if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)) {
+		ast_channel_context_set(chan, saved_context);
+		ast_channel_exten_set(chan, saved_exten);
+		ast_channel_priority_set(chan, saved_priority);
+	}
+
+	/* Restore non-hangup softhangup flags. */
+	if (saved_hangup_flags) {
+		ast_softhangup_nolock(chan, saved_hangup_flags);
+	}
+
+	ast_channel_unlock(chan);
+
+	return res;
+}
+
 static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char * const *argv)
 {
 	int old_priority, priority;
@@ -854,6 +1057,8 @@
 {
 	struct ast_context *con;
 
+	ast_install_stack_functions(NULL);
+
 	ast_agi_unregister(ast_module_info->self, &gosub_agi_command);
 
 	ast_unregister_application(app_return);
@@ -864,11 +1069,11 @@
 	ast_custom_function_unregister(&peek_function);
 	ast_custom_function_unregister(&stackpeek_function);
 
-	con = ast_context_find("gosub_virtual_context");
+	con = ast_context_find(ret_context);
 	if (con) {
 		/* leave nothing behind */
-		ast_context_remove_extension2(con, "s", 1, NULL, 0);
-		ast_context_destroy(con, "app_stack");
+		ast_context_remove_extension2(con, ret_exten, 1, NULL, 0);
+		ast_context_destroy(con, mod_name);
 	}
 
 	return 0;
@@ -878,14 +1083,19 @@
 {
 	struct ast_context *con;
 
+	/*! Setup the stack application callback functions. */
+	static struct ast_app_stack_funcs funcs = {
+		.run_sub = gosub_run,
+	};
+
 	/* Create internal gosub return target to indicate successful completion. */
-	con = ast_context_find_or_create(NULL, NULL, "gosub_virtual_context", "app_stack");
+	con = ast_context_find_or_create(NULL, NULL, ret_context, mod_name);
 	if (!con) {
-		ast_log(LOG_ERROR, "'gosub_virtual_context' does not exist and unable to create\n");
+		ast_log(LOG_ERROR, "'%s' does not exist and unable to create\n", ret_context);
 	} else {
-		ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp",
+		ast_add_extension2(con, 1, ret_exten, 1, NULL, NULL, "NoOp",
 			ast_strdup("Internal Gosub call complete GOSUB_RETVAL=${GOSUB_RETVAL}"),
-			ast_free_ptr, "app_stack");
+			ast_free_ptr, mod_name);
 	}
 
 	ast_agi_register(ast_module_info->self, &gosub_agi_command);
@@ -898,6 +1108,9 @@
 	ast_custom_function_register(&peek_function);
 	ast_custom_function_register(&stackpeek_function);
 
+	funcs.module = ast_module_info->self,
+	ast_install_stack_functions(&funcs);
+
 	return 0;
 }
 

Modified: team/rmudgett/hangup_handlers/include/asterisk/app.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/include/asterisk/app.h?view=diff&rev=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/include/asterisk/app.h (original)
+++ team/rmudgett/hangup_handlers/include/asterisk/app.h Mon Jun 11 14:02:19 2012
@@ -147,8 +147,7 @@
  * supply a NULL autoservice_chan here in case there is no
  * channel to place into autoservice.
  *
- * \note It is very important that the autoservice_chan is not
- * locked prior to calling.  Otherwise, a deadlock could result.
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
  *
  * \param autoservice_chan A channel to place into autoservice while the macro is run
  * \param macro_chan Channel to execute macro on.
@@ -169,8 +168,7 @@
  * supply a NULL autoservice_chan here in case there is no
  * channel to place into autoservice.
  *
- * \note It is very important that the autoservice_chan is not
- * locked prior to calling.  Otherwise, a deadlock could result.
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
  *
  * \param autoservice_chan A channel to place into autoservice while the macro is run
  * \param macro_chan Channel to execute macro on.
@@ -182,6 +180,40 @@
  */
 int ast_app_run_macro(struct ast_channel *autoservice_chan,
 	struct ast_channel *macro_chan, const char *macro_name, const char *macro_args);
+
+/*!
+ * \brief Stack applications callback functions.
+ */
+struct ast_app_stack_funcs {
+	/*!
+	 * Module reference pointer so the module will stick around
+	 * while a callback is active.
+	 */
+	void *module;
+
+	/*!
+	 * \brief Callback for the routine to run a subroutine on a channel.
+	 *
+	 * \note Absolutely _NO_ channel locks should be held before calling this function.
+	 *
+	 * \param chan Channel to execute subroutine on.
+	 * \param args Gosub application argument string.
+	 * \param ignore_hangup TRUE if a hangup does not stop execution of the routine.
+	 *
+	 * \retval 0 success
+	 * \retval -1 on error
+	 */
+	int (*run_sub)(struct ast_channel *chan, const char *args, int ignore_hangup);
+
+	/* Add new API calls to the end here. */
+};
+
+/*!
+ * \since 11
+ * \brief Set stack application function callbacks
+ * \param funcs Stack applications callback functions.
+ */
+void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs);
 
 /*!
  * \since 11
@@ -193,17 +225,17 @@
  * to supply a NULL autoservice_chan here in case there is no
  * channel to place into autoservice.
  *
- * \note It is very important that the autoservice_chan is not
- * locked prior to calling.  Otherwise, a deadlock could result.
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
  *
  * \param autoservice_chan A channel to place into autoservice while the subroutine is run
  * \param sub_chan Channel to execute subroutine on.
  * \param sub_args Gosub application argument string.
+ * \param ignore_hangup TRUE if a hangup does not stop execution of the routine.
  *
  * \retval 0 success
  * \retval -1 on error
  */
-int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args);
+int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup);
 
 /*!
  * \since 11
@@ -215,19 +247,19 @@
  * to supply a NULL autoservice_chan here in case there is no
  * channel to place into autoservice.
  *
- * \note It is very important that the autoservice_chan is not
- * locked prior to calling.  Otherwise, a deadlock could result.
+ * \note Absolutely _NO_ channel locks should be held before calling this function.
  *
  * \param autoservice_chan A channel to place into autoservice while the subroutine is run
  * \param sub_chan Channel to execute subroutine on.
  * \param sub_location The location of the subroutine to run.
  * \param sub_args The arguments to pass to the subroutine.
+ * \param ignore_hangup TRUE if a hangup does not stop execution of the routine.
  *
  * \retval 0 success
  * \retval -1 on error
  */
 int ast_app_run_sub(struct ast_channel *autoservice_chan,
-	struct ast_channel *sub_chan, const char *sub_location, const char *sub_args);
+	struct ast_channel *sub_chan, const char *sub_location, const char *sub_args, int ignore_hangup);
 
 /*!
  * \brief Set voicemail function callbacks

Modified: team/rmudgett/hangup_handlers/main/app.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/main/app.c?view=diff&rev=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/main/app.c (original)
+++ team/rmudgett/hangup_handlers/main/app.c Mon Jun 11 14:02:19 2012
@@ -55,6 +55,7 @@
 #include "asterisk/linkedlists.h"
 #include "asterisk/threadstorage.h"
 #include "asterisk/test.h"
+#include "asterisk/module.h"
 
 AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf);
 
@@ -312,82 +313,33 @@
 	return res;
 }
 
-int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args)
-{
-	struct ast_app *sub_app;
-	const char *saved_context;
-	const char *saved_exten;
-	int saved_priority;
-	int saved_autoloopflag;
+static const struct ast_app_stack_funcs *app_stack_callbacks;
+
+void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
+{
+	app_stack_callbacks = funcs;
+}
+
+int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
+{
+	const struct ast_app_stack_funcs *funcs;
 	int res;
 
-	sub_app = pbx_findapp("Gosub");
-	if (!sub_app) {
+	funcs = app_stack_callbacks;
+	if (!funcs || !funcs->run_sub) {
 		ast_log(LOG_WARNING,
-			"Cannot run 'Gosub(%s)'.  The application is not available.\n", sub_args);
+			"Cannot run 'Gosub(%s)'.  The app_stack module is not available.\n",
+			sub_args);
 		return -1;
 	}
+	ast_module_ref(funcs->module);
+
 	if (autoservice_chan) {
 		ast_autoservice_start(autoservice_chan);
 	}
 
-	ast_channel_lock(sub_chan);
-
-	/* Save current dialplan location */
-	saved_context = ast_strdupa(ast_channel_context(sub_chan));
-	saved_exten = ast_strdupa(ast_channel_exten(sub_chan));
-	saved_priority = ast_channel_priority(sub_chan);
-
-	/*
-	 * Save flag to restore at the end so we don't have to play with
-	 * the priority in the gosub location string.
-	 */
-	saved_autoloopflag = ast_test_flag(ast_channel_flags(sub_chan), AST_FLAG_IN_AUTOLOOP);
-	ast_clear_flag(ast_channel_flags(sub_chan), AST_FLAG_IN_AUTOLOOP);
-
-	/* Set known location for Gosub to return - 1 */
-	ast_channel_context_set(sub_chan, "gosub_virtual_context");
-	ast_channel_exten_set(sub_chan, "s");
-	ast_channel_priority_set(sub_chan, 1 - 1);
-
-	ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(sub_chan),
-		saved_context, saved_exten, saved_priority);
-
-	ast_channel_unlock(sub_chan);
-	res = pbx_exec(sub_chan, sub_app, sub_args);
-	ast_debug(4, "Gosub exited with status %d\n", res);
-	ast_channel_lock(sub_chan);
-	if (!res) {
-		struct ast_pbx_args gosub_args = {{0}};
-		struct ast_pbx *saved_pbx;
-
-		/* supress warning about a pbx already being on the channel */
-		saved_pbx = ast_channel_pbx(sub_chan);
-		ast_channel_pbx_set(sub_chan, NULL);
-
-		ast_channel_unlock(sub_chan);
-		gosub_args.no_hangup_chan = 1;
-		ast_pbx_run_args(sub_chan, &gosub_args);
-		ast_channel_lock(sub_chan);
-
-		/* Restore pbx. */
-		ast_free(ast_channel_pbx(sub_chan));
-		ast_channel_pbx_set(sub_chan, saved_pbx);
-	}
-
-	ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(sub_chan),
-		ast_channel_context(sub_chan), ast_channel_exten(sub_chan),
-		ast_channel_priority(sub_chan));
-
-	/* Restore flag */
-	ast_set2_flag(ast_channel_flags(sub_chan), saved_autoloopflag, AST_FLAG_IN_AUTOLOOP);
-
-	/* Restore dialplan location */
-	ast_channel_context_set(sub_chan, saved_context);
-	ast_channel_exten_set(sub_chan, saved_exten);
-	ast_channel_priority_set(sub_chan, saved_priority);
-
-	ast_channel_unlock(sub_chan);
+	res = funcs->run_sub(sub_chan, sub_args, ignore_hangup);
+	ast_module_unref(funcs->module);
 
 	if (autoservice_chan) {
 		ast_autoservice_stop(autoservice_chan);
@@ -395,14 +347,14 @@
 	return res;
 }
 
-int ast_app_run_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_location, const char *sub_args)
+int ast_app_run_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_location, const char *sub_args, int ignore_hangup)
 {
 	int res;
 	char *args_str;
 	size_t args_len;
 
 	if (ast_strlen_zero(sub_args)) {
-		return ast_app_exec_sub(autoservice_chan, sub_chan, sub_location);
+		return ast_app_exec_sub(autoservice_chan, sub_chan, sub_location, ignore_hangup);
 	}
 
 	/* Create the Gosub application argument string. */
@@ -413,7 +365,7 @@
 	}
 	snprintf(args_str, args_len, "%s(%s)", sub_location, sub_args);
 
-	res = ast_app_exec_sub(autoservice_chan, sub_chan, args_str);
+	res = ast_app_exec_sub(autoservice_chan, sub_chan, args_str, ignore_hangup);
 	ast_free(args_str);
 	return res;
 }

Modified: team/rmudgett/hangup_handlers/main/ccss.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/hangup_handlers/main/ccss.c?view=diff&rev=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/main/ccss.c (original)
+++ team/rmudgett/hangup_handlers/main/ccss.c Mon Jun 11 14:02:19 2012
@@ -2724,7 +2724,7 @@
 	if (!ast_strlen_zero(callback_macro)) {
 		ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback macro configured for agent %s\n",
 				agent->core_id, agent->device_name);
-		if (ast_app_run_macro(NULL, chan, callback_macro, NULL)) {
+		if (ast_app_exec_macro(NULL, chan, callback_macro)) {
 			ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
 			ast_hangup(chan);
 			return NULL;
@@ -2734,7 +2734,7 @@
 	if (!ast_strlen_zero(callback_sub)) {
 		ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback subroutine configured for agent %s\n",
 				agent->core_id, agent->device_name);
-		if (ast_app_run_sub(NULL, chan, callback_sub, NULL)) {
+		if (ast_app_exec_sub(NULL, chan, callback_sub, 0)) {
 			ast_cc_failed(agent->core_id, "Callback subroutine to %s failed. Maybe a hangup?", agent->device_name);
 			ast_hangup(chan);
 			return NULL;

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=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/main/channel.c (original)
+++ team/rmudgett/hangup_handlers/main/channel.c Mon Jun 11 14:02:19 2012
@@ -5729,7 +5729,7 @@
 		return res;
 	}
 	ast_channel_unlock(chan);
-	return ast_app_exec_sub(NULL, chan, sub_args);
+	return ast_app_exec_sub(NULL, chan, sub_args, 0);
 }
 
 int ast_call(struct ast_channel *chan, const char *addr, int timeout)
@@ -9801,7 +9801,7 @@
 	}
 	ast_channel_unlock(sub_chan);
 
-	retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args);
+	retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
 	if (!retval) {
 		struct ast_party_connected_line saved_connected;
 
@@ -9844,7 +9844,7 @@
 	}
 	ast_channel_unlock(sub_chan);
 
-	retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args);
+	retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
 	if (!retval) {
 		struct ast_party_redirecting saved_redirecting;
 

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=368780&r1=368779&r2=368780
==============================================================================
--- team/rmudgett/hangup_handlers/main/pbx.c (original)
+++ team/rmudgett/hangup_handlers/main/pbx.c Mon Jun 11 14:02:19 2012
@@ -10020,29 +10020,32 @@
  */
 static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
 {
+	int cause;
+
 	ast_set_hangupsource(chan, "dialplan/builtin", 0);
 
 	if (!ast_strlen_zero(data)) {
-		int cause;
-		char *endptr;
-
-		if ((cause = ast_str2cause(data)) > -1) {
-			ast_channel_hangupcause_set(chan, cause);
-			return -1;
-		}
-
-		cause = strtol((const char *) data, &endptr, 10);
-		if (cause != 0 || (data != endptr)) {
-			ast_channel_hangupcause_set(chan, cause);
-			return -1;
-		}
-
-		ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
-	}
-
-	if (!ast_channel_hangupcause(chan)) {
-		ast_channel_hangupcause_set(chan, AST_CAUSE_NORMAL_CLEARING);
-	}
+		cause = ast_str2cause(data);
+		if (cause <= 0) {
+			if (sscanf(data, "%30d", &cause) != 1 || cause <= 0) {
+				ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", data);
+				cause = 0;
+			}
+		}
+	} else {
+		cause = 0;
+	}
+
+	ast_channel_lock(chan);
+	if (cause <= 0) {
+		cause = ast_channel_hangupcause(chan);
+	}
+	if (cause <= 0) {
+		cause = AST_CAUSE_NORMAL_CLEARING;
+	}
+	ast_channel_hangupcause_set(chan, cause);
+	ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT);
+	ast_channel_unlock(chan);
 
 	return -1;
 }




More information about the asterisk-commits mailing list