ZMISC.C

21.8 KB 0d3ddba8b4df830a…
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*                                                                          */
/*      ------------         Bit-Bucket Software, Co.                       */
/*      \ 10001101 /         Writers and Distributors of                    */
/*       \ 011110 /          Freely Available<tm> Software.                 */
/*        \ 1011 /                                                          */
/*         ------                                                           */
/*                                                                          */
/*  (C) Copyright 1987-91, Bit Bucket Software Co., a Delaware Corporation. */
/*                                                                          */
/*                                                                          */
/*                 Zmodem routines used by Zsend and Zreceive               */
/*                                                                          */
/*                                                                          */
/*    For complete  details  of the licensing restrictions, please refer    */
/*    to the License  agreement,  which  is published in its entirety in    */
/*    the MAKEFILE and BT.C, and also contained in the file LICENSE.250.    */
/*                                                                          */
/*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
/*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
/*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
/*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
/*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
/*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
/*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
/*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
/*                                                                          */
/*                                                                          */
/* You can contact Bit Bucket Software Co. at any one of the following      */
/* addresses:                                                               */
/*                                                                          */
/* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
/* P.O. Box 460398                AlterNet 7:491/0                          */
/* Aurora, CO 80046               BBS-Net  86:2030/1                        */
/*                                Internet f491.n343.z1.fidonet.org         */
/*                                                                          */
/* Please feel free to contact us at any time to share your comments about  */
/* our software and/or licensing policies.                                  */
/*                                                                          */
/*                                                                          */
/*  This module is based largely on a similar module in OPUS-CBCS V1.03b.   */
/*  The original work is (C) Copyright 1986, Wynn Wagner III. The original  */
/*  authors have graciously allowed us to use their code in this work.      */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/* Include this file before any other includes or defines! */

#include "includes.h"

static int Rxtype;                               /* Type of header received                 */

static char hex[] = "0123456789abcdef";

/* Send a byte as two hex digits */
#define Z_PUTHEX(i,c) {i=(c);SENDBYTE(hex[((i)&0xF0)>>4]);SENDBYTE(hex[(i)&0xF]);}

/*--------------------------------------------------------------------------*/
/* Private routines                                                         */
/*--------------------------------------------------------------------------*/
int _Z_GetBinaryHeader (unsigned char *);
int _Z_32GetBinaryHeader (unsigned char *);
int _Z_GetHexHeader (unsigned char *);
int _Z_GetHex (void);
int _Z_TimedRead (void);
long _Z_PullLongFromHeader (unsigned char *);

#ifdef MILQ
/*
 * Dst   - Where to put this.  Should use a static buffer, if
 *         a destination is not provided
 *
 * Src   - The filename to be conditioned
 *
 * TblNm - Name of the file to use for the source of path
 *         conditioning entries
 *
 * Mode  -
 */

char *ZMdmFlNmCndtn( char *Dst,
                     char *Src,
                     char *Tbl,
                     int   Mode ) {
  char                 *p;
  char                 *q;

  for ( p = Src, q = Dst; *p; ) {
    switch ( *p ) {
      case '/':
      case '\\':
        switch ( UsePaths ) {
          case FALSE:
            q = Dst;
            break;
          default:
            *q++ = '/';
            break;
          }                            /* end of switch ( UsePaths ) */
        break;
      case ':':
        q = Dst;
        break;
      default:
        *q++ = (char) tolower (*p);
        break;
      }                                /* end of for ( p = Src ... ) */
    p++;
    }
  *q++ = '\0';
  return Dst;
  }
#endif

void z_message (char *s)
{
   if (fullscreen && un_attended)
      {
      if (s)
         {
         sb_move (file_hWnd, 2, 27);
         FlLnModeSet( FILE_LN_2, 0 );
         sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_STATUS ), s );
         }
#ifndef MILQ
      sb_puts (file_hWnd, "              ");
