home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
perkinelmeridris.tar.gz
/
perkinelmeridris.tar
/
pe7mai.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-12-08
|
21KB
|
723 lines
/* pe7mai.c */
/*
* K e r m i t File Transfer Utility
*
* UNIX Kermit, Columbia University, 1981, 1982, 1983
* Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
*
* Also: Jim Guyton, Rand Corporation
* Walter Underwood, Ford Aerospace
*
* usage kermit -s [-f -d -i -u -t -p -l -b] file ... to send files
* kermit -r [-d -i -u -t -p -l -b] to receive files
* kermit -g [-f -d -i -u -t -p -l -b] file ... to get files
* kermit -f [-d -t -p -l] to send finish command
* kermit -x [-d -v -i -u -t -p -l] to set server mode
* where s=send <flag>, r=receive <flag>, x=server <flag>,
* f=finish mode <flag>, g=get files mode <flag>,
* d=debug level <number>, v=verbose mode <flag>,
* i= image mode <flag>, u=no file name conversion <flag>
* l=tty line <device>, b=baud rate <speed>,
* t=turnaround mode <flag>, p=parity type <char>
*/
/*
* Modification History:
*
* Version 1.1(0)
* December 4, 1986 - Add btobemp to decode other prefixxed packets.
* - Split program into parts to allow compiling on
* machine with minimum memory configuration.
* put in version number (use -v flag)
* Chris Lent (ihnp4!philabs!phri!cooper!chris)
* March 85 - Change to use the IDRIS operating system
* Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
* - Changed MYEOL character from \n to \r.
* - Change char to int in bufill so getc would return -1 on
* EOF instead of 255 (-1 truncated to 8 bits)
* - Added read() in rpack to eat the EOL character
* - Added fflush() call in printmsg to force the output
* NOTE: The last three changes are not conditionally compiled
* since they should work equally well on any system.
*
* Changed Berkeley 4.x conditional compilation flag from
* UNIX4X to UCB4X.
* Added support for error packets and cleaned up the printing
* routines.
*/
#define KVERSION "Perkin-Elmer 7000 Series 1.1(0) 5 Dec 86"
#define UTEXT 0 /* Set for 8 bit text strings */
#include <std.h> /* Standard UNIX definitions */
#include <sys.h> /* Idris system subroutines */
/*#include "sgtty.h" /* Special tty defs */
#include "pe7tty.h" /* Special tty defs */
/* Symbol Definitions */
#define BUFSIZE 80 /* A buffer size for I/O */
#define MAXTRY 8 /* Times to retry a packet */
#define SOH 1 /* Start of header */
#define CR 13 /* ASCII Carriage Return */
#define XON 17 /* ASCII xon character */
#define SP 32 /* ASCII space */
#define DEL 127 /* Delete (rubout) */
#define MAXPACKSIZ 94 /* Maximum packet size */
#define DEFPACKSIZ 80 /* The default packet size */
#define MAXFNAME 50 /* My maximum for filename length */
#define SPOVER 14 /* The closest I may come to the end of the output
buffer */
#define MYTIME 10 /* Seconds after which I should be timed out */
#define MYPAD 0 /* Number of padding characters I will need */
#define MYPCHAR 0 /* Padding character I need (NULL) */
#define MYEOL '\r' /* End-Of-Line character I need */
#define MYQUOTE '#' /* Quote character I will use */
#define DEFQBIN 'Y' /* I will do binary quoting */
#define MYQBIN '&' /* Binary quoting character */
#define DEFCHKT '1' /* Default Check sum type */
#define MYCHKT '1' /* Check sum type */
#define DEFREPT '~' /* Repeat character I will use */
#define MYREPT '~' /* Repeat character that I need */
#define TRUE -1 /* Boolean constants */
#define FALSE 0
/* Macro Definitions */
/*
* tochar: convert a control character to a printable one by adding a space.
*
* unchar: undoes tochar.
*
* ctl: converts between control characters and printable characters by
* toggling the control bit (ie. ^A becomes A and A becomes ^A).
*/
#define tochar(ch) ((ch) + ' ')
#define unchar(ch) ((ch) - ' ')
#define ctl(ch) ((ch) ^ 64)
/* Global Variables */
/* This is the format for the return packet from the other user */
int
spsiz {MAXPACKSIZ}, /* Maximum send packet size */
timint {MYTIME}, /* Timeout for foreign host on sends */
pad {0}; /* How much padding to send */
TEXT
padchar {0}, /* Padding character to send */
eol {MYEOL}, /* End-Of-Line character to send */
quote {MYQUOTE}, /* Quote character in incoming data */
qbin {0}, /* binary conversion character */
chkt {MYCHKT}, /* Checksum type '1','2', or '3' */
rept {0}; /* Repeat character if repeat supported */
int
size[2] {0}, /* Size of present data in packets */
empty[2] {0}, /* Packets ok to fill if zero */
pknum {0}, /* Current packet buffer index */
n {0}, /* Packet number */
nxo {0}, /* Output packet counter for display */
nxi {0}, /* Nak packet counter for display */
nxs {0}, /* Saved nak counter */
repeat_count {0}, /* Repeat counter for repeated characters */
numtry {0}, /* Times this packet retried */
oldtry {0}, /* Times previous packet retried */
iflg {0}, /* Indicates to turn on the image mode */
image {0}, /* -1 means 8-bit mode (driven by iflg) */
speed {0}, /* baud rate of the link */
fflg {0}, /* Indicates to send finish command */
rflg {0}, /* Indicates receive mode */
sflg {0}, /* Indicates send mode */
xflg {0}, /* Indicates server mode */
gflg {0}, /* Indicates get file mode */
vflg {0}, /* Verbose messages in server mode */
tflg {0}, /* Turn around flag */
pflg {0}, /* What kind of parity are we using? */
spflg {0}, /* This is our start-up parity flag */
debug {0}, /* indicates level of debugging output (0=none) */
filnamcnv {0}, /* -1 means do file name case conversions */
filecount {0}; /* Number of files left to send */
TEXT
state {0}, /* Present state of the automaton */
rqbin {0}, /* 8 bit quote character saved in rpar */
sqbin {0}, /* 8 bit quote character used in spar */
rrept {0}, /* Repeat character used in spar */
**filelist {0}, /* List of files to be sent */
*filnam {0}, /* Current file name */
*files[10] {0}, /* Pointers for the server file names */
filename_buffer[MAXPACKSIZ] {0}; /* Buffer for the server file name */
TEXT
recpkt[MAXPACKSIZ] {0}, /* Receive packet buffer */
*packet[2] {0}, /* Packet pointers */
packet0[MAXPACKSIZ] {0}, /* Send packet zero buffer */
packet1[MAXPACKSIZ] {0}; /* Send packet one buffer */
FILE ttyfd {0}; /* File descriptor of tty for I/O, 0 if remote */
FIO *fd {0}; /* pfio pointer */
FIO pfio {0}; /* Buffer structure for the files */
struct tty
ttymode {0}, /* tty raw mode */
savemode {0}; /* tty cooked mode */
struct {
int files; /* Number of files */
int fc; /* Number of characters in files */
int pli; /* Number of packets received */
int plo; /* Number of packets sent */
int cli; /* Number of characters received */
int clo; /* Number of characters sent */
ULONG time; /* Total time for transaction */
} total {0}, file {0};
/*
* m a i n
*
* Main routine - parse command and options, set up the
* tty lines, and dispatch to the appropriate routine.
*
*/
main(argc,argv)
int argc; /* Character pointers to and count of */
char **argv; /* command line arguments */
{
TEXT *ttyname, /* tty name for LINE argument */
*cp; /* char pointer */
printf("IDRIS Kermit - %s",KVERSION);
if (argc < 2) /* Make sure there's a command line */
Usage("Invalid command line - Not enough arguments.");
packet[0] = &packet0; /* Set up the packet pointers */
packet[1] = &packet1;
/* Turn off the parse flags */
sflg = FALSE;
rflg = FALSE;
xflg = FALSE;
gflg = FALSE;
fflg = FALSE;
image = iflg = FALSE;
filnamcnv = TRUE; /* conversion for UNIX systems */
vflg = FALSE; /* Turn off verbose flags */
debug = FALSE; /* Turn off the debug mode */
ttyname = 0; /* We did not get a line assignment (pointer) */
speed = FALSE; /* Speed not indicated */
spflg = pflg = FALSE; /* Parity is not indicated */
tflg = FALSE; /* No turn around character */
sqbin = DEFQBIN; /* Set up default qbin character */
rqbin = sqbin;
qbin = FALSE;
/* Reset the display counters */
nxo = 0;
nxi = 0;
nxs = -1;
getflags(&argc,&argv,\
"s,r,x,g,f,i,u,v,d#,l*,b#,p?,t:F <file>",\
&sflg, &rflg, &xflg, &gflg, &fflg, &iflg, &filnamcnv, &vflg,\
&debug, &ttyname, &speed, &pflg, &tflg);
if (!ttyname) /* If LINE was not specified, use default */
ttyname = "/dev/lnk0";
ttyfd = open(ttyname, UPDATE, 0);/* Open the tty line */
if (ttyfd <= 0)
Usage("Cannot open %s.",ttyname);
/* Put the proper tty into the correct mode */
egtty(ttyfd,&savemode); /* save for later use */
egtty(ttyfd,&ttymode); /* set for changing the setup */
printf("IDRIS Kermit - %s",KVERSION);
vflg = vflg ? vflg : fflg || gflg || rflg || sflg || debug ?
TRUE : FALSE;
if ((gflg + xflg + rflg + sflg) != 1) /* Only one command allowed */
if (!fflg)
Usage("Only one command allowed - g ! r ! s ! x.");
if (fflg && (xflg || rflg))
Usage("Finish with server or receive?");
if (!pflg) /* Do we set up the parity? */
{
/* Check for raw mode and if true then force no parity */
if (ttymode.t_mode & M_RAW) pflg = FALSE;
else
{
/* What has the caller set into the hardware */
switch (ttymode.t_mode & (M_EVEN | M_ODD))
{
case M_ODD:
pflg = 'o';
break;
case M_EVEN:
pflg = 'e';
break;
case M_EVEN | M_ODD:
pflg = 'm';
break;
case 0:
pflg = 's';
}
}
}
else
{
if (scnbuf("neoms",5,pflg) == 5)
Usage("Improper parity call out.");
if (pflg == 'n') pflg = FALSE; /* If no parity then set it */
}
spflg = pflg; /* Set up start-up parity */
/* Put the hardware into raw mode */
ttymode.t_mode = (M_RAW | M_ALL | MR_XON);
if (speed) /* Do we set up the speed? */
{
switch (speed)
{
case 110:
speed = B110;
ttymode.t_mode |= M_2STOP;
break;
case 150:
speed = B150;
break;
case 300:
speed = B300;
break;
case 1200:
speed = B1200;
break;
case 2400:
speed = B2400;
break;
case 4800:
speed = B4800;
break;
case 9600:
speed = B9600;
break;
default:
Usage("Bad line speed.");
}
ttymode.t_ispeed = speed;
ttymode.t_ospeed = speed;
}
/* Set up the time-out and buffer size */
ttymode.t_min = 128;
ttymode.t_time = MYTIME * 10;
if (tflg) /* Turn around flag on? */
ttymode.t_cgo = NULL; /* Turn off XON in XON/XOFF */
estty(ttyfd,&ttymode); /* Put asg'd tty in requested mode */
/* All set up, now execute the command that was given. */
if (filnamcnv > 0) /* Do we want to do file name conversions? */
filnamcnv = FALSE;
if (iflg) /* Turn on the image mode? */
{
image = TRUE;
/* Test the parity and make a determination of the qbin
mode info */
if (pflg) /* Pflg contains the parity bit if set */
sqbin = MYQBIN; /* Set 8-bit quoting */
else
sqbin = DEFQBIN; /* We can do 8 bit transfers */
}
if (debug)
{
printf("Main 1: S=%d, R=%d, X=%d, G=%d,", sflg, rflg, xflg, gflg);
printf(" F=%d, I=%d, U=%d, V=%d,", fflg, iflg, filnamcnv, vflg);
printf(" D=%d\n", debug);
printf(" L=%s, B=%d, P=%c,", ttyname, speed, pflg);
printf(" T=%d\n", tflg);
printf("Main 2: Bits for ttyfd %x\n",ttymode.t_mode);
}
if (gflg || sflg)
{
/* Anything to get or send? */
if (argc--)
filnam = *argv++; /* Get file to send */
else
{
savemode.t_time = 0;
estty(ttyfd,&savemode); /* restore the old mode */
Usage("File name required.");
/* and give error */
}
fd = NULL; /* Indicate no file open yet */
filelist = argv; /* Set up the rest of the file list */
filecount = argc; /* Number of files left to get or send */
}
dostat(1);
if (gflg) /* Get command */
{
if (debug) printf("Main 3: Get command\n");
if (getsw() == FALSE)
Usage("Get failed.");
else
printmsg("Get done.");
}
if (sflg) /* Send command */
{
if (debug) printf("Main 4: Send command\n");
if (sendsw() == FALSE) /* Send the file(s) */
Usage("Send failed."); /* Report failure */
else /* or */
printmsg("Send done."); /* success */
}
/* end of sflg */
if (rflg) /* Receive command */
{
if (debug) printf("Main 5: Receive command\n");
if (debug < 3)
{
if (recsw() == FALSE) /* Receive the file(s) */
Usage("Receive failed.");
else /* Report failure */
printmsg("Receive done."); /* or success */
}
/* End of test for no receive of data (debug < 3) */
}
/* End of (rflg) test */
if (xflg)
while (server() == TRUE);
if (fflg)
{
if (debug) printf("Main 6: Finish command\n");
if (finishsw() == FALSE)
Usage("Finish failed.");
else
printmsg("Finish done.");
}
if (vflg)
if(total.files > 1)
{
printf("%d Files\n", total.files);
printf("%d Bytes %d Seconds %d/%d Packets",
total.fc, total.time, total.plo, total.pli);
printf(" %d/%d Characters\n", total.clo, total.cli);
}
/* Restore the tty (reset the timeout to infinite) */
savemode.t_time = 0;
estty(ttyfd,&savemode);
exit(YES);
}
/*
* s e n d s w
*
* Sendsw is the state table switcher for sending files. It loops until
* either it finishes, or an error is encountered. The routines called
* by sendsw are responsible for changing the state.
*
*/
sendsw()
{
TEXT sinit(), sfile(), sdata(), seof(), sbreak();
n = 0; /* Initialize message number */
numtry = 0; /* Say no tries yet */
state = 'S'; /* Send initiate is the start state */
while(TRUE) /* Do this as long as necessary */
{
if (debug) printf("Sendsw 1: State: %c\n",state);
switch(state)
{
case 'S': state = sinit(); break; /* Send-Init */
case 'T': state = sfile(); break; /* Send-File */
case 'E': state = sdata(); break; /* Send-Data */
case 'Z': state = seof(); break; /* Send-End-of-File */
case 'B': state = sbreak(); break; /* Send-Break */
case 'C': return (TRUE); /* Complete */
case 'A': /* "Abort" */
default: return (FALSE); /* Unknown, fail */
}
}
}
/*
* r e c s w
*
* This is the state table switcher for receiving files.
*
*/
recsw()
{
TEXT rinit(), rfile(), rdata(); /* Use these procedures */
n = 0; /* Initialize message number */
numtry = 0; /* Say no tries yet */
state = 'R'; /* Receive-Init is the start state */
while(TRUE)
{
if (debug) printf("Recsw 1: state: %c\n",state);
switch(state) /* Do until done */
{
case 'R': state = rinit(); break; /* Receive-Init */
case 'F': state = rfile(); break; /* Receive-File */
case 'D': state = rdata(); break; /* Receive-Data */
case 'C': return (TRUE); /* Complete state */
case 'A':
default: return (FALSE); /* "Abort" state */
}
}
}
/*
* g e t s w
*
* Get a file from the other end
*
*/
getsw()
{
TEXT ginit(), iinit(), rfile(), rdata(); /* Use these procedures */
TEXT filnam1[MAXFNAME],
*newfilnam,
*cp;
int num, len;
cpystr(filnam1, filnam, NULL); /* Copy file name */
newfilnam = cp = filnam1;
while (*cp != '\0')
if (*cp++ == '/')
newfilnam = cp;
if (filnamcnv) /* Convert lower case to upper */
for (cp = newfilnam; *cp != '\0'; cp++)
*cp = toupper(*cp);
len = cp - newfilnam;
printmsg("Requesting %s as %s",filnam, newfilnam);
n = 0; /* Initialize message number */
numtry = 0; /* Say no tries yet */
state = 'S';
while (TRUE)
{
if (debug) printf("Getsw 1: State: %c\n",state);
switch (state)
{
case 'S': state = iinit(); break; /* Try this */
/* Then this */
case 'R': state = ginit(len,newfilnam); break;
case 'F': state = rfile(); break; /* Fetch file name */
case 'D': state = rdata(); break; /* Fetch the data */
case 'C': return (TRUE); /* End it all goodly */
case 'A':
default: return (FALSE); /* End it all badly */
}
}
}
/*
* s e r v e r
*
* This is the state table switcher for the server mode
*
*/
server()
{
TEXT xinit(), rfile(), rdata(); /* Use these procedures */
TEXT sinit(), xfile(), sdata(), seof(), sbreak(); /* and these */
image=iflg;
pflg=spflg;
n = 0; /* Initialize message number */
numtry = 0; /* Say no tries yet */
state = 'X'; /* Begin is the start state */
while(TRUE)
{
if (debug) printf("Server 1: state: %c\n",state);
switch(state) /* Do until done */
{
case 'X': state = xinit(); break; /* Fetch what to do */
case 'S': state = sinit(); break; /* Send init packets */
case 'T': state = xfile(); break; /* maybe open file */
case 'E': state = sdata(); break; /* Send the data */
case 'Z': state = seof(); break;
case 'B': state = sbreak(); break;
case 'F': state = rfile(); break; /* Receive-File */
case 'D': state = rdata(); break; /* Receive-Data */
case 'C': return (TRUE); /* Complete state */
case 'G': return (FALSE); /* Finish command */
case 'A':
default: return (debug ? FALSE : TRUE);
}
}
}
/*
* f i n i s h s w
*
* finishsw is the state table switcher for sending general commands
* It loops until
* either it finishes, or an error is encountered. The routines called
* by finishsw are responsible for changing the state.
*
*/
finishsw()
{
TEXT sfinish();
n = 0; /* Initialize message number */
numtry = 0; /* Say no tries yet */
state = 'F'; /* Send finish is the start state */
while(TRUE) /* Do this as long as necessary */
{
if (debug) printf("Finishsw 1: State: %c\n",state);
switch(state)
{
case 'F': state = sfinish(); break; /* Send-Finish command */
case 'C': return (TRUE); /* Complete */
case 'A': /* "Abort" */
default: return (FALSE); /* Unknown, fail */
}
}
}
/*
* i i n i t
*
* Initiate: send this host's parameters and get other side's back.
*
*/
TEXT iinit()
{
int num, len, slen; /* Packet number, length */
if (numtry++ > 2) return ('R'); /* If too many tries, give up */
slen = spar(packet0); /* Fill up init info packet */
flushinput(); /* Flush pending input */
eol = MYEOL; /* Preset to my eol character */
spack('I',n,slen,packet0); /* Send an I packet */
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
{
case 'Y': /* ACK */
if (n != num) /* If wrong ACK, stay in S state */
{ /* Wrong packet number */
case 'N': /* NAK, Try it again */
case FALSE:
nxi++;
return (state);
}
if (!rpar(recpkt,&len)) /* Get the other side's init data */
return ('A'); /* error with the packet parameters */
nxtpkt();
n = 0; /* Reset packet number to zero */
return ('R'); /* OK, switch state to R */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Anything else, just "abort" */
}
}
/*
* s i n i t
*
* Send Initiate: send this host's parameters and get other side's back.
*/
TEXT sinit()
{
int num, len, slen; /* Packet number, length */
if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */
slen = spar(packet0); /* Fill up init info packet */
flushinput(); /* Flush pending input */
eol = MYEOL; /* Preset to my eol character */
spack('S',n,slen,packet0); /* Send an S packet */
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
{
case 'Y': /* ACK */
if (n != num) /* If wrong ACK, stay in S state */
{ /* Wrong packet number */
case 'N': /* NAK, Try it again */
case FALSE:
nxi++;
return (state);
}
if (!rpar(recpkt,&len)) /* Get the other side's init data */
return ('A'); /* error with the packet parameters */
nxtpkt();
return ('T'); /* OK, switch state to T */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Anything else, just "abort" */
}
}
/*
* r i n i t
*
* Receive Initialization
*/
TEXT rinit()
{
int len, num, slen; /* Packet length, number */
if (numtry++ > MAXTRY) return ('A'); /* If too many tries, "abort" */
switch(rpack(&len,&num,recpkt)) /* Get a packet */
{
case 'S': /* Send-Init packet */
if (!rpar(recpkt,&len)) /* Get the other side's init data */
return ('A'); /* error with the packet parameters */
slen = spar(packet0); /* Fill up packet with my init info */
spack('Y',n,slen,packet0); /* ACK with my parameters */
oldtry = numtry; /* Save old try count */
nxtpkt();
return ('F'); /* Enter File-Receive state */
case FALSE: /* Didn't get packet */
nxi++;
spack('N',n,0,0); /* Return a NAK */
return (state); /* Keep trying */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Some other packet type, "abort" */
}
}
/* pe7mai.c End-of-file */