diff --git a/apps/app_rpt.c b/apps/app_rpt.c
index f3edb044d77b82a967dddf2e5c766b603d5fe8ff..2ca6fa4184b7b3f3f4a1a0141ea4134a04584de5 100644
--- a/apps/app_rpt.c
+++ b/apps/app_rpt.c
@@ -1,3 +1,4 @@
+/* #define OLD_ASTERISK */
 /*
  * Asterisk -- An open source telephony toolkit.
  *
@@ -20,7 +21,7 @@
 /*! \file
  *
  * \brief Radio Repeater / Remote Base program 
- *  version 0.42 02/25/06
+ *  version 0.47 05/23/06
  * 
  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
  *
@@ -32,7 +33,18 @@
  * Repeater / Remote Functions:
  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
  * Normal mode:
- * See the function list in rpt.conf
+ * See the function list in rpt.conf (autopatchup, autopatchdn)
+ * autopatchup can optionally take comma delimited setting=value pairs:
+ *  
+ *
+ * context=string		:	Override default context with "string"
+ * dialtime=ms			:	Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
+ * farenddisconnect=1		:	Automatically disconnect when called party hangs up
+ * noct=1			:	Don't send repeater courtesy tone during autopatch calls
+ * quiet=1			:	Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
+ *
+ *
+ * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
  *
  *  To send an asterisk (*) while dialing or talking on phone,
  *  use the autopatch acess code.
@@ -93,6 +105,15 @@
  *  140 - Link Status (brief)
  *
  *
+ *
+ * 'duplex' modes:  (defaults to duplex=2)
+ *
+ * 0 - Only remote links key Tx and no main repeat audio.
+ * 1 - Everything other then main Rx keys Tx, no main repeat audio.
+ * 2 - Normal mode
+ * 3 - Normal except no main repeat audio.
+ * 4 - Normal except no main repeat audio during autopatch only
+ *
 */
 
 /*** MODULEINFO
@@ -100,14 +121,15 @@
 	<defaultenabled>no</defaultenabled>
  ***/
 
-/* The following is JUST GROSS!! There is some soft of underlying problem,
-   probably in channel_iax2.c, that causes an IAX2 connection to sometimes
-   stop transmitting randomly. We have been working for weeks to try to
-   locate it and fix it, but to no avail We finally decided to put our
-   tail between our legs, and just make the radio system re-connect upon
-   network failure. This just shouldnt have to be done. For normal operation,
-   comment-out the following line */
-#define	RECONNECT_KLUDGE 
+/* Un-comment the following to include support for MDC-1200 digital tone
+   signalling protocol (using KA6SQG's GPL'ed implementation) */
+/* file must be downloaded separately, not part of Asterisk distribution */
+/* #include "mdc_decode.c" */
+
+/* Un-comment the following to include support for notch filters in the
+   rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
+/* file must be downloaded separately, not part of Asterisk distribution */
+/* #include "rpt_notch.c" */
 
 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
 
@@ -117,6 +139,10 @@
 #define	MACROPTIME 500
 #define	DTMF_TIMEOUT 3
 
+#ifdef	__RPT_NOTCH
+#define	MAXFILTERS 10
+#endif
+
 #define	DISC_TIME 10000  /* report disc after 10 seconds of no connect */
 #define	MAX_RETRIES 5
 
@@ -124,6 +150,7 @@
 
 #define	RETRY_TIMER_MS 5000
 
+#define MAXPEERSTR 31
 #define	MAXREMSTR 15
 
 #define	DELIMCHR ','
@@ -144,6 +171,8 @@
 
 #define MAXNODESTR 300
 
+#define MAXPATCHCONTEXT 100
+
 #define ACTIONSIZE 32
 
 #define TELEPARAMSIZE 256
@@ -156,7 +185,7 @@ enum {REM_OFF,REM_MONITOR,REM_TX};
 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
 	CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
 	STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
-	TAILMSG, MACRO_NOTFOUND, MACRO_BUSY};
+	TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY};
 
 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
 
@@ -215,7 +244,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/say.h"
 #include "asterisk/localtime.h"
 
-static  char *tdesc = "Radio Repeater / Remote Base  version 0.42  02/25/2006";
+static  char *tdesc = "Radio Repeater / Remote Base  version 0.47  05/23/2006";
 
 static char *app = "Rpt";
 
@@ -263,7 +292,9 @@ char *discstr = "!!DISCONNECT!!";
 static char *remote_rig_ft897="ft897";
 static char *remote_rig_rbi="rbi";
 
-struct	ast_config *cfg;
+#ifdef	OLD_ASTERISK
+STANDARD_LOCAL_USER;
+#endif
 
 LOCAL_USER_DECL;
 
@@ -272,6 +303,7 @@ LOCAL_USER_DECL;
 #define	TOTIME 180000
 #define	IDTIME 300000
 #define	MAXRPTS 20
+#define MAX_STAT_LINKS 32
 #define POLITEID 30000
 #define FUNCTDELAY 1500
 
@@ -299,10 +331,24 @@ struct rpt_link
 	long 	retrytimer;
 	long	retxtimer;
 	int	retries;
+	int	reconnects;
+	long long connecttime;
 	struct ast_channel *chan;	
 	struct ast_channel *pchan;	
 } ;
 
