[asterisk-commits] jdixon: branch 1.4 r77846 - /branches/1.4/apps/app_rpt.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jul 31 16:09:40 CDT 2007


Author: jdixon
Date: Tue Jul 31 16:09:39 2007
New Revision: 77846

URL: http://svn.digium.com/view/asterisk?view=rev&rev=77846
Log:
Much newer version, 0.70 with much additions

Modified:
    branches/1.4/apps/app_rpt.c

Modified: branches/1.4/apps/app_rpt.c
URL: http://svn.digium.com/view/asterisk/branches/1.4/apps/app_rpt.c?view=diff&rev=77846&r1=77845&r2=77846
==============================================================================
--- branches/1.4/apps/app_rpt.c (original)
+++ branches/1.4/apps/app_rpt.c Tue Jul 31 16:09:39 2007
@@ -1,7 +1,9 @@
+/* #define OLD_ASTERISK */
+#define	OLDKEY
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2002-2005, Jim Dixon, WB6NIL
+ * Copyright (C) 2002-2007, Jim Dixon, WB6NIL
  *
  * Jim Dixon, WB6NIL <jim at lambdatel.com>
  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar at rodgers.sdcoxmail.com>
@@ -20,7 +22,7 @@
 /*! \file
  *
  * \brief Radio Repeater / Remote Base program 
- *  version 0.48 06/13/06
+ *  version 0.70 07/22/07
  * 
  * \author Jim Dixon, WB6NIL <jim at lambdatel.com>
  *
@@ -60,9 +62,23 @@
  *  1 - System warm boot
  *  2 - System enable
  *  3 - System disable
- *  4 - Test Tone On
+ *  4 - Test Tone On/Off
  *  5 - Dump System Variables on Console (debug)
  *  6 - PTT (phone mode only)
+ *  7 - Time out timer enable
+ *  8 - Time out timer disable
+ *  9 - Autopatch enable
+ *  10 - Autopatch disable
+ *  11 - Link enable
+ *  12 - Link disable
+ *  13 - Query System State
+ *  14 - Change System State
+ *  15 - Scheduler Enable
+ *  16 - Scheduler Disable
+ *  17 - User functions (time, id, etc) enable
+ *  18 - User functions (time, id, etc) disable
+ *  19 - Select alternate hang timer
+ *  20 - Select standard hang timer 
  *
  * ilink cmds:
  *
@@ -72,6 +88,12 @@
  *  4 - Enter command mode on specified link
  *  5 - System status
  *  6 - Disconnect all links
+ *  11 - Disconnect a previously permanently connected link
+ *  12 - Permanently connect specified link -- monitor only
+ *  13 - Permanently connect specified link -- tranceive
+ *  15 - Full system status (all nodes)
+ *  16 - Reconnect links disconnected with "disconnect all links"
+ *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
  *
  * remote cmds:
  *
@@ -102,7 +124,7 @@
  *  118 - Scan Up Fast
  *  119 - Transmit allowing auto-tune
  *  140 - Link Status (brief)
- *
+ *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
  *
  *
  * 'duplex' modes:  (defaults to duplex=2)
@@ -133,9 +155,17 @@
 
 #define	MAXDTMF 32
 #define	MAXMACRO 2048
+#define	MAXLINKLIST 512
+#define	LINKLISTTIME 10000
+#define	LINKLISTSHORTTIME 200
 #define	MACROTIME 100
 #define	MACROPTIME 500
 #define	DTMF_TIMEOUT 3
+#define	KENWOOD_RETRIES 5
+
+#define	AUTHTELLTIME 7000
+#define	AUTHTXTIME 1000
+#define	AUTHLOGOUTTIME 25000
 
 #ifdef	__RPT_NOTCH
 #define	MAXFILTERS 10
@@ -143,10 +173,13 @@
 
 #define	DISC_TIME 10000  /* report disc after 10 seconds of no connect */
 #define	MAX_RETRIES 5
+#define	MAX_RETRIES_PERM 1000000000
 
 #define	REDUNDANT_TX_TIME 2000
 
 #define	RETRY_TIMER_MS 5000
+
+#define	START_DELAY 10
 
 #define MAXPEERSTR 31
 #define	MAXREMSTR 15
@@ -154,7 +187,16 @@
 #define	DELIMCHR ','
 #define	QUOTECHR 34
 
+#define	MONITOR_DISK_BLOCKS_PER_MINUTE 38
+
+#define	DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
+#define	DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
+#define	DEFAULT_REMOTE_TIMEOUT (60 * 60)
+#define	DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
+#define	DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
+
 #define	NODES "nodes"
+#define	EXTNODES "extnodes"
 #define MEMORY "memory"
 #define MACRO "macro"
 #define	FUNCTIONS "functions"
