home *** CD-ROM | disk | FTP | other *** search
- Subject: v07i093: Full-featured XMODEM, Part02/02
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: seismo!noao!grandi (Steve Grandi)
- Mod.sources: Volume 7, Issue 93
- Archive-name: xmodem/Part02
-
- [ I'll be at USENIX, if you want to come look for me with bats and clubs.
- --r$ ]
-
- : This is a shar archive. Extract with sh, not csh.
- echo x - batch.c
- sed -e 's/^X//' > batch.c << '!Funky!Stuff!'
- X/*
- X * Various routines for batch tranfer
- X */
- X
- X#include "xmodem.h"
- X
- X/* make sure filename sent or received in YMODEM batch is canonical */
- X/* Turn Unix '/' into CP/M ':' and translate to all lower case */
- X
- Xunixify (name)
- Xchar *name;
- X {
- X char *ptr;
- X for (ptr=name; *ptr; ++ptr)
- X {
- X if (*ptr == '/')
- X *ptr = ':';
- X if (isupper (*ptr))
- X *ptr |= 040;
- X }
- X }
- X
- Xcpmify (name)
- Xchar *name;
- X {
- X char *ptr;
- X for (ptr=name; *ptr; ++ptr)
- X {
- X if (*ptr == ':')
- X *ptr = '/';
- X if (isupper (*ptr))
- X *ptr |= 040;
- X }
- X }
- X
- X
- X/* convert a CP/M file name received in a MODEM7 batch transfer
- X * into a unix file name mapping '/' into ':', converting to all
- X * upper case and adding dot in proper place.
- X * Use "filename" to hold name.
- X * Code stolen from D. Thompson's (IRTF) xmodem.c
- X */
- X
- Xchar *cpm_unix (string)
- Xunsigned char *string;
- X{
- X register int i;
- X unsigned char *iptr, temp;
- X register char *optr;
- X
- X if (*string == '\0')
- X error("Null file name in MODEM7 batch receive", TRUE);
- X
- X for (iptr=string; (temp = *iptr) ; ) {
- X temp &= 0177; /* strips bit 7 */
- X if (isupper(temp))
- X temp |= 040; /* set bit 5 for lower case */
- X if (temp == '/')
- X temp=':'; /* map / into : */
- X *iptr++ = temp;
- X }
- X
- X /* put in main part of name */
- X iptr=string;
- X optr=filename;
- X for (i=0; i<8; i++) {
- X if (*iptr != ' ')
- X *optr++ = *iptr++;
- X }
- X
- X /* add dot */
- X *optr++ = '.';
- X
- X /* put in extension */
- X iptr = &string[8];
- X for (i=0; i<3; i++) {
- X if (*iptr != ' ')
- X *optr++ = *iptr++;
- X }
- X
- X *optr++ = '\000';
- X return (filename);
- X}
- X
- X/* Send 11 character CP/M filename for MODEM7 batch transmission
- X * Returns -1 for a protocol error; 0 if successful
- X * NOTE: we tromp a little on the argument string!
- X * code stolen from D. Thompson's (IRTF) xmodem.c
- X */
- X
- Xsend_name(name)
- Xchar *name;
- X{
- X register int cksum;
- X register char *ptr;
- X
- X xmdebug("send_name");
- X
- X /* append cp/m EOF */
- X name[NAMSIZ] = CTRLZ;
- X name[NAMSIZ+1] = '\000';
- X
- X /* create checksum */
- X ptr = name;
- X cksum = 0;
- X while (*ptr)
- X cksum += *ptr++;
- X cksum &= 0x00FF;
- X
- X /* send filename */
- X
- X sendbyte(ACK);
- X ptr = name;
- X sendbyte(*ptr++);
- X
- X while (*ptr) {
- X
- Xchecknak: switch (readbyte(6)) {
- X
- X case CAN: {
- X if (readbyte(3) == CAN)
- X error("Program Canceled by User",TRUE);
- X else
- X goto checknak;
- X }
- X
- X case ACK: break;
- X
- X case TIMEOUT: {
- X logit("Timeout while sending filename\n");
- X sendbyte(BAD_NAME);
- X return (-1);
- X }
- X
- X default: {
- X logit("Error while sending filename\n");
- X sendbyte(BAD_NAME);
- X return (-1);
- X }
- X }
- X
- X sendbyte (*ptr++);
- X }
- X
- X /* Check checksum returned by other side against my value */
- X if (readbyte(10) != cksum) {
- X logit("Bad checksum while sending filename\n");
- X sendbyte(BAD_NAME);
- X return (-1);
- X }
- X
- X sendbyte(ACK);
- X return (0);
- X}
- X
- X/* Convert Unix filename to 11 character CP/M file name (8 char name,
- X * 3 char extension, dot in between is not included).
- X * map ':' into '/'; Use filename to hold name.
- X * code stolen from D. Thompson's (IRTF) xmodem.c
- X */
- X
- Xchar *unix_cpm(string)
- Xchar *string;
- X{
- X register char *iptr, *optr, temp;
- X int i;
- X
- X char *rindex();
- X char *strcpy();
- X
- X /* blank 11 character name */
- X (void) strcpy (filename," ");
- X
- X /* strip off any path name */
- X if ((iptr = rindex(string,'/')))
- X iptr++;
- X else
- X iptr=string;
- X
- X /* skip leading '.'s */
- X while (*iptr == '.')
- X iptr++;
- X
- X /* copy main part of name */
- X optr = filename;
- X i = 8;
- X while ((i--) && (*iptr) && (*iptr != '.'))
- X *optr++ = *iptr++;
- X
- X /* advance to unix extension, or end of unix name */
- X while ((*iptr != '.') && (*iptr))
- X iptr++;
- X
- X /* skip over the '.' */
- X while (*iptr == '.')
- X iptr++;
- X
- X /* copy extension */
- X optr = &filename[8];
- X i=3;
- X while ((i--) && (*iptr) && (*iptr != '.'))
- X *optr++ = *iptr++;
- X
- X filename[NAMSIZ] = '\000';
- X
- X /* Fuss with name */
- X for (iptr=filename; (temp = *iptr) ;) {
- X temp &= 0177; /* strip bit 7 (parity bit) */
- X if (islower(temp))
- X temp &= ~040; /* make upper case */
- X if (temp == ':')
- X temp ='/'; /* map ':' into '/' */
- X *iptr++ = temp;
- X }
- X
- X if (DEBUG)
- X fprintf (LOGFP, "DEBUG: File %s sent as %s\n", string, filename);
- X
- X return(filename);
- X}
- !Funky!Stuff!
- echo x - misc.c
- sed -e 's/^X//' > misc.c << '!Funky!Stuff!'
- X#include "xmodem.h"
- X
- X/* Print Help Message */
- Xhelp()
- X {
- X printf("\nUsage: \n\txmodem ");
- X printf("-[rb!rt!sb!st][options] filename\n");
- X printf("\nMajor Commands --");
- X printf("\n\trb <-- Receive Binary");
- X printf("\n\trt <-- Receive Text");
- X printf("\n\tsb <-- Send Binary");
- X printf("\n\tst <-- Send Text");
- X printf("\nOptions --");
- X printf("\n\tY <-- Use YMODEM Batch Mode on transmit");
- X printf("\n\tB <-- Use MODEM7 Batch Mode on transmit");
- X printf("\n\tK <-- Use 1K packets on transmit");
- X printf("\n\tc <-- Select CRC mode on receive");
- X printf("\n\td <-- Delete xmodem.log file before starting");
- X printf("\n\tl <-- (ell) Turn OFF Log File Entries");
- X printf("\n\tx <-- Include copious debugging information in log file");
- X printf("\n");
- X }
- X
- X/* get type of transmission requested (text or binary) */
- Xgettype(ichar)
- Xchar ichar;
- X {
- X if (ichar == 't') return(ichar);
- X if (ichar == 'b') return(ichar);
- X error("Invalid Send/Receive Parameter - not t or b", FALSE);
- X return(0);
- X }
- X
- X/* print error message and exit; if mode == TRUE, restore normal tty modes */
- Xerror(msg, mode)
- Xchar *msg;
- Xint mode;
- X {
- X if (mode)
- X restoremodes(TRUE); /* put back normal tty modes */
- X printf("\r\n%s\n", msg);
- X if ((LOGFLAG || DEBUG) && (LOGFP != NULL))
- X {
- X fprintf(LOGFP, "XMODEM Fatal Error: %s\n", msg);
- X fclose(LOGFP);
- X }
- X exit(-1);
- X }
- X
- X
- X/* Construct a proper (i.e. pretty) sector count for messages */
- X
- Xchar
- X*sectdisp(recvsectcnt, bufsize, plus1)
- Xlong recvsectcnt;
- Xint bufsize, plus1;
- X {
- X static char string[20];
- X if (plus1)
- X recvsectcnt += (bufsize == 128) ? 1 : 8;
- X if (bufsize == 128 || recvsectcnt == 0)
- X sprintf (string, "%d", recvsectcnt);
- X else
- X sprintf (string, "%d-%d", recvsectcnt-7, recvsectcnt);
- X return(string);
- X }
- X
- X/* type out debugging info */
- Xxmdebug(str)
- Xchar *str;
- X {
- X if (DEBUG && (LOGFP != NULL))
- X fprintf(LOGFP,"DEBUG: '%s'\n",str);
- X }
- X
- X/* print elapsed time and rate of transfer in logfile */
- X
- Xint quant[] = { 60, 60, 24};
- Xchar *sep[] = { "second", "minute", "hour" };
- X
- Xprtime (numsect, seconds)
- Xlong numsect;
- Xtime_t seconds;
- X
- X{
- X register int i;
- X register int Seconds;
- X int nums[3];
- X int rate = 0;
- X
- X if (!LOGFLAG)
- X return(0);
- X
- X Seconds = (int)seconds;
- X
- X if (Seconds != 0)
- X rate = 128 * numsect/Seconds;
- X
- X for (i=0; i<3; i++) {
- X nums[i] = (Seconds % quant[i]);
- X Seconds /= quant[i];
- X }
- X
- X fprintf (LOGFP, "%ld CP/M Sectors Transfered in ", numsect);
- X while (--i >= 0)
- X if (nums[i])
- X fprintf (LOGFP, "%d %s%c ", nums[i], sep[i],
- X nums[i] == 1 ? '\0' : 's');
- X fprintf (LOGFP, "\n");
- X
- X if (rate != 0)
- X fprintf (LOGFP, "Transfer Rate = %d Characters per Second\n", rate);
- X
- X return(0);
- X}
- X
- X/* Print elapsed time estimate */
- X
- Xprojtime (numsect, fd)
- Xlong numsect;
- XFILE *fd;
- X {
- X register int i;
- X register int seconds;
- X int nums[3];
- X
- X if (numsect == 0)
- X return (0);
- X
- X/* constant below should really be 1280; reduced to 90% to account for time lost in overhead */
- X
- X seconds = 1422 * numsect / ttyspeed + 1;
- X
- X for (i=0; i<3; i++) {
- X nums[i] = (seconds % quant[i]);
- X seconds /= quant[i];
- X }
- X
- X fprintf (fd, "Estimated transmission time ");
- X while (--i >= 0)
- X if (nums[i])
- X fprintf (fd, "%d %s%c ", nums[i], sep[i],
- X nums[i] == 1 ? '\0' : 's');
- X fprintf (fd, "\n");
- X return (0);
- X }
- !Funky!Stuff!
- echo x - receive.c
- sed -e 's/^X//' > receive.c << '!Funky!Stuff!'
- X#include "xmodem.h"
- X
- X/** receive a file **/
- X
- X/* returns TRUE if in the midst of a batch transfer */
- X/* returns FALSE if no more files are coming */
- X
- X/* This routine is one HUGE do-while loop with far to many indented levels.
- X * I chose this route to facilitate error processing and to avoid GOTOs.
- X * Given the troubles I've had keeping the nested IF statements straight,
- X * I was probably mistaken...
- X */
- X
- Xrfile(name)
- Xchar *name;
- X {
- X
- X char *sectdisp();
- X char *cpm_unix();
- X char *strcpy();
- X time_t time();
- X
- X int fd, /* file descriptor for created file */
- X checksum, /* packet checksum */
- X firstchar, /* first character of a packet */
- X sectnum, /* number of last received packet (modulo 128) */
- X sectcurr, /* second byte of packet--should be packet number (mod 128) */
- X sectcomp, /* third byte of packet--should be complement of sectcurr */
- X tmode, /* text mode if true, binary mode if false */
- X errors, /* running count of errors (reset when 1st packet starts */
- X errorflag, /* set true when packet (or first char of putative packet) is invalid */
- X fatalerror, /* set within main "read-packet" Do-While when bad error found */
- X inchecksum, /* incoming checksum or CRC */
- X expsect, /* expected number of sectors (YMODEM batch) */
- X bufsize; /* packet size (128 or 1024) */
- X long recvsectcnt; /* running sector count (128 byte sectors) */
- X int bufctr; /* number of real chars in read packet */
- X unsigned char *nameptr; /* ptr in filename for MODEM7 protocol */
- X time_t start; /* starting time of transfer */
- X int openflag = FALSE; /* is file open for writing? */
- X
- X logit("----\nXMODEM File Receive Function\n");
- X if (CRCMODE)
- X logit("CRC mode requested\n");
- X
- X BATCH = FALSE; /* don't know if really are in batch mode ! */
- X fatalerror = FALSE;
- X sectnum = errors = recvsectcnt = 0;
- X bufsize = 128;
- X
- X tmode = (XMITTYPE == 't') ? TRUE : FALSE;
- X
- X sleep(1); /* wait a second for other side to get ready */
- X if (CRCMODE) /* start up transfer */
- X sendbyte(CRCCHR);
- X else
- X sendbyte(NAK);
- X
- X
- X do /* start of MAIN Do-While loop to read packets */
- X {
- X errorflag = FALSE;
- X do /* start by reading first byte in packet */
- X {
- X firstchar = readbyte(6);
- X }
- X while ((firstchar != SOH)
- X && (firstchar != STX)
- X && (firstchar != EOT)
- X && (firstchar != ACK || recvsectcnt > 0)
- X && (firstchar != TIMEOUT)
- X && (firstchar != CAN));
- X
- X if (firstchar == EOT) /* check for REAL EOT */
- X {
- X if (readbyte(1) != TIMEOUT)
- X {
- X firstchar = TIMEOUT;
- X errorflag = TRUE;
- X logit ("EOT followed by characters; ignored\n");
- X }
- X }
- X
- X if (firstchar == TIMEOUT) /* timeout? */
- X {
- X logitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
- X errorflag = TRUE;
- X }
- X
- X if (firstchar == CAN) /* bailing out? */
- X {
- X if ((readbyte(3) & 0x7f) == CAN)
- X error("Reception canceled at user's request",TRUE);
- X else
- X {
- X errorflag = TRUE;
- X logit("Received single CAN character\n");
- X }
- X }
- X
- X if (firstchar == ACK) /* MODEM7 batch? */
- X {
- X int i,c;
- X
- X logit("MODEM7 Batch Protocol\n");
- X nameptr = buff;
- X checksum = 0;
- X
- X for (i=0; i<NAMSIZ; i++)
- X {
- X c = readbyte(3);
- X
- X if (c == CAN)
- X {
- X if (readbyte(3) == CAN)
- X error("Program Canceled by User", TRUE);
- X else
- X {
- X logit("Received single CAN character\n");
- X errorflag = TRUE;
- X break;
- X }
- X }
- X
- X if (c == EOT && i == 0)
- X {
- X logit("MODEM7 Batch Receive Complete\n");
- X return (FALSE);
- X }
- X
- X if (c == TIMEOUT)
- X {
- X logit("Timeout waiting for MODEM7 filename character\n");
- X errorflag = TRUE;
- X break;
- X }
- X
- X if (c == BAD_NAME)
- X {
- X logit("Error during MODEM7 filename transfer\n");
- X errorflag = TRUE;
- X break;
- X }
- X
- X *nameptr++ = c;
- X checksum += c;
- X sendbyte(ACK);
- X }
- X
- X if (!errorflag)
- X {
- X c = readbyte(3);
- X if (c == CTRLZ) /* OK; end of string found */
- X {
- X sendbyte(checksum + CTRLZ);
- X if (readbyte(3) == ACK) /* file name found! */
- X {
- X xmdebug("MODEM7 file name OK");
- X *nameptr = '\000';
- X name = cpm_unix(buff);
- X BATCH = TRUE;
- X }
- X else
- X {
- X logit("Checksum error in MODEM7 filename\n");
- X errorflag = TRUE;
- X }
- X }
- X else
- X {
- X logit("Length error in MODEM7 fielname\n");
- X errorflag = TRUE;
- X }
- X }
- X }
- X
- X
- X if (firstchar == SOH || firstchar == STX) /* start reading packet */
- X {
- X bufsize = (firstchar == SOH) ? 128 : 1024;
- X
- X if (recvsectcnt == 0) /* 1st data packet, initialize */
- X {
- X if (bufsize == 1024)
- X logit("1K packet mode chosen\n");
- X start = time((time_t *) 0);
- X errors = 0;
- X }
- X
- X sectcurr = readbyte(3);
- X sectcomp = readbyte(3);
- X if ((sectcurr + sectcomp) == 0xff) /* is packet number checksum correct? */
- X {
- X if (sectcurr == ((sectnum+1) & 0xff)) /* is packet number correct? */
- X {
- X if (DEBUG)
- X fprintf(LOGFP,"DEBUG: packet %d started\n", sectnum);
- X
- X /* Read, process and calculate checksum for a buffer of data */
- X
- X if (readbuf(bufsize, 3, tmode, &checksum, &bufctr) != TIMEOUT)
- X {
- X
- X /* verify checksum or CRC */
- X
- X if (CRCMODE)
- X {
- X checksum &= 0xffff;
- X inchecksum = readbyte(3); /* get 16-bit CRC */
- X inchecksum = (inchecksum<<8) | readbyte(3);
- X }
- X
- X else
- X inchecksum = readbyte(3); /* get simple 8-bit checksum */
- X
- X if (inchecksum == checksum) /* good checksum, hence good packet */
- X {
- X xmdebug("checksum ok");
- X errors = 0;
- X recvsectcnt += (bufsize == 128) ? 1 : 8;
- X sectnum = sectcurr;
- X
- X if (!openflag) /* open output file if necessary */
- X {
- X openflag = TRUE;
- X if ((fd = creat(name, CREATMODE)) < 0)
- X {
- X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- X error("Can't create file for receive", TRUE);
- X }
- X logitarg("File Name: %s\n", name);
- X }
- X
- X if (write(fd, (char *) buff, bufctr) < 0)
- X error("File Write Error", TRUE);
- X else
- X sendbyte(ACK); /* ACK the received packet */
- X }
- X
- X /* Start handling various errors and special conditions */
- X
- X else /* bad checksum */
- X {
- X logitarg("Checksum Error on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
- X errorflag = TRUE;
- X }
- X }
- X
- X else /* read timeout */
- X {
- X logitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
- X errorflag = TRUE;
- X }
- X }
- X
- X else /* sector number is wrong OR Ymodem filename */
- X {
- X if (sectcurr == 0 && recvsectcnt == 0) /* Ymodem file-name packet */
- X {
- X logit("YMODEM Batch Protocol\n");
- X
- X /* Read and process a file-name packet */
- X
- X if (readbuf(bufsize, 3, FALSE, &checksum, &bufctr) != TIMEOUT)
- X {
- X
- X /* verify checksum or CRC */
- X
- X if (CRCMODE)
- X {
- X checksum &= 0xffff;
- X inchecksum = readbyte(3); /* get 16-bit CRC */
- X inchecksum = (inchecksum<<8) | readbyte(3);
- X }
- X
- X else
- X inchecksum = readbyte(3); /* get simple 8-bit checksum */
- X
- X if (inchecksum == checksum) /* good checksum, hence good filename */
- X {
- X xmdebug("checksum ok");
- X strcpy(name, (char *)buff);
- X expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]);
- X sendbyte(ACK); /* ACK the packet */
- X BATCH = TRUE;
- X if (strlen(name) == 0) /* check for no more files */
- X {
- X logit("YMODEM Batch Receive Complete\n");
- X return (FALSE);
- X }
- X unixify(name); /* make filename canonical */
- X logitarg("YMODEM file name: %s\n", name);
- X logitarg("YMODEM estimated file length %d sectors\n", expsect);
- X logitarg("YMODEM header info: %s\n", (char *)buff + strlen(name) + 1);
- X }
- X
- X else /* bad filename checksum */
- X {
- X logit("checksum error on filename sector\n");
- X errorflag = TRUE;
- X }
- X }
- X else
- X {
- X logit("Timeout while reading filename packet\n");
- X errorflag = TRUE;
- X }
- X }
- X
- X else if (sectcurr == sectnum) /* duplicate sector? */
- X {
- X logitarg("Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
- X while(readbyte(3) != TIMEOUT)
- X ;
- X sendbyte(ACK);
- X }
- X else /* no, real phase error */
- X {
- X logitarg("Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
- X errorflag = TRUE;
- X fatalerror = TRUE;
- X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- X }
- X }
- X }
- X
- X else /* bad packet number checksum */
- X {
- X logitarg("Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
- X errorflag = TRUE;
- X }
- X
- X } /* END reading packet loop */
- X
- X if ((errorflag && !fatalerror) || recvsectcnt == 0) /* check on errors or batch transfers */
- X {
- X if (errorflag)
- X errors++;
- X if (recvsectcnt != 0)
- X while (readbyte(3) != TIMEOUT) /* wait for line to settle if not beginning */
- X ;
- X
- X if (CRCMODE && recvsectcnt == 0 && errors == CRCSWMAX)
- X {
- X CRCMODE = FALSE;
- X logit("Sender not accepting CRC request, changing to checksum\n");
- X sendbyte(NAK);
- X }
- X else if (!CRCMODE && recvsectcnt == 0 && errors == CRCSWMAX)
- X {
- X CRCMODE = TRUE;
- X logit("Sender not accepting checksum request, changing to CRC\n");
- X sendbyte(CRCCHR);
- X }
- X else if (CRCMODE && recvsectcnt == 0)
- X sendbyte(CRCCHR);
- X else
- X sendbyte(NAK);
- X }
- X }
- X while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror); /* end of MAIN Do-While */
- X
- X if ((firstchar == EOT) && (errors < ERRORMAX)) /* normal exit? */
- X {
- X close(fd);
- X sendbyte(ACK);
- X logit("Receive Complete\n");
- X prtime (recvsectcnt, time((time_t *) 0) - start);
- X
- X if (BATCH) /* send appropriate return code */
- X return(TRUE);
- X else
- X return(FALSE);
- X }
- X else /* no, error exit */
- X {
- X if (recvsectcnt != 0)
- X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- X error("ABORTED -- Too Many Errors", TRUE);
- X return (FALSE);
- X }
- X }
- !Funky!Stuff!
- echo x - send.c
- sed -e 's/^X//' > send.c << '!Funky!Stuff!'
- X/** send a file **/
- X
- X/*
- X * Operation of this routine depends on on MDM7BAT and YMDMBAT flags.
- X *
- X * If "name" is NULL; close out the BATCH send.
- X */
- X
- X#include "xmodem.h"
- X
- Xsfile(name)
- Xchar *name;
- X {
- X
- X char *sectdisp();
- X time_t time();
- X char *strcpy();
- X char *unix_cpm();
- X
- X extern unsigned short crctab[1<<B]; /* CRC-16 constant values, see getput.c */
- X
- X register int bufctr, /* array index for data buffer */
- X sectnum; /* packet number for packet header */
- X
- X register unsigned short checksum; /* checksum/crc */
- X
- X char blockbuf[BBUFSIZ+6]; /* holds packet as it is constructed */
- X
- X struct stat filestatbuf; /* file status info */
- X
- X int fd, /* file descriptor for file being transmitted */
- X errors, /* cumulative count of errors */
- X attempts, /* number of attempts made to transmit a packet */
- X nlflag, /* flag that we have to send a LF in next packet */
- X sendfin, /* flag that we are sending the last packet */
- X closeout, /* flag that we are closing out batch send */
- X tmode, /* TRUE for text mode; FALSE for binary mode */
- X bbufcnt, /* array index for packet */
- X firstchar, /* first character in protocol transaction */
- X bufsize, /* packet size (128 or 1024) */
- X sendresp, /* response char to sent block received from remote*/
- X extrachar; /* count of extra LF characters added */
- X long sentsect; /* count of 128 byte sectors actually sent */
- X long expsect; /* count of 128 byte sectors expected to be sent */
- X time_t start; /* starting time of transfer */
- X char c;
- X
- X nbchr = 0; /* clear buffered read char count */
- X
- X CRCMODE = FALSE; /* Receiver determines use of crc or checksum */
- X
- X closeout = FALSE; /* Check on NULL file name */
- X if (strcmp(name,"") == 0)
- X {
- X if (BATCH)
- X closeout = TRUE;
- X else
- X {
- X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- X error("NULL file name in send", TRUE);
- X }
- X }
- X
- X if (!closeout) /* Are we closing down batch? */
- X { /* no; let's send a file */
- X if ((fd = open(name, 0)) < 0)
- X {
- X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- X error("Can't open file for send", TRUE);
- X }
- X
- X stat(name, &filestatbuf); /* get file status bytes */
- X expsect = (filestatbuf.st_size/128) + 1;
- X
- X if (LOGFLAG)
- X {
- X fprintf(LOGFP, "----\nXMODEM Send Function\n");
- X fprintf(LOGFP, "File Name: %s\n", name);
- X fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
- X (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size);
- X projtime(expsect, LOGFP);
- X }
- X }
- X else
- X {
- X logit("----\nXMODEM Send Function\n");
- X logit("Closing down Batch Transmission\n");
- X }
- X
- X
- X tmode = (XMITTYPE == 't') ? TRUE : FALSE; /* set text mode */
- X
- X bufsize = LONGPACK ? 1024 : 128; /* set sector size */
- X if (LONGPACK && !closeout)
- X logit("1K packet mode chosen\n");
- X
- X sendfin = nlflag = FALSE;
- X attempts = 0;
- X
- X /* wait for and read startup character */
- X do
- X {
- X while (((firstchar=readbyte(30)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN))
- X if (++attempts > NAKMAX)
- X error("Remote System Not Responding", TRUE);
- X
- X if ((firstchar & 0x7f) == CAN)
- X if (readbyte(3) == CAN)
- X error("Send cancelled at user's request",TRUE);
- X
- X if (firstchar == CRCCHR)
- X {
- X CRCMODE = TRUE;
- X if (!closeout)
- X logit("CRC mode requested\n");
- X }
- X }
- X while (firstchar != NAK && firstchar != CRCCHR);
- X
- X if (closeout && MDM7BAT) /* close out MODEM7 batch */
- X {
- X sendbyte(ACK); sendbyte (EOT);
- X readbyte(2); /* flush junk */
- X return;
- X }
- X
- X if (MDM7BAT) /* send MODEM7 file name and resync for data packets */
- X {
- X if (send_name(unix_cpm(name)) == -1) /* should do better job here!! */
- X error("MODEM7-batch filename transfer botch", TRUE);
- X
- X firstchar = readbyte(5);
- X if (firstchar != CRCCHR && firstchar != NAK) /* Should do some better error handling!!! */
- X error("MODEM7 protocol botch, NAK/C expected", TRUE);
- X
- X CRCMODE = FALSE;
- X if (firstchar == CRCCHR)
- X {
- X CRCMODE = TRUE;
- X logit("CRC mode requested for MODEM7 batch transfer\n");
- X }
- X }
- X
- X sectnum = 1;
- X
- X if (YMDMBAT) /* Fudge for YMODEM transfer (to send name packet) */
- X {
- X sectnum = 0;
- X bufsize = 128;
- X }
- X
- X attempts = errors = sentsect = extrachar = 0;
- X start = time((time_t *) 0);
- X
- X do /* outer packet building/sending loop; loop till whole file is sent */
- X {
- X
- X if (closeout && YMDMBAT && sectnum == 1) /* close out YMODEM */
- X return;
- X
- X if (YMDMBAT && sectnum == 1) /* get set to send YMODEM data packets */
- X {
- X bufsize = LONGPACK ? 1024 : 128;
- X do
- X {
- X while (((firstchar=readbyte(3)) != CRCCHR) && (firstchar != CAN))
- X if (++attempts > NAKMAX)
- X error("YMODEM protocol botch, C expected", TRUE);
- X if ((firstchar&0x7f) == CAN)
- X if (readbyte(3) == CAN)
- X error("Send cancelled at User's request", TRUE);
- X }
- X while (firstchar != CRCCHR);
- X attempts = 0;
- X }
- X
- X if (extrachar >= 128) /* update expected sector count */
- X {
- X extrachar = 0;
- X expsect++;
- X }
- X
- X if ((bufsize == 1024) && (errors > KSWMAX))
- X {
- X logit("Reducing packet size to 128 due to excessive errors\n");
- X bufsize = 128;
- X }
- X
- X if ((bufsize == 1024) && ((expsect - sentsect) < 8))
- X {
- X logit("Reducing packet size to 128 for tail end of file\n");
- X bufsize = 128;
- X }
- X
- X if (sectnum > 0) /* data packet */
- X {
- X for (bufctr=0; bufctr < bufsize;)
- X {
- X if (nlflag)
- X {
- X buff[bufctr++] = LF; /* leftover newline */
- X nlflag = FALSE;
- X }
- X if (getbyte(fd, &c) == EOF)
- X {
- X sendfin = TRUE; /* this is the last sector */
- X if (!bufctr) /* if EOF on sector boundary */
- X break; /* avoid sending extra sector */
- X buff[bufctr++] = CTRLZ; /* Control-Z for CP/M EOF (even do it for binary file) */
- X continue;
- X }
- X
- X if (tmode && c == LF) /* text mode & Unix newline? */
- X {
- X extrachar++;
- X buff[bufctr++] = CR; /* insert carriage return */
- X if (bufctr < bufsize)
- X buff[bufctr++] = LF; /* insert LF */
- X else
- X nlflag = TRUE; /* insert on next sector */
- X }
- X else
- X buff[bufctr++] = c; /* copy the char without change */
- X }
- X
- X if (!bufctr) /* if EOF on sector boundary */
- X break; /* avoid sending empty sector */
- X }
- X
- X else /* YMODEM filename packet */
- X {
- X for (bufctr=0; bufctr<bufsize; bufctr++)
- X buff[bufctr]=0;
- X if (!closeout)
- X {
- X cpmify(name);
- X strcpy((char *)buff, name);
- X buff[bufsize-2] = (expsect & 0xff);
- X buff[bufsize-1] = ((expsect >> 8) & 0xff);
- X }
- X }
- X
- X bbufcnt = 0; /* start building block to be sent */
- X blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH; /* start of packet char */
- X blockbuf[bbufcnt++] = sectnum; /* current sector # */
- X blockbuf[bbufcnt++] = ~sectnum; /* and its complement */
- X
- X checksum = 0; /* initialize checksum */
- X for (bufctr=0; bufctr < bufsize; bufctr++)
- X {
- X blockbuf[bbufcnt++] = buff[bufctr];
- X
- X if (CRCMODE)
- X checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]];
- X
- X else
- X checksum = ((checksum+buff[bufctr]) & 0xff);
- X }
- X
- X if (CRCMODE) /* put in CRC */
- X {
- X checksum &= 0xffff;
- X blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
- X blockbuf[bbufcnt++] = (checksum & 0xff);
- X }
- X else /* put in checksum */
- X blockbuf[bbufcnt++] = checksum;
- X
- X attempts = 0;
- X
- X do /* inner packet loop */
- X {
- X
- X writebuf(blockbuf, bbufcnt); /* write the block */
- X
- X if (DEBUG)
- X fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n",
- X bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff);
- X
- X attempts++;
- X sendresp = readbyte(10); /* get response from remote */
- X
- X if (sendresp != ACK)
- X {
- X errors++;
- X
- X if ((sendresp & 0x7f) == CAN)
- X if ((readbyte(3) & 0x7f) == CAN)
- X error("Send cancelled at user's request\n",TRUE);
- X
- X if (sendresp == TIMEOUT)
- X {
- X logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1));
- X }
- X else
- X {
- X logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1));
- X }
- X }
- X }
- X while((sendresp != ACK) && (attempts < RETRYMAX) && (errors < ERRORMAX)); /* close of inner loop */
- X
- X sectnum++; /* increment to next sector number */
- X sentsect += (bufsize == 128) ? 1 : 8;
- X }
- X while (!sendfin && (attempts < RETRYMAX) && ( errors < ERRORMAX)); /* end of outer loop */
- X
- X if (attempts >= RETRYMAX)
- X {
- X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- X error("Remote System Not Responding", TRUE);
- X }
- X
- X if (attempts > ERRORMAX)
- X {
- X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- X error ("Too many errors in transmission", TRUE);
- X }
- X
- X attempts = 0;
- X sendbyte(EOT); /* send 1st EOT to close down transfer */
- X
- X while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX)) /* wait for ACK of EOT */
- X {
- X logit("EOT not ACKed\n");
- X sendbyte(EOT);
- X }
- X
- X if (attempts >= RETRYMAX)
- X error("Remote System Not Responding on Completion", TRUE);
- X
- X close(fd);
- X
- X logit("Send Complete\n");
- X prtime(sentsect, time((time_t *) 0) - start);
- X }
- !Funky!Stuff!
- exit
-
-