home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 300.lha / xprzmodem.library_v2.0 / send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1980-12-01  |  12.9 KB  |  468 lines

  1. /*  Send.c: File transmission routines for xprzmodem.library;
  2.     Version 2.0, 28 October 1989, by Rick Huebner.
  3.     Based closely on Chuck Forsberg's sz.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 <string.h>
  13. #include "xproto.h"
  14. #include "zmodem.h"
  15. #include "xprzmodem.h"
  16.  
  17. #ifdef DEBUGLOG
  18. extern long DebugLog;
  19. #endif
  20.  
  21.  
  22.  
  23. /* Main file transmission routine; called by comm program */
  24. long  __saveds XProtocolSend(struct XPR_IO *io) {
  25.   struct Vars *v;
  26.   short err;
  27.  
  28.   /* Perform common setup and initializations */
  29.   if (!(v = setup(io))) return XPRS_FAILURE;
  30.   v->Rxtimeout = 300;
  31.  
  32.   /* Transfer the files */  
  33.   zmputs(v,"rz\r");
  34.   stohdr(v,0L);
  35.   zshhdr(v,ZRQINIT);
  36.   if (getzrxinit(v) == ERROR) upderr(v,"Upload cancelled or timed out");
  37.   else sendbatch(v);
  38.  
  39.   /* Clean up and return */
  40.   if (err = v->Errcnt) upderr(v,"One or more files skipped due to errors");
  41.   else updmsg(v,"Done.");
  42.   if (v->io.xpr_setserial) (*v->io.xpr_setserial)(v->Oldstatus);
  43.   FreeMem(v->Filebuf,v->Filebufmax);
  44.   FreeMem(v,(long)sizeof(struct Vars));
  45.   
  46. #ifdef DEBUGLOG
  47.   if (DebugLog) {
  48.     (*v->io.xpr_fclose)(DebugLog);
  49.     DebugLog = NULL;
  50.   }
  51. #endif
  52.  
  53.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  54. }
  55.  
  56.  
  57.  
  58. /* Negotiate with receiver to start a file transfer */
  59. short getzrxinit(struct Vars *v) {
  60.   short n;
  61.  
  62.   for (n=10; --n>=0; ) {
  63.     switch (zgethdr(v)) {
  64.       case ZCHALLENGE:        /* Echo receiver's challenge number */
  65.         stohdr(v,v->Rxpos);
  66.         zshhdr(v,ZACK);
  67.         continue;
  68.       case ZCOMMAND:          /* They didn't see our ZRQINIT; try again */
  69.         stohdr(v,0L);
  70.         zshhdr(v,ZRQINIT);
  71.         continue;
  72.       case ZRINIT:            /* Receiver ready; get transfer parameters */
  73.         v->Rxbuflen = ((USHORT)v->Rxhdr[ZP1]<<8) | v->Rxhdr[ZP0];
  74. #ifdef DEBUGLOG
  75.         sprintf(v->Msgbuf,"Rxbuflen=%ld Tframlen=%ld\n",(long)v->Rxbuflen,(long)v->Tframlen);
  76.         dlog(v,v->Msgbuf);
  77. #endif
  78.         /* Use shortest of the two side's max frame lengths */
  79.         if (v->Tframlen && (!v->Rxbuflen || v->Tframlen < v->Rxbuflen))
  80.           v->Rxbuflen = v->Tframlen;
  81. #ifdef DEBUGLOG
  82.         sprintf(v->Msgbuf,"Rxbuflen=%ld\n",(long)v->Rxbuflen);
  83.         dlog(v,v->Msgbuf);
  84. #endif
  85.         return OK;
  86.       case ZCAN:
  87.       case RCDO:
  88.       case TIMEOUT:
  89.         return ERROR;
  90.       case ZRQINIT:
  91.         if (v->Rxhdr[ZF0] == ZCOMMAND) continue;
  92.         /* fallthrough... */
  93.       default:
  94.         zshhdr(v,ZNAK);
  95.         continue;
  96.     }
  97.   }
  98.   return ERROR;
  99. }
  100.  
  101.  
  102.  
  103. /* Send a batch of files */
  104. void sendbatch(struct Vars *v) {
  105.   UBYTE single, done = FALSE;
  106.   long fstate;
  107.  
  108.   /* If template routines not provided, must be single filename */
  109.   if (!v->io.xpr_ffirst || !v->io.xpr_fnext) {
  110.     single = TRUE;
  111.     strcpy(v->Filename,v->io.xpr_filename);
  112.   /* Else use the template routines to get the first filename */
  113.   } else {
  114.     single = FALSE;
  115.     fstate = (*v->io.xpr_ffirst)(v->Filename,v->io.xpr_filename);
  116.     if (!fstate) {
  117.       upderr(v,"No files match template");
  118.       return;
  119.     }
  120.   }
  121.  
  122.   /* If using templates, keep getting names & sending until done */
  123.   while (!done) {
  124.     if (sendone(v) == ERROR) return;
  125.     if (single) break;
  126.     fstate = (*v->io.xpr_fnext)(fstate,v->Filename,v->io.xpr_filename);
  127.     done = !fstate;
  128.   }
  129.  
  130.   /* End batch and return; if we never got started, just cancel receiver */
  131.   if (v->Filcnt) saybibi(v);
  132.   else canit(v);
  133. }
  134.  
  135.  
  136.  
  137. /* Send the file named in v->Filename */
  138. short sendone(struct Vars *v) {
  139.   struct SetupVars *sv;
  140.  
  141. #ifdef DEBUGLOG
  142.   sprintf(v->Msgbuf,"*** Sending %s\n",v->Filename);
  143.   dlog(v,v->Msgbuf);
  144. #endif
  145.  
  146.   /* Display name of file being sent for user */
  147.   v->xpru.xpru_updatemask = XPRU_FILENAME;
  148.   v->xpru.xpru_filename = v->Filename;
  149.   (*v->io.xpr_update)(&v->xpru);
  150.  
  151.   /* Set text/binary mode according to options before opening file */
  152.   set_textmode(v);
  153.  
  154.   /* Open the file, if possible */
  155.   if (!(v->File = bfopen(v,"r"))) {
  156.     ++v->Errcnt;
  157.     upderr(v,"Can't open file; skipping");
  158.     return OK;      /* pass over it, there may be others */
  159.   }
  160.   ++v->Filcnt;
  161.   v->Starttime = GetSysTime(NULL);
  162.  
  163.   /* Kick off the file transfer */
  164.   sv = v->io.xpr_data;
  165.   switch (sendname(v)) {
  166.     case ERROR:
  167.       ++v->Errcnt;
  168.       return ERROR;
  169.     case OK:
  170.       bfclose(v);
  171.       /* File sent; if option DY, delete file after sending */
  172.       if (*sv->option_d == 'Y' && v->io.xpr_extension >= 2 && v->io.xpr_unlink) {
  173.         updmsg(v,"Deleting file after send");
  174.         (*v->io.xpr_unlink)(v->Filename);
  175.       }
  176.       break;
  177.   }
  178.   return OK;
  179. }
  180.  
  181.  
  182.  
  183. /* Build file info block consisting of file name, length, time, and mode */
  184. short sendname(struct Vars *v) {
  185.   struct SetupVars *sv;
  186.   UBYTE *p, *q;
  187.  
  188.   /* Initialize comm program transfer status display */
  189.   v->Fsize =  (v->io.xpr_finfo) ? (*v->io.xpr_finfo)(v->Filename,1L) : -1;
  190.   v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG | XPRU_BLOCKS |
  191.                             XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK | XPRU_BYTES |
  192.                             XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE;
  193.   v->xpru.xpru_protocol = "ZModem";
  194.   v->xpru.xpru_filesize = v->Fsize;
  195.   v->xpru.xpru_msg = (v->Lzconv == ZCNL) ? "Sending text file..." :
  196.     ( (v->Lzconv == ZCBIN) ? "Sending binary file..." : "Sending file...");
  197.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  198.   v->xpru.xpru_blockcheck = "CRC-16";
  199.   v->xpru.xpru_bytes = v->Strtpos = 0;
  200.   update_rate(v);
  201.   (*v->io.xpr_update)(&v->xpru);
  202.  
  203.   sv = v->io.xpr_data;
  204.   if (*sv->option_s == 'Y') {
  205.     /* If "SY" option selected, send full path */
  206.     strcpy(v->Pktbuf,v->Filename);
  207.     p = v->Pktbuf + strlen(v->Pktbuf) + 1;
  208.   } else {
  209.     /* else extract outgoing file name without directory path */
  210.     for (p=v->Filename, q=v->Pktbuf ; *p; ++p, ++q)
  211.       if ((*q = *p) == '/' || *q == ':') q = v->Pktbuf - 1;
  212.     *q = '\0';
  213.     p = ++q;
  214.   }
  215.  
  216.   /* Zero out remainder of file info packet */
  217.   memset(p,0,sizeof(v->Pktbuf) - (p - v->Pktbuf));
  218.  
  219.   /* Store file size, timestamp, and mode in info packet */
  220.   /* XPR spec doesn't provide a way to get the file timestamp or file mode,
  221.      so we'll just fake it with the current time and a dummy 0. */
  222.   sprintf(p,"%lu %lo 0",(v->Fsize < 0) ? 0L : v->Fsize,GetSysTime(NULL)+UnixTimeOffset);
  223.                 /* ^Yes, octal; Forsberg likes octal, don't ask me why */
  224.  
  225.   /* Send filename packet */
  226.   return zsendfile(v,(short)(p - v->Pktbuf + strlen(p) + 1));
  227. }
  228.  
  229.  
  230.  
  231. /* Send the filename packet and see if receiver will accept file */
  232. short zsendfile(struct Vars *v,short blen) {
  233.   short c;
  234.  
  235.   while (TRUE) {
  236.     v->Txhdr[ZF0] = v->Lzconv; /* Text or Binary mode; from config string */
  237.     v->Txhdr[ZF1] = LZMANAG;   /* Default file management mode */
  238.     v->Txhdr[ZF2] = LZTRANS;   /* Default file transport mode */
  239.     v->Txhdr[ZF3] = 0;
  240.     zsbhdr(v,ZFILE);
  241.     zsdata(v,blen,ZCRCW);
  242. again:
  243.     switch (c = zgethdr(v)) {
  244.       case ZRINIT:
  245.         goto again;
  246.       case ZCAN:
  247.       case ZCRC:
  248.       case RCDO:
  249.       case TIMEOUT:
  250.       case ZABORT:
  251.       case ZFIN:
  252.         return ERROR;
  253.       case ZSKIP:             /* Receiver doesn't want this one */
  254.         upderr(v,"SKIP command received");
  255.         bfclose(v);
  256.         return c;
  257.       case ZRPOS:             /* Receiver wants it; this is starting position */
  258.         bfseek(v,v->Rxpos);
  259.         v->Strtpos = v->Txpos = v->Rxpos;
  260.         if (v->io.xpr_sflush) (*v->io.xpr_sflush)();
  261.         v->Modemcount = 0;
  262.         return zsendfdata(v);
  263.     }
  264.   }
  265. }
  266.  
  267.  
  268.  
  269. /* Send the file data */
  270. short zsendfdata(struct Vars *v) {
  271.   short c, e, blklen, goodbytes = 0;
  272.   USHORT framelen, maxblklen, goodneeded = 512;
  273.  
  274.   /* Figure out max data packet size to send */
  275.   maxblklen = KSIZE;
  276.   if (v->Rxbuflen && maxblklen > v->Rxbuflen) maxblklen = v->Rxbuflen;
  277.   blklen = (v->Baud < 1200) ? 256 : KSIZE;
  278.   if (blklen > maxblklen) blklen = maxblklen;
  279. #ifdef DEBUGLOG
  280.   sprintf(v->Msgbuf,"Rxbuflen=%ld blklen=%ld\n",(long)v->Rxbuflen,(long)blklen);
  281.   dlog(v,v->Msgbuf);
  282. #endif
  283.  
  284.   /* If an interruption happened, handle it; else keep sending data */
  285. somemore:
  286.   if (char_avail(v)) {
  287. waitack:
  288. #ifdef DEBUGLOG
  289.     dlog(v,"--- At waitack\n");
  290. #endif
  291.     switch (c = getinsync(v)) {
  292.       default:
  293.         upderr(v,"Transfer cancelled");
  294.         bfclose(v);
  295.         return ERROR;
  296.       case ZSKIP:  /* Receiver changed its mind and wants to skip the file */
  297.         return c;
  298.       case ZACK:   /* ACK at end of frame; resume sending data */
  299.         break;
  300.       case ZRPOS:  /* An error; resend data from last good point */
  301.         blklen >>= 2;
  302.         if (blklen < MINBLOCK) blklen = MINBLOCK;
  303.         if (goodneeded < MAXGOODNEEDED) goodneeded <<= 1;
  304.         v->xpru.xpru_updatemask = XPRU_ERRORS;
  305.         ++v->xpru.xpru_errors;
  306.         (*v->io.xpr_update)(&v->xpru);
  307.         break;
  308.       case ZRINIT:
  309.         updmsg(v,"Done.");
  310.         return OK;
  311.     }
  312.     /* Check for another incoming packet while discarding line noise */
  313.     while (char_avail(v)) {
  314.       switch (readock(v,1)) {
  315.         case CAN:
  316.         case RCDO:
  317.         case ZPAD:
  318.           goto waitack;
  319.       }
  320.     }
  321.   }
  322.  
  323.   /* Transmit ZDATA frame header */
  324.   framelen = v->Rxbuflen;
  325.   stohdr(v,v->Txpos);
  326.   zsbhdr(v,ZDATA);
  327.  
  328.   /* Keep sending data packets until finished or interrupted */
  329.   do {
  330.     /* Read next chunk of file data */
  331.     c = bfread(v,v->Pktbuf,(long)blklen);
  332.  
  333.     /* Figure out how to handle this data packet */
  334.     if (c < blklen) e = ZCRCE;   /* If end of file, this is last data packet */
  335.     else if (v->Rxbuflen && (framelen -= c) <= 0) e = ZCRCW; /* If end of frame, ask for ACK */
  336.     else e = ZCRCG;  /* Else tell receiver to expect more data packets */
  337.  
  338.     zsdata(v,c,e);  /* Send the packet */
  339.  
  340.     /* Update comm program status display */
  341.     v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES |
  342.                               XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE;
  343.     ++v->xpru.xpru_blocks;
  344.     v->xpru.xpru_blocksize = c;
  345.     v->xpru.xpru_bytes = v->Txpos += c;
  346.     update_rate(v);
  347.     (*v->io.xpr_update)(&v->xpru);
  348.  
  349.     /* If we've been sending smaller than normal packets, see if it's
  350.        time to bump the packet size up a notch yet */
  351.     if (blklen < maxblklen && (goodbytes += c) >= goodneeded) {
  352.       blklen <<= 1;
  353.       if (blklen > maxblklen) blklen = maxblklen;
  354.       goodbytes = 0;
  355. #ifdef DEBUGLOG
  356.       sprintf(v->Msgbuf,"Bumping packet size to %ld at %ld\n",(long)blklen,v->Txpos);
  357.       dlog(v,v->Msgbuf);
  358. #endif
  359.     }
  360.  
  361.     /* Give comm program its timeslice if it needs one */
  362.     if (v->io.xpr_chkmisc) (*v->io.xpr_chkmisc)();
  363.     /* Check for abort from comm program */
  364.     if (v->io.xpr_chkabort && (*v->io.xpr_chkabort)()) goto aborted;
  365.     /* If this was last packet in frame, go wait for ACK from receiver */
  366.     if (e == ZCRCW) goto waitack;
  367.  
  368.     /* Check if receiver trying to interrupt us; look for incoming packet
  369.        while discarding line noise */
  370.     while (char_avail(v)) {
  371.       switch (readock(v,1)) {
  372.         case CAN:
  373.         case RCDO:
  374.         case ZPAD:
  375.           /* Interruption detected; stop sending and process complaint */
  376. #ifdef DEBUGLOG
  377.           dlog(v,"--- Interrupted send\n");
  378. #endif
  379.           zsdata(v,0,ZCRCE);
  380.           goto waitack;
  381.       }
  382.     }
  383.   } while (e == ZCRCG);  /* If no interruption, keep sending data packets */
  384.  
  385.   /* Done sending file data; send EOF and wait for receiver to acknowledge */
  386.   while (TRUE) {
  387.     updmsg(v,"Sending EOF");
  388.     stohdr(v,v->Txpos);
  389.     zsbhdr(v,ZEOF);
  390.     switch (c = getinsync(v)) {
  391.       case ZACK:
  392.         continue;
  393.       case ZRPOS:
  394.         goto somemore;
  395.       case ZRINIT:
  396.         updmsg(v,"EOF acknowledged");
  397.         return OK;
  398.       case ZSKIP:
  399.         return c;
  400.       default:
  401. aborted: upderr(v,"Transfer cancelled");
  402.         bfclose(v);
  403.         return ERROR;
  404.     }
  405.   }
  406. }
  407.  
  408.  
  409.  
  410. /* Respond to receiver's complaint, get back in sync with receiver */
  411. short getinsync(struct Vars *v) {
  412.   short c;
  413.  
  414.   while (TRUE) {
  415. #ifdef DEBUGLOG
  416.     dlog(v,"--- At getinsync\n");
  417. #endif
  418.     c = zgethdr(v);
  419.     if (v->io.xpr_sflush) (*v->io.xpr_sflush)();
  420.     v->Modemcount = 0;
  421.     switch (c) {
  422.       case ZCAN:
  423.       case ZABORT:
  424.       case ZFIN:
  425.       case RCDO:
  426.       case TIMEOUT:
  427.         return ERROR;
  428.       case ZRPOS:
  429.         bfseek(v,v->Rxpos);
  430.         v->Txpos = v->Rxpos;
  431.         sprintf(v->Msgbuf,"Resending from %ld",v->Txpos);
  432.         upderr(v,v->Msgbuf);
  433.         return c;
  434.       case ZSKIP:
  435.         upderr(v,"SKIP command received");
  436.         /* fallthrough... */
  437.       case ZRINIT:
  438.         bfclose(v);
  439.         /* fallthrough... */
  440.       case ZACK:
  441.         return c;
  442.       default:
  443.         zsbhdr(v,ZNAK);
  444.         continue;
  445.     }
  446.   }
  447. }
  448.  
  449.  
  450.  
  451. /* End of batch transmission; disengage cleanly from receiver */
  452. void saybibi(struct Vars *v) {
  453.   while (TRUE) {
  454.     stohdr(v,0L);
  455.     zsbhdr(v,ZFIN);
  456.     switch (zgethdr(v)) {
  457.       case ZFIN:
  458.         sendline(v,'O');
  459.         sendline(v,'O');
  460.         /* fallthrough... */
  461.       case ZCAN:
  462.       case RCDO:
  463.       case TIMEOUT:
  464.         return;
  465.     }
  466.   }
  467. }
  468.