home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Workbench / Libs / XPRZ33.LHA / XprZMoDem.Library_v3.0 / Src.LhA / Src / Receive.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-13  |  18.1 KB  |  675 lines

  1. /**********************************************************************
  2.  * Receive.c:  File reception routines for xprzmodem.library;
  3.  * Version 2.10, 12 February 1991, by Rick Huebner.
  4.  * Based closely on Chuck Forsberg's rz.c example ZModem code,
  5.  * but too pervasively modified to even think of detailing the changes.
  6.  * Released to the Public Domain; do as you like with this code.
  7.  *
  8.  * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
  9.  **********************************************************************/
  10.  
  11. #include "xprzmodem_all.h"
  12.  
  13. #define CATCOMP_NUMBERS
  14. #include "xprzmodem_catalog.h"
  15.  
  16. #ifdef DEBUGLOG
  17. extern void *DebugLog;
  18. #endif
  19.  
  20. /**********************************************************
  21.  *      long XProtocolReceive(struct XPR_IO *xio)
  22.  *
  23.  * Main file reception routine; called by comm program
  24.  **********************************************************/
  25. long __saveds __asm
  26. XProtocolReceive (register __a0 struct XPR_IO *xio)
  27. {
  28.   struct SetupVars *sv;
  29.   struct Vars *v;
  30.   UBYTE err = FALSE;
  31.  
  32.   /* Perform common setup and initializations */
  33.   if (!(v = setup (xio)))
  34.     return XPRS_FAILURE;
  35.  
  36.   v->Tryzhdrtype = ZRINIT;
  37.   v->Rxtimeout = 100;
  38.  
  39.   sv = (void *) v->io.xpr_data;
  40.   if (sv->bufpos)
  41.     {
  42.       v->Modemchar = v->Modembuf;
  43.       if (sv->buflen > sizeof (v->Modembuf))
  44.     sv->buflen = sizeof (v->Modembuf);
  45.       memcpy (v->Modembuf, sv->bufpos, sv->buflen);
  46.       v->Modemcount = sv->buflen;
  47.     }
  48.  
  49.   /* Transfer the files */
  50.   if (rcvbatch (v) == ERROR)
  51.     {
  52.       upderr (v, GetLocalString( &li, MSG_DOWNLOAD_USER_ERROR ));
  53.       err = TRUE;
  54.     }
  55.   else
  56.     updmsg (v, GetLocalString( &li, MSG_DONE ));
  57.  
  58.   /* Clean up and return */
  59.   if (v->io.xpr_setserial && v->Oldstatus != -1)
  60.     (*v->io.xpr_setserial) (v->Oldstatus);
  61.   FreeMem (v->Filebuf, v->Filebufmax);
  62.   FreeMem (v, (long) sizeof (struct Vars));
  63.  
  64. #ifdef DEBUGLOG
  65.   if (DebugLog)
  66.     {
  67.       (*v->io.xpr_fclose) ((long) DebugLog);
  68.       DebugLog = NULL;
  69.     }
  70. #endif
  71.  
  72.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  73. }                /* End of long XProtocolReceive() */
  74.  
  75. /**********************************************************
  76.  *      short rcvbatch(struct Vars *v)
  77.  *
  78.  * Start the batch transfer
  79.  **********************************************************/
  80. short
  81. rcvbatch (struct Vars *v)
  82. {
  83. #ifdef DEBUGLOG
  84.   D (DEBUGINFO);
  85. #endif
  86.  
  87.   switch (tryz (v))
  88.     {
  89.     case ZCOMPL:
  90.       return OK;
  91.     case ZFILE:
  92.       if (rzfiles (v) == OK)
  93.     return OK;
  94.     }
  95.  
  96. #ifdef DEBUGLOG
  97.   D (DEBUGINFO);
  98. #endif
  99.  
  100.   canit (v);
  101.  
  102.   return ERROR;
  103. }                /* End of short rcvbatch() */
  104.  
  105. /**********************************************************
  106.  *      short tryz(struct Vars *v)
  107.  *
  108.  * Negotiate with sender to start a file transfer
  109.  **********************************************************/
  110. short
  111. tryz (struct Vars *v)
  112. {
  113.   short n, errors = 0;
  114.  
  115. #ifdef DEBUGLOG
  116.   D (DEBUGINFO);
  117. #endif
  118.  
  119.   for (n = v->ErrorLimit; --n >= 0;)
  120.     {
  121.       /* Set max frame length and capability flags */
  122.       stohdr (v, (long) v->Tframlen);
  123.       v->Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  124.       zshhdr (v, v->Tryzhdrtype);
  125.       sendbuf (v);
  126.     again:
  127.       /* Check for abort from comm program */
  128.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) ())
  129.     return ERROR;
  130.       switch (zgethdr (v))
  131.     {
  132.     case ZFILE:        /* File name and info packet */
  133.       v->Zconv = v->Rxhdr[ZF0];    /* Suggested txt mode; ZCNL = text, */
  134.       /* ZCBIN = binary, 0 = don't know. */
  135.       v->Zmanag = v->Rxhdr[ZF1];    /* Suggested file management mode. */
  136.       v->Ztrans = v->Rxhdr[ZF2];    /* Suggested file transport mode. */
  137.       v->Tryzhdrtype = ZRINIT;
  138.       if (zrdata (v, v->Pktbuf, KSIZE) == GOTCRCW)
  139.         return ZFILE;
  140.       zshhdr (v, ZNAK);    /* Packet mangled, ask for retry */
  141.       sendbuf (v);
  142.       goto again;
  143.     case ZSINIT:        /* Special attention-grabbing string to use to */
  144.       /* interrupt sender */
  145.       if (zrdata (v, v->Attn, ZATTNLEN) == GOTCRCW)
  146.         zshhdr (v, ZACK);
  147.       else
  148.         zshhdr (v, ZNAK);
  149.       sendbuf (v);
  150.       goto again;
  151.     case ZFREECNT:        /* Sender wants to know how much room we've got */
  152.       stohdr (v, getfree ());
  153.       zshhdr (v, ZACK);
  154.       sendbuf (v);
  155.       goto again;
  156.     case ZCOMMAND:        /* Sender wants us to do remote commands, */
  157.       /* but we don't do requests. */
  158.       if (zrdata (v, v->Pktbuf, KSIZE) == GOTCRCW)
  159.         {
  160.           xprsprintf (v->Msgbuf, "%s: %s", GetLocalString( &li, MSG_IGNORING_COMMAND), v->Pktbuf);
  161.           upderr (v, v->Msgbuf);    /* Ignore and report all uploaded commands */
  162.           stohdr (v, 0L);    /* whilst telling sender they worked; */
  163.           do
  164.         {
  165.           zshhdr (v, ZCOMPL);    /* paranoia can be good for you... */
  166.           sendbuf (v);
  167.         }
  168.           while (++errors < v->ErrorLimit && zgethdr (v) != ZFIN);
  169.           ackbibi (v);
  170.           return ZCOMPL;
  171.         }
  172.       else
  173.         zshhdr (v, ZNAK);
  174.       sendbuf (v);
  175.       goto again;
  176.     case ZCOMPL:
  177.       goto again;
  178.     case ZFIN:        /* Sender has ended batch */
  179.       ackbibi (v);
  180.       return ZCOMPL;
  181.     case ZCAN:
  182.     case RCDO:
  183.       upderr (v, v->Msgbuf);
  184.       return ERROR;
  185.     }
  186.     }
  187.   return ERROR;
  188. }                /* End of short tryz() */
  189.  
  190. /**********************************************************
  191.  *      short rzfiles(struct Vars *v)
  192.  *
  193.  * Receive a batch of files
  194.  **********************************************************/
  195. short
  196. rzfiles (struct Vars *v)
  197. {
  198.   struct SetupVars *sv;
  199.   short c;
  200.  
  201. #ifdef DEBUGLOG
  202.   D (DEBUGINFO);
  203. #endif
  204.  
  205.   /* Keep receiving files until end of batch or error */
  206.   while (TRUE)
  207.     {
  208.       switch (c = rzfile (v))
  209.     {
  210.     case ZEOF:
  211.     case ZSKIP:
  212.       switch (tryz (v))
  213.         {
  214.         case ZCOMPL:
  215.           return OK;
  216.         default:
  217.           return ERROR;
  218.         case ZFILE:
  219.           break;
  220.         }
  221.       break;
  222.     default:
  223.       bfclose (v);
  224.       sv = (void *) v->io.xpr_data;
  225.       if (*sv->option_k == 'N' && v->io.xpr_extension >= 2
  226.           && v->io.xpr_unlink)
  227.         {
  228.           updmsg (v, GetLocalString( &li, MSG_DELETING_RECEIVED_FILE ));
  229.           (*v->io.xpr_unlink) (v->Filename);
  230.         }
  231.       else
  232.         updmsg (v, GetLocalString( &li, MSG_KEEPING_RECEIVED_FILE));
  233.       return c;
  234.     }
  235.     }
  236. }                /* End of short rzfiles() */
  237.  
  238. /**********************************************************
  239.  *      short rzfile(struct Vars *v)
  240.  *
  241.  * Receive one file; file name packet already read into
  242.  * Pktbuf by tryz()
  243.  **********************************************************/
  244. short
  245. rzfile (struct Vars *v)
  246. {
  247.   short c, n;
  248.  
  249. #ifdef DEBUGLOG
  250.   D (DEBUGINFO);
  251. #endif
  252.  
  253.   /*
  254.      * Process file name packet; either open file and prepare to receive,
  255.      * or tell us to skip this one.
  256.    */
  257.   if (procheader (v) == ERROR)
  258.     return v->Tryzhdrtype = ZSKIP;
  259.  
  260.   n = v->ErrorLimit;
  261.   v->Rxbytes = v->Strtpos;
  262.   v->Eofseen = FALSE;
  263.  
  264.   /* Receive ZDATA frames until finished */
  265.   while (TRUE)
  266.     {
  267.       stohdr (v, v->Rxbytes);    /* Tell sender where to start frame */
  268.       zshhdr (v, ZRPOS);
  269.       sendbuf (v);
  270.     nxthdr:
  271.       /* Check for abort from comm program */
  272.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) ())
  273.     return ERROR;
  274.       switch (c = zgethdr (v))    /* Wait for frame header */
  275.     {
  276.     default:
  277. #ifdef DEBUGLOG
  278.       xprsprintf (v->Msgbuf, "rzfile: zgethdr returned %ld\n", (long) c);
  279.       dlog (v, v->Msgbuf);
  280.       D (DEBUGINFO);
  281.  
  282. #endif
  283.       return ERROR;
  284.     case ZNAK:
  285.     case TIMEOUT:
  286.       if (--n < 0)
  287.         return ERROR;
  288. #ifdef DEBUGLOG
  289.       dlog (v, "rzfile: zgethdr NAK/Timeout\n");
  290.       D (DEBUGINFO);
  291. #endif
  292.       v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  293.       xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  294.               v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  295.       v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  296.       ++v->xpru.xpru_timeouts;
  297.       (*v->io.xpr_update) (&v->xpru);
  298.       continue;
  299.     case ZFILE:        /* Sender didn't see our ZRPOS yet; try again */
  300.       zrdata (v, v->Pktbuf, KSIZE);        /* Read and discard redundant */
  301.       continue;        /* filename packet */
  302.     case ZEOF:        /* End of file data */
  303.       if (v->Rxpos != v->Rxbytes)    /* We aren't in sync; go back */
  304.         {
  305.           xprsprintf (v->Msgbuf, GetLocalString( &li, MSG_BAD_EOF ),
  306.               v->Rxbytes, v->Rxpos);
  307.           upderr (v, v->Msgbuf);
  308.           continue;
  309.         }
  310.       bfclose (v);        /* All done; close file */
  311. #ifdef DEBUGLOG
  312.       dlog (v, "rzfile: EOF\n");
  313.       D (DEBUGINFO);
  314. #endif
  315.       updmsg (v, GetLocalString( &li, MSG_EOF_RECEIVED ));
  316.       return c;
  317.     case ERROR:        /* Too much garbage while waiting for frame header */
  318.       if (--n < 0)
  319.         return ERROR;
  320. #ifdef DEBUGLOG
  321.       dlog (v, "rzfile: zgethdr garbage overflow\n");
  322.       D (DEBUGINFO);
  323. #endif
  324.       v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  325.       xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  326.               v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  327.       v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  328.       ++v->xpru.xpru_errors;
  329.       (*v->io.xpr_update) (&v->xpru);
  330.       zmputs (v, v->Attn);
  331.       continue;
  332.     case ZDATA:        /* More file data packets forthcoming */
  333.       if (v->Rxpos != v->Rxbytes)    /* We aren't in sync; go back */
  334.         {
  335.           if (--n < 0)
  336.         return ERROR;
  337.           v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  338.           xprsprintf (v->Msgbuf, GetLocalString( &li, MSG_DATA_AT_BAD_POSITION ),
  339.               v->Rxbytes, v->Rxpos);
  340.           v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  341.           ++v->xpru.xpru_errors;
  342.           (*v->io.xpr_update) (&v->xpru);
  343.           zmputs (v, v->Attn);
  344.           continue;
  345.         }
  346.       /* Receive file data packet(s) */
  347.     moredata:
  348.       /* Give comm program its timeslice if it needs one */
  349.       if (v->io.xpr_chkmisc)
  350.         (*v->io.xpr_chkmisc) ();
  351.       /* Check for abort from comm program */
  352.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort) ())
  353.         goto aborted;
  354.       switch (c = zrdata (v, v->Pktbuf, KSIZE))
  355.         {
  356.         case ZCAN:
  357.         case RCDO:
  358.         aborted:
  359. #ifdef DEBUGLOG
  360.           dlog (v, "rzfile: zrdata returned CAN\n");
  361.           D (DEBUGINFO);
  362. #endif
  363.           upderr (v, GetLocalString( &li, MSG_TRANSFER_CANCELLED ));
  364.           return ERROR;
  365.         case ERROR:    /* CRC error or packet too long */
  366.           if (--n < 0)
  367.         return ERROR;
  368. #ifdef DEBUGLOG
  369.           dlog (v, "rzfile: zrdata returned error\n");
  370.           D (DEBUGINFO);
  371. #endif
  372.           v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  373.           xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  374.               v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  375.           v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  376.           ++v->xpru.xpru_errors;
  377.           (*v->io.xpr_update) (&v->xpru);
  378. #ifdef DEBUGLOG
  379.           dlog (v, v->Msgbuf);
  380.           dlog (v, "\n");
  381.           D (DEBUGINFO);
  382. #endif
  383.           zmputs (v, v->Attn);
  384.           continue;
  385.         case TIMEOUT:
  386.           if (--n < 0)
  387.         return ERROR;
  388. #ifdef DEBUGLOG
  389.           dlog (v, "rzfile: zrdata returned timeout\n");
  390.           D (DEBUGINFO);
  391. #endif
  392.           v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  393.           xprsprintf (strchr (v->Msgbuf, '\0'), "@ %ld; %ld %s",
  394.               v->Rxbytes, (long) n, GetLocalString( &li, MSG_RETRIES_LEFT ));
  395.           v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  396.           ++v->xpru.xpru_timeouts;
  397.           (*v->io.xpr_update) (&v->xpru);
  398. #ifdef DEBUGLOG
  399.           dlog (v, v->Msgbuf);
  400.           dlog (v, "\n");
  401.           D (DEBUGINFO);
  402. #endif
  403.           continue;
  404.         case GOTCRCW:    /* Sender says it's waiting for an ACK */
  405.           n = v->ErrorLimit;
  406.           if (putsec (v) == ERROR)
  407.         return ERROR;
  408.           stohdr (v, v->Rxbytes);
  409.           zshhdr (v, ZACK);
  410.           sendbuf (v);
  411.           goto nxthdr;
  412.         case GOTCRCQ:    /* Sender says it's not waiting, */
  413.           /* but ACK anyway (rarely used) */
  414.           n = v->ErrorLimit;
  415.           if (putsec (v) == ERROR)
  416.         return ERROR;
  417.           stohdr (v, v->Rxbytes);
  418.           zshhdr (v, ZACK);
  419.           sendbuf (v);
  420.           goto moredata;
  421.         case GOTCRCG:    /* Sender says keep receiving, there's more coming */
  422.           n = v->ErrorLimit;
  423.           if (putsec (v) == ERROR)
  424.         return ERROR;
  425.           goto moredata;
  426.         case GOTCRCE:    /* Sender says this is the last packet */
  427.           n = v->ErrorLimit;
  428.           if (putsec (v) == ERROR)
  429.         return ERROR;
  430.           goto nxthdr;
  431.         }
  432.     }
  433.     }
  434. }                /* End of short rzfile() */
  435.  
  436. /**********************************************************
  437.  *      short procheader(struct Vars *v)
  438.  *
  439.  * Process file name & info packet; either open file and
  440.  * prepare to receive, or return ERROR if we should skip
  441.  * this one for some reason
  442.  **********************************************************/
  443. short
  444. procheader (struct Vars *v)
  445. {
  446.   struct SetupVars *sv;
  447.   UBYTE *p, *openmode, buff[PATHLEN];
  448.   long n;
  449.  
  450. #ifdef DEBUGLOG
  451.   D (DEBUGINFO);
  452. #endif
  453.  
  454.   openmode = "w";
  455.   v->Strtpos = 0;
  456.  
  457.   /* Extract expected filesize from file info packet, if given */
  458.   v->Fsize = -1;
  459.   p = strchr (v->Pktbuf, '\0') + 1;
  460.   if (*p)
  461.     v->Fsize = atol (p);
  462.   /*
  463.      * Make sure we have room for file; skip it if not.
  464.      * Commented out for now, since getfree() isn't implemented yet.
  465.      if (v->Fsize > getfree())
  466.      {
  467.      xprsprintf(v->Msgbuf, GetLocalString( &li, MSG_INSUFFICIENT_DISK_SPACE ),
  468.      v->Fsize, getfree());
  469.      upderr(v, v->Msgbuf);
  470.      v->Noroom = TRUE;
  471.      return ERROR;
  472.      }
  473.    */
  474.  
  475.   /* If option RY set, use full received file path */
  476.   sv = (void *) v->io.xpr_data;
  477.   if (*sv->option_r == 'Y')
  478.     strcpy (v->Filename, v->Pktbuf);
  479.   else
  480.     {
  481.       /* else use the default directory path specified in the setup options */
  482.       strcpy (v->Filename, sv->option_p);
  483.       p = v->Filename + strlen (v->Filename) - 1;
  484.       if (p >= v->Filename && *p != '/' && *p != ':')
  485.     *++p = '/';
  486.       *++p = '\0';
  487.       /*
  488.          * Append the filename from the file info packet; ignore anything before
  489.          * last /, \, or : in filename (received directory path is ignored)
  490.        */
  491.       p = strchr (v->Pktbuf, '\0');    /* start at end and scan back */
  492.       /* to start of name */
  493.       while (p >= v->Pktbuf && *p != '/' && *p != '\\' && *p != ':')
  494.     --p;
  495.       strcat (v->Filename, ++p);
  496.     }
  497.  
  498.   /* Display name of file being received for user */
  499.   v->xpru.xpru_updatemask = XPRU_FILENAME;
  500.   v->xpru.xpru_filename = (char *) v->Filename;
  501.   (*v->io.xpr_update) (&v->xpru);
  502.  
  503.   /*
  504.      * If a file with this name already exists, handle in
  505.      * accordance with O option
  506.    */
  507.   if (exist (v))
  508.     {
  509.       switch (*sv->option_o)
  510.     {
  511.     case 'N':        /* Don't overwrite; change name to prevent collision */
  512.       strcpy (buff, v->Filename);
  513.       strcat (v->Filename, ".dup");
  514.       n = 2;
  515.       while (exist (v))
  516.         {
  517.           xprsprintf (v->Filename, "%s.dup%ld", buff, n);
  518.           ++n;
  519.         }
  520.       /* Update filename display to show new name */
  521.       (*v->io.xpr_update) (&v->xpru);
  522.       break;
  523.     case 'R':        /* Resume transfer from current end of file */
  524.       openmode = "a";
  525.       v->Strtpos = (*v->io.xpr_finfo) (v->Filename, 1L);
  526.       break;
  527.     case 'S':        /* Skip it */
  528.       upderr (v, GetLocalString( &li, MSG_FILE_EXISTS ));
  529.       return ERROR;
  530.       /* Else 'Y', go ahead and overwrite it (openmode = w) */
  531.     }
  532.     }
  533.  
  534.   /* Set text/binary mode according to options before opening file */
  535.   set_textmode (v);
  536.  
  537.   /*
  538.      * Figure out file translation mode to use; either binary (verbatim
  539.      * transfer) or ASCII (perform end-of-line conversions).  If user has
  540.      * specified a mode (TY or TN), that's what we use.  If user says use
  541.      * sender's suggestion (T?), set mode according to Zconv flag.  If neither
  542.      * side specifies, default to binary mode.
  543.    */
  544.   v->Thisbinary = v->Rxbinary || !v->Rxascii;
  545.   if (!v->Rxbinary && v->Zconv == ZCNL)
  546.     v->Thisbinary = FALSE;
  547.   if (!v->Rxascii && v->Zconv == ZCBIN)
  548.     v->Thisbinary = TRUE;
  549.  
  550.   /* Open the file (finally) */
  551.   if (!(v->File = bfopen (v, openmode)))
  552.     {
  553.       ++v->Errcnt;
  554.       upderr (v, GetLocalString( &li, MSG_CANT_OPEN_FILE ));
  555.       return ERROR;
  556.     }
  557.   getsystime (&v->Starttime);
  558.  
  559.   /* Initialize comm program transfer status display */
  560.   v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  561.     | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  562.     | XPRU_BYTES | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE;
  563.   v->xpru.xpru_protocol = "ZModem";
  564.   v->xpru.xpru_filesize = v->Fsize;
  565.   v->xpru.xpru_msg = (v->Thisbinary) ? GetLocalString( &li, MSG_RECEIVE_BINARY )
  566.     : GetLocalString( &li, MSG_RECEIVE_TEXT );
  567.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  568.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  569.   v->xpru.xpru_bytes = v->Strtpos;
  570.   update_rate (v);
  571.   (*v->io.xpr_update) (&v->xpru);
  572.  
  573. #ifdef DEBUGLOG
  574.   D (DEBUGINFO);
  575. #endif
  576.  
  577.   return OK;
  578. }                /* End of short procheader() */
  579.  
  580. /**********************************************************
  581.  *      short putsec(struct Vars *v)
  582.  *
  583.  * Writes the received file data to the output file.
  584.  * If in ASCII mode, stops writing at first ^Z, and converts all
  585.  * \r\n pairs or solo \r's to \n's.
  586.  **********************************************************/
  587. short
  588. putsec (struct Vars *v)
  589. {
  590.   static char nl = '\n';
  591.   UBYTE *p;
  592.   short n;
  593.  
  594. #ifdef DEBUGLOG
  595.   D (DEBUGINFO);
  596. #endif
  597.  
  598.   /* If in binary mode, write it out verbatim */
  599.   if (v->Thisbinary)
  600.     {
  601.       if (bfwrite (v, v->Pktbuf, (long) v->Rxcount) != v->Rxcount)
  602.     goto diskfull;
  603.       /* If in text mode, perform end-of-line cleanup */
  604.     }
  605.   else
  606.     {
  607.       if (v->Eofseen)
  608.     return OK;
  609.       for (p = v->Pktbuf, n = v->Rxcount; --n >= 0; ++p)
  610.     {
  611.       if (*p == CPMEOF)
  612.         {
  613.           v->Eofseen = TRUE;
  614.           return OK;
  615.         }
  616.       else if (*p != '\n' && v->Lastsent == '\r')
  617.         {
  618.           if (bfwrite (v, &nl, 1L) != 1)
  619.         goto diskfull;
  620.         }
  621.       if (*p != '\r' && bfwrite (v, p, 1L) != 1)
  622.         goto diskfull;
  623.       v->Lastsent = *p;
  624.     }
  625.     }
  626.  
  627.   /* Update comm program status display */
  628.   v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  629.     | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE | XPRU_BLOCKCHECK;
  630.   ++v->xpru.xpru_blocks;
  631.   v->xpru.xpru_blocksize = v->Rxcount;
  632.   v->xpru.xpru_bytes = v->Rxbytes += v->Rxcount;
  633.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  634.   update_rate (v);
  635.   (*v->io.xpr_update) (&v->xpru);
  636.  
  637.   return OK;
  638.  
  639. diskfull:
  640.   upderr (v, GetLocalString( &li, MSG_ERROR_WRITING_FILE ));
  641.   v->Noroom = TRUE;
  642.   return ERROR;
  643. }                /* End of short putsec() */
  644.  
  645. /**********************************************************
  646.  *      void ackbibi(struct Vars *v)
  647.  *
  648.  * End of batch transmission; disengage cleanly from sender
  649.  **********************************************************/
  650. void
  651. ackbibi (struct Vars *v)
  652. {
  653.   short n;
  654.  
  655. #ifdef DEBUGLOG
  656.   dlog (v, "ackbibi:\n");
  657.   D (DEBUGINFO);
  658. #endif
  659.   stohdr (v, 0L);
  660.   for (n = 4; --n;)
  661.     {
  662.       zshhdr (v, ZFIN);
  663.       sendbuf (v);
  664.       switch (readock (v, 100))
  665.     {
  666.     case 'O':
  667.       readock (v, 1);    /* Discard 2nd 'O' */
  668.     case TIMEOUT:
  669.     case RCDO:
  670.       return;
  671.     }
  672.     }
  673. }                /* End of void ackbibi() */
  674. /* End of Receive.c source */
  675.