home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
perkinelmeridris.zip
/
pe7ptb.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-12-08
|
18KB
|
807 lines
/* pe7ptb.c */
/* include external declarations */
#include "pe7inc.h"
/*
* g n x t f l
*
* Get next file in a file group
*
*/
gnxtfl()
{
if (filecount-- == 0)
return (FALSE); /* If no more, fail */
if (debug) printf("Gnxtfl 1: filelist = \"%s\"\n",*filelist);
filnam = *(filelist++);
return (TRUE);
}
/*
* d o s t a t s
*
* Gather various statistics
*
*/
dostat(type)
int type;
{
ULONG time();
switch(type)
{
case 1: /* Init Overall totals */
total.files = 0;
total.fc = 0;
total.pli = 0;
total.plo = 0;
total.cli = 0;
total.clo = 0;
total.time = 0;
break;
case 2: /* Init File totals */
file.fc = 0;
file.pli = 0;
file.plo = 0;
file.cli = 0;
file.clo = 0;
file.time = time();
break;
case 3: /* Accumulate Overall totals */
file.time = time()-file.time;
if (vflg)
{
printf("%d Bytes %d Seconds %d/%d Packets",
file.fc, file.time, file.plo, file.pli);
printf(" %d/%d Characters\n", file.clo, file.cli);
}
total.fc += file.fc;
total.pli += file.pli;
total.plo += file.plo;
total.cli += file.cli;
total.clo += file.clo;
total.time += file.time;
break;
case 4: /* Count total files */
total.files++;
}
}
/*
* d o p a r
*
* Set parity bit
*
*/
dopar(ch)
TEXT ch;
{
TEXT a;
a=ch;
if (pflg) /* True = generate parity */
{
a &= 0177; /* Strip top bit */
switch (pflg)
{
case 'o': /* Odd parity */
a |= 0200; /* Set bit then do even */
case 'e': /* Even parity */
a = (a & 15) ^ ((a >> 4) & 15);
a = (a & 3) ^ ((a >> 2) & 3);
a = (a & 1) ^ ((a >> 1) & 1);
a = ch & 0177 | (a << 7);
case 's': /* Space parity */
default: /* No parity */
break;
case 'm': /* Mark parity */
a |= 0200;
}
}
return (a);
}
/*
* c h k c h a r
*
* Check range of input and return the character or FALSE
*
*/
TEXT chkchar(c)
TEXT c;
{
return ((c < 33) || (c > 62 && c < 96) || (c > 126) ? FALSE : c);
}
/*
* f l u s h i n p u t
*
* Dump all pending input to clear stacked up NACK's.
* (Implemented only for Berkeley Unix at this time).
*
*/
flushinput() /* Null version for non-Berkeley Unix */
{
estty(ttyfd,&ttymode); /* This flushes the input buffer */
}
/*
* Kermit printing routines:
*
* printmsg - like printf with "Kermit: " prepended
* error - like printmsg if local kermit; sends a error packet if remote
* prerrpkt - print contents of error packet received from remote host
*/
/*
* U s a g e
*
* Like printmsg but will exit after printing the message
*
*/
Usage(message,a1,a2,a3,a4,a5)
TEXT *message;
{
TEXT
cp[BUFSIZE];
cpystr(&cp, "Kermit usage: ", message, "\n", NULL);
printf(&cp, a1, a2, a3, a4, a5);
if (ttyfd > 0)
estty (ttyfd,&savemode); /* Restore the tty to what it was */
exit(NO);
}
/*
* p r i n t m s g
*
* Print message on standard output if not remote.
*
*/
printmsg(fmt, a1, a2, a3, a4, a5)
TEXT *fmt;
{
TEXT cp[BUFSIZE];
cpystr(&cp, "Kermit: ", fmt, "\n", NULL);
printf(&cp, a1, a2, a3, a4, a5);
}
/*
* e r r o r
*
* Print error message.
*
* If remote, send an error packet with the message.
*
*/
error(fmt, a1, a2, a3, a4, a5)
TEXT *fmt;
{
TEXT cp[MAXPACKSIZ], msg[80]; /* Some arrays for the strings */
int len; /* The length of these arrays */
convert(&cp, fmt); /* Convert the format string */
len = decode(msg, 80, &cp, a1, a2, a3, a4, a5);
spack('E',n,len,msg); /* Send the error packet */
return;
}
/*
* c o n v e r t
*
* Convert the UNIX format string to an IDRIS format string
*
*/
convert(out, in)
TEXT *out, *in;
{
TEXT t,
*cpp;
cpp = out; /* Init the buffer pointer */
while ((t = *cpp++ = *in++) != NULL)
if (t == '%')
switch (t = *in++)
{
case 'c':
*cpp++ = 'a';
*cpp++ = 'c';
break;
case 'x':
*cpp++ = 'h';
case 'd':
*cpp++ = 'i';
break;
case 's':
*cpp++ = 'p';
break;
case '\0':
--in;
break;
default:
*cpp++ = t;
}
}
/*
* p r e r r p k t
*
* Print contents of error packet received from remote host.
*
*/
prerrpkt(msg)
TEXT *msg;
{
putstr(STDERR,\
"Kermit: Abort with error from remote host:\n",\
" ",msg,"\n",NULL);
return;
}
/*
* p r i n t f
*
* Print formatted output. Convert from UNIX to IDRIS
*
*/
printf(msg, a1, a2, a3, a4, a5)
TEXT *msg;
{
TEXT
cp[MAXPACKSIZ]; /* Line pointer for the reformatted string */
convert(&cp, msg); /* Convert the string */
putfmt(&cp, a1, a2, a3, a4, a5);
}
/*
* i n l i n e
*
* Input a line (up to break char) from communications line
*
*/
inline(data)
TEXT *data;
{
TEXT t;
int len, t1;
t1 = tflg ? XON : MYEOL;
len = 0;
do
{
if (ioread(&t) <= 0)
{
data[len]=MYEOL;
return(len);
}
else
if (t)
{
if (t == SOH) /* Resync on SOH */
len = 0;
else
data[len++] = t;
}
}
while ((t != t1) && (len < MAXPACKSIZ));
file.cli += len + 1;
data[len] = '\0'; /* Terminate input string */
if (tflg) /* Turn around flag on? */
do
if (ioread(&t) < 0) break;
while (t != XON);
return (len);
}
/*
* i o r e a d
*
* Read a character from the i/o channel
*
*/
ioread(t)
TEXT *t;
{
ULONG time_end,
time();
int result;
if (timint > 0)
{
time_end = time() + timint;
do
if ((result = read(ttyfd, t, 1)) > 0) break;
while (time_end >= time());
}
else
result = read(ttyfd, t, 1);
if (pflg)
*t &= 0177; /* Handle parity */
return (result);
}
/*
* x f i l e
*
* Fetch file and send file header
*
*/
TEXT xfile()
{
TEXT filnam1[MAXFNAME]; /* A buffer for the file name */
TEXT *newfilnam; /* A pointer into the filename */
TEXT *cp; /* char pointer */
int num, len; /* Packet number, length */
ULONG time();
if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */
if (fd == NULL) /* If not already open, */
{
/* cpystr(filnam1, filnam, NULL); /* */
btobemp(filnam1, filnam, MAXFNAME);
if (filnamcnv) /* Convert upper case to lower */
for (cp = &filnam1; *cp != '\0'; cp++)
*cp = tolower(*cp);
newfilnam = cp = filnam;
while (*cp != '\0') /* Strip leading directories */
if (*cp++ == '/')
newfilnam = cp;
len = cp - newfilnam; /* Compute length of filename */
if (debug) printf("Xfile 1: Opening %s for sending.\n",&filnam1);
/* Open file to be sent */
if ((fd = fopen(&pfio, filnam1, READ)) == NULL)
{ /* If bad file pointer, give up */
error("Cannot open file %s",filnam);
return ('C'); /* Go back to idle mode */
}
if (vflg)
printmsg("Sending %s as %s", filnam1, newfilnam);
}
dostat(2);
spack('F',n,len,newfilnam); /* Send an F packet */
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
{
case 'N': /* NAK, just stay in this state, */
num = (--num<0 ? 63 : num);/* unless it's NAK for next packet */
case 'Y':
if (n != num) /* which is just like an ACK for */
{ /* Wrong packet number */
case FALSE: /* Receive failure, stay in F state */
nxi++;
return (state);
}
nxtpkt();
dostat(4);
repeat_count = 0; /* Reset repeat character counter */
empty[1-pknum] = 0; /* Make other buffer empty */
if ((empty[pknum] = size[pknum] = bufill (packet[pknum])) != EOF)
return ('E'); /* Switch to data state */
return ('Z'); /* Must be end of file */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Something else, just "abort" */
}
}
/*
* s d a t a
*
* Send File Data
*
*/
TEXT sdata()
{
int num, len; /* Packet number, length */
if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */
/* If the packet has not been acked then do not fill it
We may need to retransmit it again */
spack('D',n,size[pknum],packet[pknum]); /* Send a D packet */
if (!empty[1-pknum])
empty[1-pknum] = size[1-pknum] = bufill(packet[1-pknum]);
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
{
case 'N': /* NAK, just stay in this state, */
num = (--num<0 ? 63 : num);/* unless it's NAK for next packet */
case 'Y':
if (n != num) /* which is just like an ACK for */
{ /* Wrong packet number */
case FALSE: /* Receive failure, stay in D */
nxi++;
return (state);
}
empty[pknum] = 0; /* Empty this buffer */
nxtpkt();
if (size[pknum] == EOF)
return ('Z'); /* Send eof packet */
return ('E'); /* Got data, stay in state E */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Anything else, "abort" */
}
}
/*
* r d a t a
*
* Receive Data
*
*/
TEXT rdata()
{
int num, len; /* Packet number, length */
ULONG time();
if (numtry++ > MAXTRY) return ('A'); /* "abort" if too many tries */
switch(rpack(&len,&num,recpkt)) /* Get packet */
{
case 'D': /* Got Data packet */
if (num != n) /* Right packet? */
{
/* No */
if (oldtry++ > MAXTRY) return ('A'); /* If too many tries, abort */
if (num == ((n==0) ? 63 : n-1)) /* Else check packet number */
{
/* Previous packet again? */
spack('Y',num,0,0); /* Yes, re-ACK it */
numtry = 0; /* Reset try counter */
return (state); /* Don't write out data! */
}
else return ('A'); /* sorry, wrong number */
}
/* Got data with right packet number */
spack('Y',n,0,0); /* Acknowledge the packet */
bufemp(recpkt,len); /* Write the data to the file */
oldtry = numtry; /* Reset the try counters */
nxtpkt();
return ('D'); /* Remain in data state */
case 'F': /* Got a File Header */
if (oldtry++ > MAXTRY)
return ('A'); /* If too many tries, "abort" */
if (num == ((n==0) ? 63 : n-1)) /* Else check packet number */
{
/* It was the previous one */
spack('Y',num,0,0);/* ACK it again */
numtry = 0; /* Reset try counter */
return (state); /* Stay in Data state */
}
else return ('A'); /* Not previous packet, "abort" */
case 'Z': /* End-Of-File */
if (num != n)
return ('A'); /* Must have right packet number */
spack('Y',n,0,0); /* OK, ACK it. */
fclose(&pfio); /* Close the file */
fd = NULL; /* Say the file is closed */
nxtpkt();
dostat(3);
return ('F'); /* Go back to Receive File 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, "abort" */
}
}
/*
* s e o f
*
* Send End-Of-File.
*
*/
TEXT seof()
{
int num, len; /* Packet number, length */
ULONG time();
if (numtry++ > MAXTRY) return ('A'); /* If too many tries, "abort" */
spack('Z',n,0,0); /* Send a 'Z' packet */
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
{
case 'N': /* NAK, just stay in this state, */
num = (--num<0 ? 63 : num);/* unless it's NAK for next packet, */
case 'Y':
if (n != num) /* which is just like an ACK for */
{ /* Wrong packet number */
case FALSE: /* Receive failure, stay in Z */
nxi++;
return (state);
}
nxtpkt();
dostat(3);
if (debug) printf("Seof 1: Closing input file %s\n",filnam);
fclose(&pfio); /* Close the file */
fd = NULL; /* Set flag indicating no file open */
if (debug) printf("Seof 2: Looking for next file...\n");
if (gnxtfl() == FALSE) /* No more files go? */
return ('B'); /* if not, break, EOT, all done */
if (debug) printf("Seof 3: New file is %s\n",filnam);
return ('T'); /* More files, switch state to T */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Something else, "abort" */
}
}
/*
* s b r e a k
*
* Send Break (EOT)
*
*/
TEXT sbreak()
{
int num, len; /* Packet number, length */
ULONG time();
if (numtry++ > MAXTRY) return ('A'); /* If too many tries "abort" */
spack('B',n,0,0); /* Send a B packet */
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
{
case 'N': /* NAK, just stay in this state, */
num = (--num<0 ? 63 : num);/* unless NAK for previous packet, */
case 'Y':
if (n != num) /* Which is just like an ACK for */
{ /* Wrong packet number */
case FALSE: /* Receive failure, stay in B */
nxi++;
return (state);
}
nxtpkt();
return ('C'); /* Switch state to Complete */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Other, "abort" */
}
}
/*
* s f i n i s h
*
* Send Finish (LOGOUT)
*
*/
TEXT sfinish()
{
int num, len; /* Packet number, length */
if (numtry++ > MAXTRY) return ('A'); /* If too many tries "abort" */
spack('G',n,1,"F"); /* Send a GF packet */
switch(rpack(&len,&num,recpkt)) /* What was the reply? */
{
case 'N': /* NAK, just stay in this state, */
num = (--num<0 ? 63 : num);/* unless NAK for previous packet, */
case 'Y':
if (n != num) /* which is just like an ACK for */
{ /* Wrong packet number */
case FALSE: /* Receive failure, stay in B */
nxi++;
return (state);
}
nxtpkt();
return ('C'); /* Switch state to Complete */
case 'E': /* Error packet received */
prerrpkt(recpkt); /* Print it out and */
default:
return ('A'); /* Other, "abort" */
}
}
/*
* KERMIT utilities.
*
*/
/*
* s p a c k
*
* Send a Packet
*
*/
spack(type,num,len,data)
TEXT type, *data;
int num, len;
{
register int i; /* Character loop counter */
register TEXT *bufp; /* Buffer pointer */
TEXT buffer[100]; /* Packet buffer */
TEXT temp[12]; /* A buffer for a status message */
int checksum;
data[len] = '\0'; /* Null-terminate data to print it */
if (debug>1) /* Display outgoing packet */
{
printf("Spack 1: type: %c\n",type);
printf(" num: %d\n",num);
printf(" len: %d\n",len);
if (len != 0)
printf(" data: \"%s\"\n",data);
}
bufp = buffer; /* Set up buffer pointer */
for (i=1; i<=pad; i++)
write(ttyfd,&padchar,1); /* Issue any padding */
*bufp++ = dopar(SOH); /* Packet marker, ASCII 1 (SOH) */
/* Send character count and set up checksum */
*bufp++ = dopar(tochar(len + chkt - '0' + 2));
*bufp++ = dopar(tochar(num)); /* Packet number */
*bufp++ = dopar(type); /* Packet type */
for (i=0; i<len; i++) /* Loop for all data characters */
*bufp++ = dopar(data[i]); /* Get a character */
*bufp = '\0'; /* Mark end for block check */
switch (chkt)
{
case '1':
*bufp++ = dopar(tochar(chk1(buffer+1)));
break;
case '2':
checksum = chk2(buffer+1);
*bufp++ = dopar(tochar((checksum & 07700) >> 6));
*bufp++ = dopar(tochar(checksum & 077));
break;
case '3':
checksum = chk3(buffer+1);
*bufp++ = dopar(tochar((checksum & 0170000) >> 12));
*bufp++ = dopar(tochar((checksum & 07700) >> 6));
*bufp++ = dopar(tochar(checksum & 077));
break;
}
if (eol)
*bufp++ = dopar(eol); /* Extra-packet line terminator */
*bufp = '\0';
i = bufp - buffer;
write(ttyfd, buffer, i); /* Send the packet */
file.plo++;
file.clo += i;
if (vflg)
{
if (nxi == nxs)
write(STDERR,&temp,decode(&temp,12,"%5i/\r",nxo++));
else
write(STDERR,&temp,decode(&temp,12,"%5i/%5i\r",
nxo++, nxs = nxi));
}
}
/*
* r p a c k
*
* Read a Packet
*
*/
rpack(len,num,data)
int *len, *num; /* Packet length, number */
TEXT *data; /* Packet data */
{
int chksum, i, j, len1, pbl;
TEXT t, /* Current input character */
type, /* Packet type */
cchksum[4], /* Our (computed) checksum */
rchksum[4], /* Checksum received from other host */
rpacket[MAXPACKSIZ]; /* Receive packet */
if(!(len1=inline(&rpacket))) return (FALSE);
i = 0;
if ((t = rpacket[i++]) == MYEOL) return (FALSE);
*len = unchar(t); /* Character count */
if ((t = rpacket[i++]) == MYEOL) return (FALSE);
*num = unchar(t); /* Packet number */
if ((type = rpacket[i++]) == MYEOL) return (FALSE);
pbl = ((type == 'S') || (type == 'I')) ? 1 : type == 'N' ?
*len - 2 : chkt - '0';
*len -= pbl + 2; /* Data length */
for (j=0; j < *len;) /* The data itself, if any */
if ((data[j++] = rpacket[i++]) == MYEOL) return (FALSE);
data[*len] = '\0'; /* Mark the end of the data */
/* Fetch the checksum */
cchksum[0] = '\0';
cchksum[1] = '\0';
cchksum[2] = '\0';
cchksum[3] = '\0';
rchksum[0] = '\0';
rchksum[1] = '\0';
rchksum[2] = '\0';
rchksum[3] = '\0';
for (j=0; j < pbl;) /* The checksum */
{
if ((rchksum[j++] = rpacket[i]) == MYEOL) return (FALSE);
rpacket[i++] = '\0';
}
if (debug > 1) /* Display incoming packet */
{
printf("Rpack 2: type: %c\n",type);
printf(" num: %d\n",*num);
printf(" len: %d\n",*len);
if (*len != 0)
printf(" data: \"%s\"\n",data);
}
switch (pbl)
{
case 1:
cchksum[0] = tochar(chk1(&rpacket));
break;
case 2:
chksum = chk2(&rpacket);
cchksum[0] = tochar((chksum & 07700) >> 6);
cchksum[1] = tochar(chksum & 077);
break;
case 3:
chksum = chk3(&rpacket);
cchksum[0] = tochar((chksum & 0170000) >> 12);
cchksum[1] = tochar((chksum & 07700) >> 6);
cchksum[2] = tochar(chksum & 077);
}
if (!cmpstr(cchksum, rchksum))
type = FALSE;
file.pli++;
flushinput();
return (type); /* All OK, return packet type */
}
/*
* n e x t p k
*
* Increment packet number to the next one. Reset retry counter.
*
*/
nxtpkt()
{
pknum = 1 & (n = (n+1)%64); /* Bump packet count */
numtry = 0; /* Start a new counter */
}
/* pe7ptb.c End-of-file */