/*
 *
 * bbd.c 
 * BIG BROTHER DAEMON PROGRAM
 * Version 1.9b
 * Mar 28th, 2002
 *
 * (c) Copyright Quest Software, Inc.  1997-2002  All rights reserved. 
 *
 * This daemon just listens on a port, accepts single lines of input
 * and handles them.  It doesn't send any acknowledgements back...
 *
 * Two types of actions are possible, depending on the content we get:
 *
 *	1.	Input for the display monitor
 *	2.	Request to send a page to the admin
 */


#include "bb.h"		/* THE BIG BROTHER INCLUDE FILE */
#include <errno.h>
#include <sys/stat.h>
#include <ctype.h>
#ifdef TIMEH
#include <time.h>
#else
#include <sys/time.h>
#endif
#include <utime.h>	/* SMM NEW */
#include <dirent.h>
#ifdef SCO3
#include <unistd.h>
#endif

char bbprog[] = "bbd";

/* OLD
struct in_addr securedb[MAXLINE];
*/

struct sec {
	struct in_addr addr;
	struct in_addr mask;
};

/*
 * OK... THIS IS NOW AN ARRAY OF ADDRESSES AND NETMASKS
 */
struct sec secdb[MAXLINE];

char *bbhome;
int  fqdn;
char bblogsdir[MAXLINE];	/* DIRECTORY TO PUT LOG FILES INTO */
char bbhistdir[MAXLINE];	/* DIRECTORY TO PUT HISTORY FILES INTO */
char bbhistlogsdir[MAXLINE];	/* DIRECTORY TO PUT HISTORICAL LOG FILES INTO */
char bbhtmldir[MAXLINE];	/* DIRECTORY TO PUT HTML FILES INTO */
char bbwebdir[MAXLINE];		/* DIRECTORY WHERE HTML STATUS PAGE's FOOTER & HEADER CAN BE FOUND */
char bbtmpdir[MAXLINE];		/* TEMPORARY WORK DIRECTORY */
char *bbpid;			/* BBD PID FILE */
char security[MAXLINE];		/* WHERE THE BBD SECURITY FILE LIVES */
char pager[MAXLINE];		/* BB-PAGER PROGRAM LOCATION */
char bb[MAXLINE];		/* BB  PROGRAM LOCATION */
char *machineaddr;		/* IP ADDRESS OF CURRENT HOST (IP or DNS) */
char *bbpage;			/* IP ADDRESS OF BB PAGER - 0.0.0.0 if multiple */
char *bbpagers;			/* IP ADDRESS OF BB PAGERS */
char *bbdisp;			/* IP ADDRESS OF BB DISPLAY - 0.0.0.0 if multiple */
char *bbdisplays;		/* IP ADDRESS OF BB BBDISPLAYS */
char bbdisabledir[MAXLINE];	/* DIRECTORY TO PUT DISABLED HOSTS INTO */
char allhistname[MAXLINE];	/* NAME OF FILE THAT CONTAINS EVENTS LOG SUMMARY FOR ALL LOG EVENTS */
char bbdatadir[MAXLINE];	/* DIRECTORY TO PUT DATA FILES INTO */
char bbnotesdir[MAXLINE];	/* DIRECTORY TO PUT NOTES FILES INTO */
char bbvardir[MAXLINE];		/* DIRECTORY LEVEL FOR bbvar/ */
char bbacksdir[MAXLINE];	/* DIRECTORY TO PUT ACKS LOG FILES INTO */
char bb_hosts[MAXLINE];		/* LOCATION OF bb-hosts file */

char *bbdisplay;		/* SET TO TRUE IF HOST IS A BBDISPLAY */
char *bbpager;			/* SET TO TRUE IF HOST IS A BBPAGER */
char *bbrelays;			/* HOSTS TO RELAY MESSAGES TO */

char *pagelevels;
char *savestatuslog;
char *bbweb;
char *bbhosthistlog;		/* SAVE HISTORICAL LOG PER HOST ? */
char *bballhistlog;		/* SAVE HISTORICAL LOG FOR ALL HOSTS ? */

char *ipdotaddr;		/* IP address of the end connection in dot notation */

char *recvfromstrp;
char *statunchstrp;
char *bblogstatus;
char *perioddays;
char *periodhours;
char *periodmins;

int purpleoffset;

static char bbdisplays_env[MAXLINE];                 /* Static variable for putenv() of BBDISPLAYS */

#ifdef SIGSETJMP
sigjmp_buf jmpenv;
#else
jmp_buf jmpenv;
#endif

void do_bb();
void bblog();

char *gettimestr();

void loadfiles()
{
extern int getheader(), getfooter();

	getheader(bbwebdir,NULL);
	getfooter(bbwebdir,NULL);

	/*
	 * BB SECURITY ENHANCEMENT
	 * ALLOW BB TO RESTRICT ACCESS BASED ON A LIST OF 
	 * NUMERIC HOSTS/MASKS LOCATED IN etc/security
	 */
	getsecurity();			/* GET VALID HOSTS AND MASKS */

	/* Reset the signal */
	signal(SIGHUP, (void *)loadfiles);

}

/*
 * Return the # of seconds defined by the setting
 *
 * XXX - in minutes (x60)
 * XXXs - in seconds (x1)
 * XXXm - in minutes (x60)
 * XXXh - in hours (x1440)
 *
 * when no qualifier is specified, it is taken as in minutes
 *
 */

int calc_purple_offset(validfor)
char *validfor;
{
int offsetval;
int offset;
int qualifierpos;
char validstr[MAXLINE];

	if( !validfor || (strlen(validfor) == 0) )
		return(-1);

	/* Keep a fresh copy of validfor */
	/* Thanks to Michael Salmon <Michael.Salmon@uab.ericsson.se> */
	memset(validstr,0,sizeof(validstr));
	strncpy(validstr,validfor,MAXLINE-1);

#if DEBUG
	debug("calc_purple_offset() - validfor: <%s>  validstr: <%s>\n",validfor,validstr);
	fflush(stdout);
#endif

        offsetval = 60;         /* Default, in minutes so multiply by 60 to make it in seconds */
        qualifierpos = strlen(validstr)-1;

#if DEBUG
	debug("calc_purple_offset() - offsetval: <%d>  qualifierpos: <%d>\n",offsetval,qualifierpos);
	fflush(stdout);
#endif

	if( isalpha(validstr[qualifierpos]) ) {
		validstr[qualifierpos] = tolower(validstr[qualifierpos]);
#if DEBUG
	debug("calc_purple_offset() - validstr[qualifierpos]: <%c>\n",tolower(validstr[qualifierpos]));
	fflush(stdout);
#endif
		if( tolower(validstr[qualifierpos]) == 's' )
			offsetval = 1;
		else if( tolower(validstr[qualifierpos]) == 'm' )
			offsetval = 60;
		else if( tolower(validstr[qualifierpos]) == 'h' )
			offsetval = 3600;
		else if( tolower(validstr[qualifierpos]) == 'd' )
			offsetval = 86400;
		validstr[qualifierpos] = '\0';
	}
#if DEBUG
	debug("calc_purple_offset() - validstr: <%s> offsetval: <%d>\n",validstr,offsetval);
	fflush(stdout);
#endif
	offset = atoi(validstr);
	offset *= offsetval;

#if DEBUG
	debug("calc_purple_offset() - returns: <%d>\n",offset);
	fflush(stdout);
#endif

        return(offset);
}

