www.pudn.com > zmodem.zip > ZSEND.C


/*--------------------------------------------------------------------------*/ 
/* FILE: zsend.c    (Opus zmodem transmitter)                               */ 
/*                                                                          */ 
/*                                                                          */ 
/*               The Opus Computer-Based Conversation System                */ 
/*       (c) Copyright 1986, Wynn Wagner III, All Rights Reserved           */ 
/*                                                                          */ 
/*      This implementation of Chuck Forsberg's ZMODEM protocol was         */ 
/*              for Opus by Rick Huebner and Wynn Wagner III                */ 
/*                                                                          */ 
/* (MSC/4 with /Zp /Ox)                                                     */ 
/*                                                                          */ 
/*                                                                          */ 
/*                                                                          */ 
/*                                                                          */ 
/*  This module is similar to a routine used by Opus-Cbcs (1.00).  It is    */ 
/*  provided for your information only.  You will find routines that need   */ 
/*  to be coded and identifiers to be resolved.                             */ 
/*                                                                          */ 
/*  There is absolutely no guarantee that anything here will work.  If you  */ 
/*  break this routine, you own both pieces.                                */ 
/*                                                                          */ 
/*  USAGE:  You may use this material in any program with no obligation     */ 
/*          as long as there is no charge for your program.  For more       */ 
/*          information about commercial use, contact the "OPUSinfo HERE"   */ 
/*          BBS (124/111).                                                  */ 
/*                                                                          */ 
/*  NOTE:   There are a couple of things the Opus implementation does that  */ 
/*          aren't part of the original ZModem protocol.  They all deal     */ 
/*          with WaZOO type ("ZedZap") netmail and should only show up when */ 
/*          used under that condition.                                      */ 
/*                                                                          */ 
/*             * The maximum packet size can grow larger than 1k.  It is    */ 
/*               sensitive to the baud rate.  (2400b=2048k; 9600b=8192k)    */ 
/*             * The sender must be able to send nothing.  In other words,  */ 
/*               the sending system must be able to initiate and terminate  */ 
/*               a zmodem send session without having to actually send a    */ 
/*               file.  Normally this kind of thing would never happen in   */ 
/*               zmodem.                                                    */ 
/*                                                                          */ 
/*                                                                          */ 
/*--------------------------------------------------------------------------*/ 
 
#include "zmodem.h" 
 
 
/*--------------------------------------------------------------------------*/ 
/* Global routines                                                          */ 
/*--------------------------------------------------------------------------*/ 
int cdecl send_Zmodem(byte *,byte *,int,int,int); 
 
 
/*--------------------------------------------------------------------------*/ 
/* Private routines                                                         */ 
/*--------------------------------------------------------------------------*/ 
static void pascal ZS_SendBinaryHeader(unsigned short ,byte *); 
static void pascal ZS_SendData(byte *,int,unsigned short); 
static void pascal ZS_SendByte(byte); 
static int  pascal ZS_GetReceiverInfo(void); 
static int  pascal ZS_SendFile(int,int); 
static int  pascal ZS_SendFileData(int); 
static int  pascal ZS_SyncWithReceiver(void); 
static void pascal ZS_EndSend(void); 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* Private data                                                             */ 
/*--------------------------------------------------------------------------*/ 
static FILE *Infile;             /* Handle of file being sent               */ 
static byte *Txbuf;              /* Pointer to transmit buffer              */ 
static long  Strtpos;            /* Starting byte position of download      */ 
static long  Txpos;              /* Transmitted file position               */ 
static int Rxbuflen;             /* Receiver's max buffer length            */ 
 
 
/*--------------------------------------------------------------------------*/ 
/* External data not otherwise declared                                     */ 
/*--------------------------------------------------------------------------*/ 
extern char *FLAGGING_msg; 
extern char *NOTSENT_msg; 
extern char *TRUNC_msg; 
extern char *KBD_msg; 
 
 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* SEND ZMODEM (send a file)                                                */ 
