Index: apps/app_dial.c
===================================================================
--- apps/app_dial.c	(revision 63406)
+++ apps/app_dial.c	(working copy)
@@ -135,6 +135,16 @@
 "           * 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"
+"                          If no application is given, but interval is present,\n"
+"                          a Manager Event will be generated.\n"
+"           * LIMIT_RECHECK_DELAY      Delay (in ms) checking the new CALL_LIMIT value after\n"
+"                          the application is execututed or the Manager Event is sent.\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"
@@ -835,6 +845,7 @@
 	char *stringp = ast_strdupa(parse);
 	char *limit_str, *warning_str, *warnfreq_str;
 	const char *var;
+	long recheck_delay = 0;
 	int play_to_caller=0,play_to_callee=0;
 	int delta;
 
@@ -889,6 +900,16 @@
 	var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
 	config->warning_sound = S_OR(var, "timeleft");
 
+	var = pbx_builtin_getvar_helper(chan,"LIMIT_RECHECK_INTERVAL");
+	config->timelimit_recheck = atol(var);
+
+	var = pbx_builtin_getvar_helper(chan,"LIMIT_RECHECK_APP");
+	config->recheck_app = S_OR(var, NULL);
+
+	var = pbx_builtin_getvar_helper(chan,"LIMIT_RECHECK_DELAY");
+	if (!ast_strlen_zero(var))
+		recheck_delay = atol(var);
+
 	/* The code looking at config wants a NULL, not just "", to decide
 	 * that the message should not be played, so we replace "" with NULL.
 	 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
@@ -902,7 +923,7 @@
 	/* 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 (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
+	if (!config->timelimit_recheck && !config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
 		*calldurationlimit = config->timelimit / 1000;
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n",
@@ -912,6 +933,11 @@
 	} else if (option_verbose > 2) {
 		ast_verbose(VERBOSE_PREFIX_3 "Limit Data for this call:\n");
 		ast_verbose(VERBOSE_PREFIX_4 "timelimit      = %ld\n", config->timelimit);
+		if (config->timelimit_recheck) {
+			ast_verbose(VERBOSE_PREFIX_4 "recheck each   = %ld\n", config->timelimit_recheck);
+			ast_verbose(VERBOSE_PREFIX_4 "recheck app    = %s\n", config->recheck_app ? config->recheck_app : "Manager Event");
+			ast_verbose(VERBOSE_PREFIX_4 "recheck delay  = %ld\n", recheck_delay);
+		}
 		ast_verbose(VERBOSE_PREFIX_4 "play_warning   = %ld\n", config->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");
@@ -1174,6 +1200,111 @@
 	return 1;	/* success */
 }
 
