/*
 * Citadel/UX Intelligent Network Processor for IGnet/Open networks v3.1
 * designed and written by Art Cancro @ Uncensored Communications Group
 * see copyright.doc for copyright information
 */

/*
 * Specify where netproc should log to, and the mode for opening the file.
 * If you are logging to a file, LOGMODE should be a; if you are logging to
 * a device or fifo it should be w.
 */
#define LOGFILE "/dev/null"
#define LOGMODE "w"
#define EXPIRY_TIME (2592000L)		/* system purge time */

#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "citadel.h"

/* A list of users you wish to filter out of incoming traffic can be kept
 * in ./network/filterlist -- messages from these users will be automatically
 * moved to FILTERROOM.  Normally this will be the same as TWITROOM (the
 * room problem user messages are moved to) but you can override this by
 * specifying a different room name here.
 */
#ifndef FILTERROOM
#define FILTERROOM TWITROOM
#endif

struct msglist {
	struct msglist *next;
	long m_num;
	long m_pos;
	int m_room;
	};

struct rmlist {
	struct rmlist *next;
	char rm_name[20];
	long rm_lastsent;
	};

struct filterlist {
	struct filterlist *next;
	char person[32];
	};

struct syslist {
	struct syslist *next;
	char s_name[16];
	char s_type[4];
	char s_nexthop[128];
	long s_lastcontact;
	char s_humannode[64];
	char s_phonenum[32];
	char s_gdom[64];
	};

struct minfo {
	char A[512];
	long I;
	char N[512];
	char O[512];
	char R[512];
	long T;
	char D[512];
	char C[512];
	char nexthop[32];
	char H[512];
	char S[512];
	char B[512];
	char G[512];
	};

long atol();
long lseek();
char *malloc();
struct filterlist *filter = NULL;
char roomnames[MAXROOMS][20];
char roomdirs[MAXROOMS][15];
struct syslist *slist = NULL;

#ifdef NEW_CONFIG
struct config config;
#endif

int struncmp(lstr,rstr,len)
char lstr[],rstr[];
int len; {
	int pos = 0;
	char lc,rc;
	while (pos<len) {
		lc=tolower(lstr[pos]);
		rc=tolower(rstr[pos]);
		if ((lc==0)&&(rc==0)) return(0);
		if (lc<rc) return(-1);
		if (lc>rc) return(1);
		pos=pos+1;
		}
	return(0);
	}

/* redefine strucmp, just in case we're using an old version of citadel.h
 * that has it as a separate routine
 */
#ifndef strucmp
#undef strucmp
#endif
#define strucmp(lstr,rstr) struncmp(lstr,rstr,32767)

/*
 * for performance optimization, netproc loads the list of room names (and
 * their corresponding directory names, if applicable) into a table in memory.
 */
load_roomnames() {
	FILE *fp;
	struct quickroom qbuf;
	int i;

	fp=fopen("./quickroom","r");
	if (fp==NULL) return(1);
	for (i=0; i<MAXROOMS; ++i) {
		if (fread((char *)&qbuf,sizeof(struct quickroom),1,fp)!=1)
			return(1);
		strcpy(roomnames[i],qbuf.QRname);
		if (qbuf.QRflags & QR_DIRECTORY)
			strcpy(roomdirs[i],qbuf.QRdirname);
		else
			strcpy(roomdirs[i],config.c_bucket_dir);
		}
	fclose(fp);
	return(0);
	}

/*
 * we also load the network/mail.sysinfo table into memory, make changes
 * as we learn more about the network from incoming messages, and write
 * the table back to disk when we're done.
 */
load_syslist() {
	FILE *fp;
	struct syslist *stemp;
	char insys = 0;
	char buf[128];

	fp=fopen("network/mail.sysinfo","r");
	if (fp==NULL) return(1);

	while(1) {
		if (fgets(buf,128,fp)==NULL) {
			fclose(fp);
			return(0);
			}
		buf[strlen(buf)-1] = 0;
		while (isspace(buf[0])) strcpy(buf,&buf[1]);
		if (buf[0]=='#') buf[0]=0;
		if ( (insys==0) && (strlen(buf)!=0) ) {
			insys = 1;
			stemp =(struct syslist *)malloc(sizeof(struct syslist));
			stemp->next = slist;
			slist = stemp;
			strcpy(slist->s_name,buf);
			strcpy(slist->s_type,"bin");
			strcpy(slist->s_nexthop,"Mail");
			slist->s_lastcontact = 0L;
			strcpy(slist->s_humannode,"");
			strcpy(slist->s_phonenum,"");
			strcpy(slist->s_gdom,"");
			}
		else if ( (insys==1) && (strlen(buf)==0) ) {
			insys = 0;
			}
		else if ( (insys==1) && (!strncmp(buf,"bin",3)) ) {
			strcpy(slist->s_type,"bin");
			strcpy(slist->s_nexthop,&buf[4]);
			}
		else if ( (insys==1) && (!strncmp(buf,"use",3)) ) {
			strcpy(slist->s_type,"use");
			strcpy(slist->s_nexthop,&buf[4]);
			}
		else if ( (insys==1) && (!strncmp(buf,"uum",3)) ) {
			strcpy(slist->s_type,"uum");
			strcpy(slist->s_nexthop,&buf[4]);
			}
		else if ( (insys==1) && (!strncmp(buf,"lastcontact",11)) ) {
			sscanf(&buf[12],"%ld",&slist->s_lastcontact);
			}
		else if ( (insys==1) && (!strncmp(buf,"humannode",9)) ) {
			strcpy(slist->s_humannode,&buf[10]);
			}
		else if ( (insys==1) && (!strncmp(buf,"phonenum",8)) ) {
			strcpy(slist->s_phonenum,&buf[9]);
			}
		else if ( (insys==1) && (!strncmp(buf,"gdom",4)) ) {
			strcpy(slist->s_gdom,&buf[5]);
			}
		}
	}

