ZRECEIVE.C

38.6 KB d6c0c1c1a04cbb31…
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*                                                                          */
/*      ------------         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 file reception module                        */
/*                                                                          */
/*                                                                          */
/*    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"

/*--------------------------------------------------------------------------*/
/* Local routines                                                           */
/*--------------------------------------------------------------------------*/

int RZ_ReceiveData (byte *, int);
int RZ_32ReceiveData (byte *, int);
int RZ_InitReceiver (void);
int RZ_ReceiveBatch (FILE *);
int RZ_ReceiveFile (FILE *);
int RZ_GetHeader (void);
int RZ_SaveToDisk (long *);
void RZ_AckBibi (void);

/*--------------------------------------------------------------------------*/
/* Private declarations                                                     */
/*--------------------------------------------------------------------------*/

static long DiskAvail;
static long filetime;
static char realname[64];

/*--------------------------------------------------------------------------*/
/* Private data                                                             */
/*--------------------------------------------------------------------------*/

/* Parameters for ZSINIT frame */
#define ZATTNLEN 32

static char Attn[ZATTNLEN + 1];                  /* String rx sends to tx on
                                                  * err            */
static FILE *Outfile;                            /* Handle of file being
                                                  * received           */
static int Tryzhdrtype;                          /* Hdr type to send for Last
                                                  * rx close      */
static char isBinary;                            /* Current file is binary
                                                  * mode             */
static char EOFseen;                             /* indicates cpm eof (^Z)
                                                  * was received     */
static char Zconv;                               /* ZMODEM file conversion
                                                  * request          */
static int RxCount;                              /* Count of data bytes
                                                  * received            */
static char Upload_path[PATHLEN];                /* Dest. path of file being
                                                  * received   */
static long Filestart;                           /* File offset we started
                                                  * this xfer from   */

/*--------------------------------------------------------------------------*/
/* GET ZMODEM                                                               */
/* Receive a batch of files.                                                */
/* returns TRUE (1) for good xfer, FALSE (0) for bad                        */
/* can be called from f_upload or to get mail from a WaZOO Opus             */
/*--------------------------------------------------------------------------*/
int get_Zmodem (char *rcvpath, FILE *xferinfo)
{
   char namebuf[PATHLEN];
   int i;
   char *p;
   char *HoldName;
   long t;

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

   filetime = 0;

   IN_XON_ENABLE ();

/*   Secbuf = NULL;*/
   Outfile = NULL;
   z_size = 0;


   Rxtimeout = 100;
   Tryzhdrtype = ZRINIT;

   (void) strcpy (namebuf, rcvpath);
   Filename = namebuf;

   (void) strcpy (Upload_path, rcvpath);
   p = Upload_path + strlen (Upload_path) - 1;
   while (p >= Upload_path && *p != '\\')
      --p;
   *(++p) = '\0';

   HoldName = HoldAreaNameMunge(&called_addr);

   (void) sprintf (Abortlog_name, "%s%s.Z\0",
            HoldName, Hex_Addr_Str (&remote_addr));

   DiskAvail = zfree (Upload_path);

   if (((i = RZ_InitReceiver ()) == ZCOMPL) ||
       ((i == ZFILE) && ((RZ_ReceiveBatch (xferinfo)) == OK)))
      {
      XON_DISABLE ();
      XON_ENABLE ();                             /* Make sure xmitter is
                                                  * unstuck */
      return 1;
      }

   CLEAR_OUTBOUND ();
   XON_DISABLE ();                               /* Make sure xmitter is
                                                  * unstuck */
   send_can ();                                  /* transmit at least 10 cans    */
   t = timerset (200);                           /* wait no more than 2
                                                  * seconds  */
   while (!timeup (t) && !OUT_EMPTY () && CARRIER)
      time_release ();                           /* Give up slice while
                                                  * waiting  */
   XON_ENABLE ();                                /* Turn XON/XOFF back on...     */
/*
   if (Secbuf)
      free (Secbuf);
*/
   if (Outfile)
      (void) fclose (Outfile);

   return 0;
}                                                /* get_Zmodem */