int enable_disable(req,flags)
char *req;
int  flags;
{
char	*msgtype;
char	hostexp[MAXLINE], duration[MAXLINE], msg[MAXLINE];
char	errormsg[MAXLINE],*workptr;
char	request[MAXLINE];
char	logfilename[MAXLINE],bbhostslist[MAXLINE];
int	ftype,count,rc;
DIR	*dirinfo;
char	bbmsg[MAXLINE];
char	filemask[MAXLINE];
#ifdef SCO3
pid_t child;
#else
int child;
#endif
int	status;

	if( !req ) {
		return(0);
	}
	if( !( (flags & BB_DISABLEMSG) || (flags && BB_ENABLEMSG)) ) {
		return(0);
	}

#if DEBUG
	fprintf(stderr,"enable/disable: request <%s> flags <%d>\n",req,flags);
	fflush(stderr);
#endif

	if( flags & BB_DISABLEMSG ) {
		msgtype = "disable";
	}
	else {
		msgtype = "enable";
	}

	stripleadtrailspaces(req);

	if( strlen(req) == 0 ) {
		bb_errmsg(msgtype,"Null request");
		return(0);
	}

	memset(request,0,sizeof(request));
	strncpy(request,req,sizeof(request)-1);

	if( strlen(request) >= (sizeof(request)-1) ) {
		bb_errmsg(msgtype,"Request truncated, exceeded maximum length");
	}

	memset(hostexp,0,sizeof(hostexp));
	memset(duration,0,sizeof(duration));
	memset(msg,0,sizeof(msg));

	sscanf(request,"%s",hostexp);
	workptr = request + strlen(hostexp);
	stripleadspaces(workptr);

	if( flags & BB_DISABLEMSG ) {
		sscanf(workptr,"%s",duration);
		if( strlen(duration) == 0 ) {
			bb_errmsg(msgtype,"Duration value missing");
			return(0);
		}
		workptr = workptr + strlen(duration);
		stripleadspaces(workptr);
		if( !match(duration,"[0-9][0-9]*",REG_FULL) ) {
			if( !match(duration,"[0-9][0-9]*[smhdSMHD]",REG_FULL) ) {
				sprintf(errormsg,"Invalid duration value: <%s>",duration);
				bb_errmsg(msgtype,errormsg);
				return(0);
			}
		}
		/*
		 * If the duration is 0, then stop (why disable for 0 seconds ?)
		 */
		if( match(duration,"0*",REG_FULL) 
			|| match(duration,"[0]*[smhdSMHD]",REG_FULL) ) {
			sprintf(errormsg,"Invalid duration value: <%s>",duration);
			bb_errmsg(msgtype,errormsg);
			return(0);
		}
		if( strlen(workptr) > 0 ) {
			strncpy(msg,workptr,sizeof(msg)-1);
		}
#if DEBUG
		fprintf(stderr,"disable: hosts exp <%s> duration <%s> reason <%s>\n",hostexp,duration,msg);
		fflush(stderr);
#endif
	}
	else {
		if( strlen(workptr) > 0 ) {
			bb_errmsg(msgtype,"Invalid arguments provided, ignored");
		}
#if DEBUG
		fprintf(stderr,"enable: hosts exp <%s>\n",hostexp);
		fflush(stderr);
#endif
	}

	/*
	 * offline message should only go to local BBDISPLAY that started this script
	 * and ALL BBPAGERS ... This way we're sure that there's no SPOF
	 * to receive an offline message for the BBPAGERS.
	 * Don't send duplicate messages when BBDISPLAY == BBPAGER
	 * All hosts are saved in bbhostslist
	 */
#if DEBUG
	fprintf(stderr,"enable/disable: bbpage <%s> bbpagers <%s> machineaddr <%s>\n",bbpage,bbpagers,machineaddr);
	fflush(stderr);
#endif
	memset(bbhostslist,0,sizeof(bbhostslist));
	if( strcmp(bbpage,"0.0.0.0") == 0 ) {
		if( strlen(bbpagers) > 0 ) {
			strcpy(bbhostslist,bbpagers);
		}
		replacestr(bbhostslist,sizeof(bbhostslist),machineaddr,"");
		if( strlen(bbhostslist) > 0 ) {
			strcat(bbhostslist," ");
		}
	}
	else {
		if( strcmp(bbpage,machineaddr) != 0 ) {
			strcpy(bbhostslist,bbpage);
			strcat(bbhostslist," ");
		}
	}
	strcat(bbhostslist,machineaddr);
	replacestr(bbhostslist,sizeof(bbhostslist),"0.0.0.0","");
	stripleadtrailspaces(bbhostslist);

#if DEBUG
	fprintf(stderr,"enable/disable: bbhostslist <%s>\n",bbhostslist);
	fflush(stderr);
#endif

	if( strlen(bbhostslist) == 0 ) {
		 bb_errmsg(msgtype,"Null BBDISPLAY list, aborted");
		return(0);
	}

	bb_putenv("BBDISPLAYS",bbhostslist,bbdisplays_env,sizeof(bbdisplays_env));

	/* Get each log filename in $BBLOGS */      
	count = 0;
	if( strcmp(hostexp,"*") == 0 ) {
		strcpy(hostexp,".*");
	}
	sprintf(filemask,"%s",hostexp);
	dirinfo = NULL;
	rc = getdirfirst(&dirinfo,bblogsdir,filemask,logfilename,GETDIR_FILE,&ftype);
	while( rc == 1 ) {
		/* Don't do files that start with '.' */
		if( logfilename[0] == '.' ) {
			goto nextfile;
		}
		/* Don't do summary logs ... */
		if( strncmp(logfilename,"summary.",strlen("summary.")) == 0 ) {
			goto nextfile;
		}
		/* Send BB message */
		if( flags & BB_DISABLEMSG ) {
			/* offline */
			sprintf(bbmsg,"offline %s %s",logfilename,duration);
			if( strlen(msg) > 0 ) {
				strcat(bbmsg," ");
				strncat(bbmsg,msg,sizeof(msg)-1-strlen(bbmsg));
			}
		}
		else {
			/* online */
			sprintf(bbmsg,"online %s",logfilename);
		}
#if DEBUG
		fprintf(stderr,"enable/disable: bbsend(<%s>,<%s>)\n",bbhostslist,bbmsg);
		fflush(stderr);
#endif


		if ((child = fork()) < 0) bbd_die("fork error");
		/* child does work, thanks to svangari@uu.net */
		if (child == 0) {                       /* THE CHILD */
			/* For ZOMBIE prone OSes, use the bb exec instead of bbsend() */
			/* The reason is if bbsend() gets stuck, then the whole bbd */
			/* waits for the child process to end */
#ifdef ZOMBIE
			execlp(bb, bb, "0.0.0.0", bbmsg, (char *)NULL);
#else
			rc = bbsend("0.0.0.0",bbhostslist,bbmsg);
			exit(rc);
#endif
		}
		/* Parent continues */
#ifdef ZOMBIE
		wait(&status);
#endif

		count++;
nextfile:
		rc = getdirnext(dirinfo,bblogsdir,filemask,logfilename,GETDIR_FILE,&ftype);
	}

	bb_putenv("BBDISPLAYS",bbdisplays,bbdisplays_env,sizeof(bbdisplays_env));

	getdirdone(dirinfo);

	if( count == 0 ) {
		bb_errmsg(msgtype,"No match");
		return(0);
	}

	return(1);
}

void bb_online(req)
char *req;
{
char host[MAXLINE];
char filename[MAXLINE];

	if( strlen(req) > (MAXLINE - 2) ) {
#if DEBUG
		debug("<%s> ONLINE MSG IS TOO LARGE\n",req);
		fflush(stdout);
#endif
		return;
	}

	/* sscanf() goes before valid_logname check */
	/* Thanks to Dominique FRISE <Dominique.Frise@ci.unil.ch> */
	sscanf(req,"%s",host);

	if( !valid_logname(host) ) {
		fprintf(stderr,"%s bbd INVALID FILENAME SPECIFIED IN online MESSAGE: %s\n",gettimestr(),host);
		fflush(stderr);
		return;
	}

	sprintf(filename,"%s/%s",bbdisabledir,host);

	unlink(filename);
}

void bb_offline(req)
char *req;
{

}

void bbsave(req,type)
char *req,*type;
{
FILE *fp;
char filemode[5], *dataptr;
char filename[MAXLINE],*fname;
char filepath[MAXLINE];
int rc;

	if( strcmp(type,"data") == 0 ) {
		/* For "data" we append */
		strcpy(filemode,"a+");
	}
	else if( strcmp(type,"notes") == 0 ) {
		/* For "notes" overwrite */
		strcpy(filemode,"w+");
	}
	else {
		/* It ain't "data" or "notes", get out */
		return;
	}

	/* Check filename validity */
	/* Remove the basename from it */
	filename[0] = '\0';
	rc = sscanf(req,"%s",filename);
	if( rc != 1 ) {
		return;
	}

	fname = (char *) strrchr(filename,'/');
	if( fname == NULL ) {
		fname = filename;	/* Set to filename */
	}
	else {
		fname++;		/* Skip slash */
	}

	/* Name can't start with '.' , '-' or non-print character */
	if( *fname == '.' || *fname == '-' || !isprint(*fname) ) {
		return;
	}

	/* Do we have any real data ? */
	dataptr = (char *) strstr(req,filename);
	if( dataptr == NULL ) {
		/* This should never happen */
		return;
	}

	/* Position at character right after the name */
	dataptr += strlen(filename);

	while( isspace(*dataptr) ) {
		dataptr++;
	}

	/* End of string == No data */
	if( *dataptr == '\0' ) {
		return;
	}

	if( strcmp(type,"data") == 0 ) {
		/* For "data" we append */
		sprintf(filepath,"%s/%s",bbdatadir,fname);
	}
	else if( strcmp(type,"notes") == 0 ) {
		/* For "notes" overwrite */
		sprintf(filepath,"%s/%s",bbnotesdir,fname);
	}

	/* Try to open the file */
	if( (fp=fopen(filepath,filemode)) == NULL ) {
		return;
	}

	fprintf(fp,"%s\n",dataptr);

	fclose(fp);

	return;
}

void bb_utime(filename,timestamp)
char *filename;
time_t timestamp;
{
struct utimbuf tb;

	tb.actime = timestamp;
	tb.modtime = timestamp;

	utime(filename, &tb);
}

/* RETURN VALUES:
 *
 * 0 - not disabled
 * 1 - disabled
 *
 */

int bb_isdisabled(filename)
char *filename;
{
char disfname[MAXLINE];
struct stat statbuf;
int statres;
time_t timenow;

	/* TRY TO STAT THE EVENT IN THE /disabled DIRECTORY */
       	sprintf(disfname, "%s/%s", bbdisabledir, filename);

#if DEBUG
	debug("disfname: %s\n",disfname);
	fflush(stdout);
#endif

	statres=stat(disfname, &statbuf);

	time(&timenow);			/* GET THE TIME */

	/* IS FILE IN disabled/ DIRECTORY */
	if( statres == 0 ) {
#if DEBUG
		debug("%s exists !\n",disfname);
		fflush(stdout);
#endif
		/* YUP, HAS IT EXPIRED ? */
		if( statbuf.st_mtime < timenow ) {
			/* YUP, REMOVE IT, IT'S NOT NEEDED ANYMORE */
#if DEBUG
			debug("%s has expired, remoing it !\n",disfname);
#endif
			unlink(disfname);
		}
		else {
			/* DISABLING STILL IN EFFECT DON'T DO ANYTHING ELSE */
			return(1);
		}
	}
	return(0);
}