/*
 * here's the routine to write the table back to disk.
 */
rewrite_syslist() {
	struct syslist *stemp;
	FILE *newfp;
	long now;

	time(&now);
	newfp=fopen("network/mail.sysinfo","w");
	for (stemp=slist; stemp!=NULL; stemp=stemp->next) {
		if (!strucmp(stemp->s_name,config.c_nodename)) {
			time(&stemp->s_lastcontact);
			strcpy(stemp->s_type,"bin");
			strcpy(stemp->s_humannode,config.c_humannode);
			strcpy(stemp->s_phonenum,config.c_phonenum);
			}
	    /* remove systems we haven't heard from in a while */
	    if ( (stemp->s_lastcontact == 0L) 
		 || (now - stemp->s_lastcontact < EXPIRY_TIME) ) {
		fprintf(newfp,"%s\n%s %s\n",
			stemp->s_name,stemp->s_type,stemp->s_nexthop);
		if (strlen(stemp->s_phonenum) > 0) 
			fprintf(newfp,"phonenum %s\n",stemp->s_phonenum);
		if (strlen(stemp->s_gdom) > 0) 
			fprintf(newfp,"gdom %s\n",stemp->s_gdom);
		if (strlen(stemp->s_humannode) > 0) 
			fprintf(newfp,"humannode %s\n",stemp->s_humannode);
		if (stemp->s_lastcontact > 0L)
			fprintf(newfp,"lastcontact %ld %s",
				stemp->s_lastcontact,
				asctime(localtime(&stemp->s_lastcontact)));
		fprintf(newfp,"\n");
		}
	    }
	fclose(newfp);
	/* now free the list */
	while (slist!=NULL) {
		stemp = slist;
		slist = slist->next;
		free(stemp);
		}
	return(0);
	}


/* call this function with the node name of a system and it returns a pointer
 * to its syslist structure.
 */
struct syslist *get_sys_ptr(sysname)
char *sysname; {
	static char sysnambuf[16];
	static struct syslist *sysptrbuf = NULL;
	struct syslist *stemp;

	if ( (!strcmp(sysname,sysnambuf))
		&& (sysptrbuf!=NULL) )  return(sysptrbuf);

	strcpy(sysnambuf,sysname);
	for (stemp=slist; stemp!=NULL; stemp=stemp->next) {
		if (!strcmp(sysname,stemp->s_name)) {
			sysptrbuf = stemp;
			return(stemp);
			}
		}
	sysptrbuf = NULL;
	return(NULL);
	}


main(argc,argv)
int argc;
char *argv[];
{
	char allst[32];
	FILE *allfp;

	ulimit(2,8192L);
	freopen(LOGFILE,LOGMODE,stdout);
	freopen(LOGFILE,LOGMODE,stdout);

/*
 * the reason for the #ifdef's is that we might be using an old version of
 * Citadel that has all of the config stuff in the citadel.h file.  If this
 * is the case, the only thing we need to do is change directories.  For
 * Citadel 3.2 or above, we read the configuration off disk.
 */
#ifdef NEW_CONFIG
	get_config();
#else
	chdir(BBSDIR);
#endif

	printf("netproc: started.  pid=%d\n",getpid());
	if (load_roomnames()!=0) fprintf(stdout,"netproc: cannot load rooms\n");
	if (load_syslist()!=0) fprintf(stdout,"netproc: cannot load sysinfo\n");
	inprocess();	/* first collect incoming stuff */
	if ((argc==2) && (strcmp(argv[1],"all"))) outprocess(argv[1]);
	if ((argc==2) && (!strcmp(argv[1],"all"))) {
		allfp=(FILE *)popen("cd ./network/systems; ls","r");
		if (allfp!=NULL) {
			while (fgets(allst,32,allfp)!=NULL) {
				allst[strlen(allst)-1] = 0;
				outprocess(allst);
				}
			pclose(allfp);
			}
		}
	inprocess();	/* incoming again in case anything new was generated */
	rewrite_syslist();
	unlock_msgmain();
	printf("netproc: processing ended.\n");
	exit(0);
	}

load_filterlist() {
	FILE *fp;
	struct filterlist *fbuf;
	char sbuf[32];
	fp=fopen("./network/filterlist","r");
	if (fp==NULL) return(1);
	while (fgets(sbuf,32,fp)!=NULL) {
		if (sbuf[0]!='#') {
			sbuf[strlen(sbuf)-1]=0;
			fbuf=(struct filterlist *)
				malloc((long)sizeof(struct filterlist));
			fbuf->next = filter;
			strcpy(fbuf->person,sbuf);
			filter = fbuf;
			}
		}
	fclose(fp);
	return(0);
	}

int is_banned(who)	/* returns 1 if user is in the filter (banned) list */
char *who; {
	struct filterlist *fptr;
	for (fptr=filter; fptr!=NULL; fptr=fptr->next)
		if (!strucmp(fptr->person,who)) return(1);
	return(0);
	}