+struct rpt_lstat
+{
+	struct	rpt_lstat *next;
+	struct	rpt_lstat *prev;
+	char	peer[MAXPEERSTR];
+	char	name[MAXNODESTR];
+	char	mode;
+	char	outbound;
+	char	reconnects;
+	long long	connecttime;
+} ;
+
 struct rpt_tele
 {
 	struct rpt_tele *next;
@@ -339,53 +385,77 @@ struct telem_defaults
 
 static struct rpt
 {
-	char *name;
 	ast_mutex_t lock;
+	struct ast_config *cfg;
+	char reload;
+
+	char *name;
 	char *rxchanname;
 	char *txchanname;
-	char *ourcontext;
-	char *ourcallerid;
-	char *acctcode;
-	char *ident;
-	char *tonezone;
-	char *functions;
-	char *link_functions;
-	char *phone_functions;
-	char *dphone_functions;
-	char *nodes;
+	char *remote;
+
+	struct {
+
+		char *ourcontext;
+		char *ourcallerid;
+		char *acctcode;
+		char *ident;
+		char *tonezone;
+		char simple;
+		char *functions;
+		char *link_functions;
+		char *phone_functions;
+		char *dphone_functions;
+		char *nodes;
+		int hangtime;
+		int totime;
+		int idtime;
+		int tailmessagetime;
+		int tailsquashedtime;
+		int duplex;
+		int politeid;
+		char *tailmessages[500];
+		int tailmessagemax;
+		char	*memory;
+		char	*macro;
+		char	*startupmacro;
+		int iobase;
+		char funcchar;
+		char endchar;
+		char	nobusyout;
+	} p;
 	struct rpt_link links;
-	int hangtime;
-	int totime;
-	int idtime;
 	int unkeytocttimer;
-	int duplex;
 	char keyed;
 	char exttx;
 	char localtx;
 	char remoterx;
 	char remotetx;
 	char remoteon;
-	char simple;
-	char *remote;
 	char tounkeyed;
 	char tonotify;
 	char enable;
 	char dtmfbuf[MAXDTMF];
 	char macrobuf[MAXMACRO];
 	char rem_dtmfbuf[MAXDTMF];
+	char lastdtmfcommand[MAXDTMF];
 	char cmdnode[50];
 	struct ast_channel *rxchannel,*txchannel;
 	struct ast_channel *pchannel,*txpchannel, *remchannel;
 	struct rpt_tele tele;
+	struct timeval lasttv,curtv;
 	pthread_t rpt_call_thread,rpt_thread;
 	time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
-	int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer;
+	int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
 	int mustid,tailid;
-	int politeid;
+	int tailevent;
+	int telemrefcount;
 	int dtmfidx,rem_dtmfidx;
+	int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
+	int totalexecdcommands, dailyexecdcommands;
 	long	retxtimer;
+	long long totaltxtime;
 	char mydtmf;
-	int iobase;
 	char exten[AST_MAX_EXTENSION];
 	char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
 	char offset;
@@ -397,9 +467,12 @@ static struct rpt
 	char hfscanmode;
 	int hfscanstatus;
 	char lastlinknode[MAXNODESTR];
-	char funcchar;
-	char endchar;
 	char stopgen;
+	char patchfarenddisconnect;
+	char patchnoct;
+	char patchquiet;
+	char patchcontext[MAXPATCHCONTEXT];
+	int patchdialtime;
 	int macro_longest;
 	int phone_longestfunc;
 	int dphone_longestfunc;
@@ -407,18 +480,31 @@ static struct rpt
 	int longestfunc;
 	int longestnode;
 	int threadrestarts;		
-	int tailmessagetime;
-	int tailsquashedtime;
-	char *tailmessages[500];
-	int tailmessagemax;
 	int tailmessagen;
 	time_t disgorgetime;
 	time_t lastthreadrestarttime;
 	long	macrotimer;
-	char	*macro;
-	char	*startupmacro;
-	char	*memory;
-	char	nobusyout;
+	char	lastnodewhichkeyedusup[MAXNODESTR];
+#ifdef	__RPT_NOTCH
+	struct rptfilter
+	{
+		char	desc[100];
+		float	x0;
+		float	x1;
+		float	x2;
+		float	y0;
+		float	y1;
+		float	y2;
+		float	gain;
+		float	const0;
+		float	const1;
+		float	const2;
+	} filters[MAXFILTERS];
+#endif
+#ifdef	_MDC_DECODE_H_
+	mdc_decoder_t *mdc;
+	unsigned short lastunit;
+#endif
 } rpt_vars[MAXRPTS];	
 
 
@@ -613,6 +699,10 @@ pthread_t id;
 /* Debug mode */
 static int rpt_do_debug(int fd, int argc, char *argv[]);
 static int rpt_do_dump(int fd, int argc, char *argv[]);
+static int rpt_do_stats(int fd, int argc, char *argv[]);
+static int rpt_do_lstats(int fd, int argc, char *argv[]);
+static int rpt_do_reload(int fd, int argc, char *argv[]);
+static int rpt_do_restart(int fd, int argc, char *argv[]);
 
 static char debug_usage[] =
 "Usage: rpt debug level {0-7}\n"
@@ -622,6 +712,22 @@ static char dump_usage[] =
 "Usage: rpt dump <nodename>\n"
 "       Dumps struct debug info to log\n";
 
+static char dump_stats[] =
+"Usage: rpt stats <nodename>\n"
+"       Dumps node statistics to console\n";
+
+static char dump_lstats[] =
+"Usage: rpt lstats <nodename>\n"
+"       Dumps link statistics to console\n";
+
+static char reload_usage[] =
+"Usage: rpt reload\n"
+"       Reloads app_rpt running config parameters\n";
+
+static char restart_usage[] =
+"Usage: rpt restart\n"
+"       Restarts app_rpt\n";
+
 static struct ast_cli_entry  cli_debug =
         { { "rpt", "debug", "level" }, rpt_do_debug, 
 		"Enable app_rpt debugging", debug_usage };
@@ -630,6 +736,22 @@ static struct ast_cli_entry  cli_dump =
         { { "rpt", "dump" }, rpt_do_dump,
 		"Dump app_rpt structs for debugging", dump_usage };
 
+static struct ast_cli_entry  cli_stats =
+        { { "rpt", "stats" }, rpt_do_stats,
+		"Dump node statistics", dump_stats };
+
+static struct ast_cli_entry  cli_lstats =
+        { { "rpt", "lstats" }, rpt_do_lstats,
+		"Dump link statistics", dump_lstats };
+
+static struct ast_cli_entry  cli_reload =
+        { { "rpt", "reload" }, rpt_do_reload,
+		"Reload app_rpt config", reload_usage };
+
+static struct ast_cli_entry  cli_restart =
+        { { "rpt", "restart" }, rpt_do_restart,
+		"Restart app_rpt", restart_usage };
+
 /*
 * Telemetry defaults
 */
@@ -682,10 +804,20 @@ static struct function_table_tag function_table[] = {
 	{"remote", function_remote},
 	{"macro", function_macro}
 } ;
+
+/*
+* Break up a delimited string into a table of substrings
+*
+* str - delimited string ( will be modified )
+* strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
+* limit- maximum number of substrings to process
+*/
 	
-static int finddelim(char *str,char *strp[])
+
+
+static int finddelim(char *str, char *strp[], int limit)
 {
-int     i,inquo;
+int     i,l,inquo;
 
         inquo = 0;
         i = 0;
@@ -695,7 +827,7 @@ int     i,inquo;
                 strp[0] = 0;
                 return(0);
            }
-        for(; *str; str++)
+        for(l = 0; *str && (l < limit) ; str++)
            {
                 if (*str == QUOTECHR)
                    {
@@ -713,6 +845,7 @@ int     i,inquo;
                 if ((*str == DELIMCHR) && (!inquo))
                 {
                         *str = 0;
+			l++;
                         strp[i++] = str + 1;
                 }
            }
@@ -721,6 +854,53 @@ int     i,inquo;
 
 }
 
+/*
+* Match a keyword in a list, and return index of string plus 1 if there was a match,
+* else return 0. If param is passed in non-null, then it will be set to the first character past the match
+*/
+
+static int matchkeyword(char *string, char **param, char *keywords[])
+{
+int	i,ls;
+	for( i = 0 ; keywords[i] ; i++){
+		ls = strlen(keywords[i]);
+		if(!ls){
+			*param = NULL;
+			return 0;
+		}
+		if(!strncmp(string, keywords[i], ls)){
+			if(param)
+				*param = string + ls;
+			return i + 1; 
+		}
+	}
+	param = NULL;
+	return 0;
+}
+
+/*
+* Skip characters in string which are in charlist, and return a pointer to the
+* first non-matching character
+*/
+
+static char *skipchars(char *string, char *charlist)
+{
+int i;	
+	while(*string){
+		for(i = 0; charlist[i] ; i++){
+			if(*string == charlist[i]){
+				string++;
+				break;
+			}
+		}
+		if(!charlist[i])
+			return string;
+	}
+	return string;
+}	
+					
+
+
 static int myatoi(char *str)
 {
 int	ret;
@@ -731,6 +911,248 @@ int	ret;
 	return ret;
 }
 
+
+#ifdef	__RPT_NOTCH
+
+/* rpt filter routine */
+static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
+{
+int	i,j;
+struct	rptfilter *f;
+
+	for(i = 0; i < len; i++)
+	{
+		for(j = 0; j < MAXFILTERS; j++)
+		{
+			f = &myrpt->filters[j];
+			if (!*f->desc) continue;
+			f->x0 = f->x1; f->x1 = f->x2;
+		        f->x2 = ((float)buf[i]) / f->gain;
+		        f->y0 = f->y1; f->y1 = f->y2;
+		        f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
+		                     + (f->const1 * f->y0) + (f->const2 * f->y1);
+			buf[i] = (short)f->y2;
+		}
+	}
+}
+
+#endif
+
+/* Retrieve an int from a config file */
+                                                                                
+static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
+{
+        char *var;
+        int ret;
+                                                                                
+        var = ast_variable_retrieve(myrpt->cfg, category, name);
+        if(var){
+                ret = myatoi(var);
+                if(ret < min)
+                        ret = min;
+                if(ret > max)
+                        ret = max;
+        }
+        else
+                ret = defl;
+        return ret;
+}
+
+
+static void load_rpt_vars(int n,int init)
+{
+char *this,*val;
+int	j,longestnode;
+struct ast_variable *vp;
+struct ast_config *cfg;
+#ifdef	__RPT_NOTCH
+int	i;
+char *strs[100];
+#endif
+
+	if (option_verbose > 2)
+		ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
+			(init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
+	ast_mutex_lock(&rpt_vars[n].lock);
+	if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
+	cfg = ast_config_load("rpt.conf");
+	if (!cfg) {
+		ast_mutex_unlock(&rpt_vars[n].lock);
+ 		ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
+		pthread_exit(NULL);
+	}
+	rpt_vars[n].cfg = cfg; 
+	this = rpt_vars[n].name;
+ 	memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
+	if (init)
+	{
+		char *cp;
+		int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
+
+		cp = (char *) &rpt_vars[n].p;
+		memset(cp + sizeof(rpt_vars[n].p),0,
+			sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
+		rpt_vars[n].tele.next = &rpt_vars[n].tele;
+		rpt_vars[n].tele.prev = &rpt_vars[n].tele;
+		rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
+		rpt_vars[n].tailmessagen = 0;
+	}
+#ifdef	__RPT_NOTCH
+	/* zot out filters stuff */
+	memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
+#endif
+	val = ast_variable_retrieve(cfg,this,"context");
+	if (val) rpt_vars[n].p.ourcontext = val;
+	else rpt_vars[n].p.ourcontext = this;
+	val = ast_variable_retrieve(cfg,this,"callerid");
+	if (val) rpt_vars[n].p.ourcallerid = val;
+	val = ast_variable_retrieve(cfg,this,"accountcode");
+	if (val) rpt_vars[n].p.acctcode = val;
+	val = ast_variable_retrieve(cfg,this,"idrecording");
+	if (val) rpt_vars[n].p.ident = val;
+	val = ast_variable_retrieve(cfg,this,"hangtime");
+	if (val) rpt_vars[n].p.hangtime = atoi(val);
+		else rpt_vars[n].p.hangtime = HANGTIME;
+	val = ast_variable_retrieve(cfg,this,"totime");
+	if (val) rpt_vars[n].p.totime = atoi(val);
+		else rpt_vars[n].p.totime = TOTIME;
+	rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);		
+	rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);		
+	rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
+	rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", 60000, 2400000, IDTIME);	/* Enforce a min max */
+	rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
+	val = ast_variable_retrieve(cfg,this,"tonezone");
+	if (val) rpt_vars[n].p.tonezone = val;
+	rpt_vars[n].p.tailmessages[0] = 0;
+	rpt_vars[n].p.tailmessagemax = 0;
+	val = ast_variable_retrieve(cfg,this,"tailmessagelist");
+	if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
+	val = ast_variable_retrieve(cfg,this,"memory");
+	if (!val) val = MEMORY;
+	rpt_vars[n].p.memory = val;
+	val = ast_variable_retrieve(cfg,this,"macro");
+	if (!val) val = MACRO;
+	rpt_vars[n].p.macro = val;
+	val = ast_variable_retrieve(cfg,this,"startup_macro");
+	if (val) rpt_vars[n].p.startupmacro = val;
+	val = ast_variable_retrieve(cfg,this,"iobase");
+	/* do not use atoi() here, we need to be able to have
+		the input specified in hex or decimal so we use
+		sscanf with a %i */
+	if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
+	rpt_vars[n].p.iobase = DEFAULT_IOBASE;
+	val = ast_variable_retrieve(cfg,this,"functions");
+	if (!val)
+		{
+			val = FUNCTIONS;
+			rpt_vars[n].p.simple = 1;
+		} 
+	rpt_vars[n].p.functions = val;
+	val =  ast_variable_retrieve(cfg,this,"link_functions");
+	if (val) rpt_vars[n].p.link_functions = val;
+	else 
+		rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
+	val = ast_variable_retrieve(cfg,this,"phone_functions");
+	if (val) rpt_vars[n].p.phone_functions = val;
+	val = ast_variable_retrieve(cfg,this,"dphone_functions");
+	if (val) rpt_vars[n].p.dphone_functions = val;
+	val = ast_variable_retrieve(cfg,this,"funcchar");
+	if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
+		rpt_vars[n].p.funcchar = *val;		
+	val = ast_variable_retrieve(cfg,this,"endchar");
+	if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
+		rpt_vars[n].p.endchar = *val;		
+	val = ast_variable_retrieve(cfg,this,"nobusyout");
+	if (val) rpt_vars[n].p.nobusyout = ast_true(val);
+	val = ast_variable_retrieve(cfg,this,"nodes");
+	if (!val) val = NODES;
+	rpt_vars[n].p.nodes = val;
+#ifdef	__RPT_NOTCH
+	val = ast_variable_retrieve(cfg,this,"rxnotch");
+	if (val) {
+		i = finddelim(val,strs,MAXFILTERS * 2);
+		i &= ~1; /* force an even number, rounded down */
+		if (i >= 2) for(j = 0; j < i; j += 2)
+		{
+			rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
+			  &rpt_vars[n].filters[j >> 1].gain,
+			    &rpt_vars[n].filters[j >> 1].const0,
+				&rpt_vars[n].filters[j >> 1].const1,
+				    &rpt_vars[n].filters[j >> 1].const2);
+			sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
+				strs[j],strs[j + 1]);
+		}
+
+	}
+#endif
+	longestnode = 0;
+
+	vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
+		
+	while(vp){
+		j = strlen(vp->name);
+		if (j > longestnode)
+			longestnode = j;
+		vp = vp->next;
+	}
+
+	rpt_vars[n].longestnode = longestnode;
+		
+	/*
+	* For this repeater, Determine the length of the longest function 
+	*/
+	rpt_vars[n].longestfunc = 0;
+	vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
+	while(vp){
+		j = strlen(vp->name);
+		if (j > rpt_vars[n].longestfunc)
+			rpt_vars[n].longestfunc = j;
+		vp = vp->next;
+	}
+	/*
+	* For this repeater, Determine the length of the longest function 
+	*/
+	rpt_vars[n].link_longestfunc = 0;
+	vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
+	while(vp){
+		j = strlen(vp->name);
+		if (j > rpt_vars[n].link_longestfunc)
+			rpt_vars[n].link_longestfunc = j;
+		vp = vp->next;
+	}
+	rpt_vars[n].phone_longestfunc = 0;
+	if (rpt_vars[n].p.phone_functions)
+	{
+		vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
+		while(vp){
+			j = strlen(vp->name);
+			if (j > rpt_vars[n].phone_longestfunc)
+				rpt_vars[n].phone_longestfunc = j;
+			vp = vp->next;
+		}
+	}
+	rpt_vars[n].dphone_longestfunc = 0;
+	if (rpt_vars[n].p.dphone_functions)
+	{
+		vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
+		while(vp){
+			j = strlen(vp->name);
+			if (j > rpt_vars[n].dphone_longestfunc)
+				rpt_vars[n].dphone_longestfunc = j;
+			vp = vp->next;
+		}
+	}
+	rpt_vars[n].macro_longest = 1;
+	vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
+	while(vp){
+		j = strlen(vp->name);
+		if (j > rpt_vars[n].macro_longest)
+			rpt_vars[n].macro_longest = j;
+		vp = vp->next;
+	}
+	ast_mutex_unlock(&rpt_vars[n].lock);
+}
+
 /*
 * Enable or disable debug output at a given level at the console
 */
@@ -776,6 +1198,307 @@ static int rpt_do_dump(int fd, int argc, char *argv[])
 	return RESULT_FAILURE;
 }
 
