rsalz@uunet.uu.net (Rich Salz) (06/15/88)
Submitted-by: Steve Grandi <grandi@noao.arizona.edu> Posting-number: Volume 15, Issue 71 Archive-name: xmodem3.6/part02 : This is a shar archive. Extract with sh, not csh. echo x - xmodem.c sed -e 's/^X//' > xmodem.c << '!Funky!Stuff!' X/* X * XMODEM -- Implements the Christensen XMODEM protocol, X * for packetized file up/downloading. X * X * See the README file for some notes on SYS V adaptations. X * The program has been successfully run on VAXes (4.3BSD) and SUN-3/4s X * (SunOS 3.x) against MEX-PC and ZCOMM/DSZ. X * X * See the README and update.doc files for history and change notes. X * X * Please send bug fixes, additions and comments to: X * {ihnp4,ncar}!noao!grandi grandi@noao.arizona.edu X */ X X#include "xmodem.h" X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char *getenv(); X FILE *fopen(); X char *unix_cpm(); X char *strcpy(); X char *strcat(); X char *prtype(); X X char *fname = filename; /* convenient place to stash file names */ X char *logfile = "xmodem.log"; /* Name of LOG File */ X X char *stamptime(); /* for timestamp */ X X char *defname = "xmodem.in"; /* default file name if none given */ X X struct stat filestatbuf; /* file status info */ X X int index; X char flag; X long expsect; X X /* initialize option flags */ X X XMITTYPE = 't'; /* assume text transfer */ X DEBUG = FALSE; /* keep debugging info in log */ X RECVFLAG = FALSE; /* not receive */ X SENDFLAG = FALSE; /* not send either */ X BATCH = FALSE; /* nor batch */ X CRCMODE = FALSE; /* use checksums for now */ X DELFLAG = FALSE; /* don't delete old log file */ X LOGFLAG = TRUE; /* keep log */ X LONGPACK = FALSE; /* do not use long packets on transmit */ X MDM7BAT = FALSE; /* no MODEM7 batch mode */ X YMDMBAT = FALSE; /* no YMODEM batch mode */ X TOOBUSY = FALSE; /* not too busy for sleeping in packet read */ X X fprintf(stderr, "XMODEM Version %d.%d", VERSION/10, VERSION%10); X fprintf(stderr, " -- UNIX-Microcomputer Remote File Transfer Facility\n"); X X if (argc == 1) X { X help(); X exit(-1); X } X X index = 0; /* set index for flag loop */ X X while ((flag = argv[1][index++]) != '\0') X switch (flag) { X case '-' : break; X case 'X' : X case 'x' : DEBUG = TRUE; /* turn on debugging log */ X break; X case 'C' : X case 'c' : CRCMODE = TRUE; /* enable CRC on receive */ X break; X case 'D' : X case 'd' : DELFLAG = TRUE; /* delete log file */ X break; X case 'L' : X case 'l' : LOGFLAG = FALSE; /* turn off log */ X break; X case 'm' : X case 'M' : MDM7BAT = TRUE; /* turn on MODEM7 batch protocol */ X BATCH = TRUE; X break; X case 'y' : X case 'Y' : YMDMBAT = TRUE; /* turn on YMODEM batch protocol */ X BATCH = TRUE; X break; X case 'k' : X case 'K' : LONGPACK = TRUE; /* use 1K packets on transmit */ X break; X case 't' : X case 'T' : TOOBUSY = TRUE; /* turn off sleeping */ X break; X case 'R' : X case 'r' : RECVFLAG = TRUE; /* receive file */ X XMITTYPE = gettype(argv[1][index++]); /* get t/b */ X break; X case 'S' : X case 's' : SENDFLAG = TRUE; /* send file */ X XMITTYPE = gettype(argv[1][index++]); X break; X default : fprintf(stderr, "Invalid Flag %c ignored\n", flag); X break; X } X X if (DEBUG) X LOGFLAG = TRUE; X X if (LOGFLAG) X { X if ((fname = getenv("HOME")) == 0) /* Get HOME variable */ X error("Fatal - Can't get Environment!", FALSE); X fname = strcat(fname, "/"); X fname = strcat(fname, logfile); X if (!DELFLAG) X LOGFP = fopen(fname, "a"); /* append to LOG file */ X else X LOGFP = fopen(fname, "w"); /* new LOG file */ X if (!LOGFP) X error("Fatal - Can't Open Log File", FALSE); X X fprintf(LOGFP,"\n++++++++ %s", stamptime()); X fprintf(LOGFP,"XMODEM Version %d.%d\n", VERSION/10, VERSION%10); X fprintf(LOGFP,"Command line: %s %s", argv[0], argv[1]); X for (index=2; index<argc; ++index) X fprintf(LOGFP, " %s", argv[index]); X fprintf(LOGFP, "\n"); X } X X getspeed(); /* get tty-speed for time estimates */ X X if (RECVFLAG && SENDFLAG) X error("Fatal - Both Send and Receive Functions Specified", FALSE); X X if (MDM7BAT && YMDMBAT) X error("Fatal - Both YMODEM and MODEM7 Batch Protocols Specified", FALSE); X X if (!RECVFLAG && !SENDFLAG) X error("Fatal - Either Send or Receive Function must be chosen!",FALSE); X X if (SENDFLAG && argc==2) X error("Fatal - No file specified to send",FALSE); X X if (RECVFLAG && argc==2) X { X /* assume we really want CRC-16 in batch, unless we specify MODEM7 mode */ X CRCMODE = MDM7BAT ? FALSE : TRUE; X fprintf(stderr, "Ready for BATCH RECEIVE"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logit("Batch Receive Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X strcpy(fname, defname); X } X X if (RECVFLAG && argc>2) X { X if(open(argv[2], 0) != -1) /* check for overwriting */ X { X logit("Warning -- Target File Exists and is Being Overwritten\n"); X fprintf(stderr, "Warning -- Target File Exists and is Being Overwritten\n"); X } X fprintf(stderr, "Ready to RECEIVE File %s", argv[2]); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logitarg("Receiving in %s mode\n", prtype(XMITTYPE)); X strcpy(fname,argv[2]); X } X X if (RECVFLAG) X { X setmodes(); /* set tty modes for transfer */ X X while(rfile(fname) != FALSE); /* receive files */ X X flushin(); X restoremodes(FALSE); /* restore normal tty modes */ X X sleep(2); /* give other side time to return to terminal mode */ X exit(0); X } X X if (SENDFLAG && BATCH) X { X if (YMDMBAT) X { X fprintf(stderr, "Ready to YMODEM BATCH SEND"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X logit("YMODEM Batch Send Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X } X else if (MDM7BAT) X { X fprintf(stderr, "Ready to MODEM7 BATCH SEND"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X logit("MODEM7 Batch Send Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X } X fprintf(stderr, "Send several Control-X characters to cancel\n"); X X setmodes(); X for (index=2; index<argc; index++) { X if (stat(argv[index], &filestatbuf) < 0) { X logitarg("\nFile %s not found\n", argv[index]); X continue; X } X sfile(argv[index]); X } X sfile(""); X flushin(); X restoremodes(FALSE); X X logit("Batch Send Complete\n"); X sleep(2); X exit (0); X } X X if (SENDFLAG && !BATCH) X { X if (stat(argv[2], &filestatbuf) < 0) X error("Can't find requested file", FALSE); X expsect = (filestatbuf.st_size/128)+1; X X fprintf(stderr, "File %s Ready to SEND", argv[2]); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Estimated File Size %ldK, %ld Sectors, %ld Bytes\n", X (filestatbuf.st_size/1024)+1, expsect, X filestatbuf.st_size); X projtime(expsect, stdout); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logitarg("Sending in %s mode\n", prtype(XMITTYPE)); X X setmodes(); X sfile(argv[2]); X flushin(); X restoremodes(FALSE); X X sleep(2); X exit(0); X } 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 Xchar *sectdisp(); Xchar *cpm_unix(); Xchar *strcpy(); Xchar *ctime(); Xtime_t time(); X Xint fd, /* file descriptor for created file */ Xchecksum, /* packet checksum */ Xfirstchar, /* first character of a packet */ Xsectnum, /* number of last received packet (modulo 128) */ Xsectcurr, /* second byte of packet--should be packet number (mod 128) */ Xsectcomp, /* third byte of packet--should be complement of sectcurr */ Xtmode, /* text mode if true */ Xamode, /* apple mode if true */ Xerrors, /* count of errors for each packet */ Xsterrors, /* count of errors during startup handshake */ Xerrorflag, /* set true when packet (or first char of putative packet) is invalid */ Xfatalerror, /* set within main "read-packet" Do-While when bad error found */ Xinchecksum, /* incoming checksum or CRC */ Xexpsect, /* expected number of sectors (YMODEM batch) */ Xfirstwait, /* seconds to wait for first character in a packet */ Xbufsize; /* packet size (128 or 1024) */ Xlong recvsectcnt; /* running sector count (128 byte sectors) */ Xlong modtime; /* Unix style file mod time from YMODEM header */ Xint filemode; /* Unix style file mode from YMODEM header */ Xlong readbackup; /* "backup" value for characters read in file */ Xtime_t timep[2]; /* used in setting mod time of received file */ Xchar *p; /* generic pointer */ Xint bufctr; /* number of real chars in read packet */ Xunsigned char *nameptr; /* ptr in filename for MODEM7 protocol */ Xtime_t start; /* starting time of transfer */ Xint openflag = FALSE; /* is file open for writing? */ X Xlogit("----\nXMODEM File Receive Function\n"); Xif (CRCMODE) Xlogit("CRC mode requested\n"); X XBATCH = FALSE; /* don't know if really are in batch mode ! */ Xfatalerror = FALSE; Xfirstwait = WAITFIRST; /* For first packet, wait short time */ Xsectnum = errors = recvsectcnt = 0; Xbufsize = 128; Xmodtime = 0l; filemode = 0; Xfilelength = 0l; fileread =0l; CHECKLENGTH = FALSE; X Xtmode = (XMITTYPE == 't') ? TRUE : FALSE; Xamode = (XMITTYPE == 'a') ? TRUE : FALSE; X X/* start up transfer */ X Xsterrors = 0; Xflushin(); /* flush input queue */ X Xif (CRCMODE) X{ X sendbyte(CRCCHR); X if (LONGPACK && !MDM7BAT) X sendbyte(KCHR); X} Xelse X sendbyte(NAK); X X Xdo /* 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 flushin(); 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(ACK); /* acknowledge EOT */ 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 filename\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, amode, 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 { X flushin(); /* flush input */ X sendbyte(ACK); /* ACK the received packet */ X } 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, 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 YMDMBAT = TRUE; X if (strlen(name) == 0) /* check for no more files */ X { X flushin(); /* flush input */ 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 if (expsect) 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 firstwait = WAITFIRST; /* reset to negotiate */ 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 flushin(); /* REALLY flush input */ X while(readbyte(1) != 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 && recvsectcnt != 0) /* Handle errors */ X { X errors++; X X if (errors >= ERRORMAX) /* over error limit? */ X fatalerror = TRUE; X else /* flush input and NAK the packet */ X { X flushin(); X while (readbyte(1) != TIMEOUT) /* wait for line to settle */ X ; X sendbyte(NAK); X } X } X X if (recvsectcnt == 0 && errorflag && firstchar != EOT) /* handle startup handshake */ X { X sterrors++; X X if (sterrors >= STERRORMAX) X fatalerror = TRUE; X X else if (CRCMODE && sterrors == CRCSWMAX && !YMDMBAT) X { X CRCMODE = FALSE; X logit("Sender not accepting CRC request, changing to checksum\n"); X sendbyte(NAK); X } X X else if (!CRCMODE && sterrors == CRCSWMAX && !YMDMBAT) X { X CRCMODE = TRUE; X logit("Sender not accepting checksum request, changing to CRC\n"); X sendbyte(CRCCHR); X if (LONGPACK && !MDM7BAT) X sendbyte(KCHR); X } X X else if (CRCMODE) X { X sendbyte(CRCCHR); X if (LONGPACK && !MDM7BAT) X sendbyte(KCHR); X } X X else X sendbyte(NAK); X } X} Xwhile ((firstchar != EOT) && !fatalerror); /* end of MAIN Do-While */ X Xif ((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} Xelse /* no, error exit */ X{ X if (openflag) X { X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); X close(fd); X unlink(name); X error("ABORTED -- Too Many Errors--deleting file", TRUE); X } X else if (recvsectcnt != 0) X error("ABORTED -- Too Many Errors", TRUE); X else X error("ABORTED -- Remote system is not responding", TRUE); X} Xreturn(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 fprintf(stderr, "\nUsage: \n\txmodem "); X fprintf(stderr, "-[rb!rt!ra!sb!st!sa][options] filename\n"); X fprintf(stderr, "\nMajor Commands --"); X fprintf(stderr, "\n\trb <-- Receive Binary"); X fprintf(stderr, "\n\trt <-- Receive Text"); X fprintf(stderr, "\n\tra <-- Receive Apple macintosh text"); X fprintf(stderr, "\n\tsb <-- Send Binary"); X fprintf(stderr, "\n\tst <-- Send Text"); X fprintf(stderr, "\n\tsa <-- Send Apple macintosh text"); X fprintf(stderr, "\nOptions --"); X fprintf(stderr, "\n\ty <-- Use YMODEM Batch Mode on transmit"); X fprintf(stderr, "\n\tm <-- Use MODEM7 Batch Mode on transmit"); X fprintf(stderr, "\n\tk <-- Use 1K packets on transmit"); X fprintf(stderr, "\n\tc <-- Select CRC mode on receive"); X fprintf(stderr, "\n\tt <-- Indicate a TOO BUSY Unix system"); X fprintf(stderr, "\n\td <-- Delete xmodem.log file before starting"); X fprintf(stderr, "\n\tl <-- (ell) Turn OFF Log File Entries"); X fprintf(stderr, "\n\tx <-- Include copious debugging information in log file"); X fprintf(stderr, "\n"); X } X X/* get type of transmission requested (text or binary) */ Xgettype(ichar) Xchar ichar; X { X if (ichar == 't' || ichar == 'T') X return('t'); X else if (ichar == 'b' || ichar == 'B') X return('b'); X else if (ichar == 'a' || ichar == 'A') X return('a'); X else X error("Invalid Send/Receive Parameter - not t or b", FALSE); X return('\0'); X } X X/* return a string containing transmission type */ Xchar * Xprtype(ichar) Xchar ichar; X { X if (ichar == 't' || ichar == 'T') X return("text"); X else if (ichar == 'b' || ichar == 'B') X return("binary"); X else if (ichar == 'a' || ichar == 'A') X return("apple"); X else X return(""); 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 fprintf(stderr, "\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! exit -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.