diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 846f9cb789..e8468c0394 100644
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -566,7 +566,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
 	}
 
 	if (!uuid_found) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s. Nothing to do.\n", span_id, chan_id, name);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s\n", span_id, chan_id, name);
 		goto end;
 	}
 
@@ -3830,6 +3830,7 @@ static switch_status_t load_config(void)
 			const char *tonegroup = NULL;
 			char *digit_timeout = NULL;
 			char *dial_timeout = NULL;
+			char *release_guard_time_ms = NULL;
 			char *max_digits = NULL;
 			char *dial_regex = NULL;
 			char *hold_music = NULL;
@@ -3839,7 +3840,7 @@ static switch_status_t load_config(void)
 			char *answer_supervision = str_false;
 			char *immediate_ringback = str_false;
 			char *ringback_file = str_empty;
-			uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0;
+			uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0, release_guard_time_ms_int = 0;
 			ftdm_span_t *span = NULL;
 			analog_option_t analog_options = ANALOG_OPTION_NONE;
 
@@ -3853,6 +3854,8 @@ static switch_status_t load_config(void)
 					digit_timeout = val;
 				} else if (!strcasecmp(var, "dial-timeout")) {
 					dial_timeout = val;
+				} else if (!strcasecmp(var, "release-guard-time-ms")) {
+					release_guard_time_ms = val;
 				} else if (!strcasecmp(var, "context")) {
 					context = val;
 				} else if (!strcasecmp(var, "dialplan")) {
@@ -3893,6 +3896,10 @@ static switch_status_t load_config(void)
 				dial_timeout_int = atoi(dial_timeout);
 			}
 
+			if (release_guard_time_ms) {
+				release_guard_time_ms_int = atoi(release_guard_time_ms);
+			}
+
 			if (max_digits) {
 				max = atoi(max_digits);
 			}
@@ -3928,6 +3935,7 @@ static switch_status_t load_config(void)
 								   "ringback_file", ringback_file,
 								   "digit_timeout", &to,
 								   "dial_timeout", &dial_timeout_int,
+								   "release_guard_time_ms", &release_guard_time_ms_int,
 								   "max_dialstr", &max,
 								   FTDM_TAG_END) != FTDM_SUCCESS) {
 				LOAD_ERROR("Error starting FreeTDM span %d\n", span_id);
@@ -5246,6 +5254,98 @@ end:
 	return SWITCH_STATUS_SUCCESS;
 }
 