+/*
+* Dump statistics onto console
+*/
+
+static int rpt_do_stats(int fd, int argc, char *argv[])
+{
+	int i,j;
+	int dailytxtime, dailykerchunks;
+	int totalkerchunks, dailykeyups, totalkeyups, timeouts;
+	int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
+	long long totaltxtime;
+	struct	rpt_link *l;
+	char *listoflinks[MAX_STAT_LINKS];	
+	char *lastnodewhichkeyedusup, *lastdtmfcommand;
+	char *tot_state, *ider_state, *patch_state;
+	char *reverse_patch_state, *enable_state, *input_signal, *called_number;
+	struct rpt *myrpt;
+
+	static char *not_applicable = "N/A";
+
+	if(argc != 3)
+		return RESULT_SHOWUSAGE;
+
+	for(i = 0 ; i <= MAX_STAT_LINKS; i++)
+		listoflinks[i] = NULL;
+
+	tot_state = ider_state = 
+	patch_state = reverse_patch_state = 
+	input_signal = called_number = 
+	lastdtmfcommand = not_applicable;
+
+	for(i = 0; i < nrpts; i++)
+	{
+		if (!strcmp(argv[2],rpt_vars[i].name)){
+			/* Make a copy of all stat variables while locked */
+			myrpt = &rpt_vars[i];
+			rpt_mutex_lock(&myrpt->lock); /* LOCK */
+
+			dailytxtime = myrpt->dailytxtime;
+			totaltxtime = myrpt->totaltxtime;
+			dailykeyups = myrpt->dailykeyups;
+			totalkeyups = myrpt->totalkeyups;
+			dailykerchunks = myrpt->dailykerchunks;
+			totalkerchunks = myrpt->totalkerchunks;
+			dailyexecdcommands = myrpt->dailyexecdcommands;
+			totalexecdcommands = myrpt->totalexecdcommands;
+			timeouts = myrpt->timeouts;
+
+			/* Traverse the list of connected nodes */
+			reverse_patch_state = "DOWN";
+			j = 0;
+			l = myrpt->links.next;
+			while(l != &myrpt->links){
+				if (l->name[0] == '0'){ /* Skip '0' nodes */
+					reverse_patch_state = "UP";
+					l = l->next;
+					continue;
+				}
+				listoflinks[j] = ast_strdupa(l->name);
+				if(listoflinks[j])
+					j++;
+				l = l->next;
+			}
+
+			lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);			
+			if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
+				lastnodewhichkeyedusup = not_applicable;
+
+			if(myrpt->keyed)
+				input_signal = "YES";
+			else
+				input_signal = "NO";
+
+			if(myrpt->enable)
+				enable_state = "YES";
+			else
+				enable_state = "NO";
+
+			if(!myrpt->totimer)
+				tot_state = "TIMED OUT!";
+			else if(myrpt->totimer != myrpt->p.totime)
+				tot_state = "ARMED";
+			else
+				tot_state = "RESET";
+
+			if(myrpt->tailid)
+				ider_state = "QUEUED IN TAIL";
+			else if(myrpt->mustid)
+				ider_state = "QUEUED FOR CLEANUP";
+			else
+				ider_state = "CLEAN";
+
+			switch(myrpt->callmode){
+				case 1:
+					patch_state = "DIALING";
+					break;
+				case 2:
+					patch_state = "CONNECTING";
+					break;
+				case 3:
+					patch_state = "UP";
+					break;
+
+				case 4:
+					patch_state = "CALL FAILED";
+					break;
+
+				default:
+					patch_state = "DOWN";
+			}
+
+			if(strlen(myrpt->exten)){
+				called_number = ast_strdupa(myrpt->exten);
+				if(!called_number)
+					called_number = not_applicable;
+			}
+
+			if(strlen(myrpt->lastdtmfcommand)){
+				lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
+				if(!lastdtmfcommand)
+					lastdtmfcommand = not_applicable;
+			}
+
+			rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
+
+			ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
+			ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
+			ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state);
+			ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
+			ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
+			ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
+			ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
+			ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
+			ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
+			ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
+			ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
+			ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
+			ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
+
+			hours = dailytxtime/3600000;
+			dailytxtime %= 3600000;
+			minutes = dailytxtime/60000;
+			dailytxtime %= 60000;
+			seconds = dailytxtime/1000;
+			dailytxtime %= 1000;
+
+			ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
+				hours, minutes, seconds, dailytxtime);
+
+			hours = (int) totaltxtime/3600000;
+			totaltxtime %= 3600000;
+			minutes = (int) totaltxtime/60000;
+			totaltxtime %= 60000;
+			seconds = (int)  totaltxtime/1000;
+			totaltxtime %= 1000;
+
+			ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
+				 hours, minutes, seconds, (int) totaltxtime);
+			ast_cli(fd, "Nodes currently connected to us..................: ");
+			for(j = 0 ;; j++){
+				if(!listoflinks[j]){
+					if(!j){
+						ast_cli(fd,"<NONE>");
+					}
+					break;
+				}
+				ast_cli(fd, "%s", listoflinks[j]);
+				if(j % 4 == 3){
+					ast_cli(fd, "\n");
+					ast_cli(fd, "                                                 : ");
+				}
+				else{
+					if(listoflinks[j + 1])
+						ast_cli(fd, ", ");
+				}
+			}
+			ast_cli(fd,"\n");
+
+			ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
+			ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
+			ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
+			ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
+
+		        return RESULT_SUCCESS;
+		}
+	}
+	return RESULT_FAILURE;
+}
+
+/*
+* Link stats function
+*/
+
+static int rpt_do_lstats(int fd, int argc, char *argv[])
+{
+	int i,j;
+	struct rpt *myrpt;
+	struct rpt_link *l;
+	struct rpt_lstat *s,*t;
+	struct rpt_lstat s_head;
+	if(argc != 3)
+		return RESULT_SHOWUSAGE;
+
+	s = NULL;
+	s_head.next = &s_head;
+	s_head.prev = &s_head;
+
+	for(i = 0; i < nrpts; i++)
+	{
+		if (!strcmp(argv[2],rpt_vars[i].name)){
+			/* Make a copy of all stat variables while locked */
+			myrpt = &rpt_vars[i];
+			rpt_mutex_lock(&myrpt->lock); /* LOCK */
+			/* Traverse the list of connected nodes */
+			j = 0;
+			l = myrpt->links.next;
+			while(l != &myrpt->links){
+				if (l->name[0] == '0'){ /* Skip '0' nodes */
+					l = l->next;
+					continue;
+				}
+				if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
+					ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
+					rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
+					return RESULT_FAILURE;
+				}
+				memset(s, 0, sizeof(struct rpt_lstat));
+				strncpy(s->name, l->name, MAXREMSTR - 1);
+				pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
+				s->mode = l->mode;
+				s->outbound = l->outbound;
+				s->reconnects = l->reconnects;
+				s->connecttime = l->connecttime;
+				insque((struct qelem *) s, (struct qelem *) s_head.next);
+				l = l->next;
+			}
+			rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
+			ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME\n");
+			ast_cli(fd, "----      ----                ----------  ---------  ------------\n");
+
+			for(s = s_head.next; s != &s_head; s = s->next){
+				int hours, minutes, seconds;
+				long long connecttime = s->connecttime;
+				char conntime[31];
+				hours = (int) connecttime/3600000;
+				connecttime %= 3600000;
+				minutes = (int) connecttime/60000;
+				connecttime %= 60000;
+				seconds = (int)  connecttime/1000;
+				connecttime %= 1000;
+				snprintf(conntime, 30, "%02d:%02d:%02d.%d",
+					hours, minutes, seconds, (int) connecttime);
+				conntime[30] = 0;
+				ast_cli(fd, "%-10s%-20s%-12d%-11s%-30s\n",
+					s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
+			}	
+			/* destroy our local link queue */
+			s = s_head.next;
+			while(s != &s_head){
+				t = s;
+				s = s->next;
+				remque((struct qelem *)t);
+				free(t);
+			}			
+			return RESULT_SUCCESS;
+		}
+	}
+	return RESULT_FAILURE;
+}
+
+/*
+* reload vars 
+*/
+                                                                                                                                 
+static int rpt_do_reload(int fd, int argc, char *argv[])
+{
+int	n;
+
+        if (argc > 2) return RESULT_SHOWUSAGE;
+
+	for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
+
+	return RESULT_FAILURE;
+}
+
+/*
+* restart app_rpt
+*/
+                                                                                                                                 
+static int rpt_do_restart(int fd, int argc, char *argv[])
+{
+int	i;
+
+        if (argc > 2) return RESULT_SHOWUSAGE;
+	for(i = 0; i < nrpts; i++)
+	{
+		if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
+	}
+	return RESULT_FAILURE;
+}
+
 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
 {
 	int res;
@@ -1054,27 +1777,7 @@ static int saynum(struct ast_channel *mychannel, int num)
 }
 
 
-/* Retrieve an int from a config file */
-                                                                                
-static int retrieve_astcfgint(char *category, char *name, int min, int max, int defl)
-{
-        char *var;
-        int ret;
-                                                                                
-        var = ast_variable_retrieve(cfg, category, name);
-        if(var){
-                ret = myatoi(var);
-                if(ret < min)
-                        ret = min;
-                if(ret > max)
-                        ret = max;
-        }
-        else
-                ret = defl;
-        return ret;
-}
-
-static int telem_any(struct ast_channel *chan, char *entry)
+static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
 {
 	int res;
 	char c;
@@ -1089,11 +1792,11 @@ static int telem_any(struct ast_channel *chan, char *entry)
 	res = 0;
 	
 	if(!morseidfreq){ /* Get the morse parameters if not already loaded */
-		morsespeed = retrieve_astcfgint( mcat, "speed", 5, 20, 20);
-        	morsefreq = retrieve_astcfgint( mcat, "frequency", 300, 3000, 800);
-        	morseampl = retrieve_astcfgint( mcat, "amplitude", 200, 8192, 4096);
-		morseidampl = retrieve_astcfgint( mcat, "idamplitude", 200, 8192, 2048);
-		morseidfreq = retrieve_astcfgint( mcat, "idfrequency", 300, 3000, 330);	
+		morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
+        	morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
+        	morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
+		morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
+		morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);	
 	}
 	
 	/* Is it a file, or a tone sequence? */
@@ -1130,7 +1833,7 @@ static int telem_any(struct ast_channel *chan, char *entry)
 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
 */
 
-static int telem_lookup(struct ast_channel *chan, char *node, char *name)
+static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
 {
 	
 	int res;
@@ -1143,21 +1846,19 @@ static int telem_lookup(struct ast_channel *chan, char *node, char *name)
 	telemetry_save = NULL;
 	entry = NULL;
 	
-	
 	/* Retrieve the section name for telemetry from the node section */
-	
-	telemetry = ast_variable_retrieve(cfg, node, TELEMETRY);
-	if(telemetry){
+	telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
+	if(telemetry ){
 		telemetry_save = ast_strdupa(telemetry);
 		if(!telemetry_save){
 			ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
 			return res;
 		}
-		entry = ast_variable_retrieve(cfg, telemetry_save, name);
+		entry = ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
 	}
 	
-	/* Try to look up the telemetry name */
-	
+	/* Try to look up the telemetry name */	
+
 	if(!entry){
 		/* Telemetry name wasn't found in the config file, use the default */
 		for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
@@ -1165,10 +1866,11 @@ static int telem_lookup(struct ast_channel *chan, char *node, char *name)
 				entry = tele_defs[i].value;
 		}
 	}
-	if(entry)	
-		telem_any(chan, entry);
+	if(entry){	
+		if(strlen(entry))
+			telem_any(myrpt,chan, entry);
+	}
 	else{
-		ast_log(LOG_WARNING, "Telemetry name not found: %s\n", name);
 		res = -1;
 	}
 	return res;
@@ -1185,7 +1887,7 @@ static int get_wait_interval(struct rpt *myrpt, int type)
         char *wait_times_save;
                                                                                                                   
         wait_times_save = NULL;
-        wait_times = ast_variable_retrieve(cfg, myrpt->name, "wait_times");
+        wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
                                                                                                                   
         if(wait_times){
                 wait_times_save = ast_strdupa(wait_times);
@@ -1198,28 +1900,28 @@ static int get_wait_interval(struct rpt *myrpt, int type)
         switch(type){
                 case DLY_TELEM:
                         if(wait_times)
-                                interval = retrieve_astcfgint(wait_times_save, "telemwait", 500, 5000, 1000);
+                                interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
                         else
                                 interval = 1000;
                         break;
                                                                                                                   
                 case DLY_ID:
                         if(wait_times)
-                                interval = retrieve_astcfgint(wait_times_save, "idwait",250,5000,500);
+                                interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
                         else
                                 interval = 500;
                         break;
                                                                                                                   
                 case DLY_UNKEY:
                         if(wait_times)
-                                interval = retrieve_astcfgint(wait_times_save, "unkeywait",500,5000,1000);
+                                interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
                         else
                                 interval = 1000;
                         break;
                                                                                                                   
                 case DLY_CALLTERM:
                         if(wait_times)
-                                interval = retrieve_astcfgint(wait_times_save, "calltermwait",500,5000,1500);
+                                interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
                         else
                                 interval = 1500;
                         break;
@@ -1239,8 +1941,13 @@ static int get_wait_interval(struct rpt *myrpt, int type)
 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
 {
 	int interval;
-	if((interval = get_wait_interval(myrpt, type)))
+	interval = get_wait_interval(myrpt, type);
+	if(debug)
+		ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
+	if(interval)
 		ast_safe_sleep(chan,interval);
+	if(debug)
+		ast_log(LOG_NOTICE,"Delay complete\n");
 	return;
 }
 
@@ -1264,9 +1971,8 @@ struct tm localtm;
 
 	/* Snag copies of a few key myrpt variables */
 	rpt_mutex_lock(&myrpt->lock);
-	insque((struct qelem *)mytele, (struct qelem *)myrpt->tele.next); /* Moved from rpt_telemetry() */
 	nodename = ast_strdupa(myrpt->name);
-	ident = ast_strdupa(myrpt->ident);
+	ident = ast_strdupa(myrpt->p.ident);
 	rpt_mutex_unlock(&myrpt->lock);
 	
 	/* allocate a pseudo-channel thru asterisk */
@@ -1314,35 +2020,41 @@ struct tm localtm;
 	    case ID1:
 		/* wait a bit */
 		wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
-		res = telem_any(mychannel, ident); 
+		res = telem_any(myrpt,mychannel, ident); 
 		imdone=1;	
 		break;
 		
 	    case TAILMSG:
-		res = ast_streamfile(mychannel, myrpt->tailmessages[myrpt->tailmessagen], mychannel->language); 
+		res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
 		break;
 		
 	    case IDTALKOVER:
-	    	p = ast_variable_retrieve(cfg, nodename, "idtalkover");
+	    	p = ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
 	    	if(p)
-			res = telem_any(mychannel, p); 
+			res = telem_any(myrpt,mychannel, p); 
 		imdone=1;	
 	    	break;
 	    		
 	    case PROC:
 		/* wait a little bit longer */
 		wait_interval(myrpt, DLY_TELEM, mychannel);
-		res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
+		res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
+		if(res < 0){ /* Then default message */
+			res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
+		}
 		break;
 	    case TERM:
 		/* wait a little bit longer */
 		wait_interval(myrpt, DLY_CALLTERM, mychannel);
-		res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
+		res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
+		if(res < 0){ /* Then default message */
+			res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
+		}
 		break;
 	    case COMPLETE:
 		/* wait a little bit */
 		wait_interval(myrpt, DLY_TELEM, mychannel);
-		res = telem_lookup(mychannel, myrpt->name, "functcomplete");
+		res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
 		break;
 	    case MACRO_NOTFOUND:
 		/* wait a little bit */
@@ -1355,7 +2067,11 @@ struct tm localtm;
 		res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
 		break;
 	    case UNKEY:
-
+		if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
+			imdone = 1;
+			break;
+		}
+			
 		/*
 		* Reset the Unkey to CT timer
 		*/
@@ -1411,7 +2127,12 @@ struct tm localtm;
 			imdone = 1;
 			break;
 		}
-			
+		
+		rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
+		myrpt->dailykerchunks++;
+		myrpt->totalkerchunks++;
+		rpt_mutex_unlock(&myrpt->lock);
+	
 		haslink = 0;
 		hastx = 0;
 		hasremote = 0;		
@@ -1438,7 +2159,7 @@ struct tm localtm;
 		if (haslink)
 		{
 
-			res = telem_lookup(mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
+			res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
 			if(res)
 				ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
 			
@@ -1447,15 +2168,15 @@ struct tm localtm;
 			if (myrpt->cmdnode[0])
 			{
 				ast_safe_sleep(mychannel,200);
-				res = telem_lookup(mychannel, myrpt->name, "cmdmode");
+				res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
 				if(res)
 				 	ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
 				ast_stopstream(mychannel);
 			}
 		}
-		else if((ct = ast_variable_retrieve(cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
+		else if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
 			ct_copy = ast_strdupa(ct);
-			res = telem_lookup(mychannel, myrpt->name, ct_copy);
+			res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
 			if(res)
 			 	ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);		
 		}	
@@ -1477,14 +2198,42 @@ struct tm localtm;
 				ast_hangup(mychannel);
 				pthread_exit(NULL);
 			}
-			if((ct = ast_variable_retrieve(cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
+			if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
 				ast_safe_sleep(mychannel,200);
 				ct_copy = ast_strdupa(ct);
-				res = telem_lookup(mychannel, myrpt->name, ct_copy);
+				res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
 				if(res)
 				 	ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);		
 			}	
 		}
+#ifdef	_MDC_DECODE_H_
+		if (myrpt->lastunit)
+		{
+			char mystr[10];
+
+			ast_safe_sleep(mychannel,200);
+			/* set for all to hear */
+			ci.chan = 0;
+			ci.confno = myrpt->txconf;
+			ci.confmode = ZT_CONF_CONFANN;
+			/* first put the channel on the conference in announce mode */
+			if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
+			{
+				ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
+				rpt_mutex_lock(&myrpt->lock);
+				remque((struct qelem *)mytele);
+				rpt_mutex_unlock(&myrpt->lock);
+				ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
+				free(mytele);		
+				ast_hangup(mychannel);
+				pthread_exit(NULL);
+			}
+			sprintf(mystr,"%04x",myrpt->lastunit);
+			myrpt->lastunit = 0;
+			ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
+			break;
+		}
+#endif
 		imdone = 1;
 		break;
 	    case REMDISC:
@@ -1637,6 +2386,34 @@ struct tm localtm;
 		}			
 		imdone = 1;
 		break;
+
+	    case LASTNODEKEY: /* Identify last node which keyed us up */
+		rpt_mutex_lock(&myrpt->lock);
+		if(myrpt->lastnodewhichkeyedusup)
+			p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
+		else
+			p = NULL;
+		rpt_mutex_unlock(&myrpt->lock);
+		if(!p){
+			imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
+			break;
+		}
+		wait_interval(myrpt, DLY_TELEM, mychannel);
+		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
+		if (!res) 
+			res = ast_waitstream(mychannel, "");
+		else
+			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
+		ast_stopstream(mychannel);
+		ast_say_character_str(mychannel, p, NULL, mychannel->language);
+		if (!res) 
+			res = ast_waitstream(mychannel, "");
+		else
+			ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
+		ast_stopstream(mychannel);
+		imdone = 1;
+		break;		
+
 	    case TIMEOUT:
 		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
 		if (!res) 
@@ -1784,11 +2561,11 @@ struct tm localtm;
 		if (!res)
 		{
 			myrpt->tailmessagen++;
-			if(myrpt->tailmessagen >= myrpt->tailmessagemax) myrpt->tailmessagen = 0;
+			if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
 		}
 		else
 		{
-			myrpt->tmsgtimer = myrpt->tailsquashedtime;
+			myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
 		}
 	}
 	remque((struct qelem *)mytele);
