#include <fido.h>
#include <fidomem.h>
#include <ascii.h>
#include <xfbuf.h>

/* This is the Fido initialization program. It reads the
default .INI files and others and creates a FIDO.SYS */

/**/ clprintf() {}

/* Structure for Version 11 virtual bulletin board. */

struct _sys {
	unsigned ls_caller;	/* LS word of callers */
	int priv;		/* min. privelege to access this */
	char msgpath[40];	/* path for message base, */
	char bbspath[40];	/* path for .BBS files, */
	char hlppath[40];	/* path for HLP files, */
	char uppath[40];	/* path for uploads, */
	char filepath[40];	/* path for file area, */
	int attrib;		/* attributes */
	unsigned ms_caller;	/* MS word of callers */
	long quote_pos;		/* quote file index */
};
#define SYSMAIL 1		/* is a mail area */

/* MAIL.SYS file structure. The contents of this does not conform
to internal standards; it is for export to other programs. */

struct _mail {
	int node;		/* local node number, */
	float fudge;		/* obs */
	int rate;		/* obs */
	char msgpath[80];	/* path to find mail in */
	char filepath[80];	/* mail file path */
	int net;		/* net number */
	int alt_node;		/* alternate node number */
	int alt_net;		/* alternate net number */

/* extended length */

	int zone;
	int alt_zone;
};

/* Version 11 scheduler structure. */

#define OLDSCHEDS (5 * DAYS_WK)	/* size of time table */

struct _oldsched {
	struct {
		int year,month,day,daywk;
		int hour,mins,sec;
	} time;
	int len;
	int enable;		/* 1 == enabled -1 == disabled 0 == deleted */
	int trigger;
	int result;		/* returned value */
	char tag;		/* schedule tag */
	int a,b,c,d,e;
};

char dayname[8][4] = {
	"Sun",
	"Mon",
	"Tue",
	"Wed",
	"Thu",
	"Fri",
	"Sat",
	"All"
};
int sysfile;			/* FIDO.SYS global handle */
struct _fido fido;		/* thing we build */
struct _area area;

struct _cmd maindef[] = {
	"M]sg-Section",0,LNONE,
	"F]ile-Section",1,LNONE,
	"B]ulletins",0,LNONE,
	"S]tatistics",0,LNONE,
	"T]riggers",7,LNONE,
	"C]hange",0,LNONE,
	"P]age-Operator",1,LNONE,
	"L]ist-Callers",2,LNONE,
	"A]ns-Questionnaire",0,LNONE,
	"V]ersion",0,LNONE,
	"O]utside",7,LNONE,
	"E]xitDOS",7,LNONE,
	"G]oodbye",0,LNONE,
	"",0,LNONE
};

struct _cmd chgdef[] = {
	"N]ame",2,LNONE,
	"A]ddress",2,LNONE,
	"P]assword",0,LNONE,
	"H]elp-Level",0,LNONE,
	"C]olumns",0,LNONE,
	"L]ines",0,LNONE,
	"I]nterface",0,LNONE,
	"F]iller-nulls",0,LNONE,
	"M]ain-Menu",0,LNONE,
	"",0,LNONE
};

struct _cmd msgdef[] = {
	"N]ext",0,LNONE,
	"P]revious",0,LNONE,
	"E]nter",2,LNONE,
	"K]ill",2,LNONE,
	"T]o-You",0,LNONE,
	"A]rea-Change",2,LNONE,
	"R]eply",2,LNONE,
	"C]ontinuous",0,LNONE,
	"L]ist",0,LNONE,
	"S]earch",0,LNONE,
	"U]pdate-Msg",0,LNONE,
	"O]verride-Path",7,LNONE,
	"W]rite-Buffer",2,LNONE,
	"G]oodbye",0,LNONE,
	"M]ain-Menu",0,LNONE,
	"",0,LNONE
};

struct _cmd filedef[] = {
	"F]iles",2,LNONE,
	"D]ownload",2,LNONE,
	"U]pload",2,LNONE,
	"A]rea-Change",2,LNONE,
	"T]ype",3,LNONE,
	"S]tatistics",0,LNONE,
	"L]ocate",2,LNONE,
	"R]aw-Display",3,LNONE,
	"K]ill-File",7,LNONE,
	"O]verride-Path",7,LNONE,
	"G]oodbye",0,LNONE,
	"M]ain-Menu",0,LNONE,
	"",0,LNONE
};
struct _cmd editdef[] = {	/* edit msg */
	"S]ave",0,LNONE,
	"C]ontinue",0,LNONE,
	"A]bort",0,LNONE,
	"L]ist",0,LNONE,
	"E]dit",0,LNONE,
	"D]elete",0,LNONE,
	"I]nsert",0,LNONE,
	"R]ead-Buffer",0,LNONE,
	"H]eader",0,LNONE,
	"",0,LNONE
};

struct _cmd trigdef[] = {	/* T)rigger command */
	"T]rigger",0,LNONE,
	"E]vents",0,LNONE,
	"",0,LNONE
};

struct _cmd attdef[] = {	/* file attach/request */
	"A]ttach",4,LNONE,
	"R]equest",7,LNONE,
	"S]ubject",0,LNONE,
	"",0,LNONE
};

struct _cmd buldef[] = {	/* bulletins */
	"L]ist-Bulletins",0,LNONE,
	"M]ain-Menu",0,LNONE,
	"",0,LNONE
};

int _stack = 5000;

FLAG mailprog = 0;		/* special MAILER.EXE keyword */