/*   returns TRUE (1) for good xfer, FALSE (0) for bad                      */ 
/*   sends one file per call; 'fsent' flags start and end of batch          */ 
/*--------------------------------------------------------------------------*/ 
int cdecl send_Zmodem(fname,alias,doafter,fsent,wazoo) 
   byte  *fname; 
   byte  *alias; 
   int   doafter; 
   int   fsent; 
   int   wazoo; 
   begin 
      register byte *p; 
      register byte *q; 
      struct stat    f; 
 
      int   i; 
      int   rc; 
 
 
      _BRK_DISABLE(); 
      XON_ENABLE(); 
 
      errno    = 
      z_size   = 0; 
      Infile   = NULL; 
      Txbuf    = NULL; 
 
 
 
      if (fname) set_xy(""); 
 
      switch(fsent) 
         begin 
            case 0: 
            case NOTHING_TO_DO:  n_disable(); 
                                 if (!wazoo) 
                                    begin 
                                       Z_PutString("rz\r"); 
                                       Z_PutLongIntoHeader(0L); 
                                       Z_SendHexHeader(ZRQINIT, Txhdr); 
                                    end 
                                 Rxtimeout   = 20; 
                                 if (ZS_GetReceiverInfo() == ERROR) return FALSE; 
         end 
 
 
      Rxtimeout   = (int )(614400L/(long )cur_baud); 
      Rxtimeout  /= 10; 
 
      if (Rxtimeout < 10) Rxtimeout = 10; 
      if (Rxtimeout > 58) Rxtimeout = 58; 
 
 
      if (fname == NULL) goto Done; 
 
      /*--------------------------------------------------------------------*/ 
      /* Prepare the file for transmission.  Just ignore file open errors   */ 
      /* because there may be other files that can be sent.                 */ 
      /*--------------------------------------------------------------------*/ 
      Filename = fname; 
      CLEAR_IOERR(); 
      Infile   = fopen(Filename,read_binary); 
      if (had_error(OPEN_msg,Filename)) return OK; 
       
      Txbuf    = zalloc(); 
 
      /*--------------------------------------------------------------------*/ 
      /* Send the file                                                      */ 
      /*--------------------------------------------------------------------*/ 
      rc       = TRUE; 
 
 
      /*--------------------------------------------------------------------*/ 
      /* Display outbound filename, size, and ETA for sysop                 */ 
      /*--------------------------------------------------------------------*/ 
      fstat(fileno(Infile), &f); 
 
      message(NULL); 
      cprintf( "Z-Send %s, %ldb",Filename,f.st_size); 
 
      i  = (int)(f.st_size*10/cur_baud+27)/54; 
      if (i) cprintf(", %d min.",i); 
 
      set_xy(NULL); 
 
      /*--------------------------------------------------------------------*/ 
      /* Get outgoing file name; no directory path, lower case              */ 
      /*--------------------------------------------------------------------*/ 
      for (p=(alias!=NULL)?alias:Filename, q=Txbuf ; *p; ) 
         begin 
            if ((*q++ = tolower(*p)) == '\\') q = Txbuf; 
            p++; 
         end 
 
      *q++  = '\0'; 
      p     = q; 
 
      /*--------------------------------------------------------------------*/ 
      /* Zero out remainder of file header packet                           */ 
      /*--------------------------------------------------------------------*/ 
      while (q < (Txbuf + KSIZE)) *q++ = '\0'; 
 
      /*--------------------------------------------------------------------*/ 
      /* Store filesize, time last modified, and file mode in header packet */ 
      /*--------------------------------------------------------------------*/ 
      sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode); 
 
      /*--------------------------------------------------------------------*/ 
      /* Transmit the filename block and begin the download                 */ 
      /*--------------------------------------------------------------------*/ 
      throughput(0,0L); 
 
 
      /*--------------------------------------------------------------------*/ 
      /* Check the results                                                  */ 
      /*--------------------------------------------------------------------*/ 
      switch( ZS_SendFile(1+strlen(p)+(p-Txbuf), wazoo) ) 
         begin 
 
            case ERROR: /*--------------------------------------------------*/ 
                        /* Something tragic happened                        */ 
                        /*--------------------------------------------------*/ 
                        if (wazoo) 
                           begin 
                              status_line( NOTSENT_msg ); 
                              mdm_hangup(); 
                           end 
                        goto Err_Out; 
 
 
            case OK:    /*--------------------------------------------------*/ 
                        /* File was sent                                    */ 
                        /*--------------------------------------------------*/ 
                        CLEAR_IOERR(); 
                        fclose(Infile); 
                        had_error(CLOSE_msg,Filename); 
                        Infile   = NULL; 
 
                        status_line( "=DL %s", Filename ); 
 
                        /*--------------------------------------------------*/ 
                        /* Special WaZOO file handling following a          */ 
                        /* successful transmission.                         */ 
                        /*--------------------------------------------------*/ 
                        switch(doafter) 
                           begin 
                              case DELETE_AFTER:   /*-----------------------*/ 
                                                   /* Delete File           */ 
                                                   /*-----------------------*/ 
                                                   CLEAR_IOERR(); 
                                                   unlink(Filename); 
                                                   had_error(UNLINK_msg,Filename); 
                                                   break; 
    
                              case TRUNC_AFTER:    /*-----------------------*/ 
                                                   /* Truncate File         */ 
                                                   /*-----------------------*/ 
                                                   CLEAR_IOERR(); 
                                                   i = open(Filename,O_TRUNC,S_IWRITE); 
                                                   had_error( TRUNC_msg, Filename ); 
                                                   status_line(FLAGGING_msg,Filename); 
                                                   close(i); 
                                                   break; 
                           end /* switch */ 
 
 
            default:    /*--------------------------------------------------*/ 
                        /* Probably a ZSKIP                                 */ 
                        /*--------------------------------------------------*/ 
                        goto Done; 
 
         end /* switch */ 
 