#endif
      sb_show ();
      }
   else
      {
      gotoxy (locate_x + 20, locate_y);
      if (s)
         {
         (void) cputs (s);
         }
      (void) cputs ("               ");
      }
}

void z_log (char *s)
{
   word x, y;

   z_message (s);

   x = locate_x;
   y = locate_y;
   status_line (s);                              /* also does disk file
                                                  * logging */
   locate_x = x;
   locate_y = y;
}

void show_loc (unsigned long l, unsigned int w)
{
   char j[100];

   if (fullscreen && un_attended)
      {

      (void) sprintf (j, "Ofs=%ld Retries=%d        ", l, w);
      sb_move (file_hWnd, 2, 37);
      sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_SIZE ), j );
      sb_show ();
      }
   else
      {
      gotoxy (locate_x + 35, locate_y);
      (void) printf ("Ofs=%ld Retries=%d        ", l, w);
      }
}

/*--------------------------------------------------------------------------*/
/* Z GET BYTE                                                               */
/* Get a byte from the modem;                                               */
/* return TIMEOUT if no read within timeout tenths,                         */
/* return RCDO if carrier lost                                              */
/*--------------------------------------------------------------------------*/
int Z_GetByte (int tenths)
{
   long timeout;

   if (PEEKBYTE () >= 0)
      return (MODEM_IN ());

   timeout = timerset (tenths * 10);

   do
      {
      if (PEEKBYTE () >= 0)
         return MODEM_IN ();

      if (!CARRIER)
         return RCDO;

      if (got_ESC ())
         return -1;

      time_release ();
      }
   while (!timeup (timeout));

   return TIMEOUT;
}

/*--------------------------------------------------------------------------*/
/* Z PUT STRING                                                             */
/* Send a string to the modem, processing for \336 (sleep 1 sec)            */
/* and \335 (break signal, ignored)                                         */
/*--------------------------------------------------------------------------*/
void Z_PutString (register unsigned char *s)
{
   register unsigned c;

   while (*s)
      {
      switch (c = *s++)
         {
         case (unsigned int) '\336':
            big_pause (2);
         case (unsigned int) '\335':
/* Should send a break on this */
            break;
         default:
            SENDBYTE ((unsigned char) c);
         }                                       /* switch */

      }                                          /* while */

   Z_UncorkTransmitter ();                       /* Make sure all is well */
}                                                /* Z_PutString */

/*--------------------------------------------------------------------------*/
/* Z SEND HEX HEADER                                                        */
/* Send ZMODEM HEX header hdr of type type                                  */
/*--------------------------------------------------------------------------*/
void Z_SendHexHeader (unsigned int type, register unsigned char *hdr)
{
   register int n;
   register int i;
   register word crc;

   Z_UncorkTransmitter ();                       /* Get our transmitter going */

#ifdef DEBUG
   show_debug_name ("Z_SendHexHeader");
#endif

   SENDBYTE (ZPAD);
   SENDBYTE (ZPAD);
   SENDBYTE (ZDLE);
   SENDBYTE (ZHEX);

   Z_PUTHEX (i, type);

   Crc32t = 0;
   crc = Z_UpdateCRC (type, 0);

   for (n = 4; --n >= 0;)
      {
      Z_PUTHEX (i, (*hdr));
      crc = Z_UpdateCRC (((unsigned short) (*hdr++)), crc);
      }
   Z_PUTHEX (i, (crc >> 8));
   Z_PUTHEX (i, crc);

   /* Make it printable on remote machine */
   SENDBYTE ('\r');
   SENDBYTE ('\n');

   /* Uncork the remote in case a fake XOFF has stopped data flow */
   if (type != ZFIN && type != ZACK)
      SENDBYTE (021);

   if (!CARRIER)
      CLEAR_OUTBOUND ();

}                                                /* Z_SendHexHeader */

