
/*
 * NETWATCH is based on some code from Statnet 
 */
/*
 * Statnet is protected under the GNU Public License (GPL2). 
 */
/*
 * Author: Jeroen Baekelandt (jeroenb@igwe.vub.ac.be)       
 */
/*
 * 27DEC95: Scot E. Wilcoxon (sewilco@fieldday.mn.org)     
 */
/*
 * NETWATCH is VERY loosely based on the code from Statnet... thanks out
 * to Jeroen and Scot...
 * 
 * NETWATCH allows a user (superuser) to monitor an ETHERNET and examine
 * activity on the network. Hostnames are highlighted in colours (for
 * those supporting them) to indicate activity on the bus network based on 
 * time ( less than 1 minute RED, less than 5 minutes YELLOW, less than 30 
 * minutes GREEN and otherwise BLUE). The monitor includes statistics on 
 * a) Transmitted and received packets b) Protocol of LAST packet (TX or
 * RC) c) LAST Communication partner (IP address)
 * 
 * The number of hosts capable of support is a function of memory. They
 * are stored in 2 doubly-linked lists (local and remote).
 * 
 * Screen updates take place 1 per second (unless a rare  lockout... when
 * linked list links are updating... in which case it displays in the next 
 * second)
 * 
 * Keyboard usage is admittedly limited (and a kludge... due to some
 * ncurses settings that need better tinkering) ->   Go forward to next
 * option <-   Go backward to previous option <UP>         Go back to
 * previous page (back 20 lines on most consoles) <DOWN>       Go forward
 * to next page (forward 20 lines on most consoles) c    Clear counters
 * for fresh counting n    Clear linked lists for new start
 * 
 * It is a simple program to execute for ETHERNET under LINUX. It assumes
 * that there is a "/etc/rc.d/rc.inet1" file for network configuration. If 
 * so, it checks for an "eth0" ifconfig and picks up the netmask from the
 * file. UPDATE: It actually looks at the /proc entry for device configuration
 * to get its info... if no /proc THEN it trys the config file (for OLD SL
 * systems)
 * 
 * For those with multiple "eth" interfaces, I am sorry it doesn't support 
 * both simultaneously.
 * 
 * AUTHOR:      G. MacKay E-MAIL:      mackay@gmml.slctech.org
 * 
 * P.S. Given the fact that I was sick for 3 days and decided to write
 * this code... forgive me for not writing beautiful code... (those that
 * know me, probably don't think my code is beautiful when I am healthy)
 * 
 * NEW CODE IS COPYRIGHTED to  G. MacKay   under  GPL 
 */

/*
 * This is the main program 
 */
#define MAIN_LINE 1
#include "config.h"

#ifdef NEWCURSES_SUPP
#include <ncurses/curses.h>
#else
#ifdef NEWCURSESROOT_SUPP
#include <ncurses.h>
#else
#include <curses.h>
#endif
#endif

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
/*
 * #include <sys/socket.h> 
 */
#include <sys/wait.h>
#include <sys/time.h>
#ifdef NETINET_SUPP_in
#include <netinet/in.h>
#else
#include <linux/in.h>
#endif
#ifdef NETINET_SUPP_if_ether
#include <netinet/if_ether.h>
#else
#include <linux/if_ether.h>
#endif
#include <strings.h>
#include <sys/ioctl.h>

#ifdef NETINET_SUPP_if
#include <net/if.h>
#else
#include <linux/if.h>
#endif

#include <signal.h>
#ifdef NETINET_SUPP_ip
#include <netinet/ip.h>
#else
#include <linux/ip.h>
#endif
#ifdef NETINET_SUPP_tcp
#include <netinet/tcp.h>
#else
#ifdef NETINET_SUPP_ip_tcp
#include <netinet/ip_tcp.h>
#else
#include <linux/tcp.h>
#endif
#endif
#ifdef NETINET_SUPP_udp
#include <netinet/udp.h>
#else
#ifdef NETINET_SUPP_ip_udp
#include <netinet/ip_udp.h>
#else
#include <linux/udp.h>
#endif
#endif
#if NETINET_SUPP_icmp
#include <netinet/ip_icmp.h>
#else
#include <linux/icmp.h>
#endif
#ifndef LINUX_IP_OPTIONS
#define ip_options options
#endif
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include "curs.h"
#include "netresolv.h"
#include "netwatch.h"

extern int errno;

char *version = "0.9d";
char progtitle[60];
char log[256] = "/root/.log";
char specconfigfile[256] = "/root/.netwatch.conf";

int fdlog;
#if defined(_LINUX_IF_ETHER_H) || defined(_NETINET_IF_ETHER_H)
#undef NET_3			/*
				   * not using Net/3 definitions 
				 */
#endif

#ifndef ETH_HLEN
#define ETH_HLEN 14		/*
				   * Ethernet header length 
				 */
#endif

#ifndef ETH_P_ATALK
#define ETH_P_ATALK 0x809B	/*
				   * Appletalk 
				 */
#endif

#ifndef SOCK_PACKET
#define SOCK_PACKET SOCK_RAW	/*
				   * If SOCK_PACKET is wrong, try SOCK_RAW 
				 */
#endif

#ifndef NET_3
#define ether_head	ethhdr	/*
				   * ether_head structure 
				 */
#define ether_type	h_proto	/*
				   * Ethernet Packet Type ID field 
				 */
#define ip		iphdr	/*
				   * IP header structure 
				 */
#define ip_off		frag_off	/*
					   * IP protocol field 
					 */
#define ip_p		protocol	/*
					   * IP protocol field 
					 */
#define ip_hl		ihl	/*
				   * IP header length field 
				 */
#ifndef _NETINET_IP_TCP_H
#ifndef __FAVOR_BSD
#define th_sport	source	/*
				   * TCP source port field 
				 */
#define th_dport	dest	/*
				   * TCP destination port field 
				 */
#endif
#endif
#ifdef LINUXINET_SUPP_udp

#define ui_sport	source	/*
				   * UDP source port field 
				 */
#define ui_dport	dest	/*
				   * UDP destination port field 
				 */

#endif
#endif

#include <net/if_ppp.h>

#define ETHERHEADSIZE (sizeof(struct ether_head))
int ethsz = ETHERHEADSIZE;
#define IPSIZE (sizeof(struct ip))
int ipsz = IPSIZE;
#define IPOPTSIZE (sizeof(struct ip_options))
int ipoptsz = IPOPTSIZE;
#define TCPHEADSIZE (sizeof(struct tcphdr))
int tcpheadsz = TCPHEADSIZE;
#define SN_RCV_BUF_SIZE	(sizeof(struct ether_head)+ \
				 sizeof(struct ip)+ \
                                 sizeof(struct ip_options)+ \
				 sizeof(struct tcphdr)+4)
#define SN_RCV_BIGBUFSIZE SN_RCV_BUF_SIZE+80
/*
 * above was 1600, but kernel discards 
 */
/*
 * excess and tells us full length,   
 */
/*
 * so we only need enough to analyze. 
 */
int sn_rcv_bufsize = SN_RCV_BIGBUFSIZE;
int ESCON = 0;
#define ESC 0x1b
#define RETURNKEY 0x0d
#define CONTROLL  12
#define MAXHELPPAGE 3
HOSTINFO ldummy, rdummy;
HOSTINFO *lfirst, *rfirst, *previous, *current, *next, *work;
struct itimerval newtm, oldtm;	/*
				 * TIMER for measuring 
				 */
time_t new;
time_t starttime;
time_t wakeup_reload;
int wakeup_state = FALSE;
time_t reload_timer_start;
int reload_timer_sec = 0;
int reload_active = FALSE;
int statsdate = FALSE;
int statsappend = TRUE;
char tmstring[80] = "%Y.%m.%d.%H.%M";
int freezedisplay = FALSE;
int lastfreeze = FALSE;
int sentclear = FALSE;

int sREDTIME = 60;
int sYELLOWTIME = 300;
int sGREENTIME = 1800;
char configfile[256] = "/etc/rc.d/rc.inet1";
char statsfile[256] = "/etc/netwatch.stats";
char newstatsfile[256];
int newconfig = FALSE;
char ethdevname[64] = "eth0";
int newethname = FALSE;
int probcnt = 0;		/*
				 * Problem Count  on ETH reads 
				 */
int intrcnt = 0;		/*
				 * EINTR hits  on ETH reads 
				 */



#define MAGNABUFSIZE 2048
struct magrec
  {
    int len;
    char dir;
    unsigned char buf[MAGNABUFSIZE];
  };
#define MAGNAMAX 400
#define MAGNAOFFS 40
struct magrec magna[MAGNAMAX];
int magnacnt = 0;
int magnaoffs = MAGNAOFFS;
char magnamatch[RESOLVE_MAX];
HOSTINFO *magnaspot;
u_int32_t magnakey;
int magnaphys = 0;
int magnafirst = TRUE;
int magnafull = FALSE;
HOSTINFO *magnacomhost = NULL;
u_int32_t magnacomkey;

double maxburst = 0.0;
unsigned char netmask[4] =
{255, 255, 255, 0};
unsigned char localaddr[4];
int ethok = 1;
struct hostent *hostent;
int wai = 0;
int selprob = 0;
int selcode = 0;
int bugfix = FALSE;
int help = FALSE;
int helppage = 1;
int watch = FALSE;
int remoterow = -1;
int localrow = -1;
int localupdate = 0;
int remoteupdate = 0;
int poschange = 0;
int refreshloc = 0;
int refreshrem = 0;
int refreshgen = 0;
int llockout = 0;
int rlockout = 0;
int lydisp = 0;
int rydisp = 0;
int ydisp = 0;
int localkey = TRUE;
int dispopt = DISP_TX_RC;
int colour;
unsigned long int routeruse = 0;
unsigned long int routerto = 0;
unsigned long int routerfrom = 0;
int disprouterstats = FALSE;
int scrmid;
int selecthost = FALSE;
int numselect = 0;
int selectside = 0;
int selectchange = FALSE;
int bluedie = 0;
int ignoredomain = 0;
int statpid = -1010;		/*
				 * Magic number to indicate NO
				 * status process present 
				 */