Err_Out: 
      rc = FALSE; 
 
Done: 
      if (Infile) fclose(Infile); 
      if (Txbuf)  free(Txbuf); 
 
      if (fsent < 0) ZS_EndSend(); 
 
      return rc; 
 
   end /* send_Zmodem */ 
 
 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS SEND BINARY HEADER                                                    */ 
/* Send ZMODEM binary header hdr of type type                               */ 
/*--------------------------------------------------------------------------*/ 
static void pascal ZS_SendBinaryHeader(type, hdr) 
   unsigned short type; 
   byte          *hdr; 
   begin 
      register byte          *hptr; 
      register unsigned short crc; 
      int                     n; 
 
      SENDBYTE(ZPAD); 
      SENDBYTE(ZDLE); 
 
      SENDBYTE(ZBIN); 
      ZS_SendByte(type); 
 
      crc = Z_UpdateCRC(type, 0); 
 
      hptr  = hdr; 
      for (n=4; --n >= 0;) 
         begin 
            ZS_SendByte(*hptr); 
            crc = Z_UpdateCRC(((unsigned short)(*hptr++)), crc); 
         end 
 
      crc = Z_UpdateCRC(0,crc); 
      crc = Z_UpdateCRC(0,crc); 
 
      ZS_SendByte(crc>>8); 
      ZS_SendByte(crc); 
 
      if (type != ZDATA) wait_for_clear(); 
 
   end /* ZS_SendBinaryHeader */ 
 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS SEND DATA                                                             */ 
/* Send binary array buf with ending ZDLE sequence frameend                 */ 
/*--------------------------------------------------------------------------*/ 
static void pascal ZS_SendData(buf, length, frameend) 
   byte          *buf; 
   int            length; 
   unsigned short frameend; 
   begin 
 
      register unsigned short crc; 
      int                     t; 
 
      crc = 0; 
      for (;--length >= 0;) 
         begin 
            ZS_SendByte(*buf); 
            crc = Z_UpdateCRC(((unsigned short)(*buf++)), crc); 
         end 
 
      SENDBYTE(ZDLE); 
      SENDBYTE(frameend); 
      crc = Z_UpdateCRC(frameend, crc); 
 
      crc = Z_UpdateCRC(0,crc); 
      crc = Z_UpdateCRC(0,crc); 
      ZS_SendByte(crc>>8); 
      ZS_SendByte(crc); 
 
      if (frameend == ZCRCW) 
         begin 
            SENDBYTE(XON); 
            wait_for_clear(); 
         end 
 
   end /* ZS_SendData */ 
 
 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS SEND BYTE                                                             */ 
/* Send character c with ZMODEM escape sequence encoding.                   */ 
/* Escape XON, XOFF. Escape CR following @ (Telenet net escape)             */ 
/*--------------------------------------------------------------------------*/ 
static void pascal ZS_SendByte(c) 
   register byte c; 
   begin 
      static byte lastsent; 
 
      switch (c) 
         begin 
            case 015: 
            case 0215:  /*--------------------------------------------------*/ 
                        /*                                                  */ 
                        /*--------------------------------------------------*/ 
                        if ((lastsent & 0x7F) != '@') goto SendIt; 
            case 020: 
            case 021: 
            case 023: 
            case 0220: 
            case 0221: 
            case 0223: 
            case ZDLE:  /*--------------------------------------------------*/ 
                        /* Quoted characters                                */ 
                        /*--------------------------------------------------*/ 
                        SENDBYTE(ZDLE); 
                        c ^= 0x40; 
 
            default:    /*--------------------------------------------------*/ 
                        /* Normal character output                          */ 