/*
 * 0 - Error
 * 1 - Successful 
 */
int save_histlog(histlogdirname,timenowbuf,logdata,dur,sentby)
char *histlogdirname;
char *timenowbuf;
char *logdata;
char *dur;
char *sentby;
{
char	filename[MAXLINE],*fname,*svc,workfname[MAXLINE],*workptr;
struct stat	statinfo;
FILE *fp;

	fname = (char *) strrchr(histlogdirname,'/');
	if( fname ) {
		fname++;
		if( !*fname ) {
			fprintf(stderr,"%s bbd Invalid histlog file directory name: %s\n",gettimestr(),histlogdirname);
			fflush(stderr);
			return(0);
		}
		strcpy(workfname,fname);
	}
	else {
		strcpy(workfname,histlogdirname);
	}
	svc = (char *) strchr(workfname,'.');
	if( !svc ) {
		fprintf(stderr,"%s bbd Invalid histlog file directory name: %s\n",gettimestr(),histlogdirname);
		fflush(stderr);
		return(0);
	}
	*svc = '\0';
	svc++;
	if( !*svc ) {
		fprintf(stderr,"%s bbd Invalid histlog file directory name: %s\n",gettimestr(),histlogdirname);
		fflush(stderr);
		return(0);
	}

	while( (workptr=(char *)strchr(workfname,',')) != NULL ) {
		*workptr = '_';
		workptr++;
	}
	sprintf(filename,"%s/%s",bbhistlogsdir,workfname);
	if( stat(filename,&statinfo) != 0 ) {
		if( mkdir(filename,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0 ) {
			fprintf(stderr,"%s bbd Cannot create <%s> directory\n",gettimestr(),filename);
			fflush(stderr);
			return(0);
		}
	}
	strcat(filename,"/");
	strcat(filename,svc);
	if( stat(filename,&statinfo) != 0 ) {
		if( mkdir(filename,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0 ) {
			fprintf(stderr,"%s bbd Cannot create <%s> directory\n",gettimestr(),filename);
			fflush(stderr);
			return(0);
		}
	}

	/* At most only one space */
	strcpy(workfname,timenowbuf);
	replacestr(workfname,sizeof(workfname)-1,"  "," ");
	while( (workptr=(char *)strchr(workfname,' ')) != NULL ) {
		*workptr = '_';
		workptr++;
	}
	strcat(filename,"/");
	strcat(filename,workfname);

	if( (fp=fopen(filename,"w")) == NULL ) {
		fprintf(stderr,"%s bbd Cannot create <%s> file\n",gettimestr(),filename);
		fflush(stderr);
		return(0);
	}
	fprintf(fp,"%s\n\n%s%s", logdata, dur,sentby);
	fclose(fp);

	return(1);
}

#ifndef FUNCINFUNCOK
/*
 * BBD ALARM
 */
static void bbd_timeout()
{
	fprintf(stderr,"%s bbd Connection hung from %s (dropped)\n", gettimestr(), ipdotaddr);
	exit(1);
}
#endif

int main(argc, argv)
int argc;
char *argv[];
{
#ifdef SCO3
	pid_t child;
#else
	int child;
#endif
 	int status, sockfd, newsockfd, port, len, ttllen;
        struct sockaddr_in serv_addr, cli_addr;
	static char linebuf[MAXLINE];
	static char msgbuf[MAXLINE];		/* INCOMING MESSAGE BUFFER */
	char msgbuf_relay[MAXLINE];		/* OUTGOING RELAY MESSAGE BUFFER */
	int on=1;
	struct in_addr inc;
	char *bbtmpvar,*bblogsvar,*bbdisabledvar,*bbhistvar,*bbhistlogsvar,*bbdatavar,*bbacksvar,*bbhostsvar,*fqdnval;
	FILE *bbf;
	char *purpledelay;
	int dorecv;
	int truncated;				/* SMM */

#ifdef FUNCINFUNCOK
/*
 * BBD ALARM
 */
static void bbd_timeout()
{
	if( strlen(msgbuf) > 0 ) {
		fprintf(stderr,"%s bbd Connection terminated from %s (partial message)\n", gettimestr(), ipdotaddr);
#ifdef SIGSETJMP
		siglongjmp(jmpenv,1);
#else
		longjmp(jmpenv,1);
#endif
	}
	else {
		fprintf(stderr,"%s bbd Connection hung from %s (dropped)\n", gettimestr(), ipdotaddr);
		exit(1);
	}
}
#endif

#if DEBUG
	debug("*** Starting bbd ***: PID %d - PPID %d\n",getpid(), getppid());
#endif

	machineaddr=(char *)getenv("MACHINEADDR");
	if (!machineaddr || strlen(machineaddr) == 0 ) {
		fprintf(stderr,"%s bbd MACHINEADDR is not set in the environment! Make sure you're running bbd from runbb.sh!\n",gettimestr());
		exit(1);
	}

	bbpager=(char *)getenv("BBPAGER");
	if(!bbpager) {
		bbpager = "";
	}

	bbpage=(char *)getenv("BBPAGE");
	if (!bbpage || strlen(bbpage) == 0 ) {
		fprintf(stderr,"%s bbd BBPAGE is not set in the environment! Make sure you're running bbd from runbb.sh!\n",gettimestr());
		exit(1);
	}

	bbpagers=(char *)getenv("BBPAGERS");
	if(!bbpagers) {
		bbpagers = "";
	}

	bbdisplay=(char *)getenv("BBDISPLAY");
	if(!bbdisplay) {
		bbdisplay = "";
	}

	bbdisp=(char *)getenv("BBDISP");
	if (!bbdisp || strlen(bbdisp) == 0 ) {
		fprintf(stderr,"%s bbd BBDISP is not set in the environment! Make sure you're running bbd from runbb.sh!\n",gettimestr());
		exit(1);
	}

	bbdisplays=(char *)getenv("BBDISPLAYS");
	if(!bbdisplays) {
		bbdisplays = "";
	}

	bbrelays=(char *)getenv("BBRELAYS");
	if(!bbrelays) {
		bbrelays = "";
	}
	stripleadtrailspaces(bbrelays);	

	bbhome=(char *)getenv("BBHOME");
	if (bbhome) {
		len=strlen(bbhome);
		if (len > MAXLINE - 50) {		/* CHECK THIS... */
			fprintf(stderr,"%s bbd BBHOME is too large - go away!\n",gettimestr());
			exit(1);
		}
		/* BBTMP wasn't used in bbd, now it is ;) */
		/* thanks to Leonid Massarskiy <lmassars@mediapartnerships.com>  */
		/* for pointing this out */
		bbtmpvar=(char *)getenv("BBTMP");
		if (!bbtmpvar || (strlen(bbtmpvar) == 0) ) {
			fprintf(stderr,"%s bbd BBTMP is not set in the environment!  $BBHOME/tmp will be used\n",gettimestr());
			fflush(stderr);
			sprintf(bbtmpdir,"%s/tmp",bbhome);
		}
		else {
			strcpy(bbtmpdir,bbtmpvar);	
		}

		/* Get where the logs are saved (BBLOGS) */
		bblogsvar=(char *)getenv("BBLOGS");
		if (!bblogsvar || (strlen(bblogsvar) == 0) ) {
			fprintf(stderr,"%s bbd BBLOGS is not set in the environment!\n",gettimestr());
			exit(1);
		}
		else {
			sprintf(bblogsdir, "%s", bblogsvar);
		}

		/* Get where the disable tag files are saved (BBDISABLE) */
		bbdisabledvar=(char *)getenv("BBDISABLED");
		if (!bbdisabledvar || (strlen(bbdisabledvar) == 0) ) {
			fprintf(stderr,"%s bbd BBDISABLED is not set in the environment!\n",gettimestr());
			exit(1);
		}
		else {
			sprintf(bbdisabledir, "%s", bbdisabledvar);
		}

		/* Get where the hist files are saved (BBHIST) */
		bbhistvar=(char *)getenv("BBHIST");
		if (!bbhistvar || (strlen(bbhistvar) == 0) ) {
			fprintf(stderr,"%s bbd BBHIST is not set in the environment!\n",gettimestr());
			exit(1);
		}
		else {
			sprintf(bbhistdir, "%s", bbhistvar);
		}

		/* Get where the historical log files are saved (BBHIST) */
		bbhistlogsvar=(char *)getenv("BBHISTLOGS");
		if (!bbhistlogsvar || (strlen(bbhistlogsvar) == 0) ) {
			fprintf(stderr,"%s bbd BBHISTLOGS is not set in the environment!\n",gettimestr());
			exit(1);
		}
		else {
			sprintf(bbhistlogsdir, "%s", bbhistlogsvar);
		}

		/* Get where the datafiles are saved (BBDATA) */
		bbdatavar=(char *)getenv("BBDATA");
		if (!bbdatavar || (strlen(bbdatavar) == 0) ) {
			fprintf(stderr,"%s bbd BBDATA is not set in the environment!\n",gettimestr());
			exit(1);
		}
		else {
			sprintf(bbdatadir, "%s", bbdatavar);
		}

		/* Get where the  acks log files are saved (BBACKS) */
		bbacksvar=(char *)getenv("BBACKS");
		if (!bbacksvar || (strlen(bbacksvar) == 0) ) {
			fprintf(stderr,"%s bbd BBACKS is not set in the environment!\n",gettimestr());
			exit(1);
		}
		else {
			sprintf(bbacksdir, "%s", bbacksvar);
		}

		/* Get where the BBPID file is located */
		bbpid=(char *)getenv("BBPID");
		if (!bbpid || (strlen(bbpid) == 0) ) {
			fprintf(stderr,"%s bbd BBPID is not set in the environment!\n",gettimestr());
			exit(1);
		}

		/* Get where the bb-hosts file live (BBHOSTS) */
		bbhostsvar=(char *)getenv("BBHOSTS");
		if (!bbhostsvar || (strlen(bbhostsvar) == 0) ) {
			fprintf(stderr,"%s bbd BBHOSTS is not set in the environment!\n",gettimestr());
			exit(1);
		}
		else {
			sprintf(bb_hosts, "%s", bbhostsvar);
		}

		sprintf(allhistname,"%s/allevents",bbhistdir);
		sprintf(bbhtmldir, "%s/www/html", bbhome);
        	sprintf(security, "%s/etc/security", bbhome);
		sprintf(bbwebdir, "%s/web", bbhome);
		sprintf(pager, "%s/bin/bbpage", bbhome);
		sprintf(bb, "%s/bin/bb", bbhome);
		sprintf(bbnotesdir, "%s/www/notes", bbhome);
	}
	else {
		fprintf(stderr,"%s bbd BBHOME is not set in the environment! Make sure you're running bbd from runbb.sh!\n",gettimestr());
		exit(1);
	}

	fqdnval = (char *) getenv("FQDN");
	if( fqdnval == NULL ) {
		fqdn = 1;
	}
	else {
		if( strlen(fqdnval) == 0 ) {
			fqdn = 1;
		}
		else if( strcmp(fqdnval,"TRUE") == 0 ) {
			fqdn = 1;
		}
		else {
			fqdn = 0;
		}
	}

	pagelevels= (char *) getenv("PAGELEVELS");
	if ( pagelevels == NULL )
		pagelevels="";
	savestatuslog = (char *) getenv("SAVESTATUSLOG");
	if ( savestatuslog == NULL )
		savestatuslog="";
	bbweb = (char *) getenv("BBWEB");
	if ( bbweb == NULL )
		bbweb="";

	purpledelay = (char *) getenv("PURPLEDELAY");
	if ( purpledelay == NULL ) {
		purpledelay = "30";
		purpleoffset = 30 * 60;
	}
	else {
		purpleoffset = 0;
		/* Use abs for PURPLEDELAY */
		/* Thanks to Jon Monroe <jon_monroe@sportsmvp.com> */
		if( purpleoffset <= 0 ) {
			purpleoffset = 30 * 60;
		}
		else {
			purpleoffset = calc_purple_offset(purpledelay);
		}
	}
#if DEBUG
	debug("purpledelay: <%s>  purpleoffset: <%d>\n",purpledelay,purpleoffset);
	fflush(stdout);
#endif

	bbhosthistlog = (char *) getenv("BBHOSTHISTLOG");
	if ( bbhosthistlog == NULL )
		bbhosthistlog="";

	bballhistlog = (char *) getenv("BBALLHISTLOG");
	if ( bballhistlog == NULL )
		bballhistlog="";

	recvfromstrp= (char *) getenv("RECVFROMMSG");
	if( recvfromstrp == NULL )
		recvfromstrp = "Status message received from";

	statunchstrp= (char *) getenv("STATUNCHMSG");
	if( statunchstrp == NULL )
		statunchstrp = "Status unchanged in";

	bblogstatus = (char *) getenv("BBLOGSTATUS");
	if( bblogstatus == NULL )
		bblogstatus = "STATIC";

	perioddays= (char *) getenv("DAYS");
	if( perioddays == NULL )
		perioddays = "days";
	periodhours= (char *) getenv("HOURS");
	if( periodhours == NULL )
		periodhours = "hours";
	periodmins= (char *) getenv("MINS");
	if( periodmins == NULL )
		periodmins = "minutes";

	port = PORT;

#if DEBUG
        debug("MAKING SOCKET CONNECTION...\n");
#endif
        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                fprintf(stderr, "%s bbd Can't open socket\n",gettimestr());
		exit(1);
        }
#if DEBUG
        debug("SOCKET CONNECTED OK... : %d\n",sockfd);
#endif

	/*
	 * FINALLY FIX THE REUSE BUGLET
	 * THANKS TO Gary Mills <mills@cc.UManitoba.CA>
	 */
	(void)setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);

        bzero((char *) &serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_addr.sin_port = htons(port);

#if DEBUG
        debug("BINDING TO SOCKET...\n");
#endif
        if (bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0) {
		/* DON'T HARDCODE PORT NUMBER: frank@bluegrass.net */
                fprintf(stderr,"%s bbd: Can't bind to port %d - is bbd already running?\n", gettimestr(), port);
		exit(2);
        }
#if DEBUG
        debug("SOCKET BOUND OK...\n");
#endif

        /*
	 * NOW THE PARENT EXITS AND THE CHILD DETACHES FROM THE CONTROLLING TTY
	 * SET UP TO IGNORE SIGNALS SENT BY EXITING CHILDREN
         */

        if ((child = fork()) != 0) {
#if DEBUG
        	debug("TRYING TO OPEN BBFILE %s\n", bbpid);
#endif
        	bbf = fopen(bbpid, "w");
		if (bbf) {
			fprintf(bbf, "%d \n", child);
			fclose(bbf);
		}
		exit(0);             /* PARENT EXITS */
	}

	setsid();					/* RELEASE TTY */

#ifndef ZOMBIE
        signal(SIGCHLD, SIG_IGN);
#endif

	/* Load up the standard header/footer file */
	signal(SIGHUP, (void *)loadfiles);
	loadfiles();

	/*
	 * NOW SET UP THE LISTENING LOOP
         */
        listen(sockfd, 250);

        for ( ;; ) {

#if DEBUG
		debug("about to accept()\n");
#endif
                len = sizeof(cli_addr);
                newsockfd = accept(sockfd,(struct sockaddr*)&cli_addr,&len);
		/*
		 * THANKS TO Marc L. Allen (allen@chesapeake.rps.slb.com)
		 */

                if (newsockfd < 0 ) {
#if DEBUG
        		debug("accept(): %d : %d\n", newsockfd, errno);
#endif
                        if (errno == EINTR) continue;
			else {
				/* 
				 * Jac Kersing *kersing@the-box.com)
				 * Just retry. Might be a killed client 
				 */
				sleep(5);
				/* On some OS you must reset */
				signal(SIGHUP, (void *)loadfiles);
				continue;
			}
		}

  		/*
                 * SMM BBD SECURITY CHECK
                 */
                inc.s_addr = cli_addr.sin_addr.s_addr;
		ipdotaddr = (char *)inet_ntoa( cli_addr.sin_addr );
#if DEBUG
                debug("INCOMING CONNECTION FROM: %u - %s\n", inc.s_addr,ipdotaddr);
#endif

		if (checksecurity(&inc) == 0) { /* FAIL */
                	fprintf(stderr,"%s bbd Incoming message from %u - %s refused\n",gettimestr(),(unsigned int)inc.s_addr,ipdotaddr);
			fflush(stderr);
			close(newsockfd);
			continue;
		}

		/*
		 * NOW FORK OFF AND LET THE CHILD HANDLE THE REQUEST
 		if ((child = fork()) < 0) bbd_die("fork error"); 
		 */
 		if ((child = fork()) < 0) fprintf(stderr, "ARRRGH!!! THE FORK ERROR!\n");

		if (child != 0) {			/* THE PARENT */
			close(newsockfd);
#ifdef ZOMBIE
#if DEBUG
			debug("WAIT FOR CHILD EXIT...\n");
#endif
			wait(&status);
#if DEBUG
			debug("CLEANED UP CHILD: %d\n", status);
#endif
#endif /* ZOMBIE */
		}
		else {					/* THE CHILD */
			/* No funnies if someone tries SIGHUPping the child */
			signal(SIGHUP, SIG_IGN);
			close(sockfd); 
			/*
			 * NOW GET THE LINE FROM THE CLIENT
			 * AND HANDLE THE REQUEST...
			 * IGNORE BAD DATA...
			 * 1.07c ADDED SUPPORT FOR MESSAGES UP TO 8K
			 */
			ttllen = 0;
			memset(msgbuf,'\0',sizeof(msgbuf));
			memset(linebuf,'\0',sizeof(linebuf));
#if DEBUG
			debug("NEW INCOMING MESSAGE\n");
#endif

			/*
			 * THIS IS TO HANDLE CONNECTIONS THAT GET
			 * "STUCK" - MOSTLY NT TALKING TO SOLARIS
			 * THANKS TO jrivel@dti.net 
			 */
			dorecv = 1;
			truncated = 0;
			signal(SIGALRM, (void *)bbd_timeout);
			alarm(5);	/* SMM */
#ifdef SIGSETJMP
			if (sigsetjmp(jmpenv,1) != 0) {
#else
			if (setjmp(jmpenv) != 0) {
#endif
				/* The connection hung but partial data came in */
				/* Continue on but skip over recv() call */
				dorecv = 0;
			}
			while ( dorecv && ((len = recv(newsockfd, linebuf, MAXLINE - 1, 0)) > 0) && (ttllen != -1)) {
				alarm(5);	/* SMM */
				linebuf[len]='\0';		/* FOR ANDREY */
#if DEBUG
				debug("MESSAGE LEN: %d TOTAL: %d\n", len, ttllen);
#endif
				/* 
				 * IF IT'S GOING TO BE TOO BIG... 
				 * THE 30 CHARS IS FOR THE TRUNCATED MSG 
				 */
				if (ttllen + len + 30 > (MAXLINE-1)) {
					truncated = 1;	 	/* SMM */
					len = MAXLINE - ttllen - 30;
					if ( len > 0 ) {
						memcpy(msgbuf+ttllen, linebuf, len);
					}
					ttllen = ttllen + len;
					*(msgbuf+ttllen) = '\0';
					break;
				}
				else { /* SMM MAKE THIS NULL-SAFE */
					if( len > 0 ) {
						memcpy(msgbuf+ttllen, linebuf, len);
					}
					ttllen = ttllen + len;
					*(msgbuf+ttllen) = '\0';
					memset(linebuf,'\0',sizeof(linebuf));
				}
			}
			alarm(0);

			if (ttllen != 0) {
				if (truncated == 1) {
 					strcat(msgbuf, "\n\n... DATA TRUNCATED ...\n"); /* 25 chars ! */
/* 
					fprintf(stderr, "SIZEOF STRLEN MSGBUF %d %d\n", sizeof(msgbuf), strlen(msgbuf));
*/
				}
#ifndef DONTCLEANSTRING
				replacestr(msgbuf,sizeof(msgbuf),"&red","^red");
				replacestr(msgbuf,sizeof(msgbuf),"&green","^green");
				replacestr(msgbuf,sizeof(msgbuf),"&yellow","^yellow");
				replacestr(msgbuf,sizeof(msgbuf),"&purple","^purple");
				replacestr(msgbuf,sizeof(msgbuf),"&clear","^clear");
				replacestr(msgbuf,sizeof(msgbuf),"&blue","^blue");
#ifdef NOTAMP
				clean_string(msgbuf,"`$;|\\",'_');
#else
				clean_string(msgbuf,"`$;|&\\",'_');
#endif
				replacestr(msgbuf,sizeof(msgbuf),"^red","&red");
				replacestr(msgbuf,sizeof(msgbuf),"^green","&green");
				replacestr(msgbuf,sizeof(msgbuf),"^yellow","&yellow");
				replacestr(msgbuf,sizeof(msgbuf),"^purple","&purple");
				replacestr(msgbuf,sizeof(msgbuf),"^clear","&clear");
				replacestr(msgbuf,sizeof(msgbuf),"^blue","&blue");
#endif

				if( strlen(bbrelays) > 0 ) {
					memset(msgbuf_relay,0,sizeof(msgbuf_relay));
					strncpy(msgbuf_relay,msgbuf,sizeof(msgbuf_relay)-1);
				}

				do_bb(msgbuf);

				/* Relay message if need be */
				if( strlen(bbrelays) > 0 ) {
					/*
					 * NOW FORK OFF AND LET THE CHILD HANDLE THE RELAY REQUEST
					 */
					/* Double fork to prevent zombie */
 					if ((child = fork()) < 0) {
						fprintf(stderr, "ARRRGH!!! THE FORK ERROR!\n");
					}
					else if (child == 0) {			/* THE PARENT */
	 					if ((child = fork()) < 0) {
							fprintf(stderr, "ARRRGH!!! THE FORK ERROR!\n");
						}
						else if(child == 0) {
							bbsend("0.0.0.0",bbrelays,msgbuf_relay);
						}
						exit(0);
					}
					else {
						wait(&status);
					}
				}
			}
			close(newsockfd);
                	exit(0);
		}
	}
}

/*
 * HANDLE INCOMING BIG BROTHER REQUESTS
 * PARSE THE LINE WE'VE RECEIVED AND HANDLE IT
 */
void do_bb(req)
char *req;
{
char filename[MAXLINE];
void bb_page();
char *nextmsg;				/* SMM COMBO */

#if DEBUG
	debug("REC'D: %s\n", req);
#endif
	/*
	 * IF THE REQUEST STARTS WITH "page" THEN CALL THE PAGING SCRIPT
	 * IF THE REQUEST STARTS WITH "status" THEN LOG THE MESSAGE
	 * IF THE REQUEST STARTS WITH "combo" THEN SET A FLAG AND PROCESS MSGS
	 * IF THE REQUEST STARTS WITH "summary" THEN LOG THE MESSAGE
	 * IF THE REQUEST STARTS WITH "ack" THEN PROCEED WITH AN ACKNOWLEDGEMENT
	 * IF THE REQUEST STARTS WITH "enable" THEN ENABLE THE GIVEN HOSTS
	 * IF THE REQUEST STARTS WITH "disable" THEN DISABLE THE GIVEN HOSTS
	 * IF THE REQUEST STARTS WITH "offline" THEN SET UP THE OFFLINED HOST
	 * IF THE REQUEST STARTS WITH "online" THEN SET UP THE ONLINED HOST
	 * IF THE REQUEST STARTS WITH "data" THEN APPEND DATA TO THE GIVEN FILE NAME
	 * IF THE REQUEST STARTS WITH "notes" THEN REPLACE THE NOTES FILE IN www/notes
	 * IF THE REQUEST STARTS WITH "test" THEN DO NOTHING (MAYBE LATER DO SOMETHING)
	 * OTHERWISE IGNORE IT (FOR SAFETY SAKE)
	 */

	/* If received an agent message, skip that keyword */
	if (strncmp(req, "bbagent ",8) == 0) {
		req += 8;
	}

	if (strncmp(req, "status", 6) == 0) {
		req += 6;			/* JUMP OVER status */
		if (*req == ' ') req++;		/* SKIP THE SPACE , IF IT'S NOT IN THE status+<delay> FORMAT*/
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req ) {
#if DEBUG
			debug("LOG STATUS MSG: %s\n", req);
#endif
			bblog(req,"status");		/* LOG THE REQUEST */
		}
		else {
#if DEBUG
			debug("NULL STATUS MSG IGNORED\n");
#endif
		}
	}
	/* 
	 * THE MIGHTY combo MESSAGE
	 * ALLOW A SINGLE TRANSMISSION TO CONTAIN MULTIPLE status MESSAGES
	 * \n\nstatus INDICATES A NEW MESSAGE
	 */
	else if (strncmp(req, "combo\n", 6) == 0) {
		/* fprintf(stderr, "GOT MIGHTY COMBO!\n"); */
		req += 6;			/* JUMP OVER combo */

		nextmsg = NULL;
		if (strncmp(req, "status", 6) == 0) {
			while (strncmp(req, "status", 6) == 0) {
				nextmsg=(char *)strstr(req, "\n\nstatus");
				/*
				 * END THE MESSAGE BY PUTTING A NULL AT
				 * THE END OF THE MESSAGE, SCRIBBLING OVER
				 * THE EXTRA NEWLINE.
				 */
				if (nextmsg) {		/* END MESSAGE */
					/* fprintf(stderr, "DO STATUS MESSAGE! %s\n", req); */
					*nextmsg = '\0';
					do_bb(req);	/* SHOULD WE RECURSE? */
				}
				else {
					/* fprintf(stderr, "LAST STATUS MSG\n"); */
					do_bb(req);
					break;		/* LEAVE, WE'RE DONE! */
				}	
				req = nextmsg+2;
			}
		}
		else {
#if DEBUG
			debug("INVALID COMBO FORMAT MSG IGNORED\n");
#endif
		}
	}
	else if (strncmp(req, "page ", 5) == 0) {
		req += 5;			/* JUMP OVER page */
		/* Advance 'til the next word */
		while( *req && isspace(*req) ) {
			req++;
		}
		/* Skip the expiry delay if it was entered by mistake */
		if( *req && *req == '+' ) {
			while( *req && !isspace(*req) ) {
				req++;
			}
		}
#if DEBUG
		debug("CALL PAGER: %s\n", req);
#endif
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req ) {
			sscanf(req,"%s",filename);
			if( !bb_isdisabled(filename) ) {
				bb_page(req);
			}
		}
		else {
#if DEBUG
			debug("NULL PAGE MSG IGNORED\n");
#endif
		}
	}
	else if (strncmp(req, "summary ", 8) == 0) {
		req += 8;			/* JUMP OVER summary */
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req ) {
#if DEBUG
			debug("LOG SUMMARY MSG: %s\n", req);
#endif
			bblog(req,"summary");		/* LOG THE REQUEST */
		}
		else {
#if DEBUG
			debug("NULL SUMMARY MSG IGNORED\n");
#endif
		}
	}
	else if (strncmp(req, "ack ", 4) == 0) {
		req += 4;                       /* JUMP OVER ack */
#if DEBUG
		debug("DO ACK: %s\n", req);
#endif
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req ) {
			bb_doack(req);
		}
		else {
#if DEBUG
			debug("NULL ACK MSG IGNORED\n");
#endif
		}
	}
