home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff330.lzh
/
Vt100
/
Src.lzh
/
Src
/
kermit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-01
|
27KB
|
1,075 lines
static char rcsid[] = "$RCSfile: kermit.c,v $ $Revision: 1.3 $";
/*************************************************************
* vt100 terminal emulator - KERMIT protocol support
* :ts=8
*
* $Log: kermit.c,v $
* Revision 1.3 89/11/02 10:28:28 acs
* doksend()/dokreceive(): Memory for spackbuf and msgpkt not freed if
* filename == "$".
*
* Revision 1.2 89/10/25 21:19:54 acs
* 1) saybye(): allocate/free msgpkt and spackbuf if necessary.
* 2) Add RCS id and change log.
*
* v2.9 ACS - Kermit shouldn't NAK packet 0 but timeout waiting for
* send-init then NAK if necessary; terminate each packet with
* EOL only; don't sendstring("\r") but sendchar() it.
* v2.8a 880230 ACS - saybye() won't do anything if not in kermit
* mode.
* v2.7 870825 ACS - Fixed the "multiple-send" problem in
* doksend() et al; show status using the *InfoMsg*()
* routines in window.c; fixed erroneous calls to
* spack() and rpack(); better error handling.
* v2.6 870227 DBW - bug fixes for all the stuff in v2.5
* v2.5 870214 DBW - more additions (see readme file)
* v2.4 861214 DBW - lots of fixes/additions (see readme file)
* v2.3 861101 DBW - minor bug fixes
* v2.2 861012 DBW - more of the same
* v2.1 860915 DBW - new features (see README)
* 860901 ACS - Added eight bit quoting
* 860830 Steve Drew Wild card support, err recovry,bugs.
* 860823 DBW - Integrated and rewrote lots of code
* 860811 Steve Drew multi filexfer, bugs, status line ect..
* v2.0 860809 DBW - Major rewrite
* v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes
* v1.0 860712 DBW - First version released
*
*************************************************************/
#include "vt100.h"
#define MAXPACKSIZ 94 /* Maximum msgpkt size */
#define CR 13 /* ASCII Carriage Return */
#define LF 10 /* ASCII line feed */
#define SP 32 /* ASCII space */
#define DEL 127 /* Delete (rubout) */
#define MAXTRY 5 /* Times to retry a msgpkt */
#define MYQUOTE '#' /* Quote character I will use */
#define MYRPTQ '~' /* Repeat quote character */
#define MYEBQ '&' /* 8th bit prefix character */
#define MYPAD 0 /* Number of padding charss I will need */
#define MYPCHAR 0 /* Padding character I need (NULL) */
#define MYEOL '\n' /* End-Of-Line character I need */
#define IDOLONG 2 /* I do LONG packets! */
#define tochar(ch) ((ch) + ' ')
#define unchar(ch) ((ch) - ' ')
#define ctl(ch) ((ch) ^ 64 )
/* Global Variables */
int sending, /* Indicates that we're sending, not receiving */
lastpkt, /* Last successful packet # sent/received */
ulp, /* Using LONG packets */
size, /* Size of present data */
osize, /* Size of last data entry */
rpsiz, /* Maximum receive msgpkt size */
spsiz, /* Maximum send msgpkt size */
timint, /* Time interval to wait */
pad, /* How much padding to send */
n, /* Packet number */
tp, /* total packets */
numtry, /* Times this msgpkt retried */
retry, /* total retries */
oldtry, /* Times previous msgpkt retried */
sendabort, /* flag for aborting send file */
rptflg, /* are we doing repeat quoting */
ebqflg, /* are we doing 8th bit quoting */
notfirst, /* is this the first file received */
first, /* is this the first time in a file */
rpt, /* current repeat count */
next, /* what is the next character */
t; /* current character */
long totbytes; /* total bytes xfered on this file */
char state, /* Present state of the automaton */
padchar, /* Padding character to send */
eol, /* End-Of-Line character to send */
quote, /* Quote character in incoming data */
rptq, /* Quote character for repeats */
ebq, /* Quote character for 8th bit quoting */
ackpkt[MAXPACKSIZ+20], /* ACK/NAK packet buffer */
*msgpkt = NULL, /* Message Packet buffer is AllocMem()d */
*spackbuf = NULL, /* Dynamically allocated buffer for spack() */
filnam[40], /* remote file name */
snum[10],
mainmode[10];
FILE *fp; /* file for send/receive */
static void spack(), print_our_err(), print_host_err(),
dostats(), ClearBuffer();
char *
getfname(name) /* returns ptr to start of file name from spec */
char *name;
{
int l;
l = strlen(name);
while(l && name[l] != '/' && name[l] != ':') l--;
if (name[l] == '/' || name[l] == ':') l++;
return(name += l);
}
doksend(file,more)
char *file;
int more;
{
int amount, c, wild;
char *p, **list = NULL;
sending = 1;
if (!strcmp(file,"$")) { saybye(); return(USERABORT); }
msgpkt = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
spackbuf = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
p = file;
while(*p && *p != '*' && *p != '?') p++;
if (*p) {
wild = TRUE;
list = expand(file, &amount);
if (list == NULL) InfoMsg1Line("KERMIT: No wild card match");
}
else {
wild = FALSE;
amount = 1;
}
/* The "multiple send" problem is brought about by attempting to
** send multiple files in a single "batch" (via globbing, e.g. *.foo)
** to a remote kermit that is NOT in server mode. A 'Z' packet
** (meaning end-of-file) is sent after each of the files with a 'B'
** packet (meaning end-of-batch) coming after the last 'Z' packet.
** The old code reset the packet # on each iteration. We do it
** outside of the for loop. */
n = lastpkt = 0;
ulp = 0; /* Assume we won't use LONG packets */
for (c = 0; c < amount; c++) {
if (wild == TRUE) p = list[c];
else p = file;
strcpy(filnam,getfname(p));
ttime = TTIME_KERMIT;
tp = retry = numtry = 0; totbytes = 0L;
if ((fp = fopen(p,"r")) == NULL) {
InfoMsg2Line("KERMIT: Can't open send file:", p);
continue;
}
strcpy(mainmode,"SEND");
ClearBuffer();
/* This is another piece of the multiple-send fix. Sendsw() needs
** to know 1) that this is the first file so it can send a send-init
** packet and 2) if this is the last file so it can send a B packet
** to indicate end-of-batch. The last piece of the multiple-send fix
** is in sendsw() itself. */
if ( sendsw(c == 0, c >= (amount-1)) ) /* Successful send? */
ScrollInfoMsg(1);
fclose(fp);
}
free_expand(list);
FreeMem(spackbuf, (long)(MAXLONGPKS+20));
FreeMem(msgpkt, (long)(MAXLONGPKS+20));
msgpkt = spackbuf = NULL;
return(TRUE);
}
dokreceive(file,more)
char *file;
int more;
{
int retval;
ttime = TTIME_KERMIT;
sending = 0;
if (!strcmp(file,"$")) { saybye(); return(USERABORT); }
msgpkt = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
spackbuf = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
strcpy(filnam, file);
if (server) strcpy(mainmode,"GET");
else strcpy(mainmode,"RECV");
tp = lastpkt = retry = n = numtry = notfirst = 0; totbytes = 0L;
ClearBuffer();
retval = recsw();
FreeMem(spackbuf, (long)(MAXLONGPKS+20));
FreeMem(msgpkt, (long)(MAXLONGPKS+20));
msgpkt = spackbuf = NULL;
return(retval);
}
sendsw(firstfile, lastfile)
int firstfile, lastfile; /* Multiple-send fix */
{
char sinit(), sfile(), sdata(), seof(), sbreak();
sendabort = 0;
/* Multiple-send fix. If this is the first file of the batch then enter
** send-init state otherwise just enter send-file state. */
if(firstfile)
state = 'S';
else
state = 'F';
while(TRUE) {
switch(state) {
case 'S': state = sinit(); break;
case 'F': state = sfile(); break;
case 'D': state = sdata(); break;
case 'Z': state = seof(); break;
case 'B': if (lastfile || sendabort) {
/* Multiple-send fix. If this is the last file then
** send a B packet to indicate end-of-batch. */
state = sbreak();
break;
}
return(TRUE); /* Otherwise, just return. */
case 'C': if (sendabort) return(FALSE);
else return(TRUE);
case 'E': dostats('E',"ERROR"); /* so print the err and abort */
print_host_err(ackpkt);
return(FALSE);
case 'A': if (timeout == USERABORT) {
timeout = GOODREAD;
n = (n+1)%64;
sendabort = 1;
dostats('A',"ABORT");
strcpy(msgpkt, "D");
state = 'Z';
break;
}
if (timeout == TIMEOUT) dostats('A',"TMOUT");
else { /* protocol error dectected by us */
dostats('A',"ERROR");
print_our_err();
}
return(FALSE);
default: return(FALSE);
}
}
}
char sinit()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spar(msgpkt);
spack('S',n,13,msgpkt);
switch(rpack(&len,&num,ackpkt)) {
case 'N': return(state);
case 'Y': if (n != num) return(state);
rpar(ackpkt, len);
if (eol == 0) eol = '\n';
if (quote == 0) quote = MYQUOTE;
numtry = 0;
retry--;
n = (n+1)%64;
return('F');
case 'E': return('E');
case FALSE: if (timeout == USERABORT) state = 'A';
return(state);
default: return('A');
}
}
char sfile()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spack('F',n,strlen(filnam),filnam);
switch(rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
numtry = 0;
retry--;
n = (n+1)%64;
first = 1;
size = getpkt();
return('D');
case 'E':
return('E');
case FALSE: if (timeout == USERABORT) state = 'A';
return(state);
default:
return('A');
}
}
char sdata()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spack('D',n,size,msgpkt);
switch(rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
numtry = 0;
retry--;
n = (n+1)%64;
if ((size = getpkt()) == 0) return('Z');
return('D');
case 'E':
return('E');
case FALSE: if (timeout == USERABORT) state = 'A';
return(state);
default:
return('A');
}
}
char seof()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
/* if (timeout == USERABORT) {*/ /* tell host to discard file */
/* timeout = GOODREAD; */
/* spack('Z',n,1,"D"); */
/* } */
/* else */
spack('Z',n,sendabort,msgpkt);
switch(rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
numtry = 0;
dostats('Z',"DONE");
retry--;
n = (n+1)%64;
return('B');
case 'E': return('E');
case FALSE: return(state);
default: return('A');
}
}
char sbreak()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
spack('B',n,0,msgpkt);
switch (rpack(&len,&num,ackpkt)) {
case 'N':
num = (--num<0 ? 63:num);
if (n != num) return(state);
case 'Y':
if (n != num) return(state);
dostats('B', "DONE");
numtry = 0;
retry--;
n = (n+1)%64;
return('C');
case 'E': return('E');
case FALSE: return(state);
default: return ('A');
}
}
/* timeout equals USERABORT so lets end the file and quit */
/* when host receives 'Z' packet with "D" in data field he */
/* should discard the file. */
/*
sabort()
{
dostats(' ',"ABORT");
n = (n+1)%64;
retry--;
state = 'Z';
while (state == 'Z') state = seof();
while (state == 'B') state = sbreak();
return(FALSE);
}
*/
recsw()
{
char rinit(), rfile(), rdata();
int first_time = 1;
state = 'R';
while(TRUE) {
switch(state) {
case 'R': ulp = 0; /* Assume we won't use LONG packets */
state = rinit();
break;
case 'Z':
case 'F': state = rfile(first_time); first_time = 0;
break;
case 'D': state = rdata();
break;
case 'C': return(TRUE);
case 'E':
case 'A': /* easy way to cleanly abort
should really send and ACK
with "X" in data field and
wait for host to abort but
not all kermits support
this feature. */
if (timeout == USERABORT){
/* send an error packet back */
dostats('A',"ABORT");
spack('E',n,12,"User aborted");
}
else if (timeout == TIMEOUT) {
/* we timed out waiting */
/* will we need to spack here ?*/
dostats('A',"TMOUT");
}
/* must be 'E' from host or we detected a protocol
** error */
else dostats('A',"ERROR");
if (state == 'E') print_host_err(msgpkt);
else if (timeout == GOODREAD) /* tell host why */
print_our_err();
/* will this kill all files ?*/
do {
ttime = 2;
readchar();
} while (timeout == GOODREAD);
fclose(fp);
sendchar('\r');
return(FALSE);
default: return(FALSE);
}
}
}
char rinit()
{
int len, num, temp;
retry++;
if (numtry++ > MAXTRY) return('A');
if (server)
spack('R',n,strlen(filnam),filnam);
switch(rpack(&len,&num,msgpkt)) {
case 'S':
rpar(msgpkt, len);
/* Rpar() will set ulp if we can use long packets. We can't use
** that value right away cause we've gotta ACK with normal pkts. */
temp = ulp; ulp = 0;
spar(msgpkt);
spack('Y',n,13,msgpkt);
ulp = temp; /* Restore using long pkts flag */
oldtry = numtry;
numtry = 0;
retry--;
n = (n+1)%64;
return('F');
case 'E':
return('E');
case 'N': /* Other side NAKed us... */
return(state); /* ...so try again */
case FALSE:
if (timeout == USERABORT) return('A');
if (timeout == TIMEOUT) return(state); /* Resend Rec-init on a timeout */
spack('N',n,0,"");
return(state);
default:
return('A');
}
}
char rfile(first_time)
int first_time;
{
int num, len, temp;
USHORT a, a7, b8;
char *fileptr, *buf;
retry++;
if (numtry++ > MAXTRY) return('A');
switch(rpack(&len,&num,msgpkt)) {
case 'S':
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
/* Rpar() will set ulp if we can use long packets. We can't use
** that value right away cause we've gotta ACK with normal pkts. */
temp = ulp; ulp = 0;
spar(msgpkt);
spack('Y',num,13,msgpkt);
ulp = temp;
numtry = 0;
return(state);
}
else return('A');
case 'Z':
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
spack('Y',num,0,"");
ScrollInfoMsg(1);
numtry = 0;
return(state);
}
else return('A');
case 'F':
if (num != n) return('A');
if(!first_time) { /* Scroll the Z packet line up */
dostats('Z', "DONE");
ScrollInfoMsg(1);
}
buf = msgpkt;
fileptr = filnam;
while ((a = *buf++) != '\0') { /* Terminator added by rpack() */
if (rptflg) {
if (a == rptq) {
rpt = unchar(*buf++);
a = *buf++;
}
}
b8 = 0;
if (ebqflg) { /* 8th-bit prefixing? */
if (a == ebq) { /* Yes, got an 8th-bit prefix? */
b8 = 0200; /* Yes, remember this, */
a = *buf++; /* and get the prefixed character. */
}
}
if (a == quote) {
a = *buf++;
a7 = a & 0177;
if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
}
a |= b8;
if (rpt == 0) rpt = 1;
if (p_mode == 1 && a == '\r') continue;
for (; rpt > 0; rpt--) *fileptr++ = a;
*fileptr = '\0'; /* Terminate the filename */
}
if (p_convert) {
char *p;
p = &filnam[0];
while (*p) { *p = tolower(*p); p++; }
}
if (notfirst) {
totbytes = 0L;
dostats('F',"RECV");
}
else { /* is the first file so emit actual file name from host */
notfirst++;
}
if ((fp = fopen(filnam,"w")) == NULL) {
InfoMsg2Line("KERMIT: Unable to create file:", filnam);
strcpy(msgpkt,"VT100 - Kermit - cannot create file: ");
strcat(msgpkt,filnam);
spack('E',n,strlen(msgpkt),msgpkt); /* let host know */
dostats('E',"ERROR");
return ('\0'); /* abort everything */
}
spack('Y',n,0,"");
oldtry = numtry;
numtry = 0;
retry--;
n = (n+1)%64;
return('D');
/* totaly done server sending no more */
case 'B':
if (num != n) return ('A');
spack('Y',n,0,"");
dostats('B', "DONE");
ScrollInfoMsg(1);
retry--;
return('C');
case 'E':
return('E');
case FALSE:
if (timeout == USERABORT) return('A');
spack('N',n,0,"");
return(state);
default:
return ('A');
}
}
char rdata()
{
int num, len;
retry++;
if (numtry++ > MAXTRY) return('A');
switch(rpack(&len,&num,msgpkt)) {
case 'D':
if (num != n) {
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
spack('Y',num,6,msgpkt);
numtry = 0;
return(state);
}
else return('A');
}
decode();
spack('Y',n,0,"");
oldtry = numtry;
numtry = 0;
retry--;
n = (n+1)%64;
return('D');
case 'Z':
if (num != n) return('A');
spack('Y',n,0,"");
n = (n+1)%64;
dostats('Z',"DONE");
retry--;
fclose(fp);
return('Z');
case 'F':
if (oldtry++ > MAXTRY) return('A');
if (num == ((n==0) ? 63:n-1)) {
spack('Y',num,0,"");
numtry = 0;
return(state);
}
case 'E':
return('E');
case FALSE:
if (timeout == USERABORT) return('A');
spack('N',n,0,"");
return(state);
default:
return('A');
}
}
static void
spack(type,num,len,data)
char type, *data;
int num, len;
{
int i;
char chksum, t;
register char *bufp;
if(sending && (lastpkt != num)) {
tp++;
lastpkt = num;
}
dostats(type,mainmode);
bufp = spackbuf;
ClearBuffer();
for (i=1; i<=pad; i++) sendchar(padchar);
*bufp++ = SOH;
if(ulp && len > (MAXPACKSIZ-3)) /* Using long packets */
t = tochar(0);
else
t = tochar(len+3);
*bufp++ = t; chksum = t;
t = tochar(num);
*bufp++ = t; chksum += t;
*bufp++ = type; chksum += type;
if(ulp && len > (MAXPACKSIZ-3)) { /* Using long packets */
unsigned int pl = len + 1;
t = tochar(pl / 95);
*bufp++ = t; chksum += t;
t = tochar(pl % 95);
*bufp++ = t; chksum += t;
t = tochar((((chksum&0300) >> 6)+chksum)&077);
*bufp++ = t; chksum += t;
}
for (i=0; i<len; i++) {
*bufp++ = data[i]; chksum += data[i];
}
chksum = (((chksum&0300) >> 6)+chksum)&077;
*bufp++ = tochar(chksum);
if (eol)
*bufp++ = eol; /* Use sender's requested end-of-line */
else
*bufp++ = '\r';
*bufp = '\0';
sendstring(spackbuf);
}
rpack(len,num,data)
int *len, *num;
char *data;
{
int i, done;
char type, cchksum, rchksum;
char t = '\0';
do {
t = readchar();
if (timeout != GOODREAD) return(FALSE);
} while (t != SOH);
done = FALSE;
while (!done) {
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum = t;
*len = unchar(t)-3;
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum += t;
*num = unchar(t);
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum += t;
type = t;
if((*len == -3) && ulp) { /* Using long packets */
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum += t;
*len = unchar(t)*95;
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum += t;
*len += unchar(t);
(*len)--;
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
if(unchar(t) != ((((cchksum&0300) >> 6)+cchksum)&077)) return(FALSE);;
cchksum += t;
}
for (i=0; i<*len; i++) {
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
cchksum = cchksum + t;
data[i] = t;
}
data[*len] = 0;
t = readchar();
if (timeout != GOODREAD) return(FALSE);
rchksum = unchar(t);
t = readchar();
if (timeout != GOODREAD) return(FALSE);
if (t == SOH) continue;
done = TRUE;
}
if(type != 'B' && type != 'Z')
dostats(type,mainmode);
cchksum = (((cchksum&0300) >> 6)+cchksum)&077;
if (cchksum != rchksum) return(FALSE);
if(!sending && (*num != lastpkt)) {
tp++;
lastpkt = *num;
}
return((int)type);
}
getpkt() {
int i,eof;
static char leftover[10] = { '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0' };
if (first == 1) {
first = 0;
*leftover = '\0';
t = getc(fp);
if (t == EOF) {
first = 1;
return(size = 0);
}
totbytes++;
}
else if (first == -1) {
first = 1;
return(size = 0);
}
for (size = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ;
*leftover = '\0';
rpt = 0;
eof = 0;
while (!eof) {
next = getc(fp);
if (next == EOF) {
first = -1;
eof = 1;
}
else totbytes++;
osize = size;
encode(t);
t = next;
if (size == spsiz-3) return(size);
if (size > spsiz-3) {
for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++)
;
size = osize;
msgpkt[size] = '\0';
return(size);
}
}
return(size);
}
static void
encode(a)
char a;
{
int a7,b8;
if (p_mode == 1 && a == '\n') {
rpt = 0;
msgpkt[size++] = quote;
msgpkt[size++] = ctl('\r');
if (size <= spsiz-3) osize = size;
msgpkt[size++] = quote;
msgpkt[size++] = ctl('\n');
msgpkt[size] = '\0';
return;
}
if (rptflg) {
if (a == next && (first == 0)) {
if (++rpt < 94) return;
else if (rpt == 94) {
msgpkt[size++] = rptq;
msgpkt[size++] = tochar(rpt);
rpt = 0;
}
}
else if (rpt == 1) {
rpt = 0;
encode(a);
if (size <= spsiz-3) osize = size;
rpt = 0;
encode(a);
return;
}
else if (rpt > 1) {
msgpkt[size++] = rptq;
msgpkt[size++] = tochar(++rpt);
rpt = 0;
}
}
a7 = a & 0177;
b8 = a & 0200;
if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */
msgpkt[size++] = ebq;
a = a7;
}
if ((a7 < SP) || (a7==DEL)) {
msgpkt[size++] = quote;
a = ctl(a);
}
if (a7 == quote) msgpkt[size++] = quote;
if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;
if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */
msgpkt[size++] = quote; /* if doing 8th-bit prefixes */
msgpkt[size++] = a;
msgpkt[size] = '\0';
}
static void
decode()
{
USHORT a, a7, b8;
char *buf;
buf = msgpkt;
rpt = 0;
while ((a = *buf++) != '\0') { /* Terminator added by rpack() */
if (rptflg) {
if (a == rptq) {
rpt = unchar(*buf++);
a = *buf++;
}
}
b8 = 0;
if (ebqflg) { /* 8th-bit prefixing? */
if (a == ebq) { /* Yes, got an 8th-bit prefix? */
b8 = 0200; /* Yes, remember this, */
a = *buf++; /* and get the prefixed character. */
}
}
if (a == quote) {
a = *buf++;
a7 = a & 0177;
if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
}
a |= b8;
if (rpt == 0) rpt = 1;
if (p_mode == 1 && a == '\r') continue;
totbytes += rpt;
for (; rpt > 0; rpt--) putc(a, fp);
}
return;
}
static void
spar(data)
char data[];
{
data[0] = tochar(MAXPACKSIZ);
data[1] = tochar(TTIME_KERMIT);
data[2] = tochar(MYPAD);
data[3] = ctl(MYPCHAR);
data[4] = tochar(MYEOL);
data[5] = MYQUOTE;
if ((p_parity > 0) || ebqflg) { /* 8-bit quoting... */
data[6] = MYEBQ; /* If parity or flag on, send &. */
if ((ebq > 0040 && ebq < 0100) || /* If flag off, then turn it on */
(ebq > 0140 && ebq < 0177) || /* if other side has asked us to */
(ebq == 'Y'))
ebqflg = 1;
}
else /* Normally, */
data[6] = 'Y'; /* just say we're willing. */
data[7] = '1';
data[8] = MYRPTQ;
data[9] = tochar(IDOLONG); /* Tell 'em I do LONG packets */
data[10] = tochar(0); /* Don't do windows */
data[11] = tochar(p_kmaxpack / 95);
data[12] = tochar(p_kmaxpack % 95);
data[13] = '\0';
}
static void
rpar(data, len)
char data[];
int len;
{
int ospsiz;
spsiz = unchar(data[0]);
ospsiz = spsiz;
ttime = unchar(data[1]);
pad = unchar(data[2]);
padchar = ctl(data[3]);
eol = unchar(data[4]);
quote = data[5];
rptflg = 0;
ebqflg = 0;
if (len >= 6 && data[6] != 0) {
ebq = data[6];
if ((ebq > 040 && ebq < 0100) ||
(ebq > 0140 && ebq < 0177)) ebqflg = 1;
else if (((p_parity > 0) || ebqflg) && (ebq == 'Y')) {
ebqflg = 1;
ebq = '&';
}
else ebqflg = 0;
}
if (len >= 8 && data[8] != 0) {
rptq = data[8];
rptflg = ((rptq > 040 && rptq < 0100) ||
(rptq > 0140 && rptq < 0177));
}
if(len >= 9 && data[9] != 0) {
int capas;
for(capas=9; data[capas] & 1; capas++) ; /* Skip over continuations */
if((ulp = (data[9] & IDOLONG)) == IDOLONG) {
spsiz = 500; /* Default if no packet size specified */
if(len >= capas+3) {
spsiz = (unchar((data[capas+2])) * 95) + unchar(data[capas+3]);
if(spsiz > MAXLONGPKS)
spsiz = MAXLONGPKS;
else if(spsiz < 10) /* Reasonable? */
spsiz = 500;
}
}
}
}
void
saybye()
{
int len, num, gotbuf = 0;
if(msgpkt == NULL) { /* No msgpkt buffer, create one */
msgpkt = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
spackbuf = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
if(msgpkt == NULL || spackbuf == NULL) {
InfoMsg1Line("KERMIT: Insufficient free memory, BYE bypassed");
return;
}
gotbuf = 1;
}
if(numreqs != 0) /* Requester's up... */
Delay(5L); /* ...so wait for Intuition, just in case. */
spack('G',n,1,"F"); /* shut down server no more files */
rpack(&len,&num,ackpkt);
if(gotbuf) {
FreeMem(spackbuf, (long)(MAXLONGPKS+20));
FreeMem(msgpkt, (long)(MAXLONGPKS+20));
msgpkt = spackbuf = NULL;
}
}
static void
print_our_err()
{
if (retry > MAXTRY || oldtry > MAXTRY) {
InfoMsg1Line("KERMIT: Too may retries for packet");
strcpy(msgpkt,"VT100 KERMIT: Too many retries for packet");
}
else {
InfoMsg1Line("KERMIT: Protocol Error");
strcpy(msgpkt,"VT100 KERMIT: Protocol Error");
}
spack('E',n,strlen(msgpkt),msgpkt);
}
static void
print_host_err(msg)
char *msg;
{
InfoMsg2Line("KERMIT: Host Error:", msg);
}
static void
dostats(type,stat)
char type,*stat;
{
char *statusform = "%5s %-15.15s Pkt: %4d Retr: %2d Bytes: %6ld Type: %c",
status[80];
if (type == 'Y' || type == 'N' || type == 'G') return;
sprintf(status, statusform, stat, filnam, tp, retry-1,
(LONG)totbytes, type);
InfoMsgNoScroll(status);
}
static void
ClearBuffer()
{
AbortIO((struct IORequest *)Read_Request);
Wait(1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
WaitIO((struct IORequest *)Read_Request);
Read_Request->IOSer.io_Command = CMD_CLEAR;
DoIO((struct IORequest *)Read_Request);
Read_Request->IOSer.io_Command = CMD_READ;
SendIO((struct IORequest *)Read_Request);
}