main(argc,argv)
int argc;
char **argv;
{
char *p,fn[SS],fname[SS],buff[256];
int f,i;
FLAG change,quick;
struct _rptrcd rptrcd;

	printf("SET-FIDO (21 Jun 91) Configuration Program for ");
	copr();
	allmem();				/* get all available */
	if (! fastfile(4)) {			/* init the buffered file system */
		printf(" * Cant start the file system (fidoini)");
		exit(1);
	}
	newdelim(", \t\r\n");			/* arg delimiter list, */

/*
mailprog:	Rob Thomas' special MAILER.EXE program; does FidoNet only, 
		shares SET-FIDO etc. Special keyword 'program <n>' controls
		SET-FIDO behavior; skips portions of Fido/FidoNet init.

quick:		/Q command line option for speedy initialization -- 1 ==
		Leaves NODELIST.* files intact. (Cleared if version
		is different, etc)

change:		Internal flag to detect init level: 0 == same version and
		revision; 1 == same version, different revision; 2 == 
		different program version.
*/

	mailprog= 0;				/* no, not the special MAIL.EXE program */
	quick= 0;				/* no, don't skip .INI files */
	change= 0;				/* 0 == simply update, 1 == revision changed, */

	fname[0]= NUL;
	while (--argc) {
		++argv;
		cpyarg(fname,*argv);		/* optional .INI filename */
		strip_switch(buff,*argv);	/* the switches, */
		for (i= 0; buff[i]; i++) switch (tolower(buff[i])) {
			case 'q': quick= 1; break;
		}
	}

/* Try to look at program and file revision, determine the init level. */

	sysfile= open("fido.sys",2);		/* open it for read/write */
	if (sysfile != -1) {
		read(sysfile,&fido,sizeof(struct _fido));
		if (fido.fido_version != FIDOVER) {
			change= 2;		/* not v12, etc */
			printf(" * Different Fido/FidoNet program");
		}
		if (fido.file_version != FILEVER) {
			printf(" * Different Fido/FidoNet version");
			if (fido.file_version < ('q' - 'a' + 1))
				fido.event= -1;	/* clear old version event flag */
			change= 1;		/* (feature only in 12Q up) */
		}

	} else {
		printf(" * New installation; \"FIDO.SYS\" doesn't exist");
		change= 2;
	}
	setdefaults();				/* clear stuff set by FIDO.INI */
	if (change > 1) {			/* incompatible version */
		fido.callers= 0;		/* reset these also */
		fido.quote_pos= 0;		/* not used yet */
		fido.caller= -1;		/* no caller on yet */
		fido.switches= 0;		/* no switches set */
		fido.oneshots= 0;		/* no oneshots set */
		fido.autolog= -1;		/* no autologin */
		fido.event= -1;			/* tested right below! */
		quick= 0;			/* force full init */
	}

/* Make sure that the sysop didn't leave a FidoNet session incomplete. */

	if ((! quick) && (fido.event != -1)) {
		if (sysfile != -1) close(sysfile); /* close if open, */
		printf("\r\n\r\n * A FidoNet event was left incomplete (CTRL-ALT-DEL reboot, for\r\n");
		printf(" * example.) You must run Fido and terminate the event, or use \"FIDO/C\",\r\n");
		printf(" * before you can run \"SET-FIDO\".\r\n");
		exit(1);
	}

/* Create a new FIDO.SYS file if necessary. */

	if (change > 1) {
		if (sysfile != -1) close(sysfile);
		printf(", making a new system file\r\n");
		sysfile= creat("fido.sys",2);		/* make a new one, */
		if (sysfile == -1) {
			printf(" * Can't create \"FIDO.SYS\"!");
			exit(1);
		}
		write(sysfile,&fido,sizeof(struct _fido)); /* write it out, */

	} else if (change) printf("\r\n");

/* Now read .INI files and all that rot. */

	if (*fname) finit(fname);			/* use special name */
	else finit("FIDO.INI");				/* else default */

	if (! mailprog) {				/* for Fido/FidoNet */
		getareas("AREAS.INI");			/* always do these */
		getcmds("COMMANDS.INI");
		getsched("EVENTS.INI");
	}
	lseek(sysfile,0L,0);				/* write out */
	write(sysfile,&fido,sizeof(struct _fido));	/* new/updated file */

/* Now do all the language stuff if the right files exist. */

	if (! mailprog) {					/* Fido */
		makesname(fn,"LANGUAGE.INI");			/* try to open it */
		i= open(fn,0);
		if ((i == -1) && fbit(FBIT_LINGUAL)) 		/* if mandatory */
			cprintf(" ! The file \"LANGUAGE.INI\" is missing!\r\n");

		else {
			cprintf(" * Compiling language-specific \"COMMANDS.INI\" files\r\n");
			while (rline(i,buff,sizeof(buff))) {	/* do each one */
				p= skip_delim(buff);
				if (*p == ';') continue;	/* skip comment lines */
				if (! *p) continue;		/* skip blank lines */
				p= next_arg(p);			/* point to pathname */
				cpyarg(buff,p);			/* clean copy, */
				stoupper(buff);			/* upper case, */
				if (! fixdir(buff)) {		/* fixup pathname */
					cprintf("Subdirectory \"%s\" doesn't exist!\r\n",buff);
					continue;
				}
				strip_path(fn,buff);		/* strip off *.* */
				strcat(fn,"COMMANDS.INI");	/* full filename */
				getcmds(fn);			/* process commands */

				strip_path(fn,buff);
				strcat(fn,"COMMANDS.SYS");	/* output filename */
				f= creat(fn,1);
				if (f == -1) {
					cprintf(" ! Can't create \"%s\"?\r\n",fn);
					break;
				}
				write(f,&fido.cmd,sizeof(fido.cmd));
				close(f);
	
				getsys();			/* re-load defaults! */
			}
		}
	}

/* Do the nodemap stuff. The rptrcd is really the first record within 
NODELIST.NMP; the _nmap structure is built at runtime from .IDX and .NMP. */

	if (! quick) {
		makenname(fn,"nodemap.?");			/* kill all nodemaps */
		killall(fn);
		makenname(fn,"nodelist.nmp");			/* zap the default */
		i= open(fn,2);					/* nodemap */
		if (i != -1) {
			read(i,&rptrcd,sizeof(struct _rptrcd));
			rptrcd.tag= NUL;			/* force regeneration */
			lseek(i,0L,0);
			write(i,&rptrcd,sizeof(struct _rptrcd));
			close(i);
		}

/* Kill all the outgoing packets, etc */

		getarea(fido.netfarea,&area,1);		/* get FidoNet file area */
		makeuname(fn,"*.OUT");
		killall(fn);				/* delete output packets */
		makeuname(fn,"*.FLO");
		killall(fn);				/* delete output file lists */
		makeuname(fn,"*.REQ");
		killall(fn);				/* delete file request lists */
	}

/* If we are doing v11 compatible files, generate them now. */

	if (fbit(FBIT_V11)) {
		mailsys();				/* create MAIL.SYS */
		makesname(fn,"SYSTEM??.BBS");		/* kill old SYSTEMn.BBS */
		killall(fn);
		for (i= 0; i < fido.marea_max; i++) 	/* do all Msg Areas */
			systemn(i,0);
		for (i= 0; i < fido.farea_max; i++) 	/* do all File Areas */
			systemn(i,1);
		eventsys();				/* SCHED.BBS */
	}
	close(sysfile);
	exit(0);
}

/* Make a full nodelist pathname. */

makenname(p,s)
char *p,*s;
{
	strcpy(p,fido.nodepath);
	strcat(p,s);
}

/* Make a full upload pathname. */

makeuname(p,s)
char *p,*s;
{
	strcpy(p,area.upath);
	strcat(p,s);
}

/* Assemble a system filename. */

makesname(p,s)
char *p,*s;
{
	strcpy(p,fido.syspath);
	strcat(p,s);
}

/* Open the system file FIDO.SYS, and read the structure into memory; returns
-1 if error. */

getsys() {
int n;

	n= open("fido.sys",0);
	if (n == -1) return(-1);		/* oops! */
	read(n,&fido,sizeof(struct _fido));	/* load it */
	close(n);				/* close it */
	return(1);
}

/* Reset the variables specified in FIDO.INI */