/*--------------------------------------------------------------------------*/
/* Z UNCORK TRANSMITTER                                                     */
/* Wait a reasonable amount of time for transmitter buffer to clear.        */
/*   When it does, or when time runs out, turn XON/XOFF off then on.        */
/*   This should release a transmitter stuck by line errors.                */
/*--------------------------------------------------------------------------*/

void Z_UncorkTransmitter ()
{
   long t;

#ifdef DEBUG
   show_debug_name ("Z_UncorkTransmitter");
#endif

   if (!OUT_EMPTY () && CARRIER)
      {
      t = timerset (5 * Rxtimeout);              /* Wait for silence */
      while (!timeup (t) && !OUT_EMPTY () && CARRIER)
         time_release ();                        /* Give up slice while
                                                  * waiting  */
      }

   com_kick ();

}


/*--------------------------------------------------------------------------*/
/* Z GET HEADER                                                             */
/* Read a ZMODEM header to hdr, either binary or hex.                       */
/*   On success, set Zmodem to 1 and return type of header.                 */
/*   Otherwise return negative on error                                     */
/*--------------------------------------------------------------------------*/
int Z_GetHeader (byte *hdr)
{

   register int c;
   register int n;
   int cancount;

#ifdef DEBUG
   show_debug_name ("Z_GetHeader");
#endif

   n = cur_baud.rate_value;                      /* Max characters before
                                                  * start of frame */
   cancount = 5;

Again:

   if (got_ESC ())
      {
      send_can ();
      z_log (MSG_TXT(M_KBD_MSG));
      return ZCAN;
      }

   Rxframeind = Rxtype = 0;

   switch (c = _Z_TimedRead ())
      {
      case ZPAD:
      case ZPAD | 0200:
         /*-----------------------------------------------*/
         /* This is what we want.                         */
         /*-----------------------------------------------*/
         break;

      case RCDO:
      case TIMEOUT:
         goto Done;

      case CAN:

   GotCan:

         if (--cancount <= 0)
            {
            c = ZCAN;
            goto Done;
            }
         switch (c = Z_GetByte (1))
            {
            case TIMEOUT:
               goto Again;

            case ZCRCW:
               c = ERROR;
               /* fallthrough... */

            case RCDO:
               goto Done;

            case CAN:
               if (--cancount <= 0)
                  {
                  c = ZCAN;
                  goto Done;
                  }
               goto Again;
            }
         /* fallthrough... */

      default:

   Agn2:

         if (--n <= 0)
            {
            z_log (MSG_TXT(M_FUBAR_MSG));
            return ERROR;
            }

         if (c != CAN)
            cancount = 5;
         goto Again;

      }                                          /* switch */

   cancount = 5;

Splat:

   switch (c = _Z_TimedRead ())
      {
      case ZDLE:
         /*-----------------------------------------------*/
         /* This is what we want.                         */
         /*-----------------------------------------------*/
         break;

      case ZPAD:
         goto Splat;

      case RCDO:
      case TIMEOUT:
         goto Done;

      default:
         goto Agn2;

      }                                          /* switch */


   switch (c = _Z_TimedRead ())
      {

      case ZBIN:
         Rxframeind = ZBIN;
         Crc32 = 0;
         c = _Z_GetBinaryHeader (hdr);
         break;

      case ZBIN32:
         Crc32 = Rxframeind = ZBIN32;
         c = _Z_32GetBinaryHeader (hdr);
         break;

      case ZHEX:
         Rxframeind = ZHEX;
         Crc32 = 0;
         c = _Z_GetHexHeader (hdr);
         break;

      case CAN:
         goto GotCan;

      case RCDO:
      case TIMEOUT:
         goto Done;

      default:
         goto Agn2;

      }                                          /* switch */

   Rxpos = _Z_PullLongFromHeader (hdr);

Done:

   return c;
}                                                /* Z_GetHeader */