@@ -162,9 +204,12 @@
 #define MORSE "morse"
 #define	FUNCCHAR '*'
 #define	ENDCHAR '#'
+#define	EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
 
 #define	DEFAULT_IOBASE 0x378
 
+#define	DEFAULT_CIV_ADDR 0x58
+
 #define	MAXCONNECTTIME 5000
 
 #define MAXNODESTR 300
@@ -177,23 +222,31 @@
 
 #define REM_SCANTIME 100
 
+#define	DTMF_LOCAL_TIME 250
+#define	DTMF_LOCAL_STARTTIME 500
+
+#define	IC706_PL_MEMORY_OFFSET 50
 
 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, LASTNODEKEY};
+	TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
+	MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
+	REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE,
+	TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX};
+
 
 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
 
 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
 
-enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY};
+enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
 
 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
 
-enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
+enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY};
 
 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
 
@@ -220,9 +273,15 @@
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/io.h>
+#include <sys/vfs.h>
 #include <math.h>
+#ifdef OLD_ASTERISK
+#include <linux/zaptel.h>
+#include <tonezone.h>
+#else
 #include <zaptel/zaptel.h>
 #include <zaptel/tonezone.h>
+#endif
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
@@ -241,6 +300,15 @@
 #include "asterisk/config.h"
 #include "asterisk/say.h"
 #include "asterisk/localtime.h"
+#include "asterisk/cdr.h"
+#include <termios.h>
+
+/* Start a tone-list going */
+int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
+/*! Stop the tones from playing */
+void ast_playtones_stop(struct ast_channel *chan);
+
+static  char *tdesc = "Radio Repeater / Remote Base  version 0.70  07/22/2007";
 
 static char *app = "Rpt";
 
@@ -281,20 +349,36 @@
 "            available to the phone user.\n"
 "\n";
 
-static unsigned int vmajor = 0;
-static unsigned int vminor = 47;
-
-static int debug = 0;  /* FIXME Set this >0 for extra debug output */
+static int debug = 0;  /* Set this >0 for extra debug output */
 static int nrpts = 0;
+
+static char remdtmfstr[] = "0123456789*#ABCD";
+
+enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
+
+int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
+
+#define NRPTSTAT 7
+
+struct rpt_chan_stat
+{
+	struct timeval last;
+	long long total;
+	unsigned long count;
+	unsigned long largest;
+	struct timeval largest_time;
+};
 
 char *discstr = "!!DISCONNECT!!";
 static char *remote_rig_ft897="ft897";
 static char *remote_rig_rbi="rbi";
+static char *remote_rig_kenwood="kenwood";
+static char *remote_rig_ic706="ic706";
 
 #ifdef	OLD_ASTERISK
 STANDARD_LOCAL_USER;
+LOCAL_USER_DECL;
 #endif
-
 
 #define	MSWAIT 200
 #define	HANGTIME 5000
@@ -305,6 +389,23 @@
 #define POLITEID 30000
 #define FUNCTDELAY 1500
 
+#define	MAXXLAT 20
+#define	MAXXLATTIME 3
+
+#define MAX_SYSSTATES 10
+
+struct rpt_xlat
+{
+char	funccharseq[MAXXLAT];
+char	endcharseq[MAXXLAT];
+char	passchars[MAXXLAT];
+int	funcindex;
+int	endindex;
+time_t	lastone;
+} ;
+
+static time_t	starttime = 0;
+
 static  pthread_t rpt_master_thread;
 
 struct rpt;
@@ -319,8 +420,11 @@
 	char	name[MAXNODESTR];	/* identifier (routing) string */
 	char	lasttx;
 	char	lastrx;
+	char	lastrx1;
 	char	connected;
 	char	hasconnected;
+	char	perma;
+	char	thisconnected;
 	char	outbound;
 	char	disced;
 	char	killme;
@@ -328,11 +432,20 @@
 	long	disctime;
 	long 	retrytimer;
 	long	retxtimer;
+	long	rerxtimer;
 	int	retries;
+	int	max_retries;
 	int	reconnects;
 	long long connecttime;
 	struct ast_channel *chan;	
 	struct ast_channel *pchan;	
+	char	linklist[MAXLINKLIST];
+	time_t	linklistreceived;
+	long	linklisttimer;
+	int	dtmfed;
+	int linkunkeytocttimer;
+	struct	ast_frame *lastf1,*lastf2;
+	struct	rpt_chan_stat chan_stat[NRPTSTAT];
 } ;
 
 struct rpt_lstat
@@ -344,7 +457,9 @@
 	char	mode;
 	char	outbound;
 	char	reconnects;
+	char	thisconnected;
 	long long	connecttime;
+	struct	rpt_chan_stat chan_stat[NRPTSTAT];
 } ;
 
 struct rpt_tele
@@ -356,6 +471,7 @@
 	int	mode;
 	struct rpt_link mylink;
 	char param[TELEPARAMSIZE];
