Subject: v18i005: Fido/Usenet gateway, Part04/05 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: Heikki Suonsivu Posting-number: Volume 18, Issue 5 Archive-name: fnet/part04 #!/bin/sh # this is part 4 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file fio.c continued # CurArch=4 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file fio.c" sed 's/^X//' << 'SHAR_EOF' >> fio.c X{ X nchars = 0; X} SHAR_EOF echo "File fio.c is complete" chmod 0644 fio.c || echo "restore of fio.c fails" echo "x - extracting xtsend.c (Text)" sed 's/^X//' << 'SHAR_EOF' > xtsend.c && X#ifndef lint Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%"; X#endif X X/* Send file(s) unsing Xmodem/TeLink/MODEM7 Batch protocols. X X @(#)Copyright (c) 1987 by Teemu Torma X X Permission is given to distribute this program and alter this code as X needed to adapt it to forign systems provided that this header is X included and that the original author's name is preserved. */ X X/* LINTLIBRARY */ X X#include X#include X#include X#include X#include X#include "fnet.h" X#include "fio.h" X#include "crc.h" X Xextern time_t time(); Xextern int readline(); Xextern void sendline(); X X/* General macros to check timeouts. */ X X#define SetStart() (stime = time((long *) NULL)) X#define Timeout(t) (time((long *) NULL) - stime > (t)) X#define BytesSend (block * BlockSize) X X/* General states for finite state machines. These are used to break X loops mostly. */ X X#define Error (-1) /* error state */ X#define Done (-2) /* state to break loops */ X X/* XMODEM/TeLink send states. */ X X#define WaitTeLnk (0) X#define WaitStart (1) X#define SendBlock (2) X#define WaitACK (3) X#define WaitEnd (4) X X/* BATCH File sender states. */ X X#define MoreFiles (0) X#define CheckFNm (1) X#define CheckFile (2) X#define EndSend (3) X X/* States for MODEM7 filename sender. */ X X#define WaitNak (0) X#define WaitChAck (1) X#define WaitCksm (2) X X/* Return filename for MS-DOS. Because MS-DOS has many restrictions in X filenames (that silly dot in between), we must use something equivalent X while sending TeLink. */ X Xchar * Xconver_to_msdos_name(filename) X char *filename; X{ X static char msdos_name[16]; X register int pos; X register char *cp; X X /* strip off pathname */ X cp = basename(filename); X X /* ignore leading dot */ X if (*cp == '.') X cp++; X X /* create first 8 characters of ms-dos name */ X for (pos = 0; *cp && *cp != '.' && pos < 8; pos++, cp++) X msdos_name[pos] = *cp; X X /* add dot for ms-dos */ X msdos_name[pos] = '.'; X X /* add 3 character type */ X for (pos = 9; *cp && *cp != '.' && pos < 12; pos++, cp++) X msdos_name[pos] = *cp; X X /* null terminate ms-dos name */ X msdos_name[pos] = 0; X X debug(2, "File %s changed to %s in MS-DOS", filename, msdos_name); X return msdos_name; X} X X/* Create special TeLink block. This block will be send as block 0 before X all other data will be sent. Return false if it couldn't be created, X otherwise true. */ X Xbool Xmaketelnk(filename, buffer) X char *filename, *buffer; X{ X struct stat stbuf; X register int cnt; X register char *cp; X X /* get status of file */ X if (stat(filename, &stbuf) == -1) X { X log("$Cannot stat %s", filename); X return False; X } X X /* save file length */ X for (cnt = 0; cnt < 4; cnt++) X buffer[cnt] = (stbuf.st_size >> (cnt * 8)) & 0377; X X /* creation time and date will be all zeroes */ X for (cnt = 4; cnt < 8; cnt++) X buffer[cnt] = 0; X X /* save file name */ X for (cnt = 8, cp = /*msdosname(*/ filename /*)*/ ; *cp; cp++, cnt++) X buffer[cnt] = *cp; X X /* if name was shorter that 16 chars, fill rest of it with blanks */ X while (cnt < 24) X buffer[cnt++] = ' '; X X /* don't know why here's zero */ X buffer[cnt] = 0; X X /* name of sending program... let's ignore */ X for (cnt = 25; cnt < 41; cnt++) X buffer[cnt] = 0; X strcpy(&buffer[25], PROGRAMNAME); X X /* crc mode */ X X buffer[41] = 1; X X /* rest of buffer will be full of zeroes */ X for (cnt = 42; cnt < 128; cnt++) X buffer[cnt] = 0; X return True; X} X X/* Send block to line. Note that intial SOH or SYN is not sent by X this routine. */ X Xvoid Xxtsendblk(sxbuf, blocknum, crcmode) X char *sxbuf; X int blocknum; X bool crcmode; X{ X register unsigned short crc; X register int checksum, cnt; X X debug(1, "Send block %d", blocknum); X X /* send block number */ X sendline(blocknum & 0377); X sendline(~(blocknum & 0377)); X X /* send the block itself */ X debug(1, "Send %d bytes", BlockSize); X (void) write(line, sxbuf, BlockSize); X X /* count crc and checksum */ X for (crc = 0, checksum = 0, cnt = 0; cnt < BlockSize; cnt++) X { X crc = updcrc(sxbuf[cnt], crc); X checksum += sxbuf[cnt]; X } X X if (crcmode) X { X /* send crc */ X /* crc = updcrc(0, updcrc(0, crc)); /* What is this for? */ X debug(1, "Send crc %d", crc); X sendline((int) (crc >> 8)); X sendline((int) crc); X } X else X { X /* send checksum */ X debug(1, "send checksum %d", checksum & 0377); X sendline(checksum & 0377); X } X} X X/* Send file using XMODEM/TeLink protocol. Return True is everything went X fine, otherwise false. */ X Xbool Xxtsend(filename, telink) X char *filename; X bool telink; X{ X int state = telink ? WaitTeLnk : WaitStart; X struct stat st; X time_t stime; X int tries, c; X char sxbuf[BlockSize]; X FILE *fp; X bool resend = False, lastblock = False; X int block = 1, cnt; X bool crcmode = True; X X if ((fp = fopen(filename, "r")) == NULL) X log("$Can not open %s, sending empty file", filename); X else X log("Sending %s", filename); X X (void) stat(filename, &st); X X while (state >= WaitTeLnk && state <= WaitEnd) X switch (state) X { X case WaitTeLnk: X if (!maketelnk(filename, sxbuf)) X { X log("Unable to send file %s", filename); X state = Error; X } X else X { X SetStart(); X for (tries = 0; state == WaitTeLnk; tries++) X { X if ((c = readline(40)) == NAK || c == 'C') X { X crcmode = c == 'C'; X debug(2, "Got %02x, sending TeLink block", c); X sendline(SYN); X /* telink block always has checksum */ X xtsendblk(sxbuf, 0, False); X } X else if (c == ACK) X { X state = WaitStart; X debug(2, "Got ACK, TeLink block sent ok"); X } X else if (c == NAK) X { X if (tries > 2) X { X log("Too many tries on telink block"); X state = WaitStart; X } X /* If other stuff, not ack/nak received, just ignore */ X } X else if (Timeout(40)) X { X log("Timeout on telink block"); X state = WaitStart; X } X } X } X break; X case WaitStart: X SetStart(); X for (tries = 0; state == WaitStart; tries++) X if ((c = readline(60)) == NAK || c == 'C') X { X debug(1, "Got NAK, sendblock start"); X crcmode = True; /* c == 'C'; */ X state = SendBlock; X } X else if (Timeout(60)) X { X log("Timeout on xmodem start"); X state = Error; X } X else if (tries > 20) X { X debug(1, "Too many retries on xmodem start"); X state = Error; X } X break; X case SendBlock: X if (!resend) X if (lastblock || !fp) X { X sendline(EOT); X state = WaitEnd; X } X else { X for (cnt = 0; cnt < BlockSize; cnt++) X { X if ((c = getc(fp)) == EOF) { X c = CTRLZ; X lastblock = True; X } X sxbuf[cnt] = c; X } X sendline(SOH); X xtsendblk(sxbuf, block, crcmode); X state = WaitACK; X } X else { X sendline(SOH); X xtsendblk(sxbuf, block, crcmode); X state = WaitACK; X resend = False; X } X break; X case WaitACK: X SetStart(); X for (tries = 0; state == WaitACK; tries++) X if ((c = readline(60)) == NAK) X { X resend = True; X state = SendBlock; X debug(1, "Got NAK, resend current block"); X if (tries >= 10) X { X log("Too many tries on xmodem send"); X state = Error; X } X } X else if (c == ACK) X { X debug(1, "Got ACK, send next block"); X block++; X debug(2, "%ld bytes send (%d %%)", BytesSend, X (BytesSend / st.st_size) * 100); X state = SendBlock; X } X else if (Timeout(60)) X { X log("Xodem send timeout"); X state = Error; X } X break; X case WaitEnd: X for (tries = 0; state == WaitEnd; tries++) X if ((c = readline(60)) == NAK) X { X sendline(EOT); X debug(2, "Send EOT"); X } X else if (c == ACK) X { X log("Xmodem/TeLink send successful"); X state = Done; X } X else if (Timeout(60)) X { X log("Timeout on xmodem/telink end"); X state = Error; X } X else if (tries >= 10) X { X log("Too many retries on xmodem end"); X state = Error; X } X break; X } X X return state == Error ? False : True; X} X X/* Send MODEM7 filename. */ X Xbool Xsendmdmfn(filename) X char *filename; X{ X int state = WaitNak; X time_t stime; X int tries = 0; X int c, checksum, cnt; X X SetStart(); X while (state >= WaitNak && state <= WaitCksm) X switch (state) X { X case WaitNak: X for (tries = 0; state == WaitNak; ) X if ((c = readline(60)) == NAK) X { X debug(2, "Got NAK for filename %s", filename); X sendline(ACK); X sendline(*filename); X cnt = 1; X state = WaitChAck; X } X else if (Timeout(60)) X { X debug(1, "Timeout on filename"); X state = Error; X } X else if (tries >= 20) X { X debug(1, "Too many retries on filename"); X state = Error; X } X break; X case WaitChAck: X if (readline(2) == ACK) X { X if (filename[cnt]) X sendline(filename[cnt++]); X else X { X sendline(SUB); X state = WaitCksm; X } X } X else X { X sendline('u'); X tries++; X state = WaitNak; X } X break; X case WaitCksm: X if ((c = readline(2)) == TIMEOUT) X { X sendline('u'); X tries++; X state = WaitNak; X } X else X { X for (cnt = 0, checksum = SUB; filename[cnt]; cnt++) X checksum += filename[cnt]; X if (c != (checksum & 0377)) X { X debug(1, "Checksum error in filename"); X sendline('u'); X state = WaitNak; X tries++; X } X else X { X sendline(ACK); X debug(2, "Filename sent ok"); X state = Done; X } X } X break; X } X X return state != Error; X} X X/* Batch file sender. If filename is NULL, no more files to send. */ X Xbool Xbatchsend(filename) X char *filename; X{ X int state = MoreFiles; X int c; X time_t stime; X bool ok; X X while (state >= MoreFiles && state <= EndSend) X switch (state) X { X case MoreFiles: X if (filename) X { X debug(2, "Sending filename for %s", filename); X ok = sendmdmfn(filename); X state = CheckFNm; X } X else X state = EndSend; X break; X case CheckFNm: X if (ok) X { X debug(1, "Sending file %s", filename); X ok = xtsend(filename, True); X state = CheckFile; X } X else X state = Error; X break; X case CheckFile: X if (ok) X { X debug(1, "File send ok"); X state = Done; X } X else X { X log("TeLink file send failed"); X state = Error; X } X break; X case EndSend: X SetStart(); X while (!Timeout(10)) X if ((c = readline(10)) == NAK || c == 'C') X { X sendline(EOT); X log("Batch file send ok"); X state = Done; X break; X } X if (state != Done) X { X log("Batch file send failed, no NAK"); X sendline(EOT); X state = Error; X } X break; X } X X return state != Error; X} SHAR_EOF chmod 0644 xtsend.c || echo "restore of xtsend.c fails" echo "x - extracting xtrec.c (Text)" sed 's/^X//' << 'SHAR_EOF' > xtrec.c && X#ifndef lint Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%"; X#endif X X/* Receive file(s) using Xmodem/TeLink/MODEM7 Batch protocols. X X @(#)Copyright (c) 1987 by Teemu Torma X X Permission is given to distribute this program and alter this code as X needed to adapt it to forign systems provided that this header is X included and that the original author's name is preserved. */ X X#include X#include X#include X#include "hsu.h" X#include "fnet.h" X#include "fio.h" X#include "crc.h" X Xextern time_t time(); X X/* Macros to check timeouts */ X X#define Timeout(t) (time((long *) NULL) - stime > t) X#define SetStart() (stime = time((long *) NULL)) X X/* General error states to break the loops. */ X X#define Error (-1) X#define Done (-2) X X/* States for XMODEM/TeLink receiver. */ X X#define RecStart (0) X#define WaitFirst (1) X#define WaitBlock (2) X X/* States for BATCH file receiver. */ X X#define RecvName (0) X#define CheckFNm (1) X#define CheckFile (2) X X/* States for MODEM7 filename receiver. */ X X#define SendNak (0) X#define WaitAck (1) X#define WaitChar (2) X#define WaitOkCk (3) X Xstatic received_block_number = 0; Xint receiving_data = FALSE; X Xbool Xxtrecblk(rxbuf, blocknum, crcmode) X char *rxbuf; X int blocknum; X bool crcmode; X{ X register int c, cnt, checksum; X register unsigned short crc; X X if (blocknum == -1) X debug(1, "Receiving block ignoring block number"); X else X debug(1, "Receiving block %d", blocknum); X X received_block_number = blocknum; X X if ((c = readline(10)) == TIMEOUT || c != (blocknum & 0377)) X { X if (c == TIMEOUT) X debug(1, "Timeout on block number receive"); X else X { X if (blocknum == -1) X if (c == 0 || c == 1) /* Both telink and xmodem allowed */ X { X blocknum = c; X received_block_number = blocknum; X debug(1, "Setting blocknum to %d", blocknum); X goto blockok; X } X X debug(1, "Bad block number %d, expected %d", c, blocknum & 0377); X } X goto blidge; X } X X blockok: X if ((c = readline(10)) == TIMEOUT || c != (~blocknum & 0377)) X { X if (c == TIMEOUT) X debug(1, "Timeout on complement block number receive"); X else X debug(1, "Bad ~block number %d, expected %d", c, (~blocknum & 0377)); X goto blidge; X } X X receiving_data = TRUE; X for (crc = 0, checksum = 0, cnt = 0; cnt < BlockSize; cnt++) X if ((c = readline(5)) == TIMEOUT) X { X debug(1, "Timeout while receiving block"); X receiving_data = FALSE; X goto blidge; X } X else X { X checksum += c; X crc = updcrc(c, crc); X rxbuf[cnt] = c; X } X receiving_data = FALSE; X debug(5, "Received %d bytes", BlockSize); X X if (crcmode) X { X if (readline(10) != (int) ((crc >> 8) & 0377) X || readline(10) != (int) (crc & 0377)) X { X debug(1, "Crc error"); X goto blidge; X } X } X else X { X if (readline(10) != (checksum & 0377)) X { X debug(1, "Checksum error"); X goto blidge; X } X } X return True; X X blidge: X debug(1, "Fail, Skipping rest of the block"); X while (readline(1) != TIMEOUT) X /* skip rest of the block */; X return False; X} X Xbool Xxtrec(filename, xmodem) X char *filename; X int xmodem; X{ X int state = RecStart; X time_t stime; X int tries = 0; X bool crcmode = True; X FILE *fp; X char rxbuf[BlockSize]; X int cnt, block = 1, c; X X if ((fp = fopen(filename, "w")) == NULL) X { X log("$Unable to open %s for writing", filename); X return False; X } X log("Receive file %s", filename); X SetStart(); X while (state >= RecStart && state <= WaitBlock) X switch (state) X { X case RecStart: X debug(1,"Send %s", crcmode ? "C" : "NAK"); X sendline(crcmode ? 'C' : NAK); X sendline(0); X sendline(~0); X state = WaitFirst; X break; X case WaitFirst: X if (tries > 10 || Timeout(60)) X { X if (tries > 10) X log("Too many tries on xmodem receive"); X else X log("Timeout on xmodem receive start"); X state = Error; X } X else if ((c = readline(10)) == EOT) X { X sendline(ACK); X log("No file to receive"); X state = Done; X } X else if (c == SYN || c == SOH) /* Probably telink block? */ X { X debug(1, "Startup in %s mode", crcmode ? "crc" : "checksum"); X if (!xtrecblk(rxbuf, -1 /* c == SYN ? 0 : 1 */ , crcmode)) X { X debug(1, "Retry, bad block"); X tries++; /* No valid block received */ X state = RecStart; X#ifdef NEEDED X block = 1; /* Bad block, ignore? */ X state = WaitBlock; X#endif X } X else X { X if (c == SOH && received_block_number == 1) X { X for (cnt = 0; cnt < BlockSize; cnt++) X (void) putc(c, fp); X block = 2; X debug(2, "Block written onto disk"); X } X else if (c == SYN || received_block_number == 0) X { X sendline(ACK); /* Tell sender we got it */ X sendline(0); X sendline(~0); X block = 1; X debug(1, "TeLink block ignored"); X } X else X { X debug(1, "Retry, bad block"); X tries++; X state = RecStart; X } X state = WaitBlock; X } X } X else if (c == TIMEOUT || c == TSYNCH) /* Tsynch ? Maybe it... */ X { X debug(1, "Timout on Xmodem rcv start"); X tries++; X state = RecStart; X } X else if (tries > 3 || Timeout(30)) X { X log("Try checksum mode"); X crcmode = False; X state = RecStart; X sleep(1); X } X break; X case WaitBlock: X SetStart(); X for (tries = 0; state == WaitBlock; tries++) X if (tries > 10 || Timeout(60)) X { X if (tries > 10) X log("Too many retries (%d) on %s", tries, filename); X else X log("Timeout on receive %s, tries %d", filename, tries); X state = Error; X } X else if ((c = readline(10)) == EOT) X { X log("File %s received ok", filename); X state = Done; X } X else if (c == SOH) X { X if (xtrecblk(rxbuf, block, crcmode)) X { X for (cnt = 0; cnt < BlockSize; cnt++) X (void) putc(rxbuf[cnt], fp); X debug(2, "Block written onto disk, tries %d", tries); X sendline(ACK); X sendline(block); X sendline(~block); X block++; X tries = 0; X SetStart(); X } X else X { X debug(1, "Block not received correctly, tries %d", tries); X sendline(NAK); X sendline(block); X sendline(~block); X tries++; X } X } X else if (c == TIMEOUT) X { X debug(1, "Timeout on block %d, tries %d", block, tries); X sendline(NAK); X sendline(block); X sendline(~block); X tries++; X } X else X tries = 0; /* Trash from send-ahead... skip it */ X X } X X (void) fclose(fp); X X return state != Error; X} X Xint Xrecmdmfn(filename) X char *filename; X{ X int state = SendNak; X time_t stime; X int tries = 0, c, pos; X X SetStart(); X while (state >= SendNak && state <= WaitOkCk) X switch (state) X { X case SendNak: X if (tries > 20) X { X log("Too many tries to get filename"); X state = Error; X } X else if (Timeout(60)) X { X log("Timeout while getting filename"); X state = Error; X } X else X { X sendline(NAK); X state = WaitAck; X tries++; X } X break; X case WaitAck: X switch (readline(5)) X { X case ACK: X pos = 0; X state = WaitChar; X break; X case EOT: X pos = 0; X state = Done; X break; X case TIMEOUT: X debug(2, "Timout while waiting ACK/EOT on MDM7"); X state = SendNak; X break; X default: X state = SendNak; X debug(2, "Garbage on line while getting filename"); X (void) sleep((unsigned) 1); X flush(); X break; X } X break; X case WaitChar: X switch (c = readline(1)) X { X case EOT: X pos = 0; X debug(2, "Got EOT in middle of filename, no files left"); X state = Done; X break; X case SUB: X filename[pos] = 0; X debug(2, "Got fn %s, sending checksum", filename); X for (pos = 0, c = SUB; filename[pos]; pos++) X c += filename[pos]; X sendline(c & 0377); X state = WaitOkCk; X break; X case 'u': X debug(2, "Got 'u', send NAK again"); X state = SendNak; X break; X case TIMEOUT: X debug(2, "Timeout while waiting char of filename"); X state = SendNak; X break; X default: X filename[pos++] = c; X debug(3, "Got char '%c' of filename", c); X break; X } X break; X case WaitOkCk: X if (readline(1) == ACK) X { X debug(1, "Got filename %s ok", filename); X state = Done; X } X else X { X debug(1, "Checksum faiure in filename %s", filename); X state = SendNak; X } X break; X } X X return state == Error ? -1 : pos ? 1 : 0; X} X Xbool Xbatchrec(filename) X char *filename; X{ X int state = RecvName; X char filen[100]; X int ok; X if (!filename) filename = filen; X X while (state >= RecvName && state <= CheckFile) X switch (state) X { X case RecvName: X ok = recmdmfn(filename); X state = CheckFNm; X break; X case CheckFNm: X switch (ok) X { X case -1: X debug(1, "Abort batch receive"); X state = Error; X break; X case 0: X log("All files received successfully"); X state = Done; X break; X case 1: X ok = xtrec(filename, FALSE); X state = CheckFile; X } X break; X case CheckFile: X if (ok) X { X debug(1, "%s received successfully", filename); X state = RecvName; X } X else X { X log("Batch receive aborted, %s not received", filename); X state = Error; X } X break; X } X X return state != Error; X} SHAR_EOF chmod 0644 xtrec.c || echo "restore of xtrec.c fails" echo "x - extracting nodelist.c (Text)" sed 's/^X//' << 'SHAR_EOF' > nodelist.c && X#ifndef lint Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%"; X#endif X X/* Routines to get and translate information in nodelist. X X @(#)Copyright (c) 1987 by Teemu Torma X X Permission is given to distribute this program and alter this code as X needed to adapt it to forign systems provided that this header is X included and that the original author's name is preserved. */ X X/* X Sat Oct 8 17:36:11 1988 X Rewrote nodelist index handling and reading. Now index is kept X in memory, and has zones also. X */ X X/* LINTLIBRARY */ X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include "hsu.h" X#include "config.h" X#include "fnet.h" X#include "nodelist.h" X Xextern long atol(); XNode originnode; XNODEINDEX *nodeindex = NULL; XNAMEINDEX *nameindex = NULL; Xint nodes, names, compile_zone, compile_region, compile_net; X Xfine_convert(name) X char *name; X{ X int wasspace = TRUE; X X for (; *name; name++) X { X if (*name == '_') *name = ' '; X if (isspace(*name)) X wasspace = TRUE; X else if (wasspace) X { X *name = toupper(*name); X wasspace = FALSE; X } X else X *name = tolower(*name); X } X} X X/* Strip bad chars from names, ie chars not which may be dangerous in X different networks. Currectly removes all non-alphanumeric chars, X but leaves whitespace alone. Strips 8bit chars also. */ X Xstripbad(name) X char *name; X{ X char *d; X X d = alloca(strlen(name) + 1); X strcpy(d, name); X for (; *d; d++) if (isalpha(*d) || isspace(*d) || strchr("-._", *d)) X *name++ = *d; X X *name = *d; /* Terminating null, result can be shorter */ X} X X/* Compare two strings, considering '_' and ' ', and converting X {|}[\] to aoaAOA instead, and ignoring case. X X ascii_convert(string) does conversion. X */ X Xchar *ascii_convert(s) X char *s; X{ X char *p; X X p = s; X while (*s) { X switch (*s) { X case '_': X *s = ' '; X break; X case '{': X case '}': X case '[': X case ']': X *s = 'a'; X break; X case '|': X case '\\': X *s = 'o'; X break; X default: X *s = tolower(*s); X } X s++; X } X return p; X} X Xstricmp(d, s) X char *d, *s; X{ X char ds[BUFSIZ], ss[BUFSIZ]; X X return strcmp(ascii_convert(strcpy(ds, d)), X ascii_convert(strcpy(ss, s))); X} X Xstrnicmp(d, s, n) X char *d, *s; X int n; X{ X return strncmp(ascii_convert(strcpy(alloca(strlen(d) + 2), d)), X ascii_convert(strcpy(alloca(strlen(s) + 2), s)), n); X} X X/* Compare nodelist index entry (for qsort) */ Xcmpnodeindex(node1, node2) X NODEINDEX *node1, *node2; X{ X if (node1->zone < node2->zone) return -1; X if (node1->zone > node2->zone) return 1; X if (node1->net < node2->net) return -1; X if (node1->net > node2->net) return 1; X if (node1->node < node2->node) return -1; X if (node1->node > node2->node) return 1; X return 0; /* Same node */ X} X Xcmpnameindex(name1, name2) X NAMEINDEX *name1, *name2; X{ X int n; X n = stricmp(name1->name, name2->name); X /* debug(9, "name1 %s name2 %s = %d", name1->name, name2->name, n); */ X return n; X} X X/* Read file in to a buffer allocating buffer for it */ X Xlong read_file(buffer, name) X char **buffer, *name; X{ X FILE *fp; X long size = 0; X X if (fp = fopen(name, "r")) { X fseek(fp, 0L, SEEK_END); X size = ftell(fp); X X /* Apparently we are on 16-bit? */ X if (size > MAXINT) X { X log("Brain damaged CPU architecture reading file?"); X size = 0; X goto out; X } X X fseek(fp, 0L, SEEK_SET); X X if (*buffer) X *buffer = realloc( *buffer, (unsigned) size); X else X *buffer = malloc( (unsigned) size); X X debug(2, "Reading %d bytes from %s", size, name); X if (fread( *buffer, 1, (int) size, fp) != size) size = 0; X fclose(fp); X } X X out: X return size; X} X Xwrite_file(buffer, name, size) X char *buffer, *name; X int size; X{ X FILE *fp; X int rvalue = 0; X X if (fp = fopen(name, "w+")) X { X debug(2, "Writing %d bytes to %s", size, name); X if (fwrite(buffer, 1, size, fp) != size) rvalue = -1; X fclose(fp); X } X X return rvalue; X} X Xread_nodeindex() X{ X nodes = read_file( (char **) &nodeindex, X sprintfs("%s/%s", LIBDIR, INODELIST)) / sizeof(NODEINDEX); X return nodes == 0L; X} X Xread_nameindex() X{ X names = read_file( (char **) &nameindex, X sprintfs("%s/%s", LIBDIR, NAMELIST)) / sizeof(NAMEINDEX); X return names == 0L; X} X Xwrite_nodeindex() X{ X return write_file( (char *) nodeindex, X sprintfs("%s/%s", LIBDIR, INODELIST), X (int) (nodes * sizeof(NODEINDEX))); X} X Xwrite_nameindex() X{ X return write_file( (char *) nameindex, X sprintfs("%s/%s", LIBDIR, NAMELIST), X (int) (names * sizeof(NAMEINDEX))); X} X X/* Make nodelist's index-file. That index-file will be used to search X desired net/region from nodelist. X Return NULL if everything was fine, otherwise error-message string. */ X Xchar * Xupdate_index() X{ X struct stat nlstat, inlstat; X FILE *nl = NULL, *nlidx = NULL, *namefp = NULL; X char nodelist[BUFLEN], inodelist[BUFLEN], namelist[BUFLEN]; X char buffer[BUFSIZ]; X long offset; X char *error; X Node node; X NODEINDEX nodei; X NAMEINDEX namei; X extern void qsort(); X X /* generate nodelist and index-file names */ X (void) sprintf(nodelist, "%s/%s", LIBDIR, NODELIST); X (void) sprintf(inodelist, "%s/%s", LIBDIR, INODELIST); X (void) sprintf(namelist, "%s/%s", LIBDIR, NAMELIST); X X /* get statuses of nodelist and index */ X if (stat(nodelist, &nlstat) == -1) X return "$Error in getting nodelist status"; X X errno = 0; X if (stat(inodelist, &inlstat) == -1 && errno != ENOENT) X return "$Error in getting status of existing nodelist-index"; X X /* If index-file does exists then check modification times and X first lines. If nodelist is older and first lines are the same, X no update is needed. If index-file should be rebuild, assume X also rebuilding namelist. */ X X if (errno == 0 && nlstat.st_mtime <= inlstat.st_mtime) X { X error = NULL; X goto done; X } X else X log("Update nodelist-index: nodelist is newer than index"); X X /* open index-file for writing */ X if (nlidx != NULL) X (void) fclose(nlidx); X if ((nlidx = fopen(inodelist, "w")) == NULL) X { X error = "$Unable to open nodelist-index for writing"; X goto done; X } X if (namefp) X (void) fclose(namefp); X if ((namefp = fopen(namelist, "w")) == NULL) X { X error = "$Unable to open namelist-index for writing"; X goto done; X } X X if (!nl) X if ((nl = fopen(nodelist, "r")) == NULL) X return "$Unable to open nodelist"; X X (void) rewind(nl); X X compile_zone = MY_ZONE; X compile_region = MY_REGION; X compile_net = MY_NET; X nodes = 0; X names = 0; X X /* save host/region offsets */ X for (offset = ftell(nl); fgets(buffer, BUFSIZ, nl); offset = ftell(nl)) X { X if (*buffer == '\n' || *buffer == ';') continue; X X parse_entry(&node, buffer); X X nodei.zone = node.zone; X nodei.net = node.net; X nodei.node = node.node; X nodei.offset = offset; X X#ifdef NEEDED X debug(8, "%s", buffer); X debug(8, "writing %d:%d/%d", node.zone, node.net, node.node); X#endif X FWRITE( (char *) &nodei, sizeof(NODEINDEX), 1, nlidx); X if (ferror(nlidx)) X { X error = "$Cannot write index, no space?"; X goto done; X } X X if (node.type != REGION && node.type != HOST && X node.type != ZONE && node.type != KENL && node.type != HUB) X { X strcpy(namei.name, node.sysop); X namei.offset = offset; X namei.zone = compile_zone; X namei.net = compile_net; X names++; X FWRITE( (char *) &namei, sizeof(NAMEINDEX), 1, namefp); X if (ferror(namefp)) X { X error = "$Cannot write name index, no space?"; X goto done; X } X } X X nodes++; X } X error = NULL; X X /* Ok, now get both indices back and qsort them */ X X (void) fclose(nl); X nl = NULL; X (void) fclose(nlidx); X nlidx = NULL; X (void) fclose(namefp); X namefp = NULL; X X if (read_nodeindex()) X { X error = "$Cannot read nodelist index"; X goto done; X } X if (read_nameindex()) X { X error = "$Cannot read name index"; X goto done; X } X X log("Sorting nodelist index"); X (void) qsort( (char *) nodeindex, (unsigned) nodes, X sizeof(NODEINDEX), cmpnodeindex); X log("Sorting name index"); X (void) qsort( (char *) nameindex, (unsigned) names, X sizeof(NAMEINDEX), cmpnameindex); X log("Sorted indices"); X X if (write_nodeindex()) X { X error = "$Cannot write nodelist index"; X goto done; X } X if (write_nameindex()) X { X error = "$Cannot write name index"; X goto done; X } X X /* done, close files and return error message */ X done: X if (nl) X (void) fclose(nl); X if (nlidx) X (void) fclose(nlidx); X if (namefp) X (void) fclose(namefp); X return error; X} X X/* Convert underscores in string to spaces. In nodelist there is always X underscore insted of space (flags is special case). */ X Xvoid Xconvert_space(s) X register char *s; X{ X while (*s) X { X if (*s == '_') X *s = ' '; X s++; X } X} X X/* Get one comma-terminated field from buffer, retrun pointer to right X after terminating comma. Convert underscores to spaces in string. */ X Xchar * Xparse_field(buffer, entry, size) X char *buffer, *entry; X int size; X{ X char *np = entry; X X /* copy string */ X while (--size >= 0 && *buffer && *buffer != ',') X *entry++ = *buffer++; X *entry = 0; X X switch (*buffer) X { X case 0: X /* end of buffer */ X log("No closing comma in field"); X return (char *) 0; X case ',': X /* succesful copy */ X convert_space(np); X return buffer + 1; X default: X /* buffer too long, find comma */ X while (*buffer && *buffer != ',') X buffer++; X if (*buffer) X { X convert_space(np); X return buffer + 1; X } X else X { X log("Missing comma in field"); X return (char *) 0; X } X } X /* NOTREACHED */ X} X X/* Parse one line of nodelist to node structure. Return NULL is there X was error's in that line or missing fields. */ X XNode * Xparse_entry(entry, buffer) X Node *entry; X char *buffer; X{ X char *cp; X int n; X X /* strip newline if exists */ X if (cp = strchr(buffer, '\n')) X *cp = 0; X X /* get type of entry */ X if (!strncmp("Zone,", buffer, 5)) X entry->type = ZONE; X else if (!strncmp("Region,", buffer, 7)) X entry->type = REGION; X else if (!strncmp("Host,", buffer, 5)) X entry->type = HOST; X else if (!strncmp("Hub,", buffer, 4)) X entry->type = HUB; X else if (!strncmp("Pvt,", buffer, 4)) X entry->type = PVT; X else if (!strncmp("Hold,", buffer, 5)) X entry->type = HOLD; X else if (!strncmp("Down,", buffer, 5)) X entry->type = DOWN; X else if (!strncmp("Kenl,", buffer, 5)) X entry->type = KENL; X else if (*buffer == ',') X entry->type = NORMAL; X else X { X log("Unknown type in line '%s'", buffer); X return (Node *) 0; X } X X /* get net/region/node number */ X if ((cp = strchr(buffer, ',')) == NULL) X { X log("Missing zone/net/node/region in line '%s'", buffer); X return (Node *) 0; X } X if ((n = atoi(++cp)) == 0) X { X log("Value of zone/net/node/region is 0 in line '%s'", buffer); X return (Node *) 0; X } X if (entry->type == ZONE) X { X entry->zone = n; X entry->net = 0; X entry->node = 0; X entry->point = 0; X compile_zone = n; X debug(8, "Zone %d", compile_zone); X } X else if (entry->type == REGION) X { X entry->zone = compile_zone; X entry->region = n; X entry->net = n; /* For compatibility with old version */ X entry->node = 0; X entry->point = 0; X compile_region = n; X compile_net = n; /* For compatibility with old version */ X debug(8, "Region %d", compile_region); X } X else if (entry->type == HOST) X { X entry->zone = compile_zone; X entry->region = compile_region; X entry->net = n; X entry->node = 0; X entry->point = 0; X compile_net = n; X debug(8, "Net %d", compile_net); X } X else X { X entry->zone = compile_zone; X entry->region = compile_region; X entry->net = compile_net; X entry->node = n; X entry->point = 0; X } X while (*cp && *cp++ != ','); X X /* get node/net/region name */ X if ((cp = parse_field(cp, entry->name, sizeof(entry->name))) == NULL) X { X log("Invalid name in line '%s'", buffer); X return (Node *) 0; X } X X /* get city */ X if ((cp = parse_field(cp, entry->city, sizeof(entry->city))) == NULL) X { X log("Invalid city in line '%s'", buffer); X return (Node *) 0; X } X X /* get sysop */ X if ((cp = parse_field(cp, entry->sysop, sizeof(entry->sysop))) == NULL) X { X log("Invalid sysop in line '%s'", buffer); X return (Node *) 0; X } X X /* get phone number */ X if ((cp = parse_field(cp, entry->phone, sizeof(entry->phone))) == NULL) X { X log("Invalid phone-number in line '%s'", buffer); X return (Node *) 0; X } X X /* get maximum baud rate */ X if ((n = atoi(cp)) == 0) X { X log("Baud rate is 0 in line '%s'", buffer); X return (Node *) 0; X } X entry->speed = n; X while (*cp && *cp++ != ','); X X /* get flags */ X (void) strncpy(entry->flags, cp, sizeof(entry->flags)); X entry->flags[sizeof(entry->flags) - 1] = 0; X X /* all done */ X return entry; X} X X/* Get entry for one node from nodelist. Return NULL, if there is no X entry for that node. */ X XNode * Xnode_entry(node) X Node node; X{ X static Node entry; X FILE *fp; X char buffer[BUFSIZ]; X extern char *bsearch(); X long offset; X NODEINDEX *nodeip, nodei; X X /* Read index file into memory */ X X if (!nodeindex) X if (read_nodeindex()) X { X log("$Unable to read nodelist"); X return (Node *) 0; X } X X nodei.zone = node.zone; X nodei.net = node.net; X nodei.node = node.node; X X debug(2, "Searching %s from %d nodes", ascnodei(nodei), nodes); X nodeip = (NODEINDEX *) bsearch( (char *) &nodei, (char *) nodeindex, X (unsigned) nodes, sizeof(NODEINDEX), X cmpnodeindex); X X if (nodeip) { X offset = nodeip->offset; X X /* open nodelist */ X (void) sprintf(buffer, "%s/%s", LIBDIR, NODELIST); X if ((fp = fopen(buffer, "r")) == NULL) X { X log("$Unable to open %s", buffer); X return (Node *) 0; X } X X if (fseek(fp, offset, 0)) X { X log("$Seek error on nodelist"); X (void) fclose(fp); X return (Node *) 0; X } X X fgets(buffer, BUFSIZ, fp); X fclose(fp); X X compile_zone = nodeip->zone; X compile_net = nodeip->net; X return parse_entry(&entry, buffer); X } X X log("Could not find node %s", ascnodei(nodei)); X X /* we didn't find net/region */ X (void) fclose(fp); X return (Node *) 0; X} X Xchar *dialtable[] = { DIALTABLE }; X Xdial_translation(dest, source) X char *dest, *source; X{ X register int count = 0; X X for (;;) { X if (!*dialtable[count] || X !strncmp(dialtable[count], source, strlen(dialtable[count]))) { X X /* Matched, take prefix, */ X strcpy(dest, dialtable[count + 1]); X X /* Then add phone number */ X strcat(dest, source + strlen(dialtable[count])); X return; X } X count += 2; X } X} X Xstatic char **aliastable = NULL; Xstatic allocated = 0; Xstatic aliases = 0; X Xexpand_aliastable() X{ X if (!aliastable) X { X aliastable = (char **) malloc(sizeof(char *) * 20); X if (aliastable) allocated = 20; X } X X if (aliases == allocated) /* Need more pointers */ X { X allocated += 20; X aliastable = (char **) realloc( (char *) aliastable, X sizeof(char *) * allocated); X if (!aliastable) X { X log("Cannot realloc %d bytes", sizeof(char *) * allocated); X return -1; X } X } X return 0; X} X X#define FILENAME_SIZE 256 X Xsearch_name(name) X char *name; X{ X Node entry; X FILE *fp; X char buffer[BUFSIZ]; X extern char *bsearch(); X char *nlname; X long offset; X NAMEINDEX *nameip, namei; X X if (!nameindex) X if (read_nameindex()) X { X log("$Unable to read namelist"); X return -1; X } X X strncpy(namei.name, name, 36); X namei.name[35] = 0; X X nameip = (NAMEINDEX *) bsearch( (char *) &namei, (char *) nameindex, X (unsigned) names, sizeof(NAMEINDEX), X cmpnameindex); X X if (nameip) X { X offset = nameip->offset; X X /* Open nodelist */ X if ((fp = X fopen(nlname = sprintfs("%s/%s", LIBDIR, NODELIST), "r")) == NULL) X { X log("$Unable to open nodelist %s", nlname); X return -1; X } X X if (fseek(fp, offset, 0)) X { X log("$Seek error on nodelist"); X (void) fclose(fp); X return -1; X } X X fgets(buffer, BUFSIZ, fp); X fclose(fp); X X compile_zone = nameip->zone; X compile_net = nameip->net; X if (parse_entry(&entry, buffer) == NULL) return -1; X X debug(1, "Search name %s returns %d:%d/%d.%d", name, X entry.zone, entry.net, entry.node, entry.point); X memcpy( (char *) &originnode, (char *) &entry, sizeof(Node)); X return 0; X } X X debug(1, "Search name %s return no node", name); X return -1; X} X SHAR_EOF chmod 0644 nodelist.c || echo "restore of nodelist.c fails" echo "x - extracting gethostname.c (Text)" sed 's/^X//' << 'SHAR_EOF' > gethostname.c && X#ifndef lint Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%"; X#endif X X/* Get host name. This emulates routine with same name in BSD-Unix. X X @(#)Copyright (c) 1987 by Teemu Torma X X Permission is given to distribute this program and alter this code as X needed to adapt it to forign systems provided that this header is X included and that the original author's name is preserved. */ X X#include X#include X X/* Get name of this uucp-node. Name is stored in buffer. Len in maximum X length of buffer. Return -1 if can not do uname(2), otherwise 0. */ X Xint Xgethostname(buffer, len) X char *buffer; X int len; X{ X struct utsname name; X X if (uname(&name) == -1) X return -1; X (void) strncpy(buffer, name.nodename, len); X buffer[len - 1] = 0; X return 0; X} SHAR_EOF chmod 0644 gethostname.c || echo "restore of gethostname.c fails" echo "x - extracting dateconv.c (Text)" sed 's/^X//' << 'SHAR_EOF' > dateconv.c && X#ifndef lint Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%"; X#endif X X/* Convert date to type time_t (time in seconds since 1 Jan 1970). X X @(#)Copyright (c) 1987 by Teemu Torma X X Permission is given to distribute this program and alter this code as X needed to adapt it to forign systems provided that this header is X included and that the original author's name is preserved. */ X X/* LINTLIBRARY */ X X#include X#include X#include X#include "fnet.h" X X#define epoch 1970 X#define daysec (24l * 60l * 60l) X#define AM 1 X#define PM 2 X X/* days in each month */ Xstatic int mdays[12] = { X 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, X}; X X/* Convert hours, minutes and seconds to seconds */ X Xtime_t Xtimeconv(hh, mm, ss, mer) X int hh, mm, ss; X int mer; X{ X /* check correctness of time */ X if (mm < 0 || mm > 59 || ss < 0 || ss > 59) X return (time_t) -1; X X /* count time */ X switch (mer) X { X case AM: X if (hh < 1 || hh > 12) X return(time_t) 1; X return (60L * ((hh % 12) * 60L + mm) + ss); X case PM: X if (hh < 1 || hh > 12) X return(time_t) 1; X return (60L * ((hh % 12 +12) * 60L + mm) + ss); X case 24: X if (hh < 0 || hh > 23) X return (time_t) 1; X return (60L * (hh * 60L + mm) + ss); X default: X return (time_t) 1; X } X /* NOTREACHED */ X} X X/* Convert date to seconds from beginning of year 1970 (normal Unix X time). Return -1 if something wen't wrong. */ X X/* ARGSUSED */ Xtime_t Xdateconv(mm, dd, yy, h, m, s, mer, zone, dayflag) X int mm, dd, yy, h, m, s; X int mer, zone; X{ X time_t tod, jdate; X register int n; X X /* if negative year make it positive */ X if (yy < 0) X yy = -yy; X X /* if year is 00..99 make it right */ X if (yy < 100) X yy += 1900; X X /* count days for february */ X mdays[1] = 28 + (yy % 4 == 0 && (yy % 100 != 0 || yy % 400 == 0)); X X /* check correctess of date (year 1970..1999) */ X if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 || dd < 1 || X dd > mdays[--mm]) X return (time_t) -1; X X /* counts days from beginning of year */ X jdate = (time_t ) (dd - 1); X for (n = 0; n < mm; n++) X jdate += (time_t) mdays[n]; X X /* add years to days */ X for (n = epoch; n < yy; n++) X jdate += (time_t) (365 + (n % 4 == 0)); X X /* convert days to seconds */ X jdate *= daysec; X X /* add time of day */ X if ((tod = timeconv(h, m, s, mer)) < 0) X return (time_t) -1; X jdate += tod; X X /* add time zone to date */ X jdate += (time_t) zone * 60L; X X return jdate; X} SHAR_EOF chmod 0644 dateconv.c || echo "restore of dateconv.c fails" echo "x - extracting address.c (Text)" sed 's/^X//' << 'SHAR_EOF' > address.c && X#ifndef lint Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%"; X#endif X X/* Routines to handle fidonet addresses. Currently addres format in outside X fidonet is @..fidonet. This will propablty change when X zones are coming. Those standards are ready, but I haven't seen them X yet. X X Mon Oct 3 02:43:49 1988 X zones-format will be @....fidonet. X Fidonet-like format maybe would be easier to get used to but X parsing it with sendmails etc would be more difficult. Notice that there X certainly will be problems if different number of numbers than 4 X is specified. I will use following solution: X X case 4: assume point.node.net.zone X case 3: assume node.net.zone (point 0) X case 2: assume node.net (in current zone, point 0) X case 1: assume node (in current net, zone, point 0) X X Other way would be to force users to use zones and/or try to check X other possibilities by checking if its on the nodelist. I don't X really like points, they make life difficult, they could just be local X nodes off the nodelist, and no special support would be needed! X X @(#)Copyright (c) 1987 by Teemu Torma X X Permission is given to distribute this program and alter this code as X needed to adapt it to forign systems provided that this header is X included and that the original author's name is preserved. */ X X/* LINTLIBRARY */ X X#include X#include X#include X#include X#include "hsu.h" X#include "config.h" X#include "fnet.h" X#include "nodelist.h" X#include "shuffle.h" X X X/* Parse fidonet address to name, net and node. Address contains address, X and name, net and node will be returned. Return NULL is it was valid X fidonet address, otherwise string to error message. */ X Xchar * Xparse_address(address, name, node) X char *address, *name; X Node *node; X{ X static char error[64]; X register char *cp; X register int cnt; X X /* make address to lowercase */ X for (cp = address; *cp; cp++) X if (isupper(*cp)) X *cp = tolower(*cp); X X /* Get name. We assume that name has space at least 36 charcers (maximum X length of name in fido). First check wheather format is name@domain X of domain!name format. */ X if ((cp = strchr(address, '!')) != NULL) X { X debug(2, "Fidonet address domain!name"); X for (cp++, cnt = 0; *cp && cnt < 35; cnt++, cp++) X name[cnt] = *cp; X name[cnt] = 0; X cp = address; X debug(3, "Name %s", name); X } X else X { X debug(2, "Fidonet address name@domain"); X for (cp = address, cnt = 0; *cp && cnt < 35 && *cp != '@'; cp++, cnt++) X name[cnt] = *cp; X name[cnt] = 0; X debug(3, "Name %s", name); X X if (*cp != '@') X { X /* name is too long or address is invalid */ X while (*cp && *cp != '@') X cp++; X if (*cp == 0) X { X debug(1, "Invalid address: %s: missing @", address); X (void) sprintf(error, "No @ in address %s", address); X return error; X } X } X cp++; X } X X debug(2, "Address %s, up to '!' or end", cp); X X if (parseinternode(cp, node)) X { X sprintf(error, "Bad address %s", cp); X return error; X } X X#ifdef NEEDED X /* now parse address, cp points to beginning of it. */ X for (*node = 0; isdigit(*cp); cp++) X *node = 10 * *node + *cp - '0'; X if (*cp != '.') X { X debug(1, "Invalid address: %s: no . after node", address); X debug(2, "Rest of address %s, node %d", cp, *node); X (void) sprintf(error, "No net number in address %s", address); X return error; X } X X /* get net */ X for (cp++, *net = 0; isdigit(*cp); cp++) X *net = 10 * *net + *cp - '0'; X if (*cp != '.') X { X debug(1, "Invalid address: %s: no . after net", address); X debug(2, "Rest of address %s, net/node %d/%d", *net, *node); X (void) sprintf(error, "No domain in address %s", address); X return error; X } X X cp++; X debug(3, "Domain %s", cp); X X /* check that .fidonet is present */ X if (strncmp(cp, "fidonet", 7) || (cp[7] != 0 && cp[7] != '!')) X { X debug(1, "Invalid address: %s: not .fidonet domain", address); X (void) sprintf(error, "Domain is not .fidonet in address %s", address); X return error; X } X X#endif X /* we're done */ X return NULL; X} X Xreturnbad(errtype, s, node) X char *errtype, *s; X Node *node; X{ X log("Bad address %s : %s, returning my node", s, errtype); X node->zone = MY_ZONE; X node->net = MY_NET; X node->node = MY_NODE; X node->point = MY_POINT; X return -1; X} X X/* Parse internet format fidonet address */ X Xparseinternode(address, node) X char *address; X Node *node; X{ X char *p, *s; X int numbers[4], count = 0; X X s = alloca(strlen(address) + 1); X strcpy(s, address); X numbers[0] = numbers[1] = numbers[2] = numbers[3] = -1; X X if (strlen(s) > strlen(".fidonet")) X if (!strcmp(s + strlen(s) - strlen(".fidonet"), ".fidonet")) X s[strlen(s) - strlen(".fidonet")] = 0; X X for (p = strtok(s, "."); p; p = strtok(NULL, ".")) X numbers[count++] = atoi(p); X X if (!count) return returnbad("empty fidonet address", address, node); X if (count == 4) X { X node->zone = numbers[3]; X node->net = numbers[2]; X node->node = numbers[1]; X node->point = numbers[0]; X return 0; X } X X if (numbers[0] == -1) return returnbad("no node", address, node); X if (numbers[1] == -1) numbers[1] = MY_NET; X if (numbers[2] == -1) numbers[2] = MY_ZONE; X node->zone = numbers[2]; X node->net = numbers[1]; X node->node = numbers[0]; X node->point = 0; X return 0; X} X X/* It would have been more sensible if X fidonet addresses were down to up, it would be easier to parse. X X Fri Oct 7 12:09:21 1988 X Removes non-numeric chars at start, Opus puts 'Opus ' there X */ X Xparsefnetaddress(s, node) X char *s; X Node *node; X{ X char *p, *lastnumber; X char nodenbuf[100]; X X strncpy(nodenbuf, s, 99); X nodenbuf[99] = 0; X s = nodenbuf; X X node->zone = 0; X node->net = 0; X node->node = 0; X node->point = 0; X p = s; X X while (!isdigit(*p) && *p) p++; X X while (*p) { X switch (*p) { X case '0': X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X { X lastnumber = p; X while (isdigit(*++p)); X continue; X } X case ':': X /* Previous number is zone */ X if (node->zone) return returnbad("two zones", s, node); X node->zone = atoi(lastnumber); X lastnumber = p + 1; X break; X case '/': X /* Previous number is net */ X if (node->net) return returnbad("two nets", s, node); X node->net = atoi(lastnumber); X lastnumber = p + 1; X break; X case '.': X /* Previous number is node */ X if (node->node) return returnbad("two nodes", s, node); X node->node = atoi(lastnumber); X lastnumber = p + 1; X break; X case 0: X /* End: lastnumber should have point (or its at end, which gives us 0) */ X node->node = atoi(lastnumber); X if (node->zone == 0) node->zone = MY_ZONE; X if (node->net == 0) node->net = MY_NET; X return 0; X default: X log("Bad char %d in %s", *p, s); X return returnbad("bad char", s, node); X } X p++; X } X if (node->zone == 0) node->zone = MY_ZONE; X if (node->net == 0) return returnbad("no net", s, node); X if (node->node == 0) X node->node = atoi(lastnumber); X X return 0; X} X X/* Return address in string format */ X Xchar *ascnode(node) X Node node; X{ X SHUFFLEBUFFERS; X X sprintf(tcharp, "%d:%d/%d.%d", node.zone, node.net, node.node, node.point); X return tcharp; X} X X/* Internet format */ Xchar *internode(node) X Node node; X{ X SHUFFLEBUFFERS; X X if (node.point) X sprintf(tcharp, "%d.%d.%d.%d.fidonet", node.point, node.node, node.net, X node.zone); X else X sprintf(tcharp, "%d.%d.%d.fidonet", node.node, node.net, node.zone); X X return tcharp; X} X X/* same for index node structure */ X Xchar *ascnodei(node) X NODEINDEX node; X{ X SHUFFLEBUFFERS; X X sprintf(tcharp, "%d:%d/%d", node.zone, node.net, node.node); X return tcharp; X} SHAR_EOF chmod 0644 address.c || echo "restore of address.c fails" echo "x - extracting crc.c (Text)" sed 's/^X//' << 'SHAR_EOF' > crc.c && X#ifndef lint Xstatic char *sccsid = "@(#)%M% %I% Teemu Torma %H%"; X#endif X X/* X * @(#)Copyright (C) Teemu Torma 1987 X */ X X#include X X#ifdef NEEDED X/* ARGSUSED */ Xint main(argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X exit(0); X /* NOTREACHED */ X} X#endif X X/* crctab calculated by Mark G. Mendel, Network Systems Corporation */ Xunsigned short crctab[256] = { X 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, X 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, X 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, X 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, X 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, X 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, X 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, X 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, X 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, X 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, X 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, X 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, X 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, X 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, X 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, X 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, X 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, X 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, X 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, X 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, X 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, X 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, X 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, X 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, X 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, X 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, X 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, X 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, X 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, X 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, X 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, X 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 X}; X X#ifdef NEEDED Xstatic long cr3tab[] = { /* CRC polynomial 0xedb88320 */ X0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, X0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, X0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, X0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, X0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, X0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, X0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, X0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, X0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, X0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, X0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, X0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, X0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, X0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, X0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, X0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, X0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, X0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, X0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, X0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, X0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, SHAR_EOF echo "End of part 4" echo "File crc.c is continued in part 5" echo "5" > s2_seq_.tmp exit 0