/*--------------------------------------------------------------------------*/
/* RZ RECEIVE DATA                                                          */
/* Receive array buf of max length with ending ZDLE sequence                */
/* and CRC.  Returns the ending character or error code.                    */
/*--------------------------------------------------------------------------*/
int RZ_ReceiveData (register byte *buf, register int length)
{
   register int c;
   register word crc;
   char *endpos;
   int d;


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

   if (Rxframeind == ZBIN32)
      return RZ_32ReceiveData (buf, length);

   crc = RxCount = 0;
   buf[0] = buf[1] = 0;
   endpos = (char *)buf + length;

   while ((char *)buf <= endpos)
      {
      if ((c = Z_GetZDL ()) & ~0xFF)
         {
   CRCfoo:
         switch (c)
            {
            case GOTCRCE:
            case GOTCRCG:
            case GOTCRCQ:
            case GOTCRCW:
               /*-----------------------------------*/
               /* C R C s                           */
               /*-----------------------------------*/
               crc = Z_UpdateCRC (((d = c) & 0xFF), crc);
               if ((c = Z_GetZDL ()) & ~0xFF)
                  goto CRCfoo;

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

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

               RxCount = length - (int) (endpos - (char *) buf);
               return d;

            case GOTCAN:
               /*-----------------------------------*/
               /* Cancel                            */
               /*-----------------------------------*/
               z_log (MSG_TXT(M_CAN_MSG));
               return ZCAN;

            case TIMEOUT:
               /*-----------------------------------*/
               /* Timeout                           */
               /*-----------------------------------*/
               z_message (MSG_TXT(M_TIMEOUT));
               return c;

            case RCDO:
               /*-----------------------------------*/
               /* No carrier                        */
               /*-----------------------------------*/
               z_log (MSG_TXT(M_NO_CARRIER));
               CLEAR_INBOUND ();
               return c;

            default:
               /*-----------------------------------*/
               /* Something bizarre                 */
               /*-----------------------------------*/
               z_message (MSG_TXT(M_DEBRIS));
               CLEAR_INBOUND ();
               return c;
            }                                    /* switch */
         }                                       /* if */

      *buf++ = (unsigned char) c;
      crc = Z_UpdateCRC (c, crc);
      }                                          /* while(1) */

   z_message (MSG_TXT(M_LONG_PACKET));
   return ERROR;
}                                                /* RZ_ReceiveData */

/*--------------------------------------------------------------------------*/
/* RZ RECEIVE DATA with 32 bit CRC                                          */
/* Receive array buf of max length with ending ZDLE sequence                */
/* and CRC.  Returns the ending character or error code.                    */
/*--------------------------------------------------------------------------*/
int RZ_32ReceiveData (register byte *buf, register int length)
{
   register int c;
   unsigned long crc;
   char *endpos;
   int d;


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

   crc = 0xFFFFFFFF;
   RxCount = 0;
   buf[0] = buf[1] = 0;
   endpos = (char *)buf + length;

   while ((char *)buf <= endpos)
      {
      if ((c = Z_GetZDL ()) & ~0xFF)
         {
   CRCfoo:
         switch (c)
            {
            case GOTCRCE:
            case GOTCRCG:
            case GOTCRCQ:
            case GOTCRCW:
               /*-----------------------------------*/
               /* C R C s                           */
               /*-----------------------------------*/
               d = c;
               c &= 0377;
               crc = Z_32UpdateCRC (c, crc);
               if ((c = Z_GetZDL ()) & ~0xFF)
                  goto CRCfoo;

               crc = Z_32UpdateCRC (c, crc);
               if ((c = Z_GetZDL ()) & ~0xFF)
                  goto CRCfoo;

               crc = Z_32UpdateCRC (c, crc);
               if ((c = Z_GetZDL ()) & ~0xFF)
                  goto CRCfoo;

               crc = Z_32UpdateCRC (c, crc);
               if ((c = Z_GetZDL ()) & ~0xFF)
                  goto CRCfoo;

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

               RxCount = length - (int) (endpos - (char *)buf);
               return d;

            case GOTCAN:
               /*-----------------------------------*/
               /* Cancel                            */
               /*-----------------------------------*/
               z_log (MSG_TXT(M_CAN_MSG));
               return ZCAN;

            case TIMEOUT:
               /*-----------------------------------*/
               /* Timeout                           */
               /*-----------------------------------*/
               z_message (MSG_TXT(M_TIMEOUT));
               return c;

            case RCDO:
               /*-----------------------------------*/
               /* No carrier                        */
               /*-----------------------------------*/
               z_log (MSG_TXT(M_NO_CARRIER));
               CLEAR_INBOUND ();
               return c;

            default:
               /*-----------------------------------*/
               /* Something bizarre                 */
               /*-----------------------------------*/
               z_message (MSG_TXT(M_DEBRIS));
               CLEAR_INBOUND ();
               return c;
            }                                    /* switch */
         }                                       /* if */

      *buf++ = (unsigned char) c;
      crc = Z_32UpdateCRC (c, crc);
      }                                          /* while(1) */

   z_message (MSG_TXT(M_LONG_PACKET));
   return ERROR;
}                                                /* RZ_ReceiveData */