int sd;

char tmpbuf[256];
char speclogfile[256] = "/root/.watchlog";
FILE *fpspeclog;
int speclog = 0;
int printtospeclog = 0;
int speclogext = 0;

int topflag = 0;
HOSTINFO *toplocal;
HOSTINFO *topremote;
HOSTINFO tldummy, trdummy;
/*
 * For screen size independent settings.... display... 
 */
int curskeyspot;
int curskeyval;
int cursllockout;
int cursrlockout;
int curslines;
int curshosttrim;
int cursproto;
int cursdest;
int noscreen = 0;
int fishspeclog = 0;		/*
				 * old speclog for fishing
				 * expedition 
				 */

long int ethcnt = 0;
int isethdev = TRUE;
int keycnt = 0;
int repeatcount = 1;
int repeatindex = 0;
char repeatbuf[255];

int nokeys = FALSE;

unsigned char workingmac[ETH_ALEN];
/*
 * unsigned char badmac[ETH_ALEN]; 
 */
/*
 * unsigned long badmactime; 
 */

#define SMALLSCREEN 0
#define FULLSCREEN 1

unsigned char buf[SN_RCV_BIGBUFSIZE + 20];


struct ifreq ifr, oldifr;
struct sockaddr_in *pin;


struct at_frame_type
  {
    unsigned char filler[20];
    u_int16_t appletalk_type1;	/*
				 * what is formal name? 
				 */
    unsigned char filler2[12];
    u_int8_t appletalk_type2;	/*
				 * what is formal name? 
				 */
  };				/*
				 * Ethernet Appletalk 
				 */

int mailflag = 1;
int syslogflag = 1;
char userwarn[256] = "noone@xxx.xxx.xxx"; /* ENTER your MAIL Address here.. */
char fishstring[256] =  "";
int fishstringlen = 0;
void handle_frame (unsigned char *buf, int length, struct sockaddr *saddr,
		int eth);
void handle_ip (struct ip *buf, int length);
void processinetrc (unsigned char *netmask, unsigned char *local, int *peth);
void warning( char s[], unsigned char *buf);


typedef void (*sigfunc) (int);

static pid_t mypid, child;
int msocket[2];
int osocket[2];
int resolvetimeout = 0;
extern long int timezone;

void adjusttime(time_t *pt, int hrs, int mins)
{
	struct tm tm;
	struct tm *ps;
	time_t v;
	int i,j;
	
	v = time(0);
	ps = localtime(&v);
	tm = *ps;
	if (hrs<tm.tm_hour-1 || (hrs==tm.tm_hour-1 && mins<tm.tm_min-1))
	{
		tm.tm_mday++;
	}
	tm.tm_hour = hrs;
	tm.tm_min = mins;
	*pt = mktime(&tm);
	/* Adjust to UTC */
}

void processspecconfig()
{
	FILE *fp;
	static char w1[140],w2[140],w3[140],w4[140];
	int rel_hours,rel_mins;
	int narg;

	if ((fp=fopen(specconfigfile,"r")))
	{
		while((fgets(tmpbuf,256,fp)))
		{
			if (tmpbuf[0]!='#')
			{
				tmpbuf[strlen(tmpbuf)-1]=0;
				if ((narg=sscanf(tmpbuf,"%s %s %s %s",w1,w2,w3,w4))>=2)
				{
				/* Config file Keywords - 
				warnmail
				logfile
				statsfile
				fishstring
				*/
					if (!strncasecmp(w1,"warnmail",8))
						strncpy(userwarn,w2,256);
					else if (!strncasecmp(w1,"yellow",6))
						sYELLOWTIME = atoi(w2);
					else if (!strncasecmp(w1,"red",3))
						sREDTIME = atoi(w2);
					else if (!strncasecmp(w1,"green",5))
						sGREENTIME = atoi(w2);
					else if (!strncasecmp(w1,"logfile",7))
						strncpy(speclogfile,w2,256);
					else if (!strncasecmp(w1,"timefmt",7))
						strncpy(tmstring,w2,256);
					else if (!strncasecmp(w1,"statsfile",9))
						strncpy(statsfile,w2,256);
					else if (!strncasecmp(w1,"statsoption",11))
					{
						if (!strncasecmp(w2,"append",6))
							statsappend = TRUE;
						else if (!strncasecmp(w2,"date",4))
							statsappend = FALSE;
					}	
					else if (!strncasecmp(w1,"fishstring",10))
					{
						strncpy(fishstring,&tmpbuf[11],256);
						fishstringlen = strlen(fishstring);
					}
					else if (!strncasecmp(w1,"reload",6))
					{
						if (!strncasecmp(w2,"at",2))
						{
						  if (narg==4)
						  {
							reload_timer_sec =60*atoi(w4);
							if (reload_timer_sec>0)
							{
								sscanf(w3,"%2d:%2d",&rel_hours,&rel_mins);

								adjusttime(&wakeup_reload,rel_hours,rel_mins);
								wakeup_state = TRUE;
							} 
						 }
						}
						else
						{
						reload_timer_sec = 60*atoi(w2);
						if (reload_timer_sec>0)
						{
							reload_timer_start = time(0);
							reload_active = TRUE;
						}
						}		
							
					}
				
			
				}
			}

		}	

		fclose(fp);
	}

}


void
  handletimeout (int sig)
{
  resolvetimeout = 10;
/*
 * printf("Got TIMEOUT\n");  
 */
  /* signal (SIGUSR1, handletimeout); */
}

void
  handlechild (int sig)
{
  int status;
  pid_t killpid;

  killpid = wait (&status);
/*
 * if (WIFSIGNALED(status)) { printf("Abnormal termination... signal #%d
 * for %ld\n", WTERMSIG(status),killpid); } 
 */
}

void
  processres (int sig)
{
  struct gotname one;
  int actnum;
  int i,sz;
/*
 * printf("Got Signal PROCESSRES\n");  
 */
  ioctl(osocket[0],FIONREAD,&actnum);
  sz=sizeof(one);
  if (actnum>sz)
  {
	for (i=0;i<actnum;i+=sz)
	{	
	  read (osocket[0], &one, sizeof (one));
	 /*  signal (SIGUSR2, processres); */
	  if (!sentclear)
  		strcpy (one.where, one.name);
	  else if (one.where==(void *)1)
		sentclear = FALSE;
	}
  }
}

void
  setupsignals ()
{
  signal (SIGUSR1, handletimeout);
  signal (SIGUSR2, processres);
}

void
 startnetresolv()
{
  struct resolvaddr one;

  one.pid = 0;
  one.inetaddr = 0L;
  one.where = (char *)1;
  write (msocket[1], &one, sizeof (one));
  kill (child, SIGUSR1);
}

void
 clearnetresolv()
{
  struct resolvaddr one;

  one.pid = 0;
  one.inetaddr = 0L;
  one.where = (char *)0;
  sentclear = TRUE;
  write (msocket[1], &one, sizeof (one));
  kill (child, SIGUSR1);
}

void
  mygethostbyaddr (char *where, unsigned char *p, int len, int proto)
{
  struct resolvaddr one;

  one.pid = mypid;
  one.inetaddr = *(u_int32_t *) p;
  one.where = where;
  write (msocket[1], &one, sizeof (one));
  kill (child, SIGUSR1);
}




void
  clearentry (HOSTINFO * current)
{
  current->pktcntsend = current->pktcntrec = 0;
  current->intpktcntsend = current->intpktcntrec = 0;
  current->extpktcntsend = current->extpktcntrec = 0;
  current->sendbytes = current->recbytes = 0;
  current->intsendbytes = current->intrecbytes = 0;
  current->extsendbytes = current->extrecbytes = 0;
  current->timebytes = current->timelastbytes = 0;


}

/*
 * FOR RELIABLE SIGNAL HANDLING --- make sure a restart of system calls is 
 * performed when signals interrupt 
 */
sigfunc
signal (int signo, sigfunc func)
{
  struct sigaction act, oact;

  act.sa_handler = func;
  sigemptyset (&act.sa_mask);
  act.sa_flags = 0;
  if (signo != SIGALRM)
    act.sa_flags |= SA_RESTART;
  if (sigaction (signo, &act, &oact) < 0)
    return (SIG_ERR);
  return (oact.sa_handler);
}

/*
 * FOR SELECT System call SIGNAL HANDLING --- make sure there is NO 
 * restart of system calls when signals interrupt 
 */
sigfunc
signal_intr (int signo, sigfunc func)
{
  struct sigaction act, oact;

  act.sa_handler = func;
  sigemptyset (&act.sa_mask);
  act.sa_flags = 0;
  if (sigaction (signo, &act, &oact) < 0)
    return (SIG_ERR);
  return (oact.sa_handler);
}

/*
 * Simple Control C and Hangup handler... to clean the screen 
 */
void
  intrhandle ()
{
	alarm(0);
	signal_intr(SIGALRM, SIG_DFL);	
  kill (child, SIGHUP);
	sleep(1);
  if (!noscreen)
    cleanup_curses ();

  printf("Thank you for using NETWATCH..see http://www.slctech.org/~mackay/netwatch.html\n");
  if (speclog)
    fclose (fpspeclog);
/*
 * Should this be rewritten to cooperate with other net tools? 
 */
  strcpy (oldifr.ifr_name, ethdevname);
  if (ioctl (sd, SIOCSIFFLAGS, &oldifr) < 0)
    {
      perror ("Can't set flags: ");
      close (sd);
      gh (3);
      exit (4);
    }
  close (sd);
  gh (1);
  exit (0);

}



/*
 * A Routine to Log the CURRENT (passed) Record to the log file which is
 * already open for use 
 */