SendIt:                 /*--------------------------------------------------*/ 
                        SENDBYTE(lastsent = c); 
 
         end /* switch */ 
 
   end /* ZS_SendByte */ 
 
 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS GET RECEIVER INFO                                                     */ 
/* Get the receiver's init parameters                                       */ 
/*--------------------------------------------------------------------------*/ 
static int pascal ZS_GetReceiverInfo() 
   begin 
      int   n; 
      int   rxflags; 
 
      for (n=10; --n>=0; ) 
         begin 
 
            switch ( Z_GetHeader(Rxhdr) ) 
               begin 
                  case ZCHALLENGE:  /*--------------------------------------*/ 
                                    /* Echo receiver's challenge number     */ 
                                    /*--------------------------------------*/ 
                                    Z_PutLongIntoHeader(Rxpos); 
                                    Z_SendHexHeader(ZACK, Txhdr); 
                                    continue; 
 
                  case ZCOMMAND:    /*--------------------------------------*/ 
                                    /* They didn't see our ZRQINIT          */ 
                                    /*--------------------------------------*/ 
                                    Z_PutLongIntoHeader(0L); 
                                    Z_SendHexHeader(ZRQINIT, Txhdr); 
                                    continue; 
 
                  case ZRINIT:      /*--------------------------------------*/ 
                                    /*                                      */ 
                                    /*--------------------------------------*/ 
                                    Rxbuflen = ((word )Rxhdr[ZP1]<<8)|Rxhdr[ZP0]; 
                                    return OK; 
 
                  case ZCAN: 
                  case RCDO: 
                  case TIMEOUT:     /*--------------------------------------*/ 
                                    /*                                      */ 
                                    /*--------------------------------------*/ 
                                    return ERROR; 
 
                  case ZRQINIT:     /*--------------------------------------*/ 
                                    /*                                      */ 
                                    /*--------------------------------------*/ 
                                    if (Rxhdr[ZF0] == ZCOMMAND) continue; 
 
                  default:          /*--------------------------------------*/ 
                                    /*                                      */ 
                                    /*--------------------------------------*/ 
                                    Z_SendHexHeader(ZNAK, Txhdr); 
                                    continue; 
               end /* switch */ 
 
         end /* for */ 
 
      return ERROR; 
 
   end /* ZS_GetReceiverInfo */ 
 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS SEND FILE                                                             */ 
/* Send ZFILE frame and begin sending ZDATA frame                           */ 
/*--------------------------------------------------------------------------*/ 
static int pascal ZS_SendFile(blen, wazoo) 
   int blen; 
   int wazoo; 
   begin 
      register int c; 
 
      while(1) 
 
         begin 
 
            if (((KEYPRESS()) and (READKB()==27))) 
               begin 
                  send_can(); 
                  z_log( KBD_msg ); 
                  return ERROR; 
               end 
            else if (!CARRIER) return ERROR; 
 
    
            Txhdr[ZF0] = LZCONV;    /* Default file conversion mode */ 
            Txhdr[ZF1] = LZMANAG;   /* Default file management mode */ 
            Txhdr[ZF2] = LZTRANS;   /* Default file transport mode */ 
            Txhdr[ZF3] = 0; 
            ZS_SendBinaryHeader(ZFILE, Txhdr); 
            ZS_SendData(Txbuf, blen, ZCRCW); 
    
Again: 
            switch (c = Z_GetHeader(Rxhdr)) 
               begin 
 
                  case ZRINIT:   /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 goto Again; 
 
                  case ZCAN:      
                  case ZCRC:      
                  case RCDO:      
                  case TIMEOUT:   
                  case ZFIN: 
                  case ZABORT:    
                                 /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 return ERROR; 
    
                  case ZSKIP:    /*-----------------------------------------*/ 
                                 /* Other system wants to skip this file    */ 
                                 /*-----------------------------------------*/ 
                                 return c; 
    
                  case ZRPOS:    /*-----------------------------------------*/ 
                                 /* Resend from this position...            */ 
                                 /*-----------------------------------------*/ 
                                 fseek(Infile, Rxpos, SEEK_SET); 
                                 Strtpos = Txpos = Rxpos; 
                                 CLEAR_INBOUND(); 
                                 return ZS_SendFileData(wazoo); 
               end /* switch */ 
 
         end /* while */ 
 
   end /* ZS_SendFile */ 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS SEND FILE DATA                                                        */ 