@@ -1838,12 +2615,17 @@ pthread_attr_t attr;
 		strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
 		tele->param[TELEPARAMSIZE - 1] = 0;
 	}
+	insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
 	rpt_mutex_unlock(&myrpt->lock);
         pthread_attr_init(&attr);
         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 	res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
-	if(res < 0)
+	if(res < 0){
+		rpt_mutex_lock(&myrpt->lock);
+		remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
+		rpt_mutex_unlock(&myrpt->lock);	
 		ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
+	}
 	return;
 }
 
@@ -1853,9 +2635,10 @@ ZT_CONFINFO ci;  /* conference info */
 struct	rpt *myrpt = (struct rpt *)this;
 int	res;
 struct	ast_frame wf;
-int stopped,congstarted;
+int stopped,congstarted,dialtimer,lastcidx,aborted;
 struct ast_channel *mychannel,*genchannel;
 
+
 	myrpt->mydtmf = 0;
 	/* allocate a pseudo-channel thru asterisk */
 	mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
@@ -1897,24 +2680,24 @@ struct ast_channel *mychannel,*genchannel;
 		myrpt->callmode = 0;
 		pthread_exit(NULL);
 	}
-	if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1))
+	if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
 	{
-		ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
+		ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
 		ast_hangup(mychannel);
 		ast_hangup(genchannel);
 		myrpt->callmode = 0;
 		pthread_exit(NULL);
 	}
-	if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1))
+	if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
 	{
-		ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
+		ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
 		ast_hangup(mychannel);
 		ast_hangup(genchannel);
 		myrpt->callmode = 0;
 		pthread_exit(NULL);
 	}
-	/* start dialtone */
-	if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0)
+	/* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
+	if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0))
 	{
 		ast_log(LOG_WARNING, "Cannot start dialtone\n");
 		ast_hangup(mychannel);
@@ -1924,20 +2707,40 @@ struct ast_channel *mychannel,*genchannel;
 	}
 	stopped = 0;
 	congstarted = 0;
+	dialtimer = 0;
+	lastcidx = 0;
+	aborted = 0;
+
+
 	while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
 	{
 
-		if ((myrpt->callmode == 1) && (myrpt->cidx > 0) && (!stopped))
+		if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
+			dialtimer = 0;
+			lastcidx = myrpt->cidx;
+		}		
+
+		if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
+			rpt_mutex_lock(&myrpt->lock);
+			aborted = 1;
+			myrpt->callmode = 0;
+			rpt_mutex_unlock(&myrpt->lock);
+			break;
+		}
+	
+		if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
 		{
 			stopped = 1;
 			/* stop dial tone */
 			tone_zone_play_tone(mychannel->fds[0],-1);
 		}
-		if ((myrpt->callmode == 4) && (!congstarted))
+		if (myrpt->callmode == 4)
 		{
-			congstarted = 1;
-			/* start congestion tone */
-			tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
+			if(!congstarted){
+				congstarted = 1;
+				/* start congestion tone */
+				tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
+			}
 		}
 		res = ast_safe_sleep(mychannel, MSWAIT);
 		if (res < 0)
@@ -1949,6 +2752,7 @@ struct ast_channel *mychannel,*genchannel;
 			rpt_mutex_unlock(&myrpt->lock);
 			pthread_exit(NULL);
 		}
+		dialtimer += MSWAIT;
 	}
 	/* stop any tone generation */
 	tone_zone_play_tone(mychannel->fds[0],-1);
@@ -1960,12 +2764,14 @@ struct ast_channel *mychannel,*genchannel;
 		rpt_mutex_lock(&myrpt->lock);
 		myrpt->callmode = 0;
 		rpt_mutex_unlock(&myrpt->lock);
+		if((!myrpt->patchquiet) && aborted)
+			rpt_telemetry(myrpt, TERM, NULL);
 		pthread_exit(NULL);			
 	}
 
