home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- * Send.c: File transmission routines for xprzmodem.library;
- * Original Version 2.10, 12 February 1991, by Rick Huebner.
- * Based closely on Chuck Forsberg's sz.c example ZModem code,
- * but too pervasively modified to even think of detailing the changes.
- * Released to the Public Domain; do as you like with this code.
- *
- * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
- *
- * Version 2.51 29, January 1992, RX_timout fix by John Tillema
- **********************************************************************/
-
- #include <proto/all.h>
- #include <exec/types.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
- #include "xproto.h"
- #include "zmodem.h"
- #include "xprzmodem.h"
-
- #ifdef DEBUGLOG
- extern void *DebugLog;
- #endif
-
- /**********************************************************
- * long XProtocolSend(struct XPR_IO *xio)
- *
- * Main file transmission routine; called by comm program
- **********************************************************/
- long __saveds __asm XProtocolSend(register __a0 struct XPR_IO *xio)
- {
- struct Vars *v;
- short err;
-
- /* Perform common setup and initializations */
- if (! (v = setup(xio)) )
- return XPRS_FAILURE;
-
- /* was 600, set to 300 to fix so it uploads correctly */
- v->Rxtimeout = 300;
- v->Wantfcs32 = TRUE;
- v->Rxflags = 0;
-
- /* Transfer the files */
- zmputs(v, "rz\r");
- stohdr(v, 0L);
- zshhdr(v, ZRQINIT);
- sendbuf(v);
- if (getzrxinit(v) == ERROR)
- upderr(v, "Upload cancelled or timed out");
- else
- sendbatch(v);
-
- /* Clean up and return */
- if (err = v->Errcnt)
- upderr(v, "One or more files skipped due to errors");
- else
- updmsg(v, "Done.");
- if (v->io.xpr_setserial && v->Oldstatus != -1)
- (*v->io.xpr_setserial)(v->Oldstatus);
- FreeMem(v->Filebuf, v->Filebufmax);
- FreeMem(v, (long) sizeof(struct Vars));
-
- #ifdef DEBUGLOG
- if (DebugLog)
- {
- xpr_fclose(&v->io, DebugLog);
- DebugLog = NULL;
- }
- #endif
- return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
- } /* End of long XProtocolSend() */
-
- /**********************************************************
- * short getzrxinit(struct Vars *v)
- *
- * Negotiate with receiver to start a file transfer
- **********************************************************/
- short getzrxinit(struct Vars *v)
- {
- short n;
-
- for (n = v->ErrorLimit; --n >= 0; )
- {
- /* Check for abort from comm program */
- if (v->io.xpr_chkabort && (*v->io.xpr_chkabort)())
- return ERROR;
- switch (zgethdr(v))
- {
- case ZCHALLENGE: /* Echo receiver's challenge number */
- stohdr(v, v->Rxpos);
- zshhdr(v, ZACK);
- sendbuf(v);
- continue;
- case ZCOMMAND: /* They didn't see our ZRQINIT; try again */
- stohdr(v, 0L);
- zshhdr(v, ZRQINIT);
- sendbuf(v);
- continue;
- case ZRINIT: /* Receiver ready; get transfer parameters */
- v->Rxflags = 0xFF & v->Rxhdr[ZF0];
- v->Txfcs32 = (v->Wantfcs32 && (v->Rxflags & CANFC32));
- v->Rxbuflen = ((USHORT) v->Rxhdr[ZP1] << 8) | v->Rxhdr[ZP0];
- #ifdef DEBUGLOG
- mysprintf(v->Msgbuf, "Txfcs32=%ld Rxbuflen=%ld Tframlen=%ld\n",
- (long) v->Txfcs32, (long) v->Rxbuflen, (long) v->Tframlen);
- dlog(v, v->Msgbuf);
- #endif
- /* Use shortest of the two side's max frame lengths */
- if (v->Tframlen && (! v->Rxbuflen || v->Tframlen < v->Rxbuflen))
- v->Rxbuflen = v->Tframlen;
- #ifdef DEBUGLOG
- mysprintf(v->Msgbuf, "Rxbuflen=%ld\n", (long) v->Rxbuflen);
- dlog(v, v->Msgbuf);
- #endif
- return OK;
- case ZCAN:
- case RCDO:
- case TIMEOUT:
- upderr(v, v->Msgbuf);
- return ERROR;
- case ZRQINIT:
- if (v->Rxhdr[ZF0] == ZCOMMAND)
- continue;
- /* fallthrough... */
- default:
- zshhdr(v, ZNAK);
- sendbuf(v);
- continue;
- }
- }
- return ERROR;
- } /* End of short getzrxinit() */
-
- /**********************************************************
- * void sendbatch(struct Vars *v)
- *
- * Send a batch of files
- **********************************************************/
- void sendbatch(struct Vars *v)
- {
- UBYTE single, done = FALSE;
- long fstate;
-
- /* If template routines not provided, must be single filename */
- if (! v->io.xpr_ffirst || ! v->io.xpr_fnext)
- {
- single = TRUE;
- strcpy(v->Filename, v->io.xpr_filename);
- /* Else use the template routines to get the first filename */
- }
- else
- {
- single = FALSE;
- fstate = (*v->io.xpr_ffirst)(v->Filename, v->io.xpr_filename);
- if (! fstate)
- {
- upderr(v, "No files match template");
- return;
- }
- }
-
- /* If using templates, keep getting names & sending until done */
- while (! done)
- {
- if (sendone(v) == ERROR)
- return;
- if (single)
- break;
- fstate = (*v->io.xpr_fnext)(fstate, v->Filename, v->io.xpr_filename);
- done = ! fstate;
- }
-
- /* End batch and return; if we never got started, just cancel receiver */
- if (v->Filcnt)
- saybibi(v);
- else
- canit(v);
- } /* End of void sendbatch() */
-
- /**********************************************************
- * short sendone(struct Vars *v)
- *
- * Send the file named in v->Filename
- **********************************************************/
- short sendone(struct Vars *v)
- {
- struct SetupVars *sv;
-
- #ifdef DEBUGLOG
- mysprintf(v->Msgbuf, "*** Sending %s\n", v->Filename);
- dlog(v, v->Msgbuf);
- #endif
-
- /* Display name of file being sent for user */
- v->xpru.xpru_updatemask = XPRU_FILENAME;
- v->xpru.xpru_filename = v->Filename;
- (*v->io.xpr_update)(&v->xpru);
-
- /* Set text/binary mode according to options before opening file */
- set_textmode(v);
-
- /* Open the file, if possible */
- if (! (v->File = bfopen(v, "r")))
- {
- ++v->Errcnt;
- upderr(v, "Can't open file; skipping");
- return OK; /* pass over it, there may be others */
- }
- ++v->Filcnt;
- getsystime(&v->Starttime);
-
- /* Kick off the file transfer */
- sv = (void *) v->io.xpr_data;
- switch (sendname(v))
- {
- case ERROR:
- ++v->Errcnt;
- return ERROR;
- case OK:
- bfclose(v);
- /* File sent; if option DY, delete file after sending */
- if (*sv->option_d == 'Y' && v->io.xpr_extension >= 2 && v->io.xpr_unlink)
- {
- updmsg(v, "Deleting file after send");
- (*v->io.xpr_unlink)(v->Filename);
- }
- break;
- }
- return OK;
- } /* End of short sendone() */
-
- /**********************************************************
- * short sendname(struct Vars *v)
- *
- * Build file info block consisting of file name, length,
- * time, and mode
- **********************************************************/
- short sendname(struct Vars *v)
- {
- struct SetupVars *sv;
- UBYTE *p, *q, buff [32];
-
- /* Initialize comm program transfer status display */
- v->Fsize = (v->io.xpr_finfo) ? (*v->io.xpr_finfo)(v->Filename, 1L) : -1;
- v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
- | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
- | XPRU_BYTES | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE;
- v->xpru.xpru_protocol = "ZModem";
- v->xpru.xpru_filesize = v->Fsize;
- v->xpru.xpru_msg = (v->Lzconv == ZCNL) ? "Sending text file..." :
- ( (v->Lzconv == ZCBIN) ? "Sending binary file..." : "Sending file...");
- v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
- v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
- v->xpru.xpru_bytes = v->Strtpos = 0;
- update_rate(v);
- (*v->io.xpr_update)(&v->xpru);
-
- sv = (void *) v->io.xpr_data;
- if (*sv->option_s == 'Y')
- {
- /* If "SY" option selected, send full path */
- strcpy(v->Pktbuf, v->Filename);
- p = v->Pktbuf + strlen(v->Pktbuf) + 1;
- }
- else
- {
- /* else extract outgoing file name without directory path */
- for (p = v->Filename, q = v->Pktbuf ; *p; ++p, ++q)
- if ((*q = *p) == '/' || *q == ':')
- q = v->Pktbuf - 1;
- *q = '\0';
- p = ++q;
- }
-
- /* Zero out remainder of file info packet */
- memset(p, 0, sizeof(v->Pktbuf) - (p - v->Pktbuf));
-
- /* Store file size, timestamp, and mode in info packet */
- /*
- * XPR spec doesn't provide a way to get the file timestamp or file mode,
- * so we'll just fake it with the current time and a dummy 0.
- */
- stcl_o(buff, getsystime(NULL) + UnixTimeOffset);
- /* amiga.lib mysprintf() can't do %lo format, so we do it the hard way */
- /* Yes, octal; ZModem was originally done on Unix, and they like octal there */
- mysprintf(p, "%ld %s 0", (v->Fsize < 0) ? 0L : v->Fsize,buff);
-
- /* Send filename packet */
- return zsendfile(v, (short) (p - v->Pktbuf + strlen(p) + 1));
- } /* End of short sendname() */
-
- /**********************************************************
- * short zsendfile(struct Vars *v, short blen)
- *
- * Send the filename packet and see if receiver will accept
- * file
- **********************************************************/
- short zsendfile(struct Vars *v, short blen)
- {
- short c;
-
- while (TRUE)
- {
- v->Txhdr[ZF0] = v->Lzconv; /* Text or Binary mode; from config string */
- v->Txhdr[ZF1] = LZMANAG; /* Default file management mode */
- v->Txhdr[ZF2] = LZTRANS; /* Default file transport mode */
- v->Txhdr[ZF3] = 0;
- zsbhdr(v, ZFILE);
- zsdata(v, blen, ZCRCW);
- sendbuf(v);
- again:
- /* Check for abort from comm program */
- if (v->io.xpr_chkabort && (*v->io.xpr_chkabort)())
- {
- bfclose(v);
- return ERROR;
- }
- switch (c = zgethdr(v))
- {
- case ZRINIT:
- goto again;
- case ZCAN:
- case ZCRC:
- case RCDO:
- case TIMEOUT:
- case ZABORT:
- case ZFIN:
- upderr(v, v->Msgbuf);
- return ERROR;
- case ZSKIP: /* Receiver doesn't want this one */
- upderr(v, "SKIP command received");
- bfclose(v);
- return c;
- case ZRPOS: /* Receiver wants it; this is starting position */
- bfseek(v, v->Rxpos);
- v->Strtpos = v->Txpos = v->Rxpos;
- if (v->io.xpr_sflush)
- (*v->io.xpr_sflush)();
- v->Modemcount = 0;
- return zsendfdata(v);
- }
- }
- } /* End of short zsendfile() */
-
- /**********************************************************
- * short zsendfdata(struct Vars *v)
- *
- * Send the file data
- **********************************************************/
- short zsendfdata(struct Vars *v)
- {
- short c, e, blklen, goodbytes = 0;
- USHORT framelen, maxblklen, goodneeded = 512;
-
- /* Figure out max data packet size to send */
- maxblklen = KSIZE;
- if (v->Rxbuflen && maxblklen > v->Rxbuflen)
- maxblklen = v->Rxbuflen;
- blklen = (v->Baud < 1200) ? 256 : KSIZE;
- if (blklen > maxblklen)
- blklen = maxblklen;
- #ifdef DEBUGLOG
- mysprintf(v->Msgbuf, "Rxbuflen=%ld blklen=%ld\n", (long) v->Rxbuflen,
- (long) blklen);
- dlog(v, v->Msgbuf);
- #endif
-
- /* If an interruption happened, handle it; else keep sending data */
- somemore:
- while (char_avail(v))
- {
- /* Check for another incoming packet while discarding line noise */
- switch (readock(v, 1))
- {
- case CAN:
- case RCDO:
- case ZPAD:
- break;
- default:
- continue;
- }
- waitack:
- #ifdef DEBUGLOG
- dlog(v, "--- At waitack\n");
- #endif
- switch (c = getinsync(v))
- {
- default:
- upderr(v, "Transfer cancelled");
- bfclose(v);
- return ERROR;
- case ZSKIP: /* Receiver changed its mind and wants to skip the file */
- return c;
- case ZACK: /* ACK at end of frame; resume sending data */
- break;
- case ZRPOS: /* An error; resend data from last good point */
- blklen >>= 2;
- if (blklen < MINBLOCK)
- blklen = MINBLOCK;
- if (goodneeded < MAXGOODNEEDED)
- goodneeded <<= 1;
- v->xpru.xpru_updatemask = XPRU_ERRORS;
- ++v->xpru.xpru_errors;
- (*v->io.xpr_update)(&v->xpru);
- break;
- case ZRINIT:
- updmsg(v, "Done.");
- return OK;
- }
- }
-
- /* Transmit ZDATA frame header */
- framelen = v->Rxbuflen;
- stohdr(v, v->Txpos);
- zsbhdr(v, ZDATA);
-
- /* Keep sending data packets until finished or interrupted */
- do
- {
- /* Read next chunk of file data */
- c = bfread(v, v->Pktbuf, (long) blklen);
-
- /* Figure out how to handle this data packet */
- if (c < blklen)
- e = ZCRCE; /* If end of file, this is last data packet */
- else if (v->Rxbuflen && (framelen -= c) <= 0)
- e = ZCRCW; /* If end of frame, ask for ACK */
- else
- e = ZCRCG; /* Else tell receiver to expect more data packets */
-
- zsdata(v, c, e); /* Send the packet */
- sendbuf(v);
-
- /* Update comm program status display */
- v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
- | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE
- | XPRU_BLOCKCHECK;
- ++v->xpru.xpru_blocks;
- v->xpru.xpru_blocksize = c;
- v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
- v->xpru.xpru_bytes = v->Txpos += c;
- update_rate(v);
- (*v->io.xpr_update)(&v->xpru);
-
- /*
- * If we've been sending smaller than normal packets, see if it's
- * time to bump the packet size up a notch yet
- */
- if (blklen < maxblklen && (goodbytes += c) >= goodneeded)
- {
- blklen <<= 1;
- if (blklen > maxblklen)
- blklen = maxblklen;
- goodbytes = 0;
- #ifdef DEBUGLOG
- mysprintf(v->Msgbuf, "Bumping packet size to %ld at %ld\n",
- (long) blklen, v->Txpos);
- dlog(v, v->Msgbuf);
- #endif
- }
-
- /* Give comm program its timeslice if it needs one */
- if (v->io.xpr_chkmisc)
- (*v->io.xpr_chkmisc)();
- /* Check for abort from comm program */
- if (v->io.xpr_chkabort && (*v->io.xpr_chkabort)())
- goto aborted;
- /* If this was last packet in frame, go wait for ACK from receiver */
- if (e == ZCRCW)
- goto waitack;
-
- /*
- * Check if receiver trying to interrupt us; look for incoming packet
- * while discarding line noise
- */
- while (char_avail(v))
- {
- switch (readock(v, 1))
- {
- case CAN:
- case RCDO:
- case ZPAD:
- /* Interruption detected; stop sending and process complaint */
- #ifdef DEBUGLOG
- dlog(v, "--- Interrupted send\n");
- #endif
- zsdata(v, 0, ZCRCE);
- sendbuf(v);
- goto waitack;
- }
- }
- }
- while (e == ZCRCG); /* If no interruption, keep sending data packets */
-
- /* Done sending file data; send EOF and wait for receiver to acknowledge */
- while (TRUE)
- {
- updmsg(v, "Sending EOF");
- stohdr(v, v->Txpos);
- zsbhdr(v, ZEOF);
- sendbuf(v);
- switch (c = getinsync(v))
- {
- case ZACK:
- continue;
- case ZRPOS:
- goto somemore;
- case ZRINIT:
- updmsg(v, "EOF acknowledged");
- ++v->Starttime.tv_secs;
- update_rate(v);
- v->xpru.xpru_updatemask = XPRU_EXPECTTIME | XPRU_ELAPSEDTIME
- | XPRU_DATARATE;
- (*v->io.xpr_update)(&v->xpru);
- return OK;
- case ZSKIP:
- return c;
- default:
- aborted:
- upderr(v, "Transfer cancelled");
- bfclose(v);
- return ERROR;
- }
- }
- } /* End of short zsendfdata() */
-
- /**********************************************************
- * short getinsync(struct Vars *v)
- *
- * Respond to receiver's complaint, get back in sync with
- * receiver
- **********************************************************/
- short getinsync(struct Vars *v)
- {
- short c;
-
- while (TRUE)
- {
- #ifdef DEBUGLOG
- dlog(v, "--- At getinsync\n");
- #endif
- c = zgethdr(v);
- if (v->io.xpr_sflush)
- (*v->io.xpr_sflush)();
- v->Modemcount = 0;
- switch (c)
- {
- case ZCAN:
- case ZABORT:
- case ZFIN:
- case RCDO:
- case TIMEOUT:
- upderr(v, v->Msgbuf);
- return ERROR;
- case ZRPOS:
- bfseek(v, v->Rxpos);
- v->Txpos = v->Rxpos;
- mysprintf(v->Msgbuf, "Resending from %ld", v->Txpos);
- upderr(v, v->Msgbuf);
- return c;
- case ZSKIP:
- upderr(v, "SKIP command received");
- /* fallthrough... */
- case ZRINIT:
- bfclose(v);
- /* fallthrough... */
- case ZACK:
- return c;
- default:
- zsbhdr(v, ZNAK);
- sendbuf(v);
- continue;
- }
- }
- } /* End of short getinsync() */
-
- /**********************************************************
- * void saybibi(struct Vars *v)
- *
- * End of batch transmission; disengage cleanly from receiver
- **********************************************************/
- void saybibi(struct Vars *v)
- {
- while (TRUE)
- {
- stohdr(v, 0L);
- zsbhdr(v, ZFIN);
- sendbuf(v);
- switch (zgethdr(v))
- {
- case ZFIN:
- sendline(v, 'O');
- sendline(v, 'O');
- sendbuf(v);
- /* fallthrough... */
- case ZCAN:
- case RCDO:
- case TIMEOUT:
- return;
- }
- }
- } /* End of void saybibi() */
- /* End of Send.c source */
-