/* Send the data in the file                                                */ 
/*--------------------------------------------------------------------------*/ 
static int pascal ZS_SendFileData(wazoo) 
   int wazoo; 
   begin 
 
      register int c, e; 
      word         newcnt, blklen, maxblklen, goodblks, goodneeded = 1; 
      byte        *p; 
 
 
      maxblklen = (cur_baud<300) ? 128 : cur_baud/300*256; 
 
      if (maxblklen>WAZOOMAX)              maxblklen = WAZOOMAX; 
      if (!wazoo && maxblklen>KSIZE)       maxblklen = KSIZE; 
      if (Rxbuflen && maxblklen>Rxbuflen)  maxblklen = Rxbuflen; 
      blklen = maxblklen; 
 
 
SomeMore: 
 
      if (CHAR_AVAIL()) 
         begin 
WaitAck: 
 
            switch (c = ZS_SyncWithReceiver()) 
               begin 
                  default:       /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 z_log(Cancelled_msg); 
                                 errno = 0; 
                                 fclose(Infile); 
                                 had_error(CLOSE_msg,Filename); 
                                 return ERROR; 
 
                  case ZSKIP:    /*-----------------------------------------*/ 
                                 /* Skip this file                          */ 
                                 /*-----------------------------------------*/ 
                                 return c; 
 
                  case ZACK:     /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 break; 
 
                  case ZRPOS:    /*-----------------------------------------*/ 
                                 /* Resume at this position                 */ 
                                 /*-----------------------------------------*/ 
                                 blklen = (blklen>>2 > 64) ? blklen>>2 : 64; 
                                 goodblks = 0; 
                                 goodneeded = (goodneeded<<1) | 1; 
                                 break; 
 
                  case ZRINIT:   /*-----------------------------------------*/ 
                                 /* Receive init                            */ 
                                 /*-----------------------------------------*/ 
                                 throughput(1,Txpos-Strtpos); 
                                 return OK; 
               end /* switch */ 
 
            while (CHAR_AVAIL()) 
               begin 
                  switch (MODEM_IN()) 
                     begin 
                        case CAN: 
                        case RCDO: 
                        case ZPAD:  goto WaitAck; 
                     end /* switch */ 
               end /* while */ 
 
         end /* while */ 
 
      newcnt = Rxbuflen; 
      Z_PutLongIntoHeader(Txpos); 
      ZS_SendBinaryHeader(ZDATA, Txhdr); 
 
      do 
         begin 
 
            if (((KEYPRESS()) and (READKB()==27))) 
               begin 
                  send_can(); 
                  z_log( KBD_msg ); 
                  goto oops; 
               end 
 
            if (!CARRIER) goto oops; 
 
            if ((c=fread(Txbuf,1,blklen,Infile))!=z_size) 
               begin 
                  gotoxy( locate_x+10, locate_y ); 
                  cputs( ultoa(((unsigned long )(z_size=c)),e_input,10) ); 
                  putch(' '); 
               end 
 
            if (c < blklen) e = ZCRCE; 
            else if (Rxbuflen && (newcnt -= c) <= 0) e = ZCRCW; 
            else e = ZCRCG; 
 
            ZS_SendData(Txbuf, c, e); 
 
            gotoxy( locate_x, locate_y ); 
            cputs( ultoa(((unsigned long )Txpos),e_input,10) ); 
            putch(' '); 
 
            Txpos += c; 
            if (blklengoodneeded) 
               begin 
                  blklen = (blklen<<1 < maxblklen) ? blklen<<1 : maxblklen; 
                  goodblks = 0; 
               end 
 
            if (e == ZCRCW) goto WaitAck; 
 
            while (CHAR_AVAIL()) 
               begin 
                  switch (MODEM_IN()) 
                     begin 
                        case CAN: 
                        case RCDO: 
                        case ZPAD:  /*--------------------------------------*/ 
                                    /* Interruption detected;               */ 
                                    /* stop sending and process complaint   */ 
                                    /*--------------------------------------*/ 
                                    z_message("Trouble?"); 
                                    CLEAR_OUTBOUND(); 
                                    ZS_SendData(Txbuf, 0, ZCRCE); 
                                    goto WaitAck; 
                     end /* switch */ 
               end /* while */ 
       
         end /* do */ 
      while (e == ZCRCG); 
 
      while(1) 
         begin 
            Z_PutLongIntoHeader(Txpos); 
            ZS_SendBinaryHeader(ZEOF, Txhdr); 
 
            switch (ZS_SyncWithReceiver()) 
               begin 
                  case ZACK:     /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 continue; 
 
                  case ZRPOS:    /*-----------------------------------------*/ 
                                 /* Resume at this position...              */ 
                                 /*-----------------------------------------*/ 
                                 goto SomeMore; 
 
                  case ZRINIT:   /*-----------------------------------------*/ 
                                 /* Receive init                            */ 
                                 /*-----------------------------------------*/ 
                                 throughput(1,Txpos-Strtpos); 
                                 return OK; 
 
                  case ZSKIP:    /*-----------------------------------------*/ 
                                 /* Request to skip the current file        */ 
                                 /*-----------------------------------------*/ 
                                 z_log(Skip_msg); 
                                 CLEAR_IOERR(); 
                                 fclose(Infile); 
                                 had_error(CLOSE_msg,Filename); 
                                 return c; 
 
                  default:       /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