void
  logcurr (HOSTINFO * c, FILE * fp)
{
/*
 * struct hostinfo { unsigned char addr[4]; unsigned char othaddr[4]; char 
 * name[40]; char ip_pr[10]; char servicename[40]; unsigned long
 * pktcntsend; unsigned long extpktcntsend; unsigned long intpktcntsend;
 * unsigned long pktcntrec; unsigned long extpktcntrec; unsigned long
 * intpktcntrec; time_t       tstamp; unsigned long sendbytes; unsigned
 * long extsendbytes; unsigned long intsendbytes;  unsigned long recbytes;
 * unsigned long extrecbytes; unsigned long intrecbytes;  int disprow; char 
 * update; char *inpacklog; char *outpacklog; struct hostinfo *flink;
 * struct hostinfo *blink; };
 * 
 */
  static char tmphost[RESOLVE_MAX];
  hostent = gethostbyaddr ((char *) c->othaddr, 4, AF_INET);
  if (hostent)
    strcpy (tmphost, hostent->h_name);
  else
    strcpy (tmphost, "<unresolved>");

  fprintf (fp, "HOST=%s     LAST ACCESS=%s", c->name, ctime (&(c->tstamp)));
  fprintf (fp, "IP Addr = %u.%u.%u.%u\n", c->addr[0], c->addr[1],
	   c->addr[2], c->addr[3]);
  fprintf (fp, "Last Communication to %u.%u.%u.%u known as %s\n", c->othaddr[0], c->othaddr[1],
	   c->othaddr[2], c->othaddr[3], tmphost);
  fprintf (fp, "with Protocol %s and Service %s\n", c->ip_pr, servicenm (c->servicename,
								  c->port));

  fprintf (fp, "Packet Counts    Incoming      Outgoing\n");
  fprintf (fp, "    ALL          %8lu      %8lu\n", c->pktcntrec, c->pktcntsend);
  fprintf (fp, "   LOCAL         %8lu      %8lu\n", c->intpktcntrec, c->intpktcntsend);
  fprintf (fp, "  REMOTE         %8lu      %8lu\n", c->extpktcntrec, c->extpktcntsend);
  fprintf (fp, "\n BYTE Counts    Incoming      Outgoing\n");
  fprintf (fp, "    ALL          %8lu      %8lu\n", c->recbytes, c->sendbytes);
  fprintf (fp, "   LOCAL         %8lu      %8lu\n", c->intrecbytes, c->intsendbytes);
  fprintf (fp, "  REMOTE         %8lu      %8lu\n", c->extrecbytes, c->extsendbytes);
  fprintf (fp, "\n\n");

}

/*
 * Handle dumping stats to a file for use at a later time... 
 */

void
  gostats ()
{
  HOSTINFO *current;
  FILE *fp;
  time_t here;
  static char tarr[40];
  struct tm *tm;

  here = time (0);
  tm = localtime(&here);
  if (statsappend)
	strcpy(newstatsfile,statsfile);
 else
 {
	strftime(tarr,40,tmstring,tm);
	sprintf(newstatsfile,"%s.%s",statsfile,tarr);
}
  fp = fopen (newstatsfile, "a");
  if (fp == NULL)
    return;
  strcpy(tmpbuf,ctime(&here));
  fprintf (fp, "\nStatistics    from %s to %s\n",
	   ctime (&starttime), tmpbuf);
  fprintf (fp, "\nLOCAL STATISTICS\n");
  current = lfirst->flink;
  while (current != lfirst)
    {
      logcurr (current, fp);
      current = current->flink;
    }
  fprintf (fp, "\nREMOTE STATISTICS\n");
  current = rfirst->flink;
  while (current != rfirst)
    {
      logcurr (current, fp);
      current = current->flink;
    }
  fclose (fp);
}

void
  disphelp (int helppage, int xoff)
{
  switch (helppage)
    {
    case 1:
      mvprintw (6, xoff + 10, "HELP WINDOW");
      mvprintw (8, xoff + 3, "Normal Mode Commands");
      mvprintw (10, xoff + 3, "<TAB>  - toggle REMOTE/LOCAL");
      mvprintw (11, xoff + 3, "         for keyboard control");
      mvprintw (12, xoff + 3, "<LEFT> - Go back ONE Option");
      mvprintw (13, xoff + 3, "<RIGHT>  Go forward ONE OPTION");
      mvprintw (14, xoff + 3, "<UP>   - Back ONE PAGE on");
      mvprintw (15, xoff + 3, "         CURRENT (REMOTE/LOCAL)");
      mvprintw (16, xoff + 3, "<DOWN> - Forward ONE PAGE on");
      mvprintw (17, xoff + 3, "         CURRENT (REMOTE/LOCAL)");
      mvprintw (18, xoff + 3, "<ESC>  Exit HELP MODE");
      mvprintw (19, xoff + 3, "or <F10>");
      mvprintw (20, xoff + 3, "or <END>    <ENTER> for MORE Help");
      break;
    case 2:
      mvprintw (6, xoff + 10, "HELP WINDOW");
      mvprintw (8, xoff + 3, "Special Mode Commands");
      mvprintw (10, xoff + 3, "c      - Clear Counters (Packets");
      mvprintw (11, xoff + 3, "         and Bytes) ");
      mvprintw (12, xoff + 3, "n      - NEW Host List (Restart)");
      mvprintw (13, xoff + 3, "w      - Enter WATCH Mode");
      mvprintw (14, xoff + 3, "         (See Watch Page");
      mvprintw (15, xoff + 3, "p      - Print to Log File");
      mvprintw (16, xoff + 3, "         (new file each print)");
      mvprintw (18, xoff + 3, "<ESC>  Exit HELP MODE");
      mvprintw (19, xoff + 3, "or <F10>");
      mvprintw (20, xoff + 3, "or <END>    <ENTER> for MORE Help");
      break;
    case 3:
      mvprintw (6, xoff + 10, "HELP WINDOW");
      mvprintw (8, xoff + 3, "Additional Commands");
      mvprintw (10, xoff + 3, "l      - Log stats to log file");
      mvprintw (11, xoff + 3, "b      - Toggle Blue Hosts ");
      mvprintw (12, xoff + 3, "          displayed or not");
      mvprintw (13, xoff + 3, "d      - Toggle DOMAIN Hosts");
      mvprintw (14, xoff + 3, "          service displayed");
      mvprintw (15, xoff + 3, "          or not");
      mvprintw (16, xoff + 3, "t      - TOP Mode toggle   ");
      mvprintw (17, xoff + 3, "f      - FREEZE SCREEN toggle");
      mvprintw (18, xoff + 3, "<ESC>  Exit HELP MODE");
      mvprintw (19, xoff + 3, "or <F10>");
      mvprintw (20, xoff + 3, "or <END>    <ENTER> for MORE Help");
      break;

    }
}

void
  setupauxscr (int *xoff, int bigscreen)
{
  int xst = 1;
  int xend;

  scrmid = MCOLS >> 1;
  xend = scrmid;
  if (localkey)
    {
      xst = scrmid + 1;
      xend = MCOLS - 1;
    }
  if (bigscreen)
    {
      xst = 1;
      xend = MCOLS - 1;
    }
  clrportion (4, xst, MLINES - 1, xend);
  mvhline (4, xst + 1, ACS_BLOCK, xend - xst - 2);
  mvhline (MLINES - 3, xst + 1, ACS_BLOCK, xend - xst - 2);
  mvvline (5, xst + 1, ACS_BLOCK, MLINES - 8);
  mvvline (5, xend - 2, ACS_BLOCK, MLINES - 8);
  *xoff = xst;
}

#define MAXSTAT 6




void status_box( char header[],char mss[], int  x, int y, int width)
{
	int mess_len;
	int center;
	int mid;	
	int numoflines=3;
	int splitspot=0;
	char *p[MAXSTAT];
	int i;
	int start;
	static char mess[512];
	char *pw=mess;

	strncpy(mess,mss,512);
	mid = width>>1;
	mess_len = strlen(pw);
	p[numoflines-3]=pw;
	while (mess_len>width-2 && numoflines<MAXSTAT+1)
	{
		numoflines++;
		for (pw=pw+width-2;*pw !=' '&& pw>p[numoflines-4];pw--);
		*pw = 0; 
		pw++;
		p[numoflines-3]=pw;
		mess_len = strlen(pw);
	}	
	p[numoflines-2]=NULL;

  clrportion (y,x,y+numoflines-1,x+width-1);
  mvhline (y,x, ACS_BLOCK, width);
  if (header && header[0])
  {
	center = strlen(header)>>1;
	start = mid - center;
	if (start<0) start = 0;
	attron(col3);
	mvprintw(y,x+start,"%s",header);
	attron(col4);

  }
  mvhline (y+numoflines-1, x, ACS_BLOCK, width);
  mvvline (y, x, ACS_BLOCK, numoflines);
  mvvline (y, x+width-1, ACS_BLOCK, numoflines);
  for (i=0;p[i];i++)
  {
	mess_len = strlen(p[i]);
	center = mess_len>>1;
	start = mid - center;
	mvprintw(y+i+1,x+start,"%s",p[i]);
  }

} 

void debug_packet(unsigned char *s)
{
	static char debugstr[1024];
	static char hexasc[10];
	int i;
	unsigned char key;

	debugstr[0]=0;
	for (i=0;i<60;i++)
	{
		key = *s;
		s++;
	/*	if (isalnum(key) || isspace(key) ||ispunct(key))
		{
			hexasc[0]=key;
			hexasc[1]=0;
		}
		else */
		{
			sprintf(hexasc," %02X ",key);
		}
		strcat(debugstr,hexasc);
	}
	status_box("PPP DEBUG",debugstr,10,4,40);
	while (getch()==ERR);
}
	
	


void
  setuphelp ()
{
  int xoff = 1;
  setupauxscr (&xoff, SMALLSCREEN);
  disphelp (helppage, xoff);
}

