
/***********************************************************************/

/*  File  KLINE.C  -  Comms-line handling procedures for RML Kermit;
		Chris Kennington	RML.	9th July 1985.	*/

#define	 DEFS1	1
#define	 DEFS2	1

#include  "stdio.h"
#include  "b:kext.h"


/* local globals for nextin/nextout		*/
static	int	fuzzy = 20000;	/* arbitry value */	
static	int	ret;
static	char	dummy, typout;
static  char	comerr[] = "Comms err %x";
static	char	enter[]  = " Enter %s for mainframe:\r> ";


connect()		/* keyboard/screen to comms line relay	*/
/* Reads keyboard and transmits to line; reads line and outputs to
	screen; checks comms line for error conditions.		*/
{
    char  c, cn, conn;
    static  char  pager = 0, *data[5];
    int   in;

    printmsg("Connecting you to remote mainframe ...  ");
    keyconn();				/* make arrows valid	*/
    outc(NL);
    kmode = CONN;
    while (kmode == CONN) {		/* until stopped	*/
	if (keyget(&c) != 0) {
	    if (echo != 0)
		outc(c);
	    cn = 100;
	    while (cn-- > 0)
		if (s4put(1,&c) > 0)
		    break;
	    if (cn == 0)
		bell();
	}
	if ( (in = s4get7(1,&data)) == 1 ) {
#ifndef MPUZ80
	  if (*data != LF)
#endif
	    outfc(*data);
	}
	else if (in != 0) {
	    outc(NL);
	    printmsg("Comms error code %x; ", in);
	    while (s4test() == in)
		;
	}	    
    }			/* end switch			*/
  /* broken out	by changing kmode			*/
    return;
}		/* End of connect()			*/




flushinput()
/*  Dump all pending input to clear stacked up NAK's. */
{
    char  rubbish[11];

    while (s4get(10,rubbish) > 0)
	;
}			/* end of flushinput		*/



inctry()		/* increment tries & pkt-#	*/
/* used by both recieve & send routines			*/
{
    oldtry = numtry;
    numtry = 0;
    n = (n+1)%64;
    return;
}			/* end of inctry()		*/



/* Line-I/O Routines for sending/receiving files		*/

static nextab()		/* set abort-flag if CTLC		*/
{
    if (dummy == CTLC) {	/* treat ctlc as abort	*/
	printmsg("Abort transfer");
	if (confirm() == TRUE)
	    abtflag = 1;
	dummy = 0;
    }
    return;
}			/* end of nextab()			*/

nextin(ic)			/* next char from line		*/
/* strips parity bit if !image; handles fuzzy timeout;
   returns 0, but 1 if either abtflag or nakflag has been set	*/
char  *ic;
{
    int		r;

    abtflag = nakflag = 0;
One:
    while ( (ret = (image) ? s4get(1,ic) : s4get7(1,ic)) == 0 ) {
	keyget(&dummy);
	nextab();
	if ( (abtflag+nakflag) != 0 )
	    return(1);
	if (--fuzzy == 0) {	/* timer expired	*/
	    nakflag = 1;
	    ++timouts;
	    if (list == 1)
		outc('T');
	    if (list > 2)
		txtout("\rDbg: Timeout.");
	    return(1);
    }   }
    while (ret < 0) {		/* error		*/
	printmsg(comerr,ret);
	while ( (r = (image) ? s4get(1,ic) : s4get7(1,ic)) == ret) {
	    keyget(&dummy);
	    if ( (abtflag+nakflag) != 0 )
		return(1);
	}
	if (r == 0)
	    goto One;
	ret = r;
    }
    if (list > 4)
	outc(*ic);
    if (*ic == SOH)	
	fuzzy = fuzz[env]; /* fuzzy timer re-set on SOH only */
    return(abtflag+nakflag);
}			/* end of nextin()		*/



nextout(c)		/* next char to line		*/
/* returns 0, but 1 if either abtflag or nakflag has been set	*/
char  c;
{
    int  r;

    abtflag = nakflag = 0;
One:
    while ( (ret = s4put(1,&c)) == 0 ) {
	keyget(&dummy);
	nextab();
	if ( (abtflag+nakflag) != 0 )
	    return(1);
	}
    while (ret < 0) {		/* error		*/
	printmsg(comerr,ret);
	while ( (r = s4put(1,&c)) == ret) {
	    keyget(&dummy);
	    if ( (abtflag+nakflag) != 0 )
		return(1);
	    }
	if (r == 0)
	    goto One;
	ret = r;
    }
    if (list > 4)
	outc(c);
    keyget(&dummy);
    return(abtflag+nakflag);
}			/* end of nextout()		*/