#ifdef ENABLE_DISABLE
	else if ( strncmp(req, "enable ", 7) == 0 ) {
		req += 7;                       /* JUMP OVER enable */
#if DEBUG
		debug("DO ENABLE: %s\n", req);
#endif
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req && (strlen(req) > 0) ) {
			/* Set host(s) to enable */
			enable_disable(req,BB_ENABLEMSG);
		}
		else {
#if DEBUG
			debug("NULL ENABLE MSG IGNORED\n");
#endif
		}
	}
	else if ( strncmp(req, "disable ", 8) == 0 ) {
		req += 8;                       /* JUMP OVER disable */
#if DEBUG
		debug("DO DISABLE: %s\n", req);
#endif
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req && (strlen(req) > 0) ) {
			/* Set host(s) to disable */
			enable_disable(req,BB_DISABLEMSG);
		}
		else {
#if DEBUG
			debug("NULL DISABLE MSG IGNORED\n");
#endif
		}
	}
	else if ( strncmp(req, "online ", 7) == 0 ) {
		req += 7;                       /* JUMP OVER online */
#if DEBUG
		debug("DO ONLINE: %s\n", req);
#endif
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req && (strlen(req) < (MAXLINE-2)) ) {
			/* Set host(s) to enable */
			bb_online(req);
		}
		else {
#if DEBUG
			debug("NULL ONLINE MSG IGNORED\n");
#endif
		}
	}
	else if ( strncmp(req, "offline ", 8) == 0 ) {
		req += 8;                       /* JUMP OVER offline */
#if DEBUG
		debug("DO OFFLINE: %s\n", req);
#endif
		/* Minor bugs spotted by */
		/* Andrew Dalgleish <andrewd@axonet.com.au> */
		if ( *req && (strlen(req) < (MAXLINE-2)) ) {
			/* Set host(s) to enable */
			bblog(req,"offline");
		}
		else {
#if DEBUG
			debug("NULL OFFLINE MSG IGNORED\n");
#endif
		}
	}