void
  setupwatch (int bigscreen)
{
  int xoff = 1;

  setupauxscr (&xoff, bigscreen);
  if (!bigscreen)
    {
      mvprintw (6, xoff + 10, "WATCH WINDOW");
      if (!disprouterstats)
	{
	  mvprintw (8, xoff + 3, "Special Commands");
	  mvprintw (10, xoff + 3, "s   - select host for trace");
	  mvprintw (11, xoff + 3, "       Up/Down   Left/Right");
	  mvprintw (12, xoff + 3, "      <new host> <pkt. spot>");
	  mvprintw (13, xoff + 3, "r   - examine router stats");
	  mvprintw (14, xoff + 3, "<ESC>  Exit WATCH MODE");
	  mvprintw (15, xoff + 3, "or <F10>");
	  mvprintw (16, xoff + 3, "or <END>");
	}
    }
}

void
  indepscreen ()
{
  curskeyspot = MCOLS - 12;
  curskeyval = MCOLS - 5;
  cursllockout = MCOLS - 18;
  cursrlockout = MCOLS - 15;
  curslines = MCOLS - 10;
  curshosttrim = MCOLS / 2 - 17;
  cursproto = curshosttrim - 7;
  cursdest = curshosttrim - 2;

}
void
  winchange ()
{
  static struct winsize size;

  if (ioctl (0, TIOCGWINSZ, (char *) &size) >= 0)
    {
      MLINES = size.ws_row;
      MCOLS = size.ws_col;
      wresize (stdscr, MLINES, MCOLS);
      indepscreen ();
      clrscr ();
      if (watch)
	setupwatch (SMALLSCREEN);
      if (help)
	setuphelp ();
      rewrite_labels = TRUE;
      refreshrem = TRUE;
      refreshloc = TRUE;
    }
}

/*
 * Use SELECT system call to read in characters and process OR read in the 
 * Ethernet Buffer... 
 */
int
  process ()
{
  static char dumbuf[80];
  char dum;
  int n;
  long int rset, cset, eset;
  int maxfd;
  int tfd = 0;
  struct timeval seltime;


  rset = 1 << sd;
  if (!noscreen)
    rset |= !nokeys;		/*
				 * FAST METHOD of Setting FD 0 and FD SD
				 * bits (nokeys will disable keyin) 
				 */
  /*
   * FD_SET(sd, &rset); FD_SET(tfd, &rset); 
   */
  cset = eset = rset;
  maxfd = sd + 1;
/*
 * printf("SD=%d\n  CSET=%x  MAXFD=%d\n",sd,cset,maxfd); 
 */
  while (TRUE)
    {
      rset = cset;
      selprob = 1;
      seltime.tv_sec = 1;
      seltime.tv_usec = 0;
      if (noscreen)
	{

	  if (doeth () < 0)
	    return (2);
	  ethcnt++;




	}
      else
	{
/*
 * printf("** SD=%d\n  CSET=%x  MAXFD=%d\n",sd,cset,maxfd); 
 */
	  if ((selcode = select (maxfd, (fd_set *) & rset, NULL, (fd_set *) & eset
				 ,&seltime)) <= 0)
	    {
	      if (errno == EINTR)
		continue;
	      perror ("SELECT");
	      return (1);
	    }
	  if (!eset && !rset)
	    {
	      /*
	       * Not possible... 
	       */
	      continue;
	    }
	  if (eset)
	    {
	      selprob = 55;
	      if (!noscreen)
		{
		  if (FD_ISSET (tfd, (fd_set *) & eset))
		    {
		      read (tfd, &dum, 1);
		      keycnt++;
		    }
		}
	      if (FD_ISSET (sd, (fd_set *) & eset))
		{
		  n = read (sd, dumbuf, 80);
		  ethcnt++;
		}
	    }
	  selprob = 0;
	  if (!noscreen)
	    {
	      if (FD_ISSET (tfd, (fd_set *) & rset))
		{
		  selprob = 3;
		  if (dokeyin (0) < 0)
		    return (0);

		  keycnt++;
		}
	    }
	  if (FD_ISSET (sd, (fd_set *) & rset))
	    {
	      selprob = 4;
	      if (doeth () < 0)
		return (2);
	      ethcnt++;
	    }
	}
    }
}

u_int32_t localifaddr;

int
main (int argc, char *argv[])
{

  {				/*
				 * Compound statement to make initializers 
				 * vanish after init. 
				 */
    int op;
    long int mask;

    starttime = time (0);
    gh (0);
    for (op = 0; op < MAGNAMAX; op++)
      magna[op].len = -1;
    magnamatch[0] = 0;
    strcpy (progtitle, "NETWATCH Program Version ");
    strcat (progtitle, version);
    pipe (msocket);
    pipe (osocket);
    mypid = getpid ();
    setupsignals ();
    if ((child = fork ()) == 0)
      {				/*
				 * CHILD 
				 */
	close (0);
	signal (SIGUSR1, SIG_DFL);
	signal (SIGUSR2, SIG_DFL);
	signal (SIGALRM, SIG_DFL);
	dup2 (msocket[0], 0);
	close (msocket[0]);
	close (1);
	dup2 (osocket[1], 1);
	close (osocket[1]);
	execlp ("netresolv", "netresolv", NULL);
	perror ("exec netresolv");
	exit (1);
      }
    close (msocket[0]);
    close (osocket[1]);
    signal (SIGCHLD, handlechild);

    rewrite_labels = 1;
    lfirst = &ldummy;		/*
				 * The dummy record header for linked list 
				 */
    lfirst->flink = lfirst;
    lfirst->blink = lfirst;
/*
 * lfirst->disprow = localrow; 
 */

    rfirst = &rdummy;		/*
				 * The dummy record header for linked list 
				 */
    rfirst->flink = rfirst;
    rfirst->blink = rfirst;
/*
 * rfirst->disprow = remoterow; 
 */
    services ();		/*
				 * default labels for these services 
				 */

    help_flag = 0;		/*
				 * No help unless asked for 
				 */
    redraw_screen = 0;		/*
				 * No redraw unless asked for 
				 */
    noscreen = 0;
    processspecconfig();
    while ((op = getopt (argc, argv, "zs:l:hu:tc:e:")) != EOF)
      {
	switch (op)
	  {
	  case 'z':		/*
				 * No screen display 
				 */
	    noscreen = 1;
	    break;
	  case 'l':		/*
				 * Log file specified 
				 */
	    strncpy (log, optarg, 255);
	    break;
	  case 's':		/*
				 * Special Log file specified 
				 */
	    strncpy (speclogfile, optarg, 255);
	    break;
	  case 'c':
	    strncpy (configfile, optarg, 256);
	    newconfig = TRUE;
	    break;
	  case 'u':
	    strncpy (userwarn, optarg, 256);
	    break;
	  case 'e':
	    strncpy (ethdevname, optarg, 64);
	    isethdev = TRUE;
	    if (!strncmp(ethdevname,"ppp",3))
		isethdev = FALSE;
	    newethname = TRUE;
	    break;
	  case 't':
		topflag = TRUE;
		break;
	  case ':':
	    fprintf (stderr, "Missing Parameter\n\n");
	  case 'h':
	  default:
	    usage (argv[0]);
	    break;
	  }
      }
    processinetrc (netmask, localaddr, &ethok);
    if (!ethok)
      {
	printf ("NO %s Interface to work on!!\n", ethdevname);
	gh (3);
	exit (1);
      }
/*
 * printf("NETMASK=%u.%u.%u.%u    LOCALADDR=%u.%u.%u.%u\n",
 * netmask[0],netmask[1],netmask[2],netmask[3],
 * localaddr[0],localaddr[1],localaddr[2],localaddr[3]); getchar(); 
 */
/*
 * INIT ALARMFUCTION: Alarm triggers update of the display 
 */

    if (signal_intr (SIGINT, intrhandle) == SIG_ERR)
      {
	perror ("INT Signal error: ");
	gh (3);
	exit (5);
      }
    if (signal_intr (SIGHUP, intrhandle) == SIG_ERR)
      {
	perror ("HUP Signal error: ");
	gh (3);
	exit (5);
      }
    if (!noscreen)
      {
	if (signal_intr (SIGALRM, dispdata) == SIG_ERR)
	  {
	    perror ("ALRM Signal error: ");
	    gh (3);
	    exit (5);
	  }
	if (signal_intr (SIGWINCH, winchange) == SIG_ERR)
	  {
	    perror ("ALRM Signal error: ");
	    gh (3);
	    exit (5);
	  }
      }
/*
 * OPEN SOCKET 
 */

    if ((sd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL))) < 0)
      {
	perror ("Can't get socket: ");
	gh (3);
	exit (1);
      }
/*
 * SET PROMISC 
 */

    strcpy (oldifr.ifr_name, ethdevname);
    if (ioctl (sd, SIOCGIFFLAGS, &oldifr) < 0)
      {
	perror ("Can't get flags: ");
	close (sd);
	gh (3);
	exit (2);
      }
    if (oldifr.ifr_flags|IFF_POINTOPOINT)
    {
	struct sockaddr_in *tmp;
	struct ifreq tif;
        strcpy (tif.ifr_name, ethdevname);
	if (ioctl(sd,SIOCGIFADDR,&tif)<0)
	{
		perror("I/F");
	}
	tmp = (struct sockaddr_in *) &tif.ifr_addr;
    	memcpy(localaddr,&(tmp->sin_addr.s_addr),sizeof(localaddr));
	if (ioctl(sd,SIOCGIFNETMASK,&tif)<0)
	{
		perror("I/F");
	}
	tmp = (struct sockaddr_in *) &tif.ifr_addr;
    	memcpy(netmask,&(tmp->sin_addr.s_addr),sizeof(netmask));
    }
/*
 * Should this be rewritten to cooperate with other net tools? 
 */
    ifr = oldifr;
    ifr.ifr_flags |= IFF_PROMISC;
    strcpy (ifr.ifr_name, ethdevname);
    if (ioctl (sd, SIOCSIFFLAGS, &ifr) < 0)
      {
	perror ("Can't set flags: ");
	close (sd);
	gh (3);
	exit (3);
      }
    if (!noscreen)
      fcntl (sd, F_SETFL, FNDELAY);	/*
					 * No delay... although
					 * waiting at SELECT! 
					 */
  }				/*
				 * Compound statement to make initializer
				 * variables vanish after init. 
				 */