setdefaults() {
char *cp;
int i;
/* Clear out the damned structure. There's all sorts of things we DONT want
to init; hence the state thingie. */

	cp= (char *) &fido.zone;		/* clear starting here */
	i= 0;					/* state variable */
	while (cp - (char *) &fido < sizeof(struct _fido)) {
		switch (i) {
			case 0: if (cp == (char *) &fido.sched) ++i; else *cp= NUL; break;
			case 1: if (cp == (char *) &fido.termcode - 1) ++i; break;
			case 2: if (cp == (char *) &fido.switches) ++i; else *cp= NUL; break;
			case 3: if (cp == (char *) &fido.name - 1) ++i; break;
			case 4: if (cp == (char *) &fido.cmd) ++i; else *cp= NUL; break;
			case 5: if (cp == (char *) &fido.extra14 - 1) ++i; break;
			case 6: *cp= NUL; break;
		}
		++cp;
	}

	fido.fido_version= FIDOVER;		/* correct version, */
	fido.file_version= FILEVER;

	fido.defmnbr= 0;			/* caller default msg area number */
	fido.deffnbr= 0;			/* caller default file area number */
	fido.logonbr= -1;			/* G)oodbye msg area */

	fido.netmarea= -1;			/* default is NO net areas */
	fido.netfarea= -1;

	fido.slimit= 10;			/* default 10 signon limit */
	fido.nlimit= 60;			/* default= 1 hr time limit, */
	fido.first_limit= 60;			/* default for 1st time callers, */
	fido.klimit= 1000;			/* 1M download limit, */
	fido.dlimit= 8 * 60;			/* 8 hr daily limit, */

	fido.def_priv= NORMAL;			/* normal privelege, */
	fido.def_keys= KNONE;			/* no keys */

	fido.cd_bit= 0x80;			/* CD bit on IBM Async Card CTS */
	fido.mdmtype= HAYES;			/* default hayes modem */

	fido.textlines= 51;			/* default editor, lines */

	fido.bucks= '$';			/* default money sign */
	fido.sep_char= ',';			/* 1000's separator */
	fido.dec_char= '.';			/* decimal character */

	fido.connect_tries= 1;			/* 1 attempt with connect */
	fido.dial_tries= 20;			/* 20 attempts to dial */
	fido.event= -1;				/* no sched run yet */
	fido.rings= 1;				/* answer on first ring */
	fido.dial_interval= 1;			/* dial every minute */
	fido.cont_interval= 5;			/* enable CONT events */

	fido.zmttype= 0;			/* Zmodem Tx window default */
	fido.zmrtype= 0;			/* Zmodem Rx fully ACKed */
	fido.zmtstart= 1024;			/* initial Zmodem block size */

/* This needs to be 8192 to accomocate incoming 8K Bink data packets! */

	fido.zmblkmax= 8192;			/* max. block size for Zmodem */

	setfbit(FBIT_TSYNC,1);			/* multi-tsync YES */
	setfbit(FBIT_WAZOO,1);			/* Wazoo YES */
	setfbit(FBIT_NEWCLR,1);			/* public system */
	setfbit(FBIT_KEEPNMP,1);		/* cache nodemaps */
	setfbit(FBIT_TLG,1);			/* timelog YES */
	setfbit(FBIT_NLG,1);			/* netlog YES */

	fido.areaoff= sizeof(struct _fido);	/* offset to areas */
}

/* Copy a command table into FIDO.SYS */

setcmd(s,d)
struct _cmd *s,*d;
{
	while (*s-> name) {
		strcpy(d-> name,s-> name);
		d-> priv= s-> priv;
		d-> locks= s-> locks;
		++s; ++d;
	}
}

/* Fido initializer */

#define KEYLEN 10

char keyword[][KEYLEN] = { 

/* 0 */		"normal-li",
		"daily-lim",
		"first-lim",
		"signon-li",
		"k-limit",

/* 5 */		"e-errorle",
		"o-errorle",
		"g-errorle",

/* 8 */		"modem-typ",
		"cd-bit",
		"modem-str",

/* 11 */	"dial-trie",
		"connect-t",
		"io-port",
		"emit-v11",
		"node",
		"net",
		"alt-node",
		"alt-net",

/* 19 */	"private",
		"msg-lengt",
		"default-p",
		"money",
		"path-disp",
		"xfer-disp",

/* 25 */	"net-work-",
		"zone",
		"alt-zone",
		"new-calle",

/* 29 */	"area-file",
		"sched-fil",
		"cmd-file",

/* 32 */	"thousands",
		"decimal",

/* 34 */	"dial-pref",
		"mail-erro",
		"quick-log",
		"multi-tas",

/* 38 */	"max-baud",
		"zm-tx-typ",
		"zm-rx-typ",
		"---------",

/* 42 */	"show-seen",
		"multi-tsy",
		"wazoo",

/* 45 */	"last-name",
		"system-na",
		"fsc001",
		"external-",

/* 49 */	"zm-tx-sta",
		"zm-max-bl",
		"program",
		"text-path",

/* 53 */	"dot",			/* AARGH -- see below */
		"alt-dot",

/* 55 */	"directory",		/* this group are DCM keywords */
		"key",			/* there is no state for them */
		"aka",			/* they are here so SET-FIDO */
		"system",		/* will ignore them */
		"sysop",
		"point",
		"log",
		"flag",

/* 63 */	"keep-node",
		"rings",
		"nodelist-",
		"system-pa",
		"fsc011",

/* 68 */	"file-erro",
		"dial-inte",
		"keep-pack",
		"cont-inte",
		"timelog",
		"netlog",

/* 74 */	"multi-lin",
		"free-form",

		"password",	/* MAIL.EXE only */
		"xferlog",

		""		/* end of list */
};

finit(fn)
char *fn;
{
char *process();

int i,f;
char ln[256];			/* LONG raw input line */
char orig_word[sizeof(ln)];	/* original of word we parse */
char word[sizeof(ln)];		/* word we parse */
char arg[sizeof(ln)];		/* an arg for it */
char text[sizeof(ln)];		/* possible quoted string */
int value;			/* argument value */
int line;			/* line in file */
FLAG err;			/* error in file */
char *cp,*p;


	f= open(fn,0);
	if (f == -1) {
		printf(" * Can't find Startup File %s\r\n",fn);
		return(0);
	}
	printf(" * Reading Startup File %s\r\n",fn);

	newdelim(" \t\r\n");			/* comma not a delim */
	err= 0;
	line= 0;
	while (rline(f,ln,sizeof(ln))) {
		++line;

		clip_cmt(ln);				/* strip off comments */
		cp= skip_delim(ln);			/* skip leading blanks, etc */
		if (*cp == NUL) continue;		/* ignore blank lines */

		if (*cp == '*') {			/* label line */
			puts(ln); puts("\r\n");
			continue;
		}
		cpyatm(word,cp);			/* the key word, */
		cpyatm(orig_word,cp);			/* untouched copy */
		word[KEYLEN - 1]= NUL;			/* truncate to match */
		cp= next_arg(cp);			/* skip keyword, */

/* Preprocess the argument(s); make arg == clean copy of the word; value == its
atoi() value; value == 1 if arg is "yes" or "on"; text == raw text or
contents of quoted string. */

		cpyatm(arg,cp);				/* copy its arg */

		p= text;				/* copy any quoted string */
		if (*cp++ == '"') {			/* if a quoted string, */
			while (*p= *cp) {
				if (*p == '"') break;	/* copy up til next quote */
				++p; ++cp;
			}
		} else strcpy(p,cp);
		*p= NUL;

		value= atoi(arg);			/* atoi() it blindly */
		if (same(arg,"on") || same(arg,"yes"))
			value= 1;			/* else 0 == off == no */

		stolower(word);
		stolower(arg);

		if (! *arg) {
			inierr(fn,line,ln,"Incomplete command");
			err= 1;
			continue;
		}

		for (i= 0; *keyword[i]; ++i) {		/* find the word, */
			if (same(keyword[i],word)) {	/* if a match, */
				cp= process(i,arg,value,text,orig_word); /* do it, */
				if (*cp) {
					inierr(fn,line,ln,cp);
					err= 1;
				}
				break;
			}
		}
		if (! *keyword[i]) {
			inierr(fn,line,ln,"Not a command");
			err= 1;
		}
	}
	close(f);
	return(1);
}
/* Complain about this line. */