#endif
#ifdef DATAMSG
	else if (strncmp(req, "data ", 5) == 0) {
		/* "data <filename> <data>" */
		req += 5;			/* JUMP OVER data */
		bbsave(req,"data");
#if DEBUG
		debug("GOT DATA: %s\n",req);
#endif
	}
#endif
#ifdef NOTESMSG
	else if (strncmp(req, "notes ", 6) == 0) {
		/* "data <filename> <data>" */
		req += 6;			/* JUMP OVER notes */
		bbsave(req,"notes");
#if DEBUG
		debug("GOT NOTES: %s\n",req);
#endif
	}
#endif
	else if (strncmp(req, "test", 4) == 0) {
		req += 4;
#if DEBUG
		debug("GOT TEST\n");
#endif
	}
	else {
#if DEBUG
		debug("IGNORE MESSAGE: %s\n", req);
#endif
	}
}

/*
 * LOG A BIG BROTHER STATUS MESSAGE
 * THE MESSAGE GOES INTO THE DIRECTORY SPECIFIED BY BBLOG
 * MESSAGE FORMAT IS:
 * 	machine.area status message
 * 	summaryname.area summary message
 *
 * THE MESSAGE IS PLACED IN A FILE NAMED machine.area
 */

void bblog(msg,msgtype)
char *msg;
char *msgtype;
{
        FILE *bbfile;
        FILE *bbhist;
        FILE *bbhtml;
#ifdef SCO3
	pid_t child;
#else
	int child;
#endif
        int  rc,len,statres,status;
        char fname[MAXLINE],tmpfname[MAXLINE+1];	/* FILENAME */
        char disfname[MAXLINE],tmpdisfname[MAXLINE+1];	/* DISABLED FILENAME */
        char histname[MAXLINE];				/* HISTORY FILENAME */
        char hosthistname[MAXLINE];			/* HISTORY FILENAME */
        char htmlname[MAXLINE];				/* HTML FILENAME */
	char oldcolor[MAXLINE];				/* FOR COLOR MATCHING */
	char newcolor[MAXLINE];
	char filename[MAXLINE];
	char tmpfilename[MAXLINE];
	char dur[MAXLINE];
	char sentby[MAXLINE];
	char request[MAXLINE];
	char newcol[3],oldcol[3];
	char *hosthistnamep, *hosthistnamepp, *service;
	int state;
	time_t duration, timenow, exptime, lasttime = 0;
	long fwhere;	/* SMM */
	char validfor[MAXLINE];		/* HOW LONG IS THE MESSAGE GOOD FOR */
	char validforstr[MAXLINE];
	int offset;			/* THE ABOVE AS A NUMBER */
	double f;
	struct stat statbuf;
        char *timebuf, *exptimebuf,timenowbuf[32],lasttimebuf[32],*msgptr;
	int savelog;
	char *hostsvcdata,*newmsg;
	extern char* dohostsvc();
	time_t ticks;
	char msg_offline[MAXLINE],dismsg[MAXLINE];
	int qualifierpos, offsetval;

        if (bblogsdir || !strcmp(msgtype,"offline") ) {

		if (*msg == '+') {
			msg++;		/* SKIP THE PLUS SIGN */
                	sscanf(msg, "%s", validfor);
                	len = strlen(validfor);       
			msg += len;
			while (isspace(*msg))
				msg++;	/* SKIP SPACE(S) */
			offset = calc_purple_offset(validfor);
#if DEBUG
			debug("status msg validfor: <%s> offset: <%d>\n", validfor, offset);
			debug("status msg: <%s>\n", msg);
			fflush(stdout);
#endif
		}
		else offset = purpleoffset;

		dur[0] = '\0';
		duration = 0;
		timenow = time(NULL);		/* GET THE TIME */
		if (timenow == -1) {			/* SMM TEST */
			fprintf(stderr, "TIME FAILURE - EXITING!!!\n");
			exit(3);
		}
		timebuf = ctime(&timenow);	/* CONVERT TO ASCII */
		*(timebuf + 24) = '\0';		/* LOSE THE NEWLINE */
		strcpy(timenowbuf,timebuf);

		/* offline message has filename and maxlenght period for disabling */
		if( !strcmp(msgtype,"offline") ) {

			memset(filename,0,sizeof(filename));
			offset = 0;
			memset(dismsg,0,sizeof(dismsg));

			/* Added optional "reason" to disable message */
			/* Modified from Nicolas Chuche <chuche@teaser.fr> suggestion */
			sscanf(msg, "%s %s", filename, validfor);

			if( !valid_logname(filename) ) {
				fprintf(stderr,"%s bbd INVALID FILENAME IN %s MESSAGE: %s\n",gettimestr(),msgtype,filename);
				fflush(stderr);
				return;
			}

			offset = calc_purple_offset(validfor);
#if DEBUG
			debug("offline validfor: <%s>  offset: <%d>\n",validfor,offset);
			debug("status msg: <%s>\n", msg);
			fflush(stdout);
#endif
			strcpy(newcolor,"blue");

			msgptr = (char *)strstr(msg,filename);
			msgptr += strlen(filename);
			msgptr = (char *)strstr(msgptr,validforstr);
			msgptr += strlen(validforstr);
			strncpy(dismsg,msgptr,MAXLINE-1);

        		sprintf(disfname, "%s/%s", bbdisabledir, filename);
        		sprintf(tmpdisfname, "%s/.%s", bbdisabledir, filename);

			/* create an empty disable tag file */
        		bbfile = fopen(tmpdisfname, "w");
			if (bbfile) {
				fclose(bbfile);
			}
			else {
				return;
			}
			ticks = time(&ticks) + offset;
			bb_utime(tmpdisfname, timenow + offset);
			bb_rename(tmpdisfname,disfname);

			/* IF THIS HOST IS JUST A BBPAGER AND NOT A BBDISPLAY THEN */
			/* NOTHING ELSE IS REQUIRED */
			/* Is this host BBDISPLAY ? */
			/* Is the variable BBDISPLAY set ? */
			if( bbdisplay ) {
				/* IS BBDISPLAY set to TRUE ? */
				if( strcmp(bbdisplay,"TRUE") ) {
					/* NOPE, THEN THIS HOST IS ONLY A BBPAGER */
					/* DON'T NEED TO DO ANYTHING ELSE */
					return;
				}
			}

			exptime = timenow + offset;
			exptimebuf = ctime(&exptime);		/* CONVERT TO ASCII */
			*(exptimebuf + 24) = '\0';		/* LOSE THE NEWLINE */
			sprintf(msg_offline,"%s blue   %s    OFFLINE UNTIL %s\n\n%s",filename,timenowbuf,exptimebuf,dismsg);
			msg = msg_offline;

			/* Give some slack on the log file, so purple won't hit */
			/* immediately when purple hits */
			offset += purpleoffset;
		}
		else {
			sscanf(msg, "%s %s", filename, newcolor);
		}

		/*
		 *
		 */
		if( getcolornum(newcolor) == 0 ) {
			/* invalid color in status */
			fprintf(stderr,"%s bbd INVALID STATUS COLOR: %s FOR %s\n",gettimestr(),newcolor, filename);
			fflush(stderr);
#if DEBUG
			debug("INVALID STATUS COLOR: %s\n",newcolor);
#endif
			return;
		}
                len = strlen(filename);       
               	if (strlen(bblogsdir) + len + 2 > MAXLINE) {
                        /* too large for allocated memory, skip it */
#if DEBUG
			debug("FILENAME TOO BIG - IGNORED\n");
#endif
                        return;
                }

		if( !valid_logname(filename) ) {
			fprintf(stderr,"%s bbd INVALID FILENAME IN %s MESSAGE: %s\n",gettimestr(),msgtype,filename);
			fflush(stderr);
			return;
		}

		/*
		 * SMM BB 1.09: EVENT HISTORY AND DURATION
		 * IF THE COLOR OF AN INCOMING MESSAGE IS NOT THE SAME
		 * AS THE CURRENT STATUS, WRITE A LINE IN THE HISTORY
		 * FILE.  OTHERWISE JUST UPDATE THE LOG FILE WITH AN
		 * INDICATION OF THE DURATION OF THE CURRENT STATUS
		 */

       		sprintf(fname, "%s/%s", bblogsdir, filename);
       		sprintf(tmpfname, "%s/.%s", bblogsdir, filename);

		/* Don't do hist for summaries */
		if ( !strcmp(msgtype,"summary") ) {
			goto nohistpls;
		}

        	sprintf(histname, "%s/%s", bbhistdir, filename);

		oldcolor[0]='\0';		/* FOR ROB */

#if DEBUG
        	debug("TRYING TO OPEN BBFILE %s\n", fname);
#endif
        	bbfile = fopen(fname, "r");
		if (bbfile) {
			fscanf(bbfile, "%s", oldcolor);
			fclose(bbfile);
		}

#if DEBUG
		debug("oldcolor: %s , msgtype: %s\n",oldcolor,msgtype);
#endif

		/* IF NOT AN OFFLINE MESSAGE */
		if( strcmp(msgtype,"offline") ) {
			/* IS THE EVENT DISABLED ? */
			if( bb_isdisabled(filename) ) {
				/* YES, DOES IT HAVE A STATUS FILE ? */
				if( !bbfile ) {
					/* NO, CREATE A DUMMY ONE, THE OLD ONE MIGHT */
					/* HAVE BEEN DELETED */
        				bbfile = fopen(fname, "w");
					if (bbfile) {
						sprintf(msg_offline,"blue   %s    OFFLINE UNTIL %s \n%s %s\n%s %s",timenowbuf,"undetermined",recvfromstrp,"undetermined",statunchstrp,"undertermined");
						fputs( msg_offline , bbfile);
						fclose(bbfile);
					}
				}
				return;
			}
		}
		else {
			/* If the log file was not found, we assume this is a BBPAGER */
			/* only host that received it */
			if( !bbfile ) {
				return;
			}
		}

		savelog=0;

		statres=stat(histname, &statbuf);	/* HISTORY AVAILABLE? */

		if ((strcmp(oldcolor, newcolor) != 0) || (statres == -1)) {
			savelog=1;
#if DEBUG
        		debug("TRYING TO OPEN HISTORY FILE %s\n", histname);
#endif
			if (statres == -1)		/* CREATE IT */
        			bbhist = fopen(histname, "a+");
			else				/* OPEN IT */
        			bbhist = fopen(histname, "r+");

			if (bbhist) {
				/*
				 * ICKY THINGS HERE... BACK UP OVER THE
				 * OLD TIME, AND WRITE THE DURATION IN
				 * IT'S PLACE...
				 */
				fseek(bbhist, -11L, SEEK_END);
				fwhere=ftell(bbhist);
				if (fwhere > 0) {
					fscanf(bbhist, "%ld", &lasttime);
					fseek(bbhist, -11L, SEEK_END);
					fprintf(bbhist, " %ld %ld\n%s %s  %ld\n", lasttime, timenow - lasttime, timenowbuf, newcolor, timenow);
#if DEBUG
					debug("%s: FWHERE: %ld LASTIME %ld\n", histname, fwhere, lasttime);
#endif
				}
				else {
					/* Reopen file to reset at beginning because */
					/* some OSes (darwin) don't seem to like to have */
					/* seeked before the beginning of the file */
					fclose(bbhist);
					bbhist = fopen(histname, "a+");
					fprintf(bbhist, "%s %s  %ld\n", timenowbuf, newcolor, timenow);
					lasttime = timenow;
				}
				fclose(bbhist);
			}

			if( !strcmp(bbhosthistlog,"TRUE") || !strcmp(bballhistlog,"TRUE") ) {
				/* Save the event logs per host */
				if(strlen(oldcolor)==0)
					state = -1;
				else {
					state = getcolornum(newcolor) - getcolornum(oldcolor);

					if( state > 0 )
						state = 2;		/* Escalated */
					else if( state < 0 )
						state = 1;		/* Recovered */
					else
						state = 0;		/* No change - if 2 colors ever are equal this is useful */
				}
				strcpy(hosthistname,histname);
				/* Point to last subdir, upper directories may contain a '.' */
				hosthistnamep = (char *)strrchr(hosthistname,'/');
				if(hosthistnamep)
					hosthistnamep++;
				else
					hosthistnamep = hosthistname;
				service = (char *) strrchr(hosthistnamep,'.');
				hosthistnamepp = hosthistnamep;
				while( (hosthistnamepp=(char *)strchr(hosthistnamepp,',')) != NULL)
					*hosthistnamepp = '.';
				timebuf = ctime(&lasttime);	/* CONVERT TO ASCII */
				*(timebuf + 24) = '\0';		/* LOSE THE NEWLINE */
				strcpy(lasttimebuf,timebuf);
				memset(newcol,'\0',sizeof(newcol));
				memset(oldcol,'\0',sizeof(oldcol));
				strncpy(newcol,newcolor,2);
				strncpy(oldcol,oldcolor,2);
				if( service ) {
					*service = '\0';			/* Terminate host name */
					service++;
					if( !strcmp(bbhosthistlog,"TRUE") ) {
						bbhist = fopen(hosthistname, "a+");
						if(bbhist) {
							fprintf(bbhist,"%s %ld %ld %ld %s %s %d\n",service,timenow,lasttime,timenow-lasttime,newcol,strlen(oldcolor)!=0 ? oldcol : "-",state);
							fclose(bbhist);
						}
					}
					if( !strcmp(bballhistlog,"TRUE") ) {
						bbhist = fopen(allhistname, "a+");
						if(bbhist) {
							fprintf(bbhist,"%s %s %ld %ld %ld %s %s %d\n",hosthistnamep,service,timenow,lasttime,timenow-lasttime,newcol,strlen(oldcolor)!=0 ? oldcol : "-",state);
							fclose(bbhist);
						}
					}
				}
			}

			/*
			 * NOW FORK OFF AND LET THE CHILD HANDLE THE REQUEST
			 * Send a rm_event ack message to remove the tmp/np_* tagfile
			 * associated with this event as the color is not defined in
			 * in the PAGELEVELS variable (pagelevels token is bbwarnsetup.cfg)
			 * Also used for recovery message
			*/
			if( !pagelevels || (strlen(pagelevels) == 0) )
				pagelevels = PAGELEVELSDEFAULT; 
			if ( strstr(pagelevels,oldcolor) && !strstr(pagelevels,newcolor) ) {
				if ((child = fork()) < 0) bbd_die("fork error");
				/* child does work, thanks to svangari@uu.net */
				if (child == 0) {                       /* THE CHILD */
					if( strspn(filename,VALIDFILENAMECHARS) == strlen(filename) ) {
						/* For ZOMBIE prone OSes, use the bb exec instead of bbsend() */
						/* The reason is if bbsend() gets stuck, then the whole bbd */
						/* waits for the child process to end */
#ifdef ZOMBIE
						/* Because the bb executable looks at bbdisp and bbdisplays */
						/* to determine where to send, then we must copy bbpagers */
						/* into bbdisplays */
						bb_putenv("BBDISPLAYS",bbpagers,bbdisplays_env,sizeof(bbdisplays_env));
						sprintf(request,"ack rm_event %s %d",filename,(int)(timenow-lasttime));
						execlp(bb, bb, bbpage, request, (char *)NULL);
#else
						sprintf(request,"ack rm_event %s %d",filename,timenow-lasttime);
						rc = bbsend(bbpage,bbpagers,request);
						exit(rc);
#endif
					}
					else {
						fprintf(stderr,"%s bbd INVALID FILENAME IN ack MESSAGE: %s\n",gettimestr(),filename);     
						fflush(stderr);
						exit(1);
					}
				}
				/* Parent continues */
#ifdef ZOMBIE
				wait(&status);
#endif
			}
		}
		else {
			if (statres == 0) {
				duration = timenow - statbuf.st_mtime;
			}
		}

		if (duration > 86400) {
			f = duration / (double) 86400.00;
			sprintf(dur, "%s %.2f %s\n", statunchstrp, f, perioddays);
		}
		else if (duration > 3600) {
			f = duration / (double) 3600.00;
			sprintf(dur, "%s %.2f %s\n", statunchstrp, f, periodhours);
		}
		else {
			f = duration / (double) 60.00;
			sprintf(dur, "%s %.2f %s\n", statunchstrp, f, periodmins);
		}

nohistpls:
		sprintf(sentby,"%s %s\n",recvfromstrp,ipdotaddr);

#if DEBUG
        	debug("CREATING BBFILE %s\n", fname);
#endif
		/*
		 * THANKS TO: Andrey Alekseyev <fetch@muffin.arcadia.spb.ru> 
		 * More checking...
		 */
        	bbfile = fopen(tmpfname, "w+");            /* APPEND IT */
		if (bbfile) {
        		msg += len + 1;                 /* SKIP FIRST ARGS */
#if DEBUG
        		debug("MSG IS %s....\n", msg);
#endif
        		fprintf(bbfile, "%s\n\n%s%s", msg, dur,sentby);   /* PUKE */
        		fclose(bbfile);                 /* CLOSE */

        		/* FIX THE TIMESTAMP */
			bb_utime(tmpfname, timenow + offset);
			bb_rename(tmpfname,fname);
		}
		else {
#if DEBUG
			debug("FAILED TO OPEN STATUS FILE %s\n", bbfile);
#endif
		}

		/* Create an HTML version of the status file */

		/* Don't do html for summaries */
		/* Thanks to holger@marzen.de */
		if ( !strcmp(msgtype,"summary") )
			 return;

		if( strcmp(bblogstatus,"STATIC") == 0 ) {
			memset(tmpfilename,0,sizeof(tmpfilename));
			strncpy(tmpfilename,filename,sizeof(tmpfilename)-1);
			replacestr(tmpfilename,sizeof(tmpfilename),",",".");
        		sprintf(htmlname, "%s/%s.html", bbhtmldir, tmpfilename);
#if DEBUG
        		debug("CREATING HTML FILE %s\n", htmlname);
#endif
        		bbhtml = fopen(htmlname, "w");
			if (bbhtml) {
				newmsg = (char *) malloc(strlen(msg)+1024);
				if( newmsg != NULL ) {
					sprintf(newmsg,"%s\n\n%s%s",msg,dur,sentby);
					hostsvcdata = dohostsvc(newmsg,filename,bbweb,bbwebdir,timenowbuf);
					if( hostsvcdata != NULL ) {
						fwrite(hostsvcdata,strlen(hostsvcdata),1,bbhtml);
						free(hostsvcdata);
					}
					else {
						fprintf(bbhtml,"<HTML><BODY>Couldn't build the HTML status page - out of memory</BODY></HTML>\n");
					}
					free(newmsg);
				}
				else {
					fprintf(bbhtml,"<HTML><BODY>Couldn't build the HTML status page - out of memory</BODY></HTML>\n");
				}
				fclose(bbhtml);
			}
			else {
#if DEBUG
				debug("FAILED TO OPEN HTML FILE %s\n", htmlname);
#endif
			}
		}
		if ( savelog && savestatuslog && !strcmp(savestatuslog,"TRUE") ) {
			save_histlog(filename,timenowbuf,msg,dur,sentby);
		}
	}
	else bbd_die("BB LOGGING DIRECTORY UNDEFINED\n");

#if DEBUG
	debug("DONE IN bblog()\n");
#endif
}