+	int	submode;
 	pthread_t threadid;
 } ;
 
@@ -381,9 +497,21 @@
 } ;
 
 
+struct sysstate
+{
+	char txdisable;
+	char totdisable;
+	char linkfundisable;
+	char autopatchdisable;
+	char schedulerdisable;
+	char userfundisable;
+	char alternatetail;
+};
+
 static struct rpt
 {
 	ast_mutex_t lock;
+	ast_mutex_t remlock;
 	struct ast_config *cfg;
 	char reload;
 
@@ -391,21 +519,25 @@
 	char *rxchanname;
 	char *txchanname;
 	char *remote;
+	struct	rpt_chan_stat chan_stat[NRPTSTAT];
+	unsigned int scram;
 
 	struct {
-
-		const char *ourcontext;
-		const char *ourcallerid;
-		const char *acctcode;
-		const char *ident;
+		char *ourcontext;
+		char *ourcallerid;
+		char *acctcode;
+		char *ident;
 		char *tonezone;
 		char simple;
-		const char *functions;
-		const char *link_functions;
-		const char *phone_functions;
-		const char *dphone_functions;
-		const char *nodes;
+		char *functions;
+		char *link_functions;
+		char *phone_functions;
+		char *dphone_functions;
+		char *nodes;
+		char *extnodes;
+		char *extnodefile;
 		int hangtime;
+		int althangtime;
 		int totime;
 		int idtime;
 		int tailmessagetime;
@@ -414,13 +546,33 @@
 		int politeid;
 		char *tailmessages[500];
 		int tailmessagemax;
-		const char	*memory;
-		const char	*macro;
-		const char	*startupmacro;
+		char	*memory;
+		char	*macro;
+		char	*startupmacro;
 		int iobase;
+		char *ioport;
 		char funcchar;
 		char endchar;
-		char	nobusyout;
+		char nobusyout;
+		char notelemtx;
+		char propagate_dtmf;
+		char propagate_phonedtmf;
+		char linktolink;
+		unsigned char civaddr;
+		struct rpt_xlat inxlat;
+		struct rpt_xlat outxlat;
+		char *archivedir;
+		int authlevel;
+		char *csstanzaname;
+		char *skedstanzaname;
+		char *txlimitsstanzaname;
+		long monminblocks;
+		int remoteinacttimeout;
+		int remotetimeout;
+		int remotetimeoutwarning;
+		int remotetimeoutwarningfreq;
+		int sysstate_cur;
+		struct sysstate s[MAX_SYSSTATES];
 	} p;
 	struct rpt_link links;
 	int unkeytocttimer;
@@ -430,16 +582,17 @@
 	char remoterx;
 	char remotetx;
 	char remoteon;
+	char remtxfreqok;
 	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 ast_channel *rxchannel,*txchannel, *monchannel;
+	struct ast_channel *pchannel,*txpchannel;
+	struct ast_frame *lastf1,*lastf2;
 	struct rpt_tele tele;
 	struct timeval lasttv,curtv;
 	pthread_t rpt_call_thread,rpt_thread;
@@ -452,6 +605,7 @@
 	int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
 	int totalexecdcommands, dailyexecdcommands;
 	long	retxtimer;
+	long	rerxtimer;
 	long long totaltxtime;
 	char mydtmf;
 	char exten[AST_MAX_EXTENSION];
@@ -464,8 +618,10 @@
 	char tunerequest;
 	char hfscanmode;
 	int hfscanstatus;
+	char hfscanstop;
 	char lastlinknode[MAXNODESTR];
-	char stopgen;
+	char savednodes[MAXNODESTR];
+	int stopgen;
 	char patchfarenddisconnect;
 	char patchnoct;
 	char patchquiet;
@@ -483,6 +639,15 @@
 	time_t lastthreadrestarttime;
 	long	macrotimer;
 	char	lastnodewhichkeyedusup[MAXNODESTR];
+	int	dtmf_local_timer;
+	char	dtmf_local_str[100];
+	struct ast_filestream *monstream;
+	char	loginuser[50];
+	char	loginlevel[10];
+	long	authtelltimer;
+	long	authtimer;
+	int iofd;
+	time_t start_time,last_activity_time;
 #ifdef	__RPT_NOTCH
 	struct rptfilter
 	{
@@ -505,6 +670,23 @@
 #endif
 } rpt_vars[MAXRPTS];	
 
+struct nodelog {
+struct nodelog *next;
+struct nodelog *prev;
+time_t	timestamp;
+char archivedir[MAXNODESTR];
+char str[MAXNODESTR * 2];
+} nodelog;
+
+static int service_scan(struct rpt *myrpt);
+static int set_mode_ft897(struct rpt *myrpt, char newmode);
+static int set_mode_ic706(struct rpt *myrpt, char newmode);
+static int simple_command_ft897(struct rpt *myrpt, char command);
+static int setrem(struct rpt *myrpt);
+
+AST_MUTEX_DEFINE_STATIC(nodeloglock);
+
+AST_MUTEX_DEFINE_STATIC(nodelookuplock);
 
 #ifdef	APP_RPT_LOCK_DEBUG
 
@@ -531,7 +713,6 @@
 	struct rpt *rpt;
 	struct lockthread lockthread;
 } lock_ring[32];