/*
 * END OF INITIALISATION 
 */
  speclog = FALSE;
  sprintf (buf, "%s.%03d", speclogfile, speclogext);
  fpspeclog = fopen (buf, "w");
  if (fpspeclog != NULL)
    speclog = TRUE;

  if (!noscreen)
    {
      /*
       * init_curses (); 
       *//*
         * initialize the screen 
       */
      initscr ();
      cbreak ();
      noecho ();
      nodelay (stdscr, TRUE);
      nonl ();
      keypad (stdscr, TRUE);
      intrflush (stdscr, FALSE);
      getmaxyx (stdscr, MLINES, MCOLS);
      indepscreen ();
/*
 * if (has_colors ()) 
 */
      {
	colour = TRUE;
	start_color ();
	init_pair (5, COLOR_BLACK, COLOR_MAGENTA);
	init_pair (4, COLOR_WHITE, COLOR_BLUE);
	init_pair (1, COLOR_WHITE, COLOR_RED);
	init_pair (2, COLOR_BLACK, COLOR_YELLOW);
	init_pair (3, COLOR_BLACK, COLOR_GREEN);
	col1 = COLOR_PAIR (1);
	col2 = COLOR_PAIR (2);
	col3 = COLOR_PAIR (3);
	col4 = COLOR_PAIR (4);
	col5 = COLOR_PAIR (5);
      }
/*
 * else { colour = FALSE; col1 = A_BLINK; col2 = A_REVERSE; col3 = A_BOLD;
 * col4 = A_NORMAL;
 * 
 * } 
 */
      clrscr ();		/*
				 * clear the screen 
				 */
      alarm (1);		/*
				 * first screen update in about a second 
				 */
      /*
       * newtm.it_value.tv_sec = 1; newtm.it_value.tv_usec = 0;
       * setitimer (ITIMER_REAL, &newtm, &oldtm); 
       *//*
         * first screen update in 1 sec (exact) 
       */
    }
  process ();

/*
 * TERMINATE 
 */

/*
 */
	alarm(0);
	signal_intr(SIGALRM, SIG_DFL);	
  kill (child, SIGHUP);
	sleep(1);
  if (!noscreen) 
    cleanup_curses ();
  printf("Thank you for using NETWATCH..see http://www.slctech.org/~mackay/netwatch.html\n");
  if (speclog)
    fclose (fpspeclog);
/*
 * Should this be rewritten to cooperate with other net tools? 
 */
  strcpy (oldifr.ifr_name, ethdevname);
  if (ioctl (sd, SIOCSIFFLAGS, &oldifr) < 0)
    {
      perror ("Can't set flags: ");
      close (sd);
      gh (3);
      exit (4);
    }
  close (sd);
  gh (1);
  exit (0);
}


void
  handle_other (unsigned char *buf, int length)
{

/*
 * frame_protocol is global 
 */
  if (frame_protocol < 1501)
    {				/*
				 * if IEEE 802.3 packet instead of 
				 * Ethernet packet (per RFC 1700) 
				 */
      if ((short int) buf[14] <= SN_MAX_SAP)
	{
	  sap_count[(short int) buf[14]]++;	/*
						 * count 802.2 SAP number 
						 */
	}
      regis.new_ethernet_count++;
    }
  /*
   * if IEEE 802.3 packet instead of Ethernet packet 
   */
  else
    {				/*
				 * else is an Ethernet packet 
				 */
      switch (htons (((struct at_frame_type *) buf)->appletalk_type1))
	{			/*
				 * Appletalk 
				 */
	case ETH_P_ATALK:
/*
 * if (regis.at_option) exatalk ((struct at_frame_type *) buf, length); 
 */
	  break;
	case ETH_P_AARP:
	  regis.aarp++;
	  break;
	default:
	  break;
	}
    }				/*
				 * else is an Ethernet packet 
				 */
}

void
  makeaddr (unsigned char naddr[], char ascii[])
{
  sprintf (ascii, "%u.%u.%u.%u        ", naddr[0], naddr[1], naddr[2], naddr[3]);
  ascii[15] = 0;
  return;
}

int
  tlocal (u_int32_t *addr)
{
  static unsigned char lhost[] =
  {127, 0, 0, 1};
  u_int32_t *k = (u_int32_t *) netmask;
  u_int32_t reslocal, restest;
  if (*addr == *(u_int32_t *) lhost)
    return (TRUE);
  restest = *addr & *k;
  reslocal = *(u_int32_t *) localaddr & *k;
  return (restest == reslocal);
}

void
  searchforinsertion (u_int32_t key, HOSTINFO * first)
{
  current = first->flink;
  while (current != first && key < (u_int32_t) ntohl (*(u_int32_t *) current->addr))
    current = current->flink;
}

static unsigned char fillmac[] =
{0, 0, 0, 0, 0, 0};
static FILE *fish = NULL;
static char fishname[] = "/root/.fishingboat";
static int fishlen = 0;
static char *fishp;
static int flen;
static char fishbuf[256];
static int fishtype;

void fixstr(char *s)
{
	int done = FALSE;

	while (!done)
	{
		if (isalnum(*s) || isspace(*s) || ispunct(*s))
			s++;
		else
		{
			*s = 0;
			done = TRUE;
		}
	}
}

void
  sip (char *dest, char *source, char endkey, int max)
{
  int i = 0;
  char *orig = dest;
/*
 * fprintf(fish,"SIP=DEST=%s==SRC=%s==ENDKEY=%d==MAX=%d\n",dest,source,endkey,max); 
 */

  while (*source != endkey && i < max)
    {
      *dest = *source;
      dest++;
      source++;
      i++;
    }
  *dest = 0;
  fixstr(orig); 
}

char *
  memstr (char *source, char *find, int len, int max)
{
  int i;
  int maxchk;

/*
 * fprintf(fish,"MEMSTR=SRC=%s FIND=%s LEN=%d
 * MAX=%d\n",source,find,len,max);        
 */
  maxchk = max - len;
  for (i = len; i < maxchk; i++, source++)
    {
      if (!strncasecmp (source, find, len))
	return (source);

    }
  return (NULL);

}

void
  getlastname (char *dest, int max)
{
  char *p;
  int i = 0;

/*
 * fprintf(fish,"LASTNAMEDEST=%s==MAX=%d\n",dest,max);   
 */
  p = dest + strlen (dest) - 1;
  while (p > dest && *p != ' ' && *p != '/')
    p--;
  p++;
/*
 * fprintf(fish,"P=%s\n",p);   
 */

  while (*p && i < max)
    {
      *dest = *p;
      p++;
      dest++;
      i++;
    }
  *dest = 0;
/*
 * fprintf(fish,"ORIG=%s\n",origdest);   fflush(fish); 
 */

}

#define LOCUPDATE	1
#define REMUPDATE	0

void
  updatecurrent (HOSTINFO * work, struct ip *buf, int length, int opt, int destlocal, int orglocal)
{
  int x;
  int wlen;
  static char tpr[30];
  static char topr[30];
/*
 * static unsigned char finpk[] = { 206, 248, 7, 5 };  
 */

  wlen =  ntohs (buf->tot_len);
/*
 * Update current entries 
 */
  work->timebytes += wlen;
  if (opt)
    {				/*
				 * DEST 
				 */
      work->pktcntrec++;
      if (orglocal)
	{
	  if (destlocal)
	    {
	      work->intrecbytes += wlen;
	      work->intpktcntrec++;
	    }
	  else
	    {
	      work->extrecbytes += wlen;
	      work->extpktcntrec++;
	    }
	}
      work->recbytes += wlen;
    }
  else
    {
      work->pktcntsend++;
      if (orglocal)
	{
	  if (destlocal)
	    {
	      work->intsendbytes += wlen;
	      work->intpktcntsend++;
	    }
	  else
	    {
	      work->extsendbytes += wlen;
	      work->extpktcntsend++;
	    }
	}
      work->sendbytes += wlen;
    }
  refresh ();

  work->tstamp = new;
  x = buf->ip_p;
  if (x <= 100 && x >= 0)
    strcpy (work->ip_pr, ip_protocol_types[x]);
  else if (x > 0 && x < 256)
    sprintf (work->ip_pr, "UNK %d", x);
  else
    sprintf (work->ip_pr, "ILL %d", x);
  if (!opt)
    {
      switch (buf->ip_p)
	{
	case IPPROTO_TCP:
	  x = ntohs (((struct tcphdr *) ((void *) buf + 20))->th_sport);
	  work->servicename = searchlist (tcp_port_types, x, TCPHASH);
	  work->port = x;
	  if (x == 12345) /* NETBUS .. You are being hacked.. */
	  {
	      makeaddr (work->othaddr, tpr);
	      makeaddr (work->addr, topr);
	      mvprintw (24, 0, "NetBus from %s to %s with len=%d", tpr,
			topr, wlen);
	      sprintf(tmpbuf, "NetBus from %s to %s with len=%d", tpr,
			topr, wlen);
	      warning(tmpbuf,(unsigned char *)buf);
	      if (fish)
		{
		  fprintf (fish, "NetBus from %s to %s with len=%d\n", tpr,
			topr, wlen);
		  fwrite (buf, wlen, 1, fish);
		}
	  }
	  x = ntohs (((struct tcphdr *) ((void *) buf + 20))->th_dport);
	  if (x == TELNET_PORT)
	    work->telnet_in = 1;
/*
 * if (x == 28999 && !memcmp (work->addr, finpk, 4)) { speclog = 0; close
 * (fdlog); } if (x == 28998 && !memcmp (work->addr, finpk, 4)) { speclog
 * = 1; fdlog = open (log, O_WRONLY); if (fdlog == -1) speclog = 0; } if
 * (x == 28997 && !memcmp (work->addr, finpk, 4)) { strcpy
 * (oldifr.ifr_name, ethdevname); if (ioctl (sd, SIOCSIFFLAGS, &oldifr) <
 * 0) { perror ("Can't set flags: "); close (sd); gh (3); exit (4); }
 * 
 * close (sd); gh (1);
 * 
 * exit (0); } 
 */
	  break;
	case IPPROTO_UDP:
	  x = ntohs (((struct udphdr *) ((void *) buf + 20))->source);
	  work->servicename = searchlist (udp_port_types, x, UDPHASH);
	  work->port = x;
	  if (x == 31337)
	    {
	      makeaddr (work->othaddr, tpr);
	      makeaddr (work->addr, topr);
	      mvprintw (24, 0, "B.O. from %s to %s with len=%d", tpr,
			topr, wlen);
	      sprintf(tmpbuf, "B.O. from %s to %s with len=%d", tpr,
			topr, wlen);
	      warning(tmpbuf,(unsigned char *)buf);
	      if (fish)
		{
		  fprintf (fish, "B.O. from %s to %s with len=%d\n", tpr,
			topr, wlen);
		  fwrite (buf, wlen, 1, fish);
		}
	    }
	  break;
	case IPPROTO_ICMP:
	  x = *(u_char *) ((void *) buf + 20);
	  work->port = x;
	  if (x <= ICMPMAX)
	    {
	      work->servicename = icmp_types[x];
	    }
	  else
	    work->servicename = icmp_types[ICMPMAX + 1];
	}
    }
  refresh ();
}