/*
 * PUT AN ERROR INTO THE LOGFILE AND stderr AND DIE
 */
int bbd_die(msg)
char *msg;
{
        static char message[MAXLINE];
        sprintf(message, "%s bbd %s\n",gettimestr(), msg);

        syslog(LOG_DAEMON | LOG_CRIT , "%s",message);
        fprintf(stderr, "%s", message);
        exit(1);
}

/*
 * SMM: v.1.06b CLEAN THIS UP...
 * THANKS TO: Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
 * READS IN THE DATABASE OF IP ADDRESSES AND NETMASKS
 * FROM etc/security
 */
int getsecurity() {
	FILE *sec;
	char line[MAXLINE];
	int cnt;

	memset(secdb,'\0',sizeof(secdb));
	cnt = 0;

	sec = fopen(security, "r");
	if (sec) {
		while(fgets(line, MAXLINE-1, sec)) {
#if DEBUG
			debug("LINE IS: %s\n", line);
#endif
			if( dosecdb(line, cnt) == 0 ) cnt++;
			else {
#if DEBUG
				debug("DISCARDING: %s\n", line);
#endif
			}
		}
		fclose(sec);		/* CLOSE THE FILE */
	}

	return(0);
}

int checkrequest(ipnum,req)
unsigned long ipnum;
char *req;
{
	/* GET THE REQUEST TYPE */

	/* IF OFFLINE/ONLINE */
	/* MAKE SURE REQUEST CAME FROM A BBDISPLAY */

	return(0);
}


