<<< accfn2.c >>> /* C K C F N 2 -- System-independent Kermit protocol support functions... */ /* ...Part 2 (continued from ckcfns.c) */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Note -- if you change this file, please amend the version number and date at the top of ckcfns.c accordingly. */ #include "ckcker.h" #include "ckcdeb.h" extern int spsiz, rpsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas; extern int pktnum, prvpkt, sndtyp, bctr, bctu, size, osize, maxsize, spktl, nfils, stdouf, warn, timef; extern int parity, speed, turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn; extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize; extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; extern char padch, mypadc, eol, seol, ctlq, myctlq, sstate, *hlptxt; extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, mystch; extern char *cmarg, *cmarg2, **cmlist; char *strcpy(); /* I N P U T -- Attempt to read packet number 'pktnum'. */ /* This is the function that feeds input to Kermit's finite state machine. If a special start state is in effect, that state is returned as if it were the type of an incoming packet. Otherwise: . If the desired packet arrives within MAXTRY tries, return its type, with its data stored in the global 'data' array. . If the previous packet arrives again, resend the last packet and wait for another to come in. . If the desired packet does not arrive within MAXTRY tries, return indicating that an error packet should be sent. */ input() { int len, num, type, numtry; if (sstate != 0) { /* If a start state is in effect, */ type = sstate; /* return it like a packet type, */ sstate = 0; /* and then nullify it. */ *data = '\0'; return(type); } else type = rpack(&len,&num,data); /* Else, try to read a packet. */ /* If it's the same packet we just sent, it's an echo. Read another. */ if (type == sndtyp) type = rpack(&len,&num,data); chkint(); /* Check for console interrupts. */ /* If previous packet again, a timeout pseudopacket, or a bad packet, try again. */ for (numtry = 0; (num == prvpkt || type == 'T' || type == 'Q' || type == 'N'); numtry++) { if (numtry > MAXTRY) { /* If too many tries, give up */ strcpy(data,"Timed out."); /* and send a timeout error packet. */ return('E'); } resend(); /* Else, send last packet again, */ if (sstate != 0) { /* If an interrupt routine has set */ type = sstate; /* sstate behind our back, return */ sstate = 0; /* that. */ *data = '\0'; return(type); } else type = rpack(&len,&num,data); /* Else, try to read a packet. */ chkint(); /* Look again for interruptions. */ if (type == sndtyp) type = rpack(&len,&num,data); } return(type); /* Success, return packet type. */ } /* S P A C K -- Construct and send a packet */ spack(type,num,len,dat) char type, *dat; int num, len; { int i,j; j = dopar(padch); for (i = 0; i < npad; sndpkt[i++] = j); /* Do any requested padding */ sndpkt[i++] = dopar(mystch); /* Start packet with the start char */ sndpkt[i++] = dopar(tochar(len+bctu+2)); /* Put in the length */ sndpkt[i++] = dopar(tochar(num)); /* The packet number */ sndpkt[i++] = sndtyp = dopar(type); /* Packet type */ for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */ sndpkt[i] = '\0'; /* Mark end for block check */ switch(bctu) { case 1: /* Type 1 - 6 bit checksum */ sndpkt[i++] = dopar(tochar(chk1(sndpkt+1+npad))); break; case 2: /* Type 2 - 12 bit checksum*/ j = chk2(sndpkt+1+1); sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); sndpkt[i++] = dopar(tochar(j & 077)); break; case 3: /* Type 3 - 16 bit CRC-CCITT */ j = chk3(sndpkt+1+npad); sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12)); sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); sndpkt[i++] = dopar(tochar(j & 077)); break; } sndpkt[i++] = dopar(seol); /* EOL character */ sndpkt[i] = '\0'; /* End of the packet */ ttol(sndpkt,spktl=i); /* Send the packet just built */ flco += spktl; /* Count the characters */ tlco += spktl; if (pktlog) zsoutl(ZPFILE,sndpkt); /* If logging packets, log it */ screen(SCR_PT,type,(long)num,sndpkt); /* Update screen */ } /* D O P A R -- Add an appropriate parity bit to a character */ dopar (ch) char ch; { int a; switch (parity) { case 'm': return(ch | 128); /* Mark */ case 's': return(ch & 127); /* Space */ case 'o': ch |= 128; /* Odd (fall thru) */ case 'e': /* Even */ a = (ch & 15) ^ ((ch >> 4) & 15); a = (a & 3) ^ ((a >> 2) & 3); a = (a & 1) ^ ((a >> 1) & 1); return(ch | (a << 7)); default: return(ch); } } /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ chk1(pkt) char *pkt; { int chk; chk = chk2(pkt); return((((chk & 0300) >> 6) + chk) & 077); } /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ chk2(pkt) char *pkt; { unsigned int chk; int p; for (chk = 0; *pkt != '\0'; *pkt++) { p = (parity) ? *pkt & 0177 : *pkt; chk += p; } return(chk); } /* C H K 3 -- Compute a type-3 Kermit block check. */ /* Calculate the 16-bit CRC of a null-terminated string using a byte-oriented tableless algorithm invented by Andy Lowry (Columbia University). The magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1. Note - this function could be adapted for strings containing imbedded 0's by including a length argument. */ chk3(s) char *s; { unsigned int c, q; LONG crc = 0; while ((c = *s++) != '\0') { if (parity) c &= 0177; q = (crc ^ c) & 017; /* Low-order nibble */ crc = (crc >> 4) ^ (q * 010201); q = (crc ^ (c >> 4)) & 017; /* High order nibble */ crc = (crc >> 4) ^ (q * 010201); } return(crc); } /* Functions for sending various kinds of packets */ ack() { /* Send an ordinary acknowledgment. */ spack('Y',pktnum,0,""); /* No data. */ nxtpkt(&pktnum); /* Increment the packet number. */ } /* Note, only call this once! */ ack1(s) char *s; { /* Send an ACK with data. */ spack('Y',pktnum,strlen(s),s); /* Send the packet. */ nxtpkt(&pktnum); /* Increment the packet number. */ } /* Only call this once! */ nack() { /* Negative acknowledgment. */ spack('N',pktnum,0,""); /* NAK's never have data. */ } resend() { /* Send the old packet again. */ int w; for (w = 0; w < timint - 2; w++) { /* Be extra sure no stuff is */ ttflui(); /* still coming in. */ sleep(1); if (!ttchk() ) ttinc(1); /* be extra sure no stuff in SIII/V */ if (!ttchk() ) break; } if (*sndpkt) ttol(sndpkt,spktl); /* Resend if buffer not empty */ screen(SCR_PT,'%',(long)pktnum,sndpkt); /* Display that resend occurred */ if (pktlog && *sndpkt) zsoutl(ZPFILE,sndpkt); /* Log packet if desired */ } errpkt(reason) char *reason; { /* Send an error packet. */ encstr(reason); spack('E',pktnum,size,data); screen(SCR_TC,0,0l,""); } scmd(t,dat) char t, *dat; { /* Send a packet of the given type */ encstr(dat); /* Encode the command string */ spack(t,pktnum,size,data); } srinit() { /* Send R (GET) packet */ encstr(cmarg); /* Encode the filename. */ spack('R',pktnum,size,data); /* Send the packet. */ } nxtpkt(num) int *num; { prvpkt = *num; /* Save previous */ *num = (*num + 1) % 64; /* Increment packet number mod 64 */ } sigint() { /* Terminal interrupt handler */ errpkt("User typed "); doexit(GOOD_EXIT); /* Exit program */ } /* R P A C K -- Read a Packet */ rpack(l,n,dat) int *l, *n; char *dat; { int i, j, x, done, pstart, pbl; char chk[4], xchk[4], t, type; chk[3] = xchk[3] = 0; i = inlin(); /* Read a line */ if (i != 0) { debug(F101,"rpack: inlin","",i); screen(SCR_PT,'T',(long)pktnum,""); return('T'); } debug(F110,"rpack: inlin ok, recpkt",recpkt,0); /* Look for start of packet */ for (i = 0; ((t = recpkt[i]) != stchr) && (i < RBUFL) ; i++); if (++i >= RBUFL) return('Q'); /* Skip rest if not found */ /* now "parse" the packet */ debug(F101,"entering rpack with i","",i); done = 0; while (!done) { debug(F101,"rpack starting at i","",i); pstart = i; /* remember where packet started */ /* length */ if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */ if (t == eol) return('Q'); *l = unchar(t); /* Packet length */ debug(F101," pkt len","",*l); /* sequence number */ if ((t = recpkt[i++]) == stchr) continue; if (t == eol) return('Q'); *n = unchar(t); debug(F101,"rpack: n","",*n); /* type */ if ((type = recpkt[i++]) == stchr) continue; if (type == eol) return('Q'); debug(F101,"rpack: type","",type); if ((type == 'S') || (type == 'I')) pbl = 1; /* Heuristics for */ else if (type == 'N') pbl = *l - 2; /* syncing block check type */ else pbl = bctu; *l -= (pbl + 2); /* Now compute data length */ debug(F101,"rpack: bctu","",bctu); debug(F101," pbl","",pbl); debug(F101," data length","",*l); /* data */ dat[0] = '\0'; /* Return null string if no data */ for (j=0; j<*l; i++,j++) if ((dat[j] = recpkt[i]) == stchr) continue; else if (dat[j] == eol) return('Q'); dat[j] = '\0'; /* get the block check */ debug(F110," packet chk",recpkt+i,0); for (j = 0; j < pbl; j++) { chk[j] = recpkt[i]; debug(F101," chk[j]","",chk[j]); if (chk[j] == stchr) break; if (chk[j] == eol) return('Q'); recpkt[i++] = '\0'; } chk[j] = 0; debug(F111," chk array, j",chk,j); if (j != pbl) continue; /* Block check right length? */ done = 1; /* Yes, done. */ } /* Got packet, now check the block check */ switch (pbl) { case 1: xchk[0] = tochar(chk1(&recpkt[pstart])); if (chk[0] != xchk[0]) { if (deblog) { debug(F000,"rpack: chk","",chk[0]); debug(F000," should be ","",xchk[0]); } screen(SCR_PT,'Q',(long)n,recpkt); return('Q'); } break; case 2: x = chk2(&recpkt[pstart]); xchk[0] = tochar((x & 07700) >> 6); xchk[1] = tochar(x & 077); if (deblog) { debug(F000," xchk[0]","=",xchk[0]); debug(F000," xchk[1]","=",xchk[1]); } if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) { debug(F100," bct2's don't compare","",0); screen(SCR_PT,'Q',(long)n,recpkt); return('Q'); } break; case 3: x = chk3(&recpkt[pstart]); xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12); xchk[1] = tochar((x & 07700) >> 6); xchk[2] = tochar(x & 077); if (deblog) { debug(F000," xchk[0]","=",xchk[0]); debug(F000," xchk[1]","=",xchk[1]); debug(F000," xchk[2]","=",xchk[2]); } if ((xchk[0] != chk[0]) || (xchk[1] != chk[1]) || (xchk[2] != chk[2])) { debug(F100," bct3's don't compare","",0); screen(SCR_PT,'Q',(long)n,recpkt); return('Q'); } break; } /* Good packet, return its type */ ttflui(); /* Done, flush any remaining. */ screen(SCR_PT,type,(long)(*n),recpkt); /* Update screen */ return(type); } /* I N C H R -- Input character from communication line, with timeout */ inchr(timo) int timo; { int c; c = ttinc(timo); debug(F101,"inchr ttinc","",c); if (c < 0) return(c); /* Get a character */ if (parity) c = c & 0177; /* If parity on, discard parity bit.*/ debug(F101," after parity","",c); return(c); } /* I N L I N -- Input a line (up to break char) from communication line */ /* Returns 0 on success, nonzero on failure */ inlin() { int i, j, k, maxt; CHAR e; maxt = (speed >= 110) ? (MAXTRY * 9600 / speed) : MAXTRY; debug(F101,"inlin: speed","",speed); debug(F101," maxt","",maxt); e = (turn) ? turnch : eol; i = j = k = 0; if (parity) { while ((j != e) && (i < RBUFL) && (k < maxt)) { j = inchr(1); /* Get char, 1 second timeout */ debug(F101,"inlin inchr","",j); if (j < 0) k++; /* Timed out. */ else { if (j) recpkt[i++] = j; /* Save it */ k = 0; /* Reset timeout counter. */ } } } else { i = ttinl(recpkt,RBUFL,timint,e); /* Get them all at once */ if (i < 0) k = 1; } recpkt[i] = '\0'; /* Terminate near end of packet */ debug(F111,"inlin",recpkt,i); /* Debug report... */ debug(F101," timeouts","",k); if (i < 1) return(1); /* No characters, return. */ if (pktlog) zsoutl(ZPFILE,recpkt); /* Log any we got, if logging. */ if (k > maxt) return(1); /* If too many tries, give up. */ tlci += i; /* All OK, Count the characters. */ flci += i; return(0); } <<< accfns.c >>> char *fnsv = "Panos-Kermit functions (based on C-Kermit 4C(039)) 19 Dec 85"; /* C K C F N S -- System-independent Kermit protocol support functions. */ /* ...Part 1 (others moved to ckcfn2 to make this module small enough) */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* System-dependent primitives defined in: ck?tio.c -- terminal i/o cx?fio.c -- file i/o, directory structure */ #include "ckcker.h" /* Symbol definitions for Kermit */ #include "ckcdeb.h" /* Debug formats, typedefs, etc. */ #ifndef NULL #define NULL 0 #endif /* Externals from ckcmai.c */ extern int spsiz, rpsiz, timint, rtimo, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas; extern int pktnum, prvpkt, sndtyp, bctr, bctu, size, osize, maxsize, spktl, nfils, stdouf, warn, timef; extern int parity, speed, turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn; extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize; extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; extern char padch, mypadc, eol, ctlq, myctlq, sstate, *hlptxt; extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, mystch; extern char *cmarg, *cmarg2, **cmlist; long zchki(); char *strcpy(); /* Variables local to this module */ static char *memptr; /* Pointer for memory strings */ static char cmdstr[100]; /* Unix system command string */ static int sndsrc; /* Flag for where to send from: */ /* -1: name in cmdata */ /* 0: stdin */ /* >0: list in cmlist */ static int memstr, /* Flag for input from memory str. */ t, /* Current character */ next; /* Next character */ /* E N C S T R -- Encode a string from memory. */ /* Call this instead of getpkt() if source is a string, rather than a file */ encstr(s) char* s; { int m; char *p; m = memstr; p = memptr; /* Save these. */ memptr = s; /* Point to the string. */ memstr = 1; /* Flag memory string as source. */ next = -1; /* Initialize character lookahead. */ getpkt(spsiz); /* Fill a packet from the string. */ memstr = m; /* Restore memory string flag */ memptr = p; /* and pointer */ next = -1; /* Put this back as we found it. */ } /* E N C O D E - Kermit packet encoding procedure */ encode(a) int a; { /* The current character */ int a7; /* Low order 7 bits of character */ int b8; /* 8th bit of character */ if (rptflg) { /* Repeat processing? */ if (a == next) { /* Got a run... */ if (++rpt < 94) /* Below max, just count */ return; else if (rpt == 94) { /* Reached max, must dump */ data[size++] = rptq; data[size++] = tochar(rpt); rpt = 0; } } else if (rpt == 1) { /* Run broken, only 2? */ rpt = 0; /* Yes, reset repeat flag & count. */ encode(a); /* Do the character twice. */ if (size <= maxsize) osize = size; rpt = 0; encode(a); return; } else if (rpt > 1) { /* More than two */ data[size++] = rptq; /* Insert the repeat prefix */ data[size++] = tochar(++rpt); /* and count. */ rpt = 0; /* Reset repeat counter. */ } } a7 = a & 0177; /* Isolate ASCII part */ b8 = a & 0200; /* and 8th (parity) bit. */ if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */ data[size++] = ebq; a = a7; } if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */ data[size++] = myctlq; a = ctl(a); } if (a7 == myctlq) /* Prefix the control prefix */ data[size++] = myctlq; if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ data[size++] = myctlq; /* quote it if doing repeat counts. */ if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */ data[size++] = myctlq; /* if doing 8th-bit prefixes */ data[size++] = a; /* Finally, insert the character */ data[size] = '\0'; /* itself, and mark the end. */ } /* D E C O D E -- Kermit packet decoding procedure */ /* Call with string to be decoded and an output function. */ /* Returns 0 on success, -1 on failure (e.g. disk full). */ decode(buf,fn) char *buf; int (*fn)(); { unsigned int a, a7, b8; /* Low order 7 bits and the 8th bit */ rpt = 0; /* Initialize repeat count. */ while ((a = *buf++) != '\0') { if (rptflg) { /* Repeat processing? */ if (a == rptq) { /* Yes, got a repeat prefix? */ rpt = unchar(*buf++); /* Yes, get the repeat count, */ a = *buf++; /* and get the prefixed character. */ } } b8 = 0; /* Check high order "8th" bit */ 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 == ctlq) { /* If control prefix, */ a = *buf++; /* get its operand. */ a7 = a & 0177; /* Only look at low 7 bits. */ if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */ a = ctl(a); /* if in control range. */ } a |= b8; /* OR in the 8th bit */ if (rpt == 0) rpt = 1; /* If no repeats, then one */ #ifdef NLCHAR if (!binary) { /* If in text mode, */ if (a == CR) continue; /* discard carriage returns, */ if (a == LF) a = NLCHAR; /* convert LF to system's newline. */ } #endif for (; rpt > 0; rpt--) { /* Output the char RPT times */ ffc++, tfc++; /* Count the character */ if ((*fn)(a) < 0) return(-1); /* Send it to the output fn. */ } } return(0); } /* Output functions passed to 'decode': */ putsrv(c) char c; { /* Put character in server command buffer */ *srvptr++ = c; *srvptr = '\0'; /* Make sure buffer is null-terminated */ return(0); } puttrm(c) char c; { /* Output character to console. */ conoc(c); return(0); } putfil(c) char c; { /* Output char to file. */ if (zchout(ZOFILE,c) < 0) { czseen = 1; /* If write error... */ debug(F101,"putfil zchout write error, setting czseen","",1); return(-1); } return(0); } /* G E T P K T -- Fill a packet data field */ /* Gets characters from the current source -- file or memory string. Encodes the data into the packet, filling the packet optimally. Uses global variables: t -- current character. next -- next character. data -- the packet data buffer. size -- number of characters in the data buffer. Returns the size as value of the function, and also sets global size, and fills (and null-terminates) the global data array. Before calling getpkt the first time for a given source (file or string), set the variable 'next' to -1. */ getpkt(maxsize) int maxsize; { /* Fill one packet buffer */ int i; /* Loop index. */ static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' }; debug(F101,"getpkt, entering with next","",next); debug(F101," t","",t); if (next < 0) { /* If first time through, */ t = getch(); /* get first character of file, */ *leftover = '\0'; /* discard any interrupted leftovers. */ } /* Do any leftovers */ for (size = 0; (data[size] = leftover[size]) != '\0'; size++); *leftover = '\0'; /* Now fill up the rest of the packet. */ rpt = 0; /* Clear out any old repeat count. */ while(t >= 0) { /* Until EOF... */ next = getch(); /* Get next character for lookahead.*/ osize = size; /* Remember current position. */ encode(t); /* Encode the current character. */ t = next; /* Next is now current. */ next = 0; /* No more next. */ if (size == maxsize) { /* If the packet is exactly full, */ debug(F101,"getpkt exact fit","",size); return(size); /* and return. */ } if (size > maxsize) { /* If too big, save some for next. */ for (i = 0; (leftover[i] = data[osize+i]) != '\0'; i++); debug(F111,"getpkt leftover",leftover,size); debug(F101," osize","",osize); size = osize; /* Return truncated packet. */ data[size] = '\0'; return(size); } } debug(F101,"getpkt eof/eot","",size); return(size); /* Return any partial final buffer. */ } /* G E T C H -- Get the next character from file (or pipe). */ /* On systems like Unix, the Macintosh, etc, that use a single character (NLCHAR, defined in ckcdeb.h) to separate lines in text files, and when in text/ascii mode (binary == 0), this function maps the newline character to CRLF. If NLCHAR is not defined, then this mapping is not done, even in text mode. */ getch() { /* Get next character */ int x; CHAR a; /* The character to return. */ static int b = 0; /* A character to remember. */ if (b > 0) { /* Do we have a LF saved? */ b = 0; /* Yes, return that. */ return(LF); } if (memstr) /* Try to get the next character */ x = ((a = *memptr++) == '\0'); /* from the appropriate source, */ else /* memory or the current file. */ x = (zchin(ZIFILE,&a) == -1); if (x) return(-1); /* No more, return -1 for EOF. */ else { /* Otherwise, read the next char. */ ffc++, tfc++; /* Count it. */ #ifdef NLCHAR if (!binary && (a == NLCHAR)) { /* If nl and we must do nl-CRLF */ b = 1; /* mapping, remember a linefeed, */ return(CR); /* and return a carriage return. */ } else return(a); /* General case, return the char. */ #else return(a); #endif } } /* C A N N E D -- Check if current file transfer cancelled */ canned(buf) char *buf; { if (*buf == 'X') cxseen = 1; if (*buf == 'Z') czseen = 1; debug(F101,"canned: cxseen","",cxseen); debug(F101," czseen","",czseen); return((czseen || cxseen) ? 1 : 0); } /* T I N I T -- Initialize a transaction */ tinit() { xflg = 0; /* Reset x-packet flag */ memstr = 0; /* Reset memory-string flag */ memptr = NULL; /* and pointer */ bctu = 1; /* Reset block check type to 1 */ filcnt = 0; /* Reset file counter */ tfc = tlci = tlco = 0; /* Reset character counters */ prvpkt = -1; /* Reset packet number */ pktnum = 0; cxseen = czseen = 0; /* Reset interrupt flags */ *filnam = '\0'; /* Clear file name */ if (server) { /* If acting as server, */ timint = 30; /* Use 30 second timeout, */ nack(); /* Send first NAK */ } } /* R I N I T -- Respond to S packet */ rinit(d) char *d; { char *tp; ztime(&tp); tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ tfc = tlci = tlco = 0; spar(d); rpar(d); ack1(d); } /* S I N I T -- Make sure file exists, then send Send-Init packet */ sinit() { int x; char *tp; sndsrc = nfils; /* Where to look for files to send */ ztime(&tp); tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ debug(F101,"sinit: sndsrc","",sndsrc); if (sndsrc < 0) { /* Must expand from 'send' command */ nfils = zxpand(cmarg); /* Look up literal name. */ if (nfils < 0) { screen(SCR_EM,0,0l,"Too many files"); return(0); } else if (nfils == 0) { /* If none found, */ char xname[100]; /* convert the name. */ zrtol(cmarg,xname); nfils = zxpand(xname); /* Look it up again. */ } if (nfils < 1) { /* If no match, report error. */ if (server) errpkt("File not found"); else screen(SCR_EM,0,0l,"File not found"); return(0); } x = gnfile(); /* Position to first file. */ if (x < 1) { if (!server) screen(SCR_EM,0,0l,"No readable file to send"); else errpkt("No readable file to send"); return(0); } } else if (sndsrc > 0) { /* Command line arglist -- */ x = gnfile(); /* Get the first file from it. */ if (x < 1) return(0); /* (if any) */ } else if (sndsrc == 0) { /* stdin or memory always exist... */ cmarg2 = ""; /* No alternate name */ strcpy(filnam,"stdin"); /* If F packet, filnam is used. */ tlog(F110,"Sending from",cmdstr,0l); /* If X packet, cmdstr is used */ } debug(F101,"sinit: nfils","",nfils); debug(F110," filnam",filnam,0); debug(F110," cmdstr",cmdstr,0); ttflui(); /* Flush input buffer. */ x = rpar(data); /* Send a Send-Init packet. */ if (!local && !server) sleep(delay); spack('S',pktnum,x,data); return(1); } sipkt() { int x; ttflui(); /* Flush pending input. */ x = rpar(data); /* Send an I-Packet. */ spack('I',pktnum,x,data); } /* R C V F I L -- Receive a file */ rcvfil() { int x, oldcnv; ffc = flci = flco = 0; /* Init per-file counters */ srvptr = srvcmd; /* Decode file name from packet. */ decode(data,&putsrv); /*BUG - add & */ screen(SCR_FN,0,0l,srvcmd); /* Put it on screen */ tlog(F110,"Receiving",srvcmd,0l); /* Transaction log entry */ oldcnv = fncnv; if (cmarg2 != NULL) { /* Check for alternate name */ if (*cmarg2 != '\0') { fncnv = 0; /* Don't translate filename on open - take the name as supplied verbatim */ strcpy(srvcmd,cmarg2); /* Got one, use it. */ *cmarg2 = '\0'; } } x = openo(srvcmd,filnam); /* Try to open it */ fncnv = oldcnv; if (x) { tlog(F110," as",filnam,0l); screen(SCR_AN,0,0l,filnam); intmsg(++filcnt); } else { tlog(F110,"Failure to open",filnam,0l); screen(SCR_EM,0,0l,"Can't open file"); } return(x); /* Pass on return code from openo */ } /* R E O F -- Receive End Of File */ reof() { if (cxseen == 0) cxseen = (*data == 'D'); clsof(); if (cxseen || czseen) { tlog(F100," *** Discarding","",0l); } else { tlog(F100," end of file","",0l); tlog(F101," file characters ","",ffc); tlog(F101," communication line in ","",flci); tlog(F101," communication line out ","",flco); } } /* R E O T -- Receive End Of Transaction */ reot() { char *tp; cxseen = czseen = 0; ztime(&tp); tlog(F110,"End of transaction",tp,0l); if (filcnt > 1) { tlog(F101," files","",filcnt); tlog(F101," total file characters ","",tfc); tlog(F101," communication line in ","",tlci); tlog(F101," communication line out ","",tlco); } } /* S F I L E -- Send File header packet for global "filnam" */ sfile() { char pktnam[100]; /* Local copy of name */ if (*cmarg2 != '\0') { /* If we have a send-as name, */ strcpy(pktnam,cmarg2); /* copy it literally, */ cmarg2 = ""; /* and blank it out for next time. */ } else { /* Otherwise use actual file name: */ if (fncnv) { /* If converting names, */ zltor(filnam,pktnam); /* convert it to common form, */ } else { /* otherwise, */ strcpy(pktnam,filnam); /* copy it literally. */ } } debug(F110,"sfile",filnam,0); debug(F110," pktnam",pktnam,0); if (openi(filnam) == 0) /* Try to open the file */ return(0); flci = flco = ffc = 0; /* OK, Init counters, etc. */ encstr(pktnam); /* Encode the name. */ nxtpkt(&pktnum); /* Increment the packet number */ ttflui(); /* Clear pending input */ spack('F',pktnum,size,data); /* Send the F packet */ if (displa) { screen(SCR_FN,'F',(long)pktnum,filnam); /* Update screen */ screen(SCR_AN,0,0l,pktnam); screen(SCR_FS,0,(long)fsize,""); intmsg(++filcnt); /* Count file, give interrupt msg */ } tlog(F110,"Sending",filnam,0l); /* Transaction log entry */ tlog(F110," as",pktnam,0l); next = -1; /* Init file character lookahead. */ return(1); } /* Send an X Packet -- Like SFILE, but with Text rather than File header */ sxpack() { /* Send an X packet */ debug(F110,"sxpack",cmdstr,0); encstr(cmdstr); /* Encode any data. */ rpt = flci = flco = ffc = 0; /* Init counters, etc. */ next = -1; /* Init file character lookahead. */ nxtpkt(&pktnum); /* Increment the packet number */ spack('X',pktnum,size,data); /* No incrementing pktnum */ screen(SCR_XD,'X',(long)pktnum,cmdstr); /* Update screen. */ intmsg(++filcnt); tlog(F110,"Sending from:",cmdstr,0l); return(1); } /* S D A T A -- Send a data packet */ sdata() { int len; if (cxseen || czseen) return(-1); /* If interrupted, done. */ if ((len = getpkt(spsiz-chklen-3)) == 0) return(-1); /* If no data, done.*/ nxtpkt(&pktnum); /* Increment the packet number */ spack('D',pktnum,len,data); /* Send the packet */ return(len); } /* S E O F -- Send an End-Of-File packet */ seof() { nxtpkt(&pktnum); /* Increment the packet number */ if (czseen || cxseen) { spack('Z',pktnum,1,"D"); cxseen = 0; /* Clear this now */ tlog(F100," *** interrupted, sending discard request","",0l); } else { spack('Z',pktnum,0,""); tlog(F100," end of file","",0l); tlog(F101," file characters ","",ffc); tlog(F101," communication line in ","",flci); tlog(F101," communication line out ","",flco); } } /* S E O T -- Send an End-Of-Transaction packet */ seot() { char *tp; nxtpkt(&pktnum); /* Increment the packet number */ spack('B',pktnum,0,""); cxseen = czseen = 0; ztime(&tp); tlog(F110,"End of transaction",tp,0l); if (filcnt > 1) { tlog(F101," files","",filcnt); tlog(F101," total file characters ","",tfc); tlog(F101," communication line in ","",tlci); tlog(F101," communication line out ","",tlco); } } /* R P A R -- Fill the data array with my send-init parameters */ rpar(data) char data[]; { data[0] = tochar(rpsiz); /* Biggest packet I can receive */ data[1] = tochar(rtimo); /* When I want to be timed out */ data[2] = tochar(mypadn); /* How much padding I need (none) */ data[3] = ctl(mypadc); /* Padding character I want */ data[4] = tochar(eol); /* End-Of-Line character I want */ data[5] = CTLQ; /* Control-Quote character I send */ if (ebqflg) data[6] = ebq = '&'; else data[6] = 'Y'; /* 8-bit quoting */ data[7] = bctr + '0'; /* Block check type */ data[8] = MYRPTQ; /* Do repeat counts */ data[9] = '\0'; return(9); /* Return the length. */ } /* S P A R -- Get the other system's Send-Init parameters. */ spar(data) char data[]; { int len, x; len = strlen(data); /* Number of fields */ spsiz = (len-- > 0) ? unchar(data[0]) : DSPSIZ; /* Packet size */ if (spsiz < 10) spsiz = DSPSIZ; x = (len-- > 0) ? unchar(data[1]) : DMYTIM; /* Timeout */ if (!timef) { /* Only use if not overridden */ timint = x; if (timint < 0) timint = DMYTIM; } npad = 0; padch = '\0'; /* Padding */ if (len-- > 0) { npad = unchar(data[2]); if (len-- > 0) padch = ctl(data[3]); else padch = 0; } eol = (len-- > 0) ? unchar(data[4]) : '\r'; /* Terminator */ if ((eol < 2) || (eol > 037)) eol = '\r'; ctlq = (len-- > 0) ? data[5] : CTLQ; /* Control prefix */ if (len-- > 0) { /* 8th-bit prefix */ ebq = data[6]; if ((ebq > 040 && ebq < 0100) || (ebq > 0140 && ebq < 0177)) { ebqflg = 1; } else if (parity && (ebq == 'Y')) { ebqflg = 1; ebq = '&'; } else if (ebq == 'N') { ebqflg = 0; } else ebqflg = 0; } else ebqflg = 0; chklen = 1; /* Block check */ if (len-- > 0) { chklen = data[7] - '0'; if ((chklen < 1) || (chklen > 3)) chklen = 1; } bctr = chklen; if (len-- > 0) { /* Repeat prefix */ rptq = data[8]; rptflg = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177)); } else rptflg = 0; if (deblog) sdebu(len); } /* S D E B U -- Record spar results in debugging log */ sdebu(len) int len; { debug(F111,"spar: data",data,len); debug(F101," spsiz ","",spsiz); debug(F101," timint","",timint); debug(F101," npad ","",npad); debug(F101," padch ","",padch); debug(F101," eol ","",eol); debug(F101," ctlq ","",ctlq); debug(F101," ebq ","",ebq); debug(F101," ebqflg","",ebqflg); debug(F101," chklen","",chklen); debug(F101," rptq ","",rptq); debug(F101," rptflg","",rptflg); } /* G N F I L E -- Get the next file name from a file group. */ /* Returns 1 if there's a next file, 0 otherwise */ gnfile() { int x; long y; /* If file group interruption (C-Z) occured, fail. */ debug(F101,"gnfile: czseen","",czseen); if (czseen) { tlog(F100,"Transaction cancelled","",0l); return(0); } /* If input was stdin or memory string, there is no next file. */ if (sndsrc == 0) return(0); /* If file list comes from command line args, get the next list element.*/ y = -1; while (y < 0) { /* Keep trying till we get one... */ if (sndsrc > 0) { if (nfils-- > 0) { strcpy(filnam,*cmlist++); debug(F111,"gnfile: cmlist filnam",filnam,nfils); } else { *filnam = '\0'; debug(F101,"gnfile cmlist: nfils","",nfils); return(0); } } /* Otherwise, step to next element of internal wildcard expansion list. */ if (sndsrc < 0) { x = znext(filnam); debug(F111,"gnfile znext: filnam",filnam,x); if (x == 0) return(0); } /* Get here with a filename. */ y = zchki(filnam); /* Check if file readable */ if (y < 0) { debug(F110,"gnfile skipping:",filnam,0); tlog(F111,filnam,"not sent, reason",(long)y); screen(SCR_ST,ST_SKIP,0l,filnam); } else fsize = y; } return(1); } /* O P E N I -- Open an existing file for input */ openi(name) char *name; { int x, filno; if (memstr) return(1); /* Just return if file is memory. */ debug(F110,"openi",name,0); debug(F101," sndsrc","",sndsrc); filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */ debug(F101," file number","",filno); if (zopeni(filno,name)) { /* Otherwise, try to open it. */ debug(F110," ok",name,0); return(1); } else { /* If not found, */ char xname[100]; /* convert the name */ zrtol(name,xname); /* to local form and then */ debug(F110," zrtol:",xname,0); x = zopeni(filno,xname); /* try opening it again. */ debug(F101," zopeni","",x); if (x) { debug(F110," ok",xname,0); return(1); /* It worked. */ } else { screen(SCR_EM,0,0l,"Can't open file"); /* It didn't work. */ tlog(F110,xname,"could not be opened",0l); debug(F110," openi failed",xname,0); return(0); } } } /* O P E N O -- Open a new file for output. */ /* Returns actual name under which the file was opened in string 'name2'. */ openo(name,name2) char *name, *name2; { char xname[100], *xp; if (stdouf) /* Receiving to stdout? */ return(zopeno(ZSTDIO,"")); debug(F110,"openo: name",name,0); if (cxseen || czseen) { /* If interrupted, get out before */ debug(F100," open cancelled","",0); /* destroying existing file. */ return(1); /* Pretend to succeed. */ } xp = xname; /* OK to proceed. */ if (fncnv) { /* If desired, */ /***** This one is the special case exempted elsewhere by tweaking fncnv ****/ zrtol(name,xp); /* convert name to local form */ } else /* otherwise, */ strcpy(xname,name); /* use it literally */ debug(F110,"openo: xname",xname,0); if (warn) { /* File collision avoidance? */ if (zchki(xname) != -1) { /* Yes, file exists? */ znewn(xname,&xp); /* Yes, make new name. */ strcpy(xname,xp); debug(F110," exists, new name ",xname,0); } } if (zopeno(ZOFILE,xname) == 0) { /* Try to open the file */ debug(F110,"openo failed",xname,0); tlog(F110,"Failure to open",xname,0l); return(0); } else { strcpy(name2,xname); debug(F110,"openo ok, name2",name2,0); return(1); } } /* O P E N T -- Open the terminal for output, in place of a file */ opent() { ffc = tfc = 0; return(zopeno(ZCTERM,"")); } /* C L S I F -- Close the current input file. */ clsif() { if (memstr) { /* If input was memory string, */ memstr = 0; /* indicate no more. */ } else zclose(ZIFILE); /* else close input file. */ if (czseen || cxseen) screen(SCR_ST,ST_DISC,0l,""); else screen(SCR_ST,ST_OK,0l,""); cxseen = hcflg = 0; /* Reset flags, */ *filnam = '\0'; /* and current file name */ } /* C L S O F -- Close an output file. */ clsof() { zclose(ZOFILE); /* Close it. */ if (czseen || cxseen) { if (*filnam) zdelet(filnam); /* Delete it if interrupted. */ debug(F100,"Discarded","",0); tlog(F100,"Discarded","",0l); screen(SCR_ST,ST_DISC,0l,""); } else { debug(F100,"Closed","",0); screen(SCR_ST,ST_OK,0l,""); } cxseen = 0; /* Reset file interruption flag */ *filnam = '\0'; /* and current file name. */ } /* S N D H L P -- Routine to send builtin help */ sndhlp() { nfils = 0; /* No files, no lists. */ xflg = 1; /* Flag we must send X packet. */ strcpy(cmdstr,"help text"); /* Data for X packet. */ next = -1; /* Init getch lookahead */ memstr = 1; /* Just set the flag. */ memptr = hlptxt; /* And the pointer. */ return(sinit()); } /* C W D -- Change current working directory */ /* String passed has first byte as length of directory name, rest of string is name. Fails if can't connect, else ACKs (with name) and succeeds. */ cwd(vdir) char *vdir; { vdir[unchar(*vdir) + 1] = '\0'; /* End with a null */ if (zchdir(vdir+1)) { encstr(vdir+1); ack1(data); tlog(F110,"Changed directory to",vdir+1,0l); return(1); } else { tlog(F110,"Failed to change directory to",vdir+1,0l); return(0); } } /* S Y S C M D -- Do a system command */ /* Command string is formed by concatenating the two arguments. */ syscmd(prefix,suffix) char *prefix, *suffix; { char *cp; if (prefix == NULL || *prefix == '\0') return(0); for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ; while (*cp++ = *suffix++) ; debug(F110,"syscmd",cmdstr,0); if (zopeni(ZSYSFN,cmdstr) > 0) { debug(F100,"syscmd zopeni ok",cmdstr,0); nfils = sndsrc = 0; /* Flag that input from stdin */ xflg = hcflg = 1; /* And special flags for pipe */ return (sinit()); /* Send S packet */ } else { debug(F100,"syscmd zopeni failed",cmdstr,0); return(0); } } <<< accpro.c >>> /* WARNING -- This C source program generated by Wart preprocessor. */ /* Do not edit this file; edit the Wart-format source file instead, */ /* and then run it through Wart to produce a new C source file. */ /* Wart Version Info: */ char *wartv = "Wart Version 1A(003) 27 May 85"; char *protv = "C-Kermit Protocol Module 4C(029), 11 Jul 85"; /* -*-C-*- */ /* C K C P R O -- C-Kermit Protocol Module, in Wart preprocessor notation. */ /* Authors: Frank da Cruz (SY.FDC@CU20B), Bill Catchings, Jeff Damens; Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ #include "ckcdeb.h" #include "ckcker.h" /* Note -- This file may also be preprocessed by the Unix Lex program, but you must indent the above #include statements before using Lex, and then restore them to the left margin in the resulting C program before compilation. Also, the invocation of the "wart()" function below must be replaced by an invocation of the "yylex()" function. It might also be necessary to remove comments in the %%...%% section. */ /* State definitions for Wart (or Lex) */ #define ipkt 1 #define rfile 2 #define rdata 3 #define ssinit 4 #define ssfile 5 #define ssdata 6 #define sseof 7 #define sseot 8 #define serve 9 #define generic 10 #define get 11 #define rgen 12 /* External C-Kermit variable declarations */ extern char sstate, *versio, *srvtxt, *cmarg, *cmarg2; extern char data[], filnam[], srvcmd[], ttname[], *srvptr; extern int pktnum, timint, nfils, image, hcflg, xflg, speed, flow, mdmtyp; extern int prvpkt, cxseen, czseen, server, local, displa, bctu, bctr, quiet; extern int tsecs; extern int putsrv(), puttrm(), putfil(), errpkt(); extern char *DIRCMD, *DELCMD, *TYPCMD, *SPACMD, *SPACM2, *WHOCMD; /* Local variables */ static char vstate = 0; /* Saved State */ static char vcmd = 0; /* Saved Command */ int x; /* General-purpose integer */ char *s; /* General-purpose string pointer */ /* Macros - Note, BEGIN is predefined by Wart (and Lex) */ #define SERVE tinit(); BEGIN serve #define RESUME if (server) { SERVE; } else return #define BEGIN state = int state = 0; wart() { int c,actno; while (1) { c = input(); if ((actno = tbl(c + state*128)) != -1) switch(actno) { case 1: { tinit(); /* Do Send command */ if (sinit()) BEGIN ssinit; else RESUME; } break; case 2: { tinit(); sleep(1); nack(); BEGIN get; } break; case 3: { tinit(); vstate = get; vcmd = 0; sipkt('I'); BEGIN ipkt; } break; case 4: { tinit(); vstate = rgen; vcmd = 'C'; sipkt('I'); BEGIN ipkt; } break; case 5: { tinit(); vstate = rgen; vcmd = 'G'; sipkt('I'); BEGIN ipkt; } break; case 6: { sleep(10); SERVE; } break; case 7: { errpkt("User cancelled transaction"); /* "Abort" -- Tell other side. */ x = quiet; quiet = 1; /* Close files silently. */ clsif(); clsof(1); quiet = x; return(0); } break; case 8: { rinit(data); bctu = bctr; /* Get Send-Init */ rtimer(); BEGIN rfile; } break; case 9: { spar(data); /* Get ack for I-packet */ if (vcmd) { scmd(vcmd,cmarg); vcmd = 0; } if (vstate == get) srinit(); BEGIN vstate; } break; case 10: { if (vcmd) scmd(vcmd,cmarg); /* Get E for I-packet (ignore) */ vcmd = 0; if (vstate == get) srinit(); BEGIN vstate; } break; case 11: { srvptr = srvcmd; decode(data,putsrv); /* Get Receive-Init */ cmarg = srvcmd; nfils = -1; if (sinit()) BEGIN ssinit; else { SERVE; } } break; case 12: { spar(data); rpar(data); ack1(data); /* Get Init Parameters */ pktnum = 0; prvpkt = -1; } break; case 13: { srvptr = srvcmd; decode(data,putsrv); /* Get & decode command. */ putsrv('\0'); putsrv('\0'); sstate = srvcmd[0]; BEGIN generic; } break; case 14: { srvptr = srvcmd; /* Get command for shell */ decode(data,putsrv); putsrv('\0'); if (syscmd(srvcmd,"")) BEGIN ssinit; else { errpkt("Can't do system command"); SERVE; } } break; case 15: { errpkt("Unimplemented server function"); SERVE; } break; case 16: { if (!cwd(srvcmd+1)) errpkt("Can't change directory"); /* CWD */ SERVE; } break; case 17: { if (syscmd(DIRCMD,srvcmd+2)) BEGIN ssinit; /* Directory */ else { errpkt("Can't list directory"); SERVE; } } break; case 18: { if (syscmd(DELCMD,srvcmd+2)) BEGIN ssinit; /* Erase */ else { errpkt("Can't remove file"); SERVE; } } break; case 19: { ack(); screen(SCR_TC,0,0l,""); return(0); } break; case 20: { ack(); ttres(); screen(SCR_TC,0,0l,""); return(zkself()); } break; case 21: { if (sndhlp()) BEGIN ssinit; else { errpkt("Can't send help"); SERVE; } } break; case 22: { if (syscmd(TYPCMD,srvcmd+2)) BEGIN ssinit; else { errpkt("Can't type file"); SERVE; } } break; case 23: { x = *(srvcmd+1); /* Disk Usage query */ x = ((x == '\0') || (x == unchar(0))); x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,srvcmd+2)); if (x) BEGIN ssinit; else { errpkt("Can't check space"); SERVE; }} break; case 24: { if (syscmd(WHOCMD,srvcmd+2)) BEGIN ssinit; else { errpkt("Can't do who command"); SERVE; } } break; case 25: { errpkt("Unimplemented generic server function"); SERVE; } break; case 26: { decode(data,puttrm); RESUME; } break; case 27: { if (rcvfil()) { ack1(""); BEGIN rdata; } /* File header */ else { errpkt("Can't open file"); RESUME; } } break; case 28: { opent(); ack(); BEGIN rdata; } break; case 29: { ack(); tsecs = gtimer(); reot(); RESUME; } break; case 30: { if (cxseen) ack1("X"); /* Got data. */ else if (czseen) ack1("Z"); else ack(); decode(data,putfil); } break; case 31: { if (reof() < 0) { /* Got End Of File */ errpkt("Can't close file"); RESUME; } else { ack(); BEGIN rfile; } } break; case 32: { spar(data); bctu = bctr; /* Got ACK to Send-Init */ x = sfile(xflg); /* Send X or F header packet */ if (x) { rtimer(); BEGIN ssfile; } else { s = xflg ? "Can't execute command" : "Can't open file"; errpkt(s); RESUME; } } break; case 33: { srvptr = srvcmd; /* Got ACK to F */ decode(data,putsrv); putsrv('\0'); if (*srvcmd) tlog(F110," stored as",srvcmd,0); if (sdata() < 0) { clsif(); seof(""); BEGIN sseof; } else BEGIN ssdata; } break; case 34: { if (canned(data)) { clsif(); seof("D"); BEGIN sseof; } else if (sdata() < 0) { clsif(); seof(""); BEGIN sseof; } } break; case 35: { if (gnfile() > 0) { /* Got ACK to EOF, get next file */ if (sfile(xflg)) BEGIN ssdata; else { errpkt("Can't open file") ; RESUME; } } else { /* If no next file, EOT */ tsecs = gtimer(); seot(); BEGIN sseot; } } break; case 36: { RESUME; } break; case 37: { ermsg(data); /* Error packet, issue message. */ x = quiet; quiet = 1; /* Close files silently, */ clsif(); clsof(1); /* discarding any output file. */ tsecs = gtimer(); quiet = x; RESUME; } break; case 38: { errpkt("Unknown packet type"); RESUME; } break; } } } static short jdx[] = { 0, 1, 69, 70, 97, 98, 99, 100, 103, 104, 114, 115, 116, 118, 119, 120, 121, 128, 129, 197, 198, 217, 218, 225, 226, 227, 228, 231, 232, 242, 243, 244, 246, 247, 248, 249, 256, 257, 322, 323, 325, 326, 327, 344, 345, 353, 354, 355, 356, 359, 360, 370, 371, 372, 374, 375, 376, 377, 384, 385, 452, 453, 454, 474, 475, 481, 482, 483, 484, 487, 488, 498, 499, 500, 502, 503, 504, 505, 512, 513, 581, 582, 601, 602, 609, 610, 611, 612, 615, 616, 626, 627, 628, 630, 631, 632, 633, 640, 641, 709, 710, 729, 730, 737, 738, 739, 740, 743, 744, 754, 755, 756, 758, 759, 760, 761, 768, 769, 837, 838, 857, 858, 865, 866, 867, 868, 871, 872, 882, 883, 884, 886, 887, 888, 889, 896, 897, 965, 966, 985, 986, 993, 994, 995, 996, 999, 1000, 1010, 1011, 1012, 1014, 1015, 1016, 1017, 1024, 1025, 1093, 1094, 1113, 1114, 1121, 1122, 1123, 1124, 1127, 1128, 1138, 1139, 1140, 1142, 1143, 1144, 1145, 1152, 1153, 1219, 1220, 1223, 1224, 1225, 1226, 1234, 1235, 1236, 1249, 1250, 1251, 1252, 1255, 1256, 1266, 1267, 1268, 1270, 1271, 1272, 1273, 1280, 1281, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1356, 1357, 1364, 1365, 1366, 1367, 1368, 1377, 1378, 1379, 1380, 1383, 1384, 1394, 1395, 1396, 1398, 1399, 1400, 1401, 1408, 1409, 1477, 1478, 1491, 1492, 1505, 1506, 1507, 1508, 1511, 1512, 1522, 1523, 1524, 1526, 1527, 1528, 1529, 1536, 1537, 1605, 1606, 1607, 1619, 1620, 1624, 1625, 1626, 1633, 1634, 1635, 1636, 1639, 1640, 1650, 1651, 1652, 1654, 1655, 1656, 1664}; static int jdxupb = 268; static short jtbl[] = { -1, 38, 37, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 10, 38, 9, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 29, 38, 37, 27, 38, 28, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 30, 37, 38, 31, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 37, 38, 32, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 37, 38, 33, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 37, 38, 34, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 37, 38, 35, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 38, 37, 38, 36, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, -1, 15, 14, 15, 13, 15, 12, 15, 11, 8, 15, 7, 15, 4, 15, 5, 15, 3, 1, 15, 2, 15, 6, 15, -1, 25, 16, 17, 18, 19, 25, 21, 25, 20, 25, 22, 23, 25, 24, 25, 7, 25, 4, 25, 5, 25, 3, 1, 25, 2, 25, 6, 25, -1, 38, 37, 38, 8, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 6, 38, 0, 38, 37, 27, 38, 8, 38, 28, 26, 38, 7, 38, 4, 38, 5, 38, 3, 1, 38, 2, 38, 38}; int tbl(idx) int idx; { int l, u, m, ml, mr; /**********************************************************************/ /* tbl() simulates a (sparse) 1-D array, run-length encoded into jidx */ /* and jtbl. The assertion is: */ /* for all m, idx s.t. jdx[m] <= idx < jdx[m+1], */ /* tbl[idx] == tbl[jdx[m]] == jtbl[m] */ /* Here we (binary) search for an m s.t. jdx[m] <= idx < jdx[m+1], */ /* returning jtbl[m] (== tbl[idx], as required. */ /**********************************************************************/ l = 0; u = jdxupb; while (l <= u) { ml = jdx[m = (l + u) >> 1]; mr = jdx[m+1]; if ((ml <= idx) && (idx < mr)) return (jtbl[m]); if (ml > idx) u = m; else if (idx >= mr) l = m; } } /* P R O T O -- Protocol entry function */ proto() { extern int sigint(); int x; conint(sigint); /* Enable console interrupts */ /* Set up the communication line for file transfer. */ if (local && (speed < 0)) { screen(SCR_EM,0,0l,"Sorry, you must 'set speed' first"); return; } x = -1; if (ttopen(ttname,&x,mdmtyp) < 0) { debug(F111,"proto ttopen local",ttname,local); screen(SCR_EM,0,0l,"Can't open line"); return; } if (x > -1) local = x; debug(F111,"proto ttopen local",ttname,local); x = (local) ? speed : -1; if (ttpkt(x,flow) < 0) { /* Put line in packet mode, */ screen(SCR_EM,0,0l,"Can't condition line"); return; } if (sstate == 'x') { /* If entering server mode, */ server = 1; /* set flag, */ if (!quiet) { if (!local) /* and issue appropriate message. */ conol(srvtxt); else { conol("Entering server mode on "); conoll(ttname); } } } else server = 0; sleep(1); /* The 'wart()' function is generated by the wart program. It gets a character from the input() routine and then based on that character and the current state, selects the appropriate action, according to the state table above, which is transformed by the wart program into a big case statement. The function is active for one transaction. */ wart(); /* Enter the state table switcher. */ if (server) { /* Back from packet protocol. */ server = 0; if (!quiet) /* Give appropriate message */ conoll("C-Kermit server done"); } screen(SCR_TC,0,0l,""); /* Transaction complete */ } <<< ackerm.c >>> <<< acpcmd.c >>> char *cmdv = "Panos cmd package (based on C-Kermit V1A(019)) 19 Dec 85"; /* C K P C M D -- Interactive command package for Panos */ /* Modelled after the DECSYSTEM-20 command parser (the COMND JSYS) Features: . parses and verifies keywords, text strings, numbers, and other data . displays appropriate menu or help message when user types "?" . does keyword and filename completion when user types ESC . accepts any unique abbreviation for a keyword . allows keywords to have attributes, like "invisible" . can supply defaults for fields omitted by user . provides command line editing (character, word, and line deletion) . accepts input from keyboard, command files, or redirected stdin . allows for full or half duplex operation, character or line input . settable prompt, protected from deletion Functions: cmsetp - Set prompt (cmprom is prompt string, cmerrp is error msg prefix) cmsavp - Save current prompt prompt - Issue prompt cmini - Clear the command buffer (before parsing a new command) cmres - Reset command buffer pointers (before reparsing) cmkey - Parse a keyword cmnum - Parse a number cmifi - Parse an input file name cmofi - Parse an output file name cmfld - Parse an arbitrary field cmtxt - Parse a text string cmcfm - Parse command confirmation (end of line) stripq - Strip out backslash quotes from a string. Return codes: -3: no input provided when required -2: input was invalid -1: reparse required (user deleted into a preceding field) 0 or greater: success See individual functions for greater detail. Before using these routines, the caller should #include ckucmd.h, and set the program's prompt by calling cmsetp(). If the file parsing functions cmifi and cmofi are to be used, this module must be linked with a ck?fio file system support module for the appropriate system, e.g. ckufio for Unix. If the caller puts the terminal in character wakeup ("cbreak") mode with no echo, then these functions will provide line editing -- character, word, and line deletion, as well as keyword and filename completion upon ESC and help strings, keyword, or file menus upon '?'. If the caller puts the terminal into character wakeup/noecho mode, care should be taken to restore it before exit from or interruption of the program. If the character wakeup mode is not set, the system's own line editor may be used. Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ #include /* Standard C I/O package */ #include /* Character types */ #include "ckucmd.h" /* Command parsing definitions */ #include "ckcdeb.h" /* Formats for debug() */ /* Local variables */ int psetf = 0, /* Flag that prompt has been set */ cc = 0, /* Character count */ dpx = 0; /* Duplex (0 = full) */ int hw = HLPLW, /* Help line width */ hc = HLPCW, /* Help line column width */ hh, /* Current help column number */ hx; /* Current help line position */ #define PROML 60 /* Maximum length for prompt */ char cmprom[PROML+1]; /* Program's prompt */ char *dfprom = "Command? "; /* Default prompt */ char cmerrp[PROML+1]; /* Program's error message prefix */ int cmflgs; /* Command flags */ char cmdbuf[CMDBL+4]; /* Command buffer */ char hlpbuf[HLPBL+4]; /* Help string buffer */ char atmbuf[ATMBL+4]; /* Atom buffer */ char filbuf[ATMBL+4]; /* File name buffer */ /* Command buffer pointers */ static char *bp, /* Current command buffer position */ *pp, /* Start of current field */ *np; /* Start of next field */ long zchki(); /* From ck?fio.c. */ /* eraseleft() { printf("\b \b"); } */ /* For systems other than Panos */ /* C M S E T P -- Set the program prompt. */ cmsetp(s) char *s; { char *sx, *sy, *strncpy(); psetf = 1; /* Flag that prompt has been set. */ strncpy(cmprom,s,PROML - 1); /* Copy the string. */ cmprom[PROML] = NUL; /* Ensure null terminator. */ sx = cmprom; sy = cmerrp; /* Also use as error message prefix. */ while (*sy++ = *sx++) ; /* Copy. */ sy -= 2; if (*sy == '>') *sy = NUL; /* Delete any final '>'. */ } /* C M S A V P -- Save a copy of the current prompt. */ cmsavp(s,n) int n; char s[]; { extern char *strncpy(); /* +1 */ strncpy(s,cmprom,n-1); s[n] = NUL; } /* P R O M P T -- Issue the program prompt. */ prompt() { if (psetf == 0) cmsetp(dfprom); /* If no prompt set, set default. */ printf("\r%s",cmprom); /* Print the prompt. */ } /* C M R E S -- Reset pointers to beginning of command buffer. */ cmres() { cc = 0; /* Reset character counter. */ pp = np = bp = cmdbuf; /* Point to command buffer. */ cmflgs = -5; /* Parse not yet started. */ } /* C M I N I -- Clear the command and atom buffers, reset pointers. */ /* The argument specifies who is to echo the user's typein -- 1 means the cmd package echoes 0 somebody else (system, front end, terminal) echoes */ cmini(d) int d; { for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL; *atmbuf = NUL; dpx = d; cmres(); } stripq(s) char *s; { /* Function to strip '\' quotes */ char *t; while (*s) { if (*s == '\\') { for (t = s; *t != '\0'; t++) *t = *(t+1); } s++; } } /* C M N U M -- Parse a number in the indicated radix */ /* For now, only works for positive numbers in base 10. */ /* Returns -3 if no input present when required, -2 if user typed an illegal number, -1 if reparse needed, 0 otherwise, with n set to number that was parsed */ cmnum(xhlp,xdef,radix,n) char *xhlp, *xdef; int radix, *n; { int x; char *s; if (radix != 10) { /* Just do base 10 for now */ printf("cmnum: illegal radix - %d\n",radix); return(-1); } x = cmfld(xhlp,xdef,&s); debug(F101,"cmnum: cmfld","",x); if (x < 0) return(x); /* Parse a field */ if (digits(atmbuf)) { /* Convert to number */ *n = atoi(atmbuf); return(x); } else { printf("\n?not a number - %s\n",s); return(-2); } } /* C M O F I -- Parse the name of an output file */ /* Depends on the external function zchko(); if zchko() not available, use cmfld() to parse output file names. Returns -3 if no input present when required, -2 if permission would be denied to create the file, -1 if reparse needed, 0 or 1 otherwise, with xp pointing to name. */ cmofi(xhlp,xdef,xp) char *xhlp, *xdef, **xp; { int x; char *s; if (*xhlp == NUL) xhlp = "Output file"; *xp = ""; if ((x = cmfld(xhlp,xdef,&s)) < 0) return(x); if (chkwld(s)) { printf("\n?Wildcards not allowed - %s\n",s); return(-2); } if (zchko(s) < 0) { printf("\n?Write permission denied - %s\n",s); return(-2); } else { *xp = s; return(x); } } /* C M I F I -- Parse the name of an existing file */ /* This function depends on the external functions: zchki() - Check if input file exists and is readable. zxpand() - Expand a wild file specification into a list. znext() - Return next file name from list. If these functions aren't available, then use cmfld() to parse filenames. */ /* Returns -4 EOF -3 if no input present when required, -2 if file does not exist or is not readable, -1 if reparse needed, 0 or 1 otherwise, with: xp pointing to name, wild = 1 if name contains '*' or '?', 0 otherwise. */ cmifi(xhlp,xdef,xp,wild) char *xhlp, *xdef, **xp; int *wild; { int i, x, xc, y; char *sp; cc = xc = 0; /* Initialize counts & pointers */ *xp = ""; if ((x = cmflgs) != 1) { /* Already confirmed? */ x = getwd(); /* No, get a word */ } else { cc = setatm(xdef); /* If so, use default, if any. */ } *xp = atmbuf; /* Point to result. */ *wild = chkwld(*xp); while (1) { xc += cc; /* Count the characters. */ debug(F111,"cmifi: getwd",atmbuf,xc); switch (x) { case -4: /* EOF */ case -2: /* Out of space. */ case -1: /* Reparse needed */ return(x); case 0: /* SP or NL */ case 1: if (xc == 0) *xp = xdef; /* If no input, return default. */ else *xp = atmbuf; if (**xp == NUL) return(-3); /* If field empty, return -3. */ /* If filespec is wild, see if there are any matches */ *wild = chkwld(*xp); debug(F101," *wild","",*wild); if (*wild != 0) { y = zxpand(*xp); if (y == 0) { printf("\n?No files match - %s\n",*xp); return(-2); } else if (y < 0) { printf("\n?Too many files match - %s\n",*xp); return(-2); } else return(x); } /* If not wild, see if it exists and is readable. */ y = zchki(*xp); if (y == -3) { printf("\n?Read permission denied - %s\n",*xp); return(-2); } else if (y == -2) { printf("\n?File not readable - %s\n",*xp); return(-2); } else if (y < 0) { printf("\n?File not found - %s\n",*xp); return(-2); } return(x); case 2: /* ESC */ if (xc == 0) { if (*xdef != '\0') { printf("%s ",xdef); /* If at beginning of field, */ addbuf(xdef); /* supply default. */ cc = setatm(xdef); } else { /* No default */ beep(); } break; } if (*wild = chkwld(*xp)) { /* No completion if wild */ beep(); break; } sp = atmbuf + cc; *sp++ = '*'; *sp-- = '\0'; y = zxpand(atmbuf); /* Add * and expand list. */ *sp = '\0'; /* Remove *. */ if (y == 0) { printf("\n?No files match - %s\n",atmbuf); return(-2); } else if (y < 0) { printf("\n?Too many files match - %s\n",atmbuf); return(-2); } else if (y > 1) { /* Not unique, just beep. */ beep(); } else { /* Unique, complete it. */ znext(filbuf); /* Get whole name of file. */ sp = filbuf + cc; /* Point past what user typed. */ printf("%s ",sp); /* Complete the name. */ addbuf(sp); /* Add the characters to cmdbuf. */ setatm(pp); /* And to atmbuf. */ *xp = atmbuf; /* Return pointer to atmbuf. */ return(cmflgs = 0); } break; case 3: /* Question mark */ if (*xhlp == NUL) printf(" Input file specification"); else printf(" %s",xhlp); if (xc > 0) { sp = atmbuf + cc; /* Insert * at end */ *sp++ = '*'; *sp-- = '\0'; y = zxpand(atmbuf); *sp = '\0'; if (y == 0) { printf("\n?No files match - %s\n",atmbuf); return(-2); } else if (y < 0) { printf("\n?Too many file match - %s\n",atmbuf); return(-2); } else { printf(", one of the following:\n"); clrhlp(); for (i = 0; i < y; i++) { znext(filbuf); addhlp(filbuf); } dmphlp(); } } else printf("\n"); printf("%s%s",cmprom,cmdbuf); break; } x = getwd(); } } /* C H K W L D -- Check for wildcard characters '*' or '?' */ chkwld(s) char *s; { for ( ; *s != '\0'; s++) { if ((*s == '*') || (*s == '?')) return(1); } return(0); } /* C M F L D -- Parse an arbitrary field */ /* Returns -3 if no input present when required, -2 if field too big for buffer, -1 if reparse needed, 0 otherwise, xp pointing to string result. */ cmfld(xhlp,xdef,xp) char *xhlp, *xdef, **xp; { int x, xc; cc = xc = 0; /* Initialize counts & pointers */ *xp = ""; if ((x = cmflgs) != 1) { /* Already confirmed? */ x = getwd(); /* No, get a word */ } else { cc = setatm(xdef); /* If so, use default, if any. */ } *xp = atmbuf; /* Point to result. */ while (1) { xc += cc; /* Count the characters. */ debug(F111,"cmfld: getwd",atmbuf,xc); debug(F101," x","",x); switch (x) { case -4: /* EOF */ case -2: /* Out of space. */ case -1: /* Reparse needed */ return(x); case 0: /* SP or NL */ case 1: if (xc == 0) *xp = xdef; /* If no input, return default. */ else *xp = atmbuf; if (**xp == NUL) x = -3; /* If field empty, return -3. */ return(x); case 2: /* ESC */ if (xc == 0) { printf("%s ",xdef); /* If at beginning of field, */ addbuf(xdef); /* supply default. */ cc = setatm(xdef); /* Return as if whole field */ return(0); /* typed, followed by space. */ } else { beep(); /* Beep if already into field. */ } break; case 3: /* Question mark */ if (*xhlp == NUL) printf(" Please complete this field"); else printf(" %s",xhlp); printf("\n%s%s",cmprom,cmdbuf); break; } x = getwd(); } } /* C M T X T -- Get a text string, including confirmation */ /* Print help message 'xhlp' if ? typed, supply default 'xdef' if null string typed. Returns -1 if reparse needed or buffer overflows. 1 otherwise. with cmflgs set to return code, and xp pointing to result string. */ cmtxt(xhlp,xdef,xp) char *xhlp; char *xdef; char **xp; { int x; static int xc; debug(F101,"cmtxt, cmflgs","",cmflgs); cc = 0; /* Start atmbuf counter off at 0 */ if (cmflgs == -1) { /* If reparsing, */ xc = strlen(*xp); /* get back the total text length, */ } else { /* otherwise, */ *xp = ""; /* start fresh. */ xc = 0; } *atmbuf = NUL; /* And empty atom buffer. */ if ((x = cmflgs) != 1) { x = getwd(); /* Get first word. */ *xp = pp; /* Save pointer to it. */ } while (1) { xc += cc; /* Char count for all words. */ debug(F111,"cmtxt: getwd",atmbuf,xc); debug(F101," x","",x); switch (x) { case -4: /* EOF */ case -2: /* Overflow */ case -1: /* Deletion */ return(x); case 0: /* Space */ xc++; /* Just count it */ break; case 1: /* CR or LF */ if (xc == 0) *xp = xdef; return(x); case 2: /* ESC */ if (xc == 0) { printf("%s ",xdef); cc = addbuf(xdef); } else { beep(); } break; case 3: /* Question Mark */ if (*xhlp == NUL) printf(" Text string"); else printf(" %s",xhlp); printf("\n%s%s",cmprom,cmdbuf); break; default: printf("\n?Unexpected return code from getwd() - %d\n",x); return(-2); } x = getwd(); } } /* C M K E Y -- Parse a keyword */ /* Call with: table -- keyword table, in 'struct keytab' format; n -- number of entries in table; xhlp -- pointer to help string; xdef -- pointer to default keyword; Returns: -3 -- no input supplied and no default available -2 -- input doesn't uniquely match a keyword in the table -1 -- user deleted too much, command reparse required n >= 0 -- value associated with keyword */ cmkey(table,n,xhlp,xdef) struct keytab table[]; int n; char *xhlp, *xdef; { int i, y, z, zz, xc; char *xp; xc = cc = 0; /* Clear character counters. */ if ((zz = cmflgs) == 1) /* Command already entered? */ setatm(xdef); else zz = getwd(); debug(F101,"cmkey: table length","",n); debug(F101," cmflgs","",cmflgs); debug(F101," zz","",zz); while (1) { xc += cc; debug(F111,"cmkey: getwd",atmbuf,xc); switch(zz) { case -4: /* EOF */ case -2: /* Buffer overflow */ case -1: /* Or user did some deleting. */ return(zz); case 0: /* User terminated word with space */ case 1: /* or newline */ if (cc == 0) setatm(xdef); y = lookup(table,atmbuf,n,&z); switch (y) { case -2: printf("\n?Ambiguous - %s\n",atmbuf); return(cmflgs = -2); case -1: printf("\n?Invalid - %s\n",atmbuf); return(cmflgs = -2); default: break; } return(y); case 2: /* User terminated word with ESC */ if (cc == 0) { if (*xdef != NUL) { /* Nothing in atmbuf */ printf("%s ",xdef); /* Supply default if any */ addbuf(xdef); cc = setatm(xdef); debug(F111,"cmkey: default",atmbuf,cc); } else { beep(); /* No default, just beep */ break; } } y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */ debug(F111,"cmkey: esc",atmbuf,y); if (y == -2) { beep(); break; } if (y == -1) { printf("\n?Invalid - %s\n",atmbuf); return(cmflgs = -2); } xp = table[z].kwd + cc; printf("%s ",xp); addbuf(xp); debug(F110,"cmkey: addbuf",cmdbuf,0); return(y); case 3: /* User terminated word with "?" */ y = lookup(table,atmbuf,n,&z); if (y > -1) { printf(" %s\n%s%s",table[z].kwd,cmprom,cmdbuf); break; } else if (y == -1) { printf("\n?Invalid\n"); return(cmflgs = -2); } if (*xhlp == NUL) printf(" One of the following:\n"); else printf(" %s, one of the following:\n",xhlp); clrhlp(); for (i = 0; i < n; i++) { if (!strncmp(table[i].kwd,atmbuf,cc) && !test(table[i].flgs,CM_INV)) addhlp(table[i].kwd); } dmphlp(); printf("%s%s", cmprom, cmdbuf); break; default: printf("\n%d - Unexpected return code from getwd\n",zz); return(cmflgs = -2); } zz = getwd(); } } /* C M C F M -- Parse command confirmation (end of line) */ /* Returns -2: User typed anything but whitespace or newline -1: Reparse needed 0: Confirmation was received */ cmcfm() { int x, xc; debug(F101,"cmcfm: cmflgs","",cmflgs); xc = cc = 0; if (cmflgs == 1) return(0); while (1) { x = getwd(); xc += cc; debug(F111,"cmcfm: getwd",atmbuf,xc); switch (x) { case -4: /* EOF */ case -2: case -1: return(x); case 0: /* Space */ continue; case 1: /* End of line */ if (xc > 0) { printf("?Not confirmed - %s\n",atmbuf); return(-2); } else return(0); case 2: beep(); continue; case 3: if (xc > 0) { printf("\n?Not confirmed - %s\n",atmbuf); return(-2); } printf("\n Type a carriage return to confirm the command\n"); printf("%s%s",cmprom,cmdbuf); continue; } } } /* Keyword help routines */ /* C L R H L P -- Initialize/Clear the help line buffer */ clrhlp() { /* Clear the help buffer */ hlpbuf[0] = NUL; hh = hx = 0; } /* A D D H L P -- Add a string to the help line buffer */ addhlp(s) char *s; { /* Add a word to the help buffer */ int j; hh++; /* Count this column */ for (j = 0; j < hc; j++) { /* Fill the column */ if (*s != NUL) /* First with chars from the string */ hlpbuf[hx++] = *s++; else { if (hh < (hw / hc)) /* Then with spaces */ hlpbuf[hx++] = SP; else { hlpbuf[hx++] = NUL; /* If last column, no spaces. */ dmphlp(); /* Print it. */ return; } } } if (*s != NUL) /* Still some chars left in string? */ hlpbuf[hx-1] = '+'; /* Mark as too long for column. */ } /* D M P H L P -- Dump the help line buffer */ dmphlp() { /* Print the help buffer */ hlpbuf[hx++] = NUL; printf(" %s\n",hlpbuf); clrhlp(); } /* L O O K U P -- Lookup the string in the given array of strings */ /* Call this way: v = lookup(table,word,n,&x); table - a 'struct keytab' table. word - the target string to look up in the table. n - the number of elements in the table. x - address of an integer for returning the table array index. The keyword table must be arranged in ascending alphabetical order, and all letters must be lowercase. Returns the keyword's associated value ( zero or greater ) if found, with the variable x set to the array index, or: -3 if nothing to look up (target was null), -2 if ambiguous, -1 if not found. A match is successful if the target matches a keyword exactly, or if the target is a prefix of exactly one keyword. It is ambiguous if the target matches two or more keywords from the table. */ lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; { int i, v, cmdlen; /* Lowercase & get length of target, if it's null return code -3. */ if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3); /* Not null, look it up */ for (i = 0; i < n-1; i++) { if (!strcmp(table[i].kwd,cmd) || ((v = !strncmp(table[i].kwd,cmd,cmdlen)) && strncmp(table[i+1].kwd,cmd,cmdlen))) { *x = i; return(table[i].val); } if (v) return(-2); } /* Last (or only) element */ if (!strncmp(table[n-1].kwd,cmd,cmdlen)) { *x = n-1; return(table[n-1].val); } else return(-1); } /* G E T W D -- Gets a "word" from the command input stream */ /* Usage: retcode = getwd(); Returns: -4 if end of file (e.g. pipe broken) -2 if command buffer overflows -1 if user did some deleting 0 if word terminates with SP or tab 1 if ... CR 2 if ... ESC 3 if ... ? With: pp pointing to beginning of word in buffer bp pointing to after current position atmbuf containing a copy of the word cc containing the number of characters in the word copied to atmbuf */ getwd() { int c; /* Current char */ static int inword = 0; /* Flag for start of word found */ int quote = 0; /* Flag for quote character */ int echof = 0; /* Flag for whether to echo */ int ignore = 0; pp = np; /* Start of current field */ debug(F101,"getwd: cmdbuf","",(int) cmdbuf); debug(F101," bp","",(int) bp); debug(F101," pp","",(int) pp); debug(F110," cmdbuf",cmdbuf,0); while (bp < cmdbuf+CMDBL) { /* Loop */ ignore = echof = 0; /* Flag for whether to echo */ if ((c = *bp) == NUL) { /* Get next character */ if (dpx) echof = 1; /* from reparse buffer */ /*old c = getchar();*/ /* or from tty. */ /*new*/ c = conin(); if ((c == EOF) || (c == 4)) return(-4); } else ignore = 1; if (quote == 0) { if (!ignore && (c == '\\')) { /* Quote character */ quote = 1; continue; } if (c == FF) { /* Formfeed. */ c = NL; /* Replace with newline */ system("set vdu -mode 0"); /* and clear the screen. */ } /* if (c == HT) c = SP;*/ /* Substitute space for tab. */ if (c == SP) { /* If space */ *bp++ = c; /* deposit it in buffer. */ if (echof) putchar(c); /* echo it. */ if (inword == 0) { /* If leading, gobble it. */ pp++; continue; } else { /* If terminating, return. */ np = bp; setatm(pp); inword = 0; return(cmflgs = 0); } } if (c == NL || c == CR) { /* CR, LF */ *bp = NUL; /* End the string */ if (echof) { /* If echoing, */ putchar(c); /* echo the typein */ if (c == CR) putchar(NL); /* Panos */ } np = bp; /* Where to start next field. */ setatm(pp); /* Copy this field to atom buffer. */ inword = 0; return(cmflgs = 1); } if (!ignore && (c == '?')) { /* Question mark */ putchar(c); *bp = NUL; setatm(pp); return(cmflgs = 3); } if (c == HT/*ESC*/) { /* ESC */ *bp = NUL; setatm(pp); return(cmflgs = 2); } if (c == BS || c == RUB) { /* Character deletion */ if (bp > cmdbuf) { /* If still in buffer... */ eraseleft(); /* erase character from screen, */ bp--; /* point behind it, */ if (*bp == SP) inword = 0; /* Flag if current field gone */ *bp = NUL; /* Erase character from buffer. */ } else { /* Otherwise, */ beep(); /* beep, */ cmres(); /* and start parsing a new command. */ } if (pp < bp) continue; else return(cmflgs = -1); } if (c == LDEL) { /* ^U, line deletion */ while ((bp--) > cmdbuf) { eraseleft(); *bp = NUL; } cmres(); /* Restart the command. */ inword = 0; return(cmflgs = -1); } if (c == WDEL) { /* ^W, word deletion */ if (bp <= cmdbuf) { /* Beep if nothing to delete */ beep(); cmres(); return(cmflgs = -1); } bp--; for ( ; (bp >= cmdbuf) && (*bp == SP) ; bp--) { eraseleft(); *bp = NUL; } for ( ; (bp >= cmdbuf) && (*bp != SP) ; bp--) { eraseleft(); *bp = NUL; } bp++; inword = 0; return(cmflgs = -1); } if (c == RDIS) { /* ^R, redisplay */ *bp = NUL; printf("\n%s%s",cmprom,cmdbuf); continue; } } if (echof) putchar(c); /* If tty input, echo. */ inword = 1; /* Flag we're in a word. */ if (quote == 0 || c != NL) *bp++ = c; /* And deposit it. */ quote = 0; /* Turn off quote. */ } /* end of big while */ beep(); /* Get here if... */ printf("\n?Buffer full\n"); return(cmflgs = -2); } /* Utility functions */ /* A D D B U F -- Add the string pointed to by cp to the command buffer */ addbuf(cp) char *cp; { int len = 0; while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) { *bp++ = *cp++; /* Copy and */ len++; /* count the characters. */ } *bp++ = SP; /* Put a space at the end */ *bp = NUL; /* Terminate with a null */ np = bp; /* Update the next-field pointer */ return(len); /* Return the length */ } /* S E T A T M -- Deposit a string in the atom buffer */ setatm(cp) char *cp; { char *ap; cc = 0; ap = atmbuf; *ap = NUL; while (*cp == SP) cp++; while ((*cp != SP) && (*cp != NL) && (*cp != NUL) && (*cp != CR)) { *ap++ = *cp++; cc++; } *ap++ = NUL; return(cc); /* Return length */ } /* D I G I T S -- Verify that all the characters in line are digits */ digits(s) char *s; { while (*s) { if (!isdigit(*s)) return(0); s++; } return(1); } /* L O W E R -- Lowercase a string */ lower(s) char *s; { int n = 0; while (*s) { if (isupper(*s)) *s = tolower(*s); s++, n++; } return(n); } /* T E S T -- Bit test */ test(x,m) int x, m; { /* Returns 1 if any bits from m are on in x, else 0 */ return((x & m) ? 1 : 0); } <<< acpcon.c >>> char *connv = "Panos Connect Command (based on C-Kermit V4C(010)) 19 Dec 85"; /* C K P C O N -- Smart terminal emulation to remote system, for Panos */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. Panos version: Richard Cownie/Acorn VLSI Tools Group (c) Acorn Computers Plc 1985 */ #include #include "ckcker.h" /* parameters to be tuned for performance (NB may blow up if you go wrong) */ #define BUFSZ 2048 /* buffer up to BUFSZ chars */ #define BUFHI 1280 /* send ^S when we have this many chars pending */ #define BSIZE 32 /* grab <= BSIZE chars at a time from rs423 input */ #define LOTS 128 /* send ^S when rs423 buf contains > LOTS */ #define FEW 64 /* send ^Q when rs423 buf contains < FEW */ #define VSIZE 4 /* give <= VSIZE chars at a time to protocol handler */ #define keybf 0 #define rs423inbf 1 #define rs423outbf 2 #define CTRL_S 19 #define CTRL_Q 17 #define send(c) putinbf(rs423outbf, c) /****************************************************/ /* Procedures to do Unix termcap functions on ACW */ /****************************************************/ extern int XFindOutput() asm; extern XSWriteByte() asm; int rawvdu = -1; vdus(s) char *s; { while(*s) XSWriteByte(rawvdu, *s++); } #define vdu(c) XSWriteByte(rawvdu, c) bbc_wipe(lx,ly,ux,uy) int lx,ly,ux,uy; { if (lx > ux) return; if (ly < uy) return; vdu(28); vdu(lx); vdu(ly); vdu(ux); vdu(uy); vdu(12); vdu(26); } term_cl() { vdu(12); } term_bs() { vdu(8); } term_cm(row,col) int row,col; { vdu(31); vdu(col); vdu(row); } term_nd() { vdu(9); } term_up() { vdu(11); } term_ce() { /* clear to end of line: non-trivial */ int x, y; get_posn(&x, &y); bbc_wipe(x,y,79,y); term_cm(y,x); } term_cd() { int x, y; get_posn(&x, &y); bbc_wipe(x,y,79,y); if (y < 31) bbc_wipe(0,31,79,y+1); term_cm(y,x); } term_ta() { int x, y; get_posn(&x, &y); vdu(' '); while ((++x) % 8) vdu(' '); } term_ho() { vdu(30); } term_so() { vdu(17); vdu(0); vdu(17); vdu(129); } term_se() { vdu(17); vdu(1); vdu(17); vdu(128); } /****************************************************/ /* State machine to filter VDU stream & tweak vdu */ /****************************************************/ #define NULL 0 /* initial state for the state machine */ static int emul_state, emul_x, emul_y, emul_len; static char emul_seq[32]; emul_start() /* initialise terminal emulator */ { int j; rawvdu = XFindOutput("RAWVDU:", 7); /* set register 10 of 6845 video chip to 0 for big non-flashing cursor */ vdu(23); vdu(0); vdu(10); vdu(0); for (j = 0; j < 6; ++j) vdu(0); emul_state = NULL; emul_len = 0; } #define CR 13 #define LF 10 #define ESC 27 putseq() /* put an aborted sequence to vdu in readable form */ { int j,x; char c; for (j = 0; j < emul_len; j++) { c = emul_seq[j]; x = c; if (c < ' ') printf("[%d]", x); else vdu(c); } } #define next(s) { emul_state = s; return; } #define abort { putseq(); emul_len = 0; emul_state = NULL; return; } #define done { emul_len = 0; emul_state = NULL; return; } #define isdigit(c) (('0' <= c) && (c <= '9')) /*************************************/ /* A simple dumb terminal emulator */ /*************************************/ emul_inch(c) char c; /* deal with character received from line: dumb terminal */ { if (c >= 128) c -= 128; switch(c) { case 8: term_bs(); break; case 9: term_ta(); break; case CR: break; case LF: vdu(CR); vdu(LF); break; default: if (c >= ' ') vdu(c); } } emul_outch(c) /* send sequence corresponding to key press c on ACW keyboard */ /* sends ESC-0,..,ESC-9 for the function keys, ESC-A,...,ESC-D for the */ /* cursor keys, with control & shift adding an extra ESC- prefix each. */ { char *code = "0123456789 ]DCBA"; if (c < 128) { send(c); return; } while (c >= 144) { send(ESC); c -= 16; } send(ESC); send(code[c-128]); } /*************************************/ /* End of dumb terminal emulator */ /*************************************/ #ifdef VT52 /********************************************************************/ /* An example of a smart terminal emulator, for those who want to */ /* hack emulators for the terminal of their choice. This one does */ /* a subset of VT52 as defined by the BSD 4.2 Unix termcap file, */ /* together with inverse video highlighting. */ /********************************************************************/ /* First define states of the machine to be used to interpret codes */ #define SESC 1 #define SBRA 2 #define SO1 3 #define GETY 4 #define GETX 5 #define CL1 6 #define CL2 7 /* Now the interpreter itself */ VT52_inch(c) char c; /* deal with char c received from line: VT52 emulation */ { if (c >= 128) c -= 128; emul_seq[emul_len++] = c; switch(emul_state) { case NULL: switch(c) { case ESC: next(SESC); case 9: term_ta(); done; default: vdu(c); done; } case SESC: switch(c) { case 'A': term_up(); done; case 'C': term_nd(); done; case 'J': term_cd(); done; case 'K': term_ce(); done; case 'H': next(CL1); case 'Y': next(GETY); case '[': next(SBRA); default: abort; } case SBRA: switch(c) { case '4': case '7': next(SO1); case 'm': term_se(); done; default : abort; } case SO1: if (c == 'm') { term_so(); done; } else abort; case GETY: emul_y = (c - ' '); next(GETX); case GETX: emul_x = (c - ' '); term_cm(emul_y, emul_x); done; case CL1: if (c == ESC) { next(CL2); } else abort; case CL2: if (c == 'J') { term_cl(); done; } else abort; default: abort; } } VT52_outch(c) /* send sequence corresponding to key press c */ /* this generates some bizarre non-standard escape sequences copied */ /* from a terminal ROM developed for in-house use at ACORN. */ { char *code = "<>,.45O78J ]DCBA"; if (c < 128) { send(c); return; } while (c >= 144) { send(ESC); c -= 16; } send(ESC); send(code[c-128]); } /**************************/ /* End of VT52 emulator */ /**************************/ #endif emul_finish() /* finish terminal emulation & tidy up */ { } /**************************************************/ /* C O N E C T -- Perform terminal connection */ /**************************************************/ conect() { int key,max,min,block,doneCtrlS,ok,userok; int head = 0, tail = 0, size = 0; char buf[BUFSZ]; printf("\nYou are now connected to your host computer\n"); printf("Press SHIFT-F0 to return to local kermit\n\n"); initrs(); emul_start(); send(CR); doneCtrlS = 1; ok = userok = 1; max = min = 0; for (;;) { if (doneCtrlS) { if (min+size < FEW) ok = 1; if (ok && userok) { send(CTRL_Q); doneCtrlS = 0; } } else if ((min+size == 0) || (max > FEW)) { min = nrsbuf(); if ((min > LOTS) || (size > BUFHI)) ok = 0; if (! (ok && userok)) { send(CTRL_S); doneCtrlS = 1; } } block = min; if (block > BSIZE) block = BSIZE; while (block--) { /* get chars from rs423 buffer */ testbf(rs423inbf, &key); min--; buf[tail] = key; ++size; if (++tail >= BUFSZ) tail = 0; } block = size; if (block > VSIZE) block = VSIZE; max = min + LOTS; /* chars may be coming */ while (block--) { /* hand chars to protocol interpreter */ emul_inch(buf[head]); --size; if (++head >= BUFSZ) head = 0; } if (testbf(keybf, &key)) { /* have a key press */ if (key == 144) { termrs(); emul_finish(); printf("\nReturn to Panos-Kermit.\n"); return(1); } else if (key == CTRL_S) userok = 0; else if (key == CTRL_Q) userok = 1; else if (key >= 127) emul_outch(key); else send(key); } } } /*****************************************************/ /* H C O N N E -- Give help message for connect. */ /*****************************************************/ hconne() { int c; static char *hlpmsg[] = { "\r\n C to close the connection, or:", "\r\n S for status", "\r\n ? for help", "\r\n B to send a BREAK", "\r\n 0 to send a null", "\r\n escape character twice to send the escape character.\r\n\r\n", "" }; conola(hlpmsg); /* Print the help message. */ conol("Command> "); /* Prompt for command. */ c = coninc(0); conoc(c); /* Echo it. */ conoll(""); c &= 0177; /* Strip any parity. */ return(c); /* Return it. */ } /***************************************************************/ /* C H S T R -- Make a printable string out of a character */ /***************************************************************/ char * chstr(c) int c; { static char s[8]; char *cp = s; if (c < SP) { sprintf(cp,"CTRL-%c",ctl(c)); } else sprintf(cp,"'%c'\n",c); cp = s; return(cp); } /*********************************************************/ /* D O E S C -- Process an escape character argument */ /*********************************************************/ doesc(c) char c; {} <<< acpdia.c >>> char *dialv = "Panos Dial Command (not yet implemented) 20 Dec 85"; /* C K P D I A -- Dialing program for connection to remote system */ /* P A N O S -- temp cut down version */ #include "ckcdeb.h" #include #include #include "ckcker.h" #include "ckucmd.h" struct keytab mdmtab[] = { /* Modem types for command parsing */ "No dial-out supported", 0, 0 }; int nmdm = (sizeof(mdmtab) / sizeof(struct keytab)); /* number of modems */ /* D I A L -- Dial up the remote system */ dial(telnbr) char *telnbr; { printf("\nThe dial command has not been implemented.\n"); printf("Acorn would be interested to hear from you if\n"); printf("you have an auto-dial modem you wish to attach\n"); printf("to the ACW. In particular we would like to know\n"); printf("how many people want to use Acorn Prestel modems\n"); printf("with their workstations.\n\n"); } <<< acpfio.c >>> char *ckzv = "Panos file support, 03 Jan 86"; /* C K P F I O -- Kermit file system support for Panos */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. Panos version: Graham Toal/Acorn VLSI Tools Group (c) Acorn Computers Plc. */ /* Includes */ #include "ckcker.h" /* Kermit definitions */ #include "ckcdeb.h" /* Typedefs, debug formats, etc */ #include /* Standard i/o */ #include #define NL LF char *ckzsys = " Acorn Panos"; /* Definitions of some Panos system commands - needs changing */ char *DIRCMD = "cat "; /* For directory listing */ char *DELCMD = "delete -force -noconfirm "; /* For file deletion */ char *TYPCMD = "copy -force -noconfirm "; /* For typing a file */ char *PWDCMD = "show dir "; /* For saying where I am */ char *CWDCMD = "set dir -verbosity 0 "; /* For selecting new dir */ char *SPACMD = "star free "; /* Space/quota of current directory */ char *SPACM2 = "star free "; /* For space in specified directory */ char *WHOCMD = "star users "; /* For seeing who's logged in */ /* Functions (n is one of the predefined file numbers from ckermi.h): zopeni(n,name) -- Opens an existing file for input. zopeno(n,name) -- Opens a new file for output. zclose(n) -- Closes a file. zchin(n,&c) -- Gets the next character from an input file. zsout(n,s) -- Write a null-terminated string to output file, buffered. zsoutl(n,s) -- Like zsout, but appends a line terminator. zsoutx(n,s,x) -- Write x characters to output file, unbuffered. zchout(n,c) -- Add a character to an output file, unbuffered. zchki(name) -- Check if named file exists and is readable, return size. zchko(name) -- Check if named file can be created. znewn(name,s) -- Make a new unique file name based on the given name. zdelet(name) -- Delete the named file. zxpand(string) -- Expands the given wildcard string into a list of files. znext(string) -- Returns the next file from the list in "string". zxcmd(cmd) -- Execute the command in a lower fork. zclosf() -- Close input file associated with zxcmd()'s lower fork. zrtol(n1,n2) -- Convert remote filename into local form. zltor(n1,n2) -- Convert local filename into remote form. zchdir(dirnam) -- Change working directory. zhome() -- Return pointer to home directory name string. zkself() -- Kill self, log out own job. */ /* Declarations */ #define NOFILE -99 int fp[ZNFILS] = { NOFILE, NOFILE, NOFILE, NOFILE, NOFILE, NOFILE, NOFILE }; int isout[ZNFILS]= { 0, 0, 0, 0, 0, 0, 0 }; extern int GetFileInformation () asm; extern int EndOfFile() asm; extern int SWriteByte() asm; extern int XSWriteByte() asm; extern int SBlockWrite() asm; extern int XSBlockWrite() asm; extern int SReadByte() asm; extern int XSReadByte() asm; extern int BytesOutstanding() asm; extern int XBytesOutstanding() asm; extern int XFindInput() asm; extern int XFindOutput() asm; extern int XCloseStream() asm; extern int XSFlushOutput() asm; #define ZOBUFSIZ 4096 static char zobuf[ZOBUFSIZ]; int zohandle = NOFILE, zosize = 0; Buffer(stream) int stream; /* select this stream to be buffered */ { if (zohandle != NOFILE) BFlush(zohandle); zohandle = stream; zosize = 0; } BFlush(stream) int stream; { if (stream == zohandle) { if (zosize) { XSBlockWrite(stream, zosize, zobuf); zosize = 0; } } XSFlushOutput(stream); } BWrite(stream, num, data) int stream, num; char *data; { if (stream == zohandle) { while (num--) { zobuf[zosize++] = *data++; if (zosize >= ZOBUFSIZ) BFlush(stream); } } else XSBlockWrite(stream, num, data); } /***************************************************************/ /* Z K S E L F -- Kill Self: log out own job, if possible. */ /***************************************************************/ zkself() { return(0); } /******************************************************/ /* Z O P E N I -- Open an existing file for input. */ /******************************************************/ zopeni(n,name) int n; char *name; { debug(F111," zopeni",name,n); debug(F101," fp","", fp[n]); if (chkfn(n) != 0) return(0); isout[n] = 0; if (n == ZSYSFN) { /* Input from a system function? */ debug(F110," invoking zxcmd",name,0); return(zxcmd(name)); /* Try to fork the command */ } if (n == ZSTDIO) { /* Standard input? */ /* no easy way to check in panos ? if (isatty(0)) { ermsg("Terminal input not allowed"); return(0); } */ fp[ZIFILE] = XFindInput("INPUT:", 6); return(1); } fp[n] = XFindInput(name, strlen(name)); isout[n] = 0; debug(F111," zopeni", name, fp[n]); if (fp[n] < 0) { perror("zopeni"); fp[n] = NOFILE; } return(1); } /**************************************************/ /* Z O P E N O -- Open a new file for output. */ /**************************************************/ zopeno(n,name) int n; char *name; { if (chkfn(n)) return(0); isout[n] = 1; if (n == ZCTERM) { fp[ZOFILE] = XFindOutput("VDU:", 4); return(1); } if (n == ZSTDIO) { fp[ZOFILE] = XFindOutput("OUTPUT:", 7); return(1); } fp[n] = XFindOutput(name, strlen(name)); if (n == ZOFILE) Buffer(fp[n]); if (fp[n] < 0) { perror("zopeno can't open"); fp[n] = NOFILE; } return((fp[n] >= 0) ? 1 : 0); } /********************************************/ /* Z C L O S E -- Close the given file. */ /********************************************/ zclose(n) int n; { if (chkfn(n) < 1) return(0); /* Check range of n */ if ((n == ZIFILE) && fp[ZSYSFN]) { zclosf(); return(1); } if (fp[n] >= 0) { if (isout[n]) { BFlush(fp[n]); } XCloseStream(fp[n]); } fp[n] = NOFILE; isout[n] = 0; return(1); } /************************************************************************/ /* Z C H I N -- Get a character from the input file. */ /* Returns -1 if EOF, 0 otherwise with character returned in argument */ /************************************************************************/ zchin(n,c) int n; char *c; { int a; if (chkfn(n) < 1) return(-1); if (EndOfFile(fp[n]) == 1) return(-1); a = SReadByte(fp[n]); if (a < 0) return(-1); *c = a & 0377; return(0); } /****************************************************************/ /* Z S O U T -- Write a string to the given file, buffered. */ /****************************************************************/ zsout(n,s) int n; char *s; { if (chkfn(n) < 1) return(-1); BWrite(fp[n], strlen(s), s); return(0); } /***************************************************************************/ /* Z S O U T L -- Write string to file, with line terminator, buffered */ /***************************************************************************/ zsoutl(n,s) int n; char *s; { if (chkfn(n) < 1) return(-1); zsout(n,s); zchout(n,NL); return(0); } /**************************************************************/ /* Z S O U T X -- Write x characters to file, unbuffered. */ /**************************************************************/ zsoutx(n,s,x) int n, x; char *s; { BWrite(fp[n], x, s); BFlush(fp[n]); return(0); } /***************************************************************************/ /* Z C H O U T -- Add a character to the given file. */ /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */ /***************************************************************************/ zchout(n,c) int n; char c; { BWrite(fp[n], 1, &c); return(0); } /******************************************************************/ /* C H K F N -- Internal function to verify file number is ok */ /* */ /* Returns: */ /* -1: File number n is out of range */ /* 0: n is in range, but file is not open */ /* 1: n in range and file is open */ /******************************************************************/ chkfn(n) int n; { switch (n) { case ZCTERM: case ZSTDIO: case ZIFILE: case ZOFILE: case ZDFILE: case ZTFILE: case ZPFILE: case ZSFILE: case ZSYSFN: break; default: debug(F101,"chkfn: file number out of range","",n); return(-1); } return( (fp[n] == NOFILE) ? 0 : 1 ); } /************************************************************************/ /* Z C H K I -- Check if input file exists and is readable */ /* */ /* Returns: */ /* >= 0 if the file can be read (returns the size). */ /* -1 if file doesn't exist or can't be accessed, */ /* -2 if file exists but is not readable (e.g. a directory file). */ /* -3 if file exists but protected against read access. */ /* */ /* */ /* For Berkeley Unix, a file must be of type "regular" to be readable. */ /* Directory files, special files, and symbolic links are not readable. */ /************************************************************************/ struct FileData {int loadaddr, execaddr, length, attrib;}; struct BTim {int low, high;}; long zchki(name) char *name; { struct FileData fileinfo; struct BTim timeinfo; int rc; fileinfo.length = -1; rc = GetFileInformation(&fileinfo, &timeinfo, name, strlen(name)); if (rc == 2) return(-2); if (rc < 0) return(-1); return(fileinfo.length); } /****************************************************************************/ /* Z C H K O -- Check if output file can be created */ /* */ /* Returns -1 if write permission for the file would be denied, 0 otherwise.*/ /****************************************************************************/ zchko(name) char *name; { return(0); } /*********************************************/ /* Z D E L E T -- Delete the named file. */ /*********************************************/ zdelet(name) char *name; { char cmdstr [512]; char *prefix, *suffix; char *cp; prefix = DELCMD; suffix = name; if (prefix == NULL || *prefix == '\0') return(0); for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ; while (*cp++ = *suffix++) ; system(cmdstr); return(1); } /*******************************************************************/ /* Z R T O L -- Convert remote filename into local form */ /* For PANOS, this means changing dots into dashes. */ /*******************************************************************/ editfname(s,oldc,newc,newlast) char *s; char oldc,newc,newlast; /* changes occurrences of oldc in string s to newc, except for */ /* last occurrence which gets changed to newlast */ { char *p,*pos; pos = 0; for (p = s; *p; ++p) if (*p == oldc) { *p = newc; pos = p; } if (pos) *pos = newlast; } zrtol(remote,local) char *remote,*local; { char *ans = local; while (*local++ = *remote++); editfname(ans, '-', '=', '='); editfname(ans, '.', '_', '-'); editfname(ans, '/', '.', '.'); } /*****************************************************************/ /* Z L T O R -- Local TO Remote */ /* Convert filename from local format to common (remote) form. */ /*****************************************************************/ zltor(local,remote) char *local, *remote; { char *ans = remote; while (*remote++ = *local++); editfname(ans, '/', '=', '='); editfname(ans, '.', '/', '/'); editfname(ans, '-', '-', '.'); } /***************************************/ /* Z C H D I R -- Change directory */ /***************************************/ zchdir(dirnam) char *dirnam; { char cmdstr [512]; char *prefix, *suffix; char *cp; prefix = CWDCMD; suffix = dirnam; if (prefix == NULL || *prefix == '\0') return(0); for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ; while (*cp++ = *suffix++) ; system(cmdstr); return(1); } /************************************************************/ /* Z H O M E -- Return pointer to user's home directory */ /************************************************************/ static char *myhome = "&"; char *zhome() { return(myhome); } /****************************************************************************/ /* Z X C M D -- Run a system command so its output can be read like a file */ /****************************************************************************/ zxcmd(comand) char *comand; { char *redirect = " -output kermtmp-tmp"; char cmdstr [512]; char *prefix, *suffix; char *cp; prefix = comand; suffix = redirect; if (prefix == NULL || *prefix == '\0') return(0); for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ; while (*cp++ = *suffix++) ; fp[ZSYSFN] = XFindOutput("kermtmp-tmp", 11); XCloseStream(fp[ZSYSFN]); fp[ZSYSFN] = NOFILE; /* ensure it is empty in case not written to! */ system(cmdstr); fp[ZIFILE] = fp[ZSYSFN] = XFindInput("kermtmp-tmp", 11); return(1); } /****************************************************************************/ /* Z C L O S F - wait for the child fork to terminate and close the pipe. */ /****************************************************************************/ zclosf() { if (fp[ZSYSFN] > 0) XCloseStream(fp[ZSYSFN]); fp[ZIFILE] = fp[ZSYSFN] = NOFILE; return(1); } /****************************************************************************/ /* Z X P A N D -- Expand a wildcard string into an array of strings */ /* */ /* Returns the number of files that match fn1, with data structures set up */ /* so that first file (if any) will be returned by the next znext() call. */ /****************************************************************************/ static int countwild, bfptr; static char namebuff[4096]; addfn(fn, len, arg) char *fn; int len, arg; { int rslt; while (namebuff[bfptr++] = *fn++) ; rslt = 0; /********************************************************************/ /* we want to pass this to be called from Modula-2, which doesn't */ /* expect to have to unwind the stack: this is horrible. */ /********************************************************************/ asm { MOVD rslt, 0; EXIT #0; RXP #12; } } extern int Expand() asm; zxpand(fn) char *fn; { int i; bfptr = 0; countwild = Expand(fn, strlen(fn), &addfn, /* state arg = */ 42, /* target is dir = false */ 0); namebuff[bfptr] = '\0'; bfptr = 0; return(countwild); } /**************************************************************************/ /* Z N E X T -- Get name of next file from list created by zxpand(). */ /* */ /* Returns >0 if there's another file, with its name copied into the */ /* arg string, or 0 if no more files in list. */ /**************************************************************************/ znext(fn) char *fn; { int i = 0; char *thisone; if (countwild-- > 0) { if (namebuff[bfptr] == '\0') { printf("Internal error: eos in znext\n"); return(0); } thisone = &namebuff[bfptr]; while (namebuff[bfptr++]) ; strcpy(fn, thisone); return(1); } else return(0); } /*******************************************************/ /* Z N E W N -- Make a new name for the given file */ /*******************************************************/ znewn(fn,s) char *fn, **s; { static char buf[256]; int i = 0; while (buf[i] = fn[i]) i++; *s = buf; } <<< acpmai.c >>> char *versio = "Panos-Kermit (from C-Kermit 4C(052)) 26 Mar 86"; /* C K P M A I -- Panos-C-Kermit Main program */ /* Authors: Frank da Cruz, Bill Catchings, Jeff Damens; Columbia University Center for Computing Activities, 1984-85. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* The Kermit file transfer protocol was developed at Columbia University. It is named after Kermit the Frog, star of the television series THE MUPPET SHOW; the name is used by permission of Henson Associates, Inc. "Kermit" is also Celtic for "free". */ #include "ckcker.h" #include "ckcdeb.h" /* Text message definitions.. each should be 256 chars long, or less. */ char *hlptxt = "Kermit Server Commands:\n\n\ GET filespec REMOTE CWD [directory] REMOTE SPACE [dir]\n\ SEND filespec REMOTE DIR [filespec] REMOTE HOST command\n\ FINISH REMOTE DELETE filespec REMOTE WHO [user]\n\ REMOTE HELP REMOTE TYPE filespec BYE\n\n"; char *srvtxt = "\n\ Panos-C-Kermit server starting.\n\n\ Return to your local machine by typing its escape sequence;\n\ issue further commands from there;\n\ to shut down the Panos-Kermit server, use command BYE\n\ or FINISH then re-CONNECT.\n\n"; /* Declarations for Send-Init Parameters */ int spsiz = DSPSIZ, /* Biggest packet size we can send */ rpsiz = DRPSIZ, /* Biggest we want to receive */ timint = DMYTIM, /* Timeout interval I use */ rtimo = URTIME, /* Timeout I want you to use */ timef = 0, /* Flag to override what you ask */ npad = MYPADN, /* How much padding to send */ mypadn = MYPADN, /* How much padding to ask for */ chklen = 1, /* Length of block check */ bctr = 1, /* Block check type requested */ bctu = 1, /* Block check type used */ ebq = MYEBQ, /* 8th bit prefix */ ebqflg = 0, /* 8th-bit quoting flag */ rpt = 0, /* Repeat count */ rptq = MYRPTQ, /* Repeat prefix */ rptflg = 0, /* Repeat processing flag */ capas = 0; /* Capabilities */ char padch = MYPADC, /* Padding character to send */ mypadc = MYPADC, /* Padding character to ask for */ seol = MYEOL, /* End-Of-Line character to send */ eol = MYEOL, /* End-Of-Line character to look for */ ctlq = CTLQ, /* Control prefix in incoming data */ myctlq = CTLQ; /* Outbound control character prefix */ /* Packet-related variables */ int pktnum = 0, /* Current packet number */ prvpkt = -1, /* Previous packet number */ sndtyp, /* Type of packet just sent */ size, /* Current size of output pkt data */ osize, /* Previous output packet data size */ maxsize, /* Max size for building data field */ spktl; /* Length packet being sent */ char sndpkt[MAXPACK*2], /* Entire packet being sent */ recpkt[RBUFL], /* Packet most recently received */ data[MAXPACK+4], /* Packet data buffer */ srvcmd[MAXPACK*2], /* Where to decode server command */ *srvptr, /* Pointer to above */ mystch = SOH, /* Outbound packet-start character */ stchr = SOH; /* Incoming packet-start character */ /* File-related variables */ char filnam[50]; /* Name of current file. */ int nfils; /* Number of files in file group */ long fsize; /* Size of current file */ /* Communication line variables */ char ttname[50]; /* Name of communication line. */ int parity, /* Parity specified, 0,'e','o',etc */ flow, /* Flow control, 1 = xon/xoff */ speed = -1, /* Line speed */ turn = 0, /* Line turnaround handshake flag */ turnch = XON, /* Line turnaround character */ duplex = 0, /* Duplex, full by default */ escape = 034, /* Escape character for connect */ delay = DDELAY, /* Initial delay before sending */ mdmtyp = 0; /* Modem type (initially none) */ /* Statistics variables */ long filcnt, /* Number of files in transaction */ flci, /* Characters from line, current file */ flco, /* Chars to line, current file */ tlci, /* Chars from line in transaction */ tlco, /* Chars to line in transaction */ ffc, /* Chars to/from current file */ tfc; /* Chars to/from files in transaction */ int tsecs; /* seconds for transaction */ /* Flags */ int deblog = 0, /* Flag for debug logging */ pktlog = 0, /* Flag for packet logging */ seslog = 0, /* Session logging */ tralog = 0, /* Transaction logging */ displa = 0, /* File transfer display on/off */ stdouf = 0, /* Flag for output to stdout */ xflg = 0, /* Flag for X instead of F packet */ hcflg = 0, /* Doing Host command */ fncnv = 1, /* Flag for file name conversion */ binary = 0, /* Flag for binary file */ warn = 0, /* Flag for file warning */ quiet = 0, /* Be quiet during file transfer */ local = 0, /* Flag for external tty vs stdout */ server = 0, /* Flag for being a server */ cnflg = 0, /* Connect after transaction */ cxseen = 0, /* Flag for cancelling a file */ czseen = 0; /* Flag for cancelling file group */ /* Variables passed from command parser to protocol module */ char parser(); /* The parser itself */ char sstate = 0; /* Starting state for automaton */ char *cmarg = ""; /* Pointer to command data */ char *cmarg2 = ""; /* Pointer to 2nd command data */ char **cmlist; /* Pointer to file list in argv */ /* Miscellaneous */ char **xargv; /* Global copies of argv */ int xargc; /* and argc */ extern char *dftty; /* Default tty name from ckx???.c */ extern int dfloc; /* Default location: remote/local */ extern int dfprty; /* Default parity */ extern int dfflow; /* Default flow control */ /* M A I N -- C-Kermit main program */ main(argc,argv) int argc; char **argv; { char *strcpy(); /* Do some initialization */ xargc = argc; /* Make global copies of argc */ xargv = argv; /* ...and argv. */ sstate = 0; /* No default start state. */ strcpy(ttname,dftty); /* Set up default tty name. */ local = dfloc; /* And whether it's local or remote. */ parity = dfprty; /* Set initial parity, */ flow = dfflow; /* and flow control. */ speed = dfbaudr(); /* Ask BBC MOS for baud rate */ /* Look for a UNIX-style command line... */ if (argc > 1) { /* Command line arguments? */ concb(0); /* Tim's bit */ sstate = cmdlin(); /* Yes, parse. */ if (sstate) { proto(); /* Take any requested action, then */ if (!quiet) conoll(""); /* put cursor back at left margin, */ if (cnflg) conect(); /* connect if requested, */ doexit(GOOD_EXIT); /* and then exit with status 0. */ } } /* If no action requested on command line, enter interactive parser */ cmdini(); /* Initialize command parser */ while(sstate = parser()) { /* Loop getting commands. */ if (sstate) proto(); /* Enter protocol if requested. */ } } <<< acpmis.c >>> #include "time.h" extern char *CWDCMD; extern int OsByte() asm; extern XSWriteByte() asm; extern int RawFrig; extern msleep(); /* from ckptio */ gettimeofday(time_now, time_zone) timeval *time_now; int *time_zone; { XBinaryTime(time_now); *time_zone = 0; } unsigned int timerdiff(ts, tf) timeval ts, tf; { /* * Returns difference(in centi-seconds) between 2 time * stamp records. NB uses simplified double-precision * algorithm: ts is start time; tf is finishing time, * assumed greater than ts. */ #define MAX_U_INT (unsigned int) 0xFFFFFFFF unsigned int diff; if(tf.high = ts.high) diff =(tf.low - ts.low); /* in centi-seconds */ else if((tf.high > ts.high + 1) || (tf.low > ts.low)) diff = MAX_U_INT; /* vast difference */ else diff =(tf.low +(MAX_U_INT - ts.low) + 1); return diff; } static timeval epoch; rtimer() { int timezone; gettimeofday(&epoch, &timezone); } int gtimer() { timeval now; int timezone; gettimeofday(&now, &timezone); return (timerdiff(now, epoch) / 100); } sleep(secs) int secs; { msleep(secs * 1000); } eraseleft() { XSWriteByte(RawFrig, 127); } beep() { XSWriteByte(RawFrig, 7); } /***************************************/ /* C H D I R -- Change directory */ /***************************************/ chdir(dirnam) char *dirnam; { char cmdstr [512]; char *prefix, *suffix; char *cp; prefix = CWDCMD; suffix = dirnam; for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ; while (*cp++ = *suffix++) ; system(cmdstr); return(0); } setbaud(speed) { int newx, newy, cbit, fx; switch (speed) { case 75: fx = 1; break; case 150: fx = 2; break; case 300: fx = 3; break; case 1200: fx = 4; break; case 2400: fx = 5; break; case 4800: fx = 6; break; case 9600: fx = 7; break; case 19200: fx = 8; break; default: fx = 7; break; } OsByte(&newx, &newy, &cbit, 7, fx, 0); OsByte(&newx, &newy, &cbit, 8, fx, 0); } baudint(newx) { switch (newx&7) { case 7: return(75); case 3: return(150); case 5: return(300); case 1: return(1200); case 6: return(2400); case 2: return(4800); case 4: return(9600); case 0: return(19200); default: return(-1); } } dfbaudr () { int spare, newx, newy, cbit, fx7code, fx8code; OsByte(&newx, &newy, &cbit, 7, 1, 0); /* read old baud by changing it */ fx7code = ((newx>>3)&7); OsByte(&newx, &newy, &cbit, 8, 1, 0); /* read old baud by changing it */ fx8code = (newx&7); if (fx7code != fx8code) { printf("Warning - split baud rates not supported - %d:%d\n\ Please set speed immediately\n", baudint(fx7code), baudint(fx8code)); } else { setbaud(baudint(fx7code)); } return(baudint(fx7code)); } DirtyFlush(buffer) int buffer; { int newx, newy, cbit; OsByte(&newx, &newy, &cbit, 21, buffer, 0); } fx(a,x,y) int a,x,y; { int newx, newy, cbit; OsByte(&newx, &newy, &cbit, a, x, y); } static char escape_char; initrs() { int x, y, c; /* This should be in ttvt in ckptio - should also be undone afterwards */ fx(204,0,0); fx(2,2,0); fx(3,0,0); fx(181,1,0); fx(202,48,0); fx(118,0,0); OsByte(&x, &y, &c, 220, 255, 0); escape_char = x; } termrs() { int x, y, c; OsByte(&x, &y, &c, 220, escape_char, 0); } testbf(buff, val) int buff; int *val; { #define keybf 0 #define rs423inbf 1 #define rs423outbf 2 int newx, newy, cbit; OsByte(&newx, &newy, &cbit, 145, buff, 0); if (!cbit) { /* not empty */ *val = newy&255; return(1); } return(0); } putinbf(buff, val) int buff, val; { int newx, newy, cbit; OsByte(&newx, &newy, &cbit, 153, buff, val); return(1); } int nrsbuf() { /* returns number of chars in RS423 input buffer */ int newx, newy, cbit; OsByte(&newx, &newy, &cbit, 128, 254, 255); return(newx); } get_posn(x,y) int *x,*y; { /* returns Beeb text cursor coords */ int c; OsByte(x, y, &c, 134, 0, 0); } <<< acpscr.c >>> char *loginv = "Panos Script Command (not yet implemented) 19 Dec 85"; /* C K P S C R -- Login script for logging onto remote system */ /* P A N O S -- temp dummy */ /* L O G I N -- Login to remote system */ login(cmdstr) char *cmdstr; { printf("\nThe script command has not yet been implemented\n"); printf("It needs a Panos feature which is not available in\n"); printf("versions 1.2 or before.\n\n"); return(-2); } <<< acpsig.c >>> /* ckpsig-c */ #include "signal.h" #include "time.h" #include "stdio.h" extern int XSetEventStatus() asm; extern int XDeclareEventHandler() asm; extern int OsWord() asm; extern int Signal() asm; static int GlobalEnv; static int LastSignal; #define NIL 0 #define OFF 0 #define ON 1 int default_SIGINT() { return(Signal(-SIGINT, NIL)); } int default_SIGQUIT() { return(Signal(-SIGQUIT, NIL)); } int default_SIGALARM(){ return(Signal(-SIGALARM, NIL)); } int default_SIGPROF() { return(Signal(-SIGPROF, NIL)); } int default_SIGothers(){ return(Signal(-LastSignal, NIL)); } static int (*handler_SIGINT)() = &default_SIGINT; static int (*handler_SIGQUIT)() = &default_SIGQUIT; static int (*handler_SIGALARM)() = &default_SIGALARM; /* SIGVTALRM equated to SIGALRM */ static int (*handler_SIGPROF)() = &default_SIGPROF; static int (*handler_SIGothers)() = &default_SIGothers; static int AlarmType, AlarmInterval; internal_handler (code, ed1, ed2, handle, env) int code,ed1,ed2,handle,env; { timeval time_buff, time_now; int time_zone; int (*user)(); LastSignal = code; GlobalEnv = env; /* For attempts to unwind by default (local) handlers */ user = 0; if (code == SIGQUIT) user = handler_SIGQUIT; if (code == SIGINT) user = handler_SIGINT; if (user) { (*user)(); asm { EXIT #0; RXP #20; } } if (code == SIGALARM) { if (AlarmType == SIGPROF) { (*handler_SIGPROF)(); /* reset the clock */ time_buff.low = AlarmInterval; time_buff.high = -1; OsWord(4, &time_buff); asm { EXIT #0; RXP #20; }; } else { (*handler_SIGALARM) (); asm { EXIT #0; RXP #20; }; } } /* Remaining handlers through one routine (temp bodge) */ user = handler_SIGothers; if (user) { (*user)(); asm { EXIT #0; RXP #20; } } } int ckpsig(SIGtype, f) int SIGtype, (*f)(); { if (SIGtype == SIGINT) handler_SIGINT = f; else if (SIGtype == SIGQUIT) handler_SIGQUIT = f; else if (SIGtype == SIGALARM) handler_SIGALARM = f; else if (SIGtype == SIGPROF) handler_SIGPROF = f; else handler_SIGothers= f; if (SIGtype < 10) { XDeclareEventHandler(&internal_handler,SIGtype, 2 /*call this only*/, CSignal); } if ((SIGtype == SIGINT) || (SIGtype == SIGQUIT)) { XSetEventStatus(SIGQUIT, ON); } } alarm(seconds) int seconds; { int rc, upcount; static timeval time_buff; if (seconds == 0) { rc = XSetEventStatus(SIGALARM, OFF); handler_SIGALARM = default_SIGALARM; } else { rc = XSetEventStatus(SIGALARM, ON); upcount = 0-(seconds*100); time_buff.low = upcount; time_buff.high = -1; AlarmType = SIGALARM; rc = OsWord(4, &time_buff); } } profile (millisecs) int millisecs; { int rc, upcount; static timeval time_buff; if (millisecs == 0) { rc = XSetEventStatus(SIGALARM, OFF); handler_SIGPROF = &default_SIGPROF; } else { AlarmInterval = -(millisecs/10); /* Convert to centisecs */ upcount = AlarmInterval; time_buff.low = upcount; time_buff.high = -1; AlarmType = SIGPROF; rc = XSetEventStatus(SIGALARM, ON); rc = OsWord(4, &time_buff); } } <<< acptio.c >>> /* C K P T I O */ #include "signal-h" /* Poxy version!!! */ #include "time-h" extern int XSetEventStatus() asm; #define SIGon 1 #define SIGoff 0 extern XStandardTime() asm; extern XCloseStream() asm; extern XSFlushOutput() asm; extern int XSWriteByte() asm; extern int XSBlockWrite() asm; extern int XSBlockRead() asm; extern int XSReadByte() asm; extern int XBytesOutstanding() asm; extern int XFindInput() asm; extern int XFindOutput() asm; char *ckxv = "Panos tty I/O, July 23 1985"; char *ckxsys = "Acorn Computers PANOS"; /* C-Kermit interrupt, terminal control & i/o functions for Panos */ /* Author: Graham Toal & Richard Cownie, VLSI Tools Group (graham%acorn@ukc) Copyright (C) 1986, Acorn Computers Plc Based on originial code & interface by: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* Variables available to outside world: dftty -- Pointer to default tty name string, like "/dev/tty". dfloc -- 0 if dftty is console, 1 if external line. dfprty -- Default parity dfflow -- Default flow control ckxech -- Flag for who echoes console typein: 1 - The program (system echo is turned off) 0 - The system (or front end, or terminal). functions that want to do their own echoing should check this flag before doing so. backgrd -- Flag indicating program executing in background - not applicable Functions for assigned communication line (either external or console tty): ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access. ttclos() -- Close & reset the tty, releasing any access lock. tthang() -- Hangup phone line ttsndb() -- Send a break signal ttpkt(speed,flow) -- Put the tty in packet mode and set the speed. ttvt(speed,flow) -- Put the tty in virtual terminal mode. or in DIALING or CONNECTED modem control state. ttres() -- Restore terminal to normal mode ttinl(dest,max,timo) -- Timed read line from the tty. ttinc(timo) -- Timed read character from tty. ttchk() -- See how many characters in tty input buffer. ttxin(n,buf) -- Read n characters from tty (untimed). ttol(string,length) -- Write a string to the tty. ttoc(c) -- Write a character to the tty. ttflui() -- Flush tty input buffer. */ /* Functions for console terminal: congm() -- Get console terminal modes. concb(esc) -- Put the console in single-character wakeup mode with no echo. conbin(esc) -- Put the console in binary (raw) mode. conres() -- Restore the console to mode obtained by congm(). conoc(c) -- Unbuffered output, one character to console. conol(s) -- Unbuffered output, null-terminated string to the console. conoll(s) -- Unbuffered output, string + CR LF to the console. conola(s) -- Unbuffered output, array of strings to the console. conxo(n,s) -- Unbuffered output, n characters to the console. conchk() -- Check if characters available at console (bsd 4.2). Check if escape char (^\) typed at console (System III/V). coninc(timo) -- Timed get a character from the console. conin() -- untimed get from console (new) conint() -- Enable terminal interrupts on the console if not background. connoi() -- Disable terminal interrupts on the console if not background. Time functions msleep(m) -- Millisecond sleep ztime(&s) -- Return pointer to date/time string */ /* Declarations */ #include char *dftty = "RS423:"; /* dftty is the device name of the default device for file transfer */ int dfloc = 1; /* dfloc: 0 if dftty is the user's console terminal, 1 if an external line */ int dfprty = 0; /* Parity (0 = none) */ int dfflow = 1; /* Xon/Xoff flow control */ int backgrd = 0; /* Assume in foreground (no '&' ) */ int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */ /* PANOS - changed from 0 to -1 */ int hostin = -1; int hostout = -1; /* Handles to RS423: in each direction. */ int OldMode; /* old ckxech */ int ConsoleIn = -1; int ConsoleOut = -1; /* Currently selected console IO streams */ int OldConsoleIn; /* Save-variable for changing stdin from raw to cooked... */ int rawkb; int filteredkb; /* handles to raw & filtered kb streams */ static int conif = 0; conesc = 0; /* conesc - has been typed? */ /*******************************************************/ /* T T O P E N -- Open a tty for exclusive access. */ /* Returns 0 on success, -1 on failure. */ /*******************************************************/ ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; { /* If called with lcl < 0, sets value of lcl as follows: 0: the terminal named by ttname is the job's controlling terminal. 1: the terminal named by ttname is not the job's controlling terminal. */ hostin = XFindInput(ttname, strlen(ttname)); hostout = XFindOutput(ttname, strlen(ttname)); if ((hostin > 0) && (hostout > 0)) { *lcl = 1; /* RS423: <> TT: */ return(0); } else { return(-1); } } /*********************************************************/ /* T T C L O S -- Close the TTY, releasing any lock. */ /*********************************************************/ ttclos() { if (hostin >= 0) XCloseStream(hostin); if (hostout >= 0) XCloseStream(hostout); } /*************************************/ /* T T H A N G -- Hangup phone line */ /*************************************/ tthang() {} /*******************************************************/ /* T T R E S -- Restore terminal to "normal" mode. */ /*******************************************************/ ttres() {} /*****************************************************************/ /* T T P K T -- Condition the communication line for packets. */ /* or for modem dialing */ /* If called with speed > -1, also set the speed. */ /* Returns 0 on success, -1 on failure. */ /*****************************************************************/ ttpkt(speed,flow) int speed, flow; { if (speed > -1) setbaud(speed); return(0); } /*************************************************************************/ /* T T V T -- Condition communication line for use as virtual terminal */ /*************************************************************************/ ttvt(speed,flow) int speed, flow; { if (speed > -1) setbaud(speed); } /********************************************/ /* T T F L U I -- Flush tty input buffer */ /********************************************/ ttflui() { /* loop around testing XBytesOutstanding() until none left */ while (XBytesOutstanding(hostin) > 0) XSReadByte(hostin); } /***********************************************/ /* C O N I N T -- Console Interrupt setter */ /***********************************************/ esctrp() { /* trap console escapes */ conesc = 1; signal(SIGQUIT,0); } conint(f) int (*f)(); { /* Set an interrupt trap. */ signal(SIGINT, &esctrp); /* console escape in pkt modes */ conesc = 0; /* clear out pending escapes */ signal(SIGQUIT, f); /* Function to trap to. */ conif = 1; /* Flag console interrupts on. */ } /*******************************************************/ /* C O N N O I -- Reset console terminal interrupts */ /*******************************************************/ connoi() { signal(SIGQUIT, 0); conif = 0; } /****************************************************************************/ /* T T C H K -- Tell how many characters are waiting in tty input buffer */ /****************************************************************************/ ttchk() { return(XBytesOutstanding(hostin)); } /***********************************************************/ /* T T X I N -- Get n characters from tty input buffer */ /***********************************************************/ ttxin(n,buf) int n; char *buf; { /* XSBlockRead(hostin, n, buf); may not work in PANOS v1.1 */ while (n-- > 0) XSReadByte(hostin, *buf++); } /*******************************************************/ /* T T O L -- Similar to "ttinl", but for writing. */ /*******************************************************/ ttol(s,n) int n; char *s; { /* XSBlockWrite(hostout, n, s); may not work in PANOS v1.1 */ while (n-- > 0) XSWriteByte(hostout, *s++); XSFlushOutput(hostout); } /***************************************************************/ /* T T O C -- Output a character to the communication line */ /***************************************************************/ ttoc(c) char c; { XSWriteByte(hostout, c); XSFlushOutput(hostout); } /**************************************************************************/ /* T T I N L -- Read a record (up to break character) from comm line. */ /**************************************************************************/ ttinl(dest,max,timo,eol) int max,timo,eol; char *dest; { /* If no break character encountered within "max", return "max" characters, with disposition of any remaining characters undefined. Otherwise, return the characters that were read, including the break character, in "dest" and the number of characters read as the value of function, or 0 upon end of file, or -1 if an error occurred. Times out & returns error if not completed within "timo" seconds. */ int zone, ch, i, j, n, ngot = 0; timeval start,now; if (timo) gettimeofday(&start, &zone); if (max == 0) return(0); for (;;) { for (i = 0; i < 16; i++) { n = XBytesOutstanding(hostin); for (j = 0; j < n; j++) { if ((dest[ngot++] = XSReadByte(hostin)) == eol) return(ngot); if (ngot >= max) return(ngot); } } if (timo) { gettimeofday(&now, &zone); if (timerdiff(start, now) > (100*timo)) return(-1); /* timed out */ } } } /****************************************************************/ /* T T I N C -- Read a character from the communication line */ /****************************************************************/ ttinc(timo) int timo; { int zone,j; timeval start,now; if (timo) gettimeofday(&start, &zone); for(;;) { for(j = 0; j < 32; j++) { if (XBytesOutstanding(hostin)) return(XSReadByte(hostin)); /* got ch */ } if (timo) { gettimeofday(&now, &zone); if (timerdiff(start, now) > (100*timo)) return(-1); /* timed out */ } } } /******************************************/ /* T T S N D B -- Send a BREAK signal */ /******************************************/ ttsndb() {} /******************************************************/ /* M S L E E P -- Millisecond version of sleep(). */ /******************************************************/ msleep(m) int m; { int zone; timeval start,now; gettimeofday(&start, &zone); for(;;) { gettimeofday(&now, &zone); if ((10 * timerdiff(start, now)) > m) return(0); } } /********************************************/ /* Z T I M E -- Return date/time string */ /********************************************/ ztime(s) char **s; { static char timestring[32]; XStandardTime(timestring, 32); *s = timestring; } /************************************************/ /* C O N G M -- Get console terminal modes. */ /************************************************/ congm() { /* Saves current console mode, and establishes variables for switching between current (presumably normal) mode and other modes. */ /* Panos version does this by assigning stdout to local saved copy */ OldConsoleIn = ConsoleIn; OldMode = ckxech; } /***********************************************/ /* C O N C B -- Put console in cbreak mode. */ /***********************************************/ concb(esc) char esc; { ConsoleIn = XFindInput("RAWKB:", 6); ConsoleOut = XFindOutput("VDU:", 4); ckxech = 1; /* no echo */ return(0); } /*************************************************/ /* C O N B I N -- Put console in binary mode */ /*************************************************/ conbin(esc) char esc; { ConsoleIn = XFindInput("RAWKB:", 6); ConsoleOut = XFindOutput("VDU:", 4); ckxech = 1; /* No echo */ return(0); } /***************************************************/ /* C O N R E S -- Restore the console terminal */ /***************************************************/ conres() { ConsoleIn = OldConsoleIn; ckxech = OldMode; return(0); } /***************************************************************/ /* C O N O C -- Output a character to the console terminal */ /***************************************************************/ conoc(c) char c; { XSWriteByte(ConsoleOut, c); } /***************************************************************/ /* C O N X O -- Write x characters to the console terminal */ /***************************************************************/ conxo(x,s) char *s; int x; { XSBlockWrite(ConsoleOut, x, s); XSFlushOutput(ConsoleOut); } /*********************************************************/ /* C O N O L -- Write a line to the console terminal */ /*********************************************************/ conol(s) char *s; { conxo(strlen(s), s); } /*********************************************************************/ /* C O N O L A -- Write an array of lines to the console terminal */ /*********************************************************************/ conola(s) char *s[]; { int i; for (i=0; *s[i]; i++) conol(s[i]); } /*******************************************************/ /* C O N O L L -- Output a string followed by CRLF */ /*******************************************************/ conoll(s) char *s; { conol(s); conoc('\r'); conoc('\n'); } /***************************************************************/ /* C O N C H K -- Check if characters available at console */ /***************************************************************/ conchk() { if (conesc) { conesc = 0; return(1); } return(XBytesOutstanding(ConsoleIn)); } /*******************************************************/ /* C O N I N C -- Get a character from the console */ /*******************************************************/ coninc(timo) int timo; { int zone,j; timeval start,now; if (timo) gettimeofday(&start, &zone); for(;;) { for(j = 0; j < 32; j++) { if (conchk()) return(conin()); } if (timo) { gettimeofday(&now, &zone); if (timerdiff(start, now) > (100*timo)) return(-1); /* timed out */ } } } /*******************************************************/ /* C O N I N -- Get a character from the console */ /*******************************************************/ conin() { return(XSReadByte(ConsoleIn)); } <<< acpus3.c >>> /* C K U U S 3 -- "User Interface" for Unix Kermit, part 3 */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* SET and REMOTE commands; screen, debug, interrupt, and logging functions */ /* Includes */ #include "ckcdeb-h" #include #include #include "ckcker-h" #include "ckucmd-h" #include "ckuusr-h" /* Variables */ extern int size, spsiz, rpsiz, npad, timint, rtimo, speed, local, server, image, flow, displa, binary, fncnv, delay, parity, deblog, escape, xargc, turn, duplex, cxseen, czseen, nfils, ckxech, pktlog, seslog, tralog, stdouf, turnch, chklen, bctr, bctu, dfloc, mdmtyp, rptflg, ebqflg, warn, quiet, cnflg, timef, mypadn; extern long filcnt, tlci, tlco, ffc, tfc, fsize; extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv; extern char *cmarg, *cmarg2, **xargv, **cmlist; extern char stchr, mystch, sstate, padch, mypadc, eol, seol, ctlq; extern char filnam[], ttname[]; char *strcpy(); /* Declarations from cmd package */ extern char cmdbuf[]; /* Command buffer */ /* From main ckuser module... */ extern char line[100], *lp; /* Character buffer for anything */ extern char debfil[50], /* Debugging log file name */ pktfil[50], /* Packet log file name */ sesfil[50], /* Session log file name */ trafil[50]; /* Transaction log file name */ extern int tlevel; /* Take Command file level */ extern FILE *tfile[]; /* Array of take command fd's */ /* Keyword tables for SET commands */ /* Block checks */ struct keytab blktab[] = { "1", 1, 0, "2", 2, 0, "3", 3, 0 }; /* Duplex keyword table */ struct keytab dpxtab[] = { "full", 0, 0, "half", 1, 0 }; struct keytab filtab[] = { "display", XYFILD, 0, "names", XYFILN, 0, "type", XYFILT, 0, "warning", XYFILW, 0 }; int nfilp = (sizeof(filtab) / sizeof(struct keytab)); /* Send/Receive Parameters */ struct keytab srtab[] = { "end-of-packet", XYEOL, 0, "packet-length", XYLEN, 0, "pad-character", XYPADC, 0, "padding", XYNPAD, 0, "start-of-packet", XYMARK, 0, "timeout", XYTIMO, 0 }; int nsrtab = (sizeof(srtab) / sizeof(struct keytab)); /* Flow Control */ struct keytab flotab[] = { "none", 0, 0, "xon/xoff", 1, 0 }; int nflo = (sizeof(flotab) / sizeof(struct keytab)); /* Handshake characters */ struct keytab hshtab[] = { "bell", 007, 0, "cr", 015, 0, "esc", 033, 0, "lf", 012, 0, "none", 999, 0, /* (can't use negative numbers) */ "xoff", 023, 0, "xon", 021, 0 }; int nhsh = (sizeof(hshtab) / sizeof(struct keytab)); struct keytab fntab[] = { /* File naming */ "converted", 1, 0, "literal", 0, 0 }; struct keytab fttab[] = { /* File types */ "binary", 1, 0, "text", 0, 0 }; extern struct keytab mdmtab[] ; /* Modem types (in module ckdial.c) */ extern int nmdm; /* Parity keyword table */ struct keytab partab[] = { "even", 'e', 0, "mark", 'm', 0, "none", 0, 0, "odd", 'o', 0, "space", 's', 0 }; int npar = (sizeof(partab) / sizeof(struct keytab)); /* On/Off table */ struct keytab onoff[] = { "off", 0, 0, "on", 1, 0 }; /* D O P R M -- Set a parameter. */ /* Returns: -2: illegal input -1: reparse needed 0: success */ doprm(xx) int xx; { int x, y, z; char *s; switch (xx) { case XYEOL: /* These have all been moved to set send/receive... */ case XYLEN: /* Let the user know what to do. */ case XYMARK: case XYNPAD: case XYPADC: case XYTIMO: printf("...Use 'set send' or 'set receive' instead.\n"); printf("Type 'help set send' or 'help set receive' for more info.\n"); return(0); case XYLINE: if ((x = cmtxt("Device name",dftty,&s)) < 0) return(x); ttclos(); /* close old line, if any was open */ /** if (strcmp(ttname,dftty) == 0) local = dfloc; else local = 1; **/ local = -1; /* Let ttopen figure it out... */ if (ttopen(s,&local,mdmtyp) < 0 ) { /* Can we open the new line? */ perror("Sorry, can't open line"); return(-2); /* If not, give bad return */ } strcpy(ttname,s); /* OK, copy name into real place. */ if (!local) speed = -1; /* If remote, say speed unknown. */ debug(F111,"set line ",ttname,local); return(0); case XYCHKT: if ((y = cmkey(blktab,3,"","1")) < 0) return(y); if ((x = cmcfm()) < 0) return(x); bctr = y; return(0); case XYDEBU: return(seton(&deblog)); case XYDELA: y = cmnum("Number of seconds before starting to send","5",10,&x); debug(F101,"XYDELA: y","",y); return(setnum(&delay,x,y)); case XYDUPL: if ((y = cmkey(dpxtab,2,"","full")) < 0) return(y); if ((x = cmcfm()) < 0) return(x); duplex = y; return(0); case XYESC: y = cmnum("Decimal ASCII code for escape character","",10,&x); return(setcc(&escape,x,y)); case XYFILE: if ((y = cmkey(filtab,nfilp,"File parameter","")) < 0) return(y); switch (y) { int z; case XYFILD: /* Display */ y = seton(&z); if (y < 0) return(y); quiet = !z; return(0); case XYFILN: /* Names */ if ((x = cmkey(fntab,2,"how to handle filenames","converted")) < 0) return(x); if ((z = cmcfm()) < 0) return(z); fncnv = x; return(0); case XYFILT: /* Type */ if ((x = cmkey(fttab,2,"type of file","text")) < 0) return(x); if ((z = cmcfm()) < 0) return(z); binary = x; return(0); case XYFILW: /* Warning/Write-Protect */ return(seton(&warn)); default: printf("?unexpected file parameter\n"); return(-2); } case XYFLOW: /* Flow control */ if ((y = cmkey(flotab,nflo,"","xon/xoff")) < 0) return(y); if ((x = cmcfm()) < 0) return(x); flow = y; return(0); case XYHAND: /* Handshake */ if ((y = cmkey(hshtab,nhsh,"","none")) < 0) return(y); if ((x = cmcfm()) < 0) return(x); turn = (y > 0127) ? 0 : 1 ; turnch = y; return(0); case XYMODM: if ((x=cmkey(mdmtab,nmdm,"type of modem, direct means none","direct")) < 0) return(x); if ((z = cmcfm()) < 0) return(z); mdmtyp = x; return(0); case XYPARI: if ((y = cmkey(partab,npar,"","none")) < 0) return(y); if ((x = cmcfm()) < 0) return(x); parity = y; ebqflg = 1; /* Flag we want 8th-bit prefixing */ return(0); case XYPROM: if ((x = cmtxt("Program's command prompt","Panos-Kermit>",&s)) < 0) return(x); cmsetp(s); return(0); /* SET SEND/RECEIVE... */ case XYRECV: case XYSEND: if (xx == XYRECV) strcpy(line,"Parameter for inbound packets"); else strcpy(line,"Parameter for outbound packets"); if ((y = cmkey(srtab,nsrtab,line,"")) < 0) return(y); switch (y) { case XYEOL: y = cmnum("Decimal ASCII code for packet terminator","0",10,&x); if ((y = setcc(&z,x,y)) < 0) return(y); if (xx == XYRECV) eol = z; else seol = z; return(y); case XYLEN: y = cmnum("Maximum number of characters in a packet","90",10,&x); if ((y = setnum(&z,x,y)) < 0) return(y); if (xx == XYRECV) rpsiz = z; else spsiz = z; return(y); case XYMARK: y = cmnum("Decimal ASCII code for packet-start character","1",10,&x); if ((y = setcc(&z,x,y)) < 0) return(y); if (xx == XYRECV) stchr = z; else mystch = z; return(y); case XYNPAD: y = cmnum("How many padding characters for inbound packets","0",10,&x); if ((y = setnum(&z,x,y)) < 0) return(y); if (xx == XYRECV) npad = z; else mypadn = z; return(y); case XYPADC: y = cmnum("Decimal ASCII code for inbound pad character","0",10,&x); if ((y = setcc(&z,x,y)) < 0) return(y); if (xx == XYRECV) padch = z; else mypadc = z; return(y); case XYTIMO: y = cmnum("Interpacket timeout interval","5",10,&x); if ((y = setnum(&z,x,y)) < 0) return(y); if (xx == XYRECV) { timef = 1; timint = z; } else rtimo = z; return(y); } case XYSPEE: if (!local) { printf("\nSpeed setting can only be done on an external line\n"); printf("You must 'set line' before issuing this command\n"); return(0); } lp = line; sprintf(lp,"Baud rate for %s",ttname); if ((y = cmnum(line,"",10,&x)) < 0) return(y); if (y = (cmcfm()) < 0) return(y); y = chkspd(x); if (y < 0) printf("?Unsupported line speed - %d\n",x); else { speed = y; printf("%s: %d baud\n",ttname,speed); } return(0); default: if ((x = cmcfm()) < 0) return(x); printf("Not working yet - %s\n",cmdbuf); return(0); } } /* C H K S P D -- Check if argument is a valid baud rate */ chkspd(x) int x; { switch (x) { case 0: case 110: case 150: case 300: case 600: case 1200: case 1800: case 2400: case 4800: case 9600: return(x); default: return(-1); } } /* S E T O N -- Parse on/off (default on), set parameter to result */ seton(prm) int *prm; { int x, y; if ((y = cmkey(onoff,2,"","on")) < 0) return(y); if ((x = cmcfm()) < 0) return(x); *prm = y; return(0); } /* S E T N U M -- Set parameter to result of cmnum() parse. */ /* Call with x - number from cnum parse, y - return code from cmnum */ setnum(prm,x,y) int x, y, *prm; { debug(F101,"setnum","",y); if (y < 0) return(y); if (x > 94) { printf("\n?Sorry, 94 is the maximum\n"); return(-2); } if ((y = cmcfm()) < 0) return(y); *prm = x; return(0); } /* S E T C C -- Set parameter to an ASCII control character value. */ setcc(prm,x,y) int x, y, *prm; { if (y < 0) return(y); if ((x > 037) && (x != 0177)) { printf("\n?Not in ASCII control range - %d\n",x); return(-2); } if ((y = cmcfm()) < 0) return(y); *prm = x; return(0); } /* D O R M T -- Do a remote command */ dormt(xx) int xx; { int x; char *s, sbuf[50], *s2; if (xx < 0) return(xx); switch (xx) { case XZCWD: /* CWD */ if ((x = cmtxt("Remote directory name","",&s)) < 0) return(x); debug(F111,"XZCWD: ",s,x); *sbuf = NUL; s2 = sbuf; if (*s != NUL) { /* If directory name given, */ /* get password on separate line. */ if (tlevel > -1) { /* From take file... */ *line = NUL; if (fgets(sbuf,50,tfile[tlevel]) == NULL) ermsg("take file ends prematurely in 'remote cwd'"); debug(F110," pswd from take file",s2,0); } else { /* From terminal... */ printf(" Password: "); /* get a password */ while ( ( (x=coninc(0)) != NL) && (x != CR) ) { /* with no echo */ if ((x &= 0177) == '?') { printf("? Password of remote directory\n Password: "); s2 = sbuf; *sbuf = NUL; } else if (x == /*ESC*/HT) /* Mini command line editor... */ putchar(BEL); else if (x == BS || x == 0177) s2--; else if (x == 025) { s2 = sbuf; *sbuf = NUL; } else *s2++ = x; } *s2 = NUL; putchar('\n'); } s2 = sbuf; } else s2 = ""; debug(F110," password",s2,0); sstate = setgen('C',s,s2,""); return(0); case XZDEL: /* Delete */ if ((x = cmtxt("Name of remote file(s) to delete","",&s)) < 0) return(x); return(sstate = rfilop(s,'E')); case XZDIR: /* Directory */ if ((x = cmtxt("Remote directory or file specification","",&s)) < 0) return(x); return(sstate = setgen('D',s,"","")); case XZHLP: /* Help */ if (x = (cmcfm()) < 0) return(x); sstate = setgen('H',"","",""); return(0); case XZHOS: /* Host */ if ((x = cmtxt("Command for remote system","",&cmarg)) < 0) return(x); return(sstate = 'c'); case XZPRI: /* Print */ if ((x = cmtxt("Remote file(s) to print on remote printer","",&s)) < 0) return(x); return(sstate = rfilop(s,'S')); case XZSPA: /* Space */ if ((x = cmtxt("Confirm, or remote directory name","",&s)) < 0) return(x); return(sstate = setgen('U',s,"","")); case XZTYP: /* Type */ if ((x = cmtxt("Remote file specification","",&s)) < 0) return(x); return(sstate = rfilop(s,'T')); case XZWHO: if ((x = cmtxt("Remote user name, or carriage return","",&s)) < 0) return(x); return(sstate = setgen('W',s,"","")); default: if (x = (cmcfm()) < 0) return(x); printf("not working yet - %s\n",cmdbuf); return(-2); } } /* R F I L O P -- Remote File Operation */ rfilop(s,t) char *s, t; { if (*s == NUL) { printf("?File specification required\n"); return(-2); } debug(F111,"rfilop",s,t); return(setgen(t,s,"","")); } /* S C R E E N -- Screen display function */ /* screen(f,c,n,s) f - argument descriptor c - a character or small integer n - a long integer s - a string. Fill in this routine with the appropriate display update for the system. This version is for a dumb tty. */ screen(f,c,n,s) int f; long n; char c; char *s; { static int p = 0; /* Screen position */ static char digit = '.'; int len; /* Length of string */ char buf[80]; /* Output buffer */ len = strlen(s); /* Length of string */ if (!displa || quiet) { return; /* No update if display flag off */ } switch (f) { case SCR_FN: /* filename */ conoll(""); conol(s); conoc(SP); p = len + 1; return; case SCR_AN: /* as-name */ if (p + len > 75) { conoll(""); p = 0; } conol("=> "); conol(s); if ((p += (len + 3)) > 75) { conoll(""); p = 0; } return; case SCR_FS: /* file-size */ sprintf(buf,", Size: %ld",n); conoll(buf); p = 0; return; case SCR_XD: /* x-packet data */ conoll(""); conoll(s); p = 0; return; case SCR_ST: /* File status */ switch (c) { case ST_OK: /* Transferred OK */ if ((p += 5) > 75) { conoll(""); p = 0; } conoll(" [OK]"); p = 0; digit = '.'; return; case ST_DISC: /* Discarded */ if ((p += 12) > 75) { conoll(""); p = 0; } conoll(" [discarded]"); p = 0; digit = '.'; return; case ST_INT: /* Interrupted */ if ((p += 14) > 75) { conoll(""); p = 0; } conoll(" [interrupted]"); p = 0; digit = '.'; return; case ST_SKIP: /* Skipped */ conoll(""); conol("Skipping "); conoll(s); p = 0; digit = '.'; return; default: conoll("*** screen() called with bad status ***"); p = 0; return; } case SCR_PN: /* Packet number */ sprintf(buf,"%s: %ld",s,n); conol(buf); p += strlen(buf); return; case SCR_PT: /* Packet type or pseudotype */ if (c == 'Y') return; /* Don't bother with ACKs */ if (c == 'D') { /* Only show every 4th data packet */ if (n % 4) return; if (fsize) { c = (char) (ffc * 10 / fsize + (int) '0'); if (c != digit) digit = c; else c = '.'; } else c = '.'; } if (p++ > 75) /* BBC auto-lf*/ { /* If near right margin, */ conoll(""); /* Start new line */ p = 0; /* and reset counter. */ } conoc(c); /* Display the character. */ return; case SCR_TC: /* transaction complete */ conoc(BEL); return; case SCR_EM: /* Error message */ conoll(""); conoc('?'); conoll(s); p = 0; return; /* +1 */ case SCR_WM: /* Warning message */ conoll(""); conoll(s); p = 0; return; case SCR_TU: /* Undelimited text */ if ((p += len) > 75) { conoll(""); p = len; } conol(s); return; case SCR_TN: /* Text delimited at beginning */ conoll(""); conol(s); p = len; return; case SCR_TZ: /* Text delimited at end */ if ((p += len) > 75) conoll(""); conoll(s); p = 0; return; case SCR_QE: /* Quantity equals */ sprintf(buf,"%s: %ld",s,n); conoll(buf); p = 0; return; default: conoll("*** screen() called with bad object ***"); p = 0; return; } } /* I N T M S G -- Issue message about terminal interrupts */ intmsg(n) long n; { extern char *chstr(); char buf[80]; if ((!displa) || (quiet)) return; if (n == 1) { screen(SCR_TN,0,0l,"CTRL-F to cancel file, CTRL-R to resend current packet"); screen(SCR_TZ,0,0l,"CTRL-B to cancel batch, CTRL-A for status report..."); } else screen(SCR_TU,0,0l," "); } /* C H K I N T -- Check for console interrupts */ /*** should rework not to destroy typeahead ***/ chkint() { int ch, cn; if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */ cn = conchk(); /* Any input waiting? */ debug(F101,"conchk","",cn); while (cn > 0) { /* Yes, read it. */ cn--; /* give read 5 seconds for interrupt character */ if ((ch = coninc(5)) < 0) return(0); switch (ch & 0177) { case 0001: /* CTRL-A */ screen(SCR_TN,0,0l,"^A Status report:"); screen(SCR_TN,0,0l," file type: "); if (binary) screen(SCR_TZ,0,0l,"binary"); else screen(SCR_TZ,0,0l,"text"); screen(SCR_QE,0,(long)filcnt," file number"); screen(SCR_QE,0,(long)ffc, " characters "); screen(SCR_QE,0,(long)bctu, " block check"); screen(SCR_QE,0,(long)rptflg," compression"); screen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing"); continue; case 0033: /* ESCAPE */ case 0002: /* CTRL-B */ screen(SCR_TN,0,0l,"^B - Cancelling Batch "); czseen = 1; continue; case 0006: /* CTRL-F */ screen(SCR_TN,0,0l,"^F - Cancelling File "); cxseen = 1; continue; case 0022: /* CTRL-R */ screen(SCR_TN,0,0l,"^R - Resending "); resend(); return(1); default: /* Anything else, just ignore */ screen(SCR_TU,0,0l," [Ignored] "); continue; } } return(0); } /* D E B U G -- Enter a record in the debugging log */ /* Call with a format, two strings, and a number: f - Format, a bit string in range 0-7. If bit x is on, then argument number x is printed. s1 - String, argument number 1. If selected, printed as is. s2 - String, argument number 2. If selected, printed in brackets. n - Int, argument 3. If selected, printed preceded by equals sign. f=0 is special: print s1,s2, and interpret n as a char. */ #ifdef DEBUG debug(f,s1,s2,n) int f, n; char *s1, *s2; { static char s[200]; char *sp = s; if (!deblog) return; /* If no debug log, don't */ switch (f) { case F000: /* 0, print both strings, */ sprintf(sp,"%s%s%c\n",s1,s2,n); /* and interpret n as a char */ zsout(ZDFILE,s); break; case F001: /* 1, "=n" */ sprintf(sp,"=%d\n",n); zsout(ZDFILE,s); break; case F010: /* 2, "[s2]" */ sprintf(sp,"[%s]\n",s2); zsout(ZDFILE,""); break; case F011: /* 3, "[s2]=n" */ sprintf(sp,"[%s]=%d\n",s2,n); zsout(ZDFILE,s); break; case F100: /* 4, "s1" */ zsoutl(ZDFILE,s1); break; case F101: /* 5, "s1=n" */ sprintf(sp,"%s=%d\n",s1,n); zsout(ZDFILE,s); break; case F110: /* 6, "s1[s2]" */ sprintf(sp,"%s[%s]\n",s1,s2); zsout(ZDFILE,s); break; case F111: /* 7, "s1[s2]=n" */ sprintf(sp,"%s[%s]=%d\n",s1,s2,n); zsout(ZDFILE,s); break; default: sprintf(sp,"\n?Invalid format for debug() - %d\n",n); zsout(ZDFILE,s); } } #endif #ifdef TLOG /* T L O G -- Log a record in the transaction file */ /* Call with a format and 3 arguments: two strings and a number: f - Format, a bit string in range 0-7, bit x is on, arg #x is printed. s1,s2 - String arguments 1 and 2. n - Int, argument 3. */ tlog(f,s1,s2,n) int f; long n; char *s1, *s2; { static char s[200]; char *sp = s; int x; if (!tralog) return; /* If no transaction log, don't */ switch (f) { case F000: /* 0 (special) "s1 n s2" */ sprintf(sp,"%s %ld %s\n",s1,n,s2); zsout(ZTFILE,s); break; case F001: /* 1, " n" */ sprintf(sp," %ld\n",n); zsout(ZTFILE,s); break; case F010: /* 2, "[s2]" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"[%s]\n",s2); zsout(ZTFILE,""); break; case F011: /* 3, "[s2] n" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"[%s] %ld\n",s2,n); zsout(ZTFILE,s); break; case F100: /* 4, "s1" */ zsoutl(ZTFILE,s1); break; case F101: /* 5, "s1: n" */ sprintf(sp,"%s: %ld\n",s1,n); zsout(ZTFILE,s); break; case F110: /* 6, "s1 s2" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"%s %s\n",s1,s2); zsout(ZTFILE,s); break; case F111: /* 7, "s1 s2: n" */ x = strlen(s2); if (s2[x] == '\n') s2[x] = '\0'; sprintf(sp,"%s %s: %ld\n",s1,s2,n); zsout(ZTFILE,s); break; default: sprintf(sp,"\n?Invalid format for tlog() - %ld\n",n); zsout(ZTFILE,s); } } #endif <<< acpusr.c >>> char *userv = "Panos User Interface (based on C-Kermit 4C(046)) 19 Dec 85"; /* C K P U S R -- "User Interface" for Panos Kermit (Part 1) */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* The ckuser module contains the terminal input and output functions for Unix Kermit. It includes a simple Unix-style command line parser as well as an interactive prompting keyword command parser. It depends on the existence of Unix facilities like fopen, fgets, feof, (f)printf, argv/argc, etc. Other functions that are likely to vary among Unix implementations -- like setting terminal modes or interrupts -- are invoked via calls to functions that are defined in the system-dependent modules, ck?[ft]io.c. The command line parser processes any arguments found on the command line, as passed to main() via argv/argc. The interactive parser uses the facilities of the cmd package (developed for this program, but usable by any program). Any command parser may be substituted for this one. The only requirements for the Kermit command parser are these: 1. Set parameters via global variables like duplex, speed, ttname, etc. See ckmain.c for the declarations and descriptions of these variables. 2. If a command can be executed without the use of Kermit protocol, then execute the command directly and set the variable sstate to 0. Examples include 'set' commands, local directory listings, the 'connect' command. 3. If a command requires the Kermit protocol, set the following variables: sstate string data 'x' (enter server mode) (none) 'r' (send a 'get' command) cmarg, cmarg2 'v' (enter receive mode) cmarg2 'g' (send a generic command) cmarg 's' (send files) nfils, cmarg & cmarg2 OR cmlist 'c' (send a remote host command) cmarg cmlist is an array of pointers to strings. cmarg, cmarg2 are pointers to strings. nfils is an integer. cmarg can be a filename string (possibly wild), or a pointer to a prefabricated generic command string, or a pointer to a host command string. cmarg2 is the name to send a single file under, or the name under which to store an incoming file; must not be wild. cmlist is a list of nonwild filenames, such as passed via argv. nfils is an integer, interpreted as follows: -1: argument string is in cmarg, and should be expanded internally. 0: stdin. >0: number of files to send, from cmlist. The screen() function is used to update the screen during file transfer. The tlog() function maintains a transaction log. The debug() function maintains a debugging log. The intmsg() and chkint() functions provide the user i/o for interrupting file transfers. */ extern int XFindOutput() asm; #include "ckcdeb.h" #include #include #include "ckcker.h" #include "ckucmd.h" #include "ckuusr.h" #ifdef vax11c #define KERMRC "kermit.ini" #else #define KERMRC "kermrc-cmd" /* PANOS needs changed - see also '/' */ #endif /* External Kermit Variables, see ckmain.c for description. */ extern int size, spsiz, rpsiz, npad, timint, rtimo, speed, local, server, displa, binary, fncnv, delay, parity, deblog, escape, xargc, flow, turn, duplex, cxseen, czseen, nfils, ckxech, pktlog, seslog, tralog, stdouf, turnch, chklen, bctr, bctu, dfloc, mdmtyp, rptflg, ebqflg, warn, quiet, cnflg, timef, mypadn; extern long filcnt, tlci, tlco, ffc, tfc, fsize; extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv; extern char *dialv, *loginv; extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist; extern char mystch, stchr, sstate, mypadc, padch, eol, seol, ctlq, filnam[], ttname[]; extern char *DIRCMD, *PWDCMD, cmerrp[]; char *strcpy(), *getenv(); /* Declarations from cmd package */ extern char cmdbuf[]; /* Command buffer */ /* Declarations from ck?fio.c module */ extern char *SPACMD, *zhome(); /* Space command, home directory. */ extern int backgrd; /* Kermit executing in background */ /* The background flag is set by ckutio.c (via conint() ) to note whether */ /* this kermit is executing in background ('&' on shell command line). */ /* Variables and symbols local to this module */ char line[CMDBL+10], *lp; /* Character buffer for anything */ char debfil[50]; /* Debugging log file name */ char pktfil[50]; /* Packet log file name */ char sesfil[50]; /* Session log file name */ char trafil[50]; /* Transaction log file name */ int n, /* General purpose int */ cflg, /* Command-line connect cmd given */ action, /* Action selected on command line*/ repars, /* Reparse needed */ tlevel, /* Take command level */ cwdf = 0; /* CWD has been done */ #define MAXTAKE 20 /* Maximum nesting of TAKE files */ FILE *tfile[MAXTAKE]; /* File pointers for TAKE command */ char *homdir; /* Pointer to home directory string */ char cmdstr[100]; /* C M D L I N -- Get arguments from command line */ /* Simple Unix-style command line parser, conforming with 'A Proposed Command Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World, Vol.1, No.3, 1984. */ cmdlin() { char x; cmarg = ""; /* Initialize. */ cmarg2 = ""; action = cflg = 0; while (--xargc > 0) { /* Go through command line words */ xargv++; debug(F111,"xargv",*xargv,xargc); if (**xargv == '-') { /* Got an option (begins with dash) */ x = *(*xargv+1); /* Get the option letter */ x = doarg(x); /* Go handle the option */ if (x < 0) exit(GOOD_EXIT); } else { /* No dash where expected */ usage(); exit(BAD_EXIT); } } debug(F101,"action","",action); if (!local) { if ((action == 'g') || (action == 'r') || (action == 'c') || (cflg != 0)) fatal("-l and -b required"); } if (*cmarg2 != 0) { if ((action != 's') && (action != 'r') && (action != 'v')) fatal("-a without -s, -r, or -g"); } if ((action == 'v') && (stdouf) && (!local)) { if (isatty(1)) fatal("unredirected -k can only be used in local mode"); } if ((action == 's') || (action == 'v') || (action == 'r') || (action == 'x')) { if (local) displa = 1; if (stdouf) displa = 0; } if (quiet) displa = 0; /* No display if quiet requested */ if (cflg) { conect(); /* Connect if requested */ if (action == 0) { if (cnflg) conect(); /* And again if requested */ doexit(GOOD_EXIT); /* Then exit indicating success */ } } if (displa) concb(escape); /* (for console "interrupts") */ return(action); /* Then do any requested protocol */ } /* D O A R G -- Do a command-line argument. */ doarg(x) char x; { int z; char *xp; xp = *xargv+1; /* Pointer for bundled args */ while (x) { switch (x) { case 'x': /* server */ if (action) fatal("conflicting actions"); action = 'x'; break; case 'f': if (action) fatal("conflicting actions"); action = setgen('F',"","",""); break; case 'r': /* receive */ if (action) fatal("conflicting actions"); action = 'v'; break; case 'k': /* receive to stdout */ if (action) fatal("conflicting actions"); stdouf = 1; action = 'v'; break; case 's': /* send */ if (action) fatal("conflicting actions"); if (*(xp+1)) fatal("invalid argument bundling after -s"); z = nfils = 0; /* Initialize file counter, flag */ cmlist = xargv+1; /* Remember this pointer */ while (--xargc > 0) { /* Traverse the list */ *xargv++; if (**xargv == '-') { /* Check for sending stdin */ if (strcmp(*xargv,"-") != 0) break; z++; } nfils++; /* Bump file counter */ } xargc++, *xargv--; /* Adjust argv/argc */ if (nfils < 1) fatal("missing filename for -s"); if (z > 1) fatal("-s: too many -'s"); if (z == 1) { if (nfils == 1) nfils = 0; else fatal("invalid mixture of filenames and '-' in -s"); } if (nfils == 0) { if (isatty(0)) fatal("sending from terminal not allowed"); } debug(F101,*xargv,"",nfils); action = 's'; break; case 'g': /* get */ if (action) fatal("conflicting actions"); if (*(xp+1)) fatal("invalid argument bundling after -g"); *xargv++, xargc--; if ((xargc == 0) || (**xargv == '-')) fatal("missing filename for -g"); cmarg = *xargv; action = 'r'; break; case 'c': /* connect before */ cflg = 1; break; case 'n': /* connect after */ cnflg = 1; break; case 'h': /* help */ usage(); return(-1); case 'a': /* "as" */ if (*(xp+1)) fatal("invalid argument bundling after -a"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing name in -a"); cmarg2 = *xargv; break; case 'l': /* set line */ if (*(xp+1)) fatal("invalid argument bundling after -l"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("communication line device name missing"); strcpy(ttname,*xargv); if (strcmp(ttname,dftty) == 0) local = dfloc; else local = 1; break; case 'b': /* set baud */ if (*(xp+1)) fatal("invalid argument bundling"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing baud"); z = atoi(*xargv); /* Convert to number */ if (chkspd(z) > -1) speed = z; /* Check it */ else fatal("unsupported baud rate"); break; case 'i': /* Treat files as binary */ binary = 1; break; case 'w': /* File warning */ warn = 1; break; case 'q': /* Quiet */ quiet = 1; break; case 'd': /* debug */ debopn("debug-log"); break; case 'p': /* set parity */ if (*(xp+1)) fatal("invalid argument bundling"); *xargv++, xargc--; if ((xargc < 1) || (**xargv == '-')) fatal("missing parity"); switch(x = **xargv) { case 'e': case 'o': case 'm': case 's': parity = x; break; case 'n': parity = 0; break; default: fatal("invalid parity"); } break; case 't': turn = 1; /* Line turnaround handshake */ turnch = XON; /* XON is turnaround character */ duplex = 1; /* Half duplex */ flow = 0; /* No flow control */ break; default: fatal("invalid argument, type 'kermit -h' for help"); } x = *++xp; /* See if options are bundled */ } return(0); } /* Misc */ fatal(msg) char *msg; { /* Fatal error message */ fprintf(stderr,"\r\nFatal: %s\n",msg); tlog(F110,"Fatal:",msg,0l); doexit(BAD_EXIT); /* Exit indicating failure */ } ermsg(msg) char *msg; { /* Print error message */ if (!quiet) fprintf(stderr,"\r\n%s - %s\n",cmerrp,msg); tlog(F110,"Error -",msg,0l); } /* Interactive command parser */ /* Top-Level Keyword Table */ struct keytab cmdtab[] = { "!", XXSHE, 0, "bye", XXBYE, 0, "c", XXCON, CM_INV, "close", XXCLO, 0, "connect", XXCON, 0, "cwd", XXCWD, 0, "dial", XXDIAL, 0, "directory", XXDIR, 0, "echo", XXECH, 0, "exit", XXEXI, 0, "finish", XXFIN, 0, "get", XXGET, 0, "help", XXHLP, 0, "log", XXLOG, 0, "quit", XXQUI, 0, "r", XXREC, CM_INV, "receive", XXREC, 0, "remote", XXREM, 0, "s", XXSEN, CM_INV, "script", XXLOGI, 0, "send", XXSEN, 0, "server", XXSER, 0, "set", XXSET, 0, "show", XXSHO, 0, "space", XXSPA, 0, "statistics", XXSTA, 0, "take", XXTAK, 0 }; int ncmd = (sizeof(cmdtab) / sizeof(struct keytab)); /* Parameter keyword table */ struct keytab prmtab[] = { "baud", XYSPEE, CM_INV, "block-check", XYCHKT, 0, "delay", XYDELA, 0, "duplex", XYDUPL, 0, "end-of-packet", XYEOL, CM_INV, /* moved to send/receive */ "escape-character", XYESC, 0, "file", XYFILE, 0, "flow-control", XYFLOW, 0, "handshake", XYHAND, 0, "line", XYLINE, 0, "modem-dialer", XYMODM, 0, "packet-length", XYLEN, CM_INV, /* moved to send/receive */ "pad-character", XYPADC, CM_INV, /* moved to send/receive */ "padding", XYNPAD, CM_INV, /* moved to send/receive */ "parity", XYPARI, 0, "prompt", XYPROM, 0, "receive", XYRECV, 0, "send", XYSEND, 0, "speed", XYSPEE, 0, "start-of-packet", XYMARK, CM_INV, /* moved to send/receive */ "timeout", XYTIMO, CM_INV /* moved to send/receive */ }; int nprm = (sizeof(prmtab) / sizeof(struct keytab)); /* How many parameters */ /* Remote Command Table */ struct keytab remcmd[] = { "cwd", XZCWD, 0, "delete", XZDEL, 0, "directory", XZDIR, 0, "help", XZHLP, 0, "host", XZHOS, 0, "space", XZSPA, 0, "type", XZTYP, 0, "who", XZWHO, 0 }; int nrmt = (sizeof(remcmd) / sizeof(struct keytab)); struct keytab logtab[] = { "debugging", LOGD, 0, "packets", LOGP, 0, "session", LOGS, 0, "transactions", LOGT, 0 }; int nlog = (sizeof(logtab) / sizeof(struct keytab)); /* Show command arguments */ #define SHPAR 0 /* Parameters */ #define SHVER 1 /* Versions */ struct keytab shotab[] = { "parameters", SHPAR, 0, "versions", SHVER, 0 }; /* C M D I N I -- Initialize the interactive command parser */ int RawFrig; cmdini() { RawFrig = XFindOutput("RAWVDU:", 7); setbuf(stdin, NULL); /* PANOS */ printf("%s for %s\nType ? for help\n",versio,ckxsys); cmsetp("Panos-Kermit>"); /* Set default prompt. */ tlevel = -1; /* Take file level */ /* Look for init file in home or current directory. */ homdir = zhome(); lp = line; lp[0] = '\0'; if (homdir) { strcpy(lp,homdir); if (lp[0] == '/') strcat(lp,"/"); } strcat(lp,KERMRC); if ((tfile[0] = fopen(line,"r")) != NULL) { tlevel = 0; debug(F110,"init file",line,0); } if (homdir && (tlevel < 0)) { strcpy(lp,KERMRC); if ((tfile[0] = fopen(line,"r")) != NULL) { tlevel = 0; debug(F110,"init file",line,0); } else { debug(F100,"no init file","",0); } } congm(); /* Get console tty modes */ } /* T R A P -- Terminal interrupt handler */ trap() { debug(F100,"terminal interrupt...","",0); doexit(GOOD_EXIT); /* Exit indicating success */ } /* P A R S E R -- Top-level interactive command parser. */ parser() { int xx, cbn; char *cbp; concb(escape); /* Put console in cbreak mode. */ conint(&trap); /* Turn on console terminal interrupts. */ /* sstate becomes nonzero when a command has been parsed that requires some action from the protocol module. Any non-protocol actions, such as local directory listing or terminal emulation, are invoked directly from below. */ sstate = 0; /* Start with no start state. */ while (sstate == 0) { /* Parse cmds until action requ'std */ while ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */ fclose(tfile[tlevel]); /* file, close it */ tlevel--; /* and forget about it. */ cmini(ckxech); /* and clear the cmd buffer. */ } if (tlevel > -1) { /* If in take file */ cbp = cmdbuf; /* Get the next line. */ cbn = CMDBL; /* Loop to get next command line and all continuation lines from take file. */ again: if (fgets(line,cbn,tfile[tlevel]) == NULL) continue; lp = line; /* Got one, copy it. */ while (*cbp++ = *lp++) if (--cbn < 1) fatal("Command too long for internal buffer"); if (*(cbp - 3) == '\\') { /* Continued on next line? */ cbp -= 3; /* If so, back up pointer, */ goto again; /* go back, get next line. */ } stripq(cmdbuf); /* Strip any quotes from cmd buffer.*/ } else { /* No take file, get typein. */ prompt(); /* Issue interactive prompt. */ cmini(ckxech); } repars = 1; displa = 0; while (repars) { cmres(); /* Reset buffer pointers. */ xx = cmkey(cmdtab,ncmd,"Command",""); debug(F101,"top-level cmkey","",xx); switch (docmd(xx)) { case -4: /* EOF */ doexit(GOOD_EXIT); /* ...exit successfully */ case -1: /* Reparse needed */ repars = 1; continue; case -2: /* Invalid command given */ if (backgrd) /* if in background, terminate */ fatal("Kermit command error in background execution"); if (tlevel > -1) { /* If in take file, quit */ ermsg("Kermit command error: take file terminated."); fclose(tfile[tlevel]); tlevel--; } cmini(ckxech); /* (fall thru) */ case -3: /* Empty command OK at top level */ default: /* Anything else (fall thru) */ repars = 0; /* No reparse, get new command. */ continue; } } } /* Got an action comd; disable terminal interrupts and return start state */ if (!local) connoi(); /* Interrupts off only if remote */ return(sstate); } /* D O E X I T -- Exit from the program. */ doexit(exitstat) int exitstat; { ttclos(); /* Close external line, if any */ if (local) { strcpy(ttname,dftty); /* Restore default tty */ local = dfloc; /* And default remote/local status */ } if (!quiet) conres(); /* Restore console terminal. */ if (!quiet) connoi(); /* Turn off console interrupt traps.*/ if (deblog) { /* Close any open logs. */ debug(F100,"Debug Log Closed","",0); *debfil = '\0'; deblog = 0; zclose(ZDFILE); } if (pktlog) { *pktfil = '\0'; pktlog = 0; zclose(ZPFILE); } if (seslog) { *sesfil = '\0'; seslog = 0; zclose(ZSFILE); } if (tralog) { tlog(F100,"Transaction Log Closed","",0l); *trafil = '\0'; tralog = 0; zclose(ZTFILE); } printf("\nKermit done.\n"); exit(exitstat); /* Exit from the program. */ } /* B L D L E N -- Make length-encoded copy of string */ char * bldlen(str,dest) char *str, *dest; { int len; len = strlen(str); *dest = tochar(len); strcpy(dest+1,str); return(dest+len+1); } /* S E T G E N -- Construct a generic command */ setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3; { char *upstr, *cp; cp = cmdstr; *cp++ = type; *cp = NUL; if (*arg1 != NUL) { upstr = bldlen(arg1,cp); if (*arg2 != NUL) { upstr = bldlen(arg2,upstr); if (*arg3 != NUL) bldlen(arg3,upstr); } } cmarg = cmdstr; debug(F110,"setgen",cmarg,0); return('g'); } /* D O C M D -- Do a command */ /* Returns: -2: user typed an illegal command -1: reparse needed 0: parse was successful (even tho command may have failed). */ docmd(cx) int cx; { int x, y; char *s; switch (cx) { case -4: /* EOF */ if (!quiet) printf("\r\n"); doexit(GOOD_EXIT); case -3: /* Null command */ return(0); case -2: /* Error */ case -1: /* Reparse needed */ return(cx); case XXBYE: /* bye */ if ((x = cmcfm()) < 0) return(x); if (!local) { printf("You have to 'set line' first\n"); return(0); } sstate = setgen('L',"","",""); return(0); case XXCON: /* connect */ if ((x = cmcfm()) < 0) return(x); conres(); /* restore tty to normal mode */ x = conect(); concb(escape); /* tty back in character mode */ return(x); case XXCWD: if (cmtxt("Name of local directory, or carriage return",homdir,&s) < 0) return(-1); if (chdir(s)) perror(s); cwdf = 1; system(PWDCMD); return(0); case XXCLO: x = cmkey(logtab,nlog,"Which log to close",""); if (x == -3) { printf("?You must tell which log\n"); return(-2); } if (x < 0) return(x); if ((y = cmcfm()) < 0) return(y); switch (x) { case LOGD: if (deblog == 0) { printf("?Debugging log wasn't open\n"); return(0); } *debfil = '\0'; deblog = 0; return(zclose(ZDFILE)); case LOGP: if (pktlog == 0) { printf("?Packet log wasn't open\n"); return(0); } *pktfil = '\0'; pktlog = 0; return(zclose(ZPFILE)); case LOGS: if (seslog == 0) { printf("?Session log wasn't open\n"); return(0); } *sesfil = '\0'; seslog = 0; return(zclose(ZSFILE)); case LOGT: if (tralog == 0) { printf("?Transaction log wasn't open\n"); return(0); } *trafil = '\0'; tralog = 0; return(zclose(ZTFILE)); default: printf("\n?Unexpected log designator - %ld\n", x); return(0); } case XXDIAL: /* dial number */ if ((x = cmtxt("Number to be dialed","",&s)) < 0) return(x); return( dial(s) ); /* return success 0=connected -2=fail*/ case XXDIR: /* directory */ if ((x = cmtxt("Directory/file specification","@",&s)) < 0) return(x); lp = line; sprintf(lp,"%s %s",DIRCMD,s); system(line); return(0); case XXECH: /* echo */ x = cmtxt("Material to be echoed","",&s); if (x < 0) return(x); printf("%s\n",s); return(0); case XXQUI: /* quit, exit */ case XXEXI: if ((x = cmcfm()) > -1) doexit(GOOD_EXIT); else return(x); case XXFIN: /* finish */ if ((x = cmcfm()) < 0) return(x); if (!local) { printf("You have to 'set line' first\n"); return(0); } sstate = setgen('F',"","",""); return(0); case XXGET: /* Get */ if (!local) { printf("\nYou have to 'set line' first\n"); return(0); } x = cmtxt("Name of remote file(s), or carriage return","",&cmarg); if ((x == -2) || (x == -1)) return(x); /* If foreign file name omitted, get foreign and local names separately */ if (*cmarg == NUL) { if (tlevel > -1) { /* Input is from take file */ if (fgets(line,100,tfile[tlevel]) == NULL) fatal("take file ends prematurely in 'get'"); stripq(line); cmarg = line; if (fgets(cmdbuf,CMDBL,tfile[tlevel]) == NULL) fatal("take file ends prematurely in 'get'"); stripq(cmdbuf); if (*cmdbuf == NUL) cmarg2 = line; else cmarg2 = cmdbuf; } else { /* Input is from terminal */ char psave[40]; /* Save old prompt */ cmsavp(psave,40); cmsetp(" Remote file specification: "); /* Make new one */ cmini(ckxech); x = -1; prompt(); while (x == -1) { /* Prompt till they answer */ x = cmtxt("Name of remote file(s)","",&cmarg); debug(F111," cmtxt",cmarg,x); } if (x < 0) { cmsetp(psave); return(x); } if (*cmarg == NUL) { /* If user types a bare CR, */ printf("(cancelled)\n"); /* Forget about this. */ cmsetp(psave); /* Restore old prompt, */ return(0); /* and return. */ } strcpy(line,cmarg); /* Make a safe copy */ cmarg = line; cmsetp(" Local name to store it under: "); /* New prompt */ cmini(ckxech); x = -1; prompt(); /* Prompt */ while (x < 0) { /* Again, parse till answered */ x = cmofi("Local file name","",&cmarg2); if (x == -2) return(x); if (x == -3) { /* If bare CR, */ printf("(cancelled)\n"); /* escape from this... */ cmsetp(psave); /* restore old prompt, */ return(0); /* and return. */ } } cmsetp(psave); /* Restore old prompt. */ if ((x == cmcfm()) < 0) return(-2); } } sstate = 'r'; /* All ok, set start state. */ if (local) displa = 1; return(0); case XXHLP: /* Help */ x = cmkey(cmdtab,ncmd,"Panos-Kermit command","help"); return(dohlp(x)); case XXLOG: /* Log */ x = cmkey(logtab,nlog,"What to log",""); if (x == -3) { printf("?You must specify what is to be logged\n"); return(-2); } if (x < 0) return(x); return(dolog(x)); case XXLOGI: /* login to remote system */ if ((x = cmtxt("Text of login script","",&s)) < 0) return(x); return( login(s) ); /* return success 0=completed -2=fail*/ case XXREC: /* Receive */ cmarg2 = ""; x = cmofi("Name under which to store the file, or CR","",&cmarg2); if ((x == -1) || (x == -2)) return(x); debug(F111,"cmofi cmarg2",cmarg2,x); if ((x = cmcfm()) < 0) return(x); sstate = 'v'; if (local) displa = 1; return(0); case XXREM: /* Remote */ if (!local) { printf("\nYou have to 'set line' first\n"); return(-2); } x = cmkey(remcmd,nrmt,"Remote Kermit server command",""); if (x == -3) { printf("?You must specify a command for the remote server\n"); return(-2); } return(dormt(x)); case XXSEN: /* Send */ cmarg = cmarg2 = ""; if ((x = cmifi("File(s) to send","",&s,&y)) < 0) { if (x == -3) { printf("?A file specification is required\n"); return(-2); } return(x); } nfils = -1; /* Files come from internal list. */ strcpy(line,s); /* Save copy of string just parsed. */ debug(F101,"Send: wild","",y); *cmarg2 = '\0'; /* Initialize send-as name */ if (y == 0) { if ((x = cmtxt("Name to send it with","",&cmarg2)) < 0) return(x); } else { if ((x = cmcfm()) < 0) return(x); } cmarg = line; /* File to send */ debug(F110,"Sending:",cmarg,0); if (*cmarg2 != '\0') debug(F110," as:",cmarg2,0); sstate = 's'; /* Set start state */ if (local) displa = 1; return(0); case XXSER: /* Server */ if ((x = cmcfm()) < 0) return(x); sstate = 'x'; if (local) displa = 1; return(0); case XXSET: /* Set */ x = cmkey(prmtab,nprm,"Parameter",""); if (x == -3) { printf("?You must specify a parameter to set\n"); return(-2); } if (x < 0) return(x); return(doprm(x)); case XXSHE: /* Local shell command */ { int pid; if (cmtxt("Panos command to execute","",&s) < 0) return(-1); conres(); /* Make console normal */ system(s); concb(escape); /* Console back in cbreak mode */ return(0); } case XXSHO: /* Show */ x = cmkey(shotab,2,"","parameters"); if (x < 0) return(x); if (y = (cmcfm()) < 0) return(y); switch (x) { case SHPAR: shopar(); break; case SHVER: printf("\n%s\n%s\n",versio,protv); printf("%s\n",fnsv); printf("%s\n%s\n%s for %s\n",cmdv,userv,ckxv,ckxsys); printf("%s for %s\n%s\n",ckzv,ckzsys,connv); printf("%s\n%s\n\n",dialv,loginv); break; default: printf("\nNothing to show...\n"); break; } return(0); case XXSPA: /* space */ if ((x = cmcfm()) < 0) return(x); system(SPACMD); return(0); case XXSTA: /* statistics */ if ((x = cmcfm()) < 0) return(x); printf("\nMost recent transaction --\n"); printf(" files: %ld\n",filcnt); printf(" total file characters : %ld\n",tfc); printf(" communication line in : %ld\n",tlci); printf(" communication line out : %ld\n\n",tlco); printf(" block check type used : %d\n",bctu); printf(" compression : "); if (rptflg) printf("yes\n"); else printf("no\n"); printf(" 8th bit prefixing : "); if (ebqflg) printf("yes\n"); else printf("no\n\n"); return(0); case XXTAK: /* take */ if (tlevel > MAXTAKE-1) { printf("?Take files nested too deeply\n"); return(-2); } if ((y = cmifi("Panos-Kermit command file","",&s,&x)) < 0) { if (y == -3) { printf("?A file specification is required\n"); return(-2); } else return(y); } if (x != 0) { printf("?Wildcards not allowed in command file name\n"); return(-2); } strcpy(line,s); /* Make a safe copy of the string */ if ((y = cmcfm()) < 0) return(y); if ((tfile[++tlevel] = fopen(line,"r")) == NULL) { perror("take"); printf("Can't open command file - %s\n",line); debug(F110,"Failure to open",line,0); tlevel--; return(0); } return(0); default: printf("Not available - %s\n",cmdbuf); return(-2); } } /* S H O P A R -- Show Parameters */ shopar() { int i; extern struct keytab mdmtab[]; extern int nmdm; printf("\nLine: %s, speed: %d, mode: ",ttname,speed); if (local) printf("local"); else printf("remote"); for (i = 0; i < nmdm; i++) { if (mdmtab[i].val == mdmtyp) break; } if (i < nmdm) printf(", modem-dialer: %s",mdmtab[i].kwd); printf("\n Parity: "); switch (parity) { case 'e': printf("even"); break; case 'o': printf("odd"); break; case 'm': printf("mark"); break; case 's': printf("space"); break; case 0: printf("none"); break; default: printf("invalid - %d",parity); break; } printf(", duplex: "); if (duplex) printf("half, "); else printf("full, "); printf("flow: "); if (flow == 1) printf("xon/xoff"); else if (flow == 0) printf("none"); else printf("%d",flow); printf(", handshake: "); if (turn) printf("%d\n",turnch); else printf("none\n"); printf(" Delay: %d\n",delay); printf(" Send timeout: %d, receive timeout: %d\n",rtimo,timint); printf(" Send padding: %d, pad character: %d\n",npad,padch); printf(" Receive padding: %d pad character: %d\n",mypadn,mypadc); printf(" Send Packet start: %d, end: %d, length: %d\n",mystch,eol,spsiz); printf(" Receive Packet start: %d, end: %d, length: %d\n", stchr,seol,rpsiz); printf("Block check: %d\n",bctr); printf("\nFile parameters:\n"); printf(" Names: "); if (fncnv) printf("converted\n"); else printf("literal\n"); printf(" Type: "); if (binary) printf("binary\n"); else printf("text\n"); printf(" Warning: "); if (warn) printf("on\n"); else printf("off\n"); printf(" Display: "); if (quiet) printf("off\n"); else printf("on\n"); #ifdef KERMRC printf("\nInit File: %s",KERMRC); #endif printf("\nLogs:"); #ifdef DEBUG printf("\n Debugging: "); if (deblog) printf("%s",debfil); else printf("none"); #endif printf("\n Packets: "); if (pktlog) printf("%s",pktfil); else printf("none"); printf("\n Session: "); if (seslog) printf("%s",sesfil); else printf("none"); #ifdef TLOG printf("\n Transactions: "); if (tralog) printf("%s",trafil); else printf("none"); #endif printf("\n\n"); } /* D O L O G -- */ dolog(x) int x; { int y; char *s; switch (x) { case LOGD: #ifdef DEBUG y = cmofi("Name of debugging log file","debug-log",&s); #else y = -2; s = ""; printf("%s","- Sorry, debug log not available\n"); #endif break; case LOGP: y = cmofi("Name of packet log file","packet-log",&s); break; case LOGS: y = cmofi("Name of session log file","session-log",&s); break; case LOGT: #ifdef TLOG y = cmofi("Name of transaction log file","transact-log",&s); #else y = -2; s = ""; printf("%s","- Sorry, transaction log not available\n"); #endif break; default: printf("\n?Unexpected log designator - %d\n",x); return(-2); } if (y < 0) return(y); strcpy(line,s); s = line; if ((y = cmcfm()) < 0) return(y); switch (x) { case LOGD: return(deblog = debopn(s)); case LOGP: zclose(ZPFILE); y = zopeno(ZPFILE,s); if (y > 0) strcpy(pktfil,s); else *pktfil = '\0'; return(pktlog = y); case LOGS: zclose(ZSFILE); y = zopeno(ZSFILE,s); if (y > 0) strcpy(sesfil,s); else *sesfil = '\0'; return(seslog = y); case LOGT: zclose(ZTFILE); tralog = zopeno(ZTFILE,s); if (tralog > 0) { strcpy(trafil,s); tlog(F110,"Transaction Log:",versio,0l); tlog(F100,ckxsys,"",0); ztime(&s); tlog(F100,s,"",0l); } else *trafil = '\0'; return(tralog); default: return(-2); } } /* D E B O P N -- Open a debugging file */ debopn(s) char *s; { #ifdef DEBUG char *tp; zclose(ZDFILE); deblog = zopeno(ZDFILE,s); if (deblog > 0) { strcpy(debfil,s); debug(F110,"Debug Log ",versio,0); debug(F100,ckxsys,"",0); ztime(&tp); debug(F100,tp,"",0); } else *debfil = '\0'; return((deblog > 0) ? 1 : 0);/*GT*/ #else return(0); #endif } <<< acuus2.c >>> /* C K U U S 2 -- "User Interface" STRINGS module for Unix Kermit */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. */ /* This module separates long strings from the body of the ckuser module. */ #include "ckcdeb.h" #include #include #include "ckcker.h" #include "ckucmd.h" #include "ckuusr.h" extern char cmdbuf[]; extern int nrmt, nprm, dfloc; extern char *dftty; extern struct keytab prmtab[]; extern struct keytab remcmd[]; static char *hlp1[] = { "\n", " Usage: kermit [-x arg [-x arg]...[-yyy]..]]\n", " x is an option that requires an argument, y an option with no argument:\n", " actions (* options also require -l and -b) --\n", " -s file(s) send (use '-s -' to send from stdin)\n", " -r receive\n", " -k receive to stdout\n", " * -g file(s) get remote file(s) from server (quote wildcards)\n", " -a name alternate name, used with -s, -r, -g\n", " -x enter server mode\n", " * -f finish remote server\n", " * -c connect before transaction\n", " * -n connect after transaction\n", " -h help - print this message\n", " settings --\n", " -l line communication line device\n", " -b baud line speed, e.g. 1200\n", " -i binary file or Unix-to-Unix\n", " -p x parity, x is one of e,o,m,s,n\n", " -t line turnaround handshake = xon, half duplex\n", " -w don't write over preexisting files\n", " -q be quiet during file transfer\n", " -d log debugging info to debug.log\n", " If no action command is included, enter interactive dialog.\n", "" }; /* U S A G E */ usage() { conola(hlp1); } /* Help string definitions */ static char *tophlp[] = { "\n\ Type ? for a list of commands, type 'help x' for any command x.\n\ While typing commands, use the following special characters:\n\n\ DEL, RUBOUT, BACKSPACE, CTRL-H: Delete the most recent character typed.\n\ CTRL-W: Delete the most recent word typed.\n", "\ CTRL-U: Delete the current line.\n\ CTRL-R: Redisplay the current line.\n\ ? (question mark) display help on the current command or field.\n\ TAB (tab key '->|') Attempt to complete the current field.\n", "\ ESC (escape key) Quit the kermit program. Connection may not be severed.\n\ \\ (backslash) include the following character literally.\n\n\ From system level, type 'kermit -h' to get help about command line args.\ \n", "" }; static char *hmxxbye = "\ Shut down and log out a remote Kermit server"; static char *hmxxclo = "\ Close one of the following logs:\n\ session, transaction, packet, debugging -- 'help log' for further info."; static char *hmxxcon = "\ Connect to a remote system via the tty device given in the\n\ most recent 'set line' command"; static char *hmxxget = "\ Format: 'get filespec'. Tell the remote Kermit server to send the named\n\ files. If filespec is omitted, then you are prompted for the remote and\n\ local filenames separately."; static char *hmxxlg[] = { "\ Record information in a log file:\n\n\ debugging Debugging information, to help track down\n\ (default debug-log) bugs in the Panos-Kermit program.\n\n\ packets Kermit packets, to help track down protocol problems.\n\ (packet-log)\n\n", " session Terminal session, during CONNECT command.\n\ (session-log)\n\n\ transactions Names and statistics about files transferred.\n\ (transact-log)\n", "" } ; static char *hmxxlogi[] = { "\ Syntax: script text\n\n", "Login to a remote system using the text provided. The login script\n", "is intended to operate similarly to uucp \"L.sys\" entries.\n", "A login script is a sequence of the form:\n\n", " expect send [expect send] . . .\n\n", "where 'expect' is a prompt or message to be issued by the remote site, and\n", "'send' is the names, numbers, etc, to return. The send may also be the\n", "keyword EOT, to send control-d, or BREAK, to send a break. Letters in\n", "send may be prefixed by ~ to send special characters. These are:\n", "~b backspace, ~s space, ~q '?', ~n linefeed, ~r return, ~c don\'t\n", "append a return, and ~o[o[o]] for octal of a character. As with some \n", "uucp systems, sent strings are followed by ~r unless they end with ~c.\n\n", "Only the last 7 characters in each expect are matched. A null expect,\n", "e.g. ~0 or two adjacent dashes, causes a short delay. If you expect\n", "that a sequence might not arrive, as with uucp, conditional sequences\n", "may be expressed in the form:\n\n", " -send-expect[-send-expect[...]]\n\n", "where dashed sequences are followed as long as previous expects fail.\n", "" }; static char *hmxxrc[] = { "\ Format: 'receive [filespec]'. Wait for a file to arrive from the other\n\ Kermit, which must be given a 'send' command. If the optional filespec is\n", "given, the (first) incoming file will be stored under that name, otherwise\n\ it will be stored under the name it arrives with.", "" } ; static char *hmxxsen = "\ Format: 'send file1 [file2]'. File1 may contain wildcard characters '*' or\n\ '?'. If no wildcards, then file2 may be used to specify the name file1 is\n\ sent under; if file2 is omitted, file1 is sent under its own name."; static char *hmxxser = "\ Enter server mode on the currently selected line. All further commands\n\ will be taken in packet form from the other Kermit program."; static char *hmhset[] = { "\ The 'set' command is used to establish various communication or file\n", "parameters. The 'show' command can be used to display the values of\n", "'set' parameters. Help is available for each individual parameter;\n", "type 'help set ?' to see what's available.\n", "" } ; static char *hmxychkt[] = { "\ Type of packet block check to be used for error detection, 1, 2, or 3.\n", "Type 1 is standard, and catches most errors. Types 2 and 3 specify more\n", "rigorous checking at the cost of higher overhead. Not all Kermit programs\n", "support types 2 and 3.\n", "" } ; static char *hmxyf[] = { "\ set file: names, type, warning, display.\n\n", "'names' are normally 'converted', which means file names are converted\n", "to 'common form' during transmission; 'literal' means use filenames\n", "literally (useful between like systems).\n\n", "'type' is normally 'text', in which conversion is done between Unix\n", "newlines and CRLF line delimiters; 'binary' means to do no conversion.\n", "Use 'binary' for executable programs or binary data.\n\n", "'warning' is 'on' or 'off', normally off. When off, incoming files will\n", "overwrite existing files of the same name. When on, new names will be\n", "given to incoming files whose names are the same as existing files.\n", "\n\ 'display' is normally 'on', causing file transfer progress to be displayed\n", "on your screen when in local mode. 'set display off' is useful for\n", "allowing file transfers to proceed in the background.\n\n", "" } ; static char *hmhrmt[] = { "\ The 'remote' command is used to send file management instructions to a\n", "remote Kermit server. There should already be a Kermit running in server\n", "mode on the other end of the currently selected line. Type 'remote ?' to\n", "see a list of available remote commands. Type 'help remote x' to get\n", "further information about a particular remote command 'x'.\n", "" } ; /* D O H L P -- Give a help message */ dohlp(xx) int xx; { int x,y; if (xx < 0) return(xx); switch (xx) { case XXBYE: return(hmsg(hmxxbye)); case XXCLO: return(hmsg(hmxxclo)); case XXCON: return(hmsg(hmxxcon)); case XXCWD: #ifdef PANOS return(hmsg("Change working directory, equivalent to Panos 'set dir'")); #else #ifdef vms return(hmsg("\ Change Working Directory, equivalent to VMS SET DEFAULT command")); #else return(hmsg("Change Working Directory, equivalent to Unix 'cd' command")); #endif #endif case XXDEL: return(hmsg("Delete a local file or files")); case XXDIAL: return(hmsg("Dial a number using modem autodialer")); case XXDIR: return(hmsg("Display a directory of local files")); case XXECH: return(hmsg("Display the rest of the command on the terminal,\n\ useful in command files.")); case XXEXI: case XXQUI: return(hmsg("Exit from the Kermit program, closing any open logs.")); case XXFIN: return(hmsg("\ Tell the remote Kermit server to shut down without logging out.")); case XXGET: return(hmsg(hmxxget)); case XXHLP: return(hmsga(tophlp)); case XXLOG: return(hmsga(hmxxlg)); case XXLOGI: return(hmsga(hmxxlogi)); case XXREC: return(hmsga(hmxxrc)); case XXREM: if ((y = cmkey(remcmd,nrmt,"Remote command","")) == -2) return(y); if (y == -1) return(y); if (x = (cmcfm()) < 0) return(x); return(dohrmt(y)); case XXSEN: return(hmsg(hmxxsen)); case XXSER: return(hmsg(hmxxser)); case XXSET: if ((y = cmkey(prmtab,nprm,"Parameter","")) == -2) return(y); if (y == -2) return(y); if (x = (cmcfm()) < 0) return(x); return(dohset(y)); case XXSHE: #ifdef PANOS return(hmsg("\ Issue a command to Panos (space required after '!')")); #ifdef vms return(hmsg("\ Issue a command to VMS (space required after '!')")); #else return(hmsg("\ Issue a command to the Unix shell (space required after '!')")); #endif #endif case XXSHO: return(hmsg("\ Display current values of 'set' parameters; 'show version' will display\n\ program version information for each of the Panos-Kermit modules.")); case XXSPA: return(hmsg("Display disk usage in current device, directory")); case XXSTA: return(hmsg("Display statistics about most recent file transfer")); case XXTAK: return(hmsg("\ Take Kermit commands from the named file. Kermit command files may\n\ themselves contain 'take' commands, up to a reasonable depth of nesting.")); default: if (x = (cmcfm()) < 0) return(x); printf("Not available yet - %s\n",cmdbuf); break; } return(0); } /* H M S G -- Get confirmation, then print the given message */ hmsg(s) char *s; { int x; if (x = (cmcfm()) < 0) return(x); puts(s); return(0); } hmsga(s) char *s[]; { /* Same function, but for arrays */ int x, i; if ( x = (cmcfm()) < 0) return(x); for ( i = 0; *s[i] ; i++ ) fputs(s[i], stdout); fputc( '\n', stdout); return(0); } /* D O H S E T -- Give help for SET command */ dohset(xx) int xx; { if (xx == -3) return(hmsga(hmhset)); if (xx < 0) return(xx); switch (xx) { case XYCHKT: return(hmsga(hmxychkt)); case XYDELA: puts("\ Number of seconds to wait before sending first packet after 'send' command."); return(0); case XYDUPL: puts("\ During 'connect': 'full' means remote host echoes, 'half' means this program"); puts("does its own echoing."); return(0); case XYESC: printf("%s","\ Decimal ASCII value for escape character during 'connect', normally 28\n\ (Control-\\)\n"); return(0); case XYFILE: return(hmsga(hmxyf)); case XYFLOW: puts("\ Type of flow control to be used. Choices are 'xon/xoff' and 'none'."); puts("normally xon/xoff."); return(0); case XYHAND: puts("\ Decimal ASCII value for character to use for half duplex line turnaround"); puts("handshake. Normally, handshaking is not done."); return(0); case XYLINE: printf("\ Device name of communication line to use. Normally %s.\n",dftty); if (!dfloc) { printf("\ If you set the line to other than %s, then Kermit\n",dftty); printf("\ will be in 'local' mode; 'set line' will reset Kermit to remote mode.\n"); puts("\ If the line has a modem, and if the modem-dialer is set to direct, this"); puts("\ command causes waiting for a carrier detect (e.g. on a hayes type modem)."); puts("\ This can be used to wait for incoming calls."); puts("\ To use the modem to dial out, first set modem-dialer (e.g., to hayes), then"); puts("set line, next issue the dial command, and finally connect."); } return(0); case XYMODM: puts("\ Type of modem for dialing remote connections. Needed to indicate modem can"); puts("\ be commanded to dial without 'carrier detect' from modem. Many recently"); puts("\ manufactured modems use 'hayes' protocol. Type 'set modem ?' to see what"); puts("\ types of modems are supported by this program."); return(0); case XYPARI: puts("Parity to use during terminal connection and file transfer:"); puts("even, odd, mark, space, or none. Normally none."); return(0); case XYPROM: puts("Prompt string for this program, normally 'Panos-Kermit>'."); return(0); case XYSPEE: puts("\ Communication line speed for external tty line specified in most recent"); puts("\ 'set line' command. Any of the common baud rates:"); puts(" 0, 75, 150, 300, 1200, 2400, 4800, 9600, 19200."); return(0); case XYRECV: puts("\ Specify parameters for inbound packets:"); puts("\ End-Of-Packet (ASCII value), Packet-Length (94 or less),"); puts("\ Padding (amount, 94 or less), Pad-Character (ASCII value),"); puts("\ Start-Of-Packet (ASCII value), and Timeout (94 seconds or less),"); puts("\ all specified as decimal numbers."); return(0); case XYSEND: puts("\ Specify parameters for outbound packets:"); puts("\ End-Of-Packet (ASCII value), Packet-Length (94 or less),"); puts("\ Padding (amount, 94 or less), Pad-Character (ASCII value),"); puts("\ Start-Of-Packet (ASCII value), and Timeout (94 seconds or less),"); puts("\ all specified as decimal numbers."); return(0); default: printf("%s","Not available yet - %s\n",cmdbuf); return(0); } } /* D O H R M T -- Give help about REMOTE command */ dohrmt(xx) int xx; { int x; if (xx == -3) return(hmsga(hmhrmt)); if (xx < 0) return(xx); switch (xx) { case XZCWD: return(hmsg("\ Ask remote Kermit server to change its working directory.")); case XZDEL: return(hmsg("\ Ask remote Kermit server to delete the named file(s).")); case XZDIR: return(hmsg("\ Ask remote Kermit server to provide directory listing of the named file(s).")); case XZHLP: return(hmsg("\ Ask remote Kermit server to tell you what services it provides.")); case XZHOS: return(hmsg("\ Send a command to the remote system in its own command language\n\ through the remote Kermit server.")); case XZSPA: return(hmsg("\ Ask the remote Kermit server to tell you about its disk space.")); case XZTYP: return(hmsg("\ Ask the remote Kermit server to type the named file(s) on your screen.")); case XZWHO: return(hmsg("\ Ask the remote Kermit server to list who's logged in, or to give information\n\ about the specified user.")); default: if (x = (cmcfm()) < 0) return(x); printf("%s","not working yet - %s\n",cmdbuf); return(-2); } } <<< acwart.c >>> char *wartv = "Wart Version 1A(003) 27 May 85"; /* W A R T */ /* pre-process a lex-like file into a C program. Author:Jeff Damens, Columbia University Center for Computing Activites, 11/84. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. * input format is: * lines to be copied | %state * %% * | CHAR { actions } * ... * %% */ #include "ckcdeb.h" /* Includes */ #include #include #define C_L 014 /* Formfeed */ #define SEP 1 /* Token types */ #define LBRACK 2 #define RBRACK 3 #define WORD 4 #define COMMA 5 /* Storage sizes */ #define MAXSTATES 50 /* max number of states */ #define MAXWORD 50 /* max # of chars/word */ #define SBYTES ((MAXSTATES+7)/8) /* # of bytes for state bitmask */ /* Name of wart function in generated program */ #ifndef FNAME #define FNAME "wart" #endif /* Structure for state information */ struct trans { CHAR states[SBYTES]; /* included states */ int anyst; /* true if this good from any state */ CHAR inchr; /* input character */ int actno; /* associated action */ struct trans *nxt; }; /* next transition */ typedef struct trans *Trans; char *malloc(); /* Returns pointer (not int) */ /* Variables and tables */ int lines,nstates,nacts; char tokval[MAXWORD]; int tbl[MAXSTATES*128]; char *txt1 = "\n#define BEGIN state =\n\nint state = 0;\n\n"; char *fname = FNAME; /* function name goes here */ /* rest of program... */ char *txt2 = "()\n\ {\n\ int c,actno;\n\ while (1) {\n\ c = input();\n\ if ((actno = tbl(c + state*128)) != -1)\n\ switch(actno) {\n"; /* this program's output goes here, followed by final text... */ char *txt3 = "\n }\n }\n\}\n\n"; /* * turn on the bit associated with the given state * */ setstate(state,t) int state; Trans t; { int idx,msk; idx = state/8; /* byte associated with state */ msk = 0x80 >> (state % 8); /* bit mask for state */ t->states[idx] |= msk; } /* * see if the state is involved in the transition * */ teststate(state,t) int state; Trans t; { int idx,msk; idx = state/8; msk = 0x80 >> (state % 8); return(t->states[idx] & msk); } /* * read input from here... * */ Trans rdinput(infp,outfp) FILE *infp,*outfp; { Trans x,rdrules(); lines = 1; /* line counter */ nstates = 0; /* no states */ nacts = 0; /* no actions yet */ fprintf(outfp,"\n%c* WARNING -- This C source program generated by ",'/'); fprintf(outfp,"Wart preprocessor. */\n"); fprintf(outfp,"%c* Do not edit this file; edit the Wart-format ",'/'); fprintf(outfp,"source file instead, */\n"); fprintf(outfp,"%c* and then run it through Wart to produce a new ",'/'); fprintf(outfp,"C source file. */\n\n"); fprintf(outfp,"%c* Wart Version Info: */\n",'/'); fprintf(outfp,"char *wartv = \"%s\";\n\n",wartv); initial(infp,outfp); /* read state names, initial defs */ prolog(outfp); /* write out our initial code */ x = rdrules(infp,outfp); /* read rules */ epilogue(outfp); /* write out epilogue code */ return(x); } /* * initial - read initial definitions and state names. Returns * on EOF or %%. * */ initial(infp,outfp) FILE *infp,*outfp; { int c; char wordbuf[MAXWORD]; while ((c = getc(infp)) != EOF) { if (c == '%') { rdword(infp,wordbuf); if (strcmp(wordbuf,"states") == 0) rdstates(infp,outfp); else if (strcmp(wordbuf,"%") == 0) return; else fprintf(outfp,"%%%s",wordbuf); } else putc(c,outfp); if (c == '\n') lines++; } } /* * boolean function to tell if the given character can be part of * a word. * */ isin(s,c) char *s; int c; { for (; *s != '\0'; s++) if (*s == c) return(1); return(0); } isword(c) int c; { static char special[] = ".%_-$@"; /* these are allowable */ return(isalnum(c) || isin(special,c)); } /* * read the next word into the given buffer. * */ rdword(fp,buf) FILE *fp; char *buf; { int len = 0,c; while (isword(c = getc(fp)) && ++len < MAXWORD) *buf++ = c; *buf++ = '\0'; /* tie off word */ ungetc(c,fp); /* put break char back */ } /* * read state names, up to a newline. * */ rdstates(fp,ofp) FILE *fp,*ofp; { int c; char wordbuf[MAXWORD]; while ((c = getc(fp)) != EOF && c != '\n') { if (isspace(c) || c == C_L) continue; /* skip whitespace */ ungetc(c,fp); /* put char back */ rdword(fp,wordbuf); /* read the whole word */ enter(wordbuf,++nstates); /* put into symbol tbl */ fprintf(ofp,"#define %s %d\n",wordbuf,nstates); } lines++; } /* * allocate a new, empty transition node * */ Trans newtrans() { Trans new; int i; new = (Trans) malloc(sizeof (struct trans)); for (i=0; istates[i] = 0; new->anyst = 0; new->nxt = NULL; return(new); } /* * read all the rules. * */ Trans rdrules(fp,out) FILE *fp,*out; { Trans head,cur,prev; int curtok,i; head = cur = NULL; while ((curtok = gettoken(fp)) != SEP) switch(curtok) { case LBRACK: if (cur == NULL) cur = newtrans(); else fatal("duplicate state list"); statelist(fp,cur);/* set states */ continue; /* prepare to read char */ case WORD: if (strlen(tokval) != 1) fatal("multiple chars in state"); if (cur == NULL) { cur = newtrans(); cur->anyst = 1; } cur->actno = ++nacts; cur->inchr = tokval[0]; if (head == NULL) head = cur; else prev->nxt = cur; prev = cur; cur = NULL; copyact(fp,out,nacts); break; default: fatal("bad input format"); } return(head); } /* * read a list of (comma-separated) states, set them in the * given transition. * */ statelist(fp,t) FILE *fp; Trans t; { int curtok,sval; curtok = COMMA; while (curtok != RBRACK) { if (curtok != COMMA) fatal("missing comma"); if ((curtok = gettoken(fp)) != WORD) fatal("missing state name"); if ((sval = lkup(tokval)) == -1) { fprintf(stderr,"state %s undefined\n",tokval); fatal("undefined state"); } setstate(sval,t); curtok = gettoken(fp); } } /* * copy an action from the input to the output file * */ copyact(inp,outp,actno) FILE *inp,*outp; int actno; { int c,bcnt; fprintf(outp,"case %d:\n",actno); while (((c = getc(inp)) != '\n') && (isspace(c) || c == C_L)); if (c == '{') { bcnt = 1; putc(c,outp); while (bcnt > 0 && (c = getc(inp)) != EOF) { if (c == '{') bcnt++; else if (c == '}') bcnt--; else if (c == '\n') lines++; putc(c,outp); } if (bcnt > 0) fatal("action doesn't end"); } else { while (c != '\n' && c != EOF) { putc(c,outp); c = getc(inp); } lines++; } fprintf(outp,"\nbreak;\n"); } /* * find the action associated with a given character and state. * returns -1 if one can't be found. * */ faction(hd,state,chr) Trans hd; int state,chr; { while (hd != NULL) { if (hd->anyst || teststate(state,hd)) if (hd->inchr == '.' || hd->inchr == chr) return(hd->actno); hd = hd->nxt; } return(-1); } /* * empty the table... * */ emptytbl() { int i; for (i=0; i 1) { if ((infile = fopen(argv[1],"r")) == NULL) { fprintf(stderr,"Can't open %s\n",argv[1]); fatal("unreadable input file"); } } else infile = stdin; if (argc > 2) { if ((outfile = fopen(argv[2],"w")) == NULL) { fprintf(stderr,"Can't write to %s\n",argv[2]); fatal("bad output file"); } } else outfile = stdout; clrhash(); /* empty hash table */ head = rdinput(infile,outfile); /* read input file */ emptytbl(); /* empty our tables */ for (state = 0; state <= nstates; state++) for (c = 1; c < 128; c++) addaction(faction(head,state,c),state,c); /* find actions, add to tbl */ writetbl(outfile); copyrest(infile,outfile); printf("%d states, %d actions\n",nstates,nacts); #ifdef undef for (state = 1; state <= nstates; state ++) for (c = 1; c < 128; c++) if (tbl[state*128 + c] != -1) printf("state %d, chr %d, act %d\n", state,c,tbl[state*128 + c]); #endif exit(GOOD_EXIT); } /* * fatal error handler * */ fatal(msg) char *msg; { fprintf(stderr,"error in line %d: %s\n",lines,msg); exit(BAD_EXIT); } prolog(outfp) FILE *outfp; { int c; while ((c = *txt1++) != '\0') putc(c,outfp); while ((c = *fname++) != '\0') putc(c,outfp); while ((c = *txt2++) != '\0') putc(c,outfp); } epilogue(outfp) FILE *outfp; { int c; while ((c = *txt3++) != '\0') putc(c,outfp); } copyrest(in,out) FILE *in,*out; { int c; while ((c = getc(in)) != EOF) putc(c,out); } /* * gettoken - returns token type of next token, sets tokval * to the string value of the token if appropriate. * */ gettoken(fp) FILE *fp; { int c; while (1) { /* loop if reading comments... */ do { c = getc(fp); if (c == '\n') lines++; } while ((isspace(c) || c == C_L)); /* skip whitespace */ switch(c) { case EOF: return(SEP); case '%': if ((c = getc(fp)) == '%') return(SEP); tokval[0] = '%'; tokval[1] = c; rdword(fp,tokval+2); return(WORD); case '<': return(LBRACK); case '>': return(RBRACK); case ',': return(COMMA); case '/': if ((c = getc(fp)) == '*') { rdcmnt(fp); /* skip over the comment */ continue; } /* and keep looping */ else { ungetc(c); /* put this back into input */ c = '/'; } /* put character back, fall thru */ default: if (isword(c)) { ungetc(c,fp); rdword(fp,tokval); return(WORD); } else fatal("Invalid character in input"); } } } /* * skip over a comment * */ rdcmnt(fp) FILE *fp; { int c,star,prcnt; prcnt = star = 0; /* no star seen yet */ while (!((c = getc(fp)) == '/' && star)) { if (c == EOF || (prcnt && c == '%')) fatal("Unterminated comment"); prcnt = (c == '%'); star = (c == '*'); if (c == '\n') lines++; } } /* * symbol table management for wart * * entry points: * clrhash - empty hash table. * enter - enter a name into the symbol table * lkup - find a name's value in the symbol table. * */ #define HASHSIZE 101 /* # of entries in hash table */ struct sym { char *name; /* symbol name */ int val; /* value */ struct sym *hnxt; } /* next on collision chain */ *htab[HASHSIZE]; /* the hash table */ /* * empty the hash table before using it... * */ clrhash() { int i; for (i=0; iname = copy(name); cur->val = svalue; cur->hnxt = htab[h]; htab[h] = cur; } /* * find name in the symbol table, return its value. Returns -1 * if not found. * */ lkup(name) char *name; { struct sym *cur; for (cur = htab[hash(name)]; cur != NULL; cur = cur->hnxt) if (strcmp(cur->name,name) == 0) return(cur->val); return(-1); }