/*--------------------------------------------------------------------------*/
/* RZ INIT RECEIVER                                                         */
/* Initialize for Zmodem receive attempt, try to activate Zmodem sender     */
/* Handles ZSINIT, ZFREECNT, and ZCOMMAND frames                            */
/*                                                                          */
/* Return codes:                                                            */
/*    ZFILE .... Zmodem filename received                                   */
/*    ZCOMPL ... transaction finished                                       */
/*    ERROR .... any other condition                                        */
/*--------------------------------------------------------------------------*/
int RZ_InitReceiver ()
{
   register int n;
   int errors = 0;
   char *sptr;


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

   for (n = 12; --n >= 0;)
      {
      /*--------------------------------------------------------------*/
      /* Set buffer length (0=unlimited, don't wait).                 */
      /* Also set capability flags                                    */
      /*--------------------------------------------------------------*/
      Z_PutLongIntoHeader (0L);
      Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
      Z_SendHexHeader (Tryzhdrtype, (byte *)Txhdr);
      if (Tryzhdrtype == ZSKIP)
         Tryzhdrtype = ZRINIT;

AGAIN:

      switch (Z_GetHeader ((byte *)Rxhdr))
         {
         case ZFILE:
            Zconv = Rxhdr[ZF0];
            Tryzhdrtype = ZRINIT;
            if (RZ_ReceiveData (Secbuf, WAZOOMAX) == GOTCRCW)
               return ZFILE;
            Z_SendHexHeader (ZNAK, (byte *)Txhdr);
            if (--n < 0)
               {
               sptr = "ZFILE";
               goto Err;
               }
            goto AGAIN;

         case ZSINIT:
            if (RZ_ReceiveData ((byte *)Attn, ZATTNLEN) == GOTCRCW)
               {
               Z_PutLongIntoHeader (1L);
               Z_SendHexHeader (ZACK, (byte *)Txhdr);
               }
            else Z_SendHexHeader (ZNAK, (byte *)Txhdr);
            if (--n < 0)
               {
               sptr = "ZSINIT";
               goto Err;
               }
            goto AGAIN;

         case ZFREECNT:
            Z_PutLongIntoHeader (DiskAvail);
            Z_SendHexHeader (ZACK, (byte *)Txhdr);
            goto AGAIN;

         case ZCOMMAND:
            /*-----------------------------------------*/
            /* Paranoia is good for you...             */
            /* Ignore command from remote, but lie and */
            /* say we did the command ok.              */
            /*-----------------------------------------*/
            if (RZ_ReceiveData (Secbuf, WAZOOMAX) == GOTCRCW)
               {
               status_line (MSG_TXT(M_Z_IGNORING), Secbuf);
               Z_PutLongIntoHeader (0L);
               do
                  {
                  Z_SendHexHeader (ZCOMPL, (byte *)Txhdr);
                  }
               while (++errors < 10 && Z_GetHeader ((byte *)Rxhdr) != ZFIN);
               RZ_AckBibi ();
               return ZCOMPL;
               }
            else Z_SendHexHeader (ZNAK, (byte *)Txhdr);
            if (--n < 0)
               {
               sptr = "CMD";
               goto Err;
               }
            goto AGAIN;

         case ZCOMPL:
            if (--n < 0)
               {
               sptr = "COMPL";
               goto Err;
               }
            goto AGAIN;

         case ZFIN:
            RZ_AckBibi ();
            return ZCOMPL;

         case ZCAN:
            sptr = MSG_TXT(M_CAN_MSG);
            goto Err;

         case RCDO:
            sptr = &(MSG_TXT(M_NO_CARRIER)[1]);
            CLEAR_INBOUND ();
            goto Err;
         }                                       /* switch */
      }                                          /* for */

   sptr = MSG_TXT(M_TIMEOUT);

Err:
   (void) sprintf (e_input, MSG_TXT(M_Z_INITRECV), sptr);
   z_log (e_input);

   return ERROR;
}                                                /* RZ_InitReceiver */