int checksecurity(inc) 
struct in_addr *inc;
{
	int cnt = 0;
	int retval = 1;			/* TRUE */
	struct in_addr chk;

	while( (chk.s_addr=secdb[cnt].addr.s_addr) != 0 ) {
		retval = 0;		/* FALSE */
		/*
		 * SEEMS THE CAST TO (int) BREAKS THIS TEST ON Solaris 2.6
		 * FIXES FROM Henrik Stroem hstroem@pvv.org
		 ( GET RID OF THE OLD BROKEN TEST
			if ((ipnum & chk.s_addr) == chk.s_addr) {
		 * THANKS TO  Larry Parmelee <parmelee@CS.Cornell.EDU
		 * FOR NOTICING IT AND CARING ENOUGH TO WRITE...
		 */

#if FULLDEBUG
		debug("incoming:	%s\n",inet_ntoa(inc));
		debug("Mask:		%s\n",inet_ntoa(secdb[cnt].mask));
		debug("chk addr:	%s\n",inet_ntoa(chk));
		debug("addr:		%8x\n",inc->s_addr);
		debug("mask:		%8x\n",secdb[cnt].mask.s_addr);
		debug("addr & mask:	%8x\n",inc->s_addr & secdb[cnt].mask.s_addr);
		debug("net:		%8x\n",chk.s_addr);
#endif

		if ((inc->s_addr & secdb[cnt].mask.s_addr) == chk.s_addr) {
#if DEBUG
			debug("------> PASSED\n");
#endif
			return(1);
		}
		else {
#if DEBUG
			debug("------> FAILED\n");
#endif
		}
		cnt++;
	}