inierr(fn,lineno,ln,error)
char *fn;
int lineno;
char *ln,*error;
{
	printf("%s in file %s at line %d\r\n",error,fn,lineno);
	printf("  \"%s\"\r\n",ln);
}
/* Process the keyword. */

char *process(i,arg,value,text,orig_word)
int i;
char *arg;
int value;
char *text;
char *orig_word;
{
char *cp;
char *levelbad();
unsigned n;

	cp= "";
	switch (i) {
		case 0: fido.nlimit= value; break;
		case 1: fido.dlimit= value; break;
		case 2: fido.first_limit= value; break;
		case 3: fido.slimit= value; break;
		case 4: fido.klimit= value; break;

		case 5: cp= levelbad(value); if (! *cp) fido.termcode= value; break;
		case 6: cp= levelbad(value); if (! *cp) fido.outcode= value; break;
		case 7: cp= levelbad(value); if (! *cp) fido.byecode= value; break;

		case 8: fido.mdmtype= value; break;
		case 9: fido.cd_bit= value; break;
		case 10: arg[29]= NUL; stoupper(arg); strcpy(fido.mdmstr,arg); strcat(fido.mdmstr,"\r"); break;
		case 11: if ((value < 1) || (value > 255)) cp= "Must be 1 to 255"; else fido.dial_tries= value; break;
		case 12: if ((value < 1) || (value > 255)) cp= "Must be 1 to 255"; else fido.connect_tries= value; break;
		case 13: fido.iodev= value - 1; break;
		case 14: setfbit(FBIT_V11,value); break;

		case 15: fido.number= fido.altnumber= value; break;
		case 16: fido.net= fido.altnet= value; break;
		case 26: fido.zone= fido.altzone= value; break;
		case 53: fido.point= fido.altpoint= value; break;

		case 17: fido.altnumber= value; break;
		case 18: fido.altnet= value; break;
		case 27: fido.altzone= value; break;
		case 54: fido.altpoint= value; break;

		case 19: setfbit(FBIT_NEWCLR,!value); break;
		case 20: if ((value < 1) || (value > 175)) cp= "Must be 1 to 175"; else fido.textlines= value; break;
		case 21: if (value > EXTRA) cp= "privilege must be 0 - 4"; else fido.def_priv= value; break;

		case 22: if (! *arg) cp= "Missing money character"; else fido.bucks= *arg; break;
		case 23: setfbit(FBIT_PATHDISP,value); break;
		case 24: setfbit(FBIT_XFERDISP,value); break;

		case 25: arg[63]= NUL; if (! fixdir(arg)) cprintf("Subdirectory \"%s\" doesn't exist!\r\n",arg); 
			strip_path(fido.nodepath,arg); break;

		case 28: if ((value < 1) || (value > 32)) cp= "KEYs are numbered 1 - 32";
			else fido.def_keys |= (1 << value - 1); break;

		case 29: getareas(arg); break;
		case 30: getscheds(arg); break;
		case 31: getcmds(arg); break;

		case 32: if (! *arg) cp= "Missing seperator character"; else fido.sep_char= *arg; break;
		case 33: if (! *arg) cp= "Missing decimal character"; else fido.dec_char= *arg; break;

		case 34: arg[29]= NUL; strcpy(fido.dial_pref,arg); break;
		case 35: cp= levelbad(value); if (! *cp) fido.mailcode= value; break;
		case 36: setfbit(FBIT_QUICK,value); break;
		case 37: fido.mtasker= value; break;

		case 38: fido.maxbaud= value; break;
		case 39: fido.zmttype= value; break;
		case 40: fido.zmrtype= value; break;
		case 41: break;
		case 42: setfbit(FBIT_SEENBY,! value); break;
		case 43: setfbit(FBIT_TSYNC,value); break;
		case 44: setfbit(FBIT_WAZOO,value); break;
		case 45: setfbit(FBIT_YNAME,value); break;
		case 46: arg[59]= NUL; strcpy(fido.name,text); break;
		case 47: setfbit(FBIT_FSC001,value); break;

		case 48: cp= orig_word + strlen(orig_word) - 1;	/* cp == last char */
			n= tolower(*cp) - 'a'; 
			if (n >= sizeof(fido.ext_logins)) cp= "\"EXTERNAL LOGIN\" out of range";
			else {
				cp= levelbad(value); 		/* check for error */
				if (! *cp) fido.ext_logins[n]= value; /* set errorlevel */
			}				
			break;

		case 49: fido.zmtstart= value; break;
		case 50: fido.zmblkmax= value; break;

		case 51: mailprog= value; break;
		case 52: arg[63]= NUL; if (! fixdir(arg)) cprintf("Subdirectory \"%s\" doesn't exist!\r\n",arg); 
			strip_path(fido.textpath,arg); break;

		case 55: case 56: case 57: case 58:		/* DCM keywords */
		case 59: case 60: case 61: case 62:		/* are ignored */
			break;

		case 63: setfbit(FBIT_KEEPNMP,value); break;
		case 64: if ((value < 1) || (value > 255)) cp= "RINGS must be 1 to 255";
			else fido.rings= value; break;

		case 65: arg[63]= NUL; if (! fixdir(arg)) cprintf("Subdirectory \"%s\" doesn't exist!\r\n",arg); 
			strip_path(fido.nodepath,arg); break;
		case 66: arg[50]= NUL; if (! fixdir(arg)) cprintf("Subdirectory \"%s\" doesn't exist!\r\n",arg); 
			strip_path(fido.syspath,arg); break;
		case 67: setfbit(FBIT_DIETIFNA,value); break;
		case 68: cp= levelbad(value); if (! *cp) fido.filecode= value; break;
		case 69: if ((value < 1) || (value > 60)) cp= "DIAL-INTERVAL must be 1 to 60";
			else fido.dial_interval= value; break;
		case 70: setfbit(FBIT_KPACKET,value); break;
		case 71: if ((value < 1) || (value > 60)) cp= "CONT-INTERVAL must be 1 to 60";
			else fido.cont_interval= value; break;
		case 72: setfbit(FBIT_TLG,value); break;
		case 73: setfbit(FBIT_NLG,value); break;
		case 74: setfbit(FBIT_LINGUAL,value); break;
		case 75: setfbit(FBIT_FNAME,value); break;
		case 76: arg[8]= NUL; strcpy(fido.extra8,arg); break;
		case 77: setfbit(FBIT_LOGXFER,value); break;
	}
	return(cp);
}

/* Set an FBIT */

setfbit(bit,value)
int bit;
int value;
{
	if (value) value= 1;		/* T or NIL */

	fido.fbits[bit / sizeof(char)] &= ~(1 << (bit % sizeof(char)));
	fido.fbits[bit / sizeof(char)] |= value << (bit % sizeof(char));
}

