C-KERMIT (Part 7 of 10)
gregg at okstate.UUCP
gregg at okstate.UUCP
Fri Mar 8 17:48:00 AEST 1985
echo x - ckfns.c
sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckfns.c
Xchar *fnsv = "C-Kermit functions, 4.2(026) 5 Mar 85";
X
X/* C K F N S -- System-independent Kermit protocol support functions... */
X
X/* ...Part 1 (others moved to ckfns2 to make this module small enough) */
X
X/*
X System-dependent primitives defined in:
X
X ckx???.c -- terminal i/o
X cxz???.c -- file i/o, directory structure
X
X*/
X
X#include "ckermi.h" /* Symbol definitions for Kermit */
X
X/* Externals from ckmain.c */
X
Xextern int spsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas;
X
Xextern int pktnum, prvpkt, sndtyp, fsize, bctr, bctu,
X size, osize, maxsize, spktl, nfils, stdouf, warn, timef;
X
Xextern int parity, speed, turn, turnch,
X delay, displa, pktlog, tralog, seslog, xflg, mypadn;
X
Xextern long filcnt, ffc, flci, flco, tlci, tlco, tfc;
X
Xextern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
X
Xextern char padch, mypadc, eol, ctlq, myctlq, sstate, *hlptxt;
X
Xextern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr,
X mystch;
X
Xextern char *cmarg, *cmarg2, **cmlist;
Xchar *strcpy();
X
X/* Variables local to this module */
X
Xstatic char *memptr; /* Pointer for memory strings */
X
Xstatic char cmdstr[100]; /* Unix system command string */
X
Xstatic int sndsrc; /* Flag for where to send from: */
X /* -1: name in cmdata */
X /* 0: stdin */
X /* >0: list in cmlist */
X
Xstatic int memstr, /* Flag for input from memory string */
X t, /* Current character */
X next; /* Next character */
X
X/* E N C S T R -- Encode a string from memory. */
X
X/* Call this instead of getpkt() if source is a string, rather than a file. */
X
Xencstr(s) char* s; {
X int m; char *p;
X
X m = memstr; p = memptr; /* Save these. */
X
X memptr = s; /* Point to the string. */
X memstr = 1; /* Flag memory string as source. */
X next = -1; /* Initialize character lookahead. */
X getpkt(spsiz); /* Fill a packet from the string. */
X memstr = m; /* Restore memory string flag */
X memptr = p; /* and pointer */
X next = -1; /* Put this back as we found it. */
X debug(F111,"encstr",data,size);
X}
X
X/* E N C O D E - Kermit packet encoding procedure */
X
Xencode(a) int a; { /* The current character */
X int a7; /* Low order 7 bits of character */
X int b8; /* 8th bit of character */
X
X if (rptflg) { /* Repeat processing? */
X if (a == next) { /* Got a run... */
X if (++rpt < 94) /* Below max, just count */
X return;
X else if (rpt == 94) { /* Reached max, must dump */
X data[size++] = rptq;
X data[size++] = tochar(rpt);
X rpt = 0;
X }
X } else if (rpt == 1) { /* Run broken, only 2? */
X rpt = 0; /* Yes, reset repeat flag & count. */
X encode(a); /* Do the character twice. */
X if (size <= maxsize) osize = size;
X rpt = 0;
X encode(a);
X return;
X } else if (rpt > 1) { /* More than two */
X data[size++] = rptq; /* Insert the repeat prefix */
X data[size++] = tochar(++rpt); /* and count. */
X rpt = 0; /* Reset repeat counter. */
X }
X }
X a7 = a & 0177; /* Isolate ASCII part */
X b8 = a & 0200; /* and 8th (parity) bit. */
X
X if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */
X data[size++] = ebq;
X a = a7;
X }
X if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */
X data[size++] = myctlq;
X a = ctl(a);
X }
X if (a7 == myctlq) /* Prefix the control prefix */
X data[size++] = myctlq;
X
X if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
X data[size++] = myctlq; /* quote it if doing repeat counts. */
X
X if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */
X data[size++] = myctlq; /* if doing 8th-bit prefixes */
X
X data[size++] = a; /* Finally, insert the character */
X data[size] = '\0'; /* itself, and mark the end. */
X}
X
X/* D E C O D E -- Kermit packet decoding procedure */
X
X/* Call with string to be decoded and an output function. */
X
Xdecode(buf,fn) char *buf; int (*fn)(); {
X unsigned int a, a7, b8; /* Low order 7 bits, and the 8th bit */
X
X rpt = 0;
X
X while ((a = *buf++) != '\0') {
X if (rptflg) { /* Repeat processing? */
X if (a == rptq) { /* Yes, got a repeat prefix? */
X rpt = unchar(*buf++); /* Yes, get the repeat count, */
X a = *buf++; /* and get the prefixed character. */
X }
X }
X b8 = 0; /* Check high order "8th" bit */
X if (ebqflg) { /* 8th-bit prefixing? */
X if (a == ebq) { /* Yes, got an 8th-bit prefix? */
X b8 = 0200; /* Yes, remember this, */
X a = *buf++; /* and get the prefixed character. */
X }
X }
X if (a == ctlq) { /* If control prefix, */
X a = *buf++; /* get its operand. */
X a7 = a & 0177; /* Only look at low 7 bits. */
X if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */
X a = ctl(a); /* if in control range. */
X }
X a |= b8; /* OR in the 8th bit */
X if (rpt == 0) rpt = 1; /* If no repeats, then one */
X for (; rpt > 0; rpt--) { /* Output the char RPT times */
X if (a == CR && !binary) break; /* But skip CR if binary. */
X ffc++, tfc++; /* Count the character */
X (*fn)(a); /* Send it to the output function. */
X }
X }
X}
X
X
X/* Output functions passed to 'decode': */
X
Xputsrv(c) char c; { /* Put character in server command buffer */
X *srvptr++ = c;
X *srvptr = '\0'; /* Make sure buffer is null-terminated */
X}
X
Xputtrm(c) char c; { /* Output character to console. */
X conoc(c);
X}
X
Xputfil(c) char c; { /* Output char to file. */
X zchout(ZOFILE,c);
X}
X
X/* G E T P K T -- Fill a packet data field */
X
X/*
X Gets characters from the current source -- file or memory string.
X Encodes the data into the packet, filling the packet optimally.
X
X Uses global variables:
X t -- current character.
X next -- next character.
X data -- the packet data buffer.
X size -- number of characters in the data buffer.
X
XReturns the size as value of the function, and also sets global size,
Xand fills (and null-terminates) the global data array.
X
XBefore calling getpkt the first time for a given source (file or string),
Xset the variable 'next' to -1.
X*/
X
Xgetpkt(maxsize) int maxsize; { /* Fill one packet buffer */
X int i; /* Loop index. */
X
X static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' };
X
X if (next < 0) t = getch(); /* Get first character of file. */
X
X /* Do any leftovers */
X
X for (size = 0; (data[size] = leftover[size]) != '\0'; size++)
X ;
X *leftover = '\0';
X
X /* Now fill up the rest of the packet. */
X
X while(t >= 0) { /* Until EOF... */
X next = getch(); /* Get next character for lookahead. */
X osize = size; /* Remember current position. */
X encode(t); /* Encode the current character. */
X t = next; /* Next is now current. */
X
X if (size == maxsize) /* If the packet is exactly full, */
X return(size); /* and return. */
X
X if (size > maxsize) { /* If too big, save some for next. */
X for (i = 0; (leftover[i] = data[osize+i]) != '\0'; i++)
X ;
X size = osize; /* Return truncated packet. */
X data[size] = '\0';
X return(size);
X }
X }
X return(size); /* Return any partial final buffer. */
X}
X
X/* G E T C H -- Get the next character from file (or pipe). */
X
X/* Convert newlines to CRLFs if newline/CRLF mapping is being done. */
X
Xgetch() { /* Get next character */
X int a, x; /* The character to return. */
X static int b = 0; /* A character to remember. */
X
X if (b > 0) { /* Do we have a newline saved? */
X b = 0; /* Yes, return that. */
X return('\n');
X }
X
X if (memstr) /* Try to get the next character */
X x = ((a = *memptr++) == '\0'); /* from the appropriate source, */
X else /* memory or the current file. */
X x = ((a = zchin(ZIFILE)) < 0 );
X
X if (x)
X return(-1); /* No more, return -1 for EOF. */
X else { /* Otherwise, read the next char. */
X ffc++, tfc++; /* Count it. */
X if (a == '\n' && !binary) { /* If nl and we must do nl-CRLF */
X b = a; /* mapping, save the nl, */
X return(CR); /* and return a CR. */
X } else return(a); /* General case, return the char. */
X }
X}
X
X
X/* C A N N E D -- Check if current file transfer cancelled */
X
Xcanned(buf) char *buf; {
X if (*buf == 'X') cxseen = 1;
X if (*buf == 'Z') czseen = 1;
X debug(F101,"canned: cxseen","",cxseen);
X debug(F101," czseen","",czseen);
X return((czseen || cxseen) ? 1 : 0);
X}
X
X/* T I N I T -- Initialize a transaction */
X
Xtinit() {
X xflg = 0; /* reset x-packet flag */
X memstr = 0; /* reset memory-string flag */
X memptr = NULL; /* and pointer */
X bctu = 1; /* reset block check type to 1 */
X filcnt = 0; /* reset file counter */
X tfc = tlci = tlco = 0; /* reset character counters */
X prvpkt = -1; /* reset packet number */
X pktnum = 0;
X if (server) { /* If acting as server, */
X timint = 30; /* use 30 second timeout, */
X nack(); /* send a NAK */
X }
X}
X
X
X/* R I N I T -- Respond to S packet */
X
Xrinit(d) char *d; {
X char *tp;
X ztime(&tp);
X tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
X tfc = tlci = tlco = 0;
X spar(d);
X rpar(d);
X ack1(d);
X}
X
X/* S I N I T -- Make sure file exists, then send Send-Init packet */
X
Xsinit() {
X int x; char *tp;
X
X sndsrc = nfils; /* Where to look for files to send */
X ztime(&tp);
X tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
X debug(F101,"sinit: sndsrc","",sndsrc);
X if (sndsrc < 0) { /* Must expand from 'send' command */
X nfils = zxpand(cmarg); /* Look up literal name. */
X if (nfils < 0) {
X screen(2,0l,"?Too many files");
X return(0);
X } else if (nfils == 0) { /* If none found, */
X char xname[100]; /* convert the name. */
X zrtol(cmarg,xname);
X nfils = zxpand(xname); /* Look it up again. */
X }
X if (nfils < 1) { /* If no match, report error. */
X if (server)
X errpkt("File not found");
X else
X screen(2,0l,"?File not found");
X return(0);
X }
X x = gnfile(); /* Position to first file. */
X if (x < 1) {
X if (!server)
X screen(2,0l,"?No readable file to send");
X else
X errpkt("No readable file to send");
X return(0);
X }
X } else if (sndsrc > 0) { /* Command line arglist -- */
X x = gnfile(); /* Get the first file from it. */
X if (x < 1) return(0); /* (if any) */
X } else if (sndsrc == 0) { /* stdin or memory always exist... */
X cmarg2 = ""; /* No alternate name */
X strcpy(filnam,"stdin"); /* If F packet, filnam is used. */
X tlog(F110,"Sending from",cmdstr,0l); /* If X packet, cmdstr is used. */
X }
X
X debug(F101,"sinit: nfils","",nfils);
X debug(F110," filnam",filnam,0);
X debug(F110," cmdstr",cmdstr,0);
X ttflui(); /* Flush input buffer. */
X x = rpar(data); /* Send a Send-Init packet. */
X if (!local && !server) sleep(delay);
X spack('S',pktnum,x,data);
X return(1);
X}
X
Xsipkt() {
X int x;
X x = rpar(data); /* Send an I-Packet. */
X spack('I',pktnum,x,data);
X}
X
X/* R C V F I L -- Receive a file */
X
Xrcvfil() {
X int x;
X ffc = flci = flco = 0; /* Init per-file counters */
X srvptr = srvcmd; /* Decode packet data. */
X decode(data,putsrv);
X screen(0,0l,srvcmd); /* Update screen */
X screen(1,0l,"=> ");
X tlog(F110,"Receiving",srvcmd,0l); /* Transaction log entry */
X if (cmarg2 != NULL) { /* Check for alternate name */
X if (*cmarg2 != '\0') {
X strcpy(srvcmd,cmarg2); /* Got one, use it. */
X *cmarg2 = '\0';
X }
X }
X x = openo(srvcmd,filnam); /* Try to open it */
X if (x) {
X tlog(F110," as",filnam,0l);
X screen(2,0l,filnam);
X intmsg(++filcnt);
X } else {
X tlog(F110,"Failure to open",filnam,0l);
X screen(2,0l,"*** error");
X }
X return(x); /* Pass on return code from openo */
X}
X
X/* R E O F -- Receive End Of File */
X
Xreof() {
X
X if (cxseen == 0) cxseen = (*data == 'D');
X clsof();
X if (cxseen || czseen) {
X tlog(F100," *** Discarding","",0l);
X } else {
X tlog(F100," end of file","",0l);
X tlog(F101," file characters ","",ffc);
X tlog(F101," communication line in ","",flci);
X tlog(F101," communication line out ","",flco);
X }
X}
X
X/* R E O T -- Receive End Of Transaction */
X
Xreot() {
X char *tp;
X cxseen = czseen = 0;
X ztime(&tp);
X tlog(F110,"End of transaction",tp,0l);
X if (filcnt > 1) {
X tlog(F101," files","",filcnt);
X tlog(F101," total file characters ","",tfc);
X tlog(F101," communication line in ","",tlci);
X tlog(F101," communication line out ","",tlco);
X }
X}
X
X/* S F I L E -- Send File header packet for global "filnam" */
X
Xsfile() {
X char pktnam[100]; /* Local copy of name */
X
X if (fncnv) {
X if (*cmarg2 != '\0') { /* If we have a send-as name, */
X zltor(cmarg2,pktnam); /* convert it to common form, */
X cmarg2 = ""; /* and blank it out for next time, */
X } else zltor(filnam,pktnam); /* otherwise use the real file name. */
X } else {
X if (*cmarg2 != '\0') /* Same as above, but without */
X strcpy(pktnam,cmarg2); /* name conversion */
X else strcpy(filnam,pktnam);
X }
X
X debug(F110,"sfile",filnam,0);
X if (openi(filnam) == 0) /* Try to open the file */
X return(0);
X
X rpt = flci = flco = ffc = 0; /* OK, Init counters, etc. */
X encstr(pktnam); /* Encode the name. */
X nxtpkt(&pktnum); /* Increment the packet number */
X ttflui(); /* Clear pending input */
X spack('F',pktnum,size,data); /* Send the F packet */
X if (displa) {
X screen(0,(long)pktnum,filnam); /* Update screen */
X screen(1,0l,"=> ");
X screen(1,0l,pktnam);
X screen(3,(long)fsize,", size");
X intmsg(++filcnt); /* Count file, give interrupt msg */
X }
X tlog(F110,"Sending",filnam,0l); /* Transaction log entry */
X tlog(F110," as",pktnam,0l);
X next = -1; /* Init file character lookahead. */
X return(1);
X}
X
X
X/* Send an X Packet -- Like SFILE, but with Text rather than File header */
X
Xsxpack() { /* Send an X packet */
X debug(F110,"sxpack",cmdstr,0);
X encstr(cmdstr); /* Encode any data. */
X rpt = flci = flco = ffc = 0; /* Init counters, etc. */
X next = -1; /* Init file character lookahead. */
X nxtpkt(&pktnum); /* Increment the packet number */
X spack('X',pktnum,size,data); /* No incrementing pktnum */
X screen(0,(long)pktnum,cmdstr); /* Update screen. */
X intmsg(++filcnt);
X tlog(F110,"Sending from:",cmdstr,0l);
X return(1);
X}
X
X/* S D A T A -- Send a data packet */
X
Xsdata() {
X int len;
X if (cxseen || czseen) return(0); /* If interrupted, done. */
X if ((len = getpkt(spsiz-chklen-3)) == 0) return(0); /* If no data, done. */
X nxtpkt(&pktnum); /* Increment the packet number */
X spack('D',pktnum,len,data); /* Send the packet */
X return(1);
X}
X
X
X/* S E O F -- Send an End-Of-File packet */
X
Xseof() {
X nxtpkt(&pktnum); /* Increment the packet number */
X if (czseen || cxseen) {
X spack('Z',pktnum,1,"D");
X tlog(F100," *** interrupted, sending discard request","",0l);
X } else {
X spack('Z',pktnum,0,"");
X tlog(F100," end of file","",0l);
X tlog(F101," file characters ","",ffc);
X tlog(F101," communication line in ","",flci);
X tlog(F101," communication line out ","",flco);
X }
X}
X
X
X/* S E O T -- Send an End-Of-Transaction packet */
X
Xseot() {
X char *tp;
X nxtpkt(&pktnum); /* Increment the packet number */
X spack('B',pktnum,0,"");
X cxseen = czseen = 0;
X ztime(&tp);
X tlog(F110,"End of transaction",tp,0l);
X if (filcnt > 1) {
X tlog(F101," files","",filcnt);
X tlog(F101," total file characters ","",tfc);
X tlog(F101," communication line in ","",tlci);
X tlog(F101," communication line out ","",tlco);
X }
X}
X
X/* R P A R -- Fill the data array with my send-init parameters */
X
Xrpar(data) char data[]; {
X data[0] = tochar(spsiz); /* Biggest packet I can receive */
X data[1] = tochar(URTIME); /* When I want to be timed out */
X data[2] = tochar(mypadn); /* How much padding I need (none) */
X data[3] = ctl(mypadc); /* Padding character I want */
X data[4] = tochar(MYEOL); /* End-Of-Line character I want */
X data[5] = CTLQ; /* Control-Quote character I send */
X if (ebqflg) data[6] = ebq = '&';
X else data[6] = 'Y'; /* 8-bit quoting */
X data[7] = bctr + '0'; /* Block check type */
X data[8] = MYRPTQ; /* Do repeat counts */
X data[9] = '\0';
X return(9); /* Return the length. */
X}
X
X/* S P A R -- Get the other system's Send-Init parameters. */
X
Xspar(data) char data[]; {
X int len, x;
X
X len = strlen(data); /* Number of fields */
X
X spsiz = (len-- > 0) ? unchar(data[0]) : DSPSIZ; /* Packet size */
X if (spsiz < 10) spsiz = DSPSIZ;
X
X x = (len-- > 0) ? unchar(data[1]) : DMYTIM; /* Timeout */
X if (!timef) { /* Only use if not overridden */
X timint = x;
X if (timint < 0) timint = DMYTIM;
X }
X
X npad = 0; padch = '\0'; /* Padding */
X if (len-- > 0) {
X npad = unchar(data[2]);
X if (len-- > 0) padch = ctl(data[3]); else padch = 0;
X }
X
X eol = (len-- > 0) ? unchar(data[4]) : '\r'; /* Terminator */
X if ((eol < 2) || (eol > 037)) eol = '\r';
X
X ctlq = (len-- > 0) ? data[5] : CTLQ; /* Control prefix */
X
X if (len-- > 0) { /* 8th-bit prefix */
X ebq = data[6];
X if ((ebq > 040 && ebq < 0100) || (ebq > 0140 && ebq < 0177)) {
X ebqflg = 1;
X } else if (parity && (ebq == 'Y')) {
X ebqflg = 1;
X ebq = '&';
X } else if (ebq == 'N') {
X ebqflg = 0;
X } else ebqflg = 0;
X } else ebqflg = 0;
X
X chklen = 1; /* Block check */
X if (len-- > 0) {
X chklen = data[7] - '0';
X if ((chklen < 1) || (chklen > 3)) chklen = 1;
X }
X bctr = chklen;
X
X if (len-- > 0) { /* Repeat prefix */
X rptq = data[8];
X rptflg = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177));
X } else rptflg = 0;
X
X if (deblog) sdebu(len);
X}
X
X/* S D E B U -- Record spar results in debugging log */
X
Xsdebu(len) int len; {
X debug(F111,"spar: data",data,len);
X debug(F101," spsiz ","",spsiz);
X debug(F101," timint","",timint);
X debug(F101," npad ","",npad);
X debug(F101," padch ","",padch);
X debug(F101," eol ","",eol);
X debug(F101," ctlq ","",ctlq);
X debug(F101," ebq ","",ebq);
X debug(F101," ebqflg","",ebqflg);
X debug(F101," chklen","",chklen);
X debug(F101," rptq ","",rptq);
X debug(F101," rptflg","",rptflg);
X}
X
X/* G N F I L E -- Get the next file name from a file group. */
X
X/* Returns 1 if there's a next file, 0 otherwise */
X
Xgnfile() {
X int x, y;
X
X/* If file group interruption (C-Z) occured, fail. */
X
X debug(F101,"gnfile: czseen","",czseen);
X
X if (czseen) {
X tlog(F100,"Transaction cancelled","",0l);
X return(0);
X }
X
X/* If input was stdin or memory string, there is no next file. */
X
X if (sndsrc == 0) return(0);
X
X/* If file list comes from command line args, get the next list element. */
X
X y = -1;
X while (y < 0) { /* Keep trying till we get one... */
X
X if (sndsrc > 0) {
X if (nfils-- > 0) {
X strcpy(filnam,*cmlist++);
X debug(F111,"gnfile: cmlist filnam",filnam,nfils);
X } else {
X *filnam = '\0';
X debug(F101,"gnfile cmlist: nfils","",nfils);
X return(0);
X }
X }
X
X/* Otherwise, step to next element of internal wildcard expansion list. */
X
X if (sndsrc < 0) {
X x = znext(filnam);
X debug(F111,"gnfile znext: filnam",filnam,x);
X if (x == 0) return(0);
X }
X
X/* Get here with a filename. */
X
X y = zchki(filnam); /* Check if file readable */
X if (y < 0) {
X debug(F110,"gnfile skipping:",filnam,0);
X tlog(F111,filnam,"not sent, reason",(long)y);
X screen(0,0l,"Skipping");
X screen(2,0l,filnam);
X } else fsize = y;
X }
X return(1);
X}
X
X/* O P E N I -- Open an existing file for input */
X
Xopeni(name) char *name; {
X int x, filno;
X if (memstr) return(1); /* Just return if file is memory. */
X
X debug(F110,"openi",name,0);
X debug(F101," sndsrc","",sndsrc);
X
X filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */
X
X debug(F101," file number","",filno);
X
X if (zopeni(filno,name)) { /* Otherwise, try to open it. */
X debug(F110," ok",name,0);
X return(1);
X } else { /* If not found, */
X char xname[100]; /* convert the name */
X zrtol(name,xname); /* to local form and then */
X debug(F110," zrtol:",xname,0);
X x = zopeni(filno,xname); /* try opening it again. */
X debug(F101," zopeni","",x);
X if (x) {
X debug(F110," ok",xname,0);
X return(1); /* It worked. */
X } else {
X screen(2,0l,"Can't open file"); /* It didn't work. */
X tlog(F110,xname,"could not be opened",0l);
X debug(F110," openi failed",xname,0);
X return(0);
X }
X }
X}
X
X/* O P E N O -- Open a new file for output. */
X
X/* Returns actual name under which the file was opened in string 'name2'. */
X
Xopeno(name,name2) char *name, *name2; {
X char xname[100], *xp;
X
X if (stdouf) /* Receiving to stdout? */
X return(zopeno(ZSTDIO,""));
X
X debug(F110,"openo: name",name,0);
X
X xp = xname;
X if (fncnv) /* If desired, */
X zrtol(name,xp); /* convert name to local form */
X else /* otherwise, */
X strcpy(xname,name); /* use it literally */
X
X debug(F110,"openo: xname",xname,0);
X
X if (warn) { /* File collision avoidance? */
X if (zchki(xname) != -1) { /* Yes, file exists? */
X znewn(xname,&xp); /* Yes, make new name. */
X strcpy(xname,xp);
X debug(F110," exists, new name ",xname,0);
X }
X }
X if (zopeno(ZOFILE,xname) == 0) { /* Try to open the file */
X debug(F110,"openo failed",xname,0);
X tlog(F110,"Failure to open",xname,0l);
X return(0);
X } else {
X strcpy(name2,xname);
X debug(F110,"openo ok, name2",name2,0);
X return(1);
X }
X}
X
X/* O P E N T -- Open the terminal for output, in place of a file */
X
Xopent() {
X ffc = tfc = 0;
X return(zopeno(ZCTERM,""));
X}
X
X/* C L S I F -- Close the current input file. */
X
Xclsif() {
X if (memstr) { /* If input was memory string, */
X memstr = 0; /* indicate no more. */
X } else if (hcflg) {
X zclosf(); /* If host cmd close fork, */
X } else zclose(ZIFILE); /* else close input file. */
X
X screen(1,0l," [OK]");
X hcflg = cxseen = 0; /* Reset flags. */
X}
X
X
X/* C L S O F -- Close an output file. */
X
Xclsof() {
X zclose(ZOFILE); /* Close it. */
X if (czseen || cxseen) {
X zdelet(filnam); /* Delete it if interrupted. */
X debug(F100,"Discarded","",0);
X tlog(F100,"Discarded","",0l);
X screen(1,0l," [Discarded]");
X } else {
X debug(F100,"Closed","",0);
X screen(1,0l," [OK]");
X }
X cxseen = 0;
X}
X
X/* S N D H L P -- Routine to send builtin help */
X
Xsndhlp() {
X nfils = 0; /* No files, no lists. */
X xflg = 1; /* Flag we must send X packet. */
X strcpy(cmdstr,"help text"); /* Data for X packet. */
X next = -1; /* Init getch lookahead */
X memstr = 1; /* Just set the flag. */
X memptr = hlptxt; /* And the pointer. */
X return(sinit());
X}
X
X
X/* C W D -- Change current working directory */
X
X/*
X String passed has first byte as length of directory name, rest of string
X is name. Fails if can't connect, else ACKs (with name) and succeeds.
X*/
X
Xcwd(vdir) char *vdir; {
X vdir[unchar(*vdir) + 1] = '\0'; /* End with a null */
X if (zchdir(vdir+1)) {
X encstr(vdir+1);
X ack1(data);
X tlog(F110,"Changed directory to",vdir+1,0l);
X return(1);
X } else {
X tlog(F110,"Failed to change directory to",vdir+1,0l);
X return(0);
X }
X}
X
X
X/* S Y S C M D -- Do a system command */
X
X/* Command string is formed by concatenating the two arguments. */
X
Xsyscmd(prefix,suffix) char *prefix, *suffix; {
X char *cp;
X
X for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
X while (*cp++ = *suffix++) ;
X
X debug(F110,"syscmd",cmdstr,0);
X if (zxcmd(cmdstr) > 0) {
X debug(F100,"zxcmd ok","",0);
X nfils = sndsrc = 0; /* Flag that input from stdin */
X xflg = hcflg = 1; /* And special flags for pipe */
X return (sinit()); /* Send S packet */
X } else {
X debug(F100,"zxcmd failed","",0);
X return(0);
X }
X}
!FUNKY!STUFF!
echo x - ckfns2.c
sed '1,$s/^X//' <<\!FUNKY!STUFF! > ckfns2.c
X/* C K F N S 2 -- System-independent Kermit protocol support functions... */
X
X/* ...Part 2 (continued from ckfns.c) */
X/*
X Note -- if you change this file, please amend the version number and date at
X the top of ckfns.c accordingly.
X*/
X
X#include "ckermi.h"
X
Xextern int spsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas;
X
Xextern int pktnum, prvpkt, sndtyp, fsize, bctr, bctu,
X size, osize, maxsize, spktl, nfils, stdouf, warn, timef;
X
Xextern int parity, speed, turn, turnch,
X delay, displa, pktlog, tralog, seslog, xflg, mypadn;
X
Xextern long filcnt, ffc, flci, flco, tlci, tlco, tfc;
X
Xextern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
X
Xextern char padch, mypadc, eol, ctlq, myctlq, sstate, *hlptxt;
X
Xextern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr,
X mystch;
X
Xextern char *cmarg, *cmarg2, **cmlist;
Xchar *strcpy();
X
X/* I N P U T -- Attempt to read packet number 'pktnum'. */
X
X/*
X This is the function that feeds input to Kermit's finite state machine.
X
X If a special start state is in effect, that state is returned as if it were
X the type of an incoming packet. Otherwise:
X
X . If the desired packet arrives within MAXTRY tries, return its type,
X with its data stored in the global 'data' array.
X
X . If the previous packet arrives again, resend the last packet and wait for
X another to come in.
X
X . If the desired packet does not arrive within MAXTRY tries, return indicating
X that an error packet should be sent.
X*/
X
Xinput() {
X int len, num, type, numtry;
X
X if (sstate != 0) { /* If a start state is in effect, */
X type = sstate; /* return it like a packet type, */
X sstate = 0; /* and then nullify it. */
X *data = '\0';
X return(type);
X } else type = rpack(&len,&num,data); /* Else, try to read a packet. */
X
X/* If it's the same packet we just sent, it's an echo. Read another. */
X
X if (type == sndtyp) type = rpack(&len,&num,data);
X
X chkint(); /* Check for console interrupts. */
X/*
X If previous packet again, a timeout pseudopacket, or a bad packet, try again.
X*/
X for (numtry = 0; num == prvpkt || type == 'T' || type == 'Q' ; numtry++)
X {
X if (numtry > MAXTRY) { /* If too many tries, give up */
X strcpy(data,"Timed out."); /* and send a timeout error packet. */
X return('E');
X }
X resend(); /* Else, send last packet again, */
X type = rpack(&len,&num,data); /* and try to read a new one. */
X chkint(); /* Look again for interruptions. */
X }
X return(type); /* Success, return packet type. */
X}
X
X/* S P A C K -- Construct and send a packet */
X
Xspack(type,num,len,dat) char type, *dat; int num, len; {
X int i,j;
X
X j = dopar(padch);
X for (i = 0; i < npad; sndpkt[i++] = j) /* Do any requested padding */
X ;
X sndpkt[i++] = dopar(mystch); /* Start packet with the start char */
X sndpkt[i++] = dopar(tochar(len+bctu+2)); /* Put in the length */
X sndpkt[i++] = dopar(tochar(num)); /* The packet number */
X sndpkt[i++] = sndtyp = dopar(type); /* Packet type */
X
X for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */
X
X sndpkt[i] = '\0'; /* Mark end for block check */
X switch(bctu) {
X case 1: /* Type 1 - 6 bit checksum */
X sndpkt[i++] = dopar(tochar(chk1(sndpkt+1)));
X break;
X case 2: /* Type 2 - 12 bit checksum*/
X j = chk2(sndpkt+1);
X sndpkt[i++] = dopar(tochar((j & 07700) >> 6));
X sndpkt[i++] = dopar(tochar(j & 077));
X break;
X case 3: /* Type 3 - 16 bit CRC-CCITT */
X j = chk3(sndpkt+1);
X sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12));
X sndpkt[i++] = dopar(tochar((j & 07700) >> 6));
X sndpkt[i++] = dopar(tochar(j & 077));
X break;
X }
X for (j = npad; j > 0; j-- ) sndpkt[i++] = dopar(padch); /* Padding */
X
X sndpkt[i++] = dopar(eol); /* EOL character */
X sndpkt[i] = '\0'; /* End of the packet */
X ttol(sndpkt,spktl=i); /* Send the packet just built */
X flco += spktl; /* Count the characters */
X tlco += spktl;
X if (pktlog) zsoutl(ZPFILE,sndpkt); /* If logging packets, log it */
X screen(type,(long)num,sndpkt); /* Update screen */
X}
X
X/* D O P A R -- Add an appropriate parity bit to a character */
X
Xdopar (ch) char ch; {
X int a;
X switch (parity) {
X case 'm': return(ch | 128); /* Mark */
X case 's': return(ch & 127); /* Space */
X case 'o': ch |= 128; /* Odd (fall thru) */
X case 'e': /* Even */
X a = (ch & 15) ^ ((ch >> 4) & 15);
X a = (a & 3) ^ ((a >> 2) & 3);
X a = (a & 1) ^ ((a >> 1) & 1);
X return(ch | (a << 7));
X default: return(ch);
X }
X}
X
X/* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */
X
Xchk1(pkt) char *pkt; {
X int chk;
X chk = chk2(pkt);
X return((((chk & 0300) >> 6) + chk) & 077);
X}
X
X
X/* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */
X
Xchk2(pkt) char *pkt; {
X unsigned int chk;
X int p;
X for (chk = 0; *pkt != '\0'; *pkt++) {
X p = (parity) ? *pkt & 0177 : *pkt;
X chk += p;
X }
X return(chk);
X}
X
X
X/* C H K 3 -- Compute a type-3 Kermit block check. */
X/*
X Calculate the 16-bit CRC of a null-terminated string using a byte-oriented
X tableless algorithm invented by Andy Lowry (Columbia University). The
X magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1.
X Note - this function could adapted for strings containing imbedded 0's
X by including a length argument.
X*/
Xchk3(s) char *s; {
X unsigned int c, q;
X LONG crc = 0;
X
X while ((c = *s++) != '\0') {
X if (parity) c &= 0177;
X q = (crc ^ c) & 017; /* Low-order nibble */
X crc = (crc >> 4) ^ (q * 010201);
X q = (crc ^ (c >> 4)) & 017; /* High order nibble */
X crc = (crc >> 4) ^ (q * 010201);
X }
X return(crc);
X}
X
X/* Functions for sending various kinds of packets */
X
Xack() { /* Send an ordinary acknowledgment. */
X spack('Y',pktnum,0,""); /* No data. */
X nxtpkt(&pktnum); /* Increment the packet number. */
X} /* Note, only call this once! */
X
Xack1(s) char *s; { /* Send an ACK with data. */
X spack('Y',pktnum,strlen(s),s); /* Send the packet. */
X nxtpkt(&pktnum); /* Increment the packet number. */
X} /* Only call this once! */
X
Xnack() { /* Negative acknowledgment. */
X spack('N',pktnum,0,""); /* NAK's never have data. */
X}
X
Xresend() { /* Send the old packet again. */
X int w;
X
X for (w = 0; w < timint - 2; w++) { /* be extra sure no stuff is */
X ttflui(); /* still comming in */
X sleep(1);
X if (!ttchk() ) ttinc(1); /* be extra sure no stuff in SIII/V */
X if (!ttchk() ) break;
X }
X ttol(sndpkt,spktl);
X screen('%',(long)pktnum,sndpkt);
X if (pktlog) zsoutl(ZPFILE,sndpkt);
X}
X
Xerrpkt(reason) char *reason; { /* Send an error packet. */
X encstr(reason);
X spack('E',pktnum,size,data);
X}
X
Xscmd(t,dat) char t, *dat; { /* Send a packet of the given type */
X encstr(dat); /* Encode the command string */
X ttflui(); /* Flush pending input. */
X spack(t,pktnum,size,data);
X}
X
Xsrinit() { /* Send R (GET) packet */
X encstr(cmarg); /* Encode the filename. */
X ttflui(); /* Flush pending input. */
X spack('R',pktnum,size,data); /* Send the packet. */
X}
X
Xnxtpkt(num) int *num; {
X prvpkt = *num; /* Save previous */
X *num = (*num + 1) % 64; /* Increment packet number mod 64 */
X}
X
Xsigint() { /* Terminal interrupt handler */
X errpkt("User typed ^C");
X doexit(0); /* Exit with status = 0 */
X}
X
X/* R P A C K -- Read a Packet */
X
Xrpack(l,n,dat) int *l, *n; char *dat; {
X int i, j, x, done, pstart, pbl;
X char chk[4], xchk[4], t, type;
X
X chk[3] = xchk[3] = 0;
X i = inlin(); /* Read a line */
X if (i != 0) {
X debug(F101,"rpack: inlin","",i);
X screen('T',(long)pktnum,"");
X return('T');
X }
X debug(F110,"rpack: inlin ok, recpkt",recpkt,0);
X
X/* Look for start of packet */
X
X for (i = 0; ((t = recpkt[i]) != stchr) && (i < RBUFL) ; i++)
X ;
X if (++i >= RBUFL) return('Q'); /* Skip rest if not found */
X
X/* now "parse" the packet */
X
X debug(F101,"entering rpack with i","",i);
X done = 0;
X while (!done) {
X debug(F101,"rpack starting at i","",i);
X pstart = i; /* remember where packet started */
X
X/* length */
X
X if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */
X
X /*** if (t == 2) doexit(0); *** uncomment this to allow ^A^B cause exit ***/
X
X if (t == MYEOL) return('Q');
X *l = unchar(t); /* Packet length */
X debug(F101," pkt len","",*l);
X
X/* sequence number */
X
X if ((t = recpkt[i++]) == stchr) continue;
X if (t == MYEOL) return('Q');
X *n = unchar(t);
X debug(F101,"rpack: n","",*n);
X
X/* cont'd... */
X
X/* ...rpack(), cont'd */
X
X
X/* type */
X
X if ((type = recpkt[i++]) == stchr) continue;
X if (type == MYEOL) return('Q');
X debug(F101,"rpack: type","",type);
X
X if ((type == 'S') || (type == 'I')) pbl = 1; /* Heuristics for */
X else if (type == 'N') pbl = *l - 2; /* syncing block check type */
X else pbl = bctu;
X
X *l -= (pbl + 2); /* Now compute data length */
X debug(F101,"rpack: bctu","",bctu);
X debug(F101," pbl","",pbl);
X debug(F101," data length","",*l);
X
X/* data */
X
X dat[0] = '\0'; /* Return null string if no data */
X for (j=0; j<*l; i++,j++)
X if ((dat[j] = recpkt[i]) == stchr) continue;
X else if (dat[j] == MYEOL) return('Q');
X dat[j] = '\0';
X
X/* get the block check */
X
X debug(F110," packet chk",recpkt+i,0);
X for (j = 0; j < pbl; j++) {
X chk[j] = recpkt[i];
X debug(F101," chk[j]","",chk[j]);
X if (chk[j] == stchr) break;
X if (chk[j] == eol) return('Q');
X recpkt[i++] = '\0';
X }
X chk[j] = 0;
X debug(F111," chk array, j",chk,j);
X if (j != pbl) continue; /* Block check right length? */
X done = 1; /* Yes, done. */
X }
X
X/* cont'd... */
X
X/* ...rpack(), cont'd */
X
X
X/* Got packet, now check the block check */
X
X switch (pbl) {
X case 1:
X xchk[0] = tochar(chk1(&recpkt[pstart]));
X if (chk[0] != xchk[0]) {
X if (deblog) {
X debug(F000,"rpack: chk","",chk[0]);
X debug(F000," should be ","",xchk[0]);
X }
X screen('Q',(long)n,recpkt);
X return('Q');
X }
X break;
X case 2:
X x = chk2(&recpkt[pstart]);
X xchk[0] = tochar((x & 07700) >> 6);
X xchk[1] = tochar(x & 077);
X if (deblog) {
X debug(F000," xchk[0]","=",xchk[0]);
X debug(F000," xchk[1]","=",xchk[1]);
X }
X if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) {
X debug(F100," bct2's don't compare","",0);
X screen('Q',(long)n,recpkt);
X return('Q');
X }
X break;
X case 3:
X x = chk3(&recpkt[pstart]);
X xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12);
X xchk[1] = tochar((x & 07700) >> 6);
X xchk[2] = tochar(x & 077);
X if (deblog) {
X debug(F000," xchk[0]","=",xchk[0]);
X debug(F000," xchk[1]","=",xchk[1]);
X debug(F000," xchk[2]","=",xchk[2]);
X }
X if ((xchk[0] != chk[0]) ||
X (xchk[1] != chk[1]) ||
X (xchk[2] != chk[2])) {
X debug(F100," bct3's don't compare","",0);
X screen('Q',(long)n,recpkt);
X return('Q');
X }
X break;
X }
X
X/* Good packet, return its type */
X
X ttflui(); /* Done, flush any remaining. */
X screen(type,(long)(*n),recpkt); /* Update screen */
X return(type);
X}
X
X/* I N C H R -- Input character from communication line, with timeout */
X
Xinchr(timo) int timo; {
X int c;
X c = ttinc(timo);
X debug(F101,"inchr ttinc","",c);
X if (c < 0) return(c); /* Get a character */
X if (parity) c = c & 0177; /* If parity on, discard parity bit. */
X debug(F101," after parity","",c);
X return(c);
X}
X
X
X/* I N L I N -- Input a line (up to break char) from communication line */
X
X/* Returns 0 on success, nonzero on failure */
X
Xinlin() {
X int e, i, j, k;
X
X e = (turn) ? turnch : MYEOL;
X i = j = k = 0;
X if (parity) {
X while ((j != e) && (i < RBUFL) && (k < MAXTRY)) {
X j = inchr(1); /* Get char, 1 second timeout */
X debug(F101,"inlin inchr","",j);
X if (j < 0) k++; /* Timed out. */
X else {
X if (j) recpkt[i++] = j; /* Save it */
X k = 0; /* Reset timeout counter. */
X }
X }
X } else {
X i = ttinl(recpkt,RBUFL,timint,e); /* Get them all at once */
X if (i < 0) k = 1;
X }
X debug(F111,"inlin",recpkt,i);
X debug(F101," timeouts","",k);
X if (i < 1) return(1);
X if (pktlog) zsoutl(ZPFILE,recpkt);
X if (k > MAXTRY) return(1);
X tlci += i; /* Count the characters. */
X flci += i;
X recpkt[i+1] = '\0'; /* Terminate the input string. */
X return(0);
X}
!FUNKY!STUFF!
More information about the Comp.sources.unix
mailing list