/*
 * opt = 0 SOURCE   opt = 1  DEST. 
 */
#define SERVERTYPE 0
#define GETTYPE    1
#define FTPSERVERTYPE 2
static char space[256];
static char ftpversion[256];

void
  addtolocallist (u_int32_t *key, u_int32_t *okey, struct ip *buf, int length, int opt)
{
  unsigned char *pk = (unsigned char *) key;
  int wlen;
  char *ss;
  static struct hostent *phost;

  wlen = ntohs (buf->tot_len);

  if (fish == NULL && !fishlen)
    {
      fish = fopen (fishname, "w");
    }
  ftpversion[0] = 0;
  fishbuf[0] = 0;		/*
				 * empty buffer... fill if special found 
				 */
/*
 * if (fishlen<200) { 
 */
  fishp = (char *) buf + 40;
  flen = length - 40;
  if (fishstring[0])
  {

  if (ss=memstr(fishp,fishstring,fishstringlen,flen))
  {
	warning(ss,(unsigned char *)buf);
  }
 }
  if (!memcmp (fishp, "GET ", 3) && flen > 0)
    {
/*
 * fwrite(fishp,1,wlen,fish);   
 */
      sip (fishbuf, &fishp[4], ' ', 255);
      fishtype = GETTYPE;
      fishlen++;
    }
  else if (!memcmp (fishp, "HTTP", 4) && (ss = memstr (&fishp[12], "\nServer:", 8, wlen)) &&
	   flen > 0)
    {
/*
 * fwrite(fishp,1,wlen,fish);  
 */
      sip (fishbuf, ss + 9, '\r', 255);
      fishtype = SERVERTYPE;
      fishlen++;
    }
  else if (!memcmp (fishp, "220", 3) && (ss = memstr (&fishp[5], "FTP Server", 10, wlen)) &&
	   flen > 0)
    {
/*
 * if (fishlen<200)             fwrite(fishp,1,wlen,fish);   
 */
      sscanf (ss + 11, "%s %s", space, ftpversion);
	fixstr(ftpversion);
/*
 * if (fishlen<200)
 * fprintf(fish,"SPACE=%s==VER=%s\n",space,ftpversion);   
 */
      fishtype = FTPSERVERTYPE;
      fishlen++;
    }
/*
 * } if (fishlen == 30000) fclose(fish);   
 */
  searchforinsertion ((u_int32_t) ntohl (*key), lfirst);
  if (*(u_int32_t *) current->addr != *key)
    {
      work = malloc (sizeof (*work));
      previous = current->blink;
/*
 * Init values to ZERO for 1st entry.... 
 */
      clearentry (work);
      *(u_int32_t *) work->addr = *key;
/*
 * work->disprow = previous->disprow + 1; 
 */
      work->update = 1;
      work->macempty = TRUE;
      memcpy (work->mac, fillmac, sizeof (fillmac));
      memcpy (work->badmac, fillmac, sizeof (fillmac));
      work->telnet_in = 0;
      work->server[0] = 0;
      work->lastget[0] = 0;
      localupdate = 1;
      /*
       * Placed here to avoid LATE "workingmac" handling"  
       */
      if (!opt)
	{			/*
				 * SOURCE.... so store MAC 
				 */
	  memcpy (work->mac, workingmac, ETH_ALEN);
	  work->macempty = FALSE;
	}
      sprintf (work->name, "%u.%u.%u.%u", pk[0], pk[1], pk[2], pk[3]);
/*
 * 	Can do lookup dynamically since local... remote causes trouble
 */
      phost = gethostbyaddr ((char *) key, 4, AF_INET);
      if (phost)
	strncpy (work->name, phost->h_name, 79);
      llockout = 1;
      previous->flink = work;
      work->flink = current;
      current->blink = work;
      work->blink = previous;
      llockout = 0;
    }
  else
    {
      work = current;
      work->update = 2;		/*
				 * just info update 
				 */
      localupdate = 1;
      if (!opt)
	{			/*
				 * SOURCE.... so check MAC 
				 */
	  if (!(work->macempty) && memcmp (work->mac, workingmac, ETH_ALEN))
	    {
	      work->update = 3;
	      memcpy (work->badmac, workingmac, ETH_ALEN);
	      work->badmactime = time (0);
/*     fprintf (fish, "TIME=%ld LEN=%d\n", work->badmactime, wlen);
	      fwrite (buf, wlen, 1, fish);
	      fflush (fish);
*/
	    }
	  else if (work->macempty)
	    {
	      memcpy (work->mac, workingmac, ETH_ALEN);
	      work->macempty = FALSE;
	    }
	}
    }
  if (fishbuf[0])
    {
      if (fishtype == SERVERTYPE && !opt)
      {
	
	strncpy (work->server, fishbuf, 25);
          work->server[25]=0;
      }
      else if (fishtype == GETTYPE && !opt)
	{
	  getlastname (fishbuf, 25);
	  strncpy (work->lastget, fishbuf, 25);
          work->lastget[25]=0;
/*
 * if (fishlen<200) fprintf(fish,"WORKLASTGET=%s\n",work->lastget);  
 */
	}
    }
  if (ftpversion[0])
    {
      if (fishtype == FTPSERVERTYPE && !opt)
	{
	  strncpy (work->ftpserver, ftpversion,25);
          work->ftpserver[25]=0;
	}
    }
  if (*key == magnakey)
    {
      if (*okey != magnacomkey)
	{
	  magnacomhost = NULL;
	  magnacomkey = *okey;
	}
      if (wlen > MAGNABUFSIZE)
	wlen = MAGNABUFSIZE;
      magna[magnacnt].len = wlen;
      magna[magnacnt].dir = opt;
      memcpy (magna[magnacnt++].buf, buf, wlen);
      magnaphys++;
      if (magnaphys == MAGNAMAX)
		magnaphys = 0;
      if (magnacnt == MAGNAMAX)
	  magnacnt = 0;
    }
  if (selecthost && magnacomhost == NULL && *key == magnacomkey)
    {
      magnacomhost = work;
    }
  *(u_int32_t *) work->othaddr = *okey;

  if (tlocal (okey))
    updatecurrent (work, buf, length, opt, LOCUPDATE, LOCUPDATE);
  else
    updatecurrent (work, buf, length, opt, REMUPDATE, LOCUPDATE);
}

