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
- * Version 2.52 6 March 1992, Very minor fix with compiled 020 library
- * by William M. Perkins.
- * Version 2.63, 30 July 1993 build in locale, by Rainer Hess
- *
- **********************************************************************/
-
- #include "xprzmodem_all.h"
-
- #define CATCOMP_NUMBERS
- #include "xprzmodem_catalog.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, GetLocalString( &li, MSG_UPLOAD_USER_ERROR ));
- else
- sendbatch (v);
-
- /* Clean up and return */
- if (err = v->Errcnt)
- upderr (v, GetLocalString( &li, MSG_SKIPPED_DUE_TO_ERRORS ));
- else
- updmsg (v, GetLocalString( &li, MSG_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)
- {
- (*v->io.xpr_fclose) ((long) 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
- xprsprintf (v->Msgbuf, "Txfcs32=%ld Rxbuflen=%ld Tframlen=%ld\n",
- (long) v->Txfcs32, (long) v->Rxbuflen, (long) v->Tframlen);
- dlog (v, v->Msgbuf);
- D (DEBUGINFO);
- #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
- xprsprintf (v->Msgbuf, "Rxbuflen=%ld\n", (long) v->Rxbuflen);
- dlog (v, v->Msgbuf);
- D (DEBUGINFO);
- #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;
-
- #ifdef DEBUGLOG
- D (DEBUGINFO);
- #endif
-
- /* 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, GetLocalString( &li, MSG_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
- xprsprintf (v->Msgbuf, "*** Sending %s\n", v->Filename);
- dlog (v, v->Msgbuf);
- D (DEBUGINFO);
- #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, GetLocalString( &li, MSG_CANT_OPEN_FILE ));
- 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, GetLocalString( &li, MSG_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];
-
- #ifdef DEBUGLOG
- D (DEBUGINFO);
- #endif
-
- /* 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) ? GetLocalString( &li, MSG_SENDING_TEXT_FILE ) :
- ((v->Lzconv == ZCBIN) ? GetLocalString( &li, MSG_SENDING_BINARY_FILE ) : GetLocalString( &li, MSG_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 sprintf() 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 */
- xprsprintf (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;
-
- #ifdef DEBUGLOG
- D (DEBUGINFO);
- #endif
-
- 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, GetLocalString( &li, MSG_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;
-
- #ifdef DEBUGLOG
- D (DEBUGINFO);
- #endif
-
- /* Figure out max data packet size to send */
- maxblklen = v->ksize;
- if (v->Rxbuflen && maxblklen > v->Rxbuflen)
- maxblklen = v->Rxbuflen;
- blklen = (v->Baud < 1200) ? 256 : v->ksize;
- if (blklen > maxblklen)
- blklen = maxblklen;
- #ifdef DEBUGLOG
- xprsprintf (v->Msgbuf, "Rxbuflen=%ld blklen=%ld\n", (long) v->Rxbuflen,
- (long) blklen);
- dlog (v, v->Msgbuf);
- D (DEBUGINFO);
- #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");
- D (DEBUGINFO);
- #endif
- switch (c = getinsync (v))
- {
- default:
- upderr (v, GetLocalString( &li, MSG_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, GetLocalString( &li, MSG_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
- xprsprintf (v->Msgbuf, "Bumping packet size to %ld at %ld\n",
- (long) blklen, v->Txpos);
- dlog (v, v->Msgbuf);
- D (DEBUGINFO);
- #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");
- D (DEBUGINFO);
- #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, GetLocalString( &li, MSG_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, GetLocalString( &li, MSG_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, GetLocalString( &li, MSG_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");
- D (DEBUGINFO);
- #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;
- xprsprintf (v->Msgbuf, "%s %ld", GetLocalString( &li, MSG_RESENDING_FROM ), v->Txpos);
- upderr (v, v->Msgbuf);
- return c;
- case ZSKIP:
- upderr (v, GetLocalString( &li, MSG_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)
- {
- #ifdef DEBUGLOG
- D (DEBUGINFO);
- #endif
-
- 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 */
-