inprocess() {	/* Process incoming files in ./network/spoolin */
	FILE *fp,*message,*testfp;
	static struct minfo minfo;
	struct recentmsg recentmsg;
	struct smreturn smreturn;
	char tname[50],aaa[1024],iname[50];
	int a;
	struct syslist *stemp;

	sprintf(tname,"/tmp/net.t%d",getpid());	/* temp file name */
	sprintf(iname,"/tmp/net.i%d",getpid());	/* temp file name */

	load_filterlist();

	/* Let the shell do the dirty work. Get all data from spoolin */
sprintf(aaa,"for x in network/spoolin/*; do cat <$x; rm $x; done 2>/dev/null");
	fp=(FILE *)popen(aaa,"r");

NXMSG:	/* Seek to the beginning of the next message */
	do {
		a=getc(fp);
		} while((a!=255)&&(a>=0));
	if (a<0) goto ENDSTR;
	message=fopen(tname,"w");
	putc(255,message);
	do {
		do {
			a=getc(fp);
			putc(a,message);
			} while(a!=0);
		a=getc(fp);
		putc(a,message);
		} while (a!='M');
	do {
		a=getc(fp);
		putc(a,message);
		} while(a>0);
	fclose(message);

	/* process the individual mesage */
	minfo.D[0]=0;
	minfo.C[0]=0;
	minfo.B[0]=0;
	minfo.G[0]=0;
	msgfind(tname,&minfo);
	strncpy(recentmsg.RMnodename,minfo.N,9);
	recentmsg.RMnodename[9]=0;
	recentmsg.RMnum=minfo.I;
	printf("netproc: #%ld fm <%s> in <%s> @ <%s>\n",
		minfo.I,minfo.A,minfo.O,minfo.N);
	if (strlen(minfo.R)>0) {
		printf("         to <%s>",minfo.R);
		if (strlen(minfo.D)>0) {
			printf(" @ <%s>",minfo.D);
			}
		printf("\n");
		}
	fflush(stdout);
	if (!strucmp(minfo.D,FQDN)) strcpy(minfo.D,NODENAME);

	/* this routine updates our info on the system that sent the message */
	stemp = get_sys_ptr(minfo.N);
	if ((stemp == NULL) && (get_sys_ptr(minfo.nexthop) != NULL)) {
		/* add non-neighbor system to map */
		stemp = (struct syslist *)malloc((long)sizeof(struct syslist));
		stemp->next = slist;
		slist = stemp;
		strcpy(slist->s_name,minfo.N);
		strcpy(slist->s_type,"use");
		strcpy(slist->s_nexthop,minfo.nexthop);
		time(&slist->s_lastcontact);
		}
	else if ((stemp == NULL) && (!strucmp(minfo.N,minfo.nexthop))) {
		/* add neighbor system to map */
		sprintf(aaa,"./network/systems/%s",minfo.N);
		testfp=fopen(aaa,"r");
		if (testfp!=NULL) {
			fclose(testfp);
			stemp = (struct syslist *)
				malloc((long)sizeof(struct syslist));
			stemp->next = slist;
			slist = stemp;
			strcpy(slist->s_name,minfo.N);
			strcpy(slist->s_type,"bin");
			strcpy(slist->s_nexthop,"Mail");
			time(&slist->s_lastcontact);
			}
		}
	/* now update last contact and long node name if we can */
	if (stemp!=NULL) {
		time(&stemp->s_lastcontact);
		if (strlen(minfo.H) > 0) strcpy(stemp->s_humannode,minfo.H);
		if (strlen(minfo.B) > 0) strcpy(stemp->s_phonenum,minfo.B);
		if (strlen(minfo.G) > 0) strcpy(stemp->s_gdom,minfo.G);
		}

	/* route the message if necessary */
	if ((strucmp(minfo.D,NODENAME))&&(minfo.D[0]!=0)) { 
		a = get_sysinfo_type(minfo.D);
		printf("netproc: routing message to system <%s>\n",minfo.D);
		if (a==M_UUCP) {
			if (fork()==0) execlp("netmailer","netmailer",
						tname,&a,NULL);
			else while (wait()!=(-1));
			}
		else ship_to(tname,minfo.D);
		}

	/* check to see if it's a file transfer */
	else if (!struncmp(minfo.S,"FILE",4)) {
		proc_file_transfer(tname);
		}

	/* otherwise process it as a normal message */
	else {
		lock_msgmain();
		send_message(tname,&smreturn);
		if (minfo.R[0]!=0) {
			a=mail_to(minfo.R,&smreturn);
			if (a<0) file_message(TWITROOM,&smreturn);
			}
		else if (is_banned(minfo.A)) {
			file_message(FILTERROOM,&smreturn);
			printf("netproc: (message filtered)\n");
			}
		else {
			file_message((minfo.C[0]!=0 ? minfo.C : minfo.O)
				,&smreturn);
			}
		unlock_msgmain();
		if (!strucmp(minfo.O,"control")) process_net_control(tname);
		}

SKMSG:	unlink(tname);
	goto NXMSG;

ENDSTR:	fclose(fp);
	unlink(iname);
	return(0);
}


/*
 * Load all of the fields of a message, except the actual text, into a
 * table in memory (so we know how to process the message).
 */
msgfind(msgfile,buffer)
char *msgfile;
struct minfo *buffer;
	{
	int b,e,mtype,aflag;
	char bbb[1024];
	char userid[1024];
	FILE *fp;
		
	strcpy(userid,"");
	fp=fopen(msgfile,"rb");
	if (fp==NULL) {
		fprintf(stdout,"Can't open message file\n");
		return(1); 
		}
	e=getc(fp);
	if (e!=255) {
		fprintf(stdout,"Incorrect message format\n");
		goto END;
		}
	mtype=getc(fp); aflag=getc(fp);
	buffer->I=0L;
	buffer->R[0]=0;
	buffer->H[0]=0;
	buffer->S[0]=0;
	buffer->B[0]=0;
	buffer->G[0]=0;

BONFGM:	b=getc(fp); if (b<0) goto END;
	if (b=='M') goto END;
	fpgetfield(fp,bbb);
	while ((bbb[0]==' ')&&(strlen(bbb)>1)) strcpy(bbb,&bbb[1]);
	if (b=='A') {
		strcpy(buffer->A,bbb);
		if (strlen(userid)==0) {
			strcpy(userid,bbb);
			for (e=0; e<strlen(userid); ++e)
				if (userid[e]==' ') userid[e]='_';
			}
		}
	if (b=='O') strcpy(buffer->O,bbb);
	if (b=='C') strcpy(buffer->C,bbb);
	if (b=='N') strcpy(buffer->N,bbb);
	if (b=='S') strcpy(buffer->S,bbb);
	if (b=='P') {
		/* extract the user id from the path */
		for (e=0; e<strlen(bbb); ++e)
			if (bbb[e]=='!') strcpy(userid,&bbb[e+1]);

		/* now find the next hop */
		for (e=0; e<strlen(bbb); ++e) if (bbb[e]=='!') bbb[e]=0;
		strcpy(buffer->nexthop,bbb);
		}
	if (b=='R') {
		for (e=0; e<strlen(bbb); ++e) if (bbb[e]=='_') bbb[e]=' ';
		strcpy(buffer->R,bbb);
		}
	if (b=='D') strcpy(buffer->D,bbb);
	if (b=='T') buffer->T=atol(bbb);
	if (b=='I') buffer->I=atol(bbb);
	if (b=='H') strcpy(buffer->H,bbb);
	if (b=='B') strcpy(buffer->B,bbb);
	if (b=='G') strcpy(buffer->G,bbb);
	goto BONFGM;

END:	if (buffer->I==0L) buffer->I=buffer->T;
	fclose(fp);

	/* cache the address if necessary */
	/* cache_addr(buffer->A,userid,buffer->N); */

	return(0);
}

