v07i093: Full-featured XMODEM, Part02/02
sources-request at mirror.TMC.COM
sources-request at mirror.TMC.COM
Tue Jan 20 00:10:17 AEST 1987
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
More information about the Mod.sources
mailing list