emigh@ecsvax.UUCP (09/27/83)
: Run this shell script with "sh" not "csh" PATH=:/bin:/usr/bin:/usr/ucb export PATH all=FALSE if [ $1x = -ax ]; then all=TRUE fi /bin/echo 'Extracting uc.1l' sed 's/^X//' <<'//go.sysin dd *' >uc.1l X.TH UC 1 X.SH NAME uc - Version 1.0 - UNIX-to-CP/M File Transfer Tool X.SH SYNOPSIS UC is a file transfer tool which runs under UNIX. It, in conjunction with a CP/M-based MODEM communications program, allows the user to transfer both binary and text files between UNIX and CP/M. UC is based on ideas from UMODEM 3.5. UC is a totally new design, including many features of similar function but different implementation and adding many new features and both a menu-driven and command-completion user interface. Usage: uc c[o] [filename] where 'c' MUST be One of the Following Commands -- C -- CRC Check on Binary File (filename required) c -- CRC Check on Text File (filename required) f or F -- File Status (filename required) R -- Receive Binary File (filename required) r -- Receive Text File (filename required) S -- Send Binary File (filename required) s -- Send Text File (filename required) z or Z -- Enter Command Mode (filename NOT required) and Additional Options 'o' Include -- 1 -- Select File Transfer Protocol 1 7 -- Select 7-Bit Transfer a or A -- Enable ARPA Net Communication b or B -- Override 'c', 's', or 'r' to Binary l or L -- Turn Off Log Entries t or T -- Override 'C', 'S', or 'R' to Text Examples: uc S myfile -or- uc sb myfile <-- Send Binary File uc s7l myfile <-- Send Text File with 7 Bits and No Log X.SH DESCRIPTION X.fi UC is a file transfer tool which runs on UNIX. It allows the user to transfer files between UNIX and CP/M systems, verify the integrity of transferred files via Cyclic Redundancy Check (CRC) value computation, and perform other functions useful in file transfer. UC implements the following communications protocols: 1) "CP/M User's Group XMODEM" protocol developed by Ward Christensen (checksum only) 2) TERM II/TERM III File Transfer Protocol 1 developed by Richard Conn UC supports 7- or 8-bit transfers (7 or 8 significant bits/byte) for text files and 8-bit transfers for binary files. There is currently no batch file transfer capability. The program writes logging data to a file in the user's home directory called uc.log. This file contains a transaction of activity since the invocation of the program, and this transaction includes data on file transmissions (error log). The program's defaults can be initialized for each user by a setup file called .ucsetup (note the leading dot, so .ucsetup is hidden from normal directory displays). .ucsetup is a text file which contains initialization options for uc. It can be created by using any editor under UNIX. The program will do a protocol file transfer with error checking to or from a CP/M system running Ward Christensen's program MODEM or one of its derivatives (MODEM7 or APMOD777 etc.) or any program that uses the same protocols (e.g. ZPRO or TERM II). Note that executable and squeezed files must use the -sb or -rb options. X.SS UC SETUP FILE If a file named .ucsetup is present in the user's home directory, then uc will load this file and interpret commands from it. These commands, which are similar to the command line and command mode options, establish default conditions for uc. If .ucsetup is not present in the user's home directory, then uc will configure itself with its default values. The following are the characters which may be placed in a .ucsetup file to establish working conditions for uc: X.nf Char Function ! Comment, extending from "!" to end of line 1 Select FTP 1 3 Select FTP 3 (CP/M User's Group Protocol) 7 Select 7-Bit Transmission 8 Select 8-Bit Transmission a/A Turn on ARPA Net Communication l/L Turn on Logging to uc.log m/M Turn on Menu Display for uc Command Mode - Negate Effect of a/A, l/L, or m/M: -a/-A, -l/-L, or -m/-M X.fi If a command is omitted or the .ucsetup file is not found in the user's home directory, then the following defaults apply: X.nf 3 FTP 3 (CP/M User's Group Protocol) 8 8-Bit Transmission -A No ARPA Net Communication L Activity Log uc.log is Generated -M No Menu Display for uc Command Mode X.fi The following is a sample (and complete) .ucsetup file: X.nf ! UC Configuration File for Richard Conn 3 ! Use FTP 3 (since 3 is default, this is not necessary) 8 ! Use 8 Bits -a ! No ARPA Net Communication -m ! No Menu L ! Log File X.fi X.SS UC COMMAND MODE The following options are supported under the command mode of uc: X.nf UC Command Summary ------- Major Function ------- -- File Xfer Options -- c <file> CRC Value of File 1 or 3 Select FTP r <file> Receive File 7 or 8 Select Bits s <file> Send File a or A Toggle ARPA Net e or E Display Environ ------- UNIX Function ------- -------- Notes -------- d <dir/file> Display Directory Major Fct - if caps(C), f <file> File Size Info binary file; if not(c), l <dir> Log Into Dir text file m Toggle Menu x Exit to UNIX UNIX Fct - either case z UNIX Command X.fi A sample session which illustrates the command mode of uc follows. Comments are inserted into the session; these comments are preceeded by '<--' and continue to the end of the line. X.nf $ uc z <-- Invoke uc in command mode UC Version 1.0 - UNIX-to-CP/M File Transfer Tool UC Configuration File /user/rxc/.ucsetup UC Command Mode -- Type 'h' for Help UC Command? <-- You can type h, H, ?, or / to receive online doc UC Command? Directory of (dir or file spec) <-- I typed "d" and <CR> (<CR> selects all files) -- Filename -- - Size - -- Filename -- - Size - comhex.1 810 menu.1 8571 comhex.man 1448 menu.man 10706 cpmunix.1 825 skeleton 146 cpmunix.man 1490 type.1 1575 cpmutl7.doc 766 type.man 2239 crck.1 1553 uc.1 7743 crck.man 2189 uc.man 9338 dir.1 5542 umodem.1 4751 dir.man 5744 umodem.man 6440 man.1 3968 unixcpm.1 617 man.doc 14827 unixcpm.man 1284 man.menu 784 -- 23 Entries Displayed, 93356 Bytes -- UC Command? Login (directory) /user/rxc/.c <-- I typed "l" and "/us..." X/user/rxc/.c <-- uc showed new dir UC Command? Directory of (dir or file spec) <-- I typed "d" and <CR> -- Filename -- - Size - -- Filename -- - Size - dir.c 7485 uc.c 30629 -- 2 Entries Displayed, 38114 Bytes -- UC Command? Directory of (dir or file spec) /user/rxc/.man -- Filename -- - Size - -- Filename -- - Size - comhex.1 810 menu.1 8571 comhex.man 1448 menu.man 10706 cpmunix.1 825 skeleton 146 cpmunix.man 1490 type.1 1575 cpmutl7.doc 766 type.man 2239 crck.1 1553 uc.1 7743 crck.man 2189 uc.man 9338 dir.1 5542 umodem.1 4751 dir.man 5744 umodem.man 6440 man.1 3968 unixcpm.1 617 man.doc 14827 unixcpm.man 1284 man.menu 784 -- 23 Entries Displayed, 93356 Bytes -- UC Command? UNIX Command Line (command line) pwd X/user/rxc/.c UC Command? File Status of (file name) dir.c <-- I typed "f" and "dir.c" File Size of dir.c is 26K, 201 Blocks UC Command? File Status of (file name) uc.c File Size of uc.c is 27K, 216 Blocks UC Command? CRC of Text File (file name) uc.c <-- I typed "c" and "uc.c" CRC of uc.c is 72EE UC Command? CRC of Binary File (file name) <-- typing "C" gives binary, and striking <CR> usually aborts UC Command? Send Text File (file name) dir.c <-- I typed "s" and "dir.c" UC Sending File: dir.c File Size of dir.c is 26K, 201 Blocks FTP 3, 8-Bit Transfer Selected Ready to Send File <-- Detail Left Out --> UC Command? Exit X.fi X.SH FILES X.nf uc.c <-- source code uc.log <-- activity log file .ucsetup <-- user-specific setup options dir.c <-- source code to directory display program dir <-- binary file executed by uc for directory displays X.fi X.SH INSTALLATION NOTES UC uses another program, dir, to provide its directory displays. This program should be placed by the user in a directory along his command search path (as identified by the PATH shell variable). Creation and installation of the setup file, .ucsetup, is not mandatory. If the user desires this, .ucsetup must be placed in his HOME directory (as identified by the HOME shell variable). X.SH SEE ALSO DIR (1) X.SH WARNING UC has been tested extensively except for the ARPA Net interface. This interface is believed to work correctly, but problems may exist which are unknown at this tim. X.SH AUTHOR Richard Conn X.sp 2 DDN Addresses: rconn@brl, rconn@simtel20 X.sp 2 UC is based on ideas from UMODEM 3.5, where UMODEM was originally written by Lauren Weinstein, and was mutated by Richard Conn, Bennett Marks, Michael Rubenstein, Ben Goldfarb, David Hinnant, and Lauren Weinstein into version 3.5. UC is a totally new design, including many features of similar function but different implementation and adding many new features and both a menu-driven and command-completion user interface. //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 uc.1l /bin/echo -n ' '; /bin/ls -ld uc.1l fi /bin/echo 'Extracting uc.c' sed 's/^X//' <<'//go.sysin dd *' >uc.c X/* * UC - a UNIX-to-CP/M file transfer shell * by Richard Conn * * UC is based on ideas from UMODEM 3.5, where UMODEM was originally written * by Lauren Weinstein, and was mutated by Richard Conn, Bennett Marks, * Michael Rubenstein, Ben Goldfarb, David Hinnant, and Lauren Weinstein * into version 3.5. UC is a totally new design, including many features * of similar function but different implementation and adding many new * features and both a menu-driven and command-completion user interface. * * UC is a rather complete rewrite of the UMODEM program, with emphasis * on implementation as a "pseudo-shell". * */ #define versmaj 1 /* Major Version */ #define versmin 1 /* Minor Version */ X/* Basics */ #define FALSE 0 #define TRUE ~FALSE X/* ASCII Characters */ #define SOH 001 #define STX 002 #define ETX 003 #define EOT 004 #define ENQ 005 #define ACK 006 #define LF 012 #define CR 015 #define NAK 025 #define SYN 026 #define CAN 030 #define CTRLZ 032 #define ESC 033 X/* UC Constants */ #define TO -1 /* Timeout Flag */ #define ERRMAX 10 /* Max errors tolerated */ #define BLOCKSZ 128 /* Size of transmission block */ #define CREATE 0644 /* Mode for New Files */ #define LOGFILE "uc.log" /* Log File */ #define CFGFILE ".ucsetup" /* Configuration File */ X/* UC Defaults */ #define defarpa FALSE /* Not Using ARPA Net */ #define defmenu FALSE /* Menu */ #define defftp 3 /* FTP */ #define deflog TRUE /* Log to Disk? */ #define defbit7 FALSE /* 7-Bit Transfer? */ X/* Library Utilities */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sgtty.h> #include <signal.h> #include <ctype.h> X/* Configuration Structure */ struct environ { char filetype; /* text or binary */ int ftp; /* File Transfer Protocol */ int logflg; /* log error summary to file */ FILE *logfd; /* file descriptor for log file */ int bit7; /* allow only 7-bit transfers */ int menu; /* menu for command mode */ int arpa; /* negotiate binary on ARPA Net */ } X/* ARPA Net Constants */ X/* The following constants are used to communicate with the ARPA * Net SERVER TELNET and TAC 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 TAC; 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 TAC */ #define DONT 0376 /* Negative of Command to TAC */ #define WILL 0373 /* Command to SERVER TELNET (Host) */ #define WONT 0374 /* Negative of Command to SERVER TELNET */ #define TRBIN 0 /* Transmit Binary Command */ main (argc, argv) int argc; char *argv[]; { int sendflg, recvflg, statflg, cmndflg; /* major functions */ int crckflg; /* major function */ struct environ genv; /* global environ */ FILE *fopen(); /* forward ref */ int index; /* index for arg parsing loop */ char opt; /* current option character */ char *getenv(); /* getenv function defn */ char logfile[50]; /* space for name of log file */ char cfgfile[50]; /* space for name of configuration file */ /* Print Banner */ printf("UC Version %d.%d - UNIX-to-CP/M File Transfer Tool\n", versmaj, versmin); /* Check for Help Request */ if (argc == 1) { help(); exit(0); } /* Determine Name of Log File */ strcat (logfile, getenv("HOME")); /* Name of Home Dir */ strcat (logfile, "/"); /* Separator */ strcat (logfile, LOGFILE); /* Name of Log File */ /* Determine Name of Configuration File */ strcat (cfgfile, getenv("HOME")); /* Name of Home Dir */ strcat (cfgfile, "/"); /* Separator */ strcat (cfgfile, CFGFILE); /* Name of Configuration File */ /* Set Defaults for ARPA Net, Menu, FTP, Logging, and 7/8-Bit Xfer */ genv.logflg = deflog; genv.bit7 = defbit7; genv.ftp = defftp; genv.menu = defmenu; genv.arpa = defarpa; getdef (cfgfile, &genv); /* Get Defs from File */ /* Init for Option Parsing */ sendflg = FALSE; recvflg = FALSE; statflg = FALSE; crckflg = FALSE; cmndflg = FALSE; /* Process Options */ index = 0; while ((opt = argv[1][index++]) != '\0') switch (opt) { case '-' : /* skip dash */ break; case '1' : genv.ftp = 1; /* select FTP 1 */ break; case '3' : genv.ftp = 3; /* select FTP 3 */ break; case '7' : genv.bit7 = TRUE; /* set 7 bits */ break; case '8' : genv.bit7 = FALSE; /* set 8 bits */ break; case 'A' : case 'a' : genv.arpa = TRUE; /* set ARPA Net */ break; case 'B' : case 'b' : genv.filetype = 'b'; /* set binary type */ break; case 'C' : crckflg = TRUE; /* set crc check mode */ genv.filetype = 'b'; /* binary */ break; case 'c' : crckflg = TRUE; /* set crc check mode */ genv.filetype = 't'; /* text */ break; case 'F' : case 'f' : statflg = TRUE; /* set file stat mode */ break; case 'L' : case 'l' : genv.logflg = ~genv.logflg; /* comp log */ break; case 'R' : recvflg = TRUE; /* set file recv mode */ genv.filetype = 'b'; break; case 'r' : recvflg = TRUE; /* set file recv mode */ genv.filetype = 't'; break; case 'S' : sendflg = TRUE; /* set file send mode */ genv.filetype = 'b'; break; case 's' : sendflg = TRUE; /* set file send mode */ genv.filetype = 't'; break; case 'T' : case 't' : genv.filetype = 't'; /* set text file type */ break; case 'Z' : case 'z' : cmndflg = TRUE; /* set command mode */ break; default : printf("Invalid Option %c\n", opt); break; } /* Open Log File if Needed */ if (sendflg || recvflg || cmndflg && genv.logflg) { genv.logfd = fopen(logfile, "w"); if (genv.logfd == NULL) { printf("Can't Open Log File\n"); exit(0); } } /* Select and Execute Major Mode */ if (cmndflg) { /* Command Mode */ command(&genv); if (genv.logflg) fclose(genv.logfd); exit(0); } if (statflg) { /* File Status Display */ if (argc < 3) { printf("File Name NOT Given\n"); exit(0); } genv.logflg = FALSE; /* no logging right now */ fstat(&genv,argv[2]); exit(0); } if (crckflg) { /* CRC Check */ if (argc < 3) { printf("File Name NOT Given\n"); exit(0); } if (genv.filetype == 't') crct(argv[2]); else crcb(argv[2]); exit(0); } if (sendflg) { /* Send File */ if (argc < 3) { printf("File Name NOT Given\n"); exit(0); } send(&genv,argv[2]); if (genv.logflg) fclose(genv.logfd); exit(0); } if (recvflg) { /* Receive File */ if (argc < 3) { printf("File Name NOT Given\n"); exit(0); } recv(&genv,argv[2]); if (genv.logflg) fclose(genv.logfd); exit(0); } printf("Major Mode NOT Selected\n"); help(); exit(0); } X/* Get Defaults from User's Configuration File, if Any */ getdef (filename, env) char *filename; struct environ *env; { FILE *fd; /* File Descriptor */ FILE *fopen(); /* fopen Function */ int c; /* Dummy Input Char */ /* Open File */ if ((fd = fopen (filename, "r")) == NULL) return; /* no file */ printf("UC Configuration File %s\n", filename); /* Read Loop */ while ((c = getc(fd)) != EOF) switch (c) { case '-' : c = getc(fd); /* get next char */ switch (c) { case 'A' : case 'a' : env->arpa = FALSE; break; case 'L' : case 'l' : env->logflg = FALSE; break; case 'M' : case 'm' : env->menu = FALSE; break; default : ungetc(fd,c); /* put back */ break; } break; case '!' : /* Comment */ do { c = getc(fd); /* Flush Comment */ } while (c != LF && c != EOF); if (c == EOF) ungetc(fd,c); break; case '1' : env->ftp = 1; break; case '3' : env->ftp = 3; break; case '7' : env->bit7 = TRUE; break; case '8' : env->bit7 = FALSE; break; case 'A' : case 'a' : env->arpa = TRUE; case 'L' : case 'l' : env->logflg = TRUE; break; case 'M' : case 'm' : env->menu = TRUE; break; default : break; } /* Close File */ fclose(fd); } X/* Print Help */ help() { printf("Usage: uc c[o] [filename]\n"); printf("\n"); printf("where 'c' MUST be One of the Following Commands --\n"); printf("\tC -- CRC Check on Binary File (filename required)\n"); printf("\tc -- CRC Check on Text File (filename required)\n"); printf("\tf or F -- File Status (filename required)\n"); printf("\tR -- Receive Binary File (filename required)\n"); printf("\tr -- Receive Text File (filename required)\n"); printf("\tS -- Send Binary File (filename required)\n"); printf("\ts -- Send Text File (filename required)\n"); printf("\tz or Z -- Enter Command Mode (filename NOT required)\n"); printf("\n"); printf("and Additional Options 'o' Include --\n"); printf("\t1 -- Select File Transfer Protocol 1\n"); printf("\t7 -- Select 7-Bit Transfer\n"); printf("\ta or A -- Enable ARPA Net Communication\n"); printf("\tb or B -- Override 'c', 's', or 'r' to Binary\n"); printf("\tl or L -- Turn Off Log Entries\n"); printf("\tt or T -- Override 'C', 'S', or 'R' to Text\n"); printf("\n"); printf("Examples:\n"); printf("\tuc S myfile -or- uc sb myfile <-- Send Binary File\n"); printf("\tuc s7l myfile <-- Send Text File with 7 Bits and No Log\n"); } X/* Command Mode */ command(env) struct environ *env; { int charx(), chelp(); int running; int tlogflg; char c, uline[200], cline[200]; printf("UC Command Mode -- Type 'h' for Help\n"); running = TRUE; while (running) { if (env->menu) chelp(); printf("UC Command? "); switch (c = charx()) { case CR : printf("\n"); break; case '1' : env->ftp = 1; printf("FTP 1\n"); break; case '3' : env->ftp = 3; printf("FTP 3\n"); break; case '7' : env->bit7 = TRUE; printf("7-Bit Transmission\n"); break; case '8' : env->bit7 = FALSE; printf("8-Bit Transmission\n"); break; case 'A' : case 'a' : env->arpa = ~env->arpa; printf("ARPA Net Communication %s\n", env->arpa ? "Enabled" : "Disabled"); break; case 'C' : printf("CRC of Binary File (file name) "); gets(uline); if (uline[0]) crcb(uline); break; case 'c' : printf("CRC of Text File (file name) "); gets(uline); if (uline[0]) crct(uline); break; case 'D' : case 'd' : printf("Directory of (dir or file spec) "); gets(uline); cline[0] = '\0'; strcat (cline, "dir "); strcat (cline, uline); system(cline); break; case 'E' : case 'e' : printf("Transmission Environment\n"); printf("\tFile Transfer Protocol %c\n", env->ftp==1 ? '1' : '3'); printf("\t%c-Bit Transfer\n", env->bit7 ? '7' : '8'); printf("\tARPA Net Communication %s\n", env->arpa ? "Enabled" : "Disabled"); break; case 'F' : case 'f' : printf("File Status of (file name) "); gets(uline); tlogflg = env->logflg; env->logflg = FALSE; if (uline[0]) fstat(env,uline); env->logflg = tlogflg; break; case '?' : case '/' : case 'H' : case 'h' : printf("\n"); chelp(); break; case 'L' : case 'l' : printf("Login (directory) "); gets(uline); if (uline[0]) chdir(uline); system("pwd"); break; case 'M' : case 'm' : env->menu = ~env->menu; /* toggle menu */ printf("Menu %s\n", env->menu ? "ON" : "OFF"); break; case 'R' : env->filetype = 'b'; env->bit7 = FALSE; printf("Receive Binary File (file name) "); gets(uline); if (uline[0]) recv(env,uline); printf("\n"); break; case 'r' : env->filetype = 't'; printf("Receive Text File (file name) "); gets(uline); if (uline[0]) recv(env,uline); printf("\n"); break; case 'S' : env->filetype = 'b'; env->bit7 = FALSE; printf("Send Binary File (file name) "); gets(uline); if (uline[0]) send(env,uline); printf("\n"); break; case 's' : env->filetype = 't'; printf("Send Text File (file name) "); gets(uline); if (uline[0]) send(env,uline); printf("\n"); break; case 'X': case 'x' : running = FALSE; printf("Exit\n"); break; case 'Z' : case 'z' : printf("UNIX Command Line "); printf("(command line) "); gets(uline); if (uline[0]) system(uline); printf("\n"); break; default : printf("Invalid Command %c -- Type H for Help\n", c); break; } } } X/* print help for command mode */ chelp() { printf("\t\t\t\tUC Command Summary\n"); printf("\n"); printf("\t------- Major Function ------- -- File Xfer Options --\n"); printf("\t c <file> CRC Value of File 1 or 3 Select FTP\n"); printf("\t r <file> Receive File 7 or 8 Select Bits\n"); printf("\t s <file> Send File a or A Toggle ARPA Net\n"); printf("\t e or E Display Environ\n"); printf("\n"); printf("\t------- UNIX Function ------- -------- Notes --------\n"); printf("\td <dir/file> Display Directory Major Fct - if caps(C),\n"); printf("\tf <file> File Size Info binary file; if not(c),\n"); printf("\tl <dir> Log Into Dir text file\n"); printf("\tm Toggle Menu\n"); printf("\tx Exit to UNIX UNIX Fct - either case\n"); printf("\tz UNIX Command\n"); printf("\n"); } X/* Send File */ send(env,filename) struct environ *env; char *filename; { FILE *fd, *fopen(); int blocknum; /* Current Block Number */ int nlflg; /* New Line for File Convert */ int sending; /* Xmit In-Progress Flag */ int tries; /* Attempt Count */ int bufctr; /* Counter for Buffer Build */ int bitmask; /* 7/8 Bit Mask */ int c; /* Temp Char */ int rcode; /* Return Code */ char buf[BLOCKSZ]; /* Buffer for Transfer */ /* Print Banner */ printf("UC Sending %s File: %s\n", (env->filetype == 't') ? "Text" : "Binary", filename); if (env->logflg) fprintf(env->logfd, "\nUC Sending File: %s\n", filename); /* Open File for Input and Print Opening Messages */ if ((fd = fopen(filename, "r")) == 0) { printf("Can`t Open File %s for Send\n", filename); if (env->logflg) fprintf(env->logfd, "Can't Open File %s for Send\n", filename); return; } fstat(env,filename); /* Print File Status Info */ printf("FTP %c, %c-Bit Transfer Selected\n", (env->ftp == 1) ? '1' : '3', env->bit7 ? '7' : '8'); if (env->logflg) fprintf(env->logfd, "FTP %c, %c-Bit Transfer Selected\n", (env->ftp == 1) ? '1' : '3', env->bit7 ? '7' : '8'); printf("Ready to Send File\n"); binary(TRUE,TRUE); /* Open Binary Communications */ if (env->arpa) setarpa(); /* Binary on ARPA Net? */ if (env->bit7) bitmask = 0x7f; else bitmask = 0xff; /* Init Parameters */ blocknum = 1; nlflg = FALSE; sending = TRUE; /* Synchronize */ tries = 0; if (env->ftp == 1) { sendbyte(SYN); while (recvbyte(5,bitmask) != ACK) { if (++tries > ERRMAX) { printf("Remote System Not Responding\n"); if (env->logflg) fprintf(env->logfd, "Remote System Not Responding\n"); return; } sendbyte(SYN); } } else { while (recvbyte(30,bitmask) != NAK) if (++tries > ERRMAX) { printf("Remote System Not Responding\n"); if (env->logflg) fprintf(env->logfd, "Remote System Not Responding\n"); return; } } /* Main Transmission Loop */ while (sending) { /* Build Next Block into buf */ for (bufctr = 0; bufctr < BLOCKSZ;) { if (nlflg) { /* New Line */ buf[bufctr++] = LF; /* Store LF */ nlflg = FALSE; } if (bufctr == BLOCKSZ) break; /* Leave for Loop */ c = getc(fd); /* Get Next Byte from File */ if (c == EOF) { sending = FALSE; /* Done */ if (!bufctr) /* Avoid Extra Block */ break; if (env->filetype == 't') for (;bufctr < BLOCKSZ; bufctr++) buf[bufctr] = CTRLZ; continue; /* Exit for Loop */ } if (c == LF && env->filetype == 't') { /* NL? */ buf[bufctr++] = CR; /* Insert CR */ nlflg = TRUE; /* New Line */ } else buf[bufctr++] = c; /* Store Char */ } /* Send Block */ tries = 0; /* Set Try Count */ if (bufctr) do { putblock(env,buf,blocknum); /* Send Block */ rcode = recvbyte(10,bitmask); /* Get Response */ if (env->ftp == 1 && rcode == ESC) rcode = recvbyte(10,bitmask); if (rcode != ACK && env->logflg) fprintf(env->logfd, "%s Received on Block %d\n", (rcode == TO) ? "Timeout" : "Non-ACK", blocknum); } while (rcode != ACK && ++tries < ERRMAX); blocknum = (blocknum + 1) & bitmask; if (tries == ERRMAX) { /* Error Abort */ sending = FALSE; if (env->logflg) fprintf(env->logfd, "Error Abort\n"); } } /* Cleanup After Send */ fclose(fd); /* Close File */ tries = 0; if (env->ftp == 1) while (++tries < ERRMAX) sendbyte(EOT); else { sendbyte(EOT); while (recvbyte(15,bitmask) != ACK && ++tries < ERRMAX) sendbyte(EOT); if (tries == ERRMAX && env->logflg) fprintf(env->logfd, "Remote System Not Completing\n"); } if (env->logflg) fprintf(env->logfd, "Send Complete\n"); if (env->arpa) resetarpa(); /* Binary on ARPA Net? */ binary(FALSE,TRUE); /* Leave Binary Mode */ sleep(3); printf("\n"); } X/* Send Buffer to Receiver */ putblock(env,buf,blocknum) struct environ *env; char *buf; int blocknum; { int i, checksum, bitmask; if (env->bit7) bitmask = 0x7f; else bitmask = 0xff; sendbyte(SOH); /* Send Start of Header */ if (env->ftp == 1) sendbyte(0); /* FTP 1 Data Packet */ if (env->arpa && blocknum&bitmask == IAC) sendbyte(IAC); sendbyte(blocknum&bitmask); /* Send Block Number */ if (env->arpa && (-blocknum-1)&bitmask == IAC) sendbyte(IAC); sendbyte((-blocknum-1)&bitmask); /* Send Block Complement */ if (env->ftp == 1) sendbyte(STX); /* FTP 1 Start of Text */ checksum = 0; for (i = 0; i < BLOCKSZ; i++) { if (env->arpa && *buf&bitmask == IAC) sendbyte(IAC); sendbyte(*buf&bitmask); /* Send Byte */ checksum = (checksum + *buf++) & bitmask; } if (env->ftp == 1) sendbyte(ETX); /* FTP 1 End of Text */ if (env->arpa && checksum&bitmask == IAC) sendbyte(IAC); sendbyte(checksum&bitmask); /* Checksum */ if (env->ftp == 1) sendbyte(ENQ); /* FTP 1 Enquiry */ } X/* Receive File */ recv(env,filename) struct environ *env; char *filename; { int fd; /* file descriptor */ int blocknum; /* next block to receive */ int rbcnt; /* total number of received blocks */ int errorcnt; /* number of errors on current block */ int receiving; /* continuation flag */ int char1; /* first char received in block */ int delay; /* inter-char delay for FTP */ int rcode; /* received block code */ int bitmask; /* 7/8 bit mask */ /* Set Mask for 7/8 Bits */ if (env->bit7) bitmask = 0x7f; else bitmask = 0xff; if (!access(filename,2)) { printf("File %s Exists -- Delete it? ", filename); if (!getyn()) { printf("Aborting\n"); if (env->logflg) fprintf(env->logfd, "Overwrite of %s Disallowed\n", filename); return; } } unlink(filename); /* delete old file, if any */ if ((fd = creat(filename, CREATE)) == -1) { /* can't create */ printf("Can't Create %s\n", filename); if (env->logflg) fprintf(env->logfd, "Can't Create %s\n", filename); return; } /* We Have a GO */ printf("UC Receiving %s File: %s\n", (env->filetype == 't') ? "Text" : "Binary", filename); if (env->logflg) fprintf(env->logfd, "\nUC Receiving File: %s\n", filename); printf("FTP %c, %c-Bit Transmission Selected\n", (env->ftp == 1) ? '1' : '3', env->bit7 ? '7' : '8'); if (env->logflg) fprintf(env->logfd, "FTP %c, %c-Bit Transmission Selected\n", (env->ftp == 1) ? '1' : '3', env->bit7 ? '7' : '8'); printf("Ready to Receive\n"); /* Init Counters et al */ blocknum = 1; rbcnt = 0; errorcnt = 0; receiving = TRUE; /* Establish Binary Communications */ binary(TRUE,TRUE); if (env->arpa) setarpa(); /* Synchronize with Sender */ if (env->ftp == 1) { while (recvbyte(4,bitmask) != SYN); sendbyte(ACK); } else sendbyte(NAK); /* Receive Next Packet */ while (receiving) { do { char1 = recvbyte(6,bitmask); } while ((char1 != SOH) && (char1 != EOT) && (char1 != TO)); switch (char1) { case TO : /* Timeout */ if (env->logflg) fprintf(env->logfd, "Timeout on Block %d\n", blocknum); if (++errorcnt == ERRMAX) { close(fd); /* Close File */ sleep(3); /* Delay for Sender */ if (env->arpa) resetarpa(); /* ARPA Net */ binary(FALSE,TRUE); /* Normal I/O */ if (env->logflg) fprintf(env->logfd, "Error Abort\n"); receiving = FALSE; } sendbyte(NAK); break; case EOT : /* End of Transmission */ if (env->ftp == 3) sendbyte(ACK); while (recvbyte(3,bitmask) != TO); close(fd); /* Close File */ sleep(3); /* Delay for Sender */ if (env->arpa) resetarpa(); /* ARPA Net */ binary(FALSE,TRUE); /* Normal I/O */ if (env->logflg) { fprintf(env->logfd, "Receive Complete -- "); fprintf(env->logfd, "%dK, %d Blocks Received\n", (rbcnt%8) ? (rbcnt/8)+1 : rbcnt/8, rbcnt); } printf("\n"); receiving = FALSE; break; case SOH : /* New or Old Block */ rcode = getblock(env,fd,blocknum); /* read block */ switch (rcode) { case 0 : /* OK */ errorcnt = 0; blocknum = ++blocknum & bitmask; rbcnt++; if (env->ftp == 1) sendbyte(ESC); sendbyte(ACK); break; case 1 : /* Xmit Error, Non-Fatal */ if (++errorcnt < ERRMAX) { sendbyte(NAK); break; } default : /* Xmit Error, Fatal */ if (env->logflg) fprintf(env->logfd, "Error Abort\n"); close(fd); if (env->ftp == 1) sendbyte(ESC); sendbyte(CAN); if (env->arpa) resetarpa(); /* ARPA Net */ binary(FALSE,TRUE); while (recvbyte(3,bitmask) != TO); receiving = FALSE; break; } break; } } } X/* Get Block from Sender */ getblock(env,fd,blocknum) struct environ *env; int fd, blocknum; { int curblock, cmpblock, delay, bitmask; int recdone, checksum, inchecksum, byte, bufcnt, c; int startstx, endetx, endenq; int errflg, errchr; char buff[BLOCKSZ]; if (env->ftp == 1) { delay = 5; /* FTP 1 Delay Constant */ recvbyte(5,bitmask); /* Flush Leading Zero */ } else delay = 3; /* FTP 3 Delay Constant */ if (env->bit7) bitmask = 0x7f; else bitmask = 0xff; curblock = recvbyte(delay,bitmask); if (curblock == TO) { if (env->logflg) fprintf(env->logfd, "Timeout on Block Number\n"); return(1); } cmpblock = recvbyte(delay,bitmask); if (curblock == TO) { if (env->logflg) fprintf(env->logfd, "Timeout on Block Complement\n"); return(1); } if (env->ftp == 1) { startstx = recvbyte(delay,bitmask); if (startstx == TO) { if (env->logflg) fprintf(env->logfd, "Timeout on STX\n"); return(1); } } if ((curblock + cmpblock) != bitmask) { if (env->logflg) fprintf(env->logfd, "Block Number Error on Block %d\n", blocknum); while (recvbyte(delay,bitmask) != TO); /* Flush */ return(1); } checksum = 0; /* Init Checksum */ byte = 0; /* Init Buff Ptr */ recdone = FALSE; /* File Receive NOT Done */ for (bufcnt=0; bufcnt<BLOCKSZ; bufcnt++) { c = recvbyte(delay,bitmask); if (c == TO) { if (env->logflg) fprintf(env->logfd, "Timeout on Block Recv\n"); return(1); } buff[byte] = c; checksum = (checksum + c) & bitmask; if (env->filetype != 't') { byte++; /* binary xfer, so advance */ continue; } if (c == CR) continue; /* skip CR */ if (c == CTRLZ) { /* done */ recdone = TRUE; continue; } if (!recdone) byte++; /* continue */ } if (env->ftp == 1) { endetx = recvbyte(delay,bitmask); if (endetx == TO) { if (env->logflg) fprintf(env->logfd, "Timeout on ETX\n"); return(1); } } inchecksum = recvbyte(delay,bitmask); if (inchecksum == TO) { if (env->logflg) fprintf(env->logfd, "Timeout on Checksum\n"); return(1); } if (env->ftp == 1) { endenq = recvbyte(delay,bitmask); if (endenq == TO) { if (env->logflg) fprintf(env->logfd, "Timeout on ENQ\n"); return(1); } } errflg = FALSE; if (env->ftp == 1) { if (startstx != STX) { errflg = TRUE; errchr = STX; } if (endetx != ETX) { errflg = TRUE; errchr = ETX; } if (endenq != ENQ) { errflg = TRUE; errchr = ENQ; } if (errflg && env->logflg) { fprintf(env->logfd, "Invalid Packet Control -- "); switch (errchr) { case STX : fprintf(env->logfd,"STX"); break; case ETX : fprintf(env->logfd,"ETX"); break; case ENQ : fprintf(env->logfd,"ENQ"); break; } fprintf(env->logfd,"\n"); } } if (checksum != inchecksum) { if (env->logflg) fprintf(env->logfd, "Checksum Error: Received %d vs Computed %d\n", inchecksum, checksum); errflg = TRUE; } if (errflg) return(1); if (curblock != blocknum) { if (curblock == (blocknum+1)&bitmask) { if (env->logflg) fprintf(env->logfd, "Phase Error\n"); return(2); } if (env->logflg) fprintf(env->logfd, "Duplicate Block %d\n", blocknum); return(0); } if (write(fd,buff,byte) < 0) { if (env->logflg) fprintf(env->logfd, "File Write Error\n"); return(2); } return(0); } X/* Compute the CRC for a UNIX Text File */ crct(filename) char *filename; { unsigned crcupd(); FILE *fd, *fopen(); unsigned crc; int c; int bytecnt; /* open file for input */ if ((fd=fopen(filename, "r")) == NULL) { printf("File %s Not Found\n", filename); return; } /* init byte counter (for last block) */ bytecnt = 0; /* init CRC Value */ crc = 0; /* compute CRC on all bytes of file with file format conversion */ while ((c = getc(fd)) != EOF) { bytecnt++; if (!(bytecnt%BLOCKSZ)) bytecnt=0; if (c == LF) { crc = crcupd(CR, crc); /* Insert CR */ bytecnt++; if (!(bytecnt%BLOCKSZ)) bytecnt=0; } crc = crcupd(c, crc); /* Update CRC */ } /* fill last block with CTRLZ's */ for (;bytecnt < BLOCKSZ; bytecnt++) crc = crcupd(CTRLZ, crc); /* close file */ fclose(fd); /* print result */ printf("CRC of Text File %s is %4X\n", filename, crc); } X/* Compute a CRC Value for a Binary File */ crcb(filename) char *filename; { unsigned crcupd(); FILE *fd, *fopen(); unsigned crc; int c; /* open file for input */ if ((fd=fopen(filename, "r")) == NULL) { printf("File %s Not Found\n", filename); return; } /* init CRC Value */ crc = 0; /* compute CRC on all bytes of file */ while ((c = getc(fd)) != EOF) crc = crcupd(c, crc); /* close file */ fclose(fd); /* print result */ printf("CRC of Binary File %s is %4X\n", filename, crc); } X/* compute CRC on a byte-for-byte basis */ unsigned crcupd(byteval, crc) int byteval; unsigned crc; { unsigned newcrc, high, low; newcrc = crc << 1; /* shift CRC left one bit */ high = newcrc & 0xff00; /* get new high byte */ low = (newcrc + byteval) & 0xff; /* get new low byte */ newcrc = high | low; /* OR the two bytes together */ if (crc & 0x8000) crc = newcrc ^ 0xa097; /* apply offset */ else crc = newcrc; return(crc); } X/* File Status Display */ fstat(env,filename) struct environ *env; char *filename; { struct stat fsi; /* file status info */ if (stat (filename, &fsi) == -1) { /* get file status info */ printf("File %s Not Found\n", filename); return; } printf("File Size of %s is %ldK, %ld Blocks\n", filename, fsi.st_size%1024 ? (fsi.st_size/1024)+1 : fsi.st_size/1024, fsi.st_size%128 ? (fsi.st_size/128)+1 : fsi.st_size/128); if (env->logflg) fprintf(env->logfd, "File Size of %s is %ldK, %ld Blocks\n", filename, fsi.st_size%1024 ? (fsi.st_size/1024)+1 : fsi.st_size/1024, fsi.st_size%128 ? (fsi.st_size/128)+1 : fsi.st_size/128); } X/* SUPPORT ROUTINES */ X/* get yes or no response from user */ getyn() { int c; c = charx(); /* get char */ if (c == 'y' || c == 'Y') { printf("Yes\n"); return(TRUE); } else { printf("No\n"); return(FALSE); } } X/* get single char input */ charx() { int binary(); int c; binary(TRUE,FALSE); c = getchar(); binary(FALSE,FALSE); return (c); } X/* 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 TAC */ sendbyte(TRBIN); /* Command is: Transmit Binary */ sleep(3); /* wait for TAC to configure */ return; } X/* 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 TAC */ sendbyte(TRBIN); /* Command is: Don't Transmit Binary */ return; } X/* send byte to receiver */ sendbyte(data) char data; { write (1, &data, 1); /* write the byte */ } X/* receive a byte from sender */ recvbyte(seconds,bitmask) unsigned seconds; int bitmask; { char c; int alarmfunc(); /* forward declaration */ signal(SIGALRM,alarmfunc); /* catch alarms */ alarm(seconds); /* set clock */ if (read (0, &c, 1) < 0) /* get char or timeout */ return (TO); alarm(0); /* clear clock */ return (c&bitmask); } X/* dummy alarm function */ alarmfunc() { return; } X/* set and clear binary mode */ binary(setflg,scope) int setflg, scope; { static struct sgttyb ttys, ttysold; static struct stat statbuf; if (setflg) { /* set binary */ if (gtty (0, &ttys) < 0) return(FALSE); /* failed */ ttysold.sg_ispeed = ttys.sg_ispeed; /* save old values */ ttysold.sg_ospeed = ttys.sg_ospeed; ttysold.sg_erase = ttys.sg_erase; ttysold.sg_kill = ttys.sg_kill; ttysold.sg_flags = ttys.sg_flags; ttys.sg_flags |= RAW; /* set for RAW Mode */ ttys.sg_flags &= ~ECHO; /* set no ECHO */ if (scope) { /* cover all values? */ ttys.sg_flags &= ~XTABS; /* set no tab exp */ ttys.sg_flags &= ~LCASE; /* set no case xlate */ ttys.sg_flags |= ANYP; /* set any parity */ ttys.sg_flags &= ~NL3; /* no delays on nl */ ttys.sg_flags &= ~TAB0; /* no tab delays */ ttys.sg_flags &= ~TAB1; ttys.sg_flags &= ~CR3; /* no CR delay */ ttys.sg_flags &= ~FF1; /* no FF delay */ ttys.sg_flags &= ~BS1; /* no BS delay */ } if (stty (0, &ttys) < 0) return(FALSE); /* failed */ if (scope) system("mesg n"); /* turn off messages */ return(TRUE); } else { /* clear binary */ if (stty (0, &ttysold) < 0) return (FALSE); if (scope) system("mesg y"); /* turn on messages */ return(TRUE); /* OK */ } } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 uc.c /bin/echo -n ' '; /bin/ls -ld uc.c fi