page%swap@Sun.COM (Bob Page) (10/20/89)
Submitted-by: acs@pccuts.pcc.amdahl.com (Tony Sumrall) Posting-number: Volume 89, Issue 183 Archive-name: comm/vt100r29.6 # This is a shell archive. # Remove anything above and including the cut line. # Then run the rest of the file through 'sh'. # Unpacked files will be owned by you and have default permissions. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: SHell ARchive # Run the following text through 'sh' to create: # kermit.c # kermitproto.c # This is archive 6 of a 9-part kit. # This archive created: Thu Oct 19 22:30:31 1989 echo "extracting kermit.c" sed 's/^X//' << \SHAR_EOF > kermit.c X/************************************************************* X * vt100 terminal emulator - KERMIT protocol support X * :ts=8 X * X * v2.9 ACS - Kermit shouldn't NAK packet 0 but timeout waiting for X * send-init then NAK if necessary; terminate each packet with X * EOL only; don't sendstring("\r") but sendchar() it. X * v2.8a 880230 ACS - saybye() won't do anything if not in kermit X * mode. X * v2.7 870825 ACS - Fixed the "multiple-send" problem in X * doksend() et al; show status using the *InfoMsg*() X * routines in window.c; fixed erroneous calls to X * spack() and rpack(); better error handling. X * v2.6 870227 DBW - bug fixes for all the stuff in v2.5 X * v2.5 870214 DBW - more additions (see readme file) X * v2.4 861214 DBW - lots of fixes/additions (see readme file) X * v2.3 861101 DBW - minor bug fixes X * v2.2 861012 DBW - more of the same X * v2.1 860915 DBW - new features (see README) X * 860901 ACS - Added eight bit quoting X * 860830 Steve Drew Wild card support, err recovry,bugs. X * 860823 DBW - Integrated and rewrote lots of code X * 860811 Steve Drew multi filexfer, bugs, status line ect.. X * v2.0 860809 DBW - Major rewrite X * v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes X * v1.0 860712 DBW - First version released X * X *************************************************************/ X X#include "vt100.h" X X#define MAXPACKSIZ 94 /* Maximum msgpkt size */ X#define CR 13 /* ASCII Carriage Return */ X#define LF 10 /* ASCII line feed */ X#define SP 32 /* ASCII space */ X#define DEL 127 /* Delete (rubout) */ X X#define MAXTRY 5 /* Times to retry a msgpkt */ X#define MYQUOTE '#' /* Quote character I will use */ X#define MYRPTQ '~' /* Repeat quote character */ X#define MYEBQ '&' /* 8th bit prefix character */ X#define MYPAD 0 /* Number of padding charss I will need */ X#define MYPCHAR 0 /* Padding character I need (NULL) */ X#define MYEOL '\n' /* End-Of-Line character I need */ X#define IDOLONG 2 /* I do LONG packets! */ X X#define tochar(ch) ((ch) + ' ') X#define unchar(ch) ((ch) - ' ') X#define ctl(ch) ((ch) ^ 64 ) X X/* Global Variables */ X Xint sending, /* Indicates that we're sending, not receiving */ X lastpkt, /* Last successful packet # sent/received */ X ulp, /* Using LONG packets */ X size, /* Size of present data */ X osize, /* Size of last data entry */ X rpsiz, /* Maximum receive msgpkt size */ X spsiz, /* Maximum send msgpkt size */ X timint, /* Time interval to wait */ X pad, /* How much padding to send */ X n, /* Packet number */ X tp, /* total packets */ X numtry, /* Times this msgpkt retried */ X retry, /* total retries */ X oldtry, /* Times previous msgpkt retried */ X sendabort, /* flag for aborting send file */ X rptflg, /* are we doing repeat quoting */ X ebqflg, /* are we doing 8th bit quoting */ X notfirst, /* is this the first file received */ X first, /* is this the first time in a file */ X rpt, /* current repeat count */ X next, /* what is the next character */ X t; /* current character */ Xlong totbytes; /* total bytes xfered on this file */ X Xchar state, /* Present state of the automaton */ X padchar, /* Padding character to send */ X eol, /* End-Of-Line character to send */ X quote, /* Quote character in incoming data */ X rptq, /* Quote character for repeats */ X ebq, /* Quote character for 8th bit quoting */ X ackpkt[MAXPACKSIZ+20], /* ACK/NAK packet buffer */ X *msgpkt = NULL, /* Message Packet buffer is AllocMem()d */ X *spackbuf = NULL, /* Dynamically allocated buffer for spack() */ X filnam[40], /* remote file name */ X snum[10], X mainmode[10]; X XFILE *fp; /* file for send/receive */ X Xstatic void spack(), print_our_err(), print_host_err(), X dostats(), ClearBuffer(); X Xchar * Xgetfname(name) /* returns ptr to start of file name from spec */ Xchar *name; X{ X int l; X X l = strlen(name); X while(l && name[l] != '/' && name[l] != ':') l--; X if (name[l] == '/' || name[l] == ':') l++; X return(name += l); X} X Xdoksend(file,more) Xchar *file; Xint more; X{ X int amount, c, wild; X char *p, **list = NULL; X X msgpkt = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); X spackbuf = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); X sending = 1; X if (!strcmp(file,"$")) { saybye(); return(USERABORT); } X p = file; X while(*p && *p != '*' && *p != '?') p++; X if (*p) { X wild = TRUE; X list = expand(file, &amount); X if (list == NULL) InfoMsg1Line("KERMIT: No wild card match"); X } X else { X wild = FALSE; X amount = 1; X } X /* The "multiple send" problem is brought about by attempting to X ** send multiple files in a single "batch" (via globbing, e.g. *.foo) X ** to a remote kermit that is NOT in server mode. A 'Z' packet X ** (meaning end-of-file) is sent after each of the files with a 'B' X ** packet (meaning end-of-batch) coming after the last 'Z' packet. X ** The old code reset the packet # on each iteration. We do it X ** outside of the for loop. */ X n = lastpkt = 0; X ulp = 0; /* Assume we won't use LONG packets */ X for (c = 0; c < amount; c++) { X if (wild == TRUE) p = list[c]; X else p = file; X strcpy(filnam,getfname(p)); X ttime = TTIME_KERMIT; X tp = retry = numtry = 0; totbytes = 0L; X if ((fp = fopen(p,"r")) == NULL) { X InfoMsg2Line("KERMIT: Can't open send file:", p); X continue; X } X strcpy(mainmode,"SEND"); X ClearBuffer(); X X /* This is another piece of the multiple-send fix. Sendsw() needs X ** to know 1) that this is the first file so it can send a send-init X ** packet and 2) if this is the last file so it can send a B packet X ** to indicate end-of-batch. The last piece of the multiple-send fix X ** is in sendsw() itself. */ X if ( sendsw(c == 0, c >= (amount-1)) ) /* Successful send? */ X ScrollInfoMsg(1); X fclose(fp); X } X free_expand(list); X FreeMem(spackbuf, (long)(MAXLONGPKS+20)); X FreeMem(msgpkt, (long)(MAXLONGPKS+20)); X msgpkt = spackbuf = NULL; X return(TRUE); X} X Xdokreceive(file,more) Xchar *file; Xint more; X{ X int retval; X X msgpkt = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); X spackbuf = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR); X ttime = TTIME_KERMIT; X sending = 0; X if (!strcmp(file,"$")) { saybye(); return(USERABORT); } X strcpy(filnam, file); X if (server) strcpy(mainmode,"GET"); X else strcpy(mainmode,"RECV"); X tp = lastpkt = retry = n = numtry = notfirst = 0; totbytes = 0L; X ClearBuffer(); X retval = recsw(); X FreeMem(spackbuf, (long)(MAXLONGPKS+20)); X FreeMem(msgpkt, (long)(MAXLONGPKS+20)); X msgpkt = spackbuf = NULL; X return(retval); X} X Xsendsw(firstfile, lastfile) Xint firstfile, lastfile; /* Multiple-send fix */ X{ X char sinit(), sfile(), sdata(), seof(), sbreak(); X sendabort = 0; X /* Multiple-send fix. If this is the first file of the batch then enter X ** send-init state otherwise just enter send-file state. */ X if(firstfile) X state = 'S'; X else X state = 'F'; X while(TRUE) { X switch(state) { X case 'S': state = sinit(); break; X case 'F': state = sfile(); break; X case 'D': state = sdata(); break; X case 'Z': state = seof(); break; X case 'B': if (lastfile || sendabort) { X /* Multiple-send fix. If this is the last file then X ** send a B packet to indicate end-of-batch. */ X state = sbreak(); X break; X } X return(TRUE); /* Otherwise, just return. */ X case 'C': if (sendabort) return(FALSE); X else return(TRUE); X case 'E': dostats('E',"ERROR"); /* so print the err and abort */ X print_host_err(ackpkt); X return(FALSE); X case 'A': if (timeout == USERABORT) { X timeout = GOODREAD; X n = (n+1)%64; X sendabort = 1; X dostats('A',"ABORT"); X strcpy(msgpkt, "D"); X state = 'Z'; X break; X } X if (timeout == TIMEOUT) dostats('A',"TMOUT"); X else { /* protocol error dectected by us */ X dostats('A',"ERROR"); X print_our_err(); X } X return(FALSE); X default: return(FALSE); X } X } X} X Xchar sinit() X{ X int num, len; X X retry++; X if (numtry++ > MAXTRY) return('A'); X spar(msgpkt); X X spack('S',n,13,msgpkt); X switch(rpack(&len,&num,ackpkt)) { X case 'N': return(state); X case 'Y': if (n != num) return(state); X rpar(ackpkt, len); X if (eol == 0) eol = '\n'; X if (quote == 0) quote = MYQUOTE; X numtry = 0; X retry--; X n = (n+1)%64; X return('F'); X case 'E': return('E'); X case FALSE: if (timeout == USERABORT) state = 'A'; X return(state); X default: return('A'); X } X} X Xchar sfile() X{ X int num, len; X X retry++; X if (numtry++ > MAXTRY) return('A'); X X spack('F',n,strlen(filnam),filnam); X switch(rpack(&len,&num,ackpkt)) { X case 'N': X num = (--num<0 ? 63:num); X if (n != num) return(state); X case 'Y': X if (n != num) return(state); X numtry = 0; X retry--; X n = (n+1)%64; X first = 1; X size = getpkt(); X return('D'); X case 'E': X return('E'); X case FALSE: if (timeout == USERABORT) state = 'A'; X return(state); X default: X return('A'); X } X} X Xchar sdata() X{ X int num, len; X X retry++; X if (numtry++ > MAXTRY) return('A'); X X spack('D',n,size,msgpkt); X switch(rpack(&len,&num,ackpkt)) { X case 'N': X num = (--num<0 ? 63:num); X if (n != num) return(state); X case 'Y': X if (n != num) return(state); X numtry = 0; X retry--; X n = (n+1)%64; X if ((size = getpkt()) == 0) return('Z'); X return('D'); X case 'E': X return('E'); X case FALSE: if (timeout == USERABORT) state = 'A'; X return(state); X default: X return('A'); X } X} X Xchar seof() X{ X int num, len; X retry++; X if (numtry++ > MAXTRY) return('A'); X X/* if (timeout == USERABORT) {*/ /* tell host to discard file */ X/* timeout = GOODREAD; */ X/* spack('Z',n,1,"D"); */ X/* } */ X/* else */ X spack('Z',n,sendabort,msgpkt); X switch(rpack(&len,&num,ackpkt)) { X case 'N': X num = (--num<0 ? 63:num); X if (n != num) return(state); X case 'Y': X if (n != num) return(state); X numtry = 0; X dostats('Z',"DONE"); X retry--; X n = (n+1)%64; X return('B'); X case 'E': return('E'); X case FALSE: return(state); X default: return('A'); X } X} X Xchar sbreak() X{ X int num, len; X retry++; X if (numtry++ > MAXTRY) return('A'); X X spack('B',n,0,msgpkt); X switch (rpack(&len,&num,ackpkt)) { X case 'N': X num = (--num<0 ? 63:num); X if (n != num) return(state); X case 'Y': X if (n != num) return(state); X dostats('B', "DONE"); X numtry = 0; X retry--; X n = (n+1)%64; X return('C'); X case 'E': return('E'); X case FALSE: return(state); X default: return ('A'); X } X} X X/* timeout equals USERABORT so lets end the file and quit */ X/* when host receives 'Z' packet with "D" in data field he */ X/* should discard the file. */ X/* Xsabort() X{ X dostats(' ',"ABORT"); X n = (n+1)%64; X retry--; X state = 'Z'; X while (state == 'Z') state = seof(); X while (state == 'B') state = sbreak(); X return(FALSE); X} X*/ X X Xrecsw() X{ X char rinit(), rfile(), rdata(); X int first_time = 1; X X state = 'R'; X X while(TRUE) { X switch(state) { X case 'R': ulp = 0; /* Assume we won't use LONG packets */ X state = rinit(); X break; X case 'Z': X case 'F': state = rfile(first_time); first_time = 0; X break; X case 'D': state = rdata(); X break; X case 'C': return(TRUE); X case 'E': X case 'A': /* easy way to cleanly abort X should really send and ACK X with "X" in data field and X wait for host to abort but X not all kermits support X this feature. */ X if (timeout == USERABORT){ X /* send an error packet back */ X dostats('A',"ABORT"); X spack('E',n,12,"User aborted"); X } X else if (timeout == TIMEOUT) { X /* we timed out waiting */ X /* will we need to spack here ?*/ X dostats('A',"TMOUT"); X } X /* must be 'E' from host or we detected a protocol X ** error */ X else dostats('A',"ERROR"); X X if (state == 'E') print_host_err(msgpkt); X else if (timeout == GOODREAD) /* tell host why */ X print_our_err(); X /* will this kill all files ?*/ X do { X ttime = 2; X readchar(); X } while (timeout == GOODREAD); X fclose(fp); X sendchar('\r'); X return(FALSE); X default: return(FALSE); X } X } X} X Xchar rinit() X{ X int len, num, temp; X retry++; X if (numtry++ > MAXTRY) return('A'); X X if (server) X spack('R',n,strlen(filnam),filnam); X X switch(rpack(&len,&num,msgpkt)) { X case 'S': X rpar(msgpkt, len); X /* Rpar() will set ulp if we can use long packets. We can't use X ** that value right away cause we've gotta ACK with normal pkts. */ X temp = ulp; ulp = 0; X spar(msgpkt); X spack('Y',n,13,msgpkt); X ulp = temp; /* Restore using long pkts flag */ X oldtry = numtry; X numtry = 0; X retry--; X n = (n+1)%64; X return('F'); X case 'E': X return('E'); X case 'N': /* Other side NAKed us... */ X return(state); /* ...so try again */ X case FALSE: X if (timeout == USERABORT) return('A'); X if (timeout == TIMEOUT) return(state); /* Resend Rec-init on a timeout */ X spack('N',n,0,""); X return(state); X default: X return('A'); X } X} X Xchar rfile(first_time) Xint first_time; X{ X int num, len, temp; X USHORT a, a7, b8; X char *fileptr, *buf; X X retry++; X if (numtry++ > MAXTRY) return('A'); X X switch(rpack(&len,&num,msgpkt)) { X case 'S': X if (oldtry++ > MAXTRY) return('A'); X if (num == ((n==0) ? 63:n-1)) { X /* Rpar() will set ulp if we can use long packets. We can't use X ** that value right away cause we've gotta ACK with normal pkts. */ X temp = ulp; ulp = 0; X spar(msgpkt); X spack('Y',num,13,msgpkt); X ulp = temp; X numtry = 0; X return(state); X } X else return('A'); X case 'Z': X if (oldtry++ > MAXTRY) return('A'); X if (num == ((n==0) ? 63:n-1)) { X spack('Y',num,0,""); X ScrollInfoMsg(1); X numtry = 0; X return(state); X } X else return('A'); X case 'F': X if (num != n) return('A'); X if(!first_time) { /* Scroll the Z packet line up */ X dostats('Z', "DONE"); X ScrollInfoMsg(1); X } X buf = msgpkt; X fileptr = filnam; X while ((a = *buf++) != '\0') { /* Terminator added by rpack() */ X if (rptflg) { X if (a == rptq) { X rpt = unchar(*buf++); X a = *buf++; X } X } X b8 = 0; X if (ebqflg) { /* 8th-bit prefixing? */ X if (a == ebq) { /* Yes, got an 8th-bit prefix? */ X b8 = 0200; /* Yes, remember this, */ X a = *buf++; /* and get the prefixed character. */ X } X } X if (a == quote) { X a = *buf++; X a7 = a & 0177; X if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a); X } X a |= b8; X if (rpt == 0) rpt = 1; X if (p_mode == 1 && a == '\r') continue; X for (; rpt > 0; rpt--) *fileptr++ = a; X *fileptr = '\0'; /* Terminate the filename */ X } X X if (p_convert) { X char *p; X p = &filnam[0]; X while (*p) { *p = tolower(*p); p++; } X } X if (notfirst) { X totbytes = 0L; X dostats('F',"RECV"); X } X else { /* is the first file so emit actual file name from host */ X notfirst++; X } X if ((fp = fopen(filnam,"w")) == NULL) { X InfoMsg2Line("KERMIT: Unable to create file:", filnam); X strcpy(msgpkt,"VT100 - Kermit - cannot create file: "); X strcat(msgpkt,filnam); X spack('E',n,strlen(msgpkt),msgpkt); /* let host know */ X dostats('E',"ERROR"); X return ('\0'); /* abort everything */ X } X spack('Y',n,0,""); X oldtry = numtry; X numtry = 0; X retry--; X n = (n+1)%64; X return('D'); X X /* totaly done server sending no more */ X case 'B': X if (num != n) return ('A'); X spack('Y',n,0,""); X dostats('B', "DONE"); X ScrollInfoMsg(1); X retry--; X return('C'); X case 'E': X return('E'); X case FALSE: X if (timeout == USERABORT) return('A'); X spack('N',n,0,""); X return(state); X default: X return ('A'); X } X} X Xchar rdata() X{ X int num, len; X retry++; X if (numtry++ > MAXTRY) return('A'); X X switch(rpack(&len,&num,msgpkt)) { X case 'D': X if (num != n) { X if (oldtry++ > MAXTRY) return('A'); X if (num == ((n==0) ? 63:n-1)) { X spack('Y',num,6,msgpkt); X numtry = 0; X return(state); X } X else return('A'); X } X decode(); X spack('Y',n,0,""); X oldtry = numtry; X numtry = 0; X retry--; X n = (n+1)%64; X return('D'); X case 'Z': X if (num != n) return('A'); X spack('Y',n,0,""); X n = (n+1)%64; X dostats('Z',"DONE"); X retry--; X fclose(fp); X return('Z'); X case 'F': X if (oldtry++ > MAXTRY) return('A'); X if (num == ((n==0) ? 63:n-1)) { X spack('Y',num,0,""); X numtry = 0; X return(state); X } X case 'E': X return('E'); X case FALSE: X if (timeout == USERABORT) return('A'); X spack('N',n,0,""); X return(state); X default: X return('A'); X } X} X Xstatic void Xspack(type,num,len,data) Xchar type, *data; Xint num, len; X{ X int i; X char chksum, t; X register char *bufp; X X if(sending && (lastpkt != num)) { X tp++; X lastpkt = num; X } X dostats(type,mainmode); X bufp = spackbuf; X ClearBuffer(); X X for (i=1; i<=pad; i++) sendchar(padchar); X X *bufp++ = SOH; X if(ulp && len > (MAXPACKSIZ-3)) /* Using long packets */ X t = tochar(0); X else X t = tochar(len+3); X *bufp++ = t; chksum = t; X t = tochar(num); X *bufp++ = t; chksum += t; X *bufp++ = type; chksum += type; X if(ulp && len > (MAXPACKSIZ-3)) { /* Using long packets */ X unsigned int pl = len + 1; X X t = tochar(pl / 95); X *bufp++ = t; chksum += t; X t = tochar(pl % 95); X *bufp++ = t; chksum += t; X t = tochar((((chksum&0300) >> 6)+chksum)&077); X *bufp++ = t; chksum += t; X } X for (i=0; i<len; i++) { X *bufp++ = data[i]; chksum += data[i]; X } X chksum = (((chksum&0300) >> 6)+chksum)&077; X *bufp++ = tochar(chksum); X if (eol) X *bufp++ = eol; /* Use sender's requested end-of-line */ X else X *bufp++ = '\r'; X *bufp = '\0'; X sendstring(spackbuf); X} X Xrpack(len,num,data) Xint *len, *num; Xchar *data; X{ X int i, done; X char type, cchksum, rchksum; X char t = '\0'; X X do { X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X } while (t != SOH); X X done = FALSE; X while (!done) { X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X cchksum = t; X *len = unchar(t)-3; X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X cchksum += t; X *num = unchar(t); X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X cchksum += t; X type = t; X if((*len == -3) && ulp) { /* Using long packets */ X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X cchksum += t; X *len = unchar(t)*95; X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X cchksum += t; X *len += unchar(t); X (*len)--; X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X if(unchar(t) != ((((cchksum&0300) >> 6)+cchksum)&077)) return(FALSE);; X cchksum += t; X } X for (i=0; i<*len; i++) { X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X cchksum = cchksum + t; X data[i] = t; X } X data[*len] = 0; X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X rchksum = unchar(t); X t = readchar(); X if (timeout != GOODREAD) return(FALSE); X if (t == SOH) continue; X done = TRUE; X } X if(type != 'B' && type != 'Z') X dostats(type,mainmode); X cchksum = (((cchksum&0300) >> 6)+cchksum)&077; X if (cchksum != rchksum) return(FALSE); X if(!sending && (*num != lastpkt)) { X tp++; X lastpkt = *num; X } X return((int)type); X} X Xgetpkt() { X int i,eof; X X static char leftover[10] = { '\0', '\0', '\0', '\0', '\0', X '\0', '\0', '\0', '\0', '\0' }; X X if (first == 1) { X first = 0; X *leftover = '\0'; X t = getc(fp); X if (t == EOF) { X first = 1; X return(size = 0); X } X totbytes++; X } X else if (first == -1) { X first = 1; X return(size = 0); X } X for (size = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ; X *leftover = '\0'; X rpt = 0; X eof = 0; X while (!eof) { X next = getc(fp); X if (next == EOF) { X first = -1; X eof = 1; X } X else totbytes++; X osize = size; X encode(t); X t = next; X if (size == spsiz-3) return(size); X if (size > spsiz-3) { X for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++) X ; X size = osize; X msgpkt[size] = '\0'; X return(size); X } X } X return(size); X} X Xstatic void Xencode(a) Xchar a; X{ X int a7,b8; X X if (p_mode == 1 && a == '\n') { X rpt = 0; X msgpkt[size++] = quote; X msgpkt[size++] = ctl('\r'); X if (size <= spsiz-3) osize = size; X msgpkt[size++] = quote; X msgpkt[size++] = ctl('\n'); X msgpkt[size] = '\0'; X return; X } X if (rptflg) { X if (a == next && (first == 0)) { X if (++rpt < 94) return; X else if (rpt == 94) { X msgpkt[size++] = rptq; X msgpkt[size++] = tochar(rpt); X rpt = 0; X } X } X else if (rpt == 1) { X rpt = 0; X encode(a); X if (size <= spsiz-3) osize = size; X rpt = 0; X encode(a); X return; X } X else if (rpt > 1) { X msgpkt[size++] = rptq; X msgpkt[size++] = tochar(++rpt); X rpt = 0; X } X } X a7 = a & 0177; X b8 = a & 0200; X X if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */ X msgpkt[size++] = ebq; X a = a7; X } X X if ((a7 < SP) || (a7==DEL)) { X msgpkt[size++] = quote; X a = ctl(a); X } X if (a7 == quote) msgpkt[size++] = quote; X if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote; X X if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */ X msgpkt[size++] = quote; /* if doing 8th-bit prefixes */ X X msgpkt[size++] = a; X msgpkt[size] = '\0'; X} X Xstatic void Xdecode() X{ X USHORT a, a7, b8; X char *buf; X X buf = msgpkt; X rpt = 0; X X while ((a = *buf++) != '\0') { /* Terminator added by rpack() */ X if (rptflg) { X if (a == rptq) { X rpt = unchar(*buf++); X a = *buf++; X } X } X b8 = 0; X if (ebqflg) { /* 8th-bit prefixing? */ X if (a == ebq) { /* Yes, got an 8th-bit prefix? */ X b8 = 0200; /* Yes, remember this, */ X a = *buf++; /* and get the prefixed character. */ X } X } X if (a == quote) { X a = *buf++; X a7 = a & 0177; X if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a); X } X a |= b8; X if (rpt == 0) rpt = 1; X if (p_mode == 1 && a == '\r') continue; X totbytes += rpt; X for (; rpt > 0; rpt--) putc(a, fp); X } X return; X} X Xstatic void Xspar(data) Xchar data[]; X{ X data[0] = tochar(MAXPACKSIZ); X data[1] = tochar(TTIME_KERMIT); X data[2] = tochar(MYPAD); X data[3] = ctl(MYPCHAR); X data[4] = tochar(MYEOL); X data[5] = MYQUOTE; X if ((p_parity > 0) || ebqflg) { /* 8-bit quoting... */ X data[6] = MYEBQ; /* If parity or flag on, send &. */ X if ((ebq > 0040 && ebq < 0100) || /* If flag off, then turn it on */ X (ebq > 0140 && ebq < 0177) || /* if other side has asked us to */ X (ebq == 'Y')) X ebqflg = 1; X } X else /* Normally, */ X data[6] = 'Y'; /* just say we're willing. */ X data[7] = '1'; X data[8] = MYRPTQ; X data[9] = tochar(IDOLONG); /* Tell 'em I do LONG packets */ X data[10] = tochar(0); /* Don't do windows */ X data[11] = tochar(p_kmaxpack / 95); X data[12] = tochar(p_kmaxpack % 95); X data[13] = '\0'; X} X Xstatic void Xrpar(data, len) Xchar data[]; Xint len; X{ X int ospsiz; X X spsiz = unchar(data[0]); X ospsiz = spsiz; X ttime = unchar(data[1]); X pad = unchar(data[2]); X padchar = ctl(data[3]); X eol = unchar(data[4]); X quote = data[5]; X rptflg = 0; X ebqflg = 0; X if (len >= 6 && data[6] != 0) { X ebq = data[6]; X if ((ebq > 040 && ebq < 0100) || X (ebq > 0140 && ebq < 0177)) ebqflg = 1; X else if (((p_parity > 0) || ebqflg) && (ebq == 'Y')) { X ebqflg = 1; X ebq = '&'; X } X else ebqflg = 0; X } X if (len >= 8 && data[8] != 0) { X rptq = data[8]; X rptflg = ((rptq > 040 && rptq < 0100) || X (rptq > 0140 && rptq < 0177)); X } X if(len >= 9 && data[9] != 0) { X int capas; X for(capas=9; data[capas] & 1; capas++) ; /* Skip over continuations */ X if((ulp = (data[9] & IDOLONG)) == IDOLONG) { X spsiz = 500; /* Default if no packet size specified */ X if(len >= capas+3) { X spsiz = (unchar((data[capas+2])) * 95) + unchar(data[capas+3]); X if(spsiz > MAXLONGPKS) X spsiz = MAXLONGPKS; X else if(spsiz < 10) /* Reasonable? */ X spsiz = 500; X } X } X } X} X Xvoid Xsaybye() X{ X int len,num; X X if(msgpkt == NULL) /* No msgpkt buffer... */ X return; /* ...so just return. */ X X if(numreqs != 0) /* Requester's up... */ X Delay(5L); /* ...so wait for Intuition, just in case. */ X spack('G',n,1,"F"); /* shut down server no more files */ X rpack(&len,&num,ackpkt); X} X Xstatic void Xprint_our_err() X{ X if (retry > MAXTRY || oldtry > MAXTRY) { X InfoMsg1Line("KERMIT: Too may retries for packet"); X strcpy(msgpkt,"VT100 KERMIT: Too many retries for packet"); X } X else { X InfoMsg1Line("KERMIT: Protocol Error"); X strcpy(msgpkt,"VT100 KERMIT: Protocol Error"); X } X spack('E',n,strlen(msgpkt),msgpkt); X} X Xstatic void Xprint_host_err(msg) Xchar *msg; X{ X InfoMsg2Line("KERMIT: Host Error:", msg); X} X Xstatic void Xdostats(type,stat) Xchar type,*stat; X{ X char *statusform = "%5s %-15.15s Pkt: %4d Retr: %2d Bytes: %6ld Type: %c", X status[80]; X X if (type == 'Y' || type == 'N' || type == 'G') return; X X sprintf(status, statusform, stat, filnam, tp, retry-1, X (LONG)totbytes, type); X InfoMsgNoScroll(status); X} X Xstatic void XClearBuffer() X{ X AbortIO((struct IORequest *)Read_Request); X Wait(1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit); X WaitIO((struct IORequest *)Read_Request); X Read_Request->IOSer.io_Command = CMD_CLEAR; X DoIO((struct IORequest *)Read_Request); X Read_Request->IOSer.io_Command = CMD_READ; X SendIO((struct IORequest *)Read_Request); X} SHAR_EOF echo "extracting kermitproto.c" sed 's/^X//' << \SHAR_EOF > kermitproto.c X/* :ts=8 */ X X/* WARNING -- This C source program generated by Wart preprocessor. */ X/* Do not edit this file; edit the Wart-format source file instead, */ X/* and then run it through Wart to produce a new C source file. */ X X/* Wart Version Info: */ Xchar *wartv = "Wart Version 1A(005) Jan 1988"; X X/* X * A completely new C Kermit module. X * X * Based on code from Frank Da Cruz's excellent book, _Kermit: A File X * Transfer Protocol_, Digital Press, 1986. X * X * As this code is almost entirely from said book, it is certainly covered X * by that book's copyright. Basically, this means the code is freely X * distributable, and can be used in a commercial program provided such X * use does not increase the program's cost to the purchaser beyond a small X * handling fee. X * X * Stephen Walton, swalton@solar.stanford.edu X * Dept. of Physics and Astronomy X * California State University, Northridge X * Northridge, CA 91330 X * X * ORGANIZATION X * X * This file is in three pieces, and could probably be broken into X * two files. Leading off are #DEFINE's and declarations of X * global and external variables. Following are the unmodified sources X * from The Book. Then are the z* file-handling routines written using X * standard Unix-style (almost ANSI C) file routines. X * X * I make no apologies for the organization; my primary goals were (1) to X * use the unmodified book source except for errors found by Lint, and X * (2) to allow this file to be plugged into an otherwise unmodified X * terminal program for the Commodore Amiga computer called VT100. The X * comments starting with the string "/*lint" are for the Lint program X * of Gimpel Software, available for the Commodore Amiga and MS-DOS X * machines. I highly recommend it. X * X * A few words about style herein. Both "book Kermit" and the official X * C Kermit release make extensive use of global variables to set various X * options and keep track of what is going on. I don't like this, but X * since example source code must be part of the Kermit specification, X * I chose to keep that organization. There are several places where I X * I have tried to modularize things better. First of all, everything X * which is not needed outside of this file is declared "static". Second, X * I have kept the book Kermit code pretty much intact, except for some lint X * related things and one extra convention: tmsg() appends characters to X * an existing status line, but tmsgl() is required to force that output to X * be seen. Hence, I've changed the last in each series of tmsg() calls to X * tmsgl(). X */ X X X/* X * Revision History--Versions 0 through 1 never left me. X * X * Version 0.5--Created and linted. X * Version 0.6--Added RESUME to handling of "unknown packets". X * --Added proto() function to wrap around wart() for handling X * of startup and cleanup functions. X * --Changed handling of timeouts in input(): instead of an X * error("Timeout") call, it puts the "Timeout" message in X * the data field and pretends it read an 'E' packet. X * Version 0.7--Fixed a problem with rpsiz and MAXRP. I had set rpsiz X * to MAXRP in rpar() and was calling ttinl() with a max X * argument of MAXRP, which resulted in truncated packets; X * to wit, MAXRP+1 characters could come into ttinl counting X * the eol. Created defines DRPSIZ/DSPSIZ for default values X * for rpsiz and spsiz, and increased MAXRP. X * --Changed rcvpkt, sndpkt, and data so that they are pointers X * instead of static arrays, and allocate and de-allocate X * them in proto(). X * Version 0.8--Added client support. To make a Get X * command, point the char *cmarg at the remote file X * specification and set the start state to 'r' X * (extern char start in the calling file). X * Version 0.9--Added long packet support. This required adding an extern X * int urpsiz which is set to the desired receive packet size X * by the user interface. X * --Since the above required using the capas, I also added the X * code from C Kermit 4E(070) for negotiating window size X * in rpar() and spar(). Of course, we don't do windows yet. X * --Fixed a bug which is also part of C Kermit 4E(070). X * If we tell the sender that we can receive a packet X * of size MAXRP, the packet can contain as many as X * MAXRP+5 characters, counting the EOL and extended X * headers. So rpack() must be able to handle somewhat X * more characters than the actual maximum packet length. X * I defined MAXRP here to be 1024, but only allow X * rpsiz in proto() to be MAXRP-20. X * Version 0.95--Added code to gracefully abort transfer. This works X * via the cx and cz external variables and the state 'a'. X * Version 1.0--Unleashed upon the world. X * X */ X X/* X * Run this through the Wart preprocessor which comes with C Kermit. X */ X X#include "kermitproto.h" X Xstatic void decstr(), rinit(), error(), tinit(), spar(), zrtol(), zltor(); X X/* X * Here are the variables which need to be set to startup values, and which X * also can be freely changed between protocol transfers. At first I thought X * to declare them all "extern" in order to force definition elsewhere. X * On reflection, it makes sense to both declare them here and set them to X * their default startup values. Thus they can be ignored outside of this X * module if you so desire. X * X * Note that the names are very systematic: Names beginning with "r" have X * to do with values I use for received packets; those beginning with "s" X * are values I use for sending packets. Also note we set some, others are X * set for us. I have made the ones we get in spar() static (local), X * and the ones we send in rpar() global. X * X * First the ints. X */ X Xint cx = 0, X cz = 0, /* Flags for aborting transfers. cx (control-X)* X * is set to 1 if an abort of the current file * X * is desired, cz (control-Z) if an abort of * X * an entire batch transfer is desired. */ X rpsiz = MAXRP, /* Maximum packet size */ X /* Like most of the receive packet parameters, * X * this one is actually set by the sender. But * X * since the sender has the option to not send * X * these, we must initialize to "reasonable" * X * defaults. */ X bctr, /* Block check type to request. */ X limit = 5, /* Retry limit on receive */ X warn = 0, /* 1 for warn before overwriting files */ X rpadn = 0, /* Number of pad characters I require. */ X rtimo = 10; /* How long I want you to wait before you * X * you time me out. */ X Xchar rmark = '\1', /* Start of packet marker for receive */ X reol = '\r', /* End of packet marker for receive */ X start = 0, /* Start state */ X sctlq = '#', /* Control character quote character for send */ X rpadc = '\0'; /* Pad character I want you to use */ X X/* X * Variables which MUST be set by the external interface. X */ Xextern int X parity, /* 0 for no parity--need for proper 8th-bit quote */ X text, /* Flag 1 for text file, 0 for binary file */ X urpsiz; /* Maximum receive packet size user wants. */ X Xextern char X *cmarg; /* Character string containing Kermit server cmd */ X X/* X * In a fit of cleverness, here are some macro defines for variables we * X * aren't currently using. Only now we tell Lint to ignore constant * X * Booleans! X */ X X/*lint -e506 */ X X#define local 1 /* Local mode flag--that is, I'm on your end */ X#define server 0 /* We are never server */ X#define delay 0 /* Time to delay before sending first packet */ X#define xpkt 0 /* Send X packet instead of F? */ X X/* X * This block of defines is strictly internal flags of various kinds. * X * I hope to Grid that I've got them all. Someday this will be cleaner * X */ Xstatic int X spsiz = DSPSIZ, /* Maximum send packet size */ X wsize = MAXWS, /* Maximum window size */ X sndpkl, /* Size of packet currently being attempted */ X filcnt, /* Number of files transferred so far */ X bctu = 1, /* Block check type to use */ X rqf, /* Flag for 8th bit quote negotiations */ X ebq = '&', /* 8th-bit prefix */ X ebqflg = 0, /* 8th-bit quoting flag */ X xflag, /* Output to screen for generic server commands */ X rq = 0, /* Received 8bq bid */ X sq = 'Y', /* Sent 8bq bid */ X rpt = 0, /* Repeat count */ X rptq = '~', /* Repeat prefix */ X rptflg = 0, /* Repeat processing flag */ X capas = 10, /* Final position of inbound capas mask */ X atcapr = 0, /* Attribute capability requested */ X atcapu = 0, /* Attribute capability used */ X swcapr = 0, /* Sliding windows capability requested */ X swcapu = 0, /* Sliding windows capability used */ X lpcapr = 0, /* Long packets capability requested */ X lpcapu = 0, /* Long packets capability used */ X rsn, /* Received sequence number */ X seq = 0, /* Current sequence number */ X maxsiz, /* Maximum data size for packet */ X rln, /* Length of received data field */ X size, /* Current size of output packet data */ X osize, /* Previous output packet data size */ X first = 0, /* Some kind of lookahead flag */ X stimo = 5, /* Timeout interval for me to use */ X spadn = 0; /* Number of pad characters for me to use */ X X#define atcapb 8 /* Attribute capability bit */ X#define swcapb 4 /* Sliding windows capability bit */ X#define lpcapb 2 /* Long packets capability bit */ X#define closif zclosi /* I use closif() to close the input file in * X * case it needs to be more complex later, but * X * for now it just calls the z routine. */ X Xstatic char X smark = '\1', /* Start of packet marker for send */ X spadc = '\0', /* Pad character to use on sending */ X seol = '\r', /* End of packet marker for sending */ X rctlq = '#', /* Control character quote char for receiving */ X filnam[50], /* Current file name */ X ssc, /* Start server command */ X *sndpkt, /* Send packet. */ X *rcvpkt, /* Receieve packet. */ X *data, /* Data to send/receive before encode/decode */ X *rdatap, /* Pointer to null-terminated data field */ X *isp = NULL, /* Pointer to characters in memory */ X *osp = NULL; /* Output string pointer */ X X/* X * Forward declarations. Soon to be prototypes if the ANSI standard X * committee keeps its promises. X */ Xint input(), spack(), ack(); Xchar *rpar(); X X/* X * External routines provided. X */ X Xextern int ttinl(), ttol(), gnfile(); Xextern void ttflui(), tchar(), tmsg(), tmsgl(), sleep(); X X#define ERR(s) error(s); RESUME X#define RESUME return X X/*lint -save -e525 -e527 We don't care how Wart formats! */ X X#define ssfil 1 X#define ssdat 2 X#define sseot 3 X#define srini 4 X#define srfil 5 X#define srdat 6 X#define sipkt 7 X#define srgen 8 X X#define BEGIN state = X Xint state = 0; X Xvoid Xwart() X{ X int c,actno; X extern int tbl[]; X while (1) { X c = input(); X if ((actno = tbl[c + state*128]) != -1) X switch(actno) { Xcase 1: X { /* - Start State - */ X tinit(); /* Initialize transaction */ X if (sinit('S') < 0) { ERR("sinit"); } /* Build, send Send-Init. */ X else { /* If successful, */ X filcnt = 0; /* initialize file counter */ X BEGIN ssfil; /* and switch to ssfil state. */ X } X} X break; Xcase 2: X { tinit(); rinit(); BEGIN srini; } X break; Xcase 3: X { /* Get */ X tinit(); ssc = 0; X if (sinit('I') < 0) { ERR("sinit"); } X else BEGIN sipkt; X} X break; Xcase 4: X { /* Host */ X tinit(); ssc = 'C'; X if (sinit('I') < 0) { ERR("sinit"); } X else BEGIN sipkt; X} X break; Xcase 5: X { /* Generic */ X tinit(); ssc = 'G'; X if (sinit('I') < 0) { ERR("sinit"); } X else BEGIN sipkt; X} X break; Xcase 6: X { /* Immediate protocol abort */ X spack('E', seq, "User aborted protocol", 21); X closif(); closof(1); /* Close files, deleting output */ X RESUME; X} X break; Xcase 7: X { /* - Send File State - */ X if (filcnt++ == 0) spar(rdatap); /* Set parameters if 1st time */ X cx = 0; /* Reset file interruption flag */ X bctu = bctr; /* Switch to negotiated block check */ X /* Is there a file to send in an uncancelled batch? */ X if (!cz && gnfile(filnam, sizeof(filnam)) > 0) { X if (sfile() < 0) { ERR("sfile"); } /* Yes, open it, send F packet */ X else BEGIN ssdat; /* and if no error, switch state. */ X } else { /* No (more) files to send */ X if (seot() < 0) { ERR("seot"); } /* so send B packet */ X else BEGIN sseot; /* and switch to sseot state. */ X } X} X break; Xcase 8: X { /* - Send Data State - */ X int x; X if (rln == 1 && *rdatap == 'X') /* Did ACK contain X as data? */ X cx = 1; /* Yes, set control-x flag. */ X else if (rln == 1 && *rdatap == 'Z') /* Did ACK contain Z as data? */ X cz = 1; /* Yes set control-z flag. */ X /* Check here for cancellation of transfer and data left to send. */ X if (cx || cz || (x = sdata()) == 0) { X if (seof((cx | cz) ? "D" : "") < 0) { /* If not, send Z packet. */ X ERR("seof"); X } X else BEGIN ssfil; /* and go back to ssfil state. */ X } else if (x < 0) { ERR("sdata"); } /* Handle file i/o errors. */ X} X break; Xcase 9: X { RESUME; } X break; Xcase 10: X { X spar(rdatap); X (void) ack1(rpar()); X bctu = bctr; X BEGIN srfil; X} X break; Xcase 11: X { (void) ack(); RESUME; } X break; Xcase 12: X { if (rcvfil() < 0) { ERR("rcvfil"); } else { (void) ack(); BEGIN srdat; } } X break; Xcase 13: X { X if (cx) X ack1("X"); X else if (cz) X ack1("Z"); X else { X if (decode() < 0) { ERR("decode"); } else (void) ack(); X } X} X break; Xcase 14: X { X /* Discard output file if the sender tells us so. */ X if (closof(cx || cz || (rln == 1 && *rdatap == 'D')) < 0) { X ERR("error closing file"); X } else { X (void) ack(); BEGIN srfil; X } X} X break; Xcase 15: X { /* Got ACK for I packet */ X spar(rdatap); /* Set parameters from it */ X start = 'E'; /* Force entry into next state */ X} X break; Xcase 16: X { /* Got E for I packet */ X if (ssc) { X if (scmd(ssc,cmarg) < 0) { ERR("scmd"); } X else BEGIN srgen; X } else { X if (scmd('R',cmarg) < 0) { ERR("scmd"); } X else BEGIN srini; X } X} X break; Xcase 17: X { xflag = 1; decode(); RESUME; } X break; Xcase 18: X { xflag = 1; ack(); BEGIN srdat; } X break; Xcase 19: X { error(rdatap); X (void) closif(); X (void) closof(1); /* close files, discarding output */ X RESUME; } X break; Xcase 20: X { error("Unexpected packet type"); RESUME; } X break; X X } X } X} X Xint tbl[] = { X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 7, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 8, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 9, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 10, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 11, 20, 20, 19, 12, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 18, 20, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 13, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 14, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 15, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 20, 10, 20, 20, 20, 20, 18, 17, 20, 20, 20, 20, 20, 20, X20, 6, 20, 4, 20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, X20, 20, 3, 1, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, X}; X X X/*lint -restore */ X X/* X * First, some handy macros. X */ X X#define tochar(c) ((c) + 32) X#define unchar(c) ((c) - 32) X#define ctl(c) ((c) ^ 64) X Xstatic Xint Xinput() { /* Return packets */ X int type, try; X X if (start != 0) { /* Start state in effect? */ X type = start; /* Yes, call it a packet type, */ X start = 0; /* nullify the start state, */ X return(type); /* and return the type. */ X } X type = rpack(); /* No start state, read a packet. */ X X for (try = 0; rsn != seq || strchr("TQN",type); try++) { X if (try > limit) { /* If too mahy tries, */ X strcpy(data, "Timed out"); /* give up */ X rdatap = data; /* Make up pretend 'E' packet */ X return('E'); /* and return it */ X } X if (type == 'N' && rsn == ((seq + 1) & 63)) { X /* NAK for next packet */ X return('Y'); /* is ACK for current. */ X } else { /* Otherwise, */ X (void) resend(); /* resend previous packet. */ X } X type = rpack(); /* Try to read response. */ X } X ttflui(); /* Got a good one, clear buffer. */ X return(type); /* Return its type. */ X} X Xstatic void Xnxtpkt() { X seq = (seq + 1) & 63; /* Next packet number, mod 64 */ X} X Xstatic void Xtinit() { /* Transaction initialization */ X seq = 0; /* Start off with packet 0 */ X ebqflg = 0; /* 8-bit quoting off */ X sq = 'Y'; /* Normal 8-bit quote bid */ X rqf = -1; /* Flag other's bid not yet seen */ X rptflg = 0; /* No repeat counts by default */ X bctu = 1; /* Block check to use back to 1 */ X xflag = 0; /* Output normally to file */ X osp = NULL; /* ... */ X *filnam = *sndpkt = *rcvpkt = '\0'; /* Clear string buffers */ X} X Xstatic void Xerror(s) char *s; { /* Fatal error */ X if (local) { /* If in local mode */ X tmsg("Fatal error: "); /* Type message on console */ X tmsgl(s); X } else { /* Otherwise, */ X (void) spack('E',seq,strlen(s),s); /* Send in error packet. */ X } X} X Xstatic Xack() { X int x; /* Empty acknowledgement */ X x = spack('Y',seq,0,""); /* Send the packet */ X nxtpkt(); /* Increment the packet number */ X return(x); X} X Xstatic Xack1(s) char *s; { X int x; /* Acknowledgement with data */ X x = spack('Y',seq,strlen(s),s); /* Send the packet */ X nxtpkt(); /* Increment packet number */ X return(x); X} X Xstatic Xnak() { /* Negative acknowledgement */ X return(spack('N',seq,0,"")); /* Never has data! */ X} X X/* Functions used by file sender. */ X X/* sinit()--start the transaction by filling in the initialization string X * and sending it in an S packet. X */ X Xstatic Xsinit(c) char c; { X char *s; X s = rpar(); X if (local == 0 && c == 'S' && server == 0) { X tmsgl("Escape back to local system, give RECEIVE command..."); X sleep(delay); X } X return(spack(c,seq,strlen(s),s)); X} X X/* X * scmd() -- send a preformatted Kermit server command string. X */ Xstatic int Xscmd(t, s) char t, *s; { /* Send a packet of the given type */ X encstr(s); /* Encode the command string */ X spack(t,seq,size,data); X return 0; X} X X/* rinit() -- do whatever is needed to initialize receive. A no-op now, X * but may later initialize counters and so on. X */ Xstatic void Xrinit() X{} X X/* sfile() -- open the file and send the File-Header packet. Assumes that X * the global string pointer filnam references the file name. X */ X Xstatic Xsfile() { X int x; X char pktnam[50]; X if (zopeni(filnam) < 0) /* Try to open file. */ X return -1; X zltor(filnam,pktnam); /* OK, convert name. */ X x = encstr(pktnam); /* Encode the result */ X if (local) { /* If in local mode, */ X tmsg("Sending "); /* let user know we're */ X tmsg(filnam); /* sending this file */ X tmsg(" as "); /* under */ X tmsgl(pktnam); /* this name */ X } X first = 1; /* Flag beginning of file */ X maxsiz = spsiz - (bctr + 3); /* Maximum data length */ X nxtpkt(); /* Increment packet number */ X return(spack((xpkt ? 'X' : 'F'),seq,x,data)); /* Send packet */ X} X X/* sdata() -- get next packet's worth of data */ X Xstatic Xsdata() { X int x; X if ((x = getpkt(maxsiz)) == 0) /* If no data left to send, */ X return(0); /* return EOF indication. */ X nxtpkt(); X return(spack('D',seq,x,data)); /* Send the data packet */ X} X X/* seof -- close the input file and send a Z packet. */ X Xstatic Xseof(s) char *s; { X if (closif() < 0) /* Try to close the file. */ X return -1; /* On error, return failure. */ X else { /* Otherwise, */ X if (local) tmsgl("OK"); /* if local, reassure user. */ X nxtpkt(); X return(spack('Z',seq,strlen(s),s)); /* Send Z packet */ X } X} X X/* seot -- send B packet. */ X Xstatic Xseot() { X nxtpkt(); X if (local) tmsgl("Done"); X return(spack('B',seq,0,"")); X} X Xstatic Xrcvfil() { /* Receive a file */ X char myname[50]; X decstr(filnam); /* Decode name */ X zrtol(filnam,myname,warn); /* Convert to local form. */ X if (zopeno(myname) < 0) X return -1; X else { /* File open OK, give message. */ X if (local && !xflag) { X tmsg("Receiving "); tmsg(filnam); tmsg(" as "); tmsgl(myname); X } X return 0; X } X} X Xstatic Xclosof(nokeep) int nokeep; { /* Close output file, but */ X if (xflag) return 0; /* not if it's the screen. */ X if (zcloso(nokeep) < 0) X return -1; X return 0; X} X Xstatic Xspack(type,n,len,d) char type, *d; int n, len; { X int i = 0, j, k; X X for (i = 0; i < spadn; i++) X sndpkt[i] = spadc; /* Do requested padding */ X sndpkt[i++] = smark; /* Packet mark */ X k = i++; /* Remember this place */ X sndpkt[i++] = tochar(n); /* Sequence number */ X sndpkt[i++] = type; /* Packet type */ X j = len + bctu; /* True length */ X if (j > 95) { /* Long packet? */ X sndpkt[k] = tochar(0); /* Set LEN to 0 */ X sndpkt[i++] = tochar(j / 95); /* High part of length */ X sndpkt[i++] = tochar(j % 95); /* Low part of length */ X sndpkt[i] = '\0'; /* Header checksum */ X sndpkt[i++] = tochar(chk1(sndpkt+k)); X } else X sndpkt[k] = tochar(j+2); /* True length. */ X X for (j = len; j > 0; j--) { /* Data */ X sndpkt[i++] = *d++; X } X sndpkt[i] = '\0'; /* Null terminate. */ X switch (bctu) { X case 1: /* Type 1 - 6 bit checksum */ X sndpkt[i++] = tochar(chk1(sndpkt+k)); X break; X case 2: /* Type 2 - 12 bit checksum */ X j = chksum(sndpkt+k); X sndpkt[i++] = tochar((j >> 6) & 077); X sndpkt[i++] = tochar(j & 077); X break; X case 3: /* Type 3 - 16 bit CRC-CCITT */ X j = chk3(sndpkt + k); X sndpkt[i++] = tochar((j >> 12) & 017); X sndpkt[i++] = tochar((j >> 6) & 077); X sndpkt[i++] = tochar(j & 077); X break; X } X sndpkt[i++] = seol; /* End of line */ X sndpkt[i] = '\0'; /* Null string-terminator. */ X sndpkl = i; /* Remember length. */ X i = ttol(sndpkt,sndpkl); /* Send the packet. */ X if (local && !xflag) tchar('.'); X return(i); X} X Xstatic Xresend() { X int x; X if (*sndpkt) X x = ttol(sndpkt,sndpkl); /* Send previous packet */ X else X x = nak(); /* or NAK if none */ X if (local && !xflag) tchar('%'); /* Let the user know. */ X return(x); X} X Xchk1(packet) char *packet; { /* Compute Kermit's */ X int s, t; /* 1-character block check. */ X s = chksum(packet); /* Get the arithmetic sum. */ X t = (((s & 192) >> 6) + s) & 63; /* Fold it into 6 bits. */ X return(t); X} X Xstatic Xchksum(p) char *p; { /* Compute the checksum. */ X unsigned m; X long s; X X m = (parity) ? 0177 : 0377; /* Mask for parity bit. */ X s = 0; X for (; *p != '\0'; p++) /* For each character, */ X s += *p & m; /* accumulate the sum, */ X return(s & 07777); /* and then return it. */ X} X X/* X * rpack reads a packet and returns the packet type, or else Q if the X * packet was invalid, or T if a timeout occured. Upon successful return, X * sets the global variables: X * rsn - the received sequence number X * rln - length of the received data field X * rdatap - a pointer to the null-terminated contents of the data field X */ Xstatic Xrpack() { X int i, j, x, type, rlnpos; X char pbc[4]; /* Packet block check. */ X X rsn = rln = -1; /* In case of failure. */ X X *rcvpkt = '\0'; /* Initialize receive buffer. */ X j = ttinl(rcvpkt,MAXRP,reol,stimo); /* Try to get a "line". */ X if (j < 0) return('T'); /* Timed out. */ X X for (i = 0; rcvpkt[i] != rmark && (i < j); i++) /* Find mark. */ X ; X if (i == j) return('Q'); /* If no mark, bad packet. */ X X rlnpos = ++i; /* Got it, remember position. */ X if ((j = unchar(rcvpkt[i++])) == 0) { /* Long packet? */ X j = rlnpos + 5; /* Yes, check header */ X if (j > MAXRP) return('Q'); /* Be defensive. */ X x = rcvpkt[j]; /* Remember header checksum */ X rcvpkt[j] = '\0'; X if (unchar(x) != chk1(rcvpkt+rlnpos)) /* Check header */ X return('Q'); X rcvpkt[j] = x; /* Restore packet */ X rln = unchar(rcvpkt[j-2]) * 95 + unchar(rcvpkt[j-1]) - bctu; X j = 3; X } else { X rln = j - bctu - 2; /* Regular packet */ X j = 0; /* No extended header */ X } X rsn = unchar(rcvpkt[i++]); /* Sequence number. */ X type = rcvpkt[i++]; /* Packet type */ X i += j; /* Skip extended header, if any */ X rdatap = rcvpkt + i; /* The data itself. */ X j = rln + i; /* Position of block check. */ X if (j > MAXRP) X return('Q'); /* Be defensive! */ X for (x = 0; x < bctu; x++) /* Copy the block check. */ X pbc[x] = rcvpkt[j+x]; X rcvpkt[j] = '\0'; X switch (bctu) { /* Which block check type? */ X case 1: X if (unchar(*pbc) != chk1(rcvpkt+rlnpos)) return('Q'); X break; X case 2: X x = unchar(*pbc) << 6 | unchar(pbc[1]); X if (x != chksum(rcvpkt+rlnpos)) return('Q'); X case 3: X x = unchar(*pbc) << 12 | unchar(pbc[1]) << 6 | unchar(pbc[2]); X if (x != chk3(rcvpkt+rlnpos)) return('Q'); X break; X default: X error("Impossible block check type."); X } X return type; /* Otherwise, return packet type */ X} X X/* X * CHK3 X * Calculate the 16-bit CRC of a null-terminated string using a X * byte-oriented tableless algorithm devised by Andy Lowry (Columbia X * University). The magic number 010201 is derived from the CRC-CCITT X * polynomial x^16+x^12+x^5+1. X */ Xstatic Xchk3(s) char *s; { X unsigned int c, q; X long crc = 0; X X while ((c = *s++) != '\0') { X if (parity) c &= 0177; X q = (crc ^ c) & 017; /* Low order nybble */ X crc = (crc >> 4) ^ (q * 010201); X q = (crc ^ (c >> 4)) & 017; /* High order nybble */ X crc = (crc >> 4) ^ (q * 010201); X } X return(crc); X} X X/* X * getpkt--Fill a packet to the maximum. Result goes in local data array X * whose current length is indicated in global size. X */ Xstatic Xgetpkt(maxlen) int maxlen; { X int i, next; X static int c; X static char remain[6] = {'\0', '\0', '\0', '\0', '\0', '\0'}; X void encode(); X X if (first == 1) { /* If first time thru... */ X first = 0; /* remember not to do this next time, */ X remain[0] = '\0'; /* discard any old leftovers, */ X c = gnchar(); /* get first character of file */ X if (c < 0) { /* watching out for null file */ X first = -1; X return(size = 0); X } X } else if (first == -1) { /* EOF from last time? */ X return(size = 0); X } X X X/* Copy any leftovers that didn't fit in the last packet. */ X X for (size = 0; (data[size] = remain[size]) != '\0'; size++) X ; X *remain = '\0'; X X/* Get, encode, and deposit the next character. */ X X rpt = 0; /* Initialize repeat counter. */ X X while (first > -1) { /* Until end of file or string... */ X next = gnchar(); /* Look ahead one character */ X if (next < 0) first = -1; /* If none, we're at EOF. */ X osize = size; /* Remember current size. */ X encode(c, next); /* Encode the character. */ X c = next; /* Old next char is now current. */ X if (size == maxlen) return(size); /* If just at end, done. */ X if (size > maxlen) { /* Past end, must save some. */ X for (i = 0; (remain[i] = data[osize+i]) != '\0'; i++) X ; X size = osize; X data[size] = '\0'; X return(size); /* Return size. */ X } X } X return(size); /* EOF, return size. */ X} X Xstatic Xgnchar() { X char c; X X if (isp) { /* From string in memory */ X return((c = *isp++) > 0 ? c : -1); X } else X return(zgetc(text)); /* or from a file. */ X} X X/* X * Encodes the character a into the global data array, X * and the global size is updated. X * Global sctlq is the control prefix for sending data. X */ Xstatic void Xencode(a, next) char a; int next; { X int a7, b8; X X if (rptflg) { /* Doing run-length encoding? */ X if (a == next) { /* Yes, got a run? */ X if (++rpt < 94) { /* Yes count. */ X return; X } else if (rpt == 94) { /* If at maximum */ X data[size++] = rptq; /* Emit prefix, */ X data[size++] = tochar(rpt); /* and count, */ X rpt = 0; /* and reset counter. */ X } X } else if (rpt == 1) { /* Run broken, only two? */ X rpt = 0; /* Yes, do the character wice */ X encode(a,-1); /* by calling self recursively. */ X if (size <= maxsiz) osize = size; /* Watch for boundary */ X rpt = 0; /* Call self second time. */ X encode(a,-1); X return; X } else if (rpt > 1) { /* Run broken, more than two? */ X data[size++] = rptq; /* Yes, emit prefix and count */ X data[size++] = tochar(++rpt); X rpt = 0; /* and reset counter. */ X } X } X a7 = a & 127; /* Isolate low 7 bits */ X b8 = a & 128; /* And "parity" bit */ X X if (ebqflg & b8) { /* If doing 8th-bit prefixing */ X data[size++] = ebq; /* and 8th bit on, insert prefix */ X a = a7; /* and clear the 8th bit. */ X } X if (a7 < 32 || a7 == 127) { /* If control character */ X data[size++] = sctlq; /* insert control quote */ X a = ctl(a); /* and make printable. */ X } else if (a7 == sctlq) /* If data is control prefix, */ X data[size++] = sctlq; /* prefix it. */ X else if (ebqflg && a7 == ebq) /* If doing 8th-bit prefixing, */ X data[size++] = sctlq; /* ditto for 8th-bit prefix. */ X else if (rptflg && a7 == rptq) /* If doing run-length encoding, */ X data[size++] = sctlq; /* ditto for repeat prefix. */ X X data[size++] = a; /* Finally, emit the character. */ X data[size] = '\0'; /* Terminate string. */ X} X X/* X * Decodes the data pointed to by the global pointer rdatap. X */ Xstatic Xdecode() { X int a, a7, b8; X X while ((a = *rdatap++) != '\0') { X rpt = 1; /* Initialize repeat count. */ X if (rptflg) { /* Repeat processing? */ X if (a == rptq) { /* Yes, have repat prefix? */ X rpt = unchar(*rdatap++); /* Yes, get count. */ X a = *rdatap++; /* and following character. */ X } X } X b8 = 0; /* Assume 8th bit not on. */ X if (ebqflg) { /* Doing 8th-bit prefixing? */ X if (a == ebq) { /* Yes, have 8th-bit prefix? */ X b8 = 128; /* Yes, remember bit 8 on */ X a = *rdatap++; /* and get following character. */ X } X } X if (a == rctlq) { /* Is it control prefix? */ X a = *rdatap++; /* Yes, get next character */ X a7 = a & 127; /* and its low 7 bits. */ X if (a7 > 62 && a7 < 96) /* Encoded control character? */ X a = ctl(a); /* Yes, controllify */ X } X a |= b8; /* OR in the 8th bit. */ X for (; rpt > 0; rpt--) X if (pnchar(a) < 0) return -1; /* Output the character. */ X } X return(0); X} X Xstatic Xpnchar(c) int c; { /* Put next character. */ X if (xflag) { /* To screen if desired. */ X tchar(c); X return(1); X } else if (osp) { /* Or to string in memory... */ X *osp++ = c; X return(1); X } else return(zputc(c,text)); /* Otherwise to file. */ X} X Xstatic Xencstr(s) char *s; { /* Fill a packet from the string */ X first = 1; /* Start lookahead. */ X isp = s; /* Set input string pointer */ X (void) getpkt(spsiz); /* Fill a packet */ X isp = NULL; /* Reset input string pointer */ X return(size); /* Return data field length */ X} X Xstatic void Xdecstr(s) char *s; { /* Decode packet data into a string */ X osp = s; /* Set output string pointer */ X (void) decode(); /* Decode the string */ X *osp = '\0'; /* Terminate the string */ X osp = NULL; /* Reset output string pointer */ X} X Xstatic void Xspar(s) char *s; { /* Set parameters */ X int x; X X s--; /* Line up with field numbers. */ X X /* Limit on size of outbound packets */ X x = (rln >= 1) ? unchar(s[1]) : 80; X spsiz = (x < 10) ? 80 : x; X X /* Timeout on inbound packets */ X x = (rln >= 2) ? unchar(s[2]) : 5; X stimo = (x < 0) ? 5 : x; X X X /* Outbound padding */ X spadn = 0; spadc = '\0'; X if (rln >= 3) { X spadn = unchar(s[3]); X if (rln >= 4) X spadc = ctl(s[4]); X } X X /* Outbound packet terminator */ X seol = (rln >= 5) ? unchar(s[5]) : '\r'; X if (seol < 2 || seol > 31) seol = '\r'; X X /* Control prefix */ X x = (rln >= 6) ? s[6] : '#'; X rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#'; X X /* 8th-bit quoting */ X rq = (rln >= 7) ? s[7] : 0; X if (rq == 'Y') rqf = 1; X else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2; X else rqf = 0; X X switch (rqf) { X case 0: ebqflg = 0; break; X case 1: if (parity) { ebqflg = 1; ebq = '&'; } break; X case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq; X } X X /* Block check */ X x = 1; X if (rln >= 8) { X x = s[8] - '0'; X if (x < 1 || x > 3) x = 1; X } X bctr = x; X X /* Repeat prefix */ X if (rln >= 9) { X rptq = s[9]; X rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127)); X } else rptflg = 0; X X /* Capabilities */ X atcapu = lpcapu = swcapu = 0; /* No capabilities by default */ X if (rln >= 10) { X x = unchar(s[10]); X atcapu = (x & atcapb) && atcapr; /* Attribute packets */ X lpcapu = (x & lpcapb) && lpcapr; /* Long packets */ X swcapu = (x & swcapb) && swcapr; /* Sliding windows */ X for (capas = 10; (unchar(s[capas]) & 1) && (rln >= capas); capas++) X ; /* Skip to capas + 1 */ X } X X /* Long packets */ X if (lpcapu) { /* Flag set above */ X if (rln > capas+2) { X x = unchar(s[capas+2]) * 95 + unchar(s[capas+3]); X spsiz = x > MAXSP ? MAXSP : x; X } X /* else a fatal error, but how do we terminate? */ X } X X /* Sliding windows */ X if (swcapu) { X if (rln > capas+1) { X x = unchar(s[capas+1]); X wsize = x > MAXWS ? MAXWS : x; X } else X wsize = 1; X } X} X X/* Fill the array with my send-init parameters */ X Xstatic char * Xrpar() { X data[1] = tochar(DRPSIZ); /* Biggest packet I can receive */ X data[2] = tochar(rtimo); /* When I want to be timed out */ X data[3] = tochar(rpadn); /* How much padding I need */ X data[4] = ctl(rpadc); /* Padding character I want */ X data[5] = tochar(reol); /* End-of-Line character I want */ X data[6] = sctlq; /* Control-Quote character I send */ X switch(rqf) { /* 8th-bit prefix */ X case -1: X case 1: if (parity) ebq = sq = '&'; break; X case 0: X case 2: break; X } X data[7] = sq; X data[8] = bctr + '0'; /* Block Check Type */ X if (rptflg) data[9] = rptq; else data[9] = '~'; X data[10] = tochar(atcapr?atcapb:0 | lpcapr?lpcapb:0 | swcapr?swcapb:0); X capas = 10; X data[capas+1] = tochar(swcapr ? wsize : 0); /* Window size */ X data[capas+2] = tochar(rpsiz / 95); /* Long packet size */ X data[capas+3] = tochar(rpsiz % 95); /* ... */ X data[capas+4] = '\0'; X return(data+1); /* Return a pointer to the string */ X} X X/* X * proto()--Kermit protocol entry point. Set your start state and call X * this, NOT wart(). Modified to set long packets capability on the X * basis of the packet size set in the external user interface. X */ Xvoid Xproto() X{ X void *malloc(); X X sndpkt = (char *) malloc((unsigned) (MAXSP+200)); X rcvpkt = (char *) malloc((unsigned) (MAXRP+100)); X data = (char *) malloc((unsigned) (MAXSP+1)); X if (urpsiz > 94) { /* Long packets? */ X rpsiz = (urpsiz > MAXRP - 20 ? MAXRP - 20 : urpsiz); X lpcapr = 1; /* Request long packets */ X bctr = 3; /* And 16 bit CRC's */ X } else { /* No long packets */ X lpcapr = 0; X bctr = 1; /* Drop back to type 1 */ X if (urpsiz < 10) /* Too small? */ X rpsiz = 80; X else X rpsiz = DRPSIZ; X } X cx = cz = 0; /* Haven't aborted yet */ X if (sndpkt == NULL || rcvpkt == NULL || data == NULL) X tmsgl("Can't allocate memory for Kermit!!"); X else X wart(); X if (sndpkt) free(sndpkt); X if (rcvpkt) free(rcvpkt); X if (data) free(data); X} X X/* X * That ends the system-independent Kermit modules. What follows X * are the system-dependent ones. X */ X X/* X * Now for the file routines. I chose to use the z...() routines X * written in terms of stdio. X */ X X#include <stdio.h> X Xstatic FILE *ifp = NULL, *ofp = NULL; X Xstatic Xzopeni(name) char *name; { X ifp = fopen(name, "r"); X if (ifp == NULL) X return -1; X else X return 0; X} X Xstatic Xzopeno(name) char *name; { X ofp = fopen(name, "w"); X if (ofp == NULL) X return -1; X else X return 0; X} X Xstatic Xzclosi() { X int x; X X if (ifp == NULL) X return 0; X x = fclose(ifp); X ifp = NULL; X if (x < 0) X return -1; X else X return 0; X} X Xstatic Xzcloso(discard) int discard; { X int x; X X if (ofp == NULL) X return 0; X x = fclose(ofp); X ofp = NULL; X if (x < 0) X return -1; X else if (discard) X if (unlink(filnam) < 0) X return -1; X return 0; X} X X#include <ctype.h> X Xextern int convert; /* 0 for literal files, 1 for translate */ X Xstatic void Xzrtol(s1,s2,warn) char *s1, *s2; int warn; { X strcpy(s2,s1); /* for now */ X if (convert) X while (*s2 != '\0') { X if (isalpha(*s2)) X *s2 = tolower(*s2); X s2++; X } X} X Xstatic void Xzltor(s1,s2) char *s1, *s2; { X char dotseen = 0; X X if (!convert) X strcpy(s2, s1); X else { X while (*s1 != '\0') { X if (islower(*s1)) X *s2 = toupper(*s1); X else if (isalnum(*s1)) X *s2 = *s1; X else if (*s1 == '.') X if (!dotseen) { X dotseen = 1; X *s2 = *s1; X } else X *s2 = 'X'; X /* else a character we're not prepared to handle. */ X s1++; s2++; X } X *s2 = '\0'; X } X} X X/* X * System-dependent function to return next character from file. X * If the text flag argument is nonzero, first convert to canonic form. X */ Xstatic Xzgetc(text) { /* Get next char from file. */ X#define MAXREC 100 /* Size of record buffer. */ X X static char recbuf[MAXREC + 1]; /* Big enough for MAXREC newlines */ X static char *rbp; /* Buffer pointer */ X static int i = 0; /* Buffer char counter */ X int c; X X if (i == 0) { /* If the buffer is empty, */ X /* read next line from file. */ X for (i = 0; X i < MAXREC - 1 && (c = getc(ifp)) != EOF && c != '\n'; X i++) X recbuf[i] = c; X if (c == '\n') { /* Got newline */ X if (text) { /* If in text mode */ X recbuf[i++] = '\r'; /* Substitute CRLF */ X } X recbuf[i++] = c; X } X recbuf[i] = '\0'; /* Done, terminate buffer */ X if (i == 0) return -1; /* If empty, indicate EOF */ X rbp = recbuf; /* Remember position for next time */ X } X i--; /* Adjust the counter. */ X return(*rbp++ & 0377); /* Return hext character */ X} X Xstatic Xzputc(c, text) int c, text; { /* Put character in file. */ X unsigned int x; X X c &= 255; /* Undo any sign extension */ X if (text && c == '\r') /* If in text mode, */ X return 0; /* eliminate carriage returns. */ X else { /* Otherwise, */ X x = putc(c, ofp) & 255; /* output the character. */ X if (c == 255) return 0; /* Special handling for all 1's */ X return ((x != c) ? -1 : 0); /* Normal return code. */ X } X} SHAR_EOF echo "End of archive 6 (of 9)" # if you want to concatenate archives, remove anything after this line exit