v18i005: Fido/Usenet gateway, Part04/05
Rich Salz
rsalz at uunet.uu.net
Tue Mar 7 06:08:08 AEST 1989
Submitted-by: Heikki Suonsivu <hsu at santra.hut.fi>
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 <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <string.h>
X#include <time.h>
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 <stdio.h>
X#include <sys/types.h>
X#include <string.h>
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 <stdio.h>
X#include <string.h>
X#include <unistd.h>
X#include <errno.h>
X#include <ctype.h>
X#include <malloc.h>
X#include <values.h>
X#include <sys/types.h>
X#include <sys/stat.h>
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 <sys/utsname.h>
X#include <string.h>
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 <stdio.h>
X#include <sys/types.h>
X#include <time.h>
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 <name>@<node>.<net>.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 <name>@<point>.<node>.<net>.<zone>.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 <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <sys/types.h>
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 at 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 at 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 <stdio.h>
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
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list