/************************************************************* * vt100 terminal emulator - KERMIT protocol support * :ts=8 * * 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; msgpkt = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); spackbuf = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); sending = 1; if (!strcmp(file,"$")) { saybye(); return(USERABORT); } 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; msgpkt = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); spackbuf = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); ttime = TTIME_KERMIT; sending = 0; if (!strcmp(file,"$")) { saybye(); return(USERABORT); } 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> 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); }