/* Return true if the FBIT is set. */

fbit(bit)
int bit;
{
	return(fido.fbits[bit / sizeof(char)] & (1 << bit % sizeof(char)));
}

/* Return a pointer to an error message if the ERRORLEVEL passed is bad. */

char *levelbad(e)
int e;
{
	if (e == 0) return("");
	if ((e >= 3) && (e <= 255)) return("");
	return("ERRORLEVELs must be 0 or 3 - 255");
}


/* Generate the message and file areas. This writes directly into the end
of the system file. We have to make two passes; one for the message
areas, one for the file areas, since the number of areas is variable
and messages come first. */

getareas(fn)
char *fn;
{
char *cp;
int f;

	newdelim(", \t\r\n");			/* arg delimiter list, */
	fido.marea_max= 0;
	fido.farea_max= 0;			/* number of areas so far */

	setcmd(&maindef,&fido.cmd.main);	/* set default command names */
	setcmd(&chgdef,&fido.cmd.chg);
	setcmd(&msgdef,&fido.cmd.msg);
	setcmd(&filedef,&fido.cmd.file);
	setcmd(&editdef,&fido.cmd.edit);
	setcmd(&trigdef,&fido.cmd.trigger);
	setcmd(&attdef,&fido.cmd.fileatt);
	setcmd(&buldef,&fido.cmd.bulletin);

	f= open(fn,0);
	if (f == -1) {
		printf(" * Can't find Area Definition file %s -- using defaults\r\n",fn);
		return;
	}
	printf(" * Reading Area Definition file %s\r\n",fn);

	getarea1(f,0,fn);			/* do message areas, */
	lseek(f,0L,0);				/* beginning of file again, */
	getarea1(f,1,fn);			/* do file areas */
	close(f);				/* close area def file */
}

/* Go through the file and process either the message areas or the
file areas. */

getarea1(f,pass,fn)
int f,pass;
char *fn;
{
char *s,*cp,arg[SS],ln[SS * 2];
int i;
FLAG err;
int lineno;		/* line number in the file */
struct _area area;
char *build_area();

	cp= (char *) &area;
	for (i= sizeof(struct _area); i--;)
		*cp++= NUL;		/* clear out the area, */

	++pass;					/* make it 1 or 2 */
	lineno= 0;
	err= 0;
	printf("   Pass #%d: Compiling %s Areas     \r",pass,pass == 2 ? "File" : "Message");

	while (rline(f,ln,sizeof(ln))) {
		++lineno;
		clip_cmt(ln);			/* strip off comments */
		cp= skip_delim(ln);		/* skip leading blanks, etc */
		if (*cp == NUL) continue;	/* ignore blank lines */

		s= arg;				/* copy the first word */
		while (isalpha(*cp)) 		/* hopefully MSGAREA or FILEAREA */
			*s++= *cp++;
		*s= NUL;			/* terminate it, */
		stolower(arg);			/* for comparison, */

		if (same(arg,"msgarea")) i= 1;
		else if (same(arg,"filearea")) i= 2;
		else {
			inierr(fn,lineno,ln,"An area definition must start with either \"MSGAREA\" or \"FILEAREA\"");
			err= 1;
			continue;
		}
		if (i != pass) continue;	/* must be the right one */

		cp= build_area(&area,cp,pass);	/* build an area, */
		if (*cp) {			/* if bad, say so */
			inierr(fn,lineno,ln,cp);
			err= 1;
			continue;
		}
		if (pass == 1) {
			if ((fido.marea_max + 1 >= MAXAREA)) {
				printf(" * Too many message areas\r\n");
				err= 1;
				break;
			}
			++fido.marea_max;

		} else {
			if ((fido.farea_max + 1 >= MAXAREA)) {
				printf(" * Too many file areas\r\n");
				err= 1;
				break;
			}
			++fido.farea_max;
		}
		write(sysfile,&area,sizeof(struct _area));
	}
}
/* Fill out the area structure from the string given. Return a pointer
to an error message string if there is any error. */

char *build_area(a,ln,pass)
struct _area *a;
char *ln;
int pass;
{
char *cp,buff[SS];
int c,n;
long l;
char *findeq();

	cp= (char *) a; 				/* clear out the struct */
	for (n= sizeof(struct _area); n--;) *cp++= NUL;

	ln= findeq(ln);					/* find the "=" */
	if (*ln++ != '=') return("Missing the first equal sign");
	ln= skip_delim(ln);				/* skip blanks, etc */
	if (! makepath(a-> path,ln)) return("Drive or subdirectory name is bad");
	strcpy(a-> upath,a-> path);			/* upload same as download */
	ln= next_arg(ln);				/* skip main path */

	while (num_args(ln)) {
		c= *ln++;				/* get the command character, */
		
		ln= findeq(ln);				/* find the "=" */
		if (*ln++ != '=') return("Missing equal sign");
		ln= skip_delim(ln);			/* skip blanks, etc */

		switch (tolower(c)) {
			case 'o':
				c= tolower(*ln) << 8;		/* convert first two chars */
				c |= tolower(ln[1]);		/* into a word for switch() */
				switch (c) {
					case 'fi': if (pass == 1) fido.netmarea= fido.marea_max;
						else fido.netfarea= fido.farea_max; 
						break;

					case 'ne': if (pass == 1) fido.defmnbr= fido.marea_max;
						else fido.deffnbr= fido.farea_max; 
						break;

					case 'go': if (pass == 1) fido.logonbr= fido.marea_max;
						else return("\"GOODBYE\" option works only on MSGAREAs!");
						break;

					case 'ov': if (pass == 2) a-> flags |= AREA_OVW; 
						else return("\"OVERWRITE\" works only on FILEAREAs!");
						break;

					case 'an': if (pass == 1) a-> flags |= AREA_ANON;
						else return("\"ANON\" option works only on MSGAREAs!");
						break;

					case 'pu': if (pass == 1) a-> flags |= AREA_NPVT;
						else return("\"PUBLIC\" option works only on MSGAREAs!");
						break;

					case 'pr': if (pass == 1) a-> flags |= AREA_PVT;
						else return("\"PRIVATE\" option works only on MSGAREAs!");
						break;

					case 'sh': if (pass == 1) a-> flags |= AREA_SHARED;
						else return("\"SHARED\" option works only on MSGAREAs!");
						break;

					case 're': if (pass == 1) a-> flags |= AREA_RO;
						else return("\"READONLY\" option works only on MSGAREAs!");
						break;

					case 'ha': if (pass == 1) a-> flags |= AREA_HARDCR;
						else return("\"HARD-CR\" option works only on MSGAREAs!");
						break;

					default:
						return("Unknown option (Must be at least two letters starting with 12Q)");

				}
				ln= next_arg(ln);
				break;

			case 'u': 			/* alternate pathname */
				if (! makepath(a-> upath,ln)) return("Bad upload pathname");
				a-> flags |= AREA_UPLD;
				ln= next_arg(ln);
				break;

			case 'l':			/* locks */
				while (atoi(ln)) {	/* set all lock bits */
					n= atoi(ln);
					if ((n < 1) || (n > 32)) return("LOCKs must be 1 - 32");
					l= 1L; l <<= (n - 1);
					a-> locks |= l;
					ln= next_arg(ln);
				}
				break;

			case 'i':			/* task ID */
				a-> taskid= atoi(ln);
				ln= next_arg(ln);
				break;

			case 'p':			/* priv level */
				a-> priv= atoi(ln);
				if ((a-> priv > EXTRA) && (a-> priv != SYSOP)) return("Privilege must be 0 - 4 (or 7 for sysops only)");
				ln= next_arg(ln);
				break;

			case 'd':			/* description */
				if (*ln++ != '"') return("Missing first quote on area description");
				cp= buff;
				while (*cp= *ln) {
					if (*ln == '"') break;	/* end of quoted string */
					++cp; ++ln;
				}
				if (*ln != '"') return("Missing closing quote on area description");
				ln= skip_delim(++ln);		/* skip the trailing quote */
				*cp= NUL;
				buff[PS]= NUL;
				strcpy(a-> desc,buff);
				break;

			case 'n':
				if (! *ln) return("Missing the N= AREANAME");
				cpyarg(buff,ln);		/* copy one word */
				stoupper(buff);			/* make all upper case */
				if (strlen(buff) > sizeof(a-> name)) return("Area Name is too long (15 chars max.)");
				cpyarg(a-> name,buff);
				ln= next_arg(ln);		/* skip the name */
				break;

			default:
				return("Not a command");
				break;
		}
	}
	if (*a-> path) return("");
	else return("Missing or bad pathname");
}