/*--------------------------------------------------------------------------*/
/* RZFILES                                                                  */
/* Receive a batch of files using ZMODEM protocol                           */
/*--------------------------------------------------------------------------*/
int RZ_ReceiveBatch (FILE *xferinfo)
{
   register int c;
   char namebuf[PATHLEN];


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

   for (;;)
      {
      switch (c = RZ_ReceiveFile (xferinfo))
         {
         case ZEOF:
            if (Resume_WaZOO)
               {
               remove_abort (Abortlog_name, Resume_name);
               (void) strcpy (namebuf, Upload_path);
               (void) strcat (namebuf, Resume_name);
               unique_name (namebuf);
               (void) rename (Filename, namebuf);
               }
            /* fallthrough */
         case ZSKIP:
            switch (RZ_InitReceiver ())
               {
               case ZCOMPL:
                  return OK;
               default:
                  return ERROR;
               case ZFILE:
                  break;
               }                                 /* switch */
            break;

         default:
            (void) fclose (Outfile);
            Outfile = NULL;
            if (remote_capabilities)
               {
               if (!Resume_WaZOO)
                  {
                  add_abort (Abortlog_name, Resume_name, Filename, Upload_path, Resume_info);
                  }
               }
            else (void) unlink (Filename);
            return c;
         }                                       /* switch */
      }                                          /* while */
}                                                /* RZ_ReceiveBatch */