oops:                            z_log(Cancelled_msg); 
                                 errno = 0; 
                                 fclose(Infile); 
                                 had_error(CLOSE_msg,Filename); 
                                 return ERROR; 
               end /* switch */ 
         end /* while */ 
 
   end /* ZS_SendFileData */ 
 
 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS SYNC WITH RECEIVER                                                    */ 
/* Respond to receiver's complaint, get back in sync with receiver          */ 
/*--------------------------------------------------------------------------*/ 
static int pascal ZS_SyncWithReceiver() 
   begin 
      register int c; 
      int          num_errs   = 7; 
 
      while(1) 
         begin 
            c = Z_GetHeader(Rxhdr); 
            CLEAR_INBOUND(); 
            switch (c) 
               begin 
                  case TIMEOUT:  z_message( TIME_msg ); 
                                 if ((num_errs--) >= 0) break; 
 
                  case ZCAN: 
                  case ZABORT: 
                  case ZFIN: 
                  case RCDO: 
                                 /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 z_log("Err"); 
                                 return ERROR; 
 
                  case ZRPOS:    /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 rewind(Infile);   /* In case file EOF seen */ 
                                 fseek(Infile, Rxpos, SEEK_SET); 
                                 Txpos = Rxpos; 
                                 z_message(NULL); 
                                 cputs("Resending from "); 
                                 cputs( ultoa(((unsigned long )(Txpos)),e_input,10) ); 
                                 return c; 
 
                  case ZSKIP:    /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 z_log(Skip_msg); 
 
                  case ZRINIT:   /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 CLEAR_IOERR(); 
                                 fclose(Infile); 
                                 had_error(CLOSE_msg,Filename); 
                                 return c; 
 
                  case ZACK:     /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 z_message( NULL ); 
                                 return c; 
 
                  default:       /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 z_message( IDUNNO_msg ); 
                                 ZS_SendBinaryHeader(ZNAK, Txhdr); 
                                 continue; 
               end /* switch */ 
         end /* while */ 
   end /* ZS_SyncWithReceiver */ 
 
 
 
 
/*--------------------------------------------------------------------------*/ 
/* ZS END SEND                                                              */ 
/* Say BIBI to the receiver, try to do it cleanly                           */ 
/*--------------------------------------------------------------------------*/ 
static void pascal ZS_EndSend() 
   begin 
 
      while(1) 
         begin 
            Z_PutLongIntoHeader(0L); 
            ZS_SendBinaryHeader(ZFIN, Txhdr); 
 
            switch (Z_GetHeader(Rxhdr)) 
               begin 
                  case ZFIN:     /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 SENDBYTE('O'); 
                                 SENDBYTE('O'); 
                                 wait_for_clear(); 
                                 /* fallthrough... */ 
                  case ZCAN: 
                  case RCDO: 
                  case TIMEOUT:  /*-----------------------------------------*/ 
                                 /*                                         */ 
                                 /*-----------------------------------------*/ 
                                 return; 
               end /* switch */ 
         end /* while */ 
   end /* ZS_EndSend */ 
 
 
/* END OF FILE: z_send.c */