#include #include #include #include /* 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 ' 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 */ } }