	if (retval == 0) {		/* FAILED - NOT IN THE TABLE! */
#if DEBUG
		debug("--> FAILED - NOT IN TABLE\n");
#endif
	}

#if DEBUG
	debug("CHECKSECUITY DEFAULT RETURNING %d\n", retval);
#endif
	return(retval);
}

/*
 * dosecdb
 * ADD A LINE TO THE SECURITY DATABASE
 *
 * OK, THINGS CAN GET UGLY HERE
 * A LINE CAN HAVE SEVERAL FORMS
 * AN IP ADDRESS: 204.191.20.8 
 * A NET ADDRESS: 204.191.20.0 (MASK IMPLIED 255.255.255.0)
 * A NET ADDRESS + NETMASK 204.191.20.0/255.255.240.0
 * ANYTHING ELSE MUST GO AWAY
 */
int dosecdb(xline, xcnt)
char *xline;
int xcnt;
{
	char *mask;
	char netmask[MAXLINE];
	int oct1, oct2, oct3, oct4;	/* OCTETS */

	struct in_addr iaddr;

#if DEBUG
	debug("INTO dosecdb %s %d\n", xline, xcnt);
#endif

 	while( isspace(*xline) )
		xline++;

	/* If it's a comment or an empty line */
	if( *xline == '#' || (strlen(xline) == 0) ) {
		return(1);
	}
	
	/*
	 * HANDLE THE NET/MASK
	if (1 == 3) {	
	 */
	if ( (mask=(char *)strchr(xline, '/')) != NULL ) {
#if DEBUG
		debug("FOUND A NETMASK!\n");
#endif
		strcpy(netmask,mask+1);	/* SECOND PART */
		*mask = '\0';
	}
	else {	/* NO EXPLICIT MASK SET, FIGURE IT OUT... */
#if DEBUG
		debug("NO NETMASK!\n");
#endif
		sscanf(xline, "%d.%d.%d.%d", &oct1, &oct2, &oct3, &oct4);
#if DEBUG
		debug("%d-%d-%d-%d\n", oct1, oct2, oct3, oct4);
#endif

		if (oct4 == 0) {
			if (oct3 == 0) {
				if (oct2 == 0) {
					if (oct1 == 0) oct1=0;
					else oct1=255;
				}
				else oct1=oct2=255;
			}
			else oct1=oct2=oct3=255;
		}
		else oct1=oct2=oct3=oct4=255;

		sprintf(netmask, "%d.%d.%d.%d", oct1, oct2, oct3, oct4);
	}

#if DEBUG
	debug("IPaddr set to: %s\n", xline);
	debug("Netmask set to: %s\n", netmask);
#endif
	/* 
	 * SMM UGH.
	 * 255.255.255.255 is actually a VALID netmask
	 * BUT IT ALSO HAPPENS TO EQUAL -1... 
	 * SO NO ERROR CHECKING ON NETMASKS SINCE -1 IS AS RESTRICTIVE
	 * AS YOU CAN GET...
	iaddr.s_addr = inet_addr(netmask);

	if (iaddr.s_addr == -1) {
		fprintf(stderr, "%s bbd Invalid address %s (ignored)\n", gettimestr(),xline);
		fflush(stderr);
		return(1);
	}
	else 
	 */

	iaddr.s_addr = inet_addr(xline);

	/*
	 * NOW SAVE IT IF IT'S VALID...
	 */
	if ((iaddr.s_addr != -1)&&(xcnt < MAXLINE - 1)) {
#if DEBUG
		debug("ADDING LINE %d %s\n", xcnt, xline);
#endif
		secdb[xcnt].addr.s_addr = iaddr.s_addr & inet_addr(netmask);
		secdb[xcnt].mask.s_addr = inet_addr(netmask);
		return(0);
	}
	else {
		fprintf(stderr, "%s bbd Invalid IP addr on %s (ignored)\n", gettimestr(),xline);
		fflush(stderr);
		return(1);		/* FAIL */
	}
}
