sources-request@mirror.TMC.COM (01/19/87)
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