/* Return a pointer to the next non white space character. */

char *findeq(ln)
char *ln;
{
	while (*ln) {					/* look for the = */
		if (*ln == '=') break;			/* found it */
/*		if (! delim(*ln)) break; */
		++ln;
	}
	return(ln);
}

/* Create a path from the given string. Return 0 if error. */

makepath(path,ln)
char *path,*ln;
{
char *cp,buff[SS];

	if (*ln == '"') {			/* if a quoted string, */
		++ln;				/* skip it, */
		cp= buff;
		while (*ln) {			/* copy it in, */
			if (*ln == '"') break;	/* stop at another quote, */
			*cp++= *ln++;		/* or end of string */
		}
		*cp= NUL;			/* terminate */

	} else cpyatm(buff,ln);

	if (! *buff) return(1);			/* return null strings immediately */

	buff[PS - SF]= NUL;			/* truncate to fit */
	stoupper(buff);
	if (strlen(buff) > 1) {			/* not for \ by itself */
		for (cp= buff; *cp; ++cp);	/* find the end, */
		--cp;				/* check last character, */
		if (ispath_delim(*cp)) 
			*cp= NUL;		/* truncate trailing \'s */
	}
	if (! isdir(buff)) {			/* if its not valid, */
		printf(" * Subdirectory \"%s\" doesn't exist; creating it\r\n",buff);
		mkdir(buff);			/* try to create it */
		if (! isdir(buff)) return(0);	/* still bad */
	}
	fixdir(buff);				/* append / *.* */
	strip_path(path,buff);			/* copy prefix only */
	return(1);
}	

/* Generate the command names. The number of commands in each area
is HARD CODED into this code on versions pre-v12k, and delimited with
\START and \END starting with 12k. Oh well, so shoot me. */

getcmds(fn)
char *fn;
{
char *cp,arg[SS],ln[256];
int i,f,area;
FLAG err,start,newstyle;
int lineno;
struct _cmd *ap;
char *build_cmd();

	newdelim(", \t\r\n");			/* arg delimiter list, */
	f= open(fn,0);
	if (f == -1) {
		printf(" * Can't find Command Name Definition file \"%s\"\r\n",fn);
		return;
	}
	printf(" * Reading Command Name Definition file %s\r\n",fn);

	area= 0;				/* KLUDGE area selector */
	lineno= 0;				/* file line number */
	err= 0;
	start= 0;				/* no START keyword yet */
	newstyle= 0;
	i= 0;

/* Old COMMAND.INI files had hard-coded number of commands per section; 
therefore the number of commands per menu could not be expanded. New style
use \START and \END markers; we only process commands between them. The 
order of the command menus is still fixed. */

	while (rline(f,ln,sizeof(ln))) {
		++lineno;			/* count lines for error reports */
		clip_cmt(ln);			/* strip off comments */
		cp= skip_delim(ln);		/* skip leading blanks, etc */
		if (*cp == NUL) continue;	/* ignore blank lines */

		cpyarg(arg,cp);			/* test first word */
		if (*arg == '\\') {		/* for reserved character */
			newstyle= 1;		/* (error check for previous file format) */
			stolower(arg);
			if (same(arg,"\\start")) { /* START */
				if (start) {
					cputs("\r\n");
					inierr(fn,lineno,ln,"Should be an \"\\END\" before next \"\\START\"");
					err= 1;
				}
				switch (area++) {
					case 0: cputs("\r   Main Commands  "); ap= fido.cmd.main; i= 13; break;
					case 1:	cputs("\r   Change Commands "); ap= fido.cmd.chg; i= 9; break;
					case 2: cputs("\r   Message Commands "); ap= fido.cmd.msg; i= 15; break;
					case 3: cputs("\r   File Commands    "); ap= fido.cmd.file; i= 12; break;
					case 4: cputs("\r   Edit Commands    "); ap= fido.cmd.edit; i= 9; break;
					case 5: cputs("\r   Trigger Commands "); ap= fido.cmd.trigger; i= 3; break;
					case 6: cputs("\r   Message-File Cmds"); ap= fido.cmd.fileatt; i= 3; break;
					case 7: cputs("\r   Bulletin Commands"); ap= fido.cmd.bulletin; i= 2; break;
					case 8:	i= 0; break;
				}
				if (i == 0) break; /* ... no more commands */
				start= 1;	/* start parsing */

			} else if (same(arg,"\\end")) {
				if (i > 0) {
					cputs("\r\n");
					inierr(fn,lineno,ln,"Not enough command words in this section (check file versions)");
					err= 1;

				} else if (i < 0) {
					cputs("\r\n");
					inierr(fn,lineno,ln,"Too many command words in this section (check file versions)");
					err= 1;
				}
				start= 0;	/* end parsing */
			}
			continue;		/* dont parse keywords! */
		}
		if (! start) continue;		/* wait for a START first */

/* Process a new command word. */

		cp= build_cmd(ap,cp);		/* build a command, */
		if (*cp) {			/* oops! an error */
			inierr(fn,lineno,ln,cp);
			err= 1;
		}
		i--;				/* down-count commands parsed */
		++ap;				/* next... */
	}
	cputs("\r");
	if (! newstyle) inierr(fn,lineno,ln,"Never found a \"\\START\" keyword (Check file\r\nversion); did you run \"12N.EXE\"?)");
	close(f);				/* close area def file */

	return(err);
}
/* Fill in the command name structure. */

