rsalz@bbn.com (Rich Salz) (03/04/88)
Submitted-by: Steve Grandi <grandi@noao.arizona.edu> Posting-number: Volume 13, Issue 95 Archive-name: xmodem3.4/part03 : This is a shar archive. Extract with sh, not csh. 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 char *ctime(); 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 firstwait, /* seconds to wait for first character in a packet */ X bufsize; /* packet size (128 or 1024) */ X long recvsectcnt; /* running sector count (128 byte sectors) */ X long modtime; /* Unix style file mod time from YMODEM header */ X int filemode; /* Unix style file mode from YMODEM header */ X long readbackup; /* "backup" value for characters read in file */ X time_t timep[2]; /* used in setting mod time of received file */ X char *p; /* generic pointer */ 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 firstwait = WAITFIRST; /* For first packet, wait short time */ X sectnum = errors = recvsectcnt = 0; X bufsize = 128; X modtime = 0l; filemode = 0; X filelength = 0l; fileread =0l; CHECKLENGTH = FALSE; X X tmode = (XMITTYPE == 't') ? TRUE : FALSE; X X /* start up transfer */ X if (CRCMODE) X { X sendbyte(CRCCHR); X if (LONGPACK && !MDM7BAT) X sendbyte(KCHR); X } 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(firstwait); X } X while ((firstchar != SOH) X && (firstchar != STX) X && (firstchar != EOT) X && (firstchar != ACK || recvsectcnt > 0) X && (firstchar != TIMEOUT) X && (firstchar != CAN || recvsectcnt > 0)); X X if (firstchar == EOT) /* check for REAL EOT */ X { X sendbyte(NAK); /* NAK the EOT */ X if ((firstchar = readbyte(3)) != EOT) /* check next character */ X { X logit("Spurious EOT detected; ignored\n"); X if ((firstchar == SOH) || (firstchar == STX) || X (firstchar == ACK && recvsectcnt == 0) || X (firstchar == CAN && recvsectcnt == 0) || X (firstchar == TIMEOUT)) X break; X else X { X firstchar = 0; X errorflag = TRUE; X } X } X } X X if (firstchar == TIMEOUT) /* timeout? */ X { X if (recvsectcnt > 0) X logitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1)); X errorflag = TRUE; X } X X if (firstchar == CAN) /* bailing out? (only at beginning) */ 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? (only at beginning) */ 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 in MODEM7 filename\n"); X errorflag = TRUE; X break; X } X } X X if (c == EOT && i == 0) X { X sendbyte(NAK); /* NAK the EOT to force verification */ X if ((c=readbyte(3)) != EOT) X { X logit("Spurious EOT detected in MODEM7 filename\n"); X errorflag = TRUE; X break; X } X sendbyte(ACK); /* acknowledge EOT */ X while (readbyte(1) != TIMEOUT) /* flush garbage */ 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(15) == ACK) /* file name found! */ X { X xmdebug("MODEM7 file name OK"); X *nameptr = '\000'; /* unixify the file name */ X name = cpm_unix(buff); X BATCH = TRUE; X logitarg("MODEM7 file name: %s\n", name); X errors = 0; /* restart crc handshake */ X sleep(2); /* give other side a chance */ 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 firstwait = 5; 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 readbackup = fileread; X if (readbuf(bufsize, 1, tmode, recvsectcnt, &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 if (!BATCH) X logitarg("File Name: %s\n", name); X } X X if (write(fd, (char *) buff, bufctr) != bufctr) X { X close(fd); X unlink(name); X error("File Write Error", TRUE); X } 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: ", sectdisp(recvsectcnt,bufsize,1)); X logitarg("sent=%x ", inchecksum); X logitarg("recvd=%x\n", checksum); X fileread = readbackup; X errorflag = TRUE; X } X } X X else /* read timeout */ X { X logitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1)); X fileread = readbackup; 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, 1, FALSE, recvsectcnt, &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 BATCH = TRUE; X if (strlen(name) == 0) /* check for no more files */ X { X sendbyte(ACK); /* ACK the packet */ X logit("YMODEM Batch Receive Complete\n"); X return (FALSE); X } X unixify(name); /* make filename canonical */ X X /* read rest of YMODEM header */ X p = (char *)buff + strlen((char *)buff) + 1; X sscanf(p, "%ld%lo%o", &filelength, &modtime, &filemode); X logitarg("YMODEM file name: %s\n", name); X fileread = 0l; X if (filelength) X { X CHECKLENGTH = TRUE; X logitarg("YMODEM file size: %ld\n", filelength); X } X else X logitarg("YMODEM estimated file length %d sectors\n", expsect); X if (modtime) X { X logitarg("YMODEM file date: %s", ctime(&modtime)); X } X if (filemode) X logitarg("YMODEM file mode: %o", filemode); X X sendbyte(ACK); /* ACK the packet */ 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 } 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) || /* check on errors or batch transfers */ X ((recvsectcnt == 0) && (firstchar != EOT))) 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 (recvsectcnt == 0 && errors >= STERRORMAX) X fatalerror = TRUE; X else 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 if (errors > ERRORMAX && recvsectcnt != 0) /* over error limit? */ X fatalerror = TRUE; X } X while ((firstchar != EOT) && !fatalerror); /* end of MAIN Do-While */ X X if ((firstchar == EOT) && !fatalerror) /* normal exit? */ X { X if (openflag) /* close the file */ X close(fd); X sendbyte(ACK); /* ACK the EOT */ X logit("Receive Complete\n"); X prtime (recvsectcnt, time((time_t *) 0) - start); X X if (openflag && modtime) /* set file modification time */ X { X timep[0] = time((time_t *) 0); X timep[1] = modtime; X utime(name, timep); X } 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); sendbyte(CAN); sendbyte(CAN); X if (openflag) X { X close(fd); X unlink(name); X } X error("ABORTED -- Too Many Errors--deleting file", TRUE); X return (FALSE); X } 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\tm <-- 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\tt <-- Indicate a TOO BUSY Unix system"); 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' || ichar == 'T') return('t'); X if (ichar == 'b' || ichar == 'B') return('b'); 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[3][10] = { "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; X X if (!LOGFLAG || numsect == 0) X return(0); X X Seconds = (int)seconds; X Seconds = (Seconds > 0) ? Seconds : 0; X X rate = (Seconds != 0) ? 128 * numsect/Seconds : 0; X X for (i=0; i<3; i++) { X nums[i] = (Seconds % quant[i]); X Seconds /= quant[i]; X } X X fprintf (LOGFP, "%ld Sectors Transfered in ", numsect); X X if (rate == 0) X fprintf (LOGFP, "0 seconds"); X else X while (--i >= 0) X if (nums[i]) X fprintf (LOGFP, "%d %s%c ", nums[i], &sep[i][0], X nums[i] == 1 ? ' ' : '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 X while (--i >= 0) X if (nums[i]) X fprintf (fd, "%d %s%c ", nums[i], &sep[i][0], X nums[i] == 1 ? ' ' : 's'); X fprintf (fd, "\n"); X return (0); X } !Funky!Stuff! echo x - tip.diffs sed -e 's/^X//' > tip.diffs << '!Funky!Stuff!' X X*** cmdtab.c.ORIG Mon May 5 11:01:59 1986 X--- cmdtab.c Thu Aug 21 10:08:50 1986 X*************** X*** 15,16 **** X--- 15,17 ---- X extern int cu_take(), cu_put(), dollar(), genbrk(), suspend(); X+ extern int rtfile(), stfile(), rbfile(), sbfile(); X X*************** X*** 35,36 **** X--- 36,41 ---- X { '#', NORM, "send break", genbrk }, X+ { '{', NORM, "receive xmodem text file", rtfile }, X+ { '}', NORM, "send xmodem text file", stfile }, X+ { '(', NORM, "receive xmodem binary file", rbfile }, X+ { ')', NORM, "send xmodem binary file", sbfile }, X { 0, 0, 0 } X X X X*** cmds.c.ORIG Mon May 5 11:01:56 1986 X--- cmds.c Tue Sep 30 10:17:11 1986 X*************** X*** 855,856 **** X--- 865,1412 ---- X return(0); X+ } X+ X+ X+ /* XMODEM stuff; sag sept 1984 - Feb 1985 X+ * Taken from Brian Kantor's (sdccsu3!brian) xmodem version 1.0 X+ * Note that this code will work on version 4.2 ONLY (uses select) X+ */ X+ X+ #include <sys/stat.h> X+ #include <sys/time.h> X+ X+ /* ASCII Constants */ X+ #define SOH 001 X+ #define STX 002 X+ #define ETX 003 X+ #define EOT 004 X+ #define ENQ 005 X+ #define ACK 006 X+ #define LF 012 /* Unix LF/NL */ X+ #define CR 015 X+ #define NAK 025 X+ #define SYN 026 X+ #define CAN 030 X+ #define ESC 033 X+ #define CTRLZ 032 /* CP/M EOF for text (usually!) */ X+ X+ /* XMODEM Constants */ X+ #define TIMEOUT -1 X+ #define ERRORMAX 10 /* maximum errors tolerated */ X+ #define RETRYMAX 10 /* maximum retries to be made */ X+ #define BBUFSIZ 128 /* buffer size -- do not change! */ X+ #define DEBUG 0 /* 1 for debugging output */ X+ #define GETERR -10 /* error code for getbyte routine */ X+ X+ char buff[BBUFSIZ]; X+ X+ int nbchr; /* number of chars read so far for buffered read */ X+ X+ /* Receive a text file */ X+ rtfile(c) X+ char c; X+ { X+ putchar (c); X+ rfile ('t'); X+ } X+ X+ /* Receive a binary file */ X+ rbfile(c) X+ char c; X+ { X+ putchar (c); X+ rfile ('b'); X+ } X+ X+ /* Send a text file */ X+ stfile(c) X+ char c; X+ { X+ putchar (c); X+ sfile ('t'); X+ } X+ X+ /* Send a binary file */ X+ sbfile(c) X+ char c; X+ { X+ putchar (c); X+ sfile ('b'); X+ } X+ X+ /* print error message and cleanup for exit */ X+ error(msg) X+ char *msg; X+ { X+ printf("\r\nXMODEM: %s\n", msg); X+ ioctl (0, TIOCSETC, &tchars); X+ write (fildes[1], (char *)&ccc, 1); X+ signal (SIGINT, SIG_DFL); X+ } X+ X+ /* X+ * X+ * Get a byte from the specified file. Buffer the read so we don't X+ * have to use a system call for each character. X+ * X+ */ X+ getbyte(fildes, ch) /* Buffered disk read */ X+ int fildes; X+ char *ch; X+ X+ { X+ static char buf[BUFSIZ]; /* Remember buffer */ X+ static char *bufp = buf; /* Remember where we are in buffer */ X+ X+ if (nbchr == 0) /* Buffer exausted; read some more */ X+ { X+ if ((nbchr = read(fildes, buf, BUFSIZ)) < 0) X+ { X+ error("File Read Error"); X+ return (GETERR); X+ } X+ bufp = buf; /* Set pointer to start of array */ X+ } X+ if (--nbchr >= 0) X+ { X+ *ch = *bufp++; X+ return(0); X+ } X+ else X+ return(EOF); X+ } X+ X+ /** receive a file **/ X+ rfile(mode) X+ char mode; X+ { X+ register int bufctr, checksum; X+ register int c; X+ int j, firstchar, sectnum, sectcurr, tmode; X+ int sectcomp, errors, errorflag, recfin; X+ int fatalerror, inchecksum; X+ long recvsectcnt; X+ X+ int (*f) (); X+ char *cp, *expand(); X+ time_t start; X+ X+ if (prompt (" Receive local file name? ", copyname)) X+ return; X+ cp = expand (copyname); X+ if ((sfd = creat (cp, 0666)) < 0) X+ { X+ printf ("\r\n%s: Cannot creat\r\n", copyname); X+ return; X+ } X+ X+ kill (pid, SIGIOT); X+ read (repdes[0], (char *)&ccc, 1); /* wait until read process stops */ X+ ioctl (0, TIOCSETC, &defchars); /* set tty modes */ X+ f = signal (SIGINT, intcopy); /* intercept control-c */ X+ X+ start = time(0); X+ quit = 0; X+ (void) setjmp(intbuf); /* set control-c catcher */ X+ X+ if (quit) X+ { X+ error("Control-C; Reception canceled"); X+ close (sfd); X+ return; X+ } X+ X+ printf("XMODEM: Ready to RECEIVE File %s", cp); X+ puts("\r\nControl-C to cancel.\n"); X+ X+ recfin = FALSE; X+ sectnum = errors = 0; X+ fatalerror = FALSE; /* NO fatal errors */ X+ recvsectcnt = 0; /* number of received sectors */ X+ X+ if (mode == 't') X+ tmode = TRUE; X+ else X+ tmode = FALSE; X+ X+ sendbyte(NAK); /* Start up the sender's first block */ X+ X+ do X+ { X+ errorflag = FALSE; X+ do X+ { X+ firstchar = readbyte(6); X+ } X+ while ((firstchar != SOH) X+ && (firstchar != EOT) X+ && (firstchar != TIMEOUT) X+ && ((firstchar & 0x7f) != CAN)); X+ X+ if (firstchar == TIMEOUT) X+ { X+ printf("\r\nTimeout on Sector %d\n", sectnum+1); X+ errorflag = TRUE; X+ } X+ X+ if ((firstchar & 0x7f) == CAN) X+ { X+ error("Reception canceled at user's request"); X+ close (sfd); X+ return; X+ } X+ X+ if (firstchar == SOH) X+ { X+ sectcurr = readbyte(3); /* get sector numbers */ X+ sectcomp = readbyte(3); X+ if ((sectcurr + sectcomp) == 0xff) X+ { X+ if (sectcurr == ((sectnum+1) & 0xff)) X+ { X+ checksum = 0; X+ for (j = bufctr = 0; j < BBUFSIZ; j++) X+ { X+ buff[bufctr] = c = readbyte(3); X+ checksum = ((checksum+c) & 0xff); X+ if (!tmode) /* binary mode */ X+ { X+ bufctr++; X+ continue; X+ } X+ if (c == CR) X+ continue; /* skip CR's */ X+ if (c == CTRLZ) /* CP/M EOF char */ X+ { X+ recfin = TRUE; /* flag EOF */ X+ continue; X+ } X+ if (!recfin) X+ bufctr++; X+ } X+ inchecksum = readbyte(3); /* get checksum */ X+ if (checksum == inchecksum) /* good checksum */ X+ { X+ errors = 0; X+ recvsectcnt++; X+ sectnum = sectcurr; X+ if (DEBUG) printf ("\n"); X+ printf ("\rreceived sector %-4d", recvsectcnt); X+ if (write(sfd, buff, bufctr) < 0) X+ { X+ sendbyte(CAN); X+ error("File Write Error"); X+ close (sfd); X+ return; X+ } X+ else X+ sendbyte(ACK); X+ X+ } X+ else X+ { X+ printf("\r\nChecksum Error on Sector %d\n", sectnum+1); X+ errorflag = TRUE; X+ } X+ } X+ else X+ { X+ if (sectcurr == sectnum) X+ { X+ while(readbyte(3) != TIMEOUT) X+ ; X+ sendbyte(ACK); X+ } X+ else X+ { X+ printf("\r\nPhase Error - Received Sector is "); X+ printf("%d while Expected Sector is %d\n", X+ sectcurr, ((sectnum+1) & 0xff)); X+ errorflag = TRUE; X+ fatalerror = TRUE; X+ sendbyte(CAN); X+ } X+ } X+ } X+ else X+ { X+ printf("\r\nHeader Sector Number Error on Sector %d\n", X+ sectnum+1); X+ errorflag = TRUE; X+ } X+ } X+ X+ if (errorflag) X+ { X+ errors++; X+ while (readbyte(3) != TIMEOUT) X+ ; X+ sendbyte(NAK); X+ } X+ } X+ while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror); X+ X+ if ((firstchar == EOT) && (errors < ERRORMAX) && !fatalerror) X+ { X+ close(sfd); X+ sendbyte(ACK); X+ printf("\n\rReceive Complete"); X+ printf("\n\r%ld CP/M Records ", recvsectcnt); X+ prtime(" transferred in ", time(0)-start); X+ X+ ioctl (0, TIOCSETC, &tchars); /* reset ttys */ X+ write (fildes[1], (char *)&ccc, 1); /* wakeup tip */ X+ signal (SIGINT, SIG_DFL); /* reset control-c catcher */ X+ } X+ else X+ { X+ sendbyte(CAN); X+ error("\r\nABORTED -- Too Many Errors"); X+ close (sfd); X+ return; X+ } X+ } X+ X+ /** send a file **/ X+ sfile(mode) X+ char mode; X+ { X+ register int bufctr, checksum, sectnum; X+ char blockbuf[134]; X+ int fd, attempts; X+ int nlflag, sendfin, tmode; X+ int bbufcnt; X+ int firstchar; X+ int getretrn; X+ char c; X+ int sendresp; /* response char to sent block */ X+ X+ int (*f) (); X+ char *cp, *expand(); X+ time_t start; X+ X+ if (prompt (" Send local file name? ", copyname)) X+ return; X+ cp = expand (copyname); X+ if ((fd = open(cp, 0)) < 0) X+ { X+ printf("Can't open file for send\n"); X+ return; X+ } X+ X+ kill (pid, SIGIOT); X+ read (repdes[0], (char *)&ccc, 1); /* wait until read process stops */ X+ ioctl (0, TIOCSETC, &defchars); /* setup tty */ X+ f = signal (SIGINT, intcopy); /* prepare to catch control-c */ X+ start = time(0); X+ quit = 0; X+ (void) setjmp(intbuf); /* setup control-c catcher */ X+ X+ nbchr = 0; /* clear buffered read char count */ X+ X+ if (quit) X+ { X+ sendbyte(CAN); X+ error("Control-C; Send canceled"); X+ close (fd); X+ return; X+ } X+ X+ printf("XMODEM: File %s Ready to SEND", cp); X+ prfilestat(cp); /* print file size statistics */ X+ puts("\r\nControl-C to cancel.\n"); X+ X+ if (mode == 't') X+ tmode = TRUE; X+ else X+ tmode = FALSE; X+ X+ sendfin = nlflag = FALSE; X+ attempts = 0; X+ X+ while (((firstchar=readbyte(30)) != NAK) && (firstchar != CAN)) X+ { X+ if (++attempts > RETRYMAX) { X+ error("Remote System Not Responding"); X+ close (fd); X+ return; X+ } X+ } X+ X+ if ((firstchar & 0x7f) == CAN) X+ { X+ error("Send cancelled at user's request."); X+ close (fd); X+ return; X+ } X+ X+ sectnum = 1; /* first sector number */ X+ attempts = 0; X+ X+ do X+ { X+ for (bufctr=0; bufctr < BBUFSIZ;) X+ { X+ if (nlflag) X+ { X+ buff[bufctr++] = LF; /* leftover newline */ X+ nlflag = FALSE; X+ } X+ getretrn = getbyte(fd, &c); X+ if (getretrn == GETERR) X+ { X+ sendbyte(CAN); X+ error ("Read error on local file"); X+ close (fd); X+ return; X+ } X+ if (getretrn == 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+ if (tmode) X+ buff[bufctr++] = CTRLZ; /* Control-Z for CP/M EOF */ X+ else X+ bufctr++; X+ continue; X+ } X+ X+ if (tmode && c == LF) /* text mode & Unix newline? */ X+ { X+ buff[bufctr++] = CR; /* insert carriage return */ X+ if (bufctr < BBUFSIZ) 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+ attempts = 0; X+ X+ if (!bufctr) /* if EOF on sector boundary */ X+ break; /* avoid sending empty sector */ X+ X+ do X+ { X+ bbufcnt = 0; /* start building block to be sent */ X+ blockbuf[bbufcnt++] = SOH; /* start of packet char */ X+ blockbuf[bbufcnt++] = sectnum; /* current sector # */ X+ blockbuf[bbufcnt++] = -sectnum-1; /* and its complement */ X+ X+ checksum = 0; /* init checksum */ X+ for (bufctr=0; bufctr < BBUFSIZ; bufctr++) X+ { X+ blockbuf[bbufcnt++] = buff[bufctr]; X+ checksum = ((checksum+buff[bufctr]) & 0xff); X+ } X+ X+ blockbuf[bbufcnt++] = checksum; X+ write(FD, blockbuf, 132); /* write the block */ X+ ioctl(FD,TIOCFLUSH,0); X+ X+ attempts++; X+ sendresp = readbyte(10); /* get response */ X+ if (sendresp != ACK) X+ { X+ printf("\r\nNon-ACK Received on Sector %d\n",sectnum); X+ if (sendresp == TIMEOUT) X+ printf("\r\nThis Non-ACK was a TIMEOUT\n"); X+ } X+ } X+ while((sendresp != ACK) && (attempts < RETRYMAX)); X+ X+ sectnum++; /* increment to next sector number */ X+ if (DEBUG) printf ("\n"); X+ printf ("\rsent sector %-4d", sectnum-1); X+ } X+ while (!sendfin && (attempts < RETRYMAX)); X+ X+ if (attempts >= RETRYMAX) X+ { X+ error("Remote System Not Responding"); X+ close (fd); X+ return; X+ } X+ X+ attempts = 0; X+ sendbyte(EOT); /* send 1st EOT */ X+ X+ while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX)) X+ sendbyte(EOT); X+ X+ if (attempts >= RETRYMAX) X+ error("Remote System Not Responding on Completion"); X+ X+ close(fd); X+ printf("\r\nSend Complete\r\n"); X+ prtime("Data transferred in ", time(0)-start); X+ X+ ioctl (0, TIOCSETC, &tchars); /* restore tty */ X+ write (fildes[1], (char *)&ccc, 1); /* wakeup tip */ X+ signal (SIGINT, SIG_DFL); /* reset control-c catcher */ X+ sleep(5); /* give other side time to return to terminal mode */ X+ X+ } X+ X+ /* print file size status information */ X+ prfilestat(name) X+ char *name; X+ { X+ struct stat filestatbuf; /* file status info */ X+ X+ stat(name, &filestatbuf); /* get file status bytes */ X+ printf("\r\nEstimated File Size %ldK, %ld Records, %ld Bytes", X+ (filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1, X+ filestatbuf.st_size); X+ return; X+ } X+ X+ /* get a byte from data stream -- timeout if "seconds" elapses */ X+ int readbyte(seconds) X+ int seconds; X+ { X+ int i, readfd; X+ char c; X+ struct timeval tmout; X+ X+ tmout.tv_sec = seconds; X+ tmout.tv_usec = 0; X+ X+ readfd = 1 << FD; X+ X+ if ((i=select(FD+1, &readfd, 0, 0, &tmout)) == 0) X+ { X+ return(TIMEOUT); X+ } X+ X+ read(FD, &c, 1); X+ X+ return(c & 0xff); /* return the char */ X+ } X+ X+ /* send a byte to data stream */ X+ sendbyte(data) X+ char data; X+ { X+ write(FD, &data, 1); /* write the byte */ X+ ioctl(FD,TIOCFLUSH,0); /* flush so it really happens now! */ X+ return; X+ } X+ X+ /* X+ * "nap" for specified time X+ */ X+ nap (milliseconds) X+ int milliseconds; X+ { X+ struct timeval timeout; X+ X+ if (milliseconds == 0) X+ return; X+ timeout.tv_sec = 0; X+ timeout.tv_usec = milliseconds * 1000; X+ X+ (void) select(1, 0, 0, 0, &timeout); X } !Funky!Stuff! exit -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.