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