/*--------------------------------------------------------------------------*/
/* RZ RECEIVE FILE                                                          */
/* Receive one file; assumes file name frame is preloaded in Secbuf         */
/*--------------------------------------------------------------------------*/
int RZ_ReceiveFile (FILE *xferinfo)
{
   register int c;
   int n;
   long rxbytes;
   char *sptr;
   struct utimbuf utimes;
   char j[50];


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

   EOFseen = FALSE;
   c = RZ_GetHeader ();
   if (c == ERROR || c == ZSKIP)
      return (Tryzhdrtype = ZSKIP);

   n = 10;
   rxbytes = Filestart;

   for (;;)
      {
      Z_PutLongIntoHeader (rxbytes);
      Z_SendHexHeader (ZRPOS, (byte *)Txhdr);
NxtHdr:
      switch (c = Z_GetHeader ((byte *)Rxhdr))
         {
         case ZDATA:
            /*-----------------------------------------*/
            /* Data Packet                             */
            /*-----------------------------------------*/
            if (Rxpos != rxbytes)
               {
               if (--n < 0)
                  {
                  sptr = MSG_TXT(M_FUBAR_MSG);
                  goto Err;
                  }
               (void) sprintf (j, "%s; %ld/%ld", MSG_TXT(M_BAD_POS), rxbytes, Rxpos);
               z_message (j);
               Z_PutString ((byte *)Attn);
               continue;
               }
      MoreData:
            switch (c = RZ_ReceiveData (Secbuf, WAZOOMAX))
               {
               case ZCAN:
                  sptr = MSG_TXT(M_CAN_MSG);
                  goto Err;

               case RCDO:
                  sptr = &(MSG_TXT(M_NO_CARRIER)[1]);
                  CLEAR_INBOUND ();
                  goto Err;

               case ERROR:
                  /*-----------------------*/
                  /* CRC error             */
                  /*-----------------------*/
                  if (--n < 0)
                     {
                     sptr = MSG_TXT(M_FUBAR_MSG);
                     goto Err;
                     }
                  show_loc (rxbytes, n);
                  Z_PutString ((byte *)Attn);
                  continue;

               case TIMEOUT:
                  if (--n < 0)
                     {
                     sptr = MSG_TXT(M_TIMEOUT);
                     goto Err;
                     }
                  show_loc (rxbytes, n);
                  continue;

               case GOTCRCW:
                  /*---------------------*/
                  /* End of frame          */
                  /*-----------------------*/
                  n = 10;
                  if (RZ_SaveToDisk (&rxbytes) == ERROR)
                     return ERROR;
                  Z_PutLongIntoHeader (rxbytes);
                  Z_SendHexHeader (ZACK, (byte *)Txhdr);
                  goto NxtHdr;

               case GOTCRCQ:
                  /*---------------------*/
                  /* Zack expected         */
                  /*-----------------------*/
                  n = 10;
                  if (RZ_SaveToDisk (&rxbytes) == ERROR)
                     return ERROR;
                  Z_PutLongIntoHeader (rxbytes);
                  Z_SendHexHeader (ZACK, (byte *)Txhdr);
                  goto MoreData;

               case GOTCRCG:
                  /*---------------------*/
                  /* Non-stop              */
                  /*-----------------------*/
                  n = 10;
                  if (RZ_SaveToDisk (&rxbytes) == ERROR)
                     return ERROR;
                  goto MoreData;

               case GOTCRCE:
                  /*---------------------*/
                  /* Header to follow      */
                  /*-----------------------*/
                  n = 10;
                  if (RZ_SaveToDisk (&rxbytes) == ERROR)
                     return ERROR;
                  goto NxtHdr;
               }                                 /* switch */

         case ZNAK:
         case TIMEOUT:
            /*-----------------------------------------*/
            /* Packet was probably garbled             */
            /*-----------------------------------------*/
            if (--n < 0)
               {
               sptr = MSG_TXT(M_JUNK_BLOCK);
               goto Err;
               }
            show_loc (rxbytes, n);
            continue;

         case ZFILE:
            /*-----------------------------------------*/
            /* Sender didn't see our ZRPOS yet         */
            /*-----------------------------------------*/
            (void) RZ_ReceiveData (Secbuf, WAZOOMAX);
            continue;

         case ZEOF:
            /*-----------------------------------------*/
            /* End of the file                         */
            /* Ignore EOF if it's at wrong place; force */
            /* a timeout because the eof might have    */
            /* gone out before we sent our ZRPOS       */
            /*-----------------------------------------*/
            if (locate_y && !(fullscreen && un_attended))
               gotoxy (2, (byte) locate_y - 1);
            if (Rxpos != rxbytes)
               goto NxtHdr;

            throughput (2, rxbytes - Filestart);

            (void) fclose (Outfile);

            status_line ("%s-Z%s %s", MSG_TXT(M_FILE_RECEIVED), Crc32 ? "/32" : "", realname);

            update_files (0);

            if (filetime)
               {
               utimes.UT_ACTIME = filetime;
               utimes.modtime = filetime;
               (void) utime (Filename, (UTIMBUF *)&utimes);
               }

            Outfile = NULL;
            if (xferinfo != NULL)
               {
               (void) fprintf (xferinfo, "%s\n", Filename);
               }
            return c;

         case ERROR:
            /*-----------------------------------------*/
            /* Too much garbage in header search error */
            /*-----------------------------------------*/
            if (--n < 0)
               {
               sptr = MSG_TXT(M_JUNK_BLOCK);
               goto Err;
               }
            show_loc (rxbytes, n);
            Z_PutString ((byte *)Attn);
            continue;

         case ZSKIP:
            return c;

         default:
            sptr = IDUNNO_msg;
            CLEAR_INBOUND ();
            goto Err;
         }                                       /* switch */
      }                                          /* while */

Err:
   (void) sprintf (e_input, MSG_TXT(M_Z_RZ), sptr);
   z_log (e_input);
   return ERROR;
}                                                /* RZ_ReceiveFile */