+/*! \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 sleep_ms = 0, delay_ms = 0;
+	struct timeval last_run = ast_tvnow();
+
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+
+	if (!ast_strlen_zero(bridge_data->config->recheck_app)) {
+		s = ast_strdupa(bridge_data->config->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';
+	}
+
+	{
+		const char *r = pbx_builtin_getvar_helper(bridge_data->ch0,"LIMIT_RECHECK_DELAY");
+		if (!ast_strlen_zero(r))
+			delay_ms = atol(r);
+	}
+
+	for (/* ever */;;) {
+		sleep_ms = ast_tvdiff_ms(ast_tvadd(last_run, ast_samp2tv(bridge_data->config->timelimit_recheck, 1000)),ast_tvnow());
+
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+		if (sleep_ms < 1)
+			sleep_ms = 1;
+		usleep(sleep_ms*1000);
+		last_run = ast_tvnow();
+
+		if (!bridge_data->config->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);
+
+		pthread_testcancel();
+		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+		if (!ast_strlen_zero(app_name) && app_data) {
+			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->config->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->config->recheck_app, bridge_data->ch0->uniqueid);
+				res = 0;
+				continue;
+			}
+		}
+		else {
+			manager_event(EVENT_FLAG_CALL, "RecheckTimeLimit", 
+			      "Channel1: %s\r\n"
+			      "Channel2: %s\r\n"
+			      "Uniqueid1: %s\r\n"
+			      "Uniqueid2: %s\r\n"
+			      "CallerID1: %s\r\n"
+			      "CallerID2: %s\r\n",
+			      bridge_data->ch0->name, bridge_data->ch1->name, bridge_data->ch0->uniqueid, bridge_data->ch1->uniqueid, bridge_data->ch0->cid.cid_num, bridge_data->ch1->cid.cid_num);
+		}
+
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+		pthread_testcancel();
+		if (delay_ms > 0)
+			usleep(delay_ms*1000);
+
+		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)) {
+				long 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. Current limit %ld\n", bridge_data->ch0->uniqueid, bridge_data->config->timelimit);
+		}
+	}
+}
+
 static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags, int *continue_exec)
 {
 	int res = -1;	/* default: error */
@@ -1189,6 +1320,9 @@
 
 	struct ast_bridge_config config;
 	unsigned int calldurationlimit = 0;
+	struct ast_bridge_combo bridge_data;
+	pthread_t rchk_thread = AST_PTHREADT_NULL;
+
 	char *dtmfcalled = NULL, *dtmfcalling = NULL;
 	struct privacy_args pa = {
 		.sentringing = 0,
@@ -1690,10 +1824,25 @@
 				ast_channel_setoption(chan,
 					AST_OPTION_OPRMODE,&oprmode,sizeof(struct oprmode),0);
 			}
+			if (config.timelimit_recheck) {
+				bridge_data.ch0 = chan;
+				bridge_data.ch1 = peer;
+				bridge_data.config = &config;
+				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", config.recheck_app, chan->name);
+			}
+
 			res = ast_bridge_call(chan,peer,&config);
 			end_time = time(NULL);
 			snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
 			pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
+
+			if (config.timelimit_recheck && rchk_thread && rchk_thread != AST_PTHREADT_NULL && rchk_thread != AST_PTHREADT_STOP) {
+				config.timelimit_recheck = 0;
+				pthread_cancel(rchk_thread);
+				pthread_join(rchk_thread, NULL);
+				rchk_thread = AST_PTHREADT_STOP;
+			}
 		}
 
 		snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
Index: include/asterisk/channel.h
===================================================================
--- include/asterisk/channel.h	(revision 63406)
+++ include/asterisk/channel.h	(working copy)
@@ -554,17 +554,26 @@
 	struct ast_flags features_caller;
 	struct ast_flags features_callee;
 	struct timeval start_time;
+	struct timeval nexteventts;
 	long feature_timer;
 	long timelimit;
+	long timelimit_recheck;
 	long play_warning;
 	long warning_freq;
 	const char *warning_sound;
 	const char *end_sound;
 	const char *start_sound;
+	const char *recheck_app;
 	int firstpass;
 	unsigned int flags;
 };
 
+struct ast_bridge_combo {
+	struct ast_channel *ch0;
+	struct ast_channel *ch1;
+	struct ast_bridge_config *config;
+};
+
 struct chanmon;
 
 struct outgoing_helper {
Index: main/channel.c
===================================================================
--- main/channel.c	(revision 63406)
+++ main/channel.c	(working copy)
@@ -3786,7 +3786,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];
@@ -3824,8 +3824,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) {
 				if (config->timelimit)
 					res = AST_BRIDGE_RETRY;
@@ -3950,7 +3950,6 @@
 	int o0nativeformats;
 	int o1nativeformats;
 	long time_left_ms=0;
-	struct timeval nexteventts = { 0, };
 	char caller_warning = 0;
 	char callee_warning = 0;
 
@@ -4006,11 +4005,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));
 	}
 
 	if (!c0->tech->send_digit_begin)
@@ -4024,9 +4023,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) {
 				if (!config->timelimit) {
 					res = AST_BRIDGE_COMPLETE;
@@ -4062,9 +4061,9 @@
 						bridge_playfile(c1, c0, config->warning_sound, t);
 				}
 				if (config->warning_freq && (time_left_ms > (config->warning_freq + 5000)))
-					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));
 			}
 		}
 
@@ -4166,7 +4165,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;
 	}