-
 
 int lock_ring_index = 0;
 
@@ -691,6 +872,19 @@
 #endif  /* APP_RPT_LOCK_DEBUG */
 
 /*
+* Return 1 if rig is multimode capable
+*/
+
+static int multimode_capable(struct rpt *myrpt)
+{
+	if(!strcmp(myrpt->remote, remote_rig_ft897))
+		return 1;
+	if(!strcmp(myrpt->remote, remote_rig_ic706))
+		return 1;
+	return 0;
+}	
+
+/*
 * CLI extensions
 */
 
@@ -699,8 +893,10 @@
 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_nodes(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 int rpt_do_fun(int fd, int argc, char *argv[]);
 
 static char debug_usage[] =
 "Usage: rpt debug level {0-7}\n"
@@ -718,6 +914,10 @@
 "Usage: rpt lstats <nodename>\n"
 "       Dumps link statistics to console\n";
 
+static char dump_nodes[] =
+"Usage: rpt nodes <nodename>\n"
+"       Dumps a list of directly and indirectly connected nodes to the console\n";
+
 static char reload_usage[] =
 "Usage: rpt reload\n"
 "       Reloads app_rpt running config parameters\n";
@@ -726,30 +926,42 @@
 "Usage: rpt restart\n"
 "       Restarts app_rpt\n";
 
-static struct ast_cli_entry cli_rpt[] = {
-	{ { "rpt", "debug", "level" },
-	rpt_do_debug, "Enable app_rpt debugging",
-	debug_usage },
-
-        { { "rpt", "dump" },
-	rpt_do_dump, "Dump app_rpt structs for debugging",
-	dump_usage },
-
-        { { "rpt", "stats" },
-	rpt_do_stats, "Dump node statistics",
-	dump_stats },
-        { { "rpt", "lstats" },
-	rpt_do_lstats, "Dump link statistics",
-	dump_lstats },
-
-        { { "rpt", "reload" },
-	rpt_do_reload, "Reload app_rpt config",
-	reload_usage },
-
-        { { "rpt", "restart" },
-	rpt_do_restart, "Restart app_rpt",
-	restart_usage },
-};
+static char fun_usage[] =
+"Usage: rpt fun <nodename> <command>\n"
+"       Send a DTMF function to a node\n";
+
+
+static struct ast_cli_entry  cli_debug =
+        { { "rpt", "debug", "level" }, rpt_do_debug, 
+		"Enable app_rpt debugging", debug_usage };
+
+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_nodes =
+        { { "rpt", "nodes" }, rpt_do_nodes,
+		"Dump node list", dump_nodes };
+
+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 };
+
+static struct ast_cli_entry  cli_fun =
+        { { "rpt", "fun" }, rpt_do_fun,
+		"Execute a DTMF function", fun_usage };
 
 /*
 * Telemetry defaults
@@ -776,6 +988,10 @@
 */
 
 static int setrbi(struct rpt *myrpt);
+static int set_ft897(struct rpt *myrpt);
+static int set_ic706(struct rpt *myrpt);
+static int setkenwood(struct rpt *myrpt);
+static int setrbi_check(struct rpt *myrpt);
 
 
 
@@ -803,6 +1019,228 @@
 	{"remote", function_remote},
 	{"macro", function_macro}
 } ;
