ZRECEIVE.C
上传用户:haiyue
上传日期:2007-01-05
资源大小:21k
文件大小:32k
源码类别:

通讯/手机编程

开发平台:

C/C++

  1. /*--------------------------------------------------------------------------*/
  2. /* FILE: zreceive.c (Opus zmodem receiver)                                  */
  3. /*                                                                          */
  4. /*                                                                          */
  5. /*               The Opus Computer-Based Conversation System                */
  6. /*       (c) Copyright 1986, Wynn Wagner III, All Rights Reserved           */
  7. /*                                                                          */
  8. /*      This implementation of Chuck Forsberg's ZMODEM protocol was         */
  9. /*              for Opus by Rick Huebner and Wynn Wagner III                */
  10. /*                                                                          */
  11. /* (MSC/4 with /Zp /Ox)                                                     */
  12. /*                                                                          */
  13. /*                                                                          */
  14. /*                                                                          */
  15. /*                                                                          */
  16. /*  This module is similar to a routine used by Opus-Cbcs (1.00).  It is    */
  17. /*  provided for your information only.  You will find routines that need   */
  18. /*  to be coded and identifiers to be resolved.                             */
  19. /*                                                                          */
  20. /*  There is absolutely no guarantee that anything here will work.  If you  */
  21. /*  break this routine, you own both pieces.                                */
  22. /*                                                                          */
  23. /*  USAGE:  You may use this material in any program with no obligation     */
  24. /*          as long as there is no charge for your program.  For more       */
  25. /*          information about commercial use, contact the "OPUSinfo HERE"   */
  26. /*          BBS (124/111).                                                  */
  27. /*                                                                          */
  28. /*  NOTE:   There are a couple of things the Opus implementation does that  */
  29. /*          aren't part of the original ZModem protocol.  They all deal     */
  30. /*          with WaZOO type ("ZedZap") netmail and should only show up when */
  31. /*          used under that condition.                                      */
  32. /*                                                                          */
  33. /*             * The maximum packet size can grow larger than 1k.  It is    */
  34. /*               sensitive to the baud rate.  (2400b=2048k; 9600b=8192k)    */
  35. /*             * The sender must be able to send nothing.  In other words,  */
  36. /*               the sending system must be able to initiate and terminate  */
  37. /*               a zmodem send session without having to actually send a    */
  38. /*               file.  Normally this kind of thing would never happen in   */
  39. /*               zmodem.                                                    */
  40. /*                                                                          */
  41. /*                                                                          */
  42. /*--------------------------------------------------------------------------*/
  43. #include "zmodem.h"
  44. /*--------------------------------------------------------------------------*/
  45. /* External material                                                        */
  46. /*--------------------------------------------------------------------------*/
  47. extern int  dexists(byte *);
  48. /*--------------------------------------------------------------------------*/
  49. /* Local routines                                                           */
  50. /*--------------------------------------------------------------------------*/
  51. int cdecl get_Zmodem(byte *,FILE *);
  52. static int  pascal RZ_ReceiveData(byte *,int );
  53. static int  pascal RZ_InitReceiver(void);
  54. static int  pascal RZ_ReceiveBatch(FILE *);
  55. static int  pascal RZ_ReceiveFile(FILE *);
  56. static int  pascal RZ_GetHeader(void);
  57. static int  pascal RZ_SaveToDisk(unsigned long *);
  58. static void pascal RZ_AckBibi(void);
  59. /*--------------------------------------------------------------------------*/
  60. /* Private declarations                                                     */
  61. /*--------------------------------------------------------------------------*/
  62. static long DiskAvail;
  63. /*--------------------------------------------------------------------------*/
  64. /* Private data                                                             */
  65. /*--------------------------------------------------------------------------*/
  66. /* Parameters for ZSINIT frame */
  67. #define ZATTNLEN 32              /* Max length of attention string          */
  68. static char  Attn[ZATTNLEN+1];   /* String rx sends to tx on err            */
  69. static FILE *Outfile;            /* Handle of file being received           */
  70. static byte *Secbuf;             /* Pointer to receive buffer               */
  71. static int   Tryzhdrtype;        /* Hdr type to send for Last rx close      */
  72. static char  isBinary;           /* Current file is binary mode             */
  73. static char  EOFseen;            /* indicates cpm eof (^Z) was received     */
  74. static char  Zconv;              /* ZMODEM file conversion request          */
  75. static int   RxCount;            /* Count of data bytes received            */
  76. /*--------------------------------------------------------------------------*/
  77. /* GET ZMODEM                                                               */
  78. /* Receive a batch of files.                                                */
  79. /* returns TRUE (1) for good xfer, FALSE (0) for bad                        */
  80. /* can be called from f_upload or to get mail from a WaZOO Opus             */
  81. /*--------------------------------------------------------------------------*/
  82. int cdecl get_Zmodem(rcvpath, xferinfo)
  83.    byte *rcvpath;
  84.    FILE *xferinfo;
  85.    begin
  86.       byte        namebuf[PATHLEN];
  87.       int         i;
  88.       errno = 0;
  89.       _BRK_DISABLE();
  90.       XON_ENABLE();
  91.       n_disable();
  92.       Secbuf      = NULL;
  93.       Outfile     = NULL;
  94.       z_size      = 0;
  95.       DiskAvail   = freespace(toupper(sys.uppath[0])-'@');
  96.       Rxtimeout   = 10;
  97.       Tryzhdrtype = ZRINIT;
  98.       Secbuf      = zalloc();
  99.       strcpy(namebuf, rcvpath);
  100.       Filename = namebuf;
  101.       if (((i=RZ_InitReceiver())==ZCOMPL) or
  102.           ((i==ZFILE) and ((RZ_ReceiveBatch(xferinfo))==OK)) )
  103.          begin
  104.             free(Secbuf);
  105.             return 1;
  106.          end
  107.       CLEAR_OUTBOUND();
  108.       send_can();          /* transmit at least 10 cans */
  109.       wait_for_clear();
  110.       if (Secbuf)    free(Secbuf);
  111.       if (Outfile)   fclose(Outfile);
  112.       return 0;
  113.    end /* get_Zmodem */
  114. /*--------------------------------------------------------------------------*/
  115. /* RZ RECEIVE DATA                                                          */
  116. /* Receive array buf of max length with ending ZDLE sequence                */
  117. /* and CRC.  Returns the ending character or error code.                    */
  118. /*--------------------------------------------------------------------------*/
  119. static int pascal RZ_ReceiveData(buf, length)
  120.    byte *buf;
  121.    int length;
  122.    begin
  123.       register int   c;
  124.       register word  crc;
  125.       int            d;
  126.       crc   = RxCount   = 0;
  127.       while(1)
  128.          begin
  129.             if ((c = Z_GetZDL()) & ~0xFF)
  130.                begin
  131. CRCfoo:
  132.                   switch (c)
  133.                      begin
  134.                         case GOTCRCE:
  135.                         case GOTCRCG:
  136.                         case GOTCRCQ:
  137.                         case GOTCRCW:  /*-----------------------------------*/
  138.                                        /* C R C s                           */
  139.                                        /*-----------------------------------*/
  140.                                        crc = Z_UpdateCRC(((d=c)&0xFF), crc);
  141.                                        if ((c=Z_GetZDL()) & ~0xFF) goto CRCfoo;
  142.                                        crc = Z_UpdateCRC(c, crc);
  143.                                        if ((c=Z_GetZDL()) & ~0xFF) goto CRCfoo;
  144.                                        crc = Z_UpdateCRC(c, crc);
  145.                                        if (crc & 0xFFFF)
  146.                                           begin
  147.                                              z_message( CRC_msg );
  148.                                              return ERROR;
  149.                                           end
  150.                                        return d;
  151.                         case GOTCAN:   /*-----------------------------------*/
  152.                                        /* Cancel                            */
  153.                                        /*-----------------------------------*/
  154.                                        z_log(Cancelled_msg);
  155.                                        return ZCAN;
  156.                         case TIMEOUT:  /*-----------------------------------*/
  157.                                        /* Timeout                           */
  158.                                        /*-----------------------------------*/
  159.                                        z_message( TIME_msg );
  160.                                        return c;
  161.                         case RCDO:     /*-----------------------------------*/
  162.                                        /* No carrier                        */
  163.                                        /*-----------------------------------*/
  164.                                        z_log( CARRIER_msg );
  165.                                        return c;
  166.                         default:       /*-----------------------------------*/
  167.                                        /* Something bizarre                 */
  168.                                        /*-----------------------------------*/
  169.                                        z_message("Debris");
  170.                                        return c;
  171.                      end /* switch */
  172.                end /* if */
  173.             if (--length < 0)
  174.                begin
  175.                   z_message("Long pkt");
  176.                   return ERROR;
  177.                end
  178.             ++RxCount;
  179.             *buf++ = c;
  180.             crc = Z_UpdateCRC(c, crc);
  181.             continue;
  182.          end /* while(1) */
  183.    end /* RZ_ReceiveData */
  184. /*--------------------------------------------------------------------------*/
  185. /* RZ INIT RECEIVER                                                         */
  186. /* Initialize for Zmodem receive attempt, try to activate Zmodem sender     */
  187. /* Handles ZSINIT, ZFREECNT, and ZCOMMAND frames                            */
  188. /*                                                                          */
  189. /* Return codes:                                                            */
  190. /*    ZFILE .... Zmodem filename received                                   */
  191. /*    ZCOMPL ... transaction finished                                       */
  192. /*    ERROR .... any other condition                                        */
  193. /*--------------------------------------------------------------------------*/
  194. static int pascal RZ_InitReceiver()
  195.    begin
  196.       register int   n;
  197.       int            errors = 0;
  198.       for (n=10; --n>=0; )
  199.          begin
  200.             /*--------------------------------------------------------------*/
  201.             /* Set buffer length (0=unlimited, don't wait).                 */
  202.             /* Also set capability flags                                    */
  203.             /*--------------------------------------------------------------*/
  204.             Z_PutLongIntoHeader(0L);
  205.             Txhdr[ZF0] = CANFDX|CANOVIO;
  206.             Z_SendHexHeader(Tryzhdrtype, Txhdr);
  207. AGAIN:
  208.             switch (Z_GetHeader(Rxhdr))
  209.                begin
  210.                   case ZFILE:    /*-----------------------------------------*/
  211.                                  /*                                         */
  212.                                  /*-----------------------------------------*/
  213.                                  Zconv = Rxhdr[ZF0];
  214.                                  Tryzhdrtype = ZRINIT;
  215.                                  if (RZ_ReceiveData(Secbuf,WAZOOMAX)==GOTCRCW)
  216.                                     return ZFILE;
  217.                                  Z_SendHexHeader(ZNAK, Txhdr);
  218.                                  goto AGAIN;
  219.                   case ZSINIT:   /*-----------------------------------------*/
  220.                                  /*                                         */
  221.                                  /*-----------------------------------------*/
  222.                                  if (RZ_ReceiveData(Attn, ZATTNLEN) == GOTCRCW)
  223.                                     Z_SendHexHeader(ZACK, Txhdr);
  224.                                  else Z_SendHexHeader(ZNAK, Txhdr);
  225.                                  goto AGAIN;
  226.                   case ZFREECNT: /*-----------------------------------------*/
  227.                                  /*                                         */
  228.                                  /*-----------------------------------------*/
  229.                                  Z_PutLongIntoHeader(DiskAvail);
  230.                                  Z_SendHexHeader(ZACK, Txhdr);
  231.                                  goto AGAIN;
  232.                   case ZCOMMAND: /*-----------------------------------------*/
  233.                                  /* Paranoia is good for you...             */
  234.                                  /* Ignore command from remote, but lie and */
  235.                                  /* say we did the command ok.              */
  236.                                  /*-----------------------------------------*/
  237.                                  if (RZ_ReceiveData(Secbuf,WAZOOMAX)==GOTCRCW)
  238.                                     begin
  239.                                        status_line("!Ignoring `%s'", Secbuf);
  240.                                        Z_PutLongIntoHeader(0L); 
  241.                                        do
  242.                                           begin
  243.                                              Z_SendHexHeader(ZCOMPL, Txhdr);
  244.                                           end
  245.                                        while (++errors<10 && Z_GetHeader(Rxhdr) != ZFIN);
  246.                                        RZ_AckBibi();
  247.                                        return ZCOMPL;
  248.                                     end
  249.                                  else Z_SendHexHeader(ZNAK, Txhdr);
  250.                                  goto AGAIN;
  251.                   case ZCOMPL:   /*-----------------------------------------*/
  252.                                  /*                                         */
  253.                                  /*-----------------------------------------*/
  254.                                  goto AGAIN;
  255.                   case ZFIN:     /*-----------------------------------------*/
  256.                                  /*                                         */
  257.                                  /*-----------------------------------------*/
  258.                                  RZ_AckBibi();
  259.                                  return ZCOMPL;
  260.                   case ZCAN:
  261.                   case RCDO:     /*-----------------------------------------*/
  262.                                  /*                                         */
  263.                                  /*-----------------------------------------*/
  264.                                  return ERROR;
  265.                end /* switch */
  266.          end /* for */
  267.       return ERROR;
  268.    end /* RZ_InitReceiver */
  269. /*--------------------------------------------------------------------------*/
  270. /* RZFILES                                                                  */
  271. /* Receive a batch of files using ZMODEM protocol                           */
  272. /*--------------------------------------------------------------------------*/
  273. static int pascal RZ_ReceiveBatch(xferinfo)
  274.    FILE *xferinfo;
  275.    begin
  276.       register int c;
  277.       set_xy("");
  278.       while(1)
  279.          begin
  280.             switch (c = RZ_ReceiveFile(xferinfo))
  281.                begin
  282.                   case ZEOF:
  283.                   case ZSKIP:
  284.                               switch (RZ_InitReceiver())
  285.                                  begin
  286.                                     case ZCOMPL:   return OK;
  287.                                     default:       return ERROR;
  288.                                     case ZFILE:    break;
  289.                                  end /* switch */
  290.                               break;
  291.                   default:
  292.                               fclose(Outfile);
  293.                               Outfile  = NULL;
  294.                               unlink(Filename);
  295.                               errno    = 0;
  296.                               return c;
  297.                end /* switch */
  298.          end /* while */
  299.    end /* RZ_ReceiveBatch */
  300. /*--------------------------------------------------------------------------*/
  301. /* RZ RECEIVE FILE                                                          */
  302. /* Receive one file; assumes file name frame is preloaded in Secbuf         */
  303. /*--------------------------------------------------------------------------*/
  304. static int pascal RZ_ReceiveFile(xferinfo)
  305.    FILE *xferinfo;
  306.    begin
  307.       register int   c;
  308.       int            n;
  309.       long           rxbytes;
  310.       EOFseen=FALSE;
  311.       if (RZ_GetHeader() == ERROR)  return (Tryzhdrtype = ZSKIP);
  312.       n        = 10;
  313.       rxbytes  = 0L;
  314.       while(1)
  315.          begin
  316.             Z_PutLongIntoHeader(rxbytes);
  317.             Z_SendHexHeader(ZRPOS, Txhdr);
  318. NxtHdr:
  319.             switch (c = Z_GetHeader(Rxhdr))
  320.                begin
  321.                   case ZDATA:    /*-----------------------------------------*/
  322.                                  /* Data Packet                             */
  323.                                  /*-----------------------------------------*/
  324.                                  if (Rxpos != rxbytes)
  325.                                     begin
  326.                                        if ( --n < 0) return ERROR;
  327.                                        z_message(NULL);
  328.                                        cprintf("Bad pos; %ld/%ld",rxbytes,Rxpos);
  329.                                        Z_PutString(Attn);
  330.                                        continue;
  331.                                     end
  332. MoreData:
  333.                                  switch (c = RZ_ReceiveData(Secbuf,WAZOOMAX))
  334.                                     begin
  335.                                        case ZCAN:
  336.                                        case RCDO:  /*-----------------------*/
  337.                                                    /* CAN or CARRIER        */
  338.                                                    /*-----------------------*/
  339.                                                    z_log(Cancelled_msg);
  340.                                                    return ERROR;
  341.                                        case ERROR: /*-----------------------*/
  342.                                                    /* CRC error             */
  343.                                                    /*-----------------------*/
  344.                                                    if (--n<0)
  345.                                                       begin
  346.                                                          z_log( FUBAR_msg );
  347.                                                          return ERROR;
  348.                                                       end
  349.                                                    show_loc(rxbytes,n);
  350.                                                    Z_PutString(Attn);
  351.                                                    continue;
  352.                                        case TIMEOUT: /*---------------------*/
  353.                                                    /*                       */
  354.                                                    /*-----------------------*/
  355.                                                    if (--n<0)
  356.                                                       begin
  357.                                                          z_log( TIME_msg );
  358.                                                          return ERROR;
  359.                                                       end
  360.                                                    show_loc(rxbytes,n);
  361.                                                    continue;
  362.                                        case GOTCRCW: /*---------------------*/
  363.                                                    /* End of frame          */
  364.                                                    /*-----------------------*/
  365.                                                    n = 10;
  366.                                                    if (RZ_SaveToDisk(&rxbytes)==ERROR)
  367.                                                       return ERROR;
  368.                                                    Z_PutLongIntoHeader(rxbytes);
  369.                                                    Z_SendHexHeader(ZACK, Txhdr);
  370.                                                    goto NxtHdr;
  371.                                        case GOTCRCQ: /*---------------------*/
  372.                                                    /* Zack expected         */
  373.                                                    /*-----------------------*/
  374.                                                    n = 10;
  375.                                                    if (RZ_SaveToDisk(&rxbytes)==ERROR)
  376.                                                       return ERROR;
  377.                                                    Z_PutLongIntoHeader(rxbytes);
  378.                                                    Z_SendHexHeader(ZACK, Txhdr);
  379.                                                    goto MoreData;
  380.                                        case GOTCRCG: /*---------------------*/
  381.                                                    /* Non-stop              */
  382.                                                    /*-----------------------*/
  383.                                                    n = 10;
  384.                                                    if (RZ_SaveToDisk(&rxbytes)==ERROR)
  385.                                                       return ERROR;
  386.                                                    goto MoreData;
  387.                                        case GOTCRCE: /*---------------------*/
  388.                                                    /* Header to follow      */
  389.                                                    /*-----------------------*/
  390.                                                    n = 10;
  391.                                                    if (RZ_SaveToDisk(&rxbytes)==ERROR)
  392.                                                       return ERROR;
  393.                                                    goto NxtHdr;
  394.                                     end /* switch */
  395.                   case ZNAK:
  396.                   case TIMEOUT:  /*-----------------------------------------*/
  397.                                  /* Packed was probably garbled             */
  398.                                  /*-----------------------------------------*/
  399.                                  if ( --n < 0)
  400.                                     begin
  401.                                        z_log( "Garbled packet" );
  402.                                        return ERROR;
  403.                                     end
  404.                                  show_loc(rxbytes,n);
  405.                                  continue;
  406.                   case ZFILE:    /*-----------------------------------------*/
  407.                                  /* Sender didn't see our ZRPOS yet         */
  408.                                  /*-----------------------------------------*/
  409.                                  RZ_ReceiveData(Secbuf, WAZOOMAX);
  410.                                  continue;
  411.                   case ZEOF:     /*-----------------------------------------*/
  412.                                  /* End of the file                         */
  413.                                  /*-----------------------------------------*/
  414.                                  if (Rxpos != rxbytes)
  415.                                     begin
  416.                                        status_line("-Bad EOF; %ld/%ld", rxbytes, Rxpos);
  417.                                        continue;
  418.                                     end
  419.                                  throughput(2,rxbytes);
  420.                                  errno = 0;
  421.                                  fclose(Outfile);
  422.                                  had_error(CLOSE_msg,Filename);
  423.                                  status_line("=UL %s",Filename);
  424.                                  Outfile  = NULL;
  425.                                  if (xferinfo != NULL)
  426.                                     begin
  427.                                        fprintf(xferinfo, "%sn", Filename);
  428.                                        had_error(WRITE_msg,"XferInfo");
  429.                                     end
  430.                                  return c;
  431.                   case ERROR:    /*-----------------------------------------*/
  432.                                  /* Too much garbage in header search error */
  433.                                  /*-----------------------------------------*/
  434.                                  if ( --n < 0) return ERROR;
  435.                                  show_loc(rxbytes,n);
  436.                                  Z_PutString(Attn);
  437.                                  continue;
  438.                   default:       /*-----------------------------------------*/
  439.                                  /*                                         */
  440.                                  /*-----------------------------------------*/
  441.                                  z_log( IDUNNO_msg );
  442.                                  return ERROR;
  443.                end /* switch */
  444.          end /* while */
  445.    end /* RZ_ReceiveFile */
  446. /*--------------------------------------------------------------------------*/
  447. /* RZ GET HEADER                                                            */
  448. /* Process incoming file information header                                 */
  449. /*--------------------------------------------------------------------------*/
  450. static int pascal RZ_GetHeader()
  451.    begin
  452.       static char    suffix[] = ".001";
  453.       register byte *p;
  454.       register int   n;
  455.       byte          *ourname;
  456.       byte          *theirname;
  457.       unsigned long  filesize;
  458.       /*--------------------------------------------------------------------*/
  459.       /* Setup the transfer mode                                            */
  460.       /*--------------------------------------------------------------------*/
  461.       isBinary  = (!RXBINARY && Zconv == ZCNL)? 0 : 1;
  462.       /*--------------------------------------------------------------------*/
  463.       /* Extract and verify filesize, if given.                             */
  464.       /* Reject file if not at least 10K free                               */
  465.       /*--------------------------------------------------------------------*/
  466.       filesize = 0L;
  467.       p        = Secbuf + 1 + strlen(Secbuf);
  468.       if (*p) sscanf(p, "%ld", &filesize);
  469.       if (filesize+10240 > DiskAvail)
  470.          begin
  471.             status_line("!Disk space");
  472.             return ERROR;
  473.          end
  474.       /*--------------------------------------------------------------------*/
  475.       /* Get and/or fix filename for uploaded file                          */
  476.       /*--------------------------------------------------------------------*/
  477.       p  = Filename+strlen(Filename)-1;     /* Find end of Opus upload path */
  478.       while (p>=Filename && *p!='\') p--;
  479.       ourname = ++p;
  480.       p = Secbuf+strlen(Secbuf)-1;      /* Find transmitted simple filename */
  481.       while (p >= Secbuf && *p!='\' && *p!='/' && *p!=':') p--;
  482.       theirname = ++p;
  483.       strcpy(ourname,theirname);          /* Start w/ our path & their name */
  484.       if (dexists(Filename))
  485.          begin                            /* If file already exists...      */
  486.             p = ourname;
  487.             while (*p && *p!='.') p++;    /* ...find the extension, if any  */
  488.             for (n=0; n<4; n++)           /* ...fill it out if neccessary   */
  489.                if (!*p)
  490.                   begin
  491.                      *p       = suffix[n];
  492.                      *(++p)   = '';
  493.                   end
  494.                else p++;
  495.             while (dexists(Filename))    /* ...If 'file.ext' exists suffix++ */
  496.                begin
  497.                   p = ourname+strlen(ourname)-1;
  498.                   for (n=3; n--;)
  499.                      begin
  500.                         if (!isdigit(*p)) *p = '0';
  501.                         if (++(*p) <= '9') break;
  502.                         else *p-- = '0';
  503.                      end /* for */
  504.                end /* while */
  505.          end /* if exist */
  506.       errno = 0;
  507.       if (strcmp(ourname,theirname))
  508.          status_line("+Dupe renamed: %s",ourname);
  509.    
  510.       errno = 0;
  511.       Outfile = fopen( Filename, write_binary );
  512.       if (had_error(OPEN_msg,Filename)) return ERROR;
  513.     set_xy(NULL);
  514.       cprintf("Z-Recv %s, %s%ldb, %d min.",
  515.                   Filename,
  516.                   (isBinary)? "": "ASCII ",
  517.                   filesize,
  518.                   (int)(filesize*10/cur_baud+27)/54);
  519.       set_xy(NULL);
  520.       throughput(0,0L);
  521.       return OK;
  522.    end /* RZ_GetHeader */
  523. /*--------------------------------------------------------------------------*/
  524. /* RZ SAVE TO DISK                                                          */
  525. /* Writes the received file data to the output file.                        */
  526. /* If in ASCII mode, stops writing at first ^Z, and converts all            */
  527. /*   solo CR's or LF's to CR/LF pairs.                                      */
  528. /*--------------------------------------------------------------------------*/
  529. static int pascal RZ_SaveToDisk(rxbytes)
  530.    unsigned long *rxbytes;
  531.    begin
  532.       static byte    lastsent;
  533.       register byte *p;
  534.       register int   count;
  535.       count = RxCount;
  536.       if (((KEYPRESS()) and (READKB()==27)))
  537.          begin
  538.             send_can();
  539.             z_log( KBD_msg );
  540.             return ERROR;
  541.          end
  542.       if (count!=z_size)
  543.          begin
  544.             gotoxy( locate_x+10, locate_y );
  545.             cputs( ultoa(((unsigned long )(z_size=count)),e_input,10) );
  546.             putch(' ');
  547.          end
  548.       errno = 0;
  549.       if (isBinary)
  550.          begin
  551.             fwrite( Secbuf, count, 1, Outfile );
  552.             if (errno) goto oops;
  553.          end
  554.       else
  555.          begin
  556.             if (EOFseen) return OK;
  557.             for (p=Secbuf; --count>=0; ++p )
  558.                begin
  559.                   if ( *p == CPMEOF)
  560.                      begin
  561.                         EOFseen = TRUE;
  562.                         return OK;
  563.                      end
  564.                   if ( *p=='n' ) {
  565.                      if (lastsent!='r' && putc('r', Outfile) == EOF)
  566.                         goto oops;
  567.                   } else {
  568.                      if (lastsent=='r' && putc('n', Outfile) == EOF)
  569.                         goto oops;
  570.                   }
  571.                   if (putc((lastsent=*p), Outfile) == EOF)  goto oops;
  572.                end
  573.          end
  574.       *rxbytes += RxCount;
  575.       
  576.       gotoxy( locate_x, locate_y );
  577.       cputs( ultoa(((unsigned long )(*rxbytes)),e_input,10) );
  578.       return OK; 
  579. oops:
  580.       had_error(WRITE_msg,Filename);
  581.       return ERROR;
  582.    end /* RZ_SaveToDisk */
  583. /*--------------------------------------------------------------------------*/
  584. /* RZ ACK BIBI                                                              */
  585. /* Ack a ZFIN packet, let byegones be byegones                              */
  586. /*--------------------------------------------------------------------------*/
  587. static void pascal RZ_AckBibi()
  588.    begin
  589.       register int n;
  590.       Z_PutLongIntoHeader(0L);
  591.       for (n=4; --n;)
  592.          begin
  593.             Z_SendHexHeader(ZFIN, Txhdr);
  594.             switch (Z_GetByte(100))
  595.                begin
  596.                   case 'O':      Z_GetByte(1);    /* Discard 2nd 'O' */
  597.                   case TIMEOUT:
  598.                   case RCDO:     return;
  599.                end /* switch */
  600.          end /* for */
  601.    end /* RZ_AckBibi */