char *build_cmd(a,cp)
struct _cmd *a;
char *cp;
{
char *s,buff[SS],c;
int n;
long l;

	cpyarg(buff,cp);				/* copy the command name, */
	cp= next_arg(cp);				/* next ... */
	buff[19]= NUL;					/* truncate to fit, */
	strcpy(a-> name,buff);				/* copy in the name, */
	for (s= a-> name; *s; ++s)			/* convert _ to space */
		if (*s == '_') *s= ' ';

	while (num_args(cp)) {
		c= *cp++;				/* get the command character, */
		if (*cp++ != '=') 
			return("Missing equal sign");	/* must be x= */
		cp= skip_delim(cp);			/* skip any spaces after = */

		switch (tolower(c)) {
			case 'l':			/* locks */
				while (atoi(cp)) {	/* set all lock bits */
					n= atoi(cp);
					if (n > 32) return("LOCKs must be 1 - 32");
					l= 1L; l <<= (n - 1);
					a-> locks |= l;
					cp= next_arg(cp);
				}
				break;

			case 'p':			/* priv level */
				a-> priv= atoi(cp);
				if ((a-> priv > EXTRA) && (a-> priv != SYSOP)) return("Privilege must be 0 - 4 (or 7 for sysops only)");
				cp= next_arg(cp);
				break;

			default:
				return("Unknown command"); break;
		}
	}
	return("");

}
/* Generate the schedules. */

getsched(fn)
char *fn;
{
char *cp,arg[SS],ln[256];
int i,f,area;
FLAG err;
int n,lineno;
struct _sched *ap;
char *build_sched();

	newdelim(", \t\r\n");			/* arg delimiter list, */
	f= open(fn,0);
	if (f == -1) {
		printf(" * Can't find Schedule file %s\r\n",fn);
		return;
	}
	printf(" * Reading Schedule Definition file %s\r\n",fn);

	cp= (char *) fido.sched; 		/* clear all events */
	for (n= sizeof(struct _sched) * SCHEDS; n--;) *cp++= NUL;

	lineno= 0;
	err= 0;
	ap= fido.sched;
	while (rline(f,ln,sizeof(ln))) {
		++lineno;
		clip_cmt(ln);			/* strip off comments */
		cp= skip_delim(ln);		/* skip leading blanks, etc */
		if (*cp == NUL) continue;	/* ignore blank lines */

		cp= build_sched(ap,cp);		/* build a command, */
		if (*cp) {
			inierr(fn,lineno,ln,cp);
			err= 1;
		}
		if (++n >= SCHEDS) {
			inierr(fn,lineno,ln,"Scheduler full; extra events ignored");
			err= 1;
			break;
		}
		++ap;
	}
	close(f);					/* close area def file */

	return(err);
}
/* Fill in the event structure. */

char *build_sched(a,cp)
struct _sched *a;
char *cp;
{
char buff[SS],c;
int n,h,m;
long l;

	a-> bits= SCHED_QUICK;				/* all are QUICK these days */

	while (1) {
		cpyarg(buff,cp);			/* check the 1st item */
		cp= next_arg(cp);
		buff[3]= NUL;				/* 3 chars only */
		stolower(buff);
		if (same(buff,"opt")) {			/* check prefixes */
			a-> bits |= SCHED_OPTIONAL;	/* set optional bits, */
			continue;			/* check again, */

		} else if (same(buff,"rus")) {
			a-> bits |= SCHED_RUSH;
			continue;

		} else if (same(buff,"qui")) {		/* REPEAT */
			a-> bits |= SCHED_QUICK;	/* mark as repeat */
			continue;

		} else if (same(buff,"con")) {		/* CONT */
			a-> bits |= SCHED_CNT;		/* continuous */
			continue;

		} else break;
	}
	buff[0]= toupper(buff[0]);			/* caps 1st char */
	for (n= 0; *dayname[n]; n++) {			/* find the day, */
		if (same(buff,dayname[n])) break;
	}
	if (! *dayname[n]) {
		return("Day-of-the-week is nonsense");
	}
	a-> daywk= n;					/* set the day of the week */

	a-> hr= atoi(cp);				/* get start time, */
	if (a-> hr > 23) return("Hours in the day run 0 to 23");
	while (isdigit(*cp)) ++cp;			/* look for a colon */
	if (*cp == ':') a-> min= atoi(++cp);		/* get mins if so, */
	else a-> min= 0;
	if (a-> min > 59) return("Minutes in an hour run 0 to 59");

	cp= next_arg(cp);				/* get sched width */
	a-> len= atoi(cp);
	if (a-> len > 1440) return("Be serious, a day is only 1440 min. long");

	cp= next_arg(cp);
	cpyarg(buff,cp);				/* now do action type */
	stolower(buff);
	buff[3]= NUL;					/* 3 chars long */
	cp= next_arg(cp);				/* point to action arg */
	if (same(buff,"fid")) {				/* FIDONET */
		a-> tag= toupper(*cp);			/* letter tag, */
		cp= next_arg(cp);			/* point to next */
		if ((a-> tag < 'A') || (a-> tag > 'W'))
			return("FIDONET events are A - W only");

	} else if (same(buff,"err")) {			/* ERRORLEVEL */
		a-> tag= 'X';
		a-> result= atoi(cp);
		cp= next_arg(cp);			/* point to next */
		if ((a-> result < 3) || (a-> result > 255)) 
			return("ERRORLEVEL must be 3 to 255 only");

	} else if (same(buff,"idl")) {			/* IDLE */
		a-> tag= '!';

/*	} else if (same(buff,"onl")) {			/* ONLINE */
		a-> tag= 'Z';
		a-> result= atoi(cp);
		cp= next_arg(cp);			/* point to next */
		if ((a-> result < 3) || (a-> result > 255)) 
			return("ERRORLEVEL must be 3 to 255 only");

	} else if (same(buff,"pro")) {			/* PROGRAM */
		return("\"PROGRAM\" not supported yet");

*/	} else if (same(buff,"pag")) {			/* YELL */
		a-> tag= 'Y';

	} else if (same(buff,"fil")) {			/* FILE REQUEST */
		a-> tag= 'Z';

	} else return("Unknown schedule event type");

	while (*cp) {						/* process options */
		c= *cp++; c= tolower(c);			/* get the option character, */
		cp= findeq(cp);					/* find the "=" */
		if (*cp++ != '=') return("Missing equal sign after the option letter");
		cp= skip_delim(cp);				/* skip blanks, etc */

		if (c == 'i') {					/* task ID */
			a-> taskid= atoi(cp);			/* set it */

		} else if (c == 't') {				/* trigger */
			a-> swtch= atoi(cp);
			if ((a-> swtch < 1) || (a-> swtch > 8))
				return("Event Triggers must be numbered 1 to 8");

		} else return("Unknown option letter");

		cp= next_arg(cp);				/* next option... */
	}
	return("");
}

/* Strip comments from a line of text; truncate it at the semicolon, then work
backwards deleting delimiters. */

clip_cmt(cp)
char *cp;
{
char *sp;
FLAG q;

	q= 0;
	sp= cp;					/* remember where we started */
	while (*cp) {
		if (*cp == '"') {		/* dont clip inside quotes! */
			if (q) q= 0; else ++q;
		}
		if (!q && (*cp == ';')) {	/* search for a semicolon */
			*cp= NUL;		/* kill it, */
			while (delim(*--cp)) 	/* kill all delims */
				*cp= NUL;
			break;
		}
		++cp;
	}
}

