#include #include #include /* This program compiles the nodelist. */ int nodefile; /* .NMP */ int ntcfile; /* .NTC */ int ndatfile; /* .BBS (in) */ int idxfile; /* .IDX */ int ndxfile; /* .NDX */ int zdxfile; /* .ZDX */ int bbsfile; /* .BBS out */ int doscode; /* program result code (0 == OK) */ struct _nmap nmap; /* .NMP file structure */ struct _ndat ndat; /* .BBS file intermediate structure */ struct _ntc ntc; /* .NTC file not used here */ struct _idx index; /* .IDX file structure */ struct _n { /* in-memory table of nodes/passwords */ struct _node node; /* target node, */ char pwd[9]; /* password, */ FLAG success; /* was-found flag */ }; struct _n *s; /* table pointer */ unsigned max; /* max size of table/number of entries */ char *membuf; /* output buffer */ unsigned bufsize; /* output buffer size */ struct _node id; /* satisfy link */ struct _node altid; /* satisfy link */ int nodetotal; /* satisfy link */ struct _fido fido; /* satisfy link */ int dial_tries,connect_tries; /* satisfy link */ int sysfile; /* during initialization only */ main(argc,argv) int argc; char **argv; { char *p,fn[SS],sw[SS]; int i; printf("MAKELIST (21 Jun 91) NodeList Compiler for "); copr(); allmem(); /* get all available */ if (! fastfile(8)) { /* init the buffered file system */ printf(" * Cant start the file system\r\n"); exit(1); } doscode= 0; /* no error (yet) */ newdelim(" \t;,\r\n"); /* arg delimiter list, */ i= open("fido.sys",0); /* load system stuff */ if (i == -1) { printf("The Fido system file \"FIDO.SYS\" is missing!\r\n"); exit(1); } read(i,&fido,sizeof(fido)); close(i); if ((fido.fido_version != FIDOVER) || (fido.file_version != FILEVER)) { cprintf(" * The Fido system file \"FIDO.SYS\" doesn't match this \"FIDO.EXE\"\r\n"); cprintf(" * program; make sure you have the latest versions.\r\n\r\n"); cprintf(" * FIDO.SYS is from Fido/FidoNet version %d%c\r\n",fido.fido_version,fido.file_version + 96); cprintf(" * This program is Fido/FidoNet version %d%c\r\n",FIDOVER,96+FILEVER); cprintf(" * You must run \"SET-FIDO\" to change Fido/FidoNet program versions\r\n"); exit(1); } if (fido.event != -1) { printf("\r\n\r\n * A FidoNet event was left incomplete; you must run Fido\r\n"); printf("and terminate the event, or use \"FIDO/C\", before you can run \"MAKELIST\".\r\n"); exit(1); } id.zone= fido.zone; /* node ID */ id.net= fido.net; id.number= fido.number; id.point= fido.point; altid.zone= fido.altzone; /* alternate ID */ altid.net= fido.altnet; altid.number= fido.altnumber; altid.point= fido.altpoint; bufsize= sizmem(); /* get a bunch of memory, */ membuf= getmem(bufsize); /* allocate the table */ load_pwds(); /* load password table */ if (bufsize <= 256) { printf(" * NOT ENOUGH MEMORY?!\r\n"); exit(1); } init_node(); /* build nodelist */ exit(doscode); } /* Build the in-memory table of nodes to process. */ load_pwds() { int io; char *cp,ln[SS]; int n; s= (struct _n *) membuf; /* define start of buffer */ max= 0; /* how much is in it */ makenname(ln,"nodelist.pwd"); io= open(ln,0); /* open it, */ if (io == -1) return; /* nothing to do */ printf(" * Reading session password list NODELIST.PWD\r\n"); max= (bufsize + sizeof(struct _n) - 1) / sizeof(struct _n); /* max == # elements */ n= 0; /* table empty */ while (rline(io,ln,sizeof(ln))) { if (*cp == ';') continue; /* ignore comments */ cp= skip_delim(ln); /* skip leading garbage, */ if (! *cp) continue; /* skip blank lines */ if (n >= max) { printf(" * Too many entries to process at once!\r\n"); break; } cpy_node(&s[n].node,&id); /* set default zone/net */ set_nn(cp,&s[n].node); /* parse node, */ s[n].success= 0; /* not processed yet */ cp= next_arg(cp); /* point to password */ cp[8]= NUL; /* clip to 8 chars */ if (! *cp) { printf(" * For %s: no password specified?\r\n",str_node(&s[n].node)); continue; } strcpy(&s[n].pwd,cp); /* add password to table */ ++n; /* anoth entry */ } close(io); /* done with it */ max= n; /* max == max. nodes in list */ bufsize -= max * sizeof(struct _n); /* this much was used */ membuf= (char *) &s[max]; /* it starts here */ printf(" * %d nodes to receive session passwords\r\n",max); } /* Create the node list, in a digestible form. This just builds a fixed structure version of the ASCII list, and leaves it laying around on the disk. CAUTION: This builds NODELIST.IDX and NODELIST.NMP at the same time, and in parallel. IDX is the index to the nodelist, and contains the net/node numbers for the nodelist. They must be kept in sync, record by record! */ init_node() { int zonecnt,regcnt,netcnt,nodecnt; /* tally for display only */ int host_num; /* 0 if "host", else -1 for old "region" */ char c,arg[SS],nextarg[SS]; char *ln; /* pointer to line "buffer" */ char *cp; struct _rptrcd *r; int i; int o; /* output buffer count */ int n; /* offset to start of .BBS data */ unsigned recd; /* current record number */ unsigned ndx_recd; /* record number of NDX file */ long pos; /* current .BBS file position */ FLAG watch_it; /* to detect IFNA nodelist fuckups (missing REGION statements) */ long watch_pos; /* generate missing REGION */ struct _rptrcd rptrcd; /* dummy repeat record */ printf(" * Creating the node list index and routing table\r\n"); /* printf(" * NOTE: The file \"NODELIST.SYS\" is no longer used\r\n"); */ makenname(arg,"nodelist.bbs"); stoupper(arg); ndatfile= open(arg,0); /* open source file, */ if (ndatfile == -1) { stoupper(arg); printf(" * Cannot find \"%s\"\r\n",arg); doscode= 2; return; } bbsfile= -1; /* assume no output file */ if (max > 0) { /* if we have passwords to add */ makenname(arg,"nodelist.$b$"); stoupper(arg); bbsfile= creat(arg,2); /* .BBS output file */ if (bbsfile == -1) { printf(" * Cannot create \"%s\", is your \"node_path\" (in FIDO.INI) OK?\r\n",arg); doscode= 2; return; } } makenname(arg,"nodelist.idx"); stoupper(arg); idxfile= creat(arg,2); /* the index */ if (idxfile == -1) { printf(" * Cannot create \"%s\", is your \"node_path\" (in FIDO.INI) OK?\r\n",arg); doscode= 2; return; /* if not there skip it */ } makenname(arg,"nodelist.zdx"); /* zone index */ zdxfile= creat(arg,2); makenname(arg,"nodelist.ndx"); /* net/region index */ ndxfile= creat(arg,2); makenname(arg,"nodelist.nmp"); nodefile= creat(arg,2); /* the node map */ makenname(arg,"nodelist.ntc"); /* we dont use this, but */ ntcfile= creat(arg,2); /* put_, get_, etc check it */ makenname(arg,"nodemap.?"); killall(arg); /* kill preserved nodemaps */ if (node_files()) { /* if any not open, */ cprintf(" * Cannot create one of the NODELIST.* files\r\n"); close_node(); doscode= 2; return; } /* First .NMP record; this contains the revision marker and the REPEAT record used to potentially re-use a previously created routing table. Because of the funny way it is stored we have to write it in the last two elements. */ for (cp= (char *) &rptrcd, i= sizeof(struct _rptrcd); i--;) *cp++= 255; /* set to all -1's */ rptrcd.bits= 0; /* except these */ *rptrcd.mdmstr= NUL; *rptrcd.dial_pref= NUL; rptrcd.revision= NODEVERS; /* set revision, */ write(nodefile,&rptrcd,sizeof(struct _rptrcd)); /* The first .IDX record; place keeper and index. */ ndx_recd= 0; /* record number */ recd= 1; /* next will be real data */ pos= 0L; /* .BBS ($B$) file position */ index.zone= index.net= index.number= -1; index.pos= pos; /* first record position */ write(idxfile,&index,sizeof(index)); /* write index */ /* The watch_it flag is used to detect missing REGION or NET definitions after a ZONE definition. IFNA is leaving the old region 1 nodes right after the ZONE statement, which is meant to leave them in REGION 1. We gotta fix this and add the missing REGION. */ watch_it= 0; cpy_node(&nmap.node,&id); /* default to "us" */ nmap.bits= 0; /* we dont set these here */ index.zone= id.zone; /* index too */ index.net= id.net; index.number= id.number; zonecnt= regcnt= nodecnt= netcnt= 0; /* count of zones, nodes and nets */ /* Load one line/record from NODELIST.BBS into the buffer; if there is not enough room (assume 256 chars needed) flush it first. */ o= 0; /* buffer is empty */ while (doscode == 0) { if (bbsfile == -1) o= 0; /* not outputting */ else if (bufsize - o < 256) { /* if it needs flushing */ fw(bbsfile,membuf,o); o= 0; } cp= ln= &membuf[o]; /* start of current buffer */ n= 0; /* bytes read so far */ while (read(ndatfile,cp,1)) { /* one char at a time */ ++n; if (*cp == CR) continue; if (*cp == LF) break; if (n > 255) break; /* max. line length */ ++cp; /* room for the next */ } *cp= NUL; /* terminate the line */ if (! n) break; /* end of file */ if (*ln == NUL) continue; /* blank line */ if (*ln == ';') continue; /* skip comments */ /* Now we need to strip off any existing session password. Lines should look like: HOST 102 26 9600 SoCalNet 1-213-874-9484 Los_Angeles_CA 135 26 9600 Manhattan_Transfer 1-213-372-4800 Manhattan_Beach 13 26 9600 Manhattan_Transfer 1-213-372-4800 Manhattan_Beach PASSWORD Each record is basically six fields, possibly preceded by a keyword, possibly followed by a password. We need to strip off the password, plus any trailing delimiters. */ if (bbsfile != -1) { cp= skip_delim(ln); /* skip over the basic fields */ n= isdigit(*cp) ? 6 : 7; /* 6 or 7 fields */ while (n--) cp= next_arg(cp); if (*cp) { /* if a password, */ while (*(cp - 1) == ' ') --cp; /* truncate it */ *cp= NUL; /* and any delims */ } } /* Now we need to process the keyword. All that Fido/FidoNet wants to see at runtime is the info starting with cost field. The offset in the .IDX record then is made to point to the cost field; we skip the leading junk here (so it doesn't have to be done at runtime). */ cp= skip_delim(ln); /* if the first item is not */ if (!isdigit(*cp)) cp= next_arg(cp); /* a number, skip it */ cp= next_arg(cp); /* skip the node (net, etc) number */ n= cp - ln; /* n == add'l offset */ cp= ln; /* cp == line to process */ if (isdigit(*cp)) { /* We have a regular node definition. The watch_it flag will be clear if we had a REGION or HOST definition; if not this node doesnt belong to a REGION (which is mathematically OK but the IFNA nodelist assumes that they are in region 1 in the current zone). */ if (watch_it) { nmap.node.number= 0; /* is region */ nmap.node.net= watch_it; /* IFNA region kludge */ cpyi(&index,&nmap.node); /* duplicate it */ index.pos= watch_pos; /* current file position */ fw(idxfile,&index,sizeof(index)); /* write index */ index.pos= 0L + recd; /* net/region index entry */ fw(ndxfile,&index,sizeof(index)); nmap.route_recd= recd; /* route-to self */ nmap.attr= NMAP_REGION; /* not a host */ put_node(recd); /* node route data */ ++recd; ++regcnt; ++nodecnt; watch_it= 0; } nmap.node.number= make_node(ln); /* a node */ nmap.attr= 0; /* not a region host */ index.number= nmap.node.number; ++nodecnt; /* Well, maybe its a keyword. */ } else { cpyatm(arg,cp); stolower(arg); /* copy of the arg word, */ cp= next_arg(cp); cpyatm(nextarg,cp); /* and the next one */ stolower(nextarg); nmap.attr= 0; /* assume not a region host */ /* ZONE zz zz:-1/00 Zone #zz REGION nn zz:nn/-1 current Zone, Net #nn, no host HOST nn zz:nn/00 current Zone, Net #nn, with host mm zz:nn/mm current Zone, current Net, node #mm HUB nn zz:nn/mm treat as node */ if (same(arg,"hub")) { nmap.node.number= make_node(cp);/* set node number */ cpyi(&index,&nmap.node); ++nodecnt; } else if (same(arg,"host")) { nmap.node.net= make_node(cp); /* set Net number */ nmap.node.number= 0; /* is a host */ cpyi(&index,&nmap.node); ++netcnt; ++nodecnt; watch_it= 0; } else if (same(arg,"region")) { nmap.node.net= make_node(cp); /* set Net number */ nmap.node.number= 0; /* is a host */ nmap.attr= NMAP_REGION; /* flag as region host */ cpyi(&index,&nmap.node); /* duplicate, */ index.number= 0; /* except node 0 */ ++regcnt; ++nodecnt; watch_it= 0; } else if (same(arg,"zone")) { nmap.node.zone= make_node(cp); /* set Zone number */ nmap.node.net= 0; /* always 0 */ nmap.node.number= 0; /* always 0 */ cpyi(&index,&nmap.node); /* full copy */ ++zonecnt; ++nodecnt; watch_it= nmap.node.zone; /* check for missing REGION */ watch_pos= pos + n; /* save since we have to */ } else continue; cpy_node(&ndat.node,&nmap.node); /* for listing */ listnode(&ndat); /* list it */ } /* Now see if the node we just processed is in the list of nodes to get session passwords; if so, append the password text to the data record. (Note that the _idx structure doesnt really contain a _node structure, but the same_node() func works anyways.) */ for (i= 0; i < max; i++) { /* check the table, */ if (same_node(&s[i].node,&index)) { /* if found, */ strcat(ln," "); /* add a space, */ strcat(ln,s[i].pwd); /* add the password */ s[i].success= 1; /* flag as successful */ break; } } /* Now write out the records we just created; the .IDX file gets the node number plus the offset to this data record; the .NDX file gets only /0 records; the .NMP file gets an un-filled nodemap entry; the .$B$ file (.BBS output) is only written if bbsfile != -1, and in any case the data is collected in membuf until it is nearly full. The ZDX file is an index into the NDX file; its record numbers are relative to the NDX file. Hence the separate record number counter for NDX records. */ index.pos= pos + n; /* .IDX file */ fw(idxfile,&index,sizeof(index)); /* write index */ nmap.route_recd= recd; /* route-to self */ put_node(recd); /* .NMP record */ if (is_zonehost(&index)) { /* .ZDX zone index */ index.pos= 0L + ndx_recd; fw(zdxfile,&index,sizeof(index)); } if (is_host(&index)) { /* .NDX net/region index */ index.pos= 0L + recd; fw(ndxfile,&index,sizeof(index)); ++ndx_recd; /* recd # in NDX file */ } strcat(ln,"\r\n"); /* add the CR/LF terminator */ i= strlen(ln); /* length of this recd */ pos += i; /* current .$B$ position */ o += i; /* current buffer position */ ++recd; /* logical record number */ } printf(" * %d Zones, %d Regions, %d Nets, %d total Nodes \r\n", zonecnt,regcnt,netcnt,nodecnt); close_node(); /* If we were processing passwords, replace the original .BBS file with the one we just created, that contains all the passwords. */ if (bbsfile != -1) { if (o) fw(bbsfile,membuf,o); close(bbsfile); if (! doscode) { /* if OK */ makenname(membuf,"nodelist.$b$");/* our output file */ makenname(arg,"nodelist.bbs"); /* our input file */ delete(arg); /* kill the old one */ rename(membuf,arg); /* rename */ } } n= 0; for (i= 0; i < max; i++) { if (! s[i].success) { if (! n) printf("\r\n * Nodes not found in the nodelist (hence not passworded)\r\n"); printf(" Node %s, password \"%s\"\r\n",str_node(&s[i].node),s[i].pwd); n= 1; } } } /* Do a disk write, return doscode set if write error. */ fw(f,b,n) int f; char *b; unsigned n; { if (write(f,b,n) != n) { printf("DISK FULL!!!!!! \r\n"); doscode= 3; } } /* Fill the index structure's node address. */ cpyi(i,n) struct _idx *i; struct _node *n; { i-> zone= n-> zone; i-> net= n-> net; i-> number= n-> number; } /* Parse a text string into a nodemap, and return the number found. Zone, Net and Number are left untouched. The string has the format: num cost name phone city comments */ char *maken0(); char *maken1(); make_node(s) char *s; { int n; s= maken0(&n,s); s= maken0(&ndat.cost,s); s= maken0(&ndat.rate,s); s= maken1(ndat.name,sizeof(ndat.name),s); s= maken1(ndat.phone,sizeof(ndat.phone),s); s= maken1(ndat.city,sizeof(ndat.city),s); return(n); } /* Make node function #0; pull a decimal number out, skip to the next argument. */ char *maken0(i,sp) int *i; char *sp; { *i= atoi(sp); return(next_arg(sp)); } /* Make node function #1; copy one atom out, put it in the array, fixing for maximum length and converting underscores to spaces, and returning a pointer to the next atom. */ char *maken1(cp,n,sp) char *cp; int n; char *sp; { char atom[SS]; cpyatm(atom,sp); /* one clean copy */ atom[n - 1]= NUL; /* truncate to maximum */ maken3(cp,n,atom); /* copy in, converting, */ return(next_arg(sp)); /* next ... */ } /* Copy a string, with a maximum length, converting underscodes to spaces. */ maken3(cp,n,sp) char *sp; int n; char *cp; { if (n) --n; /* room for the null */ while (*sp && --n) { if (*sp == '_') *cp= ' '; else *cp= *sp; ++sp; ++cp; } *cp= NUL; } /* List node information. */ listnode(nd) struct _ndat *nd; { struct _node d; char buff[256]; cpy_node(&d,&nd-> node); sprintf(buff," * %s %s, %s ", str_node(&d),nd-> name,nd-> city); buff[70]= NUL; printf("%s\r",buff); } /* Dummy */ clprintf() {} lprintf() {} /* Error printer */ error(s) char *s; { printf(" * %s\r\n",s); } /* Return true if the FBIT is set. */ fbit(bit) int bit; { return(fido.fbits[bit / sizeof(char)] & (1 << bit % sizeof(char))); } /* Delete all matching files in the upload path. */ 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 */ } }