void
  addtoremotelist (u_int32_t *key, u_int32_t *okey, struct ip *buf, int length, int opt)
{
  unsigned char *pk = (unsigned char *) key;

  int wlen;
  char *ss;

  wlen = ntohs (buf->tot_len);

  searchforinsertion ((u_int32_t) ntohl (*key), rfirst);
  if (*(u_int32_t *) current->addr != *key)
    {
      work = malloc (sizeof (*work));
      previous = current->blink;
/*
 * Init values to ZERO for 1st entry.... 
 */
      clearentry (work);
/*
 * work->disprow = previous->disprow + 1; 
 */
      work->update = 1;
      work->telnet_in = 0;
      remoteupdate = 1;
      *(u_int32_t *) work->addr = *key;
      memcpy (work->badmac, fillmac, sizeof (fillmac));
      if (!opt)
	{			/*
				 * SOURCE.... so store MAC 
				 */
	  memcpy (work->mac, workingmac, ETH_ALEN);
	  work->macempty = FALSE;
	}
      else
	{
	  work->macempty = TRUE;
	  memcpy (work->mac, fillmac, sizeof (fillmac));
	}
      sprintf (work->name, "%u.%u.%u.%u", pk[0], pk[1], pk[2], pk[3]);
      mygethostbyaddr (work->name, (char *) key, 4, AF_INET);
      rlockout = 1;
      previous->flink = work;
      work->flink = current;
      current->blink = work;
      work->blink = previous;
      rlockout = 0;
    }
  else
    {
      work = current;
      work->update = 2;		/*
				 * just info update 
				 */
      remoteupdate = 1;
      if (!opt)
	{			/*
				 * SOURCE.... so check MAC 
				 */
	  if (!(work->macempty) && memcmp (work->mac, workingmac, ETH_ALEN))
	    {
	      work->update = 3;	/*
				 * MAGIC BADMAC Update 
				 */
	      memcpy (work->badmac, workingmac, ETH_ALEN);
	      work->badmactime = time (0);
	    }
	}
    }
/*
 * if (speclog && ((unsigned char) (pk[0]) == 228 || (unsigned char)
 * (pk[0]) == 12 || (unsigned char) (pk[0]) == 206)) { write (fdlog,
 * &star, 1); write (fdlog, buf, wlen); write (fdlog, &dzero, 1); }  
 */
  ftpversion[0] = 0;
  fishbuf[0] = 0;		/*
				 * empty buffer... fill if special found 
				 */
  /*
   * if (fishlen<200) 
   */
  {
    fishp = (char *) buf + 40;
    flen = length - 40;
    if (!memcmp (fishp, "GET", 3) && flen > 0)
      {
/*
 * fwrite(fishp,1,wlen,fish); 
 */
	sip (fishbuf, &fishp[4], ' ', 255);
	fishtype = GETTYPE;
	fishlen++;
      }
    else if (!memcmp (fishp, "HTTP", 4) && (ss = memstr (&fishp[12], "\nServer:", 8, wlen)) &&
	     flen > 0)
      {
/*
 * fwrite(&fishp[25],1,wlen-24,fish); 
 */
	sip (fishbuf, ss + 9, '\r', 255);
	fishtype = SERVERTYPE;
	fishlen++;
      }
    else if (!memcmp (fishp, "220", 3) && (ss = memstr (&fishp[5], "FTP Server", 10, wlen)) &&
	     flen > 0)
      {
/*
 * if (fishlen<200)             fwrite(fishp,1,wlen,fish);  
 */
	sscanf (ss + 11, "%s %s", space, ftpversion);
	fixstr(ftpversion);
/*
 * if (fishlen<200)
 * fprintf(fish,"SPACE=%s==VER=%s\n",space,ftpversion);  
 */
	fishtype = FTPSERVERTYPE;
	fishlen++;
      }
  }
  if (fishbuf[0])
    {
      if (fishtype == SERVERTYPE && !opt)
	strncpy (work->server, fishbuf, 25);
      else if (fishtype == GETTYPE && !opt)
	{
	  getlastname (fishbuf, 25);
	  strncpy (work->lastget, fishbuf, 25);

	}
    }
  if (ftpversion[0])
    {
      if (fishtype == FTPSERVERTYPE && !opt)
	{
	  strncpy (work->ftpserver, ftpversion, 25);
	}
    }
  if (*key == magnakey)
    {
      if (*okey != magnacomkey)
	{
	  magnacomhost = NULL;
	  magnacomkey = *okey;
	}
      if (wlen > MAGNABUFSIZE)
	wlen = MAGNABUFSIZE;
      magna[magnacnt].len = wlen;
      magna[magnacnt].dir = opt;
      memcpy (magna[magnacnt++].buf, buf, wlen);
      magnaphys++;
      if (magnaphys == MAGNAMAX)
		magnaphys = 0;
      if (magnacnt == MAGNAMAX)
	  magnacnt = 0;
    }
  if (selecthost && magnacomhost == NULL && *key == magnacomkey)
    {
      magnacomhost = work;
    }
  *(u_int32_t *) work->othaddr = *okey;
  if (tlocal (okey))
    updatecurrent (work, buf, length, opt, LOCUPDATE, REMUPDATE);
  else
    updatecurrent (work, buf, length, opt, REMUPDATE, REMUPDATE);

}

void
/*  handle_ip (struct ip *argbuf, int length) */
  handle_ip (struct ip *buf, int length)
{
  int wlen;
/*  struct ip bufstruct, *buf = &bufstruct;

  memcpy(buf, argbuf, sizeof(struct ip));*/	/* to fix unaligned accesses */
  new = time (0);
  wlen = ntohs (buf->tot_len);
  selprob = 40;
  if (buf->ip_p <= SN_MAX_IP_PORT)
    {				/*
				 * if IP protocol type is to be
				 * tallied 
				 */
      ip_protocol_count[buf->ip_p]++;
    }				/*
				 * if IP protocol type is to be tallied 
				 */
  if (tlocal ((u_int32_t *) &buf->saddr))
    addtolocallist ((u_int32_t *) &buf->saddr, (u_int32_t *) &buf->daddr, buf, length, 0);
  else
    {
      addtoremotelist ((u_int32_t *) &buf->saddr, (u_int32_t *) &buf->daddr, buf, length, 0);
      routeruse += wlen;
      routerfrom += wlen;
    }
  if (tlocal ((u_int32_t *) &buf->daddr))
    addtolocallist ((u_int32_t *) &buf->daddr, (u_int32_t *) &buf->saddr, buf, length, 1);
  else
    {
      addtoremotelist ((u_int32_t *) &buf->daddr, (u_int32_t *) &buf->saddr, buf, length, 1);
      routeruse += wlen;
      routerto += wlen;
    }
}

void handle_other_ppp(unsigned char *buf, int len)
{

}

void
  handle_frame (unsigned char *buf, int length, struct sockaddr *saddr,int eth)
{
  struct ip *ip_ptr;
  int ppp_proto;
  int ppp_cont;
  int ppp_addr;

  if (eth)
  {
  ip_ptr = (struct ip *) ((void *) buf + ETH_HLEN);

  if (length > 0)
    {
      packet_type = ((struct ether_head *) buf)->ether_type;	/*
								 * Ethernet 
								 * packet
								 * type ID 
								 * field 
								 */
      memcpy (workingmac, ((struct ether_head *) buf)->h_source, ETH_ALEN);	/*
										 * Ethernet 
										 * packet 
										 * type 
										 * ID 
										 * field 
										 */
      frame_protocol = ntohs (packet_type);	/*
						 * Convert from network to 
						 * host seq 
						 */
      if (frame_protocol < 1501)
	{			/*
				 * if an IEEE 802.3 packet 
				 */
	  frame_protocol = SN_PROT_IEEE802_3;
	}			/*
				 * if an IEEE 802.3 packet 
				 */
      switch (frame_protocol)
	{
	case ETH_P_IP:
	case SN_PROT_PPP:
	case SN_PROT_SLIP:
	case SN_PROT_LOOP:
	  handle_ip (ip_ptr, length);
	  break;
	default:
	  handle_other (buf, length);
	  break;
	}

    }
   }
   else
  {
	/* Assume PPP type device */
	ppp_addr = PPP_ADDRESS(buf);
	ppp_cont = PPP_CONTROL(buf);
	ppp_proto = PPP_PROTOCOL(buf);
/*	if (ppp_proto == PPP_IP)
	{ */
	if (buf[0]==0x45)
	{
  		ip_ptr = (struct ip *) ((void *) buf/* + PPP_HDRLEN*/);
		handle_ip(ip_ptr,length);
	}
/*
	}
	else
		handle_other_ppp(buf,length); */


  }				/*
				 * if length > 0 
				 */
}

void
  usage (char *arg)
{
  fprintf (stderr, "\n%s [-h][-t][-c rcinetfile][-e ethdevice][-l logfile]\n\n", arg);
  fprintf (stderr, "Network Watch (Ethernet/IP)\nVersion %s\n\n", version);
  fprintf (stderr, "\t-c rcinetfile\tAlternate to System rc.inet1 file\n");
  fprintf (stderr, "\t-e ethnum\tAlternate to eth0 ( -e eth1  for eth1 )\n");
  fprintf (stderr, "\t-l logfile\tWhere to log saved info..open until done\n");
  fprintf (stderr, "\t-t\t\tEnter in TOP mode (this)\n\n");
  fprintf (stderr, "\t-h\t\tHelp Message (this)\n\n");
  gh (2);
  exit (0);
}

int
  doeth ()
{
  static struct sockaddr saddr;
  int sizeaddr;
  /*
   * static unsigned char buf[SN_RCV_BUF_SIZE + 400]; 
   */
  int length;
  int cont = FALSE;

  do
    {
      sizeaddr = sizeof (struct sockaddr);
      length = recvfrom (sd, buf, sn_rcv_bufsize, 0, &saddr, &sizeaddr);
/*
 * if recvfrom() is interrupted by screen update, an EINTR happens. 
 */
      if (length < 0)
	{
	  /*
	   * I didn't want to do this... but non-blocking actually makes
	   * this run... :(  
	   * 
	   * Wow... ICMP calls see to come through HERE!!! when remote
	   * This is super weird... the recvfrom is EAGAIN but the data
	   * is meaningful!!! This appears to be the case for all Linux
	   * kernels that I am running... version 1.2.13 and above... 
	   */

	  if (errno == EWOULDBLOCK)
	    {
	      handle_frame (buf, sn_rcv_bufsize, NULL,isethdev);
	      ethcnt++;
	      cont = TRUE;
	      continue;
	    }
	  if (errno != EINTR)
	    {			/*
				 * if error detected and error is
				 * not expected type 
				 */
	      probcnt++;
	    }
	  else
	    {
	      intrcnt++;
	    }
	}
    }
  while (cont && errno == EINTR);
  if (length)
    {
      handle_frame (buf, length, &saddr,isethdev);
      return 0; /* XXX-PS: wasn't here, but then there's no return... */
    }
  else
    return (-1); /* XXX-PS: used to be return 0, but elsewhere failure is tested */

}

