/************************************************************* * vt100 terminal emulator - KERMIT protocol support * v1.0 DBW 860622 Dave Wecker *************************************************************/ #define MODULE_KERMIT 1 #include "vt100.h" #define MAXPACKSIZ 94 /* Maximum msgpkt size */ #define SOH 1 /* Start of header */ #define CR 13 /* ASCII Carriage Return */ #define LF 10 /* ASCII line feed */ #define SP 32 /* ASCII space */ #define DEL 127 /* Delete (rubout) */ #define MAXTRY 10 /* Times to retry a msgpkt */ #define MYQUOTE '#' /* Quote character I will use */ #define MYRPTQ '~' /* Repeat quote character */ #define MYPAD 0 /* Number of padding characters I will need */ #define MYPCHAR 0 /* Padding character I need (NULL) */ #define MYEOL '\n' /* End-Of-Line character I need */ #define MYTIME 10 /* Seconds after which I should be timed out */ #define MAXTIM 60 /* Maximum timeout interval */ #define MINTIM 2 /* Minumum timeout interval */ #define tochar(ch) ((ch) + ' ') #define unchar(ch) ((ch) - ' ') #define ctl(ch) ((ch) ^ 64 ) /* Global Variables */ short 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 */ numtry, /* Times this msgpkt retried */ oldtry, /* Times previous msgpkt retried */ rptflg, /* are we doing repeat quoting */ first, /* is this the first time in a file */ rpt; /* current repeat count */ char next, /* what is the next character */ t, /* current character */ 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 */ ackpkt[MAXPACKSIZ+10], /* ACK/NAK packet buffer */ msgpkt[MAXPACKSIZ+10], /* Message Packet buffer */ filnam[40]; /* remote file name */ FILE *fp; /* file for send/receive */ doksend(file) char *file; { short retval; if ((fp = fopen(file,"r")) == NULL) { emits("Cannot open send file\n"); return FALSE; } emits("Remote file name [local name]: "); filename(filnam); if (filnam[0] == 0) strcpy(filnam,file); timeout = FALSE; emits("\nType to abort transfer\n"); retval = sendsw(); emits("\n"); fclose(fp); return(retval); } dokreceive(file) char *file; { short retval; if ((fp = fopen(file,"w")) == NULL) { emits("Cannot open file\n"); return FALSE; } emits("Remote file name [local name]: "); filename(filnam); if (filnam[0] == 0) strcpy(filnam,file); timeout = FALSE; emits("\nType to abort transfer\n"); retval = recsw(); emits("\n"); fclose(fp); return(retval); } sendsw() { char sinit(), sfile(), sdata(), seof(), sbreak(); state = 'S'; n = 0; numtry = 0; 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': state = sbreak(); break; case 'C': return(TRUE); case 'A': return(FALSE); default: return(FALSE); } } } char sinit() { int num, len; if (numtry++ > MAXTRY) return('A'); spar(msgpkt); spack('S',n,9,msgpkt); switch(rpack(&len,&num,ackpkt)) { case 'N': return(state); case 'Y': if (n != num) return(state); rpar(ackpkt); if (eol == 0) eol = '\n'; if (quote == 0) quote = '#'; numtry = 0; n = (n+1)%64; return('F'); case 'E': return('A'); case FALSE:return(state); default: return('A'); } } char sfile() { int num, len; 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; n = (n+1)%64; first = 1; size = getpkt(); return('D'); case 'E': return('A'); case FALSE: return(state); default: return('A'); } } char sdata() { int num, len; 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; n = (n+1)%64; if ((size = getpkt()) == 0) return('Z'); return('D'); case 'E': return('A'); case FALSE: return(state); default: return('A'); } } char seof() { int num, len; if (numtry++ > MAXTRY) return('A'); spack('Z',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); numtry = 0; n = (n+1)%64; return('B'); case 'E': return('A'); case FALSE: return(state); default: return('A'); } } char sbreak() { int num, len; 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); numtry = 0; n = (n+1)%64; return('C'); case 'E': return('A'); case FALSE: return(state); default: return ('A'); } } recsw() { char rinit(), rfile(), rdata(); state = 'R'; n = 0; numtry = 0; while(TRUE) { switch(state) { case 'R': state = rinit(); break; case 'F': state = rfile(); break; case 'D': state = rdata(); break; case 'C': return(TRUE); case 'A': return(FALSE); } } } char rinit() { int len, num; if (numtry++ > MAXTRY) return('A'); spack('R',n,strlen(filnam),filnam); switch(rpack(&len,&num,msgpkt)) { case 'S': rpar(msgpkt); spar(msgpkt); spack('Y',n,9,msgpkt); oldtry = numtry; numtry = 0; n = (n+1)%64; return('F'); case 'E': return('A'); case FALSE: spack('N',n,0,0); return(state); default: return('A'); } } char rfile() { int num, len; if (numtry++ > MAXTRY) return('A'); switch(rpack(&len,&num,msgpkt)) { case 'S': if (oldtry++ > MAXTRY) return('A'); if (num == ((n==0) ? 63:n-1)) { spar(msgpkt); spack('Y',num,9,msgpkt); 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,0); numtry = 0; return(state); } else return('A'); case 'F': if (num != n) return('A'); spack('Y',n,0,0); oldtry = numtry; numtry = 0; n = (n+1)%64; return('D'); case 'B': if (num != n) return ('A'); spack('Y',n,0,0); return('C'); case 'E': return('A'); case FALSE: spack('N',n,0,0); return(state); default: return ('A'); } } char rdata() { int num, len; 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,0); oldtry = numtry; numtry = 0; n = (n+1)%64; return('D'); case 'F': if (oldtry++ > MAXTRY) return('A'); if (num == ((n==0) ? 63:n-1)) { spack('Y',num,0,0); numtry = 0; return(state); } else return('A'); case 'Z': if (num != n) return('A'); spack('Y',n,0,0); n = (n+1)%64; return('C'); case 'E': return('A'); case FALSE: spack('N',n,0,0); return(state); default: return('A'); } } spack(type,num,len,data) char type, *data; short num, len; { short i; char chksum, buffer[100]; register char *bufp; if (type != 'Y' && type != 'N') { if (num == 0) emits("\n"); emit(type); } bufp = buffer; for (i=1; i<=pad; i++) sendchar(padchar); *bufp++ = SOH; *bufp++ = tochar(len+3); chksum = tochar(len+3); *bufp++ = tochar(num); chksum += tochar(num); *bufp++ = type; chksum += type; for (i=0; i> 6)+chksum)&077; *bufp++ = tochar(chksum); *bufp++ = '\r'; *bufp++ = '\n'; *bufp = 0; sendstring(buffer); } rpack(len,num,data) short *len, *num; char *data; { short i, done; char t, type, cchksum, rchksum; while (t != SOH) { t = readchar(); if (timeout) return(FALSE); } done = FALSE; while (!done) { t = readchar(); if (timeout) return(FALSE); if (t == SOH) continue; cchksum = t; *len = unchar(t)-3; t = readchar(); if (timeout) return(FALSE); if (t == SOH) continue; cchksum = cchksum + t; *num = unchar(t); t = readchar(); if (timeout) return(FALSE); if (t == SOH) continue; cchksum = cchksum + t; type = t; for (i=0; i<*len; i++) { t = readchar(); if (timeout) return(FALSE); if (t == SOH) continue; cchksum = cchksum + t; data[i] = t; } data[*len] = 0; t = readchar(); if (timeout) return(FALSE); rchksum = unchar(t); t = readchar(); if (timeout) return(FALSE); if (t == SOH) continue; done = TRUE; } if (type != 'Y' && type != 'N') { if (*num == 0) emits("\n"); emit(type); } cchksum = (((cchksum&0300) >> 6)+cchksum)&077; if (cchksum != rchksum) return(FALSE); return(type); } getpkt() { short i,eof; static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' }; if (first == 1) { first = 0; *leftover = '\0'; t = getc(fp); if (t == EOF) { first = 1; return(size = 0); } } 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; } 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); } encode(a) char a; { short a7,b8; if ((!imagemode) && a == '\n') { rpt = 0; msgpkt[size++] = quote; msgpkt[size++] = ctl('\r'); if (size <= spsiz-3) osize = size; msgpkt[size++] = quote; msgpkt[size++] = ctl('\n'); 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 ((a7 < SP) || (a7==DEL)) { msgpkt[size++] = quote; a = ctl(a); } if (a7 == quote) msgpkt[size++] = quote; if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote; msgpkt[size++] = a; msgpkt[size] = '\0'; } decode() { USHORT a, a7, b8; char *buf; buf = msgpkt; rpt = 0; while ((a = *buf++) != '\0') { if (rptflg) { if (a == rptq) { rpt = unchar(*buf++); a = *buf++; } } if (a == quote) { a = *buf++; a7 = a & 0177; if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a); } if (rpt == 0) rpt = 1; if ((!imagemode) && a == '\r') continue; for (; rpt > 0; rpt--) putc(a, fp); } return(0); } spar(data) char data[]; { data[0] = tochar(MAXPACKSIZ); data[1] = tochar(MYTIME); data[2] = tochar(MYPAD); data[3] = ctl(MYPCHAR); data[4] = tochar(MYEOL); data[5] = MYQUOTE; data[6] = 'N'; data[7] = '1'; data[8] = MYRPTQ; data[9] = '\0'; } rpar(data) char data[]; { spsiz = unchar(data[0]); timint = unchar(data[1]); pad = unchar(data[2]); padchar = ctl(data[3]); eol = unchar(data[4]); quote = data[5]; rptflg = 0; if (data[6] == 0) return; if (data[7] == 0) return; if (data[8] == 0) return; rptq = data[8]; rptflg = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177)); }