Index: apps/app_dial.c
===================================================================
--- apps/app_dial.c	(revision 43844)
+++ apps/app_dial.c	(working copy)
@@ -132,6 +132,12 @@
 "           * LIMIT_CONNECT_FILE       File to play when call begins.\n"
 "           * LIMIT_WARNING_FILE       File to play as warning if 'y' is defined.\n"
 "                                      The default is to say the time remaining.\n"
+"           * LIMIT_RECHECK_INTERVAL   Recheck the timelimit in ms.\n"
+"           * LIMIT_RECHECK_APP        Application to start: AppName(AppArgs).\n"
+"                          Use as argument <bridge_combo> to pass to your app structure\n"
+"                          containing the two channels and the bridge configuration.\n"
+"                          The application should set CALL_LIMIT variable with the new call limit\n"
+"                          or to change the limit and config->nexteventts accordingly\n"
 "    m([class]) - Provide hold music to the calling party until a requested\n"
 "           channel answers. A specific MusicOnHold class can be\n"
 "           specified.\n"
@@ -766,6 +772,84 @@
 	return 0;
 }
 
+/*! \brief Finds and regulary starts the requested application to recheck the timelimit for a bridged call */
+static void *ast_call_governor(void *data)
+{
+	struct ast_bridge_combo *bridge_data = data;
+	struct ast_app *app;
+	char *s, *app_name, *app_data;
+	int res = 0;
+	long res_ms = 0, sleep_ms = 0;
+	struct timeval last_run = ast_tvnow();
+
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+
+	s = ast_strdupa(bridge_data->recheck_app);
+	app_name = strsep(&s,"(");
+	memset(&app_data, 0, sizeof(app_data));
+	if (!ast_strlen_zero(s))
+		app_data = ast_strip(s);
+
+	if (!ast_strlen_zero(app_data) && (s = strrchr(app_data, ')')))
+		app_data[strlen(app_data)-strlen(s)] = '\0';
+
+	for (/* ever */;;) {
+		sleep_ms = ast_tvdiff_ms(ast_tvadd(last_run, ast_samp2tv(bridge_data->timelimit_recheck, 1000)),ast_tvnow());
+		if (sleep_ms < 1)
+			sleep_ms = 1;
+		usleep(sleep_ms*1000);
+		last_run = ast_tvnow();
+
+		pthread_testcancel();
+		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+		if (!bridge_data->timelimit_recheck || (bridge_data->config->timelimit && (bridge_data->config->timelimit - bridge_data->config->play_warning < ast_tvdiff_ms(ast_tvnow(), bridge_data->config->start_time))))
+			pthread_exit(NULL);
+
+		app = pbx_findapp(app_name);
+		if (!app) {
+			ast_log(LOG_WARNING, "Could not find application (%s). Timelimit not checked for call (%s)\n", bridge_data->recheck_app, bridge_data->ch0->uniqueid);
+			continue;
+		}
+
+		if (strcmp(app_data, "<bridge_combo>")) {
+			char with_data[2048];
+			memset(with_data, 0, 2048);
+			pbx_substitute_variables_helper(bridge_data->ch0, app_data, with_data, sizeof(with_data) - 1);
+			if (option_verbose > 10)
+				ast_verbose( VERBOSE_PREFIX_4 "Substitute %s TO %s\n", app_data, with_data);
+			res = pbx_exec(bridge_data->ch0, app, with_data);
+		}
+		else res = pbx_exec(bridge_data->ch0, app, data);
+
+		if (res) {
+			ast_log(LOG_ERROR, "Error executing application (%s). Timelimit not checked for call (%s)\n", bridge_data->recheck_app, bridge_data->ch0->uniqueid);
+			res = 0;
+			continue;
+		}
+
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+		pthread_testcancel();
+
+		if (bridge_data->config->timelimit - bridge_data->config->play_warning < ast_tvdiff_ms(ast_tvnow(), bridge_data->config->start_time))
+			pthread_exit(NULL);
+
+		const char *r = pbx_builtin_getvar_helper(bridge_data->ch0,"CALL_LIMIT");
+		if (r && (res = atoi(r)) && (res -= bridge_data->config->timelimit/1000)) {
+			res_ms = res*1000;
+			if (bridge_data->ch0->whentohangup)
+				bridge_data->ch0->whentohangup += res_ms;
+			bridge_data->config->timelimit += res_ms;
+			bridge_data->config->nexteventts.tv_sec += res;
+			if (option_verbose > 10)
+					ast_verbose( VERBOSE_PREFIX_4 "Recheck executed for call %s. New limit %ld\n", bridge_data->ch0->uniqueid, bridge_data->config->timelimit);
+		}
+		else if (option_verbose > 10)
+			ast_verbose( VERBOSE_PREFIX_4 "Recheck executed for call %s. No changes\n", bridge_data->ch0->uniqueid);
+	}
+}
+
 static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags)
 {
 	int res = -1;
@@ -783,6 +867,10 @@
 	int privdb_val = 0;
 	unsigned int calldurationlimit = 0;
 	long timelimit = 0;
+	long timelimit_recheck = 0;
+	const char *recheck_app=NULL;
+	struct ast_bridge_combo bridge_data;
+	pthread_t rchk_thread = AST_PTHREADT_NULL;
 	long play_warning = 0;
 	long warning_freq = 0;
 	const char *warning_sound = NULL;
@@ -904,10 +992,16 @@
 		var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
 		start_sound = S_OR(var, NULL);	/* XXX not much of a point in doing this! */
 
+		var = pbx_builtin_getvar_helper(chan,"LIMIT_RECHECK_INTERVAL");
+		timelimit_recheck = atol(var);
+
+		var = pbx_builtin_getvar_helper(chan,"LIMIT_RECHECK_APP");
+		recheck_app = S_OR(var, NULL);
+
 		/* undo effect of S(x) in case they are both used */
 		calldurationlimit = 0;
 		/* more efficient to do it like S(x) does since no advanced opts */
-		if (!play_warning && !start_sound && !end_sound && timelimit) {
+		if (!timelimit_recheck && !play_warning && !start_sound && !end_sound && timelimit) {
 			calldurationlimit = timelimit / 1000;
 			if (option_verbose > 2)
 				ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n", calldurationlimit);
@@ -915,6 +1009,10 @@
 		} else if (option_verbose > 2) {
 			ast_verbose(VERBOSE_PREFIX_3 "Limit Data for this call:\n");
 			ast_verbose(VERBOSE_PREFIX_4 "timelimit      = %ld\n", timelimit);
+			if (timelimit_recheck) {
+				ast_verbose(VERBOSE_PREFIX_4 "recheck each   = %ld\n", timelimit_recheck);
+				ast_verbose(VERBOSE_PREFIX_4 "recheck app   = %s\n", recheck_app ? recheck_app : "Manager event");
+			}
 			ast_verbose(VERBOSE_PREFIX_4 "play_warning   = %ld\n", play_warning);
 			ast_verbose(VERBOSE_PREFIX_4 "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
 			ast_verbose(VERBOSE_PREFIX_4 "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
@@ -1593,6 +1691,17 @@
 				ast_channel_setoption(chan,
 					AST_OPTION_OPRMODE,&oprmode,sizeof(struct oprmode),0);
 			}
+
+			if (timelimit_recheck) {
+				bridge_data.ch0 = chan;
+				bridge_data.ch1 = peer;
+				bridge_data.config = &config;
+				bridge_data.timelimit_recheck = timelimit_recheck;
+				bridge_data.recheck_app = recheck_app;
+				if (ast_pthread_create(&rchk_thread, NULL, ast_call_governor, &bridge_data) < 0)
+					ast_log(LOG_WARNING, "Failed to start new limit recheck thread for application %s on channel %s\n", recheck_app, chan->name);
+			}
+
 			res = ast_bridge_call(chan,peer,&config);
 			time(&end_time);
 			{
@@ -1600,6 +1709,14 @@
 				snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
 				pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
 			}
+
+			if (timelimit_recheck && rchk_thread && rchk_thread != AST_PTHREADT_NULL && rchk_thread != AST_PTHREADT_STOP) {
+				timelimit_recheck = 0;
+				pthread_cancel(rchk_thread);
+				pthread_join(rchk_thread, NULL);
+				rchk_thread = AST_PTHREADT_STOP;
+			}
+
 		} else {
 			time(&end_time);
 			res = -1;
Index: include/asterisk/channel.h
===================================================================
--- include/asterisk/channel.h	(revision 43844)
+++ include/asterisk/channel.h	(working copy)
@@ -492,6 +492,7 @@
 	struct ast_flags features_caller;
 	struct ast_flags features_callee;
 	struct timeval start_time;
+	struct timeval nexteventts;
 	long feature_timer;
 	long timelimit;
 	long play_warning;
@@ -503,6 +504,14 @@
 	unsigned int flags;
 };
 
+struct ast_bridge_combo {
+	struct ast_channel *ch0;
+	struct ast_channel *ch1;
+	struct ast_bridge_config *config;
+	long timelimit_recheck;
+	const char *recheck_app;
+};
+
 struct chanmon;
 
 #define LOAD_OH(oh) {	\
Index: main/channel.c
===================================================================
--- main/channel.c	(revision 43844)
+++ main/channel.c	(working copy)
@@ -3556,7 +3556,7 @@
 
 static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct ast_channel *c1,
 						 struct ast_bridge_config *config, struct ast_frame **fo,
-						 struct ast_channel **rc, struct timeval bridge_end)
+						 struct ast_channel **rc)
 {
 	/* Copy voice back and forth between the two channels. */
 	struct ast_channel *cs[3];
@@ -3594,8 +3594,8 @@
 			res = AST_BRIDGE_RETRY;
 			break;
 		}
-		if (bridge_end.tv_sec) {
-			to = ast_tvdiff_ms(bridge_end, ast_tvnow());
+		if (config->nexteventts.tv_sec) {
+			to = ast_tvdiff_ms(config->nexteventts, ast_tvnow());
 			if (to <= 0) {
 				res = AST_BRIDGE_COMPLETE;
 				break;
@@ -3714,7 +3714,6 @@
 	int o0nativeformats;
 	int o1nativeformats;
 	long time_left_ms=0;
-	struct timeval nexteventts = { 0, };
 	char caller_warning = 0;
 	char callee_warning = 0;
 
@@ -3770,11 +3769,11 @@
 	o1nativeformats = c1->nativeformats;
 
 	if (config->feature_timer) {
-		nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->feature_timer, 1000));
+		config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->feature_timer, 1000));
 	} else if (config->timelimit) {
-		nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
+		config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
 		if (caller_warning || callee_warning)
-			nexteventts = ast_tvsub(nexteventts, ast_samp2tv(config->play_warning, 1000));
+			config->nexteventts = ast_tvsub(config->nexteventts, ast_samp2tv(config->play_warning, 1000));
 	}
 
 	for (/* ever */;;) {
@@ -3783,9 +3782,9 @@
 
 		to = -1;
 
-		if (!ast_tvzero(nexteventts)) {
+		if (!ast_tvzero(config->nexteventts)) {
 			now = ast_tvnow();
-			to = ast_tvdiff_ms(nexteventts, now);
+			to = ast_tvdiff_ms(config->nexteventts, now);
 			if (to <= 0) {
 				res = AST_BRIDGE_COMPLETE;
 				break;
@@ -3818,9 +3817,9 @@
 						bridge_playfile(c1, c0, config->warning_sound, t);
 				}
 				if (config->warning_freq) {
-					nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+					config->nexteventts = ast_tvadd(config->nexteventts, ast_samp2tv(config->warning_freq, 1000));
 				} else
-					nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
+					config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
 			}
 		}
 
@@ -3919,7 +3918,7 @@
 			o0nativeformats = c0->nativeformats;
 			o1nativeformats = c1->nativeformats;
 		}
-		res = ast_generic_bridge(c0, c1, config, fo, rc, nexteventts);
+		res = ast_generic_bridge(c0, c1, config, fo, rc);
 		if (res != AST_BRIDGE_RETRY)
 			break;
 	}