int wrapgetc(fp)
FILE *fp; {
	int a;
	if (ftell(fp)>=MM_FILELEN) fseek(fp,0L,0);
	a=getc(fp);
	return(a);
	}

fpgetfield(fp,string)
FILE *fp;
char string[]; {
	int a,b,c;

	strcpy(string,"");
	a=0;
	do {
		b=wrapgetc(fp);
		if (b<1) {
			string[a]=0;
			return(0);
			}
		string[a]=b;
		++a;
		} while (b!=0);
	}



send_message(filename,retbuf)	/* send a message to the master file */
char filename[];		/* tempfilename of proper message */
struct smreturn *retbuf;	/* return information */
{

int file,a,c,d;
long bb,cc,templen,hibytes,origpos,bytes_written;
char sbuf[BUFSIZ];
char mid[30];
FILE *fp,*fp2;
struct msgmain msgmain;

	/* lock_msgmain(); */
	file=open("MMstructure",O_RDWR);
	lseek(file,0L,0);
	a=read(file,&msgmain,sizeof(struct msgmain));
	lseek(file,0L,0);
	close(file);

	origpos=msgmain.MMcurpos;
	++msgmain.MMhighest;
	sprintf(mid,"I%ld",msgmain.MMhighest);

	/* measure the message */
	fp=fopen(filename,"r");
	fseek(fp,0L,2);
	templen=ftell(fp);
	fclose(fp);
	templen=templen+((long)strlen(mid))+2L;

	/* check for FF bytes, to determine how many msgs we're overwriting */
	hibytes=0L;
	fp=fopen("msgmain","rb");
	fseek(fp,msgmain.MMcurpos,0);
	cc=ftell(fp);
	for (bb=0L; bb<templen; ++bb) {
		if (cc>=MM_FILELEN) {
			fseek(fp,0L,0);
			cc=0L;
			}
		c=getc(fp); ++cc;
		if (c>127) ++hibytes;	/* bump count if hi bit set */
		}
	fclose(fp);
	msgmain.MMlowest=msgmain.MMlowest+hibytes;

	fp=fopen("msgmain","r+");
	fseek(fp,msgmain.MMcurpos,0);
	cc=ftell(fp);
	fp2=fopen(filename,"r");
	fread((char *)sbuf,3,1,fp2);
	fwrite((char *)sbuf,3,1,fp);
	fprintf(fp,"%s",mid);
	putc(0,fp);

	/* 3 header + mid (I field) + 1 zero-byte */
	bytes_written = 4L + ((long)strlen(mid));

	while (bytes_written < templen) {
		d=getc(fp2);
		if (d<0) d=0;
		putc(d,fp);
		++cc;
		if (cc>=MM_FILELEN) {
			fseek(fp,0L,0);
			cc = 0L;
			}
		++bytes_written;
		}

	msgmain.MMcurpos=ftell(fp);
	fclose(fp2);	/* done with temp file */
	fclose(fp);	/* done with master file */

	/* now update the message structure */
	file=open("MMstructure",O_RDWR);
	a=write(file,&msgmain,sizeof(struct msgmain));
	close(file);

	/* unlock_msgmain(); */

	retbuf->smnumber=msgmain.MMhighest;
	retbuf->smpos=origpos;

	return(0);
	}


