geoff@desint.UUCP (Geoff Kuenning) (01/24/85)
# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by geoff on Wed Jan 23 20:00:40 PST 1985 # Contents: README umodem.c echo x - README sed 's/^@//' > "README" <<'@//E*O*F README//' Well, the response has been overwhelming, so here it is: a UMODEM that will run under system V. Note that this is *not* the latest version of UMODEM, but it at least seems to run with the BBS I tested it with. Have fun. Geoff Kuenning ...!ihnp4!trwrb!desint!geoff @//E*O*F README// chmod u=rw,g=r,o=r README echo x - umodem.c sed 's/^@//' > "umodem.c" <<'@//E*O*F umodem.c//' /* * UMODEM -- Implements the "CP/M User's Group XMODEM" protocol, * the TERM II File Transfer Protocol (FTP) Number 1, * and the TERM II File Transfer Protocol Number 4 for * packetized file up/downloading. * * Note: UNIX System-Dependent values are indicated by the string [SD] * in a comment field on the same line as the values. * * * -- Lauren Weinstein, 6/81 * -- (Version 2.0) Modified for JHU/UNIX by Richard Conn, 8/1/81 * -- Version 2.1 Mods by Richard Conn, 8/2/81 * . File Size Included on Send Option * -- Version 2.2 Mods by Richard Conn, 8/2/81 * . Log File Generation and Option Incorporated * -- Version 2.3 Mods by Richard Conn, 8/3/81 * . TERM II FTP 1 Supported * . Error Log Reports Enhanced * . CAN Function Added to FTP 3 * . 'd' Option Added to Delete umodem.log File before starting * -- Version 2.4 Mods by Richard Conn, 8/4/81 * . 16K-extent sector number check error corrected * . Count of number of received sectors added * -- Version 2.5 Mods by Richard Conn, 8/5/81 * . ARPA Net Flag added * . ARPA Net parameter ('a') added to command line * . ARPA Net BIS, BIE, BOS, BOE added * . ARPA Net FFH escape added * -- Version 2.6 Mods by Bennett Marks, 8/21/81 (Bucky @ CCA-UNIX) * . mods for UNIX V7 (Note: for JHU compilation define * the variable JHU during 'cc' * . added 'mungmode' flag to protect from inadvertant * overwrite on file receive * . changed timeout handling prior to issuing checksum * -- Version 2.7 Mods by Richard Conn, 8/25/81 (rconn @ BRL) * . correct minor "ifndef" error in which ifndef had no arg * . restructured "ifdef" references so that other versions * of UNIX than Version 7 and JHU can be easily incorporated; * previous ifdef references were for JHU/not JHU; * to compile under Version 7 or JHU UNIX, the following * command lines are recommended: * "cc umodem.c -o umodem -DVER7" for Version 7 * "cc -7 umodem.c -o umodem -DJHU" for JHU * . added 'y' file status display option; this option gives * the user an estimate of the size of the target file to * send from the UNIX system in terms of CP/M records (128 * bytes) and Kbytes (1024 byte units) * . added '7' option which modifies the transmission protocols * for 7 significant bits rather than 8; modifies both FTP 1 * and FTP 3 * -- Version 2.8 Mods by Richard Conn, 8/28/81 * . corrected system-dependent reference to TIOCSSCR (for * disabling page mode) and created the PAGEMODE flag which * is to be set to TRUE to enable this * . added -4 option which engages TERM II, FTP 4 (new release) * -- Version 2.9 Mods by Richard Conn, 9/1/81 * . internal documentation on ARPA Net protocols expanded * . possible operator precedence problem with BITMASK corrected * by redundant parentheses * -- Version 3.0 Mods by Lauren Weinstein, 9/14/81 * . fixed bug in PAGEMODE defines (removed PAGEMODE define * line; now should be compiled with "-DPAGEMODE" if * Page Mode is desired) * . included forward declaration of ttyname() to avoid problems * with newer V7 C compilers * -- Version 3.1 Mods by Geoff Kuenning, 8/28/84 * . Modified to use USG (S3/S5) ioctl's for tty control; other * USG port mods. For USG, compile with the line: * "cc umodem.c -o umodem -DUSG" * */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> /* JHU UNIX tty parameter file */ #ifdef JHU #include <stty.h> #endif /* Version 7 UNIX tty parameter file */ #ifdef VER7 #include <sgtty.h> #endif /* USG UNIX tty parameter file */ #ifdef USG #include <termio.h> #endif #include <signal.h> #define VERSION 31 /* Version Number */ #define TRUE 1 #define FALSE 0 /* Compile with "-DPAGEMODE" if Page Mode (TIOCSSCR) is supported on your * UNIX system. If it is supported, make sure that TIOCSSCR is the * correct name for Page Mode engagement. */ /* ASCII Constants */ #define SOH 001 #define STX 002 #define ETX 003 #define EOT 004 #define ENQ 005 #define ACK 006 #define LF 012 /* Unix LF/NL */ #define CR 015 #define NAK 025 #define SYN 026 #define CAN 030 #define ESC 033 #define CTRLZ 032 /* CP/M EOF for text (usually!) */ /* UMODEM Constants */ #define TIMEOUT -1 #define ERRORMAX 10 /* maximum errors tolerated */ #define RETRYMAX 10 /* maximum retries to be made */ #define BBUFSIZ 128 /* buffer size -- do not change! */ /* [SD] Mode for Created Files */ #define CREATMODE 0666 /* mode for created files */ /* ARPA Net Constants */ /* The following constants are used to communicate with the ARPA * Net SERVER TELNET and TIP programs. These constants are defined * as follows: * IAC <-- Is A Command; indicates that * a command follows * WILL/WONT <-- Command issued to SERVER TELNET * (Host); WILL issues command * and WONT issues negative of * the command * DO/DONT <-- Command issued to TIP; DO issues * command and DONT issues * negative of the command * TRBIN <-- Transmit Binary Command * Examples: * IAC WILL TRBIN <-- Host is configured to transmit Binary * IAC WONT TRBIN <-- Host is configured NOT to transmit binary * IAC DO TRBIN <-- TIP is configured to transmit Binary * IAC DONT TRBIN <-- TIP is configured NOT to transmit binary */ #define IAC 0377 /* Is A Command */ #define DO 0375 /* Command to TIP */ #define DONT 0376 /* Negative of Command to TIP */ #define WILL 0373 /* Command to SERVER TELNET (Host) */ #define WONT 0374 /* Negative of Command to SERVER TELNET */ #define TRBIN 0 /* Transmit Binary Command */ /* JHU UNIX structures */ #ifdef JHU struct sttybuf ttys, ttysnew, ttystemp; /* for stty terminal mode calls */ #endif /* Version 7 UNIX structures */ #ifdef VER7 struct sgttyb ttys, ttysnew, ttystemp; /* for stty terminal mode calls */ #endif /* USG UNIX structures */ #ifdef USG struct termio ttys, ttysnew, ttystemp; /* for stty terminal mode calls */ #endif struct stat statbuf; /* for terminal message on/off control */ FILE *LOGFP, *fopen(); char buff[BBUFSIZ]; int wason; #ifdef VER7 int pagelen; #endif extern char *ttyname (); /* forward declaration for C */ char *tty; char XMITTYPE; int ARPA, RECVFLAG, SENDFLAG, FTP1, PMSG, DELFLAG, LOGFLAG, MUNGMODE; int STATDISP, BIT7, BITMASK; int delay; alarmfunc(); main(argc, argv) int argc; char **argv; { char *logfile; int index; char flag; logfile = "umodem.log"; /* Name of LOG File */ fprintf (stderr, "\nUMODEM Version %d.%d", VERSION/10, VERSION%10); fprintf (stderr, " -- UNIX-Based Remote File Transfer Facility\n"); if (argc < 3 || *argv[1] != '-') { fprintf (stderr, "\nUsage: \n\tumodem "); fprintf (stderr, "-[rb!rt!sb!st][p][l][1][a][m][d][y][7][4]"); fprintf (stderr, " filename\n"); fprintf (stderr, "\n"); fprintf (stderr, "\n\trb <-- Receive Binary"); fprintf (stderr, "\n\trt <-- Receive Text"); fprintf (stderr, "\n\tsb <-- Send Binary"); fprintf (stderr, "\n\tst <-- Send Text"); fprintf (stderr, "\n\tp <-- Turn ON Parameter Display"); fprintf (stderr, "\n\tl <-- (ell) Turn OFF LOG File Entries"); fprintf (stderr, "\n\t1 <-- (one) Employ TERM II FTP 1"); fprintf (stderr, "\n\ta <-- Turn ON ARPA Net Flag"); fprintf (stderr, "\n\tm <-- Allow file overwiting on receive"); fprintf (stderr, "\n\td <-- Delete umodem.log File before starting"); fprintf (stderr, "\n\ty <-- Display file status (size) information only"); fprintf (stderr, "\n\t7 <-- Enable 7-bit transfer mask"); fprintf (stderr, "\n\t4 <-- Enable TERM II FTP 4"); fprintf (stderr, "\n"); exit(-1); } index = 1; /* set index for loop */ delay = 3; /* assume FTP 3 delay */ PMSG = FALSE; /* turn off flags */ FTP1 = FALSE; /* assume FTP 3 (CP/M UG XMODEM2) */ RECVFLAG = FALSE; /* not receive */ SENDFLAG = FALSE; /* not send either */ XMITTYPE = 't'; /* assume text */ DELFLAG = FALSE; /* do NOT delete log file before starting */ LOGFLAG = TRUE; /* assume log messages */ ARPA = FALSE; /* assume not on ARPA Net */ MUNGMODE = FALSE; /* protect files from overwriting */ STATDISP = FALSE; /* assume not a status display */ BIT7 = FALSE; /* assume 8-bit communication */ while ((flag = argv[1][index++]) != '\0') switch (flag) { case 'a' : ARPA = TRUE; /* set ARPA Net */ break; case 'p' : PMSG = TRUE; /* print all messages */ break; case '1' : FTP1 = TRUE; /* select FTP 1 */ delay = 5; /* FTP 1 delay constant */ fprintf (stderr, "\nUMODEM: TERM II FTP 1 Selected\n"); break; case 'd' : DELFLAG = TRUE; /* delete log file first */ break; case 'l' : LOGFLAG = FALSE; /* turn off log report */ break; case 'r' : RECVFLAG = TRUE; /* receive file */ XMITTYPE = gettype(argv[1][index++]); /* get t/b */ break; case 's' : SENDFLAG = TRUE; /* send file */ XMITTYPE = gettype(argv[1][index++]); break; case 'm' : MUNGMODE = TRUE; /* allow overwriting of files */ break; case 'y' : STATDISP = TRUE; /* display file status */ break; case '7' : BIT7 = TRUE; /* transfer only 7 bits */ break; case '4' : FTP1 = TRUE; /* select FTP 1 (varient) */ BIT7 = TRUE; /* transfer only 7 bits */ delay = 5; /* FTP 1 delay constant */ fprintf (stderr, "\nUMODEM: TERM II FTP 4 Selected\n"); break; default : error("Invalid Flag", FALSE); } if (BIT7 && (XMITTYPE == 'b')) { fprintf (stderr, "\nUMODEM: Fatal Error -- Both 7-Bit Transfer and "); fprintf (stderr, "Binary Transfer Selected"); exit(-1); /* error exit to UNIX */ } if (BIT7) /* set MASK value */ BITMASK = 0177; /* 7 significant bits */ else BITMASK = 0377; /* 8 significant bits */ if (PMSG) { fprintf (stderr, "\nSupported File Transfer Protocols:"); fprintf (stderr, "\n\tTERM II FTP 1"); fprintf (stderr, "\n\tCP/M UG XMODEM2 (TERM II FTP 3)"); fprintf (stderr, "\n\tTERM II FTP 4"); fprintf (stderr, "\n\n"); } if (LOGFLAG) { if (!DELFLAG) LOGFP = fopen(logfile, "a"); /* append to LOG file */ else LOGFP = fopen(logfile, "w"); /* new LOG file */ if (LOGFP) { setbuf (LOGFP, (char *) NULL); fprintf(LOGFP,"\n\n++++++++\n"); fprintf(LOGFP,"\nUMODEM Version %d.%d\n", VERSION/10, VERSION%10); fprintf (stderr, "\nUMODEM: LOG File '%s' is Open\n", logfile); } else { LOGFLAG = FALSE; fprintf (stderr, "\nUMODEM: Couldn't open LOG FILE '%s'\n", logfile); perror ("Reason: "); } } if (STATDISP) yfile(argv[2]); /* status of a file */ if (RECVFLAG && SENDFLAG) error("Both Send and Receive Functions Specified", FALSE); if (!RECVFLAG && !SENDFLAG) error("Neither Send nor Receive Functions Specified", FALSE); if (RECVFLAG) { if(open(argv[2], 0) != -1) /* possible abort if file exists */ { fprintf (stderr, "\nUMODEM: Warning -- Target File Exists\n"); if( MUNGMODE == FALSE ) error("Fatal - Can't overwrite file\n",FALSE); fprintf (stderr, "UMODEM: Overwriting Target File\n"); } rfile(argv[2]); /* receive file */ } else sfile(argv[2]); /* send file */ } gettype(ichar) char ichar; { if (ichar == 't') return(ichar); if (ichar == 'b') return(ichar); error("Invalid Send/Receive Parameter - not t or b", FALSE); return; } /* set tty modes for UMODEM transfers */ setmodes() { /* Device characteristics for JHU UNIX */ #ifdef JHU if (gtty(0, &ttys) < 0) /* get current tty params */ error("Can't get TTY Parameters", TRUE); tty = ttyname(0); /* identify current tty */ /* duplicate current modes in ttysnew structure */ ttysnew.ispeed = ttys.ispeed; /* copy input speed */ ttysnew.ospeed = ttys.ospeed; /* copy output speed */ ttysnew.xflags = ttys.xflags; /* copy JHU/UNIX extended flags */ ttysnew.mode = ttys.mode; /* copy standard terminal flags */ ttysnew.mode |= RAW; /* set for RAW Mode */ /* This ORs in the RAW mode value, thereby setting RAW mode and leaving the other mode settings unchanged */ ttysnew.mode &= ~ECHO; /* set for no echoing */ /* This ANDs in the complement of the ECHO setting (for NO echo), thereby leaving all current parameters unchanged and turning OFF ECHO only */ ttysnew.mode &= ~XTABS; /* set for no tab expansion */ ttysnew.mode &= ~LCASE; /* set for no upper-to-lower case xlate */ ttysnew.mode |= ANYP; /* set for ANY Parity */ ttysnew.mode &= ~NL3; /* turn off ALL delays - new line */ ttysnew.mode &= ~TAB3; /* turn off tab delays */ ttysnew.mode &= ~CR3; /* turn off CR delays */ ttysnew.mode &= ~FF1; /* turn off FF delays */ ttysnew.mode &= ~BS1; /* turn off BS delays */ /* the following are JHU/UNIX xflags settings; they are [SD] */ ttysnew.xflags &= ~PAGE; /* turn off paging */ ttysnew.xflags &= ~STALL; /* turn off ^S/^Q recognition */ ttysnew.xflags &= ~TAPE; /* turn off ^S/^Q input control */ ttysnew.xflags &= ~FOLD; /* turn off CR/LF folding at col 72 */ ttysnew.xflags |= NB8; /* turn on 8-bit input/output */ if (stty(0, &ttysnew) < 0) /* set new params */ error("Can't set new TTY Parameters", TRUE); if (stat(tty, &statbuf) < 0) /* get tty status */ #ifdef ERROROK ; #else error("Can't get your TTY Status", TRUE); #endif if (statbuf.st_mode&011) /* messages are on [SD] */ { wason = TRUE; if (chmod(tty, 020600) < 0) /* turn off tty messages [SD] */ #ifdef ERROROK ; #else error("Can't change TTY Mode", TRUE); #endif } else wason = FALSE; /* messages are already off */ #endif /* Device characteristics for Version 7 UNIX */ #ifdef VER7 if (ioctl(0,TIOCGETP,&ttys)<0) /* get tty params [V7] */ error("Can't get TTY Parameters", TRUE); tty = ttyname(0); /* identify current tty */ /* transfer current modes to new structure */ ttysnew.sg_ispeed = ttys.sg_ispeed; /* copy input speed */ ttysnew.sg_ospeed = ttys.sg_ospeed; /* copy output speed */ ttysnew.sg_erase = ttys.sg_erase; /* copy erase flags */ ttysnew.sg_flags = ttys.sg_flags; /* copy flags */ ttysnew.sg_kill = ttys.sg_kill; /* copy std terminal flags */ ttysnew.sg_flags |= RAW; /* set for RAW Mode */ /* This ORs in the RAW mode value, thereby setting RAW mode and leaving the other mode settings unchanged */ ttysnew.sg_flags &= ~ECHO; /* set for no echoing */ /* This ANDs in the complement of the ECHO setting (for NO echo), thereby leaving all current parameters unchanged and turning OFF ECHO only */ ttysnew.sg_flags &= ~XTABS; /* set for no tab expansion */ ttysnew.sg_flags &= ~LCASE; /* set for no upper-to-lower case xlate */ ttysnew.sg_flags |= ANYP; /* set for ANY Parity */ ttysnew.sg_flags &= ~NL3; /* turn off ALL delays - new line */ ttysnew.sg_flags &= ~TAB2; /* turn off tab delays */ ttysnew.sg_flags &= ~CR3; /* turn off CR delays */ ttysnew.sg_flags &= ~FF1; /* turn off FF delays */ ttysnew.sg_flags &= ~BS1; /* turn off BS delays */ ttysnew.sg_flags &= ~TANDEM; /* turn off flow control */ #ifdef PAGEMODE /* make sure page mode is off */ ioctl(0,TIOCSSCR,&pagelen); /* [SD] */ #endif /* set new paramters */ if (ioctl(0,TIOCSETP,&ttysnew) < 0) error("Can't set new TTY Parameters", TRUE); if (stat(tty, &statbuf) < 0) /* get tty status */ #ifdef ERROROK ; #else error("Can't get your TTY Status", TRUE); #endif if (statbuf.st_mode & 022) /* messages are on */ { wason = TRUE; /* turn off tty messages */ if (chmod (tty, statbuf.st_mode & ~022) < 0) #ifdef ERROROK ; #else error ("Can't change TTY Mode", TRUE); #endif } else wason = FALSE; /* messages are already off */ #endif /* Device characteristics for USG UNIX */ #ifdef USG if (ioctl (0, TCGETA, &ttys) < 0) /* get tty params [USG] */ #ifdef ERROROK ; #else error("Can't get TTY Parameters", TRUE); #endif tty = ttyname(0); /* identify current tty */ /* transfer current modes to new structure */ ttysnew = ttys; ttysnew.c_iflag |= IGNPAR; ttysnew.c_iflag &= ~(PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC | IXON | IXANY | IXOFF); ttysnew.c_oflag = 0; /* Turn off everything */ ttysnew.c_cflag &= ~PARENB; ttysnew.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH); ttysnew.c_cc[VMIN] = 6; ttysnew.c_cc[VTIME] = 1; /* set new parameters */ if (ioctl (0, TCSETAW, &ttysnew) < 0) #ifdef ERROROK ; #else error ("Can't set new TTY Parameters", TRUE); #endif if (stat (tty, &statbuf) < 0) /* get tty status */ #ifdef ERROROK ; #else error ("Can't get your TTY Status", TRUE); #endif if (statbuf.st_mode & 022) /* messages are on */ { wason = TRUE; /* turn off tty messages */ #ifdef notdef if (chmod (tty, statbuf.st_mode & ~022) < 0) #ifdef ERROROK ; #else error ("Can't change TTY Mode", TRUE); #endif #else chmod (tty, statbuf.st_mode & ~022); #endif } else wason = FALSE; /* messages are already off */ #endif if (PMSG) { fprintf (stderr, "\nUMODEM: TTY Device Parameters Altered"); ttyparams(); /* print tty params */ } if (ARPA) /* set 8-bit on ARPA Net */ setarpa(); return; } /* set ARPA Net for 8-bit transfers */ setarpa() { sendbyte(IAC); /* Is A Command */ sendbyte(WILL); /* Command to SERVER TELNET (Host) */ sendbyte(TRBIN); /* Command is: Transmit Binary */ sendbyte(IAC); /* Is A Command */ sendbyte(DO); /* Command to TIP */ sendbyte(TRBIN); /* Command is: Transmit Binary */ sleep(3); /* wait for TIP to configure */ return; } /* restore normal tty modes */ restoremodes(errcall) int errcall; { if (ARPA) /* if ARPA Net, reconfigure */ resetarpa(); /* Device characteristic restoration for JHU UNIX */ #ifdef JHU if (wason) /* if messages were on originally */ if (chmod(tty, 020611) < 0) /* [SD] */ error("Can't change TTY Mode", FALSE); if (stty(0, &ttys) < 0) /* restore original tty modes */ { if (!errcall) error("RESET - Can't restore normal TTY Params", FALSE); else { fprintf (stderr, "UMODEM: "); fprintf (stderr, "RESET - Can't restore normal TTY Params\n"); } } #endif /* Device characteristic restoration for Version 7 UNIX */ #ifdef VER7 if (wason) /* if messages were on originally */ if (chmod (tty, statbuf.st_mode) < 0) error("Can't change TTY Mode", FALSE); if (ioctl(0,TIOCSETP,&ttys) < 0) { if (!errcall) error("RESET - Can't restore normal TTY Params", FALSE); else { fprintf (stderr, "UMODEM: "); fprintf (stderr, "RESET - Can't restore normal TTY Params\n"); } } #endif /* Device characteristic restoration for USG UNIX */ #ifdef USG if (wason) /* if messages were on originally */ #ifdef notdef if (chmod (tty, statbuf.st_mode) < 0) #ifdef ERROROK ; #else error("Can't change TTY Mode", FALSE); #endif #else chmod (tty, statbuf.st_mode); #endif if (ioctl (0, TCSETAW, &ttys) < 0) #ifdef ERROROK ; #else { if (!errcall) error("RESET - Can't restore normal TTY Params", FALSE); else { fprintf (stderr, "UMODEM: "); fprintf (stderr, "RESET - Can't restore normal TTY Params\n"); } } #endif #endif if (PMSG) { fprintf (stderr, "\nUMODEM: TTY Device Parameters Restored"); ttyparams(); /* print tty params */ } return; } /* reset the ARPA Net */ resetarpa() { sendbyte(IAC); /* Is A Command */ sendbyte(WONT); /* Negative Command to SERVER TELNET (Host) */ sendbyte(TRBIN); /* Command is: Don't Transmit Binary */ sendbyte(IAC); /* Is A Command */ sendbyte(DONT); /* Negative Command to TIP */ sendbyte(TRBIN); /* Command is: Don't Transmit Binary */ return; } /* print error message and exit; if mode == TRUE, restore normal tty modes */ error(msg, mode) char *msg; int mode; { if (mode) restoremodes(TRUE); /* put back normal tty modes */ fprintf (stderr, "UMODEM: %s\n", msg); if (LOGFLAG) { fprintf(LOGFP, "UMODEM Fatal Error: %s\n", msg); fclose(LOGFP); } exit(-1); } /** print status (size) of a file **/ yfile(name) char *name; { fprintf (stderr, "UMODEM File Status Display for %s\n", name); if (LOGFLAG) fprintf(LOGFP,"UMODEM File Status Display for %s\n", name); if (open(name,0) < 0) { fprintf (stderr, "File %s does not exist\n", name); if (LOGFLAG) fprintf(LOGFP,"File %s does not exist\n", name); exit(-1); /* error exit to UNIX */ } prfilestat(name); /* print status */ fprintf (stderr, "\n"); if (LOGFLAG) { fprintf(LOGFP,"\n"); fclose(LOGFP); } exit(0); /* exit to UNIX -- no error */ } /** receive a file **/ rfile(name) char *name; { char mode; int fd, j, firstchar, sectnum, sectcurr, tmode; int sectcomp, errors, errorflag, recfin; register int bufctr, checksum; register int c; int errorchar, fatalerror, startstx, inchecksum, endetx, endenq; long recvsectcnt; mode = XMITTYPE; /* set t/b mode */ if ((fd = creat(name, CREATMODE)) < 0) error("Can't create file for receive", FALSE); setmodes(); /* setup tty modes for xfer */ fprintf (stderr, "\r\nUMODEM: File Name: %s", name); if (LOGFLAG) { fprintf(LOGFP, "\n----\nUMODEM Receive Function\n"); fprintf(LOGFP, "File Name: %s\n", name); if (FTP1) if (!BIT7) fprintf(LOGFP, "TERM II File Transfer Protocol 1 Selected\n"); else fprintf(LOGFP, "TERM II File Transfer Protocol 4 Selected\n"); else fprintf(LOGFP, "TERM II File Transfer Protocol 3 (CP/M UG) Selected\n"); if (BIT7) fprintf(LOGFP, "7-Bit Transmission Enabled\n"); else fprintf(LOGFP, "8-Bit Transmission Enabled\n"); } fprintf (stderr, "\r\nUMODEM: "); if (BIT7) fprintf (stderr, "7-Bit"); else fprintf (stderr, "8-Bit"); fprintf (stderr, " Transmission Enabled"); fprintf (stderr, "\r\nUMODEM: Ready to RECEIVE File\r\n"); recfin = FALSE; sectnum = errors = 0; fatalerror = FALSE; /* NO fatal errors */ recvsectcnt = 0; /* number of received sectors */ if (mode == 't') tmode = TRUE; else tmode = FALSE; if (FTP1) { while (readbyte(4) != SYN); sendbyte(ACK); /* FTP 1 Sync */ } else sendbyte(NAK); /* FTP 3 Sync */ do { errorflag = FALSE; do { firstchar = readbyte(6); } while ((firstchar != SOH) && (firstchar != EOT) && (firstchar != TIMEOUT)); if (firstchar == TIMEOUT) { if (LOGFLAG) fprintf(LOGFP, "Timeout on Sector %d\n", sectnum); errorflag = TRUE; } if (firstchar == SOH) { if (FTP1) readbyte(5); /* discard leading zero */ sectcurr = readbyte(delay); sectcomp = readbyte(delay); if (FTP1) startstx = readbyte(delay); /* get leading STX */ if ((sectcurr + sectcomp) == BITMASK) { if (sectcurr == ((sectnum+1)&BITMASK)) { checksum = 0; for (j = bufctr = 0; j < BBUFSIZ; j++) { buff[bufctr] = c = readbyte(delay); checksum = ((checksum+c)&BITMASK); if (!tmode) /* binary mode */ { bufctr++; continue; } if (c == CR) continue; /* skip CR's */ if (c == CTRLZ) /* skip CP/M EOF char */ { recfin = TRUE; /* flag EOF */ continue; } if (!recfin) bufctr++; } if (FTP1) endetx = readbyte(delay); /* get ending ETX */ inchecksum = readbyte(delay); /* get checksum */ if (FTP1) endenq = readbyte(delay); /* get ENQ */ if (checksum == inchecksum) /* good checksum */ { errors = 0; recvsectcnt++; sectnum = sectcurr; /* update sector counter */ if (write(fd, buff, bufctr) < 0) error("File Write Error", TRUE); else { if (FTP1) sendbyte(ESC); /* FTP 1 requires <ESC> */ sendbyte(ACK); } } else { if (LOGFLAG) fprintf(LOGFP, "Checksum Error on Sector %d\n", sectnum); errorflag = TRUE; } } else { if (sectcurr == sectnum) { while(readbyte(3) != TIMEOUT); if (FTP1) sendbyte(ESC); /* FTP 1 requires <ESC> */ sendbyte(ACK); } else { if (LOGFLAG) { fprintf(LOGFP, "Phase Error - Received Sector is "); fprintf(LOGFP, "%d while Expected Sector is %d\n", sectcurr, ((sectnum+1)&BITMASK)); } errorflag = TRUE; fatalerror = TRUE; if (FTP1) sendbyte(ESC); /* FTP 1 requires <ESC> */ sendbyte(CAN); } } } else { if (LOGFLAG) fprintf(LOGFP, "Header Sector Number Error on Sector %d\n", sectnum); errorflag = TRUE; } } if (FTP1 && !errorflag) { if (startstx != STX) { errorflag = TRUE; /* FTP 1 STX missing */ errorchar = STX; } if (endetx != ETX) { errorflag = TRUE; /* FTP 1 ETX missing */ errorchar = ETX; } if (endenq != ENQ) { errorflag = TRUE; /* FTP 1 ENQ missing */ errorchar = ENQ; } if (errorflag && LOGFLAG) { fprintf(LOGFP, "Invalid Packet-Control Character: "); switch (errorchar) { case STX : fprintf(LOGFP, "STX"); break; case ETX : fprintf(LOGFP, "ETX"); break; case ENQ : fprintf(LOGFP, "ENQ"); break; default : fprintf(LOGFP, "Error"); break; } fprintf(LOGFP, "\n"); } } if (errorflag == TRUE) { errors++; while (readbyte(3) != TIMEOUT); sendbyte(NAK); } } while ((firstchar != EOT) && (errors != ERRORMAX) && !fatalerror); if ((firstchar == EOT) && (errors < ERRORMAX)) { if (!FTP1) sendbyte(ACK); close(fd); restoremodes(FALSE); /* restore normal tty modes */ if (FTP1) while (readbyte(3) != TIMEOUT); /* flush EOT's */ sleep(3); /* give other side time to return to terminal mode */ if (LOGFLAG) { fprintf(LOGFP, "\nReceive Complete\n"); fprintf(LOGFP,"Number of Received CP/M Records is %ld\n", recvsectcnt); fclose(LOGFP); } fprintf (stderr, "\n"); exit(0); } else { if (LOGFLAG && FTP1 && fatalerror) fprintf(LOGFP, "Synchronization Error"); error("TIMEOUT -- Too Many Errors", TRUE); } } /** send a file **/ sfile(name) char *name; { char mode; int fd, charval, attempts; int nlflag, sendfin, tmode; register int bufctr, checksum, sectnum; char c; int sendresp; /* response char to sent block */ mode = XMITTYPE; /* set t/b mode */ if ((fd = open(name, 0)) < 0) { if (LOGFLAG) fprintf(LOGFP, "Can't Open File\n"); error("Can't open file for send", FALSE); } setmodes(); /* setup tty modes for xfer */ fprintf (stderr, "\r\nUMODEM: File Name: %s", name); if (LOGFLAG) { fprintf(LOGFP, "\n----\nUMODEM Send Function\n"); fprintf(LOGFP, "File Name: %s\n", name); } prfilestat(name); /* print file size statistics */ if (LOGFLAG) { if (FTP1) if (!BIT7) fprintf(LOGFP, "TERM II File Transfer Protocol 1 Selected\n"); else fprintf(LOGFP, "TERM II File Transfer Protocol 4 Selected\n"); else fprintf(LOGFP, "TERM II File Transfer Protocol 3 (CP/M UG) Selected\n"); if (BIT7) fprintf(LOGFP, "7-Bit Transmission Enabled\n"); else fprintf(LOGFP, "8-Bit Transmission Enabled\n"); } printf("\r\nUMODEM: "); if (BIT7) fprintf (stderr, "7-Bit"); else fprintf (stderr, "8-Bit"); fprintf (stderr, " Transmission Enabled"); fprintf (stderr, "\r\nUMODEM: Ready to SEND File\r\n"); if (mode == 't') tmode = TRUE; else tmode = FALSE; sendfin = nlflag = FALSE; attempts = 0; if (FTP1) { sendbyte(SYN); /* FTP 1 Synchronize with Receiver */ while (readbyte(5) != ACK) { if(++attempts > RETRYMAX*6) error("Remote System Not Responding", TRUE); sendbyte(SYN); } } else { while (readbyte(30) != NAK) /* FTP 3 Synchronize with Receiver */ if (++attempts > RETRYMAX) error("Remote System Not Responding", TRUE); } sectnum = 1; /* first sector number */ attempts = 0; do { for (bufctr=0; bufctr < BBUFSIZ;) { if (nlflag) { buff[bufctr++] = LF; /* leftover newline */ nlflag = FALSE; } if ((charval = read(fd, &c, 1)) < 0) error("File Read Error", TRUE); if (charval == 0) /* EOF for read */ { sendfin = TRUE; /* this is the last sector */ if (tmode) buff[bufctr++] = CTRLZ; /* Control-Z for CP/M EOF */ else bufctr++; continue; } if (tmode && c == LF) /* text mode & Unix newline? */ { if (c == LF) /* Unix newline? */ { buff[bufctr++] = CR; /* insert carriage return */ if (bufctr < BBUFSIZ) buff[bufctr++] = LF; /* insert Unix newline */ else nlflag = TRUE; /* insert newline on next sector */ } continue; } buff[bufctr++] = c; /* copy the char without change */ } attempts = 0; do { sendbyte(SOH); /* send start of packet header */ if (FTP1) sendbyte(0); /* FTP 1 Type 0 Packet */ sendbyte(sectnum); /* send current sector number */ sendbyte(-sectnum-1); /* and its complement */ if (FTP1) sendbyte(STX); /* send STX */ checksum = 0; /* init checksum */ for (bufctr=0; bufctr < BBUFSIZ; bufctr++) { sendbyte(buff[bufctr]); /* send the byte */ if (ARPA && (buff[bufctr]==0xff)) /* ARPA Net FFH esc */ sendbyte(buff[bufctr]); /* send 2 FFH's for one */ checksum = ((checksum+buff[bufctr])&BITMASK); } /* while (readbyte(3) != TIMEOUT); flush chars from line */ if (FTP1) sendbyte(ETX); /* send ETX */ sendbyte(checksum); /* send the checksum */ if (FTP1) sendbyte(ENQ); /* send ENQ */ attempts++; if (FTP1) { sendresp = NAK; /* prepare for NAK */ if (readbyte(10) == ESC) sendresp = readbyte(10); } else sendresp = readbyte(10); /* get response */ if ((sendresp != ACK) && LOGFLAG) { fprintf(LOGFP, "Non-ACK Received on Sector %d\n", sectnum); if (sendresp == TIMEOUT) fprintf(LOGFP, "This Non-ACK was a TIMEOUT\n"); } } while((sendresp != ACK) && (attempts != RETRYMAX)); sectnum++; /* increment to next sector number */ } while (!sendfin && (attempts != RETRYMAX)); if (attempts == RETRYMAX) error("Remote System Not Responding", TRUE); attempts = 0; if (FTP1) while (attempts++ < 10) sendbyte(EOT); else { sendbyte(EOT); /* send 1st EOT */ while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX)) sendbyte(EOT); if (attempts >= RETRYMAX) error("Remote System Not Responding on Completion", TRUE); } close(fd); restoremodes(FALSE); sleep(5); /* give other side time to return to terminal mode */ if (LOGFLAG) { fprintf(LOGFP, "\nSend Complete\n"); fclose(LOGFP); } fprintf (stderr, "\n"); exit(0); } /* print file size status information */ prfilestat(name) char *name; { struct stat filestatbuf; /* file status info */ stat(name, &filestatbuf); /* get file status bytes */ fprintf (stderr, "\r\nUMODEM: Estimated File Size %ldK, %ld Records, %ld Bytes", (filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1, filestatbuf.st_size); if (LOGFLAG) fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n", (filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1, filestatbuf.st_size); return; } /* get a byte from data stream -- timeout if "seconds" elapses */ readbyte(seconds) unsigned seconds; { char c; signal(SIGALRM,alarmfunc); /* catch alarms */ alarm(seconds); /* set the alarm clock */ if (read(0, &c, 1) < 0) /* get a char; error means we timed out */ { return(TIMEOUT); } alarm(0); /* turn off the alarm */ return((c&BITMASK)); /* return the char */ } /* send a byte to data stream */ sendbyte(data) char data; { char dataout; dataout = (data&BITMASK); /* mask for 7 or 8 bits */ write(1, &dataout, 1); /* write the byte */ return; } /* function for alarm clock timeouts */ alarmfunc() { return; /* this is basically a dummy function to force error */ /* status return on the "read" call in "readbyte" */ } /* print data on TTY setting */ ttyparams() { /* Obtain TTY parameters for JHU UNIX */ #ifdef JHU gtty(0, &ttystemp); /* get current tty params */ #endif /* Obtain TTY parameters for Version 7 UNIX */ #ifdef VER7 ioctl(0,TIOCGETP,&ttystemp); #endif /* Obtain TTY parameters for USG UNIX */ #ifdef USG ioctl (0, TCGETA, &ttystemp); #endif tty = ttyname(0); /* get name of tty */ stat(tty, &statbuf); /* get more tty params */ /* Print terminal characteristics for JHU UNIX */ #ifdef JHU fprintf (stderr, "\r\n\nTTY Device Parameter Display"); fprintf (stderr, "\r\n\tTTY Device Name is %s\r\n\n", tty); fprintf (stderr, "\tAny Parity Allowed "); pryn(ANYP); fprintf (stderr, "\tEven Parity Allowed"); pryn(EVENP); fprintf (stderr, "\tOdd Parity Allowed "); pryn(ODDP); fprintf (stderr, "\tEcho Enabled "); pryn(ECHO); fprintf (stderr, "\tLower Case Map "); pryn(LCASE); fprintf (stderr, "\tTabs Expanded "); pryn(XTABS); fprintf (stderr, "\tCR Mode Enabled "); pryn(CRMOD); fprintf (stderr, "\tRAW Mode Enabled "); pryn(RAW); fprintf (stderr, "\tBinary Mode Enabled"); pryn1(NB8); fprintf (stderr, "\tCR/LF in Col 72 "); pryn1(FOLD); fprintf (stderr, "\tRecognize ^S/^Q "); pryn1(STALL); fprintf (stderr, "\tSend ^S/^Q "); pryn1(TAPE); fprintf (stderr, "\tTerminal can BS "); pryn1(SCOPE); fprintf (stderr, "\r\n"); /* New line to separate topics */ fprintf (stderr, "\tTerminal Paging is "); pryn1(PAGE); if (ttystemp.xflags&PAGE) fprintf (stderr, "\t Lines/Page is %d\r\n", ttystemp.xflags&PAGE); fprintf (stderr, "\r\n"); /* New line to separate topics */ fprintf (stderr, "\tTTY Input Rate : "); prbaud(ttystemp.ispeed); /* print baud rate */ fprintf (stderr, "\tTTY Output Rate : "); prbaud(ttystemp.ospeed); /* print output baud rate */ fprintf (stderr, "\r\n"); /* New line to separate topics */ fprintf (stderr, "\tMessages Enabled "); if (statbuf.st_mode&011) fprintf (stderr, ": Yes\r\n"); else fprintf (stderr, ": No\r\n"); #endif /* Print characteristics for Version 7 UNIX */ #ifdef VER7 fprintf (stderr, "\r\n\nTTY Device Parameter Display"); fprintf (stderr, "\r\n\tTTY Device Name is %s\r\n\n", tty); fprintf (stderr, "\tAny Parity Allowed "); pryn(ANYP); fprintf (stderr, "\tEven Parity Allowed"); pryn(EVENP); fprintf (stderr, "\tOdd Parity Allowed "); pryn(ODDP); fprintf (stderr, "\tEcho Enabled "); pryn(ECHO); fprintf (stderr, "\tLower Case Map "); pryn(LCASE); fprintf (stderr, "\tTabs Expanded "); pryn(XTABS); fprintf (stderr, "\tCR Mode Enabled "); pryn(CRMOD); fprintf (stderr, "\tRAW Mode Enabled "); pryn(RAW); fprintf (stderr, "\tTTY Input Rate : "); prbaud(ttystemp.sg_ispeed); fprintf (stderr, "\tTTY Output Rate : "); prbaud(ttystemp.sg_ospeed); /* print output baud rate */ fprintf (stderr, "\tMessages Enabled "); if (statbuf.st_mode&022) fprintf (stderr, ": Yes\r\n"); else fprintf (stderr, ": No\r\n"); #endif /* Print characteristics for USG UNIX */ #ifdef USG fprintf (stderr, "\r\n\nTTY Device Parameter Display"); fprintf (stderr, "\r\n\tTTY Device Name is %s\r\n\n", tty); fprintf (stderr, "\tIgnore Break "); pryn (ttysnew.c_iflag, IGNBRK); fprintf (stderr, "\tInterrupt on Break "); pryn (ttysnew.c_iflag, BRKINT); fprintf (stderr, "\tIgnore Bad-Parity Characters "); pryn (ttysnew.c_iflag, IGNPAR); fprintf (stderr, "\tMark Parity Errors "); pryn (ttysnew.c_iflag, PARMRK); fprintf (stderr, "\tEnable Input Parity Check "); pryn (ttysnew.c_iflag, INPCK); fprintf (stderr, "\tStrip to Seven Bits "); pryn (ttysnew.c_iflag, ISTRIP); fprintf (stderr, "\tMap NL to CR on Input "); pryn (ttysnew.c_iflag, INLCR); fprintf (stderr, "\tMap CR to NL on Input "); pryn (ttysnew.c_iflag, ICRNL); fprintf (stderr, "\tIgnore CR Characters "); pryn (ttysnew.c_iflag, IGNCR); fprintf (stderr, "\tMap Upper to Lower on Input "); pryn (ttysnew.c_iflag, IUCLC); fprintf (stderr, "\tX-on/X-off Response Enabled "); pryn (ttysnew.c_iflag, IXON); fprintf (stderr, "\tAny Character Restarts Output"); pryn (ttysnew.c_iflag, IXANY); fprintf (stderr, "\tSend X-on/X-off "); pryn (ttysnew.c_iflag, IXOFF); fprintf (stderr, "\r\n"); /* New line to separate topics */ fprintf (stderr, "\tOutput Postprocessing Enabled"); pryn (ttysnew.c_oflag, OPOST); fprintf (stderr, "\tMap Lower to Upper on Output "); pryn (ttysnew.c_oflag, OLCUC); fprintf (stderr, "\tMap NL to CR/NL on Output "); pryn (ttysnew.c_oflag, ONLCR); fprintf (stderr, "\tMap CR to NL on Output "); pryn (ttysnew.c_oflag, OCRNL); fprintf (stderr, "\tCR Output at Column 0 "); pryn (~ttysnew.c_oflag, ONOCR); fprintf (stderr, "\tNL Performs CR Function "); pryn (ttysnew.c_oflag, ONLRET); fprintf (stderr, "\tUse Fill Characters for Delay"); pryn (ttysnew.c_oflag, OFILL); fprintf (stderr, "\tFill Character DEL, not NULL "); pryn (ttysnew.c_oflag, OFDEL); fprintf (stderr, "\tTabs Expanded "); pryn ((ttysnew.c_oflag & TAB3) == TAB3, 1); fprintf (stderr, "\r\n"); /* New line to separate topics */ fprintf (stderr, "\tCharacter Size : "); prcsize (ttysnew.c_cflag & CSIZE); fprintf (stderr, "\tTwo stop bits "); pryn (ttysnew.c_cflag, CSTOPB); fprintf (stderr, "\tParity Enabled "); pryn (ttysnew.c_cflag, PARENB); fprintf (stderr, "\tOdd Parity "); pryn (ttysnew.c_cflag, PARODD); fprintf (stderr, "\tHang Up on Last Close "); pryn (ttysnew.c_cflag, HUPCL); fprintf (stderr, "\tLocal Line "); pryn (ttysnew.c_cflag, CLOCAL); fprintf (stderr, "\r\n"); /* New line to separate topics */ fprintf (stderr, "\tSignal Processing Enabled "); pryn (ttysnew.c_lflag, ISIG); fprintf (stderr, "\tCanonical Input Processing "); pryn (ttysnew.c_lflag, ICANON); fprintf (stderr, "\tCanonical Upper/Lower Output "); pryn (ttysnew.c_lflag, XCASE); fprintf (stderr, "\tEcho Enabled "); pryn (ttysnew.c_lflag, ECHO); fprintf (stderr, "\tCRT Backspace Enabled "); pryn (ttysnew.c_lflag, ECHOE); fprintf (stderr, "\tEcho Kill After NL Character "); pryn (ttysnew.c_lflag, ECHOK); fprintf (stderr, "\tEcho NL "); pryn (ttysnew.c_lflag, ECHONL); fprintf (stderr, "\tFlush When Signal Received "); pryn (~ttysnew.c_lflag, NOFLSH); fprintf (stderr, "\r\n"); /* New line to separate topics */ fprintf (stderr, "\tInterrupt Character : 0x%x\r\n", ttysnew.c_cc[VINTR]); fprintf (stderr, "\tQuit Character : 0x%x\r\n", ttysnew.c_cc[VQUIT]); fprintf (stderr, "\tErase Character : 0x%x\r\n", ttysnew.c_cc[VERASE]); fprintf (stderr, "\tKill Character : 0x%x\r\n", ttysnew.c_cc[VKILL]); if (ttysnew.c_lflag & ICANON) { fprintf (stderr, "\tEOF Character : 0x%x\r\n", ttysnew.c_cc[VEOF]); fprintf (stderr, "\tEOL Character : 0x%x\r\n", ttysnew.c_cc[VEOL]); } else { fprintf (stderr, "\tMinimum Characters : %d\r\n", ttysnew.c_cc[VMIN]); fprintf (stderr, "\tMaximum Time : %d\r\n", ttysnew.c_cc[VTIME]); } fprintf (stderr, "\tTTY Data Rate : "); prbaud (ttystemp.c_cflag & CBAUD); fprintf (stderr, "\tMessages Enabled "); pryn (statbuf.st_mode, 022); #endif } #ifdef JHU pryn (iflag) int iflag; { /* JHU UNIX flag test */ if (ttystemp.mode&iflag) #endif #ifdef VER7 pryn (iflag) int iflag; { /* Version 7 UNIX flag test */ if (ttystemp.sg_flags&iflag) #endif #ifdef USG pryn (mode, iflag) int mode, iflag; { /* USG UNIX flag test */ if (mode & iflag) #endif fprintf (stderr, ": Yes\r\n"); else fprintf (stderr, ": No\r\n"); } /* Extended flag test for JHU UNIX only */ #ifdef JHU pryn1(iflag) int iflag; { if (ttystemp.xflags&iflag) fprintf (stderr, ": Yes\r\n"); else fprintf (stderr, ": No\r\n"); } #endif prbaud(speed) char speed; { switch (speed) { /* JHU UNIX speed flag cases */ #ifdef JHU case B0050 : fprintf (stderr, "50"); break; case B0075 : fprintf (stderr, "75"); break; case B0110 : fprintf (stderr, "110"); break; case B0134 : fprintf (stderr, "134.5"); break; case B0150 : fprintf (stderr, "150"); break; case B0200 : fprintf (stderr, "200"); break; case B0300 : fprintf (stderr, "300"); break; case B0600 : fprintf (stderr, "600"); break; case B1200 : fprintf (stderr, "1200"); break; case B1800 : fprintf (stderr, "1800"); break; case B2400 : fprintf (stderr, "2400"); break; case B4800 : fprintf (stderr, "4800"); break; case B9600 : fprintf (stderr, "9600"); break; case EXT_A : fprintf (stderr, "External A"); break; case EXT_B : fprintf (stderr, "External B"); break; #endif /* Version 7 UNIX speed flag cases */ #ifdef VER7 case B50 : fprintf (stderr, "50"); break; case B75 : fprintf (stderr, "75"); break; case B110 : fprintf (stderr, "110"); break; case B134 : fprintf (stderr, "134.5"); break; case B150 : fprintf (stderr, "150"); break; case B200 : fprintf (stderr, "200"); break; case B300 : fprintf (stderr, "300"); break; case B600 : fprintf (stderr, "600"); break; case B1200 : fprintf (stderr, "1200"); break; case B1800 : fprintf (stderr, "1800"); break; case B2400 : fprintf (stderr, "2400"); break; case B4800 : fprintf (stderr, "4800"); break; case B9600 : fprintf (stderr, "9600"); break; case EXTA : fprintf (stderr, "External A"); break; case EXTB : fprintf (stderr, "External B"); break; #endif /* USG UNIX speed flag cases */ #ifdef USG case B50 : fprintf (stderr, "50"); break; case B75 : fprintf (stderr, "75"); break; case B110 : fprintf (stderr, "110"); break; case B134 : fprintf (stderr, "134.5"); break; case B150 : fprintf (stderr, "150"); break; case B200 : fprintf (stderr, "200"); break; case B300 : fprintf (stderr, "300"); break; case B600 : fprintf (stderr, "600"); break; case B1200 : fprintf (stderr, "1200"); break; case B1800 : fprintf (stderr, "1800"); break; case B2400 : fprintf (stderr, "2400"); break; case B4800 : fprintf (stderr, "4800"); break; case B9600 : fprintf (stderr, "9600"); break; case EXTA : fprintf (stderr, "External A"); break; case EXTB : fprintf (stderr, "External B"); break; #endif default : fprintf (stderr, "Error"); break; } fprintf (stderr, " Baud\r\n"); } /* USG UNIX Character size cases */ #ifdef USG prcsize (size) int size; { switch (size) { case CS5 : fprintf (stderr, "5"); break; case CS6 : fprintf (stderr, "6"); break; case CS7 : fprintf (stderr, "7"); break; case CS8 : fprintf (stderr, "8"); break; default : fprintf (stderr, "Error"); break; } fprintf (stderr, " bits\r\n"); } #endif @//E*O*F umodem.c// chmod u=rw,g=r,o=r umodem.c exit 0 -- Geoff Kuenning ...!ihnp4!trwrb!desint!geoff