-	if (myrpt->ourcallerid && *myrpt->ourcallerid){
+	if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
 		char *name, *loc, *instr;
-		instr = strdup(myrpt->ourcallerid);
+		instr = strdup(myrpt->p.ourcallerid);
 		if(instr){
 			ast_callerid_parse(instr, &name, &loc);
 			if(loc){
@@ -1983,9 +2789,10 @@ struct ast_channel *mychannel,*genchannel;
 	}
 
 	strncpy(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
-	strncpy(mychannel->context, myrpt->ourcontext, sizeof(mychannel->context) - 1);
-	if (myrpt->acctcode)
-		ast_string_field_set(mychannel, accountcode, myrpt->acctcode);
+	strncpy(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
+	
+	if (myrpt->p.acctcode)
+		strncpy((char *)mychannel->accountcode, myrpt->p.acctcode, sizeof(mychannel->accountcode) - 1);
 	mychannel->priority = 1;
 	ast_channel_undefer_dtmf(mychannel);
 	if (ast_pbx_start(mychannel) < 0)
@@ -2001,15 +2808,39 @@ struct ast_channel *mychannel,*genchannel;
 	usleep(10000);
 	rpt_mutex_lock(&myrpt->lock);
 	myrpt->callmode = 3;
+	/* set appropriate conference for the pseudo */
+	ci.chan = 0;
+	ci.confno = myrpt->conf;
+	ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
+		(ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
+	/* first put the channel on the conference in announce mode */
+	if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
+	{
+		ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
+		ast_hangup(mychannel);
+		ast_hangup(genchannel);
+		myrpt->callmode = 0;
+		pthread_exit(NULL);
+	}
 	while(myrpt->callmode)
 	{
 		if ((!mychannel->pbx) && (myrpt->callmode != 4))
 		{
-			myrpt->callmode = 4;
-			rpt_mutex_unlock(&myrpt->lock);
-			/* start congestion tone */
-			tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
-			rpt_mutex_lock(&myrpt->lock);
+			if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
+				myrpt->callmode = 0;
+				if(!myrpt->patchquiet){
+					rpt_mutex_unlock(&myrpt->lock);
+					rpt_telemetry(myrpt, TERM, NULL);
+					rpt_mutex_lock(&myrpt->lock);
+				}
+			}
+			else{ /* Send congestion until patch is downed by command */
+				myrpt->callmode = 4;
+				rpt_mutex_unlock(&myrpt->lock);
+				/* start congestion tone */
+				tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
+				rpt_mutex_lock(&myrpt->lock);
+			}
 		}
 		if (myrpt->mydtmf)
 		{
@@ -2036,6 +2867,16 @@ struct ast_channel *mychannel,*genchannel;
 	rpt_mutex_lock(&myrpt->lock);
 	myrpt->callmode = 0;
 	rpt_mutex_unlock(&myrpt->lock);
+	/* set appropriate conference for the pseudo */
+	ci.chan = 0;
+	ci.confno = myrpt->conf;
+	ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
+		(ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
+	/* first put the channel on the conference in announce mode */
+	if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
+	{
+		ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
+	}
 	pthread_exit(NULL);
 }
 
@@ -2092,6 +2933,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 	char tmp[300], deststr[300] = "",modechange = 0;
 	char digitbuf[MAXNODESTR];
 	struct rpt_link *l;
+	int reconnects = 0;
 	ZT_CONFINFO ci;  /* conference info */
 
 	if(!param)
@@ -2110,7 +2952,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 		case 1: /* Link off */
 			if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
 				strcpy(digitbuf,myrpt->lastlinknode);
-			val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
+			val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
 			if (!val){
 				if(strlen(digitbuf) >= myrpt->longestnode)
 					return DC_ERROR;
@@ -2136,7 +2978,6 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 			}
 			if (l != &myrpt->links){ /* if found */
 				struct	ast_frame wf;
-
 				strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
 				l->retries = MAX_RETRIES + 1;
 				l->disced = 1;
@@ -2162,7 +3003,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 		case 2: /* Link Monitor */
 			if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
 				strcpy(digitbuf,myrpt->lastlinknode);
-			val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
+			val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
 			if (!val){
 				if(strlen(digitbuf) >= myrpt->longestnode)
 					return DC_ERROR;
@@ -2196,6 +3037,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 					return DC_COMPLETE;
 					
 				}
+				reconnects = l->reconnects;
 				rpt_mutex_unlock(&myrpt->lock);
 				if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
 				l->retries = MAX_RETRIES + 1;
@@ -2270,6 +3112,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 				return DC_ERROR;
 			}
 			rpt_mutex_lock(&myrpt->lock);
+			l->reconnects = reconnects;
 			/* insert at end of queue */
 			insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
 			rpt_mutex_unlock(&myrpt->lock);
@@ -2278,7 +3121,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 		case 3: /* Link transceive */
 			if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
 				strcpy(digitbuf,myrpt->lastlinknode);
-			val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
+			val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
 			if (!val){
 				if(strlen(digitbuf) >= myrpt->longestnode)
 					return DC_ERROR;
@@ -2310,6 +3153,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 					rpt_telemetry(myrpt, REMALREADY, NULL);
 					return DC_COMPLETE;
 				}
+				reconnects = l->reconnects;
 				rpt_mutex_unlock(&myrpt->lock);
 				if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
 				l->retries = MAX_RETRIES + 1;
@@ -2386,6 +3230,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 				return DC_ERROR;
 			}
 			rpt_mutex_lock(&myrpt->lock);
+			l->reconnects = reconnects;
 			/* insert at end of queue */
 			insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
 			rpt_mutex_unlock(&myrpt->lock);
@@ -2406,7 +3251,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 			if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
 				strcpy(digitbuf,myrpt->lastlinknode);
 			/* node must at least exist in list */
-			val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
+			val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
 			if (!val){
 				if(strlen(digitbuf) >= myrpt->longestnode)
 					return DC_ERROR;
@@ -2428,12 +3273,16 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 		case 6: /* All Links Off */
 			l = myrpt->links.next;
 			
-			while(l != &myrpt->links){
+			while(l != &myrpt->links){ /* This code is broke and needs to be changed to work with the reconnect kludge */
 				if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
 				l = l->next;
 			}
 			rpt_telemetry(myrpt, COMPLETE, NULL);
 			break;
+
+		case 7: /* Identify last node which keyed us up */
+			rpt_telemetry(myrpt, LASTNODEKEY, NULL);
+			break;
 	
 		default:
 			return DC_ERROR;
@@ -2450,7 +3299,19 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digits, int comm
 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
 {
 	pthread_attr_t attr;
-	
+	int i, index, paramlength;
+	char *lparam;
+	char *value = NULL;
+	char *paramlist[20];
+
+	static char *keywords[] = {
+	"context",
+	"dialtime",
+	"farenddisconnect",
+	"noct",
+	"quiet",
+	NULL
+	};
 		
 	if (!myrpt->enable)
 		return DC_ERROR;
@@ -2458,12 +3319,61 @@ static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf,
 	if(debug)
 		printf("@@@@ Autopatch up\n");
 
+	if(!myrpt->callmode){
+		/* Set defaults */
+		myrpt->patchnoct = 0;
+		myrpt->patchdialtime = 0;
+		myrpt->patchfarenddisconnect = 0;
+		myrpt->patchquiet = 0;
+		strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
+
+		if(param){
+			/* Process parameter list */
+			lparam = ast_strdupa(param);
+			if(!lparam){
+				ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
+				return DC_ERROR;	
+			}
+			paramlength = finddelim(lparam, paramlist, 20); 			
+			for(i = 0; i < paramlength; i++){
+				index = matchkeyword(paramlist[i], &value, keywords);
+				if(value)
+					value = skipchars(value, "= ");
+				switch(index){
+
+					case 1: /* context */
+						strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
+						break;
+						
+					case 2: /* dialtime */
+						myrpt->patchdialtime = atoi(value);
+						break;
+
+					case 3: /* farenddisconnect */
+						myrpt->patchfarenddisconnect = atoi(value);
+						break;
+
+					case 4:	/* noct */
+						myrpt->patchnoct = atoi(value);
+						break;
+
+					case 5: /* quiet */
+						myrpt->patchquiet = atoi(value);
+						break;
+				 					
+					default:
+						break;
+				}
+			}
+		}
+	}
+					
 	rpt_mutex_lock(&myrpt->lock);
-	
+
 	/* if on call, force * into current audio stream */
 	
 	if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
-		myrpt->mydtmf = myrpt->funcchar;
+		myrpt->mydtmf = myrpt->p.funcchar;
 	}
 	if (myrpt->callmode){
 		rpt_mutex_unlock(&myrpt->lock);
@@ -2562,8 +3472,8 @@ struct	ast_channel *mychannel;
 			return DC_ERROR;
 	}
    
-	if (*digitbuf == '0') val = myrpt->startupmacro;
-	else val = ast_variable_retrieve(cfg, myrpt->macro, digitbuf);
+	if (*digitbuf == '0') val = myrpt->p.startupmacro;
+	else val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
 	/* param was 1 for local buf */
 	if (!val){
 		rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
@@ -2631,7 +3541,7 @@ static int collect_function_digits(struct rpt *myrpt, char *digits,
 	int i;
 	char *stringp,*action,*param,*functiondigits;
 	char function_table_name[30] = "";
-	char workstring[80];
+	char workstring[200];
 	
 	struct ast_variable *vp;
 	
@@ -2639,18 +3549,18 @@ static int collect_function_digits(struct rpt *myrpt, char *digits,
 		printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
 	
 	if (command_source == SOURCE_DPHONE) {
-		if (!myrpt->dphone_functions) return DC_INDETERMINATE;
-		strncpy(function_table_name, myrpt->dphone_functions, sizeof(function_table_name) - 1);
+		if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
+		strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
 		}
 	else if (command_source == SOURCE_PHONE) {
-		if (!myrpt->phone_functions) return DC_INDETERMINATE;
-		strncpy(function_table_name, myrpt->phone_functions, sizeof(function_table_name) - 1);
+		if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
+		strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
 		}
 	else if (command_source == SOURCE_LNK)
-		strncpy(function_table_name, myrpt->link_functions, sizeof(function_table_name) - 1);
+		strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
 	else
-		strncpy(function_table_name, myrpt->functions, sizeof(function_table_name) - 1);
-	vp = ast_variable_browse(cfg, function_table_name);
+		strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
+	vp = ast_variable_browse(myrpt->cfg, function_table_name);
 	while(vp) {
 		if(!strncasecmp(vp->name, digits, strlen(vp->name)))
 			break;
@@ -2795,21 +3705,23 @@ struct	ast_frame wf;
 		return;
 	}
 	rpt_mutex_lock(&myrpt->lock);
-	if (c == myrpt->endchar) myrpt->stopgen = 1;
+	if (c == myrpt->p.endchar) myrpt->stopgen = 1;
 	if (myrpt->callmode == 1)
 	{
 		myrpt->exten[myrpt->cidx++] = c;
 		myrpt->exten[myrpt->cidx] = 0;
 		/* if this exists */
-		if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
+		if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
 		{
 			myrpt->callmode = 2;
-			rpt_mutex_unlock(&myrpt->lock);
-			rpt_telemetry(myrpt,PROC,NULL); 
-			rpt_mutex_lock(&myrpt->lock);
+			if(!myrpt->patchquiet){
+				rpt_mutex_unlock(&myrpt->lock);
+				rpt_telemetry(myrpt,PROC,NULL); 
+				rpt_mutex_lock(&myrpt->lock);
+			}
 		}
 		/* if can continue, do so */
-		if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
+		if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
 		{
 			/* call has failed, inform user */
 			myrpt->callmode = 4;
@@ -2819,7 +3731,7 @@ struct	ast_frame wf;
 	{
 		myrpt->mydtmf = c;
 	}
-	if (c == myrpt->funcchar)
+	if (c == myrpt->p.funcchar)
 	{
 		myrpt->rem_dtmfidx = 0;
 		myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
@@ -2827,7 +3739,7 @@ struct	ast_frame wf;
 		rpt_mutex_unlock(&myrpt->lock);
 		return;
 	} 
-	else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
+	else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
 	{
 		time(&myrpt->rem_dtmf_time);
 		if (myrpt->rem_dtmfidx < MAXDTMF)
@@ -2852,6 +3764,10 @@ struct	ast_frame wf;
 				
 				
 				case DC_COMPLETE:
+					myrpt->totalexecdcommands++;
+					myrpt->dailyexecdcommands++;
+					strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
+					myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
 					myrpt->rem_dtmfbuf[0] = 0;
 					myrpt->rem_dtmfidx = -1;
 					myrpt->rem_dtmf_time = 0;
@@ -2879,7 +3795,7 @@ char	cmd[300];
 int	res;
 
 	rpt_mutex_lock(&myrpt->lock);
-	if (c == myrpt->endchar)
+	if (c == myrpt->p.endchar)
 	{
 		if (mylink->lastrx)
 		{
@@ -2909,15 +3825,17 @@ int	res;
 		myrpt->exten[myrpt->cidx++] = c;
 		myrpt->exten[myrpt->cidx] = 0;
 		/* if this exists */
-		if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
+		if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
 		{
 			myrpt->callmode = 2;
-			rpt_mutex_unlock(&myrpt->lock);
-			rpt_telemetry(myrpt,PROC,NULL); 
-			rpt_mutex_lock(&myrpt->lock);
+			if(!myrpt->patchquiet){
+				rpt_mutex_unlock(&myrpt->lock);
+				rpt_telemetry(myrpt,PROC,NULL); 
+				rpt_mutex_lock(&myrpt->lock);
+			}
 		}
 		/* if can continue, do so */
-		if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
+		if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
 		{
 			/* call has failed, inform user */
 			myrpt->callmode = 4;
@@ -2927,7 +3845,7 @@ int	res;
 	{
 		myrpt->mydtmf = c;
 	}
-	if (c == myrpt->funcchar)
+	if (c == myrpt->p.funcchar)
 	{
 		myrpt->rem_dtmfidx = 0;
 		myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
@@ -2935,7 +3853,7 @@ int	res;
 		rpt_mutex_unlock(&myrpt->lock);
 		return;
 	} 
-	else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
+	else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
 	{
 		time(&myrpt->rem_dtmf_time);
 		if (myrpt->rem_dtmfidx < MAXDTMF)
@@ -2979,6 +3897,10 @@ int	res;
 				
 				
 				case DC_COMPLETE:
+					myrpt->totalexecdcommands++;
+					myrpt->dailyexecdcommands++;
+					strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
+					myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
 					myrpt->rem_dtmfbuf[0] = 0;
 					myrpt->rem_dtmfidx = -1;
 					myrpt->rem_dtmf_time = 0;
@@ -3170,14 +4092,14 @@ static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
         od = *data++; 
         for(j = 0 ; j < 8 ; j++){
             d = od & 1;
-            outb(d,myrpt->iobase);
+            outb(d,myrpt->p.iobase);
 	    /* >= 15 us */
 	    for(delayvar = 1; delayvar < 15000; delayvar++); 
             od >>= 1;
-            outb(d | 2,myrpt->iobase);
+            outb(d | 2,myrpt->p.iobase);
 	    /* >= 30 us */
 	    for(delayvar = 1; delayvar < 30000; delayvar++); 
-            outb(d,myrpt->iobase);
+            outb(d,myrpt->p.iobase);
 	    /* >= 10 us */
 	    for(delayvar = 1; delayvar < 10000; delayvar++); 
             }
@@ -3799,6 +4721,7 @@ static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
 
 static int setrem(struct rpt *myrpt)
 {
+	return 0; /* XXX BROKEN!! */
 	if(!strcmp(myrpt->remote, remote_rig_ft897))
 		return set_ft897(myrpt);
 	else if(!strcmp(myrpt->remote, remote_rig_rbi))
@@ -3809,6 +4732,7 @@ static int setrem(struct rpt *myrpt)
 
 static int closerem(struct rpt *myrpt)
 {
+	return 0; /* XXX BROKEN!! */
 	if(!strcmp(myrpt->remote, remote_rig_ft897))
 		return closerem_ft897(myrpt);
 	else
@@ -4030,7 +4954,7 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c
 					return DC_ERROR;
 			}
 	    
-			val = ast_variable_retrieve(cfg, myrpt->memory, digitbuf);
+			val = ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, digitbuf);
 			if (!val){
 				if (ast_safe_sleep(mychannel,1000) == -1)
 					return DC_ERROR;
@@ -4717,7 +5641,7 @@ int	ret,res = 0,src;
 	if (myrpt->dtmfidx == -1)
 	{
 		/* if not lead-in digit, dont worry */
-		if (c != myrpt->funcchar) return 0;
+		if (c != myrpt->p.funcchar) return 0;
 		myrpt->dtmfidx = 0;
 		myrpt->dtmfbuf[0] = 0;
 		myrpt->dtmf_time_rem = now;
@@ -4730,11 +5654,11 @@ int	ret,res = 0,src;
 		myrpt->dtmfbuf[0] = 0;
 		myrpt->dtmf_time_rem = now;
 	}
-	if (c == myrpt->funcchar)
+	if (c == myrpt->p.funcchar)
 	{
 		/* if star at beginning, or 2 together, erase buffer */
 		if ((myrpt->dtmfidx < 1) || 
-			(myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->funcchar))
+			(myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
 		{
 			myrpt->dtmfidx = 0;
 			myrpt->dtmfbuf[0] = 0;
@@ -4771,6 +5695,10 @@ int	ret,res = 0,src;
 				
 				
 		case DC_COMPLETE:
+			myrpt->totalexecdcommands++;
+			myrpt->dailyexecdcommands++;
+			strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
+			myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
 			myrpt->dtmfbuf[0] = 0;
 			myrpt->dtmfidx = -1;
 			myrpt->dtmf_time_rem = 0;
@@ -4819,7 +5747,7 @@ int	seq,res;
 		ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
 	}
 	if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1;
-	res = telem_lookup(myrpt->remchannel, myrpt->name, "functcomplete");
+	res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete");
 	rmt_telem_finish(myrpt,myrpt->remchannel);
 	return res;
 }
@@ -4829,7 +5757,7 @@ static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int
 int	res;
 
 
-	if (keyed && *keyed && (c == myrpt->endchar))
+	if (keyed && *keyed && (c == myrpt->p.endchar))
 	{
 		*keyed = 0;
 		return DC_INDETERMINATE;
@@ -4845,7 +5773,7 @@ int	res;
 		ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
 	}
 	if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1;
-	res = telem_lookup(myrpt->remchannel, myrpt->name, "functcomplete");
+	res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete");
 	rmt_telem_finish(myrpt,myrpt->remchannel);
 	return res;
 }
@@ -4855,7 +5783,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
 	char *val, *s, *s1, *s2, *tele;
 	char tmp[300], deststr[300] = "";
 
-	val = ast_variable_retrieve(cfg, myrpt->nodes, l->name);
+	val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, l->name);
 	if (!val)
 	{
 		fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
@@ -4878,6 +5806,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
 	}
 	*tele++ = 0;
 	l->elaptime = 0;
+	l->connecttime = 0;
 	l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
 	if (l->chan){
 		ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
@@ -4902,7 +5831,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
 		return -1;
 	}
 	rpt_mutex_lock(&myrpt->lock);
-	/* put back in queue queue */
+	/* put back in queue */
 	insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
 	rpt_mutex_unlock(&myrpt->lock);
 	ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
@@ -4916,10 +5845,10 @@ int	res;
 pthread_attr_t	attr;
 char	cmd[MAXDTMF+1] = "";
 
-	if (c == myrpt->endchar)
+	if (c == myrpt->p.endchar)
 	{
 	/* if in simple mode, kill autopatch */
-		if (myrpt->simple && myrpt->callmode)
+		if (myrpt->p.simple && myrpt->callmode)
 		{
 			rpt_mutex_lock(&myrpt->lock);
 			myrpt->callmode = 0;
@@ -4946,9 +5875,9 @@ char	cmd[MAXDTMF+1] = "";
 		send_link_dtmf(myrpt,c);
 		return;
 	}
-	if (!myrpt->simple)
+	if (!myrpt->p.simple)
 	{
-		if (c == myrpt->funcchar)
+		if (c == myrpt->p.funcchar)
 		{
 			myrpt->dtmfidx = 0;
 			myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
@@ -4956,7 +5885,7 @@ char	cmd[MAXDTMF+1] = "";
 			time(&myrpt->dtmf_time);
 			return;
 		} 
-		else if ((c != myrpt->endchar) && (myrpt->dtmfidx >= 0))
+		else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
 		{
 			time(&myrpt->dtmf_time);
 			
@@ -4978,6 +5907,10 @@ char	cmd[MAXDTMF+1] = "";
 					myrpt->dtmfbuf[0] = 0;
 					break;
 				    case DC_COMPLETE:
+					myrpt->totalexecdcommands++;
+					myrpt->dailyexecdcommands++;
+					strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
+					myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
 					myrpt->dtmfbuf[0] = 0;
 					myrpt->dtmfidx = -1;
 					myrpt->dtmf_time = 0;
@@ -4999,9 +5932,14 @@ char	cmd[MAXDTMF+1] = "";
 	}
 	else /* if simple */
 	{
-		if ((!myrpt->callmode) && (c == myrpt->funcchar))
+		if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
 		{
 			myrpt->callmode = 1;
+			myrpt->patchnoct = 0;
+			myrpt->patchquiet = 0;
+			myrpt->patchfarenddisconnect = 0;
+			myrpt->patchdialtime = 0;
+			strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
 			myrpt->cidx = 0;
 			myrpt->exten[myrpt->cidx] = 0;
 			rpt_mutex_unlock(&myrpt->lock);
@@ -5016,15 +5954,16 @@ char	cmd[MAXDTMF+1] = "";
 		myrpt->exten[myrpt->cidx++] = c;
 		myrpt->exten[myrpt->cidx] = 0;
 		/* if this exists */
-		if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
+		if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
 		{
 			myrpt->callmode = 2;
 			rpt_mutex_unlock(&myrpt->lock);
-			rpt_telemetry(myrpt,PROC,NULL); 
+			if(!myrpt->patchquiet)
+				rpt_telemetry(myrpt,PROC,NULL); 
 			return;
 		}
 		/* if can continue, do so */
-		if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
+		if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
 		{
 			/* call has failed, inform user */
 			myrpt->callmode = 4;
@@ -5046,19 +5985,48 @@ char	cmd[MAXDTMF+1] = "";
 static void queue_id(struct rpt *myrpt)
 {
 	myrpt->mustid = myrpt->tailid = 0;
-	myrpt->idtimer = myrpt->idtime; /* Reset our ID timer */
+	myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
 	rpt_mutex_unlock(&myrpt->lock);
 	rpt_telemetry(myrpt,ID,NULL);
 	rpt_mutex_lock(&myrpt->lock);
 }
 
+/* Scheduler */
+
+static void do_scheduler(struct rpt *myrpt)
+{
+	int res;
+	struct tm tmnow;
+
+	memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
+	
+	if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
+		ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
+
+	/* Try to get close to a 1 second resolution */
+	
+	if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
+		return;
+
+	ast_localtime(&myrpt->curtv.tv_sec, &tmnow, NULL);
+
+	/* If midnight, then reset all daily statistics */
+	
+	if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
+		myrpt->dailykeyups = 0;
+		myrpt->dailytxtime = 0;
+		myrpt->dailykerchunks = 0;
+		myrpt->dailyexecdcommands = 0;
+	}
+}
+
 
 /* single thread with one file (request) to dial */
 static void *rpt(void *this)
 {
 struct	rpt *myrpt = (struct rpt *)this;
 char *tele,*idtalkover,c;
-int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,nonidentqueued,tailmessagequeued,ctqueued;
+int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued,tailmessagequeued,ctqueued;
 struct ast_channel *who;
 ZT_CONFINFO ci;  /* conference info */
 time_t	t;
@@ -5066,13 +6034,30 @@ struct rpt_link *l,*m;
 struct rpt_tele *telem;
 char tmpstr[300];
 
+	rpt_mutex_lock(&myrpt->lock);
 
+	telem = myrpt->tele.next;
+	while(telem != &myrpt->tele)
+	{
+		ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
+		telem = telem->next;
+	}
+	rpt_mutex_unlock(&myrpt->lock);
+	/* find our index, and load the vars initially */
+	for(i = 0; i < nrpts; i++)
+	{
+		if (&rpt_vars[i] == myrpt)
+		{
+			load_rpt_vars(i,0);
+			break;
+		}
+	}
 	rpt_mutex_lock(&myrpt->lock);
 	strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
 	tele = strchr(tmpstr,'/');
 	if (!tele)
 	{
-		fprintf(stderr,"rpt:Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
+		fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
 		rpt_mutex_unlock(&myrpt->lock);
 		myrpt->rpt_thread = AST_PTHREADT_STOP;
 		pthread_exit(NULL);
@@ -5119,7 +6104,7 @@ char tmpstr[300];
 		tele = strchr(tmpstr,'/');
 		if (!tele)
 		{
-			fprintf(stderr,"rpt:Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
+			fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
 			rpt_mutex_unlock(&myrpt->lock);
 			ast_hangup(myrpt->rxchannel);
 			myrpt->rpt_thread = AST_PTHREADT_STOP;
@@ -5204,7 +6189,7 @@ char tmpstr[300];
 	/* make a conference for the pseudo */
 	ci.chan = 0;
 	ci.confno = -1; /* make a new conf */
-	ci.confmode = (myrpt->duplex == 2) ? ZT_CONF_CONFANNMON :
+	ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
 		(ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
 	/* first put the channel on the conference in announce mode */
 	if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
@@ -5257,16 +6242,18 @@ char tmpstr[300];
 	myrpt->links.prev = &myrpt->links;
 	myrpt->tailtimer = 0;
 	myrpt->totimer = 0;
-	myrpt->tmsgtimer = myrpt->tailmessagetime;
-	myrpt->idtimer = myrpt->politeid;
+	myrpt->tmsgtimer = myrpt->p.tailmessagetime;
+	myrpt->idtimer = myrpt->p.politeid;
 	myrpt->mustid = myrpt->tailid = 0;
 	myrpt->callmode = 0;
 	myrpt->tounkeyed = 0;
 	myrpt->tonotify = 0;
 	myrpt->retxtimer = 0;
+	myrpt->skedtimer = 0;
+	myrpt->tailevent = 0;
 	lasttx = 0;
 	myrpt->keyed = 0;
-	idtalkover = ast_variable_retrieve(cfg, myrpt->name, "idtalkover");
+	idtalkover = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
 	myrpt->dtmfidx = -1;
 	myrpt->dtmfbuf[0] = 0;
 	myrpt->rem_dtmfidx = -1;
@@ -5275,9 +6262,21 @@ char tmpstr[300];
 	myrpt->rem_dtmf_time = 0;
 	myrpt->enable = 1;
 	myrpt->disgorgetime = 0;
-	if (myrpt->startupmacro)
+	myrpt->lastnodewhichkeyedusup[0] = '\0';
+	myrpt->dailytxtime = 0;
+	myrpt->totaltxtime = 0;
+	myrpt->dailykeyups = 0;
+	myrpt->totalkeyups = 0;
+	myrpt->dailykerchunks = 0;
+	myrpt->totalkerchunks = 0;
+	myrpt->dailyexecdcommands = 0;
+	myrpt->totalexecdcommands = 0;
+	myrpt->timeouts = 0;
+	myrpt->exten[0] = '\0';
+	myrpt->lastdtmfcommand[0] = '\0';
+	if (myrpt->p.startupmacro)
 	{
-		snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->startupmacro);
+		snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
 	}
 	rpt_mutex_unlock(&myrpt->lock);
 	val = 0;
@@ -5313,8 +6312,7 @@ char tmpstr[300];
 			ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
 			ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
 			ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
-			ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
-			ast_log(LOG_NOTICE,"myrpt->tailid = %d\n",myrpt->tailid);
+			ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
 
 			zl = myrpt->links.next;
               		while(zl != &myrpt->links){
@@ -5329,7 +6327,7 @@ char tmpstr[300];
 				ast_log(LOG_NOTICE,"        link->disctime %ld\n",zl->disctime);
 				ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",zl->retrytimer);
 				ast_log(LOG_NOTICE,"        link->retries = %d\n",zl->retries);
-
+				ast_log(LOG_NOTICE,"        link->reconnects = %d\n",zl->reconnects);
                         	zl = zl->next;
                 	}
                                                                                                                                
@@ -5345,98 +6343,122 @@ char tmpstr[300];
 		}	
 
 
+		if (myrpt->reload)
+		{
+			struct rpt_tele *telem;
+
+			rpt_mutex_lock(&myrpt->lock);
+			telem = myrpt->tele.next;
+			while(telem != &myrpt->tele)
+			{
+				ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
+				telem = telem->next;
+			}
+			myrpt->reload = 0;
+			rpt_mutex_unlock(&myrpt->lock);
+			usleep(10000);
+			/* find our index, and load the vars */
+			for(i = 0; i < nrpts; i++)
+			{
+				if (&rpt_vars[i] == myrpt)
+				{
+					load_rpt_vars(i,0);
+					break;
+				}
+			}
+		}
+
 		rpt_mutex_lock(&myrpt->lock);
 		if (ast_check_hangup(myrpt->rxchannel)) break;
 		if (ast_check_hangup(myrpt->txchannel)) break;
 		if (ast_check_hangup(myrpt->pchannel)) break;
 		if (ast_check_hangup(myrpt->txpchannel)) break;
+
+		/* Update local tx with keyed if not parsing a command */
 		myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]);
-		
 		/* If someone's connected, and they're transmitting from their end to us, set remrx true */
-		
 		l = myrpt->links.next;
 		remrx = 0;
 		while(l != &myrpt->links)
 		{
-			if (l->lastrx) remrx = 1;
+			if (l->lastrx){
+				remrx = 1;
+				if(l->name[0] != '0') /* Ignore '0' nodes */
+					strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
+			}
 			l = l->next;
 		}
-		
-		/* Create a "must_id" flag for the cleanup ID */	
-			
+		/* Create a "must_id" flag for the cleanup ID */		
 		myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
-
 		/* Build a fresh totx from myrpt->keyed and autopatch activated */
-		
 		totx = myrpt->callmode;
-		if (myrpt->duplex > 1) totx = totx || myrpt->localtx;
-		 
-		/* Traverse the telemetry list to see if there's an ID queued and if there is not an ID queued */
-		
+		/* If full duplex, add local tx to totx */
+		if (myrpt->p.duplex > 1) totx = totx || myrpt->localtx;
+		/* Traverse the telemetry list to see what's queued */
 		identqueued = 0;
-		nonidentqueued = 0;
+		othertelemqueued = 0;
 		tailmessagequeued = 0;
 		ctqueued = 0;
 		telem = myrpt->tele.next;
 		while(telem != &myrpt->tele)
 		{
 			if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
-				identqueued = 1;
+				identqueued = 1; /* Identification telemetry */
 			}
 			else if(telem->mode == TAILMSG)
 			{
-				tailmessagequeued = 1;
+				tailmessagequeued = 1; /* Tail message telemetry */
 			}
 			else
 			{
 				if (telem->mode != UNKEY)
-					nonidentqueued = 1;
+					othertelemqueued = 1;  /* Other telemetry */
 				else
-					ctqueued = 1;
+					ctqueued = 1; /* Courtesy tone telemetry */
 			}
 			telem = telem->next;
 		}
 	
-		/* Add in any non-id telemetry */
-		
-		if (myrpt->duplex > 0) totx = totx || nonidentqueued;
-		
-		/* Update external transmitter PTT state with everything but ID telemetry */
-		
+		/* Add in any "other" telemetry, if 3/4 or full duplex */
+		if (myrpt->p.duplex > 0) totx = totx || othertelemqueued;
+		/* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
 		myrpt->exttx = totx;
-		if (myrpt->duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
-		
+		/* If half or 3/4 duplex, add localtx to external link tx */
+		if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
 		/* Add in ID telemetry to local transmitter */
 		totx = totx || remrx;
-		if (myrpt->duplex > 0)
+		/* If 3/4 or full duplex, add in ident and CT telemetry */
+		if (myrpt->p.duplex > 0)
 			totx = totx || identqueued || ctqueued;
+		/* Reset time out timer variables if there is no activity */
 		if (!totx) 
 		{
-			myrpt->totimer = myrpt->totime;
+			myrpt->totimer = myrpt->p.totime;
 			myrpt->tounkeyed = 0;
 			myrpt->tonotify = 0;
 		}
 		else
-			myrpt->tailtimer = myrpt->hangtime; /* Initialize tail timer */
-
+			myrpt->tailtimer = myrpt->p.hangtime; /* Initialize tail timer */
+		/* Disable the local transmitter if we are timed out */
 		totx = totx && myrpt->totimer;
 		/* if timed-out and not said already, say it */
 		if ((!myrpt->totimer) && (!myrpt->tonotify))
 		{
 			myrpt->tonotify = 1;
+			myrpt->timeouts++;
 			rpt_mutex_unlock(&myrpt->lock);
 			rpt_telemetry(myrpt,TIMEOUT,NULL);
 			rpt_mutex_lock(&myrpt->lock);
 		}
-		/* if wants to transmit and in phone call, but timed out, 
-			reset time-out timer if keyed */
+
+		/* If unkey and re-key, reset time out timer */
 		if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
 		{
 			myrpt->tounkeyed = 1;
 		}
 		if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
 		{
-			myrpt->totimer = myrpt->totime;
+			myrpt->totimer = myrpt->p.totime;
 			myrpt->tounkeyed = 0;
 			myrpt->tonotify = 0;
 			rpt_mutex_unlock(&myrpt->lock);
@@ -5477,35 +6499,42 @@ char tmpstr[300];
 		/* If within 30 seconds of the time to ID, try do it in the tail */
 		/* else if at ID time limit, do it right over the top of them */
 		/* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
-
-/*		if (((totx && (!myrpt->exttx) && (myrpt->idtimer <= myrpt->politeid) && myrpt->tailtimer)) ||
-		   (myrpt->mustid && (!myrpt->idtimer)))
-		{
-			myrpt->mustid = 0;
-			myrpt->idtimer = myrpt->idtime; 
-			rpt_mutex_unlock(&myrpt->lock);
-			rpt_telemetry(myrpt,ID,NULL);
-			rpt_mutex_lock(&myrpt->lock);
-		}
-*/
-
 		if(myrpt->mustid && (!myrpt->idtimer))
 			queue_id(myrpt);
 
 		if ((totx && (!myrpt->exttx) &&
-			 (myrpt->idtimer <= myrpt->politeid) && myrpt->tailtimer)) 
+			 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) 
 			{
 				myrpt->tailid = 1;
 			}
 
+		/* If tail timer expires, then check for tail messages */
 
+		if(myrpt->tailevent){
+			myrpt->tailevent = 0;
+			if(myrpt->tailid){
+				totx = 1;
+				queue_id(myrpt);
+			}
+			else if ((myrpt->p.tailmessages[0]) &&
+				(myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
+					totx = 1;
+					myrpt->tmsgtimer = myrpt->p.tailmessagetime;	
+					rpt_mutex_unlock(&myrpt->lock);
+					rpt_telemetry(myrpt, TAILMSG, NULL);
+					rpt_mutex_lock(&myrpt->lock);
+			}	
+		}
 
+		/* Main TX control */
 
 		/* let telemetry transmit anyway (regardless of timeout) */
-		if (myrpt->duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
+		if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
 		if (totx && (!lasttx))
 		{
 			lasttx = 1;
+			myrpt->dailykeyups++;
+			myrpt->totalkeyups++;
 			rpt_mutex_unlock(&myrpt->lock);
 			ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
 			rpt_mutex_lock(&myrpt->lock);
@@ -5531,8 +6560,9 @@ char tmpstr[300];
 			myrpt->rem_dtmfidx = -1;
 			myrpt->rem_dtmfbuf[0] = 0;
 		}	
-		
-		/* Reconnect kludge */
+
+		/* Reconnect */
+	
 		l = myrpt->links.next;
 		while(l != &myrpt->links)
 		{
@@ -5586,7 +6616,6 @@ char tmpstr[300];
 					if (l->chan) ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
 				}
 			} else l->retxtimer = 0;
-#ifdef	RECONNECT_KLUDGE
 			if (l->disctime) /* Disconnect timer active on a channel ? */
 			{
 				l->disctime -= elap;
@@ -5599,7 +6628,10 @@ char tmpstr[300];
 				l->retrytimer -= elap;
 				if (l->retrytimer < 0) l->retrytimer = 0;
 			}
-#endif
+
+			/* Tally connect time */
+			l->connecttime += elap;
+
 			/* ignore non-timing channels */
 			if (l->elaptime < 0)
 			{
@@ -5614,13 +6646,9 @@ char tmpstr[300];
 				l->elaptime = 0;
 				rpt_mutex_unlock(&myrpt->lock);
 				if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
-#ifndef	RECONNECT_KLUDGE
-				rpt_telemetry(myrpt,CONNFAIL,l);
-#endif
 				rpt_mutex_lock(&myrpt->lock);
 				break;
 			}
-#ifdef	RECONNECT_KLUDGE
 			if ((!l->chan) && (!l->retrytimer) && l->outbound && 
 				(l->retries++ < MAX_RETRIES) && (l->hasconnected))
 			{
@@ -5677,26 +6705,17 @@ char tmpstr[300];
                                 rpt_mutex_lock(&myrpt->lock);
                                 break;
                         }
-#endif
 			l = l->next;
 		}
+		if(totx){
+			myrpt->dailytxtime += elap;
+			myrpt->totaltxtime += elap;
+		}
 		i = myrpt->tailtimer;
 		if (myrpt->tailtimer) myrpt->tailtimer -= elap;
 		if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
-
-		if((i) && (myrpt->tailtimer == 0)){
-			if(myrpt->tailid){
-				queue_id(myrpt);
-			}
-			else if ((myrpt->tailmessages[0]) &&
-				(myrpt->tailmessagetime) && (myrpt->tmsgtimer == 0)){
-					myrpt->tmsgtimer = myrpt->tailmessagetime;	
-					rpt_mutex_unlock(&myrpt->lock);
-					rpt_telemetry(myrpt, TAILMSG, NULL);
-					rpt_mutex_lock(&myrpt->lock);
-			}	
-		}
-		if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
+		if((i) && (myrpt->tailtimer == 0))
+			myrpt->tailevent = 1;
 		if (myrpt->totimer) myrpt->totimer -= elap;
 		if (myrpt->totimer < 0) myrpt->totimer = 0;
 		if (myrpt->idtimer) myrpt->idtimer -= elap;
@@ -5706,6 +6725,13 @@ char tmpstr[300];
 		/* do macro timers */
 		if (myrpt->macrotimer) myrpt->macrotimer -= elap;
 		if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
+		/* Execute scheduler appx. every 2 tenths of a second */
+		if (myrpt->skedtimer <= 0){
+			myrpt->skedtimer = 200;
+			do_scheduler(myrpt);
+		}
+		else
+			myrpt->skedtimer -=elap;
 		if (!ms) 
 		{
 			rpt_mutex_unlock(&myrpt->lock);
@@ -5731,8 +6757,59 @@ char tmpstr[300];
 			}
 			if (f->frametype == AST_FRAME_VOICE)
 			{
-				if (!myrpt->localtx)
+#ifdef	_MDC_DECODE_H_
+				unsigned char ubuf[2560];
+				short *sp;
+				int n;
+#endif
+
+				if (!myrpt->localtx) {
 					memset(f->data,0,f->datalen);
+				}
+
+#ifdef	_MDC_DECODE_H_
+				sp = (short *) f->data;
+				/* convert block to unsigned char */
+				for(n = 0; n < f->datalen / 2; n++)
+				{
+					ubuf[n] = (*sp++ >> 8) + 128;
+				}
+				n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
+				if (n == 1)
+				{
+						unsigned char op,arg;
+						unsigned short unitID;
+
+						mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
+						if (debug > 2)
+						{
+							ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
+							ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
+								op & 255,arg & 255,unitID);
+						}
+						if ((op == 1) && (arg == 0))
+						{
+							myrpt->lastunit = unitID;
+						}
+				}
+				if ((debug > 2) && (i == 2))
+				{
+					unsigned char op,arg,ex1,ex2,ex3,ex4;
+					unsigned short unitID;
+
+					mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
+						&ex1,&ex2,&ex3,&ex4);
+					ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
+					ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
+						op & 255,arg & 255,unitID);
+					ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
+						ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
+				}
+#endif
+#ifdef	__RPT_NOTCH
+				/* apply inbound filters, if any */
+				rpt_filter(myrpt,f->data,f->datalen / 2);
+#endif
 				ast_write(myrpt->pchannel,f);
 			}
 			else if (f->frametype == AST_FRAME_DTMF)
@@ -5853,7 +6930,6 @@ char tmpstr[300];
 				f = ast_read(l->chan);
 				if (!f)
 				{
-#ifdef	RECONNECT_KLUDGE
 					if ((!l->disced) && (!l->outbound))
 					{
 						if ((l->name[0] == '0') || l->isremote)
@@ -5884,7 +6960,6 @@ char tmpstr[300];
 						rpt_mutex_lock(&myrpt->lock);
 						break;
 					}
-#endif
 					rpt_mutex_lock(&myrpt->lock);
 					/* remove from queue */
 					remque((struct qelem *) l);
@@ -5926,7 +7001,10 @@ char tmpstr[300];
 						l->hasconnected = 1;
 						l->elaptime = -1;
 						l->retries = 0;
-						if (!lconnected) rpt_telemetry(myrpt,CONNECTED,l);
+						if (!lconnected) 
+							rpt_telemetry(myrpt,CONNECTED,l);
+						else
+							l->reconnects++;
 					}
 					/* if RX key */
 					if (f->subclass == AST_CONTROL_RADIO_KEY)
@@ -5943,7 +7021,6 @@ char tmpstr[300];
 					if (f->subclass == AST_CONTROL_HANGUP)
 					{
 						ast_frfree(f);
-#ifdef	RECONNECT_KLUDGE
 						if ((!l->outbound) && (!l->disced))
 						{
 							if ((l->name[0] == '0') || l->isremote)
@@ -5973,7 +7050,6 @@ char tmpstr[300];
 							rpt_mutex_lock(&myrpt->lock);
 							break;
 						}
-#endif
 						rpt_mutex_lock(&myrpt->lock);
 						/* remove from queue */
 						remque((struct qelem *) l);
@@ -6075,187 +7151,56 @@ char tmpstr[300];
 	return NULL;
 }
 
-
+	
 static void *rpt_master(void *ignore)
 {
-char *this,*val;
-struct ast_variable *vp;
-int	i,j,n,longestnode;
+int	i,n;
 pthread_attr_t attr;
+struct ast_config *cfg;
+char *this,*val;
 
-	/* start with blank config */
-	memset(&rpt_vars,0,sizeof(rpt_vars));
-
-	cfg = ast_config_load("rpt.conf");
+	/* go thru all the specified repeaters */
+	this = NULL;
+	n = 0;
+	rpt_vars[n].cfg = ast_config_load("rpt.conf");
+	cfg = rpt_vars[n].cfg;
 	if (!cfg) {
 		ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
 		pthread_exit(NULL);
 	}
-
-	/* go thru all the specified repeaters */
-	this = NULL;
-	n = 0;
 	while((this = ast_category_browse(cfg,this)) != NULL)
 	{
-	
 		for(i = 0 ; i < strlen(this) ; i++){
 			if((this[i] < '0') || (this[i] > '9'))
 				break;
 		}
-		if(i != strlen(this))
-			continue; /* Not a node defn */
-			
-		ast_log(LOG_DEBUG,"Loading config for repeater %s\n",this);
+		if(i != strlen(this)) continue; /* Not a node defn */
+		memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
+		rpt_vars[n].name = strdup(this);
+		val = ast_variable_retrieve(cfg,this,"rxchannel");
+		if (val) rpt_vars[n].rxchanname = strdup(val);
+		val = ast_variable_retrieve(cfg,this,"txchannel");
+		if (val) rpt_vars[n].txchanname = strdup(val);
+		val = ast_variable_retrieve(cfg,this,"remote");
+		if (val) rpt_vars[n].remote = strdup(val);
 		ast_mutex_init(&rpt_vars[n].lock);
 		rpt_vars[n].tele.next = &rpt_vars[n].tele;
 		rpt_vars[n].tele.prev = &rpt_vars[n].tele;
 		rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
-		rpt_vars[n].name = this;
-		rpt_vars[n].rxchanname = ast_variable_retrieve(cfg,this,"rxchannel");
-		rpt_vars[n].txchanname = ast_variable_retrieve(cfg,this,"txchannel");
-		rpt_vars[n].ourcontext = ast_variable_retrieve(cfg,this,"context");
-		if (!rpt_vars[n].ourcontext) rpt_vars[n].ourcontext = this;
-		rpt_vars[n].ourcallerid = ast_variable_retrieve(cfg,this,"callerid");
-		rpt_vars[n].acctcode = ast_variable_retrieve(cfg,this,"accountcode");
-		rpt_vars[n].ident = ast_variable_retrieve(cfg,this,"idrecording");
-		val = ast_variable_retrieve(cfg,this,"hangtime");
-		if (val) rpt_vars[n].hangtime = atoi(val);
-			else rpt_vars[n].hangtime = HANGTIME;
-		val = ast_variable_retrieve(cfg,this,"totime");
-		if (val) rpt_vars[n].totime = atoi(val);
-			else rpt_vars[n].totime = TOTIME;
-
-		rpt_vars[n].tailmessagetime = retrieve_astcfgint(this, "tailmessagetime", 0, 2400000, 0);		
-		rpt_vars[n].tailsquashedtime = retrieve_astcfgint(this, "tailsquashedtime", 0, 2400000, 0);		
-		rpt_vars[n].duplex = retrieve_astcfgint(this,"duplex",0,3,2);
-		rpt_vars[n].idtime = retrieve_astcfgint( this, "idtime", 60000, 2400000, IDTIME);	/* Enforce a min max */
-		rpt_vars[n].politeid = retrieve_astcfgint( this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
-		rpt_vars[n].remote = ast_variable_retrieve(cfg,this,"remote");
-		rpt_vars[n].tonezone = ast_variable_retrieve(cfg,this,"tonezone");
-		rpt_vars[n].tailmessages[0] = 0;
-		rpt_vars[n].tailmessagemax = 0;
 		rpt_vars[n].tailmessagen = 0;
-		val = ast_variable_retrieve(cfg,this,"tailmessagelist");
-		if (val) rpt_vars[n].tailmessagemax = finddelim(val,rpt_vars[n].tailmessages);
-		val = ast_variable_retrieve(cfg,this,"memory");
-		if (!val) val = MEMORY;
-		rpt_vars[n].memory = val;
-		val = ast_variable_retrieve(cfg,this,"macro");
-		if (!val) val = MACRO;
-		rpt_vars[n].macro = val;
-		rpt_vars[n].startupmacro = ast_variable_retrieve(cfg,this,"startup_macro");
-		val = ast_variable_retrieve(cfg,this,"iobase");
-		/* do not use atoi() here, we need to be able to have
-			the input specified in hex or decimal so we use
-			sscanf with a %i */
-		if ((!val) || (sscanf(val,"%i",&rpt_vars[n].iobase) != 1))
-			rpt_vars[n].iobase = DEFAULT_IOBASE;
-		rpt_vars[n].simple = 0;
-		rpt_vars[n].functions = ast_variable_retrieve(cfg,this,"functions");
-		if (!rpt_vars[n].functions) 
-		{
-			rpt_vars[n].functions = FUNCTIONS;
-			rpt_vars[n].simple = 1;
-		}
-		rpt_vars[n].link_functions = ast_variable_retrieve(cfg,this,"link_functions");
-		if (!rpt_vars[n].link_functions) 
-			rpt_vars[n].link_functions = rpt_vars[n].functions;
-		rpt_vars[n].phone_functions = ast_variable_retrieve(cfg,this,"phone_functions");
-		rpt_vars[n].dphone_functions = ast_variable_retrieve(cfg,this,"dphone_functions");
-		val = ast_variable_retrieve(cfg,this,"funcchar");
-		if (!val) rpt_vars[n].funcchar = FUNCCHAR; else 
-			rpt_vars[n].funcchar = *val;		
-		val = ast_variable_retrieve(cfg,this,"endchar");
-		if (!val) rpt_vars[n].endchar = ENDCHAR; else 
-			rpt_vars[n].endchar = *val;		
-		val = ast_variable_retrieve(cfg,this,"nobusyout");
-		if (val) rpt_vars[n].nobusyout = ast_true(val);
-		rpt_vars[n].nodes = ast_variable_retrieve(cfg,this,"nodes");
-		if (!rpt_vars[n].nodes) 
-			rpt_vars[n].nodes = NODES;
+#ifdef	_MDC_DECODE_H_
+		rpt_vars[n].mdc = mdc_decoder_new(8000);
+#endif
 		n++;
 	}
 	nrpts = n;
-	ast_log(LOG_DEBUG, "Total of %d repeaters configured.\n",n);
+	ast_config_destroy(cfg);
+
 	/* start em all */
 	for(i = 0; i < n; i++)
 	{
+		load_rpt_vars(i,1);
 
-		/*
-		* Go through the node list to determine the longest node
-		*/
-		longestnode = 0;
-
-		vp = ast_variable_browse(cfg, rpt_vars[i].nodes);
-		
-		while(vp){
-			j = strlen(vp->name);
-			if (j > longestnode)
-				longestnode = j;
-			vp = vp->next;
-		}
-
-
-		rpt_vars[i].longestnode = longestnode;
-		
-		/*
-		* For this repeater, Determine the length of the longest function 
-		*/
-		rpt_vars[i].longestfunc = 0;
-		vp = ast_variable_browse(cfg, rpt_vars[i].functions);
-		while(vp){
-			j = strlen(vp->name);
-			if (j > rpt_vars[i].longestfunc)
-				rpt_vars[i].longestfunc = j;
-			vp = vp->next;
-		}
-		/*
-		* For this repeater, Determine the length of the longest function 
-		*/
-		rpt_vars[i].link_longestfunc = 0;
-		vp = ast_variable_browse(cfg, rpt_vars[i].link_functions);
-		while(vp){
-			j = strlen(vp->name);
-			if (j > rpt_vars[i].link_longestfunc)
-				rpt_vars[i].link_longestfunc = j;
-			vp = vp->next;
-		}
-		rpt_vars[i].phone_longestfunc = 0;
-		if (rpt_vars[i].phone_functions)
-		{
-			vp = ast_variable_browse(cfg, rpt_vars[i].phone_functions);
-			while(vp){
-				j = strlen(vp->name);
-				if (j > rpt_vars[i].phone_longestfunc)
-					rpt_vars[i].phone_longestfunc = j;
-				vp = vp->next;
-			}
-		}
-		rpt_vars[i].dphone_longestfunc = 0;
-		if (rpt_vars[i].dphone_functions)
-		{
-			vp = ast_variable_browse(cfg, rpt_vars[i].dphone_functions);
-			while(vp){
-				j = strlen(vp->name);
-				if (j > rpt_vars[i].dphone_longestfunc)
-					rpt_vars[i].dphone_longestfunc = j;
-				vp = vp->next;
-			}
-		}
-		rpt_vars[i].macro_longest = 1;
-		vp = ast_variable_browse(cfg, rpt_vars[i].macro);
-		while(vp){
-			j = strlen(vp->name);
-			if (j > rpt_vars[i].macro_longest)
-				rpt_vars[i].macro_longest = j;
-			vp = vp->next;
-		}
-		if (!rpt_vars[i].rxchanname)
-		{
-			ast_log(LOG_WARNING,"Did not specify rxchanname for node %s\n",rpt_vars[i].name);
-			ast_config_destroy(cfg);
-			pthread_exit(NULL);
-		}
 		/* if is a remote, dont start one for it */
 		if (rpt_vars[i].remote)
 		{
@@ -6268,7 +7213,7 @@ pthread_attr_t attr;
 			rpt_vars[i].powerlevel = REM_MEDPWR;
 			continue;
 		}
-		if (!rpt_vars[i].ident)
+		if (!rpt_vars[i].p.ident)
 		{
 			ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
 			ast_config_destroy(cfg);
@@ -6392,7 +7337,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 		m = myrpt->callmode;
 		rpt_mutex_unlock(&myrpt->lock);
 
-		if ((!myrpt->nobusyout) && m)
+		if ((!myrpt->p.nobusyout) && m)
 		{
 			if (chan->_state != AST_STATE_UP)
 			{
@@ -6457,9 +7402,13 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 		}
 		/* At this point we have a priority and maybe an extension and a context */
 		chan->priority = atoi(priority);
-		if (exten)
+#ifdef OLD_ASTERISK
+		if(exten && strcasecmp(exten, "BYEXTENSION"))
+#else
+		if(exten)
+#endif
 			strncpy(chan->exten, exten, sizeof(chan->exten)-1);
-		if (context)
+		if(context)
 			strncpy(chan->context, context, sizeof(chan->context)-1);
 		} else {  /* increment the priority by default*/
 			chan->priority++;
@@ -6528,7 +7477,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 
 
 		/* look for his reported node string */
-		val = ast_variable_retrieve(cfg, myrpt->nodes, b1);
+		val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, b1);
 		if (!val)
 		{
 			ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
@@ -6580,6 +7529,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 	{
 
 		char *b,*b1;
+		int reconnects = 0;
 
 		/* look at callerid to see what node this comes from */
 		if (!chan->cid.cid_num) /* if doesn't have caller id */
@@ -6615,6 +7565,8 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 			l->killme = 1;
 			l->retries = MAX_RETRIES + 1;
 			l->disced = 2;
+			reconnects = l->reconnects;
+			reconnects++;
                         rpt_mutex_unlock(&myrpt->lock);
 			usleep(500000);	
 		} else 
@@ -6634,6 +7586,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 		l->chan = chan;
 		l->connected = 1;
 		l->hasconnected = 1;
+		l->reconnects = reconnects;
 		l->phonemode = phone_mode;
 		ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
 		ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
@@ -6680,13 +7633,24 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 		rpt_mutex_lock(&myrpt->lock);
 	}
 	myrpt->remoteon = 1;
-	if (ioperm(myrpt->iobase,1,1) == -1)
+	if (ioperm(myrpt->p.iobase,1,1) == -1)
 	{
 		rpt_mutex_unlock(&myrpt->lock);
-		ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->iobase);
+		ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
 		return -1;
 	}
 	LOCAL_USER_ADD(u);
+	rpt_mutex_unlock(&myrpt->lock);
+	/* find our index, and load the vars initially */
+	for(i = 0; i < nrpts; i++)
+	{
+		if (&rpt_vars[i] == myrpt)
+		{
+			load_rpt_vars(i,0);
+			break;
+		}
+	}
+	rpt_mutex_lock(&myrpt->lock);
 	tele = strchr(myrpt->rxchanname,'/');
 	if (!tele)
 	{
@@ -6765,11 +7729,12 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 	myrpt->dtmf_time_rem = 0;
 	myrpt->hfscanmode = 0;
 	myrpt->hfscanstatus = 0;
-	if (myrpt->startupmacro)
+	if (myrpt->p.startupmacro)
 	{
 		myrpt->remchannel = chan; /* Save copy of channel */
-		snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->startupmacro);
+		snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
 	}
+	myrpt->reload = 0;
 	rpt_mutex_unlock(&myrpt->lock);
 	setrem(myrpt); 
 	ast_set_write_format(chan, AST_FORMAT_SLINEAR);
@@ -6801,6 +7766,21 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 	{
 		if (ast_check_hangup(chan)) break;
 		if (ast_check_hangup(myrpt->rxchannel)) break;
+		if (myrpt->reload)
+		{
+			myrpt->reload = 0;
+			rpt_mutex_unlock(&myrpt->lock);
+			/* find our index, and load the vars */
+			for(i = 0; i < nrpts; i++)
+			{
+				if (&rpt_vars[i] == myrpt)
+				{
+					load_rpt_vars(i,0);
+					break;
+				}
+			}
+			rpt_mutex_lock(&myrpt->lock);
+		}
 		ms = MSWAIT;
 		who = ast_waitfor_n(cs,n,&ms);
 		if (who == NULL) ms = 0;
@@ -7028,13 +8008,17 @@ static int rpt_exec(struct ast_channel *chan, void *data)
 	return res;
 }
 
-static int unload_module(void *mod)
+#ifdef	OLD_ASTERISK
+int unload_module()
+#else
+static int unload_module(void* mod)
+#endif
 {
 	int i;
 
 	STANDARD_HANGUP_LOCALUSERS;
 	for(i = 0; i < nrpts; i++) {
-		if (!strcmp(rpt_vars[i].name,rpt_vars[i].nodes)) continue;
+		if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
                 ast_mutex_destroy(&rpt_vars[i].lock);
 	}
 	i = ast_unregister_application(app);
@@ -7042,30 +8026,72 @@ static int unload_module(void *mod)
 	/* Unregister cli extensions */
 	ast_cli_unregister(&cli_debug);
 	ast_cli_unregister(&cli_dump);
+	ast_cli_unregister(&cli_stats);
+	ast_cli_unregister(&cli_lstats);
+	ast_cli_unregister(&cli_reload);
+	ast_cli_unregister(&cli_restart);
 
 	return i;
 }
 
+#ifdef	OLD_ASTERISK
+int load_module()
+#else
 static int load_module(void *mod)
+#endif
 {
 	ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
 
 	/* Register cli extensions */
 	ast_cli_register(&cli_debug);
 	ast_cli_register(&cli_dump);
+	ast_cli_register(&cli_stats);
+	ast_cli_register(&cli_lstats);
+	ast_cli_register(&cli_reload);
+	ast_cli_register(&cli_restart);
 
 	return ast_register_application(app, rpt_exec, synopsis, descrip);
 }
 
+#ifdef	OLD_ASTERISK
+char *description()
+#else
 static const char *description(void)
+#endif
 {
 	return tdesc;
 }
 
+#ifdef OLD_ASTERISK
+int usecount(void)
+{
+	int res;
+	STANDARD_USECOUNT(res);
+	return res;
+}
+#endif
+
+#ifdef	OLD_ASTERISK
+char *key()
+#else
 static const char *key(void)
+#endif
 {
 	return ASTERISK_GPL_KEY;
 }
 
-STD_MOD1;
+#ifdef	OLD_ASTERISK
+int reload()
+#else
+static int reload(void *mod)
+#endif
+{
+int	n;
+
+	for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
+	return(0);
+}
 
+#ifndef	OLD_ASTERISK
+STD_MOD(MOD_1, reload, NULL, NULL);
+#endif