outprocess(sysname) /* send new room messages to sysname */
char *sysname; {
	char sysflnm[64];
	char srmname[32];
	char shiptocmd[128];
	char lbuf[64];
	char tempflnm[64];
	struct quickroom cquickrm;
	struct fullroom cfullrm;
	struct msglist *cmlist = NULL;
	struct rmlist *crmlist = NULL;
	struct rmlist *rmptr,*rmptr2;
	struct msglist *cmptr,*cmptr2;
	FILE *sysflfp,*qrfp,*frfp,*tempflfp;
	int a,b,file,outgoing_msgs;
	struct msgmain mmstruct;

	sprintf(tempflnm,"/tmp/%s.%d",NODENAME,getpid());
	tempflfp=fopen(tempflnm,"w");
	if (tempflfp==NULL) return(1);

	file=open("./MMstructure",O_RDWR);
	if (file>=0) {
		read(file,&mmstruct,sizeof(struct msgmain));
		close(file);
		}
	else mmstruct.MMlowest = 0L;

/*
 * Read system file for node in question and put together room list
 */
	sprintf(sysflnm,"./network/systems/%s",sysname);
	sysflfp=fopen(sysflnm,"r");
	if (sysflfp==NULL) return(2);
	fgets(shiptocmd,128,sysflfp); shiptocmd[strlen(shiptocmd)-1]=0;
	while(!feof(sysflfp)) {
		if (fgets(srmname,32,sysflfp)==NULL) break;
		srmname[strlen(srmname)-1]=0;
		fgets(lbuf,32,sysflfp);
		rmptr=(struct rmlist *)malloc(sizeof(struct rmlist));
		rmptr->next = NULL;
		strcpy(rmptr->rm_name,srmname);
		rmptr->rm_lastsent = atol(lbuf);
		if (rmptr->rm_lastsent < mmstruct.MMlowest)
			rmptr->rm_lastsent = mmstruct.MMlowest;
		if (crmlist==NULL) crmlist=rmptr;
		else if (!strucmp(rmptr->rm_name,"control")) {
			/* control has to be first in room list */
			rmptr->next = crmlist;
			crmlist = rmptr;
			}
		else {
			rmptr2=crmlist;
			while (rmptr2->next != NULL) rmptr2=rmptr2->next;
			rmptr2->next=rmptr;
			}
		}
	fclose(sysflfp);

/*
 * Assemble list of messages to be spooled
 */
	for (rmptr=crmlist; rmptr!=NULL; rmptr=rmptr->next) {
		qrfp=fopen("quickroom","r");
		b=(-1);
		for (a=0; a<MAXROOMS; ++a) {
			fread((char *)&cquickrm,sizeof(struct quickroom),
				1,qrfp);
			if (!strucmp(cquickrm.QRname,rmptr->rm_name)) b=a;
			if (!strucmp(cquickrm.QRname,rmptr->rm_name)) break;
			}
		fclose(qrfp);
#ifdef TRACING
		fprintf(stdout,"netproc: room #%02d <%s>\n",
			b,rmptr->rm_name);
#endif
		if (b<0) break;
		sprintf(lbuf,"./rooms/fullrm%d",b);
		frfp=fopen(lbuf,"r");
		fread((char *)&cfullrm,sizeof(struct fullroom),1,frfp);
		fclose(frfp);
		for (a=0; a<MSGSPERRM; ++a) {
			if ( cfullrm.FRnum[a] > (rmptr->rm_lastsent) ) {
				rmptr->rm_lastsent = cfullrm.FRnum[a];
				
			cmptr=(struct msglist *)malloc(sizeof(struct msglist));
				cmptr->next = NULL;
				cmptr->m_num = cfullrm.FRnum[a];
				cmptr->m_pos = cfullrm.FRpos[a];
				cmptr->m_room = b;

				if (cmlist == NULL) cmlist = cmptr;
				else {
					cmptr2 = cmlist;
					while (cmptr2->next != NULL)
						cmptr2 = cmptr2->next;
					cmptr2->next = cmptr;
					}
				}
			}
		}

	outgoing_msgs=0; cmptr2=cmlist;	/* this loop counts the messages */
	while (cmptr2!=NULL) {
		++outgoing_msgs;
		cmptr2 = cmptr2->next;
		}
	printf("netproc: %d messages to be spooled to %s\n",
		outgoing_msgs,sysname);
	fflush(stdout);

/*
 * spool out the messages, but only if there are any
 */
	fflush(stdout);
	if (outgoing_msgs!=0) outgoing_msgs=spool_out(cmlist,tempflfp,sysname);
	printf("netproc: %d messages actually spooled\n",
		outgoing_msgs);
	fflush(stdout);

/*
 * Deallocate list of spooled messages
 */
	while(cmlist!=NULL) {
		cmptr=cmlist->next;
		free(cmlist);
		cmlist=cmptr;
		}

/*
 * Rewrite system file and deallocate room list
 */
	printf("Spooling...\n");
	fflush(stdout);
	sysflfp=fopen(sysflnm,"w");
	fprintf(sysflfp,"%s\n",shiptocmd);
	for (rmptr=crmlist; rmptr!=NULL; rmptr=rmptr->next)  
		fprintf(sysflfp,"%s\n%ld\n",rmptr->rm_name,rmptr->rm_lastsent);
	fclose(sysflfp);
	while(crmlist!=NULL) {
		rmptr=crmlist->next;
		free(crmlist);
		crmlist=rmptr;
		}

/* 
 * Close temporary file, ship it out, and return
 */
	fclose(tempflfp);
	if (outgoing_msgs!=0) ship_to(tempflnm,sysname);
	unlink(tempflnm);
	return(0);
	}

ship_to(filenm,sysnm)	/* send spool file filenm to system sysnm */
char *filenm;
char *sysnm; {
	char sysflnm[100];
	char commbuf1[100];
	char commbuf2[100];
	FILE *sysflfd;

#ifdef TRACING
	fprintf(stdout,"netproc: shipping %s to %s\n",filenm,sysnm);
#endif
	sprintf(sysflnm,"./network/systems/%s",sysnm);
	sysflfd=fopen(sysflnm,"r");
	if (sysflfd==NULL) fprintf(stdout,"netproc: cannot open %s\n",sysflnm);
	fgets(commbuf1,99,sysflfd);
	commbuf1[strlen(commbuf1)-1] = 0;
	fclose(sysflfd);
	sprintf(commbuf2,commbuf1,filenm);
	return(system(commbuf2));
	}

int spool_out(cmlist,destfp,sysname)	/* spool list of messages to a file */
struct msglist *cmlist;			/* returns # of msgs spooled */
FILE *destfp; {
	struct msglist *cmptr;
	FILE *mmfp;
	char fbuf[128];
	int a;
	int msgs_spooled = 0;

	mmfp=fopen("msgmain","r");
	if (mmfp==NULL) return(0);

	for (cmptr=cmlist; cmptr!=NULL; cmptr=cmptr->next) {
		if (ismsgok(cmptr->m_pos,mmfp,sysname)) {
			++msgs_spooled;
			fflush(stdout);
			fseek(mmfp,cmptr->m_pos,0);
			fread(fbuf,3,1,mmfp);
			fwrite(fbuf,3,1,destfp);
			while (a=getc(mmfp),((a!=0)&&(a!='M'))) {
				if (a!='C') putc(a,destfp);
				fpgetfield(mmfp,fbuf);
				if (a=='P') fprintf(destfp,"%s!",NODENAME);
				if (a!='C')
					fwrite(fbuf,strlen(fbuf)+1,1,destfp);
				}
			if (a=='M') {
				putc('C',destfp);
				fwrite(roomnames[cmptr->m_room],
					strlen(roomnames[cmptr->m_room])+1,
					1,destfp);
				putc('M',destfp);
				do {
					if (ftell(mmfp)>=MM_FILELEN)
						fseek(mmfp,0L,0);
					a=getc(mmfp);
					putc(a,destfp);
					} while(a>0);
				}
			}
		}

	fclose(mmfp);
	return(msgs_spooled);
	}

