[asterisk-commits] branch bweschke/polycom_acd_functions r29967 - in /team/bweschke/polycom_acd_...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed May 24 07:03:55 MST 2006


Author: bweschke
Date: Wed May 24 09:03:54 2006
New Revision: 29967

URL: http://svn.digium.com/view/asterisk?rev=29967&view=rev
Log:
Merged revisions 29903,29905,29935,29938 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

........
r29903 | kpfleming | 2006-05-23 23:28:49 -0400 (Tue, 23 May 2006) | 4 lines

add a new option for 'obscuring' SIP user/peer names from fishers
use an enum for authentication results and clean up code
fix a bug where SUBSCRIBE for an unknown user/peer would not generate a response

........
r29905 | kpfleming | 2006-05-23 23:32:55 -0400 (Tue, 23 May 2006) | 2 lines

block SIP obscurity fix from merging... trunk version was different

........
r29935 | jdixon | 2006-05-24 03:01:02 -0400 (Wed, 24 May 2006) | 2 lines

Added incoming audio notch filtering, plus a bunch of command improvements, etc.

........
r29938 | crichter | 2006-05-24 03:58:52 -0400 (Wed, 24 May 2006) | 1 line

fixed to early connect bug which came in yesterday.., also added the transmit of progress indicators through channel vars
........

Modified:
    team/bweschke/polycom_acd_functions/   (props changed)
    team/bweschke/polycom_acd_functions/apps/app_rpt.c
    team/bweschke/polycom_acd_functions/channels/chan_misdn.c
    team/bweschke/polycom_acd_functions/channels/chan_sip.c
    team/bweschke/polycom_acd_functions/configs/misdn.conf.sample
    team/bweschke/polycom_acd_functions/configs/sip.conf.sample

Propchange: team/bweschke/polycom_acd_functions/
------------------------------------------------------------------------------
Binary property 'branch-1.2-blocked' - no diff available.

Propchange: team/bweschke/polycom_acd_functions/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed May 24 09:03:54 2006
@@ -1,1 +1,1 @@
-/trunk:1-29880
+/trunk:1-29966

Modified: team/bweschke/polycom_acd_functions/apps/app_rpt.c
URL: http://svn.digium.com/view/asterisk/team/bweschke/polycom_acd_functions/apps/app_rpt.c?rev=29967&r1=29966&r2=29967&view=diff
==============================================================================
--- team/bweschke/polycom_acd_functions/apps/app_rpt.c (original)
+++ team/bweschke/polycom_acd_functions/apps/app_rpt.c Wed May 24 09:03:54 2006
@@ -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 at 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{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 @@
 #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 @@
 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 @@
 #define	TOTIME 180000
 #define	IDTIME 300000
 #define	MAXRPTS 20
+#define MAX_STAT_LINKS 32
 #define POLITEID 30000
 #define FUNCTDELAY 1500
 
@@ -299,8 +331,22 @@
 	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
@@ -339,53 +385,77 @@
 
 static struct rpt
 {
+	ast_mutex_t lock;
+	struct ast_config *cfg;
+	char reload;
+
 	char *name;
-	ast_mutex_t lock;
 	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 @@
 	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 @@
 	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 @@
 /* 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 @@
 "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 };
@@ -629,6 +735,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 @@
 	{"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[])
-{
-int     i,inquo;
+
+
+static int finddelim(char *str, char *strp[], int limit)
+{
+int     i,l,inquo;
 
         inquo = 0;
         i = 0;
@@ -695,7 +827,7 @@
                 strp[0] = 0;
                 return(0);
            }
-        for(; *str; str++)
+        for(l = 0; *str && (l < limit) ; str++)
            {
                 if (*str == QUOTECHR)
                    {
@@ -713,6 +845,7 @@
                 if ((*str == DELIMCHR) && (!inquo))
                 {
                         *str = 0;
+			l++;
                         strp[i++] = str + 1;
                 }
            }
@@ -721,6 +854,53 @@
 
 }
 
+/*
+* 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;
@@ -729,6 +909,248 @@
 	/* leave this %i alone, non-base-10 input is useful here */
 	if (sscanf(str,"%i",&ret) != 1) return -1;
 	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);
 }
 
 /*
@@ -772,6 +1194,307 @@
 		        ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
 		        return RESULT_SUCCESS;
 		}
+	}
+	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;
 }
@@ -1054,27 +1777,7 @@
 }
 
 
-/* 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 @@
 	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 @@
 * 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 @@
 	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 @@
 				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 @@
         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 @@
         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 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 @@
 
 	/* 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 @@
 	    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");

[... 2456 lines stripped ...]


More information about the asterisk-commits mailing list