+#define CASINTS(cas) ((cas) & (1 << 3)) ? 1 : 0, \
+                     ((cas) & (1 << 2)) ? 1 : 0, \
+                     ((cas) & (1 << 1)) ? 1 : 0, \
+                     ((cas) & (1 << 0)) ? 1 : 0
+FTDM_CLI_DECLARE(ftdm_cmd_cas)
+{
+	uint32_t chan_id = 0;
+	switch_bool_t do_read = SWITCH_FALSE;
+	ftdm_channel_t *chan;
+	ftdm_iterator_t *iter = NULL;
+	ftdm_iterator_t *curr = NULL;
+	ftdm_span_t *span = NULL;
+	const char *write_bits_str = "";
+	int32_t abcd_bits = 0;
+
+	if (argc < 3) {
+		print_usage(stream, cli);
+		goto end;
+	}
+
+	if (!strcasecmp(argv[1], "read")) {
+		do_read = SWITCH_TRUE;
+		chan_id = argc > 3 ? atoi(argv[3]) : 0;
+	} else if (!strcasecmp(argv[1], "write") && argc >= 4) {
+		const char *str = NULL;
+		int mask = 0x08;
+		do_read = SWITCH_FALSE;
+		if (argc == 4) {
+			chan_id = 0;
+			write_bits_str = argv[3];
+		} else {
+			chan_id = atoi(argv[3]);
+			write_bits_str = argv[4];
+		}
+		if (strlen(write_bits_str) != 4) {
+			stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str);
+			goto end;
+		}
+		str = write_bits_str;
+		while (*str) {
+			if (*str == '1') {
+				abcd_bits |= mask;
+			} else if (*str != '0') {
+				stream->write_function(stream, "-ERR Invalid CAS bits '%s'. CAS ABCD string must be composed of only four 1's and 0's (e.g. 1101)\n", write_bits_str);
+				goto end;
+			}
+			str++;
+			mask = (mask >> 1);
+		}
+	} else {
+		print_usage(stream, cli);
+		goto end;
+	}
+
+	ftdm_span_find_by_name(argv[2], &span);
+	if (!span) {
+		stream->write_function(stream, "-ERR failed to find span %s\n", argv[2]);
+		goto end;
+	}
+
+	if (chan_id) {
+		if (chan_id > ftdm_span_get_chan_count(span)) {
+			stream->write_function(stream, "-ERR invalid channel\n");
+			goto end;
+		}
+		chan = ftdm_span_get_channel(span, chan_id);
+		if (do_read) {
+			ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits);
+			stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits);
+		} else {
+			stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id);
+		}
+	} else {
+		iter = ftdm_span_get_chan_iterator(span, NULL);
+		for (curr  = iter; curr; curr = ftdm_iterator_next(curr)) {
+			chan = ftdm_iterator_current(curr);
+			//ftdm_channel_command();
+			chan_id = ftdm_channel_get_id(chan);
+			if (do_read) {
+				ftdm_channel_command(chan, FTDM_COMMAND_GET_CAS_BITS, &abcd_bits);
+				stream->write_function(stream, "Read CAS bits from channel %d: %d%d%d%d (0x0%X)\n", chan_id, CASINTS(abcd_bits), abcd_bits);
+			} else {
+				stream->write_function(stream, "Writing 0x0%X to channel %d\n", abcd_bits, chan_id);
+			}
+		}
+		ftdm_iterator_free(iter);
+	}
+	stream->write_function(stream, "+OK\n");
+end:
+	return SWITCH_STATUS_SUCCESS;
+}
+
 SWITCH_STANDARD_API(ftdm_api_exec_usage)
 {
 	char *mycmd = NULL, *argv[10] = { 0 };
@@ -5326,6 +5426,7 @@ static ftdm_cli_entry_t ftdm_cli_options[] =
 	{ "queuesize", "<rxsize> <txsize> <span_id|span_name> [<chan_id>]", "", NULL, ftdm_cmd_queuesize, NULL },
 	{ "iostats", "enable|disable|flush|print <span_id|span_name> <chan_id>", "::[enable:disable:flush:print", NULL, ftdm_cmd_iostats, NULL },
 	{ "ioread", "<span_id|span_name> <chan_id> [num_times] [interval]", "", NULL, ftdm_cmd_ioread, NULL },
+	{ "cas", "read|write <span_id|span_name> [<chan_id>] [<write_bits>]", "::[read:write", NULL, ftdm_cmd_cas, NULL },
 
 	/* Stand-alone commands (not part of the generic ftdm API */
 	{ "ftdm_usage", "<span_id|span_name> <chan_id>", "", "Return channel call count", NULL, ftdm_api_exec_usage },
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 650ef359d4..0b0673ba84 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -1489,6 +1489,16 @@ static __inline__ int chan_is_avail(ftdm_channel_t *check)
 			return 0;
 		}
 	}
+	/* release guard time check */
+	if (check->span->sig_release_guard_time_ms && check->last_release_time) {
+		ftdm_time_t time_diff = (ftdm_current_time_in_ms() - check->last_release_time);
+		if (time_diff < check->span->sig_release_guard_time_ms) {
+			return 0;
+		}
+		/* circuit now available for outbound dialing */
+		check->last_release_time = 0;
+		ftdm_log_chan(check, FTDM_LOG_DEBUG, "Channel is now available, release guard timer expired %zdms ago\n", (time_diff - check->span->sig_release_guard_time_ms));
+	}
 	return 1;
 }
 
@@ -2981,6 +2991,11 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan)
 		ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
 		ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
 	}
+
+	if (ftdmchan->span->sig_release_guard_time_ms) {
+		ftdmchan->last_release_time = ftdm_current_time_in_ms();
+	}
+
 	ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n");
 	return FTDM_SUCCESS;
 }