int ismsgok(mpos,mmfp,sysname)
long mpos;
FILE *mmfp; {
	int a;
	char fbuf[128];

	fseek(mmfp,mpos,0);
	if (getc(mmfp)!=255) return(0);
	getc(mmfp); getc(mmfp);

	while (a=wrapgetc(mmfp),((a!='M')&&(a!=0))) {
		fpgetfield(mmfp,fbuf);
		if ((a=='P')&&(checkpath(fbuf,sysname)==0)) return(0);
		}
	return(1);
	}

int mail_to(user,where)
char user[];
struct smreturn *where; {
	struct usersupp usersupp;
	long uspos;
	int a;
	FILE *usfp;
	long aa;

	usfp=fopen("usersupp","r+");
	if (usfp==NULL) return(-1);
	uspos = (-1L);

	while (aa=ftell(usfp),
	      fread((char *)&usersupp,sizeof(struct usersupp),1,usfp)>0) {
		if (!struncmp(usersupp.fullname,user,strlen(user)))
			uspos=aa;
		if (!strucmp(usersupp.fullname,user)) goto ENDSEARCH;
		}

ENDSEARCH: if (uspos<0L) {
		fclose(usfp);
		return(-1);
		}

	fseek(usfp,uspos,0);
	fread((char *)&usersupp,sizeof(struct usersupp),1,usfp);
	for (a=0; a<(MAILSLOTS-1); ++a) {
		usersupp.mailnum[a]=usersupp.mailnum[a+1];
		usersupp.mailpos[a]=usersupp.mailpos[a+1];
		}
	usersupp.mailnum[MAILSLOTS-1]=where->smnumber;
	usersupp.mailpos[MAILSLOTS-1]=where->smpos;
	fseek(usfp,uspos,0);
	fwrite((char *)&usersupp,sizeof(struct usersupp),1,usfp);
	fclose(usfp);
	return(0);
	}

file_message(room,where)
char room[];
struct smreturn *where; {
	struct quickroom quickroom;
	struct fullroom fullroom;
	int rmnum,a,file;
	char frname[64];

	strcpy(frname,room);
	frname[sizeof(quickroom.QRname)-1]=0;
	rmnum=2;
	file=open("quickroom",O_RDWR);
	if (file<0) fprintf(stdout,"netproc: cannot open quickroom!\n");
	for (a=0; a<MAXROOMS; ++a) {
		if (read(file,&quickroom,sizeof(struct quickroom))<1)
			fprintf(stdout,"netproc: cannot read quickroom!\n");
		if (!strucmp(quickroom.QRname,frname)) rmnum=a;
		}
	lseek(file,(long)(rmnum*sizeof(struct quickroom)),0);
	if (read(file,&quickroom,sizeof(struct quickroom))<1)
		fprintf(stdout,"netproc: cannot read quickroom!\n");
	quickroom.QRhighest=where->smnumber;
	lseek(file,(long)(rmnum*sizeof(struct quickroom)),0);
	if (write(file,&quickroom,sizeof(struct quickroom))<1)
		fprintf(stdout,"netproc: cannot write to quickroom!\n");
	close(file);
	sprintf(frname,"./rooms/fullrm%d",rmnum);
	file=open(frname,O_RDWR);
	read(file,&fullroom,sizeof(struct fullroom));
	for (a=0; a<(MSGSPERRM-1); ++a) {
		fullroom.FRnum[a]=fullroom.FRnum[a+1];
		fullroom.FRpos[a]=fullroom.FRpos[a+1];
		}
	fullroom.FRnum[MSGSPERRM-1]=where->smnumber;
	fullroom.FRpos[MSGSPERRM-1]=where->smpos;
	lseek(file,0L,0);
	write(file,&fullroom,sizeof(struct fullroom));
	close(file);
	return(0);
}

checkpath(path,sys)	/* Checks to see whether its ok to send */
char path[];		/* Returns 1 for ok, send message	*/
char sys[]; {		/* Returns 0 if message already there	*/
	int a;
	char sys2[512];
	strcpy(sys2,sys);
	strcat(sys2,"!");

	for (a=0; a<strlen(path); ++a) 
		if (!strncmp(&path[a],sys2,strlen(sys2))) return(0);
	return(1);
}

get_sysinfo_type(name)	/* determine routing from sysinfo file */
char name[]; {
	struct syslist *stemp;
GETSN:	for (stemp=slist; stemp!=NULL; stemp=stemp->next) {
	    if (!strucmp(stemp->s_name,name)) {
		if (!strucmp(stemp->s_type,"use")) {
			strcpy(name,stemp->s_nexthop);
			goto GETSN;
			}
		if (!strucmp(stemp->s_type,"bin")) {
			return(M_BINARY);
			}
		if (!strucmp(stemp->s_type,"uum")) {
			return(M_UUCP);
			}
		}
	    }
	printf("netproc: cannot find system '%s' in mail.sysinfo\n",name);
	return(-1);
	}

getstring(file,string)		/* get a line of text from a file */
int file; char string[]; {	/* ignores lines beginning with # */
int a,b,c;
do {
	strcpy(string,"");
	a=0;
	do {
		c=0; b=read(file,&c,1);
		if (b<1) { string[a]=0; return(-1); }
		string[a]=c;
		++a;
		} while(c!=10);
		string[a-1]=0;
	} while(string[0]=='#');
return(strlen(string));
}

/*
 * routine to delete a room to process deleteroom commands
 */
