home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 592b.lha / XprZmodem_v2.50 / Send.c < prev    next >
C/C++ Source or Header  |  1991-11-19  |  17KB  |  602 lines

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