/*--------------------------------------------------------------------------*/
/* RZ GET HEADER                                                            */
/* Process incoming file information header                                 */
/*--------------------------------------------------------------------------*/
int RZ_GetHeader ()
{
   register byte *p;
   struct stat f;
   int i;
   char *ourname;
   char *theirname;
   long filesize;
   char *fileinfo;
   char j[80];


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

   /*--------------------------------------------------------------------*/
   /* Setup the transfer mode                                            */
   /*--------------------------------------------------------------------*/
   isBinary = (char) ((!RXBINARY && Zconv == ZCNL) ? 0 : 1);
   Resume_WaZOO = 0;

   /*--------------------------------------------------------------------*/
   /* Extract and verify filesize, if given.                             */
   /* Reject file if not at least 10K free                               */
   /*--------------------------------------------------------------------*/
   filesize = 0L;
   filetime = 0L;
   fileinfo = (char *)Secbuf + 1 + strlen ((char *)Secbuf);
   if (*fileinfo)
      (void) sscanf (fileinfo, "%ld %lo", &filesize, &filetime);
   if (filesize + 10240 > DiskAvail)
      {
      status_line (MSG_TXT(M_OUT_OF_DISK_SPACE));
      return ERROR;
      }

   /*--------------------------------------------------------------------*/
   /* Get and/or fix filename for uploaded file                          */
   /*--------------------------------------------------------------------*/
   p = (byte *)(Filename + strlen (Filename) - 1);/* Find end of upload path */
   while ((char *)p >= Filename && *p != '\\')
      p--;
   ourname = (char *)++p;

   p = Secbuf + strlen ((char *)Secbuf) - 1;     /* Find transmitted simple
                                                  * filename */
   while (p >= Secbuf && *p != '\\' && *p != '/' && *p != ':')
      p--;
   theirname = (char *)++p;

   (void) strcpy (ourname, theirname);           /* Start w/ our path & their
                                                  * name */
   (void) strcpy (realname, Filename);

   /*--------------------------------------------------------------------*/
   /* Save info on WaZOO transfer in case of abort                       */
   /*--------------------------------------------------------------------*/
   if (remote_capabilities)
      {
      (void) strcpy (Resume_name, theirname);
      (void) sprintf (Resume_info, "%ld %lo", filesize, filetime);
      }

   /*--------------------------------------------------------------------*/
   /* Check if this is a failed WaZOO transfer which should be resumed   */
   /*--------------------------------------------------------------------*/
   if (remote_capabilities && dexists (Abortlog_name))
      {
      Resume_WaZOO = (byte) check_failed (Abortlog_name, theirname, Resume_info, ourname);
      }

   /*--------------------------------------------------------------------*/
   /* Open either the old or a new file, as appropriate                  */
   /*--------------------------------------------------------------------*/
   if (Resume_WaZOO)
      {
      if (dexists (Filename))
         p = (byte *)"r+b";
      else p = (byte *)write_binary;
      }
   else
      {
      (void) strcpy (ourname, theirname);
      /*--------------------------------------------------------------------*/
      /* If the file already exists:                                        */
      /* 1) And the new file has the same time and size, return ZSKIP    */
      /* 2) And OVERWRITE is turned on, delete the old copy              */
      /* 3) Else create a unique file name in which to store new data    */
      /*--------------------------------------------------------------------*/
      if (dexists (Filename))
         {                                       /* If file already exists...      */
         if ((Outfile = fopen (Filename, read_binary)) == NULL)
            {
            (void) got_error (MSG_TXT(M_OPEN_MSG), Filename);
            return ERROR;
            }
         (void) fstat (fileno (Outfile), &f);
         (void) fclose (Outfile);
         if (filesize == f.st_size && filetime == f.st_mtime)
            {
            status_line (MSG_TXT(M_ALREADY_HAVE), Filename);
            return ZSKIP;
            }
         i = strlen (Filename) - 1;
         if ((!overwrite) || (is_arcmail (Filename, i)))
            {
            unique_name (Filename);
            }
         else
            {
            (void) unlink (Filename);
            }
         }                                       /* if exist */

      if (strcmp (ourname, theirname))
         {
         status_line (MSG_TXT(M_RENAME_MSG), ourname);
         }
      p = (byte *)write_binary;
      }
   if ((Outfile = fopen (Filename, (char *)p)) == NULL)
      {
      (void) got_error (MSG_TXT(M_OPEN_MSG), Filename);
      return ERROR;
      }
   if (isatty (fileno (Outfile)))
      {
      errno = 1;
      (void) got_error (MSG_TXT(M_DEVICE_MSG), Filename);
      (void) fclose (Outfile);
      return (ERROR);
      }

   Filestart = (Resume_WaZOO) ? filelength (fileno (Outfile)) : 0L;
   if (Resume_WaZOO)
      status_line (MSG_TXT(M_SYNCHRONIZING_OFFSET), Filestart);
   (void) fseek (Outfile, Filestart, SEEK_SET);

   if (remote_capabilities)
        p = (byte *)check_netfile(theirname);
   else p = NULL;

   (void) sprintf (j, "%s %s; %s%ldb, %d min.",
            (p != NULL) ? (char *)p : MSG_TXT(M_RECEIVING),
            realname,
            (isBinary) ? "" : "ASCII ",
            filesize,
            (int) ((filesize - Filestart) * 10 / cur_baud.rate_value + 53) / 54);

   file_length = filesize;

   if (un_attended && fullscreen)
      {
      clear_filetransfer ();
      sb_move (file_hWnd, 1, 2);
      FlLnModeSet( FILE_LN_2, 1 );
      sb_puts( GetDlgItem( file_hWnd, FILE_LN_1 ), j );
      elapse_time ();
      i = (int) (filesize * 10 / cur_baud.rate_value + 53) / 54;

      (void) sprintf(j, "%3d min", i);
      sb_move (file_hWnd, 2, 69);
      FlLnModeSet( FILE_LN_2, 1 );
      sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_DTTM ), j );
      sb_show ();
      }
   else
      {
      set_xy (j);
      set_xy (NULL);
      locate_x += 2;
      }

   throughput (0, 0L);

   return OK;
}                                                /* RZ_GetHeader */