@@ -3442,7 +3457,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
 					ftdmchan->dtmf_on = val;
 					GOTO_STATUS(done, FTDM_SUCCESS);
 				} else {
-					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+					ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "invalid value %d range 10-1000", val);
 					GOTO_STATUS(done, FTDM_FAIL);
 				}
 			}
@@ -3456,7 +3471,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
 					ftdmchan->dtmf_off = val;
 					GOTO_STATUS(done, FTDM_SUCCESS);
 				} else {
-					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+					ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "invalid value %d range 10-1000", val);
 					GOTO_STATUS(done, FTDM_FAIL);
 				}
 			}
@@ -5096,6 +5111,12 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const
 		if (chan_config->dtmf_on_start) {
 			span->channels[chan_index]->dtmfdetect.trigger_on_start = 1;
 		}
+		if (chan_config->dtmf_time_on) {
+			ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_DTMF_ON_PERIOD, &chan_config->dtmf_time_on);
+		}
+		if (chan_config->dtmf_time_off) {
+			ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_DTMF_OFF_PERIOD, &chan_config->dtmf_time_off);
+		}
 	}
 
 	return FTDM_SUCCESS;
@@ -5335,6 +5356,14 @@ static ftdm_status_t load_config(void)
 						chan_config.dtmf_on_start = FTDM_FALSE;
 					}
 				}
+			} else if (!strcasecmp(var, "dtmf_time_on")) {
+				if (sscanf(val, "%u", &(chan_config.dtmf_time_on)) != 1) {
+					ftdm_log(FTDM_LOG_ERROR, "invalid dtmf_time_on: '%s'\n", val);
+				}
+			} else if (!strcasecmp(var, "dtmf_time_off")) {
+				if (sscanf(val, "%u", &(chan_config.dtmf_time_off)) != 1) {
+					ftdm_log(FTDM_LOG_ERROR, "invalid dtmf_time_off: '%s'\n", val);
+				}
 			} else if (!strncasecmp(var, "iostats", sizeof("iostats")-1)) {
 				if (ftdm_true(val)) {
 					chan_config.iostats = FTDM_TRUE;
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h
index ec20070262..2bc1717556 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h
@@ -43,7 +43,7 @@ typedef enum {
 	FTDM_ANALOG_POLARITY_CALLERID = (1 << 4)
 } ftdm_analog_flag_t;
 
-#define FTDM_MAX_HOTLINE_STR		20
+#define FTDM_MAX_HOTLINE_STR		32
 #define MAX_DTMF 256
 
 struct ftdm_analog_data {
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h b/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h
index 121381d522..e52a319155 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h
@@ -44,10 +44,12 @@
 #define MAX_DIALSTRING 256
 
 typedef enum {
-	FTDM_ANALOG_EM_RUNNING = (1 << 0)
+	FTDM_ANALOG_EM_RUNNING = (1 << 0),
+	FTDM_ANALOG_EM_LOCAL_WRITE = (1 << 2),
+	FTDM_ANALOG_EM_LOCAL_SUSPEND = (1 << 3),
+	FTDM_ANALOG_EM_REMOTE_SUSPEND = (1 << 4),
 } ftdm_analog_em_flag_t;
 
-
 struct ftdm_analog_data {
 	uint32_t flags;
 	uint32_t max_dialstr;
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
index 8a537bb5e6..98fde2a514 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
@@ -178,8 +178,7 @@ static ftdm_status_t ftdm_analog_em_sig_write(ftdm_channel_t *ftdmchan, void *da
 	ftdm_analog_em_data_t *analog_data = ftdmchan->span->signal_data;
 	if (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA
 	    && analog_data->immediate_ringback
-	    && ftdmchan->call_data) {
-		/* DO NOT USE ftdmchan->call_data, as is a dummy non-null pointer */
+	    && ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE)) {
 		/* ringback is being played in the analog thread, ignore user data for now */
 		return FTDM_BREAK;
 	}
@@ -283,7 +282,7 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_em_get_span_sig_status)
 	return FTDM_SUCCESS;
 }
 
-static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status)
+static ftdm_status_t analog_em_set_channel_sig_status_ex(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status, ftdm_bool_t remote)
 {
 	switch (status) {
 	case FTDM_SIG_STATE_DOWN:
@@ -299,17 +298,30 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status)
 			}
 			ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED);
 		}