char  rpack(len,num,data)	/*  Read a Packet		*/
/*  If !image, nextin() has stripped the parity bit.		*/
int *len, *num;				/* Packet length, number */
char *data;				/* Packet data */
{
    int i, done;			/* Data character number, loop exit */
    char t,				/* Current input character */
	cchksum,			/* Our (computed) checksum */
	rchksum;			/* Checksum received from other host */
    static int oldnum = 63;

Top:
    fuzzy = fuzz[env];			/* set timer		*/
    t = type = 0;			/* could be garbage	*/
    *len = 0;				/* in case timeout	*/
    while (t != SOH) if (nextin(&t) != 0) {
	    type = 'T';
	    goto Flag;
    }

    done = FALSE;			/* Got SOH, init loop */
    while (!done) {			/* Loop to get a packet */
	if (nextin(&t) != 0)		/* Get length character */
	    break;
	cchksum = t;			/* Start the checksum */
	if (t == SOH)
	    continue;			/* Resynchronize if SOH */
	t &= 0x7f;			/* 7-bit protocol char	*/
	if ( (*len = unchar(t)-3) < 0 )	/* Character count */
	    return(FALSE);		/* protect against bad length	*/
	if (nextin(&t) != 0)		/* Get packet-number character */
	    break;
	cchksum = cchksum + t;		/* Update checksum */
	t &= 0x7f;			/* 7-bit protocol char	*/
	if (t == SOH)
	    continue;			/* Resynchronize if SOH */
	*num = unchar(t);		/* Packet number */
	if (*num == oldnum)
	    ++dupes;			/*  its a duplicate	*/
	else
	    oldnum = *num;
	vtout(LOCSEQ,t|0x80);

	if (nextin(&t) != 0)		/* Get packet-type character */
	    break;
	cchksum = cchksum + t;		/* Update checksum */
	t &= 0x7f;			/* 7-bit protocol char	*/
	if (t == SOH)
	    continue;			/* Resynchronize if SOH */
	if ( (type = t) == 'N' ) {
	    ++naxin;			/*  its a NAK	*/
	    if (list == 1)
		outc('N');
	}
	if (type == typout)
	    goto Top;			/* its an echo		*/
	vtout(LOCIN,type);

	for (i=0; i<*len; i++) {	/* The data itself, if any */
	    if (nextin(&t) != 0)	/* Get data character */
		break;
	    cchksum = cchksum + t;	/* Update checksum */
	    data[i] = t;		/* Put it in the data buffer */
	    t &= 0x7f;			/* 7-bit char		*/
	    if (t == SOH) break;	/* stop if SOH */
	}
	if (t == SOH)
	    continue;			/* Resynchronize if SOH */
	if ( (nakflag+abtflag) != 0 )
	    break;
	data[*len] = 0;			/* Mark the end of the data */

	if (nextin(&t) != 0)		/* Get checksum character */
	    break;
	rchksum = unchar(t);		/* Convert to numeric */
	done = TRUE;			/* Got checksum, done */
    }
    flushinput();			/* discard anything stacked */
    if ( (list > 3) && ( (nakflag+abtflag) == 0 ) ) {	/* Display	*/
	outc(CR);
	printf("  Packet in: type %c, num %d, len%d;",type,*num,*len);
	outc(CR);
	if (*len != 0) {
	    data[*len] = 0;
	    printf("  data: \"%s\";",data);
	    outc(CR);
    }	}

Flag:				/* check for user abort or nak	*/
    vtout(LOCIN,type|0x80);		/* inverse of type	*/
    if (nakflag != 0)
	return(FALSE);			/* cause NAK to be sent	*/
    if (abtflag != 0) {
	abtflag = 0;
	return('A');			/* cause ABORT		*/
    }
					/* Fold in bits 7,8 to compute */
    cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */

    if (cchksum == rchksum) {
	if (type == 'D')
	    blockmv(oldpkt,data,*len);	/* copy for reference	*/
	 return(type);			/* OK return		*/
    }
    ++badcrcs;				/* count bad checksum	*/
    if (list == 1)
	outc('C');
    else if (list > 2)
	txtout(" Bad checksum ");
    return(FALSE);
}			/* end of rpack()			*/