/*--------------------------------------------------------------------------*/
/* RZ SAVE TO DISK                                                          */
/* Writes the received file data to the output file.                        */
/* If in ASCII mode, stops writing at first ^Z, and converts all            */
/*   solo CR's or LF's to CR/LF pairs.                                      */
/*--------------------------------------------------------------------------*/
int RZ_SaveToDisk (long *rxbytes)
{
   static byte lastsent;

   register byte *p;
   register unsigned int count;
   int i;
   char j[100];

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

   count = RxCount;

   if (got_ESC ())
      {
      send_can ();                               /* Cancel file */
      while ((i = Z_GetByte (20)) != TIMEOUT && i != RCDO)      /* Wait for line to
                                                                 * clear */
         CLEAR_INBOUND ();
      send_can ();                               /* and Cancel Batch */
      z_log (MSG_TXT(M_KBD_MSG));
      return ERROR;
      }

   if (count != z_size)
      {
      if (fullscreen && un_attended)
         {
         sb_move (file_hWnd, 2, 12);
         sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_SIZE ),
                  ultoa (((unsigned long) (z_size = count)), e_input, 10));
#ifndef MILQ
         sb_puts (file_hWnd, "    ");
#endif
         elapse_time ();
         sb_show ();
         }
      else
         {
         gotoxy (locate_x + 10, locate_y);
         (void) cputs (ultoa (((unsigned long) (z_size = count)), e_input, 10));
         (void) putch (' ');
         }
      }

   if (isBinary)
      {
      if (fwrite (Secbuf, 1, count, Outfile) != count)
         goto oops;
      }
   else
      {
      if (EOFseen)
         return OK;
      for (p = Secbuf; count > 0; count--)
         {
         if (*p == CPMEOF)
            {
            EOFseen = TRUE;
            return OK;
            }

         if (*p == '\n')
            {
            if (lastsent != '\r' && putc ('\r', Outfile) == EOF)
               goto oops;
            }
         else
            {
            if (lastsent == '\r' && putc ('\n', Outfile) == EOF)
               goto oops;
            }

         if (putc ((lastsent = *p++), Outfile) == EOF)
            goto oops;
         }
      }

   *rxbytes += RxCount;
   i = (int) ((file_length - *rxbytes)* 10 / cur_baud.rate_value + 53) / 54;
   (void) sprintf (j, "%3d min", i);


   if (fullscreen && un_attended)
      {
      elapse_time();
      sb_move (file_hWnd, 2, 2);
      sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_TOTAL ),
               ultoa (((unsigned long) (*rxbytes)), e_input, 10));
      sb_move (file_hWnd, 2, 69);
      sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_DTTM ), j );
      elapse_time ();
      sb_show ();
      }
   else
      {
      gotoxy (locate_x, locate_y);
      (void) cputs (ultoa (((unsigned long) (*rxbytes)), e_input, 10));
      gotoxy (locate_x + 20, locate_y);
      (void) printf ("%s", j);
      (void) putch (' ');
      }
   return OK;

oops:
   (void) got_error (MSG_TXT(M_WRITE_MSG), Filename);
   return ERROR;

}                                                /* RZ_SaveToDisk */

/*--------------------------------------------------------------------------*/
/* RZ ACK BIBI                                                              */
/* Ack a ZFIN packet, let byegones be byegones                              */
/*--------------------------------------------------------------------------*/
void RZ_AckBibi ()
{
   register int n;


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

   Z_PutLongIntoHeader (0L);
   for (n = 4; --n;)
      {
      Z_SendHexHeader (ZFIN, (byte *)Txhdr);
      switch (Z_GetByte (100))
         {
         case 'O':
            (void) Z_GetByte (1);                /* Discard 2nd 'O' */

         case TIMEOUT:
         case RCDO:
            return;
         }                                       /* switch */
      }                                          /* for */
}                                                /* RZ_AckBibi */