home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / dirs / xprzmodem_459.lzh / XprZmodem / receive.c < prev    next >
C/C++ Source or Header  |  1991-02-18  |  16KB  |  506 lines

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