/*--------------------------------------------------------------------------*/
/* Z GET BINARY HEADER                                                      */
/* Receive a binary style header (type and position)                        */
/*--------------------------------------------------------------------------*/
int _Z_GetBinaryHeader (register unsigned char *hdr)
{
   register int c;
   register unsigned int crc;
   register int n;

#ifdef DEBUG
   show_debug_name ("Z_GetBinaryHeader");
#endif

   if ((c = Z_GetZDL ()) & ~0xFF)
      return c;
   Rxtype = c;
   crc = Z_UpdateCRC (c, 0);

   for (n = 4; --n >= 0;)
      {
      if ((c = Z_GetZDL ()) & ~0xFF)
         return c;
      crc = Z_UpdateCRC (c, crc);
      *hdr++ = (unsigned char) (c & 0xff);
      }
   if ((c = Z_GetZDL ()) & ~0xFF)
      return c;

   crc = Z_UpdateCRC (c, crc);
   if ((c = Z_GetZDL ()) & ~0xFF)
      return c;

   crc = Z_UpdateCRC (c, crc);
   if (crc & 0xFFFF)
      {
      z_message (MSG_TXT(M_CRC_MSG));
      return ERROR;
      }

   return Rxtype;
}                                                /* _Z_GetBinaryHeader */


/*--------------------------------------------------------------------------*/
/* Z GET BINARY HEADER with 32 bit CRC                                      */
/* Receive a binary style header (type and position)                        */
/*--------------------------------------------------------------------------*/
int _Z_32GetBinaryHeader (register unsigned char *hdr)
{
   register int c;
   register unsigned long crc;
   register int n;

#ifdef DEBUG
   show_debug_name ("Z_32GetBinaryHeader");
#endif

   if ((c = Z_GetZDL ()) & ~0xFF)
      return c;
   Rxtype = c;
   crc = 0xFFFFFFFF;
   crc = Z_32UpdateCRC (c, crc);

   for (n = 4; --n >= 0;)
      {
      if ((c = Z_GetZDL ()) & ~0xFF)
         return c;
      crc = Z_32UpdateCRC (c, crc);
      *hdr++ = (unsigned char) (c & 0xff);
      }

   for (n = 4; --n >= 0;)
      {
      if ((c = Z_GetZDL ()) & ~0xFF)
         return c;

      crc = Z_32UpdateCRC (c, crc);
      }

   if (crc != 0xDEBB20E3)
      {
      z_message (MSG_TXT(M_CRC_MSG));
      return ERROR;
      }

   return Rxtype;
}                                                /* _Z_32GetBinaryHeader */

/*--------------------------------------------------------------------------*/
/* Z GET HEX HEADER                                                         */
/* Receive a hex style header (type and position)                           */
/*--------------------------------------------------------------------------*/
int _Z_GetHexHeader (register unsigned char *hdr)
{
   register int c;
   register unsigned int crc;
   register int n;

#ifdef DEBUG
   show_debug_name ("Z_GetHexHeader");
#endif

   if ((c = _Z_GetHex ()) < 0)
      return c;
   Rxtype = c;
   crc = Z_UpdateCRC (c, 0);

   for (n = 4; --n >= 0;)
      {
      if ((c = _Z_GetHex ()) < 0)
         return c;
      crc = Z_UpdateCRC (c, crc);
      *hdr++ = (unsigned char) c;
      }

   if ((c = _Z_GetHex ()) < 0)
      return c;
   crc = Z_UpdateCRC (c, crc);
   if ((c = _Z_GetHex ()) < 0)
      return c;
   crc = Z_UpdateCRC (c, crc);
   if (crc & 0xFFFF)
      {
      z_message (MSG_TXT(M_CRC_MSG));
      return ERROR;
      }
   if (Z_GetByte (1) == '\r')
      (void) Z_GetByte (1);                    /* Throw away possible cr/lf */

   return Rxtype;
}