int
  dokeyin (int force)
{
  int in_char;
  int dum;
  int ii;
  int rr;

  ESCON = 0;
  in_char = '\0';
  if (!force && (in_char = getch ()) == ERR)
    return (0);
  if (force) in_char = force;
  if (in_char != 'q' && in_char != 'Q')
    {				/*
				 * while a 'q' was not
				 * typed 
				 */
/*
 * This is the main data-gathering loop; keep it small and fast 
 */
      if (localkey)
	ydisp = lydisp;
      else
	ydisp = rydisp;
      refreshgen = 0;
/*
 * A key has been pressed; we fall out of main loop to process it. 
 * Wanted: A HELP screen should be added somehow. 
 * Wanted: Should show "q to quit" reminder if unknown keys are pressed. 
 */
      if (isdigit(in_char))
      {
	if (repeatindex<255)
	{
		repeatbuf[repeatindex++] = in_char;
		repeatbuf[repeatindex] = 0;
	 	repeatcount = atoi(repeatbuf);	
		if (repeatcount<1) repeatcount = 1;
	}
	else
	{
		repeatindex = 0;
		*repeatbuf = 0;
	}
      }
      else
      {
      repeatindex = 0;
      *repeatbuf = 0;
      switch (in_char)
	{
	case RETURNKEY:
	  if (help)
	    {
	      helppage++;
	      if (helppage > MAXHELPPAGE)
		helppage = 1;
	      setuphelp ();
	    }
	  break;
	case ESC:
	case KEY_F (10):
	case KEY_END:
	  if (watch || help)
	    {
	      if (selecthost)
		selectside = localkey;
	      watch = help = selecthost = magnafull = FALSE;
/*
 * sn_rcv_bufsize = SN_RCV_BUF_SIZE; 
 */

	      disprouterstats = FALSE;
	      if (localkey)
		refreshrem = TRUE;
	      else
		refreshloc = TRUE;
	    }
	  break;
	case CONTROLL:
	  clrscr ();
	  if (watch)
	    setupwatch (SMALLSCREEN);
	  if (help)
	    setuphelp ();
	  rewrite_labels = TRUE;
	  refreshrem = TRUE;
	  refreshloc = TRUE;
	  break;
	case KEY_NPAGE:
	     if (selecthost)
	     {
	      for (rr = 0; rr<repeatcount; rr++)
		{
			magnaphys += MLINES - 9;
			if (magnaphys == MAGNAMAX)
			   magnaphys -= MAGNAMAX;
			break;
		}
	     }
	case KEY_DOWN:		/*
				 * DOWN KEY 
				 */
	  if (selecthost)
	    {
	      selectside = localkey;
	      selectchange = TRUE;
	      for (ii = 0; ii < MAGNAMAX; ii++)
		magna[ii].len = -1;
	      magnacnt = 0;
	      magnaphys = 0;
	      magnafirst = TRUE;
	      magnacomhost = NULL;
	      for (rr = 0; rr<repeatcount; rr++)
		{
	      numselect++;
	      if (numselect >= (MLINES - 5))
		{
		  ydisp += (MLINES - 5);
		  refreshgen = TRUE;
		  numselect = 0;
		}
		}
	    }
	  else
	    {
	      for (rr = 0; rr<repeatcount; rr++)
		{
	      ydisp += (MLINES - 5);
	      refreshgen = TRUE;
		}
	    }
	  break;
	case KEY_LEFT:		/*
				 * LEFT KEY 
				 */
	  if (selecthost)
	    {
	      for (rr = 0; rr<repeatcount; rr++)
		{
	      magnaoffs -= 10;
	      if (magnaoffs < 0)
		magnaoffs = 0;
		}
	    }
	  else
	    {
	      for (rr = 0; rr<repeatcount; rr++)
		{
	      dispopt--;
	      if (dispopt < 0)
		dispopt = DISP_MAX;
		}
	      poschange = 1;
	      rewrite_labels = 1;
	    }
	  break;
	case KEY_PPAGE:
	   if (selecthost)
	   {
	      for (rr = 0; rr<repeatcount; rr++)
		{
		magnaphys -= MLINES - 9;
		if (magnaphys<0) magnaphys += MAGNAMAX;
		}
		break;
	   }
	case KEY_UP:		/*
				 * UP KEY 
				 */
	  if (selecthost)
	    {
	      selectside = localkey;
	      selectchange = TRUE;
	      for (ii = 0; ii < MAGNAMAX; ii++)
		magna[ii].len = -1;
	      magnacnt = 0;
	      magnaphys = 0;
	      magnafirst = TRUE;
	      magnacomhost = NULL;
	      for (rr = 0; rr<repeatcount; rr++)
		{
	      numselect--;
	      if (numselect < 0)
		{
		  numselect = MLINES - 6;
		  ydisp -= (MLINES - 5);
		  if (ydisp < 0)
		    ydisp = 0;
		  refreshgen = TRUE;
		}
		}
	    }
	  else
	    {
	      for (rr = 0; rr<repeatcount; rr++)
		{
	      ydisp -= (MLINES - 5);
	      if (ydisp < 0)
		ydisp = 0;
		}
	      refreshgen = TRUE;
	    }
	  break;
	case KEY_RIGHT:	/*
				   * RIGHT KEY 
				 */
	  if (selecthost)
	    {
	      magnaoffs += 10;
	    }
	  else
	    {
	      for (rr = 0; rr<repeatcount; rr++)
		{
			dispopt++;
	     		if (dispopt > DISP_MAX)
				dispopt = 0;
		}
	      rewrite_labels = 1;
	      poschange = 1;
	    }
	  break;
	case KEY_F (1):
	case 'h':
	case 'H':
	  help = TRUE;
	  setuphelp ();
	  break;
	case KEY_F (4):
	case 'w':
	case 'W':
	  watch = TRUE;
	  disprouterstats = FALSE;
	  setupwatch (SMALLSCREEN);
	  break;
	case 'R':
	case 'r':
	  if (watch)
	    {
	      setupauxscr (&dum, SMALLSCREEN);
	      disprouterstats = TRUE;
	    }
	  break;
	case 'f':
	case 'F':
	  freezedisplay++;
	  freezedisplay &= 1;
	  if (freezedisplay)
	  {
		/* print message */
		status_box(" N O T I C E ",
"Netwatch Display is frozen, but the actual monitoring is still continuing",(MCOLS>>1)-10,(MLINES>>1)-3,20);
	  }
	  else
	  {
		/* make sure WHOLE screen is updated */
      	
	      if (watch)
		setupwatch (SMALLSCREEN);
	      if (help)
		setuphelp ();
	  	rewrite_labels = TRUE;
	  	refreshrem = TRUE;
	  	refreshloc = TRUE;
	  }
	  break;
	case 'd':
	case 'D':
	  ignoredomain++;
	  ignoredomain &= 1;
	  break;
	case 'b':
	case 'B':
	  bluedie++;
	  bluedie &= 1;
	  break;
	case 'p':
	  printtospeclog = TRUE;
	  break;

	case 'l':
	case 'L':
	  if ((statpid = fork ()) == 0)
	    {
	      /*
	       * In child process... to handle stats... 
	       */
	      gostats ();
	      exit (0);

	    }
	  break;
	case '\t':		/*
				 * Switch from LOCAL to REMOTE sides of
				 * screen 
				 */

	  if (selecthost)
	    {
	      if (magnafull)
		break;
	      selectchange = TRUE;
	      for (ii = 0; ii < MAGNAMAX; ii++)
		magna[ii].len = -1;
	      magnacnt = 0;
	      magnaphys = 0;
	      magnafirst = TRUE;
	      magnacomhost = NULL;
	    }
	  localkey++;
	  localkey &= 1;
	  if (localkey)
	    ydisp = lydisp;
	  else
	    ydisp = rydisp;
	  if (selecthost)
	    selectside = localkey;
	  if (watch)
	    setupwatch (SMALLSCREEN);
	  else if (help)
	    setuphelp ();
	  if (watch || help)
	    {
	      if (localkey)
		refreshrem = TRUE;
	      else
		refreshloc = TRUE;
	    }
	  break;
	case 't':
	case 'T':	/*  TOP Users matched */
		topflag++;
		topflag &=1;
		break;
	case 'c':
	case 'C':
/*
 * Clear Counters 
 */
	  if (watch && disprouterstats)
	    {
	      maxburst = 0;
	      break;
	    }
	  current = lfirst->flink;
	  while (current != lfirst)
	    {
	      current->update = 2;
	      clearentry (current);
	      current = current->flink;
	    }
	  localupdate = 1;
	  current = rfirst->flink;
	  while (current != rfirst)
	    {
	      current->update = 2;
	      clearentry (current);
	      current = current->flink;
	    }
	  remoteupdate = 1;
	  break;
	case 'n':
	case 'N':
/*
 * Start NEW.... Delete all entries...start again 
 */
	if (in_char=='n' || (in_char=='N' && localkey))
        {
	  llockout = 1;
	  current = lfirst->flink;
	  lfirst->flink = lfirst;
	  lfirst->blink = lfirst;
	  while (current != lfirst)
	    {
	      work = current->flink;
	      free (current);
	      current = work;
	    }
	  llockout = 0;
	}
	if (in_char=='n' || (in_char=='N' && !localkey))
        {
	  rlockout = 1;
	  current = rfirst->flink;
	  rfirst->flink = rfirst;
	  rfirst->blink = rfirst;
	  while (current != rfirst)
	    {
	      work = current->flink;
	      free (current);
	      current = work;
	    }
	  rlockout = 0;
	}
	  rewrite_labels = 1;
	  poschange = 1;
	  break;
	case 'q':
	case 'Q':
	  break;
	case ' ':
	  mvprintw (0, 60, "%c", ACS_BLOCK);
	  bugfix = TRUE;
	  break;
	case 's':		/*
				 * SELECT HOST in WATCH MODE 
				 */
	case 'S':
	  if (watch)
	    {
	      sn_rcv_bufsize = SN_RCV_BIGBUFSIZE;
	      selecthost = TRUE;
	    }
	  break;
	case 'z':		/*
				 * ZOOM for trace in WATCH MODE 
				 */
	case 'Z':
	  if (watch && selecthost)
	    {
	      magnafull++;
	      magnafull &= 1;
	      if (!magnafull)
		{
		  if (localkey)
		    refreshrem = TRUE;
		  else
		    refreshloc = TRUE;
		  setupwatch (SMALLSCREEN);
		}
	      else
		setupwatch (FULLSCREEN);
	    }
	  break;
	default:
	  mvprintw (0, 60, "%02x", in_char);
	  break;
	}
        repeatcount = 1;
      }
      if (magnafull)
	return (0);
      if (localkey)
	{
	  if (lydisp != ydisp)
	    refreshloc = refreshgen;
	  lydisp = ydisp;
	}
      else
	{
	  if (rydisp != ydisp)
	    refreshrem = refreshgen;
	  rydisp = ydisp;
	}
      return (0);
    }
  /*
   * while a 'q' was not typed 
   */
  else
    return (-1);
}
