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