/*--------------------------------------------------------------------------*/
/* Z GET HEX                                                                */
/* Decode two lower case hex digits into an 8 bit byte value                */
/*--------------------------------------------------------------------------*/
int _Z_GetHex ()
{
   register int c, n;

#ifdef DEBUG
   show_debug_name ("Z_GetHex");
#endif

   if ((n = _Z_TimedRead ()) < 0)
      return n;
   n -= '0';
   if (n > 9)
      n -= ('a' - ':');
   if (n & ~0xF)
      return ERROR;

   if ((c = _Z_TimedRead ()) < 0)
      return c;
   c -= '0';
   if (c > 9)
      c -= ('a' - ':');
   if (c & ~0xF)
      return ERROR;

   return ((n << 4) | c);
}

/*--------------------------------------------------------------------------*/
/* Z GET ZDL                                                                */
/* Read a byte, checking for ZMODEM escape encoding                         */
/* including CAN*5 which represents a quick abort                           */
/*--------------------------------------------------------------------------*/
int Z_GetZDL ()
{
   register int c;

   if ((c = Z_GetByte (Rxtimeout)) != ZDLE)
      return c;

   switch (c = Z_GetByte (Rxtimeout))
      {
      case CAN:
         return ((c = Z_GetByte (Rxtimeout)) < 0) ? c :
            ((c == CAN) && ((c = Z_GetByte (Rxtimeout)) < 0)) ? c :
            ((c == CAN) && ((c = Z_GetByte (Rxtimeout)) < 0)) ? c : (GOTCAN);

      case ZCRCE:
      case ZCRCG:
      case ZCRCQ:
      case ZCRCW:
         return (c | GOTOR);

      case ZRUB0:
         return 0x7F;

      case ZRUB1:
         return 0xFF;

      default:
         return (c < 0) ? c :
            ((c & 0x60) == 0x40) ? (c ^ 0x40) : ERROR;

      }                                          /* switch */
}                                                /* Z_GetZDL */

/*--------------------------------------------------------------------------*/
/* Z TIMED READ                                                             */
/* Read a character from the modem line with timeout.                       */
/*  Eat parity, XON and XOFF characters.                                    */
/*--------------------------------------------------------------------------*/
int _Z_TimedRead ()
{
   register int c;

#ifdef DEBUG
   show_debug_name ("Z_TimedRead");
#endif

   for (;;)
      {
      if ((c = Z_GetByte (Rxtimeout)) < 0)
         return c;

      switch (c &= 0x7F)
         {
         case XON:
         case XOFF:
            continue;

         default:
            if (!(c & 0x60))
               continue;

         case '\r':
         case '\n':
         case ZDLE:
            return c;
         }                                       /* switch */

      }                                          /* for */
}                                                /* _Z_TimedRead */

/*--------------------------------------------------------------------------*/
/* Z LONG TO HEADER                                                         */
/* Store long integer pos in Txhdr                                          */
/*--------------------------------------------------------------------------*/
void Z_PutLongIntoHeader (long pos)
{
#ifndef GENERIC
   *((long *) Txhdr) = pos;
#else
   Txhdr[ZP0] = pos;
   Txhdr[ZP1] = pos >> 8;
   Txhdr[ZP2] = pos >> 16;
   Txhdr[ZP3] = pos >> 24;
#endif
}                                                /* Z_PutLongIntoHeader */

/*--------------------------------------------------------------------------*/
/* Z PULL LONG FROM HEADER                                                  */
/* Recover a long integer from a header                                     */
/*--------------------------------------------------------------------------*/
long _Z_PullLongFromHeader (unsigned char *hdr)
{
#ifndef GENERIC
   return (*((long *) hdr)); /*PLF Fri  05-05-1989  06:42:41 */
#else

   long l;

   l = hdr[ZP3];
   l = (l << 8) | hdr[ZP2];
   l = (l << 8) | hdr[ZP1];
   l = (l << 8) | hdr[ZP0];
   return l;
#endif
}                                                /* _Z_PullLongFromHeader */

/* END OF FILE: zmisc.c */