deleteroom(roomname)
char *roomname; {
	struct quickroom qrbuf;
	int a;
	FILE *qr;
	long pos;

	qr=fopen("quickroom","r+");
	if (qr==NULL) return(1);
	fseek(qr,(long)(3*sizeof(struct quickroom)),0);
	for (a=3; (a<MAXROOMS)&&(strucmp(qrbuf.QRname,roomname)); ++a) {
		pos=ftell(qr);
		fread((char *)&qrbuf,sizeof(struct quickroom),1,qr);
		if (!strucmp(qrbuf.QRname,roomname)) {
			qrbuf.QRflags = qrbuf.QRflags ^ QR_INUSE;
			fseek(qr,pos,0);
			fwrite((char *)&qrbuf,sizeof(struct quickroom),1,qr);
			}
		}
	fclose(qr);
	return(0);
	}
		
/*
 * routine to create a room automatically to process addroom commands
 */
entroom(roomname,roomaccess,roompassword)
char *roomname;
int roomaccess;
char *roompassword; {
	int a,c,d,file;
	int exists,free_slot;
	long exists_pos,free_pos;
	char aaa[64];
	struct quickroom QRscratch,quickroom;
	struct fullroom fullroom;

	file=open("quickroom",O_RDWR);
	exists=(-1);
	free_slot=(-1);
	for (a=0; a<MAXROOMS; ++a) {
		read(file,&QRscratch,sizeof(struct quickroom));
		if ( (QRscratch.QRflags & QR_INUSE)
		   && (!strucmp(QRscratch.QRname,roomname)) ) exists=a;
		if ((QRscratch.QRflags&QR_INUSE)==0) free_slot=a;
		}
	if (exists!=(-1)) { /* room already exists, just set the network flag */
		printf("netproc: '%s' exists; adding network flag\n",roomname);
		exists_pos = ((long)exists) * ((long)sizeof(struct quickroom));
		lseek(file,exists_pos,0);
		read(file,&quickroom,sizeof(struct quickroom));
		quickroom.QRflags=quickroom.QRflags|QR_NETWORK;
		lseek(file,exists_pos,0);
		write(file,&quickroom,sizeof(struct quickroom));
		close(file);
		return(0);
		}
	if (free_slot==(-1)) {
		close(file);
		fprintf(stdout,"netproc: no room space available\n");
		return(0);
		}
	printf("netproc: creating room '%s' in slot #%d\n",roomname,free_slot);
	free_pos = ((long)free_slot) * ((long)sizeof(struct quickroom));
	lseek(file,free_pos,0);
	read(file,&quickroom,sizeof(struct quickroom));
	strcpy(quickroom.QRname,roomname);
	strcpy(quickroom.QRpasswd,"");
	if (roomaccess==3) strcpy(quickroom.QRpasswd,roompassword);
	quickroom.QRroomaide=(-1L);
	quickroom.QRhighest=0L;
	++quickroom.QRgen; if (quickroom.QRgen==100) quickroom.QRgen=10;
	quickroom.QRflags=(QR_INUSE|QR_NETWORK);
	if (roomaccess>1) quickroom.QRflags=(quickroom.QRflags|QR_PRIVATE);
	if (roomaccess==2) quickroom.QRflags=(quickroom.QRflags|QR_GUESSNAME);
	if (roomaccess==3) quickroom.QRflags=(quickroom.QRflags|QR_PASSWORDED);
	lseek(file,free_pos,0);
	write(file,&quickroom,sizeof(struct quickroom));
	close(file);

	/* Initialize a blank fullroom structure */
	for (a=0; a<MSGSPERRM; ++a) {
		fullroom.FRnum[a]=0L;
		fullroom.FRpos[a]=0L;
		}

	sprintf(aaa,"./rooms/fullrm%d",free_slot);
	file=open(aaa,O_RDWR);
	write(file,&fullroom,sizeof(struct fullroom));
	close(file);
	return(0);
}

/*
 * add a room to the sending list for every system we send "control" to
 */
add_netwide_room(roomname)
char *roomname; {
	FILE *nsls,*sysfl;
	char buf[128];
	char found_control,found_room;

	nsls=popen("ls ./network/systems/*","r");
	if (nsls==NULL) return(1);
	while (fgets(buf,128,nsls)!=NULL) {
		buf[strlen(buf)-1]=0;
		sysfl=fopen(buf,"r+");
		if (sysfl!=NULL) {
			found_control=0; found_room=0;
			while (fgets(buf,128,sysfl)!=NULL) {
				buf[strlen(buf)-1]=0;
				if (!strucmp(buf,"control")) found_control=1;
				if (!strucmp(buf,roomname)) found_room=1;
				}
			if (found_control && (!found_room))
				fprintf(sysfl,"%s\n%ld\n",roomname,0L);
			fclose(sysfl);
			}
		}
	pclose(nsls);
	return(0);
	}

/*
 * delete a room from the sending list for every system we send "control" to
 */
delete_netwide_room(roomname)
char *roomname; {
	FILE *nsls,*sysfl,*newsysfl;
	char buf[128],tempfile[32],sysflnm[64];
	char found_control,found_room;

	sprintf(tempfile,"/tmp/dnr%d",getpid());
	nsls=popen("ls ./network/systems/*","r");
	if (nsls==NULL) return(1);
	while (fgets(sysflnm,64,nsls)!=NULL) {
		sysflnm[strlen(sysflnm)-1]=0;
		sysfl=fopen(sysflnm,"r");
		if (sysfl!=NULL) {
			newsysfl=fopen(tempfile,"w");
			found_control=0; found_room=0;
			while (fgets(buf,128,sysfl)!=NULL) {
				buf[strlen(buf)-1]=0;
				if (!strucmp(buf,"control")) found_control=1;
				if ((found_control)&&(!strucmp(buf,roomname))) {
					fgets(buf,128,sysfl);
					found_room=1;
					}
				else fprintf(newsysfl,"%s\n",buf);
				}
			fclose(sysfl);
			fclose(newsysfl);
			sprintf(buf,"rm %s; mv %s %s",sysflnm,tempfile,sysflnm);
			if (found_room) system(buf);
			else unlink(tempfile);
			}
		}
	pclose(nsls);
	return(0);
	}