/* Generate a version 11 SCHED.BBS file. */

eventsys()
{
struct _oldsched o;
int f,i,t;
char *cp;

	f= creat("SCHED.BBS",2);
	if (f == -1) {
		cprintf("Can't create \"SCHED.BBS\"!\r\n");
		return;
	}
	for (cp= (char *) &o, i= sizeof(struct _oldsched); i--;)
		*cp++= 0;			/* clear it out, */

	for (i= t= 0; i < SCHEDS; i++) {
		if (! fido.sched[i].tag) break;	/* end of table */
		o.enable= 1;

		o.time.daywk= fido.sched[i].daywk;
		o.time.hour= fido.sched[i].hr;
		o.time.mins= fido.sched[i].min;

		o.tag= fido.sched[i].tag;
		o.len= fido.sched[i].len;
		o.result= fido.sched[i].result;
		o.trigger= fido.sched[i].swtch;		/* N.A. in v11 ... */

		write(f,&o,sizeof(struct _oldsched));
		++t;					/* total v11 entries */
	}
	o.tag= o.enable= 0;
	while (t < OLDSCHEDS) {				/* round out to max size */
		write(f,&o,sizeof(struct _oldsched));
		++t;
	}
	close(f);
}

/* Generate a version 11 MAIL.SYS file. */

mailsys() {

struct _mail mail;
struct _area area;
char *cp;
int i;

	for (cp= (char *) &mail, i= sizeof(struct _mail); i--;) 
		*cp++= 0;				/* clear it out */

	mail.node= fido.number;
	mail.net= fido.net;
	mail.zone= fido.zone;

	mail.node= fido.altnumber;
	mail.net= fido.altnet;
	mail.zone= fido.altzone;

	getarea(fido.netmarea,&area,0);			/* get msg path */
	strcpy(mail.msgpath,area.path);
	getarea(fido.netfarea,&area,1);			/* get file path */
	strcpy(mail.filepath,area.path);

	i= creat("mail.sys",2);
	if (i == -1) {
		printf("Can't create \"MAIL.SYS\"?!\r\n");
		return;
	}
	write(i,&mail,sizeof(struct _mail));
	close(i);
}

/* Convert (Msg, File) Area #(n) to a matching SYSTEMn.BBS, creating
the file if necessary. */

systemn(n,fa)
int n;			/* area # */
int fa;			/* 0 == msg else file */
{
struct _area area;	/* v12 msg/file area */
struct _sys sys;	/* v11 SYSTEMn.BBS structure */
char fname[SS];		/* v11 SYSTEMn filename */
char buff[PS];
char *cp;
int o,i;

	if (n) sprintf(fname,"SYSTEM%d.BBS",n);	/* goofy name */
	else strcpy(fname,"SYSTEM.BBS");

	cp= (char *) &sys;			/* clear it out, */
	for (i= sizeof(struct _sys); i--;) *cp++= 0;
	sys.priv= -1;				/* lowest possible priv */

	o= open(fname,2);			/* if it already exists */
	if (o != -1) {				/* load contents */
		read(o,&sys,sizeof(struct _sys));
		lseek(o,0L,0);

	} else if (o == -1) o= creat(fname,2);	/* make a new one */
	if (o == -1) {				/* if doesnt exist (yet) */
		printf("Can't create \"%s\"?\r\n",fname);
		return;
	}

	i= getarea(n,&area,fa);			/* get the right area, */
	switch (area.priv) {			/* translate priv */
		case 0: i= -1; break;		/* TWIT */
		case 1: i= 0; break;		/* DISGRACE */
		case 2: i= 2; break;		/* NORMAL */
		case 3: i= 4; break;		/* PRIVEL */
		case 4: i= 6; break;		/* EXTRA */
		case 7: i= 10; break;		/* SYSOP */
		default: i= 2; break;
	}
	if (i > sys.priv) sys.priv= i;		/* set area privilege */

	if (n == 0) {				/* SYSTEM.BBS gets global stuff */
		sys.ls_caller= (fido.callers & 0xffff);
		sys.ms_caller= (fido.callers >> 16) & 0xffff;
		sys.quote_pos= fido.quote_pos;
	}

	if (fa) {				/* if file area, */
		pathcpy(sys.filepath,area.path);/* copy both paths */
		pathcpy(sys.uppath,area.upath);
		if (n == fido.netfarea) sys.attrib |= SYSMAIL;

	} else {
		pathcpy(sys.msgpath,area.path);	/* else single path */
		if (n == fido.netmarea) sys.attrib |= SYSMAIL;
	}
	pathcpy(sys.hlppath,fido.textpath);	/* help file path */

/* Convert v12 flags to v11 flags as best we can, including Opus extentions. */

	n= 1;				/* bit mask */
	for (i= 0; i < sizeof(area.flags) * 8; i++, n <<= 1) {
		switch (area.flags & n) {
			case AREA_OVW: sys.attrib |= 0x02; break;
			case AREA_ECHO: sys.attrib |= 0x20; break;
			case AREA_ANON: sys.attrib |= 0x10; break;
			case AREA_NPVT: sys.attrib |= 0x04; break;
			case AREA_PVT: sys.attrib |= 0x08; break;
		}
	}
	write(o,&sys,sizeof(struct _sys));	/* write it out, */
	close(o);
}

/* Copy a Fido 12 path to a Fido 11 path; they are different sizes. */

pathcpy(old,new)
char *old,*new;
{
	*new= NUL;
	if (strlen(new) > 39) printf("Fido12 path \"%s\" is too long to fit in Fido11 path (39 chars max)\r\n",new);
	else strcpy(old,new);
}

/* Get message or file area #n; return 0 if not set, illegal number
or other error. You could use this code in YOUR program. (hint hint) */

getarea(n,a,fa)
int n;			/* area number */
struct _area *a;	/* struct to load */
int fa;			/* 1 == get a file area */
{
int i;
long off;

	if (n < 0) return(0);				/* no such area */
	off= 0L + sizeof(struct _fido);			/* offset to beg msg areas */
	if (fa) {					/* if a file area, */
		if (n >= fido.farea_max) return(0);	/* bound it */
		off += (long)(sizeof(struct _area) * fido.marea_max); /* beg file areas */

	} else if (n >= fido.marea_max) return(0);	/* msg area max */

	off += (long)(n * sizeof(struct _area));	/* offset plus area # */
	lseek(sysfile,off,0);				/* seek there, */
	i= read(sysfile,a,sizeof(struct _area));	/* read some, */

	if (i != sizeof(struct _area)) return(0);	/* check read error */
	a-> number= n;					/* set the path number */
	return(*a-> path != '\0');			/* invalid if no path set */
}

/* Dummy error() function. */

error(s)
char *s;
{
	printf(" * %s\r\n",s);
}
/* Delete all matching files. */

static killall(s)
char *s;
{
int i;
char path[SS],file[SS];
struct _xfbuf xfbuf;

	i= 0;
	xfbuf.s_attrib= 0;
	strip_path(path,s);			/* save a copy of the path, */
	while (_find(s,i++,&xfbuf)) {		/* find each file */
		strcpy(file,path);		/* build the full filename */
		strcat(file,xfbuf.name);
		delete(file);			/* kill it */
	}
}