+		if (remote) {
+			ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND);
+		} else {
+			ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND);
+		}
 		break;
 	case FTDM_SIG_STATE_UP:
 		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) {
-			int cas_bits = 0x00;
-			ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED);
-			ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits);
-			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
-				ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
+			if (remote) {
+				ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND);
+			} else {
+				ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND);
 			}
-			if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
-				ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP);
+			if (!ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_REMOTE_SUSPEND) &&
+				!ftdm_test_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_SUSPEND)) {
+				int cas_bits = 0x00;
+				ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+				ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits);
+				if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+					ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
+				}
+				if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
+					ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP);
+				}
 			}
 		}
 		break;
@@ -320,6 +332,11 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status)
 	return FTDM_SUCCESS;
 }
 
+static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status)
+{
+	return analog_em_set_channel_sig_status_ex(ftdmchan, status, FTDM_FALSE);
+}
+
 static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status)
 {
 	ftdm_iterator_t *chaniter = NULL;
@@ -335,7 +352,7 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(analog_em_set_span_sig_status)
 		ftdm_channel_t *fchan = ftdm_iterator_current(citer);
 		/* we set channel's state through analog_em_set_channel_sig_status(), since it already takes care of notifying the user when appropriate */
 		ftdm_channel_lock(fchan);
-		if ((analog_em_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) {
+		if ((analog_em_set_channel_sig_status_ex(fchan, status, FTDM_FALSE)) != FTDM_SUCCESS) {
 			ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status));
 		}
 		ftdm_channel_unlock(fchan);
@@ -361,6 +378,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
 	uint32_t digit_timeout = 2000;
 	uint32_t max_dialstr = 11;
 	uint32_t dial_timeout = 0;
+	uint32_t release_guard_time_ms = 500;
 	ftdm_bool_t answer_supervision = FTDM_FALSE;
 	const char *var, *val;
 	int *intval;
@@ -412,6 +430,11 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
 				break;
 			}
 			max_dialstr = *intval;
+		} else if (!strcasecmp(var, "release_guard_time_ms")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			release_guard_time_ms = *intval;
 		} else {
 			ftdm_log(FTDM_LOG_ERROR, "Invalid parameter for analog em span: '%s'\n", var);
 			return FTDM_FAIL;
@@ -443,6 +466,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
 	span->get_span_sig_status = analog_em_get_span_sig_status;
 	span->set_channel_sig_status = analog_em_set_channel_sig_status;
 	span->set_span_sig_status = analog_em_set_span_sig_status;
+	span->sig_release_guard_time_ms = release_guard_time_ms;
 	ftdm_span_load_tones(span, tonemap);
 	if (immediate_ringback || !ftdm_strlen_zero(ringback_file)) {
 		analog_data->immediate_ringback = FTDM_TRUE;
@@ -496,6 +520,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
 	uint32_t cas_hangup = 0;
 	int cas_answer_ms = 500;
 	int cas_hangup_ms = 500;
+	ftdm_bool_t busy_timeout = FTDM_FALSE;
 	FILE *ringback_f = NULL;
 	ftdm_bool_t digits_sent = FTDM_FALSE;
 
@@ -762,6 +787,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
 						indicate = 1;
 					} else {
 						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+						busy_timeout = FTDM_TRUE;
 					}
 				}
 				break;
@@ -925,17 +951,25 @@ read_try:
 			}
 		}
 
-		/* we must lock the channel and make sure we let our own generated audio thru (ftdmchan->call_data is tested in the ftdm_analog_em_sig_write handler)*/
+		/* we must lock the channel and make sure we let our own generated audio thru (FTDM_ANALOG_EM_LOCAL_WRITE is tested in the ftdm_analog_em_sig_write handler)*/
 		ftdm_channel_lock(ftdmchan);