/*
 * rename a room
 * (renames *all* references to the old room name in quickroom and in
 * all network/systems files, whether we feed them Control or not)
 */
rename_netwide_room(oldname,newname)
char *oldname,*newname; {
	FILE *quickroom_fp,*shell_fp;
	struct quickroom qr_buf;
	int counter;
	FILE *nsls,*sysfl,*newsysfl;
	char buf[128],tempfile[32],sysflnm[64];

	if ( (!strucmp(oldname,"Control")) ||
	     (!strucmp(oldname,"Patio")) ||
	     (!strucmp(oldname,"Mail")) ||
	     (!strucmp(oldname,"Aide")) )
		return(1); /* no way! */

	quickroom_fp=fopen("quickroom","r+");
	if (quickroom_fp==NULL) return(1);

	for (counter=3; counter<MAXROOMS; ++counter) {
		fseek(quickroom_fp,(long)counter*sizeof(struct quickroom),0);
		fread((char *)&qr_buf,sizeof(struct quickroom),1,quickroom_fp);
		if (!strucmp(qr_buf.QRname,oldname)) {
			strcpy(qr_buf.QRname,newname);
			fseek(quickroom_fp,
				(long)counter*sizeof(struct quickroom),0);
			fwrite((char *)&qr_buf,sizeof(struct quickroom),
				1,quickroom_fp);
			}
		}
	fclose(quickroom_fp);

	/* now update the network/systems files */
	sprintf(tempfile,"/tmp/dnr%d",getpid());
	nsls=popen("ls ./network/systems/*","r");
	if (nsls==NULL) return(1);
	while (fgets(sysflnm,64,nsls)!=NULL) {
		sysflnm[strlen(sysflnm)-1]=0;
		sysfl=fopen(sysflnm,"r");
		if (sysfl!=NULL) {
			newsysfl=fopen(tempfile,"w");
			while (fgets(buf,128,sysfl)!=NULL) {
				buf[strlen(buf)-1]=0;
				if (!strucmp(buf,oldname)) {
					strcpy(buf,newname);
					}
				fprintf(newsysfl,"%s\n",buf);
				}
			fclose(sysfl);
			fclose(newsysfl);
			sprintf(buf,"rm %s; mv %s %s",sysflnm,tempfile,sysflnm);
			system(buf);
			}
		}
	pclose(nsls);
	return(0);
	}


/* 
 * process network control messages
 */
process_net_control(filename)
char *filename; {
	FILE *msg;
	char buf[64];
	char fields[10][64];
	int a;

	/* open the file and read the header */
	msg=fopen(filename,"r");
	if (getc(msg)!=255) return(1);
	getc(msg); getc(msg);

	/* skip to the message text */
	while (a=getc(msg), ((a!='M')&&(a>=0)) ) fpgetfield(msg,buf);
	if (a<0) {
		fclose(msg);
		return(2);
		}

	fgets(buf,64,msg);
	if (strncmp(buf,"#netcmd",7)) return(3);

	printf("netproc: net command |");
	for (a=0; a<10; ++a) fields[a][0]=0;
	for (a=0; a<10; ++a) {
		if (fgets(fields[a],64,msg)==NULL) break;
		fields[a][strlen(fields[a])-1]=0;
		printf("%s|",fields[a]);
		}
	printf("\n");
	fclose(msg);

	/* various net commands we can process... */
	if (!strcmp(fields[0],"addroom")) {
		a=atoi(fields[2]); if ((a<1)||(a>4)) a=1;
		entroom(fields[1],a,fields[3]);
		add_netwide_room(fields[1]);
		}
	else if (!strcmp(fields[0],"deleteroom")) {
		deleteroom(fields[1]);
		delete_netwide_room(fields[1]);
		}
	else if (!strcmp(fields[0],"disconnect")) {
		delete_netwide_room(fields[1]);
		}
	else if (!strcmp(fields[0],"renameroom")) {
		rename_netwide_room(fields[1],fields[2]);
		}
	else printf("netproc: unrecognized command\n");
	return(0);
	}


/*
 * proc_file_transfer()  -  handle a simple file transfer packet
 */
proc_file_transfer(tname)
char *tname; {	/* name of temp file containing the whole message */
	char buf[128];
	char dest_dir[32];
	FILE *tfp,*uud;
	int a,b;

	printf("netproc: processing network file transfer...\n");
	strcpy(dest_dir,config.c_bucket_dir);

	tfp=fopen(tname,"r");
	if (tfp==NULL) printf("netproc: cannot open %s\n",tname);
	getc(tfp); getc(tfp); getc(tfp);
	do {
		a=getc(tfp);
		if (a!='M') {
			fpgetfield(tfp,buf);
			if (a=='O') for (b=0; b<MAXROOMS; ++b) {
				if (!strucmp(buf,roomnames[b]))
					strcpy(dest_dir,roomdirs[b]);
				}
			}
		} while ((a!='M')&&(a>=0));
	if (a!='M') {
		fclose(tfp);
		printf("netproc: no message text for file transfer\n");
		return;
		}

	sprintf(buf,"cd ./files/%s; exec uudecode",dest_dir);
	uud=(FILE *)popen(buf,"w");
	if (uud==NULL) {
		printf("netproc: cannot open uudecode pipe\n");
		fclose(tfp);
		return;
		}

	fgets(buf,128,tfp);
	buf[strlen(buf)-1] = 0;
	for (a=0; a<strlen(buf); ++a) if (buf[a]=='/') buf[a]='_';
	fprintf(uud,"%s\n",buf);
	printf("netproc: %s\n",buf);
	while(a=getc(tfp), a>0) putc(a,uud);
	fclose(tfp);
	pclose(uud);
	return;
	}
