Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: Notesfiles $Revision: 1.7 $; site okstate Path: utzoo!watmath!clyde!cbosgd!ihnp4!okstate!authorplaceholder From: gregg@okstate.UUCP Newsgroups: net.sources Subject: C-KERMIT (Part 7 of 10) Message-ID: <5200021@okstate> Date: Fri, 8-Mar-85 02:48:00 EST Article-I.D.: okstate.5200021 Posted: Fri Mar 8 02:48:00 1985 Date-Received: Sat, 9-Mar-85 10:19:14 EST Lines: 1274 Nf-ID: #N:okstate:5200021:000:37912 Nf-From: okstate!gregg Mar 8 01:48:00 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!