-		ftdmchan->call_data = (void *)0xFF; /* ugh! */
+		ftdm_set_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE);
 		ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
-		ftdmchan->call_data = NULL;
+		ftdm_clear_sflag(ftdmchan, FTDM_ANALOG_EM_LOCAL_WRITE);
 		ftdm_channel_unlock(ftdmchan);
 	}
 
  done:
 
 	ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
+	if (busy_timeout) {
+		ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_CAS_BITS, &cas_bits);
+		if (cas_bits == 0XF) {
+			/* the remote end never sent any digits, neither moved to onhook, let's stay suspended */
+			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Moving channel to suspended after timeout, remote end still offhook\n");
+			analog_em_set_channel_sig_status_ex(ftdmchan, FTDM_SIG_STATE_SUSPENDED, FTDM_TRUE);
+		}
+	}
 	
 	closed_chan = ftdmchan;
 	ftdm_channel_close(&ftdmchan);
@@ -984,6 +1018,11 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
 	ftdm_mutex_lock(event->channel->mutex);
 	locked++;
 
+	if (event->enum_id == FTDM_OOB_ONHOOK && ftdm_test_sflag(event->channel, FTDM_ANALOG_EM_REMOTE_SUSPEND)) {
+		/* We've got remote suspend, now we're back on hook, lift the remote suspend status */
+		analog_em_set_channel_sig_status_ex(event->channel, FTDM_SIG_STATE_UP, FTDM_TRUE);
+	}
+
 	if (ftdm_test_flag(event->channel, FTDM_CHANNEL_SUSPENDED)) {
 		ftdm_log(FTDM_LOG_WARNING, "Ignoring event %s on channel %d:%d in state %s, channel is suspended\n",
 				ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index c5b82c9b06..46bf880e12 100755
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -74,10 +74,10 @@ extern "C" {
 #endif
 
 /*! \brief Limit to span names */
-#define FTDM_MAX_NAME_STR_SZ 80
+#define FTDM_MAX_NAME_STR_SZ 128
 
 /*! \brief Limit to channel number strings */
-#define FTDM_MAX_NUMBER_STR_SZ 20
+#define FTDM_MAX_NUMBER_STR_SZ 32
 
 /*! \brief Hangup cause codes */
 typedef enum {
@@ -355,7 +355,7 @@ typedef enum {
 FTDM_STR2ENUM_P(ftdm_str2ftdm_transfer_response, ftdm_transfer_response2str, ftdm_transfer_response_t)
 
 /*! \brief Digit limit used in DNIS/ANI */
-#define FTDM_DIGITS_LIMIT 25
+#define FTDM_DIGITS_LIMIT 64
 
 #define FTDM_SILENCE_VALUE(fchan) (fchan)->native_codec == FTDM_CODEC_ULAW ? 255 : (fchan)->native_codec == FTDM_CODEC_ALAW ? 0xD5 : 0x00
 
@@ -533,6 +533,8 @@ typedef struct ftdm_channel_config {
 	uint8_t debugdtmf;
 	uint8_t dtmf_on_start;
 	uint32_t dtmfdetect_ms;
+	uint32_t dtmf_time_on;
+	uint32_t dtmf_time_off;
 	uint8_t iostats;
 } ftdm_channel_config_t;
 
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index f4a1fe4e29..609198e731 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -477,6 +477,7 @@ struct ftdm_channel {
 	int32_t rxdrops;
 	ftdm_usrmsg_t *usrmsg;
 	ftdm_time_t last_state_change_time;
+	ftdm_time_t last_release_time;
 };
 
 struct ftdm_span {
@@ -515,6 +516,7 @@ struct ftdm_span {
 	ftdm_channel_sig_write_t sig_write;
 	ftdm_channel_sig_dtmf_t sig_queue_dtmf;
 	ftdm_channel_sig_dtmf_t sig_send_dtmf;
+	uint32_t sig_release_guard_time_ms;
 	ftdm_channel_state_processor_t state_processor; /*!< This guy is called whenever state processing is required */
 	void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */
 	char *type;