+
+static long diskavail(struct rpt *myrpt)
+{
+struct	statfs statfsbuf;
+
+	if (!myrpt->p.archivedir) return(0);
+	if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
+	{
+		ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
+			myrpt->p.archivedir,myrpt->name);
+		return(-1);
+	}
+	return(statfsbuf.f_bavail);
+}
+
+static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
+{
+struct        rpt_link *l;
+
+       l = myrpt->links.next;
+       /* go thru all the links */
+       while(l != &myrpt->links)
+       {
+               if (!l->phonemode)
+               {
+                       l = l->next;
+                       continue;
+               }
+               /* dont send to self */
+               if (mylink && (l == mylink))
+               {
+                       l = l->next;
+                       continue;
+               }
+               if (l->chan) ast_senddigit(l->chan,c);
+               l = l->next;
+       }
+       return;
+}
+
+/* node logging function */
+static void donodelog(struct rpt *myrpt,char *str)
+{
+struct nodelog *nodep;
+char	datestr[100];
+
+	if (!myrpt->p.archivedir) return;
+	nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
+	if (nodep == NULL)
+	{
+		ast_log(LOG_ERROR,"Cannot get memory for node log");
+		return;
+	}
+	time(&nodep->timestamp);
+	strncpy(nodep->archivedir,myrpt->p.archivedir,
+		sizeof(nodep->archivedir) - 1);
+	strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
+		localtime(&nodep->timestamp));
+	snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
+		myrpt->name,datestr,str);
+	ast_mutex_lock(&nodeloglock);
+	insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
+	ast_mutex_unlock(&nodeloglock);
+}
+
+/* must be called locked */
+static void do_dtmf_local(struct rpt *myrpt, char c)
+{
+int	i;
+char	digit;
+static const char* dtmf_tones[] = {
+	"!941+1336/200,!0/200",	/* 0 */
+	"!697+1209/200,!0/200",	/* 1 */
+	"!697+1336/200,!0/200",	/* 2 */
+	"!697+1477/200,!0/200",	/* 3 */
+	"!770+1209/200,!0/200",	/* 4 */
+	"!770+1336/200,!0/200",	/* 5 */
+	"!770+1477/200,!0/200",	/* 6 */
+	"!852+1209/200,!0/200",	/* 7 */
+	"!852+1336/200,!0/200",	/* 8 */
+	"!852+1477/200,!0/200",	/* 9 */
+	"!697+1633/200,!0/200",	/* A */
+	"!770+1633/200,!0/200",	/* B */
+	"!852+1633/200,!0/200",	/* C */
+	"!941+1633/200,!0/200",	/* D */
+	"!941+1209/200,!0/200",	/* * */
+	"!941+1477/200,!0/200" };	/* # */
+
+
+	if (c)
+	{
+		snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
+		if (!myrpt->dtmf_local_timer) 
+			 myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
+	}
+	/* if at timeout */
+	if (myrpt->dtmf_local_timer == 1)
+	{
+		/* if anything in the string */
+		if (myrpt->dtmf_local_str[0])
+		{
+			digit = myrpt->dtmf_local_str[0];
+			myrpt->dtmf_local_str[0] = 0;
+			for(i = 1; myrpt->dtmf_local_str[i]; i++)
+			{
+				myrpt->dtmf_local_str[i - 1] =
+					myrpt->dtmf_local_str[i];
+			}
+			myrpt->dtmf_local_str[i - 1] = 0;
+			myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
+			rpt_mutex_unlock(&myrpt->lock);
+			if (digit >= '0' && digit <='9')
+				ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
+			else if (digit >= 'A' && digit <= 'D')
+				ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
+			else if (digit == '*')
+				ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
+			else if (digit == '#')
+				ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
+			else {
+				/* not handled */
+				ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
+			}
+			rpt_mutex_lock(&myrpt->lock);
+		}
+		else
+		{
+			myrpt->dtmf_local_timer = 0;
+		}
+	}
+}
+
+static int openserial(char *fname)
+{
+	struct termios mode;
+	int fd;
+
+	fd = open(fname,O_RDWR);
+	if (fd == -1)
+	{
+		ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
+		return -1;
+	}
+	memset(&mode, 0, sizeof(mode));
+	if (tcgetattr(fd, &mode)) {
+		ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
+		return -1;
+	}
+#ifndef SOLARIS
+	cfmakeraw(&mode);
+#else
+        mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                        |INLCR|IGNCR|ICRNL|IXON);
+        mode.c_oflag &= ~OPOST;
+        mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+        mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
+        mode.c_cflag |= CS8;
+	mode.c_cc[TIME] = 3;
+	mode.c_cc[MAX] = 1;
+#endif
+
+	cfsetispeed(&mode, B9600);
+	cfsetospeed(&mode, B9600);
+	if (tcsetattr(fd, TCSANOW, &mode)) 
+		ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
+	return(fd);	
+}
+
+static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
+{
+time_t	now;
+int	gotone;
+
+	time(&now);
+	gotone = 0;
+	/* if too much time, reset the skate machine */
+	if ((now - xlat->lastone) > MAXXLATTIME)
+	{
+		xlat->funcindex = xlat->endindex = 0;
+	}
+	if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
+	{
+		time(&xlat->lastone);
+		gotone = 1;
+		if (!xlat->funccharseq[xlat->funcindex])
+		{
+			xlat->funcindex = xlat->endindex = 0;
+			return(myrpt->p.funcchar);
+		}
+	} else xlat->funcindex = 0;
+	if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
+	{
+		time(&xlat->lastone);
+		gotone = 1;
+		if (!xlat->endcharseq[xlat->endindex])
+		{
+			xlat->funcindex = xlat->endindex = 0;
+			return(myrpt->p.endchar);
+		}
+	} else xlat->endindex = 0;
+	/* if in middle of decode seq, send nothing back */
+	if (gotone) return(0);
+	/* if no pass chars specified, return em all */
+	if (!xlat->passchars[0]) return(c);
+	/* if a "pass char", pass it */
+	if (strchr(xlat->passchars,c)) return(c);
+	return(0);
+}
+
+/*
+ * Return a pointer to the first non-whitespace character
+ */
+
+static char *eatwhite(char *s)
+{
+	while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
+		if(!*s)
+			break;
+		s++;
+	}
+	return s;
+}
 
 /*
 * Break up a delimited string into a table of substrings
@@ -853,9 +1291,135 @@
 
 }
 
+/* must be called locked */
+static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
+{
+struct rpt_link *l;
+char mode;
+int	i,spos;
+
+	buf[0] = 0; /* clear output buffer */
+	/* go thru all links */
+	for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
+	{
+		/* if is not a real link, ignore it */
+		if (l->name[0] == '0') continue;
+		/* dont count our stuff */
+		if (l == mylink) continue;
+		if (mylink && (!strcmp(l->name,mylink->name))) continue;
+		/* figure out mode to report */
+		mode = 'T'; /* use Tranceive by default */
+		if (!l->mode) mode = 'R'; /* indicate RX for our mode */
+		if (!l->thisconnected) 	mode = 'C'; /* indicate connecting */
+		spos = strlen(buf); /* current buf size (b4 we add our stuff) */
+		if (spos)
+		{
+			strcat(buf,",");
+			spos++;
+		}
+		/* add nodes into buffer */
+		if (l->linklist[0])
+		{
+			snprintf(buf + spos,MAXLINKLIST - spos,
+				"%c%s,%s",mode,l->name,l->linklist);
+		}
+		else /* if no nodes, add this node into buffer */
+		{
+			snprintf(buf + spos,MAXLINKLIST - spos,
+				"%c%s",mode,l->name);
+		}
+		/* if we are in tranceive mode, let all modes stand */
+		if (mode == 'T') continue;
+		/* downgrade everyone on this node if appropriate */
+		for(i = spos; buf[i]; i++)
+		{
+			if (buf[i] == 'T') buf[i] = mode;
+			if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
+		}
+	}
+	return;
+}
+
+/* must be called locked */
+static void __kickshort(struct rpt *myrpt)
+{
+struct rpt_link *l;
+
+	for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
+	{
+		/* if is not a real link, ignore it */
+		if (l->name[0] == '0') continue;
+		l->linklisttimer = LINKLISTSHORTTIME;
+	}
+	return;
+}
+
+static char *node_lookup(struct rpt *myrpt,char *digitbuf)
+{
+
+char *val;
+int longestnode,j;
+struct stat mystat;
+static time_t last = 0;
+static struct ast_config *ourcfg = NULL;
+struct ast_variable *vp;
+
+	/* try to look it up locally first */
+	val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
+	if (val) return(val);
+	ast_mutex_lock(&nodelookuplock);
+	/* if file does not exist */
+	if (stat(myrpt->p.extnodefile,&mystat) == -1)
+	{
+		if (ourcfg) ast_config_destroy(ourcfg);
+		ourcfg = NULL;
+		ast_mutex_unlock(&nodelookuplock);
+		return(NULL);
+	}
+	/* if we need to reload */
+	if (mystat.st_mtime > last)
+	{
+		if (ourcfg) ast_config_destroy(ourcfg);
+		ourcfg = ast_config_load(myrpt->p.extnodefile);
+		/* if file not there, just bail */
+		if (!ourcfg)
+		{
+			ast_mutex_unlock(&nodelookuplock);
+			return(NULL);
+		}
+		/* reset "last" time */
+		last = mystat.st_mtime;
+
+		/* determine longest node length again */		
+		longestnode = 0;
+		vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
+		while(vp){
+			j = strlen(vp->name);
+			if (j > longestnode)
+				longestnode = j;
+			vp = vp->next;
+		}
+
+		vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
+		while(vp){
+			j = strlen(vp->name);
+			if (j > longestnode)
+				longestnode = j;
+			vp = vp->next;
+		}
+
+		myrpt->longestnode = longestnode;
+	}
+	val = NULL;
+	if (ourcfg)
+		val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
+	ast_mutex_unlock(&nodelookuplock);
+	return(val);
+}
+
 /*
-* 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
+* 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[])
@@ -900,7 +1464,7 @@
 					
 
 
-static int myatoi(const char *str)
+static int myatoi(char *str)
 {
 int	ret;
 
@@ -910,6 +1474,16 @@
 	return ret;
 }
 
+static int mycompar(const void *a, const void *b)
+{
+char	**x = (char **) a;
+char	**y = (char **) b;
+int	xoff,yoff;
+
+	if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
+	if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
+	return(strcmp((*x) + xoff,(*y) + yoff));
+}
 
 #ifdef	__RPT_NOTCH
 
@@ -937,16 +1511,50 @@
 
 #endif
 
+
+/*
+ Get the time for the machine's time zone
+ Note: Asterisk requires a copy of localtime
+ in the /etc directory for this to work properly.
+ If /etc/localtime is not present, you will get
+ GMT time! This is especially important on systems
+ running embedded linux distributions as they don't usually
+ have support for locales. 
+
+ If OLD_ASTERISK is defined, then the older localtime_r
+ function will be used. The /etc/localtime file is not
+ required in this case. This provides backward compatibility
+ with Asterisk 1.2 systems.
+
+*/
+
+static void rpt_localtime( time_t * t, struct tm *lt)
+{
+#ifdef OLD_ASTERISK
+	localtime_r(t, lt);
+#else
+	ast_localtime(t, lt, NULL);
+#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)
 {
-        const char *var;
+        char *var;
         int ret;
-                                                                                
-        var = ast_variable_retrieve(myrpt->cfg, category, name);
+	char include_zero = 0;
+
+	if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
+		min = -min;
+		include_zero = 1;
+	}           
+                                                                     
+        var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
         if(var){
                 ret = myatoi(var);
+		if(include_zero && !ret)
+			return 0;
                 if(ret < min)
                         ret = min;
                 if(ret > max)
@@ -960,15 +1568,14 @@
 
 static void load_rpt_vars(int n,int init)
 {
-char *this;
-	const char *val;
-int	j,longestnode;
+char *this,*val;
+int	i,j,longestnode;
 struct ast_variable *vp;
 struct ast_config *cfg;
-#ifdef	__RPT_NOTCH
-int	i;
 char *strs[100];
-#endif
+char s1[256];
+static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
+				"ufena","ufdis","atena","atdis",NULL};
 
 	if (option_verbose > 2)
 		ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
@@ -1001,76 +1608,118 @@
 	/* zot out filters stuff */
 	memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
 #endif
-	val = ast_variable_retrieve(cfg,this,"context");
+	val = (char *) 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");
+	val = (char *) ast_variable_retrieve(cfg,this,"callerid");
 	if (val) rpt_vars[n].p.ourcallerid = val;
-	val = ast_variable_retrieve(cfg,this,"accountcode");
+	val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
 	if (val) rpt_vars[n].p.acctcode = val;
-	val = ast_variable_retrieve(cfg,this,"idrecording");
+	val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
 	if (val) rpt_vars[n].p.ident = val;
-	val = ast_variable_retrieve(cfg,this,"hangtime");
+	val = (char *) 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");
+	val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
+	if (val) rpt_vars[n].p.althangtime = atoi(val);
+		else rpt_vars[n].p.althangtime = HANGTIME;
+	val = (char *) 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.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);	/* Enforce a min max including zero */
 	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 = ast_strdupa(val);
+	val = (char *) 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(ast_strdupa(val), rpt_vars[n].p.tailmessages, 500);
-	val = ast_variable_retrieve(cfg,this,"memory");
+	val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
+	if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
+	val = (char *) ast_variable_retrieve(cfg,this,"memory");
 	if (!val) val = MEMORY;
 	rpt_vars[n].p.memory = val;
-	val = ast_variable_retrieve(cfg,this,"macro");
+	val = (char *) ast_variable_retrieve(cfg,this,"macro");
 	if (!val) val = MACRO;
 	rpt_vars[n].p.macro = val;
-	val = ast_variable_retrieve(cfg,this,"startup_macro");
+	val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
 	if (val) rpt_vars[n].p.startupmacro = val;
-	val = ast_variable_retrieve(cfg,this,"iobase");
+	val = (char *) 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");
+	val = (char *) ast_variable_retrieve(cfg,this,"ioport");
+	rpt_vars[n].p.ioport = val;
+	val = (char *) 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");
+	val =  (char *) 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");
+	val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
 	if (val) rpt_vars[n].p.phone_functions = val;
-	val = ast_variable_retrieve(cfg,this,"dphone_functions");
+	val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
 	if (val) rpt_vars[n].p.dphone_functions = val;
-	val = ast_variable_retrieve(cfg,this,"funcchar");
+	val = (char *) 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");
+	val = (char *) 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");
+	val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
 	if (val) rpt_vars[n].p.nobusyout = ast_true(val);
-	val = ast_variable_retrieve(cfg,this,"nodes");
+	val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
+	if (val) rpt_vars[n].p.notelemtx = ast_true(val);
+	val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
+	if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
+	val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
+	if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
+	val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
+	if (val) rpt_vars[n].p.linktolink = ast_true(val);
+	val = (char *) ast_variable_retrieve(cfg,this,"nodes");
 	if (!val) val = NODES;
 	rpt_vars[n].p.nodes = val;
+	val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
+	if (!val) val = EXTNODES;
+	rpt_vars[n].p.extnodes = val;
+	val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
+	if (!val) val = EXTNODEFILE;
+	rpt_vars[n].p.extnodefile = val;
+	val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
+	if (val) rpt_vars[n].p.archivedir = val;
+	val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
+	if (val) rpt_vars[n].p.authlevel = atoi(val); 
+	else rpt_vars[n].p.authlevel = 0;
+	val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
+	if (val) rpt_vars[n].p.monminblocks = atol(val); 
+	else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
+	val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
+	if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
+	else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
+	val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
+	if (val) rpt_vars[n].p.civaddr = atoi(val); 
+	else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
+	val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
+	if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
+	else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
+	val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
+	if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
+	else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
+	val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
+	if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
+	else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
 #ifdef	__RPT_NOTCH
-	val = ast_variable_retrieve(cfg,this,"rxnotch");
+	val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
 	if (val) {
-		i = finddelim(ast_strdupa(val),strs,MAXFILTERS * 2);
+		i = finddelim(val,strs,MAXFILTERS * 2);
 		i &= ~1; /* force an even number, rounded down */
 		if (i >= 2) for(j = 0; j < i; j += 2)
 		{
@@ -1085,6 +1734,34 @@
 
 	}
 #endif
+	val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
+	if (val) {
+		memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
+		i = finddelim(val,strs,3);
+		if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
+		if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
+		if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
+	}
+	val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
+	if (val) {
+		memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
+		i = finddelim(val,strs,3);
+		if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
+		if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
+		if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
+	}
+	/* retreive the stanza name for the control states if there is one */
+	val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
+	rpt_vars[n].p.csstanzaname = val;
+		
+	/* retreive the stanza name for the scheduler if there is one */
+	val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
+	rpt_vars[n].p.skedstanzaname = val;
+
+	/* retreive the stanza name for the txlimits */
+	val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
+	rpt_vars[n].p.txlimitsstanzaname = val;
+
 	longestnode = 0;
 
 	vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
@@ -1150,6 +1827,88 @@
 			rpt_vars[n].macro_longest = j;
 		vp = vp->next;
 	}
+	
+	/* Browse for control states */
+	if(rpt_vars[n].p.csstanzaname)
+		vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
+	else
+		vp = NULL;
+	for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
+		int k,nukw,statenum;
+		statenum=atoi(vp->name);
+		strncpy(s1, vp->value, 255);
+		s1[255] = 0;
+		nukw  = finddelim(s1,strs,32);
+		
+		for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */	
+			for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
+				if(!strcmp(strs[k],cs_keywords[j])){
+					switch(j){
+						case 0: /* rptena */
+							rpt_vars[n].p.s[statenum].txdisable = 0;
+							break;
+						case 1: /* rptdis */
+							rpt_vars[n].p.s[statenum].txdisable = 1;
+							break;
+			
+						case 2: /* apena */
+							rpt_vars[n].p.s[statenum].autopatchdisable = 0;
+							break;
+
+						case 3: /* apdis */
+							rpt_vars[n].p.s[statenum].autopatchdisable = 1;
+							break;
+
+						case 4: /* lnkena */
+							rpt_vars[n].p.s[statenum].linkfundisable = 0;
+							break;
+	
+						case 5: /* lnkdis */
+							rpt_vars[n].p.s[statenum].linkfundisable = 1;
+							break;
+
+						case 6: /* totena */
+							rpt_vars[n].p.s[statenum].totdisable = 0;
+							break;
+					
+						case 7: /* totdis */
+							rpt_vars[n].p.s[statenum].totdisable = 1;
+							break;
+
+						case 8: /* skena */
+							rpt_vars[n].p.s[statenum].schedulerdisable = 0;
+							break;
+
+						case 9: /* skdis */
+							rpt_vars[n].p.s[statenum].schedulerdisable = 1;
+							break;
+
+						case 10: /* ufena */
+							rpt_vars[n].p.s[statenum].userfundisable = 0;
+							break;
+
+						case 11: /* ufdis */
+							rpt_vars[n].p.s[statenum].userfundisable = 1;
+							break;
+
+						case 12: /* atena */
+							rpt_vars[n].p.s[statenum].alternatetail = 1;
+							break;
+
+						case 13: /* atdis */
+							rpt_vars[n].p.s[statenum].alternatetail = 0;
+							break;
+			
+						default:
+							ast_log(LOG_WARNING,
+								"Unhandled control state keyword %s", cs_keywords[i]);
+							break;
+					}
+				}
+			}
+		}
+		vp = vp->next;
+	}
 	ast_mutex_unlock(&rpt_vars[n].lock);
 }
 
@@ -1213,7 +1972,8 @@
 	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;

[... 7385 lines stripped ...]



More information about the asterisk-commits mailing list