servsend(type)		/* send command to server-Kermit etc.	*/
char	type;
{
    int		*len, *num;
    char	pkt;

    switch(type) {

      case RMSV:		/* Server Commands		*/
	pkt = 'K';			/* packet-type		*/
	goto Rmcont;

      case RMH:			/* OS Commands			*/
	pkt = 'C';			/* packet-type		*/
Rmcont:
	txtout(" Calling mainframe ... ");
	if (parex() == 0) {		/* exchange parameters	*/
	    printmsg("Mainframe Kermit seems dead ");
	    kmode = KERM;
	    break;
	}
	else forever {
	    printmsg(enter,"message");
	    if (keyline(packet) == 0) {
		kmode = CMND;
		break;
	    }
	    printmsg("Telling mainframe ... ");
	    recsw(type,pkt);
	}
	break;

      case GET:			/* fetch files			*/
	printf(inform);
	printmsg(enter,"filenames");
	if (keyline(packet) == 0)
	    kmode = KERM;
	else {
	    vtline(LOCMODE,rcvng);
	    state = kmode = GET;
	}
	break;

      case SEND:		/* send files			*/
	vtline(LOCMODE,sendf);
	kmode = SEND;
	break;

      case BYE:			/* logout from mainframe	*/
	spack('G',n,1,"L");		/* generic logout	*/
	kmode = KERM;
	outc(SP);
	txtout(trying);
	rpack(&len,&num,recpkt);
	if (len != 0) {
	    recpkt[*len] = 0;
	    printmsg("%s %s",mainsays,recpkt);
	}
	break;

      case LOGO:		/* cancel mainframe Kermit	*/
	spack('G',n,1,"F");		/* try "Finish"		*/
	txtout(dots);
	if (rpack(&len,&num,recpkt) != 'Y') /* synchronize	*/
	    spack('E',0,strlen(errmsg),errmsg);
	vtline(LOCMODE,connto);
	kmode = CONN;
	break;

      case QUIT:		/* cancel (local) Kermit	*/
	kermkill(1);

      case MAIN:		/* back to top level		*/
	kmode = KERM;
	break;

    }			/* end switch				*/
    return;
}			/* end of servsend()			*/



setbaud()		/* set line-speed from spdcode	*/
{
    vtline(LOCSPEED+3,"  ");
    vtline(LOCSPEED,spval[spdcode]);
    s4speed(spdcode);
    return;
}			/* end of setbaud()		*/



setpar()		/* set parity from parity	*/
{
    commode &= 0xfcff;		/* remove parity bits	*/
    commode |= (int)parity * 256; /* substitute new	*/
    s4set(commode,comctrl);
    return;
}			/* end of setpar()		*/



spack(type,num,len,data)		/*  Send a Packet */
char type, *data;
int num, len;
{
    int i;				/* Character loop counter */
    char 	c, chksum;
    register char *bufp;		/* Buffer pointer */
    static  int  cumnum = 0;

    if (list > 3) {			/* Display outgoing packet */
	outc(CR);
	printf("  Packet out: type %c, num %d, len %d:",type,num,len);
	outc(CR);
	if (len != 0) {
	    data[len] = 0;
	    printf("  data: \"%s\";",data);
	    outc(CR);
    }	}

    vtout(LOCOUT,type);
    vtout(LOCSEQ,tochar(n));
    sprintf(work,"%d =",cumnum++);
    vtline(LOCPKTS,work);

    for (i=1; i<=pad; i++)
	if (nextout(&padchar) != 0)	/* padding	*/
	    return;
    bufp = work;			/* buffer pointer */
    *bufp++ = SOH;
    *bufp++ = tochar(len+3);
    chksum  = tochar(len+3);
    *bufp++ = tochar(num);
    chksum += tochar(num);
    typout = *bufp++ = type;
    chksum += type;

    for (i=0; i<len; i++) {		/* for all data characters */
	*bufp++ = c = data[i];
	chksum += c;
    }
    chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
    *bufp++ = tochar(chksum);
    *bufp++ = eol;			/* Extra-packet line terminator */
    *bufp = CR;				/*  & CR for safety		*/
    len = bufp-work+1;
    bufp = work;
    while (len-- > 0)
	if (nextout(*bufp++) != 0)
	    break;
    vtout(LOCOUT,type|0x80);		/* inverse of type		*/
    if (netslow)			/* discard any buffered dupes	*/
	flushinput();
    return;
}			/* end of spack()				*/



/**********************  End of KLINE.C  **************************/


