/* rcnct.c */

#define	RCNCTMASTER

/*
 *  Includes
 */
#include <string.h>
#include <stdio.h>

#include "os.h"
#include "vrsion.h"
#include "vrcnct.h"
#include "dfault.h"
#include "evtdef.h"
#include "hstdef.h"
#include "prodef.h"
#include "kbkeys.h"
#include "cliutl.h"
#include "cticks.h"
#include "tsxutl.h"
#include "rtfile.h"
#include "kbdutl.h"
#include "inicli.h"
#include "jobmon.h"
#include "usrblk.h"
#include "suspnd.h"

/*
 * Internal routines
 */

/*
 * Due to DECUS C aborts from lack of space
 * all functions/subroutines of type 'int'
 * are no longer explicitly defined.
 *
 * DECUS C defaults to 'int', VOID == int
 */

#if 0
extern	VOID	printtxt();
extern	int	cltsxline();
extern	int	setrtel();
extern	int	dosess();
extern	VOID	rctresp();
extern	VOID	transfer();
extern	VOID	lsterr();
extern	int	rtresp();
extern	VOID	strlwr();
extern	int	getword();
extern	VOID	rcnctd();
extern	int	parse();
extern	int	Scheckpass();
extern	int	Scompass();
#endif

extern	char	*stptok();
extern	char	*stpblk();

/*
 * debug -
 *
 *	bit 0	(0x01)	enable printing of internal events
 *	bit 1	(0x02)	enable printing of telnet negotiations
 */
#define DBUGTRUE	-1	/* all debuggers */


#if ts$sys
char *usetxt[] = {
       "",
#ifdef	DEBUGOPTION
       "  RCNCT [?] [-d level] [-hmp filespec] [-acelrtvyz] [parameters]",
       "	d  level	Debug Level",
       "		1 -	enable event printing",
       "	?               List the Help Text and Exit RCNCT",
#else
       "  RCNCT [?] [-hmp filespec] [-acelrtvyz] [parameters]",
       "	?               List the Help Text and Exit RCNCT",
#endif
       "	a		Attach to Service",
       "	c  i		CL line i is cross connected to TSX line j",
       "	e		Enable Monitoring of all Transactions",
       "	h		Specify the Help Filespec",
       "	l  n		Number of CL/TSX line pairs",
       "	m		Specify the Message Filespec",
       "	p		Specify the Password Filespec",
       "	r		Restart RCNCT after Disconnect",
       "	t  j		TSX line j is cross connected to CL line i",
       "	v		Verbose Mode",
       "	y  s		Login Timeout in seconds",
       "	z  s		Inactivity Timeout in seconds",
       "",
       0
       };
#endif

#if rt$sys
char *usetxt[] = {
       "",
#ifdef	DEBUGOPTION
       "  RCNCT [?] [-d level] [-hmp filespec] [-certvyz] [parameters]",
       "	d level	Debug Level",
       "	   1 -	enable event printing",
       "	?       List the Help Text and Exit RCNCT",
#else
       "  RCNCT [?] [-hmp filespec] [-celrtvyz] [parameters]",
       "	?       List the Help Text and Exit RCNCT",
#endif
       "	c  i	Connection Line i is attached to Terminal line j",
       "	e	Enable Monitoring of all Transactions",
       "	h	Specify the Help Filespec",
       "	m	Specify the Message Filespec",
       "	p	Specify the Password Filespec",
       "	r	Restart RCNCT after Disconnect",
       "	t  j	Terminal Line j is attached to Connection line i",
       "	v	Verbose Mode",
       "	y  s	Login Timeout in seconds",
       "	z  s	Inactivity Timeout in seconds",
       "",
       0
       };
#endif

/* Definitions for supported telnet protocols */

#define IP			244	/* \364 */
#define AO			245	/* \365 */
#define AYT			246	/* \366 */
#define IAC		 	255	/* \377 */

#define IACFOUND		6
#define	CRFOUND			3
#define STNORM			0

/*
 *	Global Buffers / Pointers
 */

char	pathname[94],		/* path */
	username[80],		/* username */
	password[80],		/* password */
	command[80],		/* command string */
	rsp[256],		/* response string */
	scratch[256];		/* scratch string */

struct userblock
	user;			/* usernames / passwords / mailboxes */

char	xs[2];			/* dumby buffer required by TSXUTL.C */

int	aflag = 0,		/* attach flag */
	rflag = 0,		/* restart flag */
	mflag = 0,		/* monitor flag */
	pswdreqd = 1,		/* password required */
	clunit = -1,		/* CL unit number */
	tsxline = -1,		/* TSX line number */
	ctpairs = 1,		/* CL/TSX line pairs */
	cline = -1,		/* CLn line in use */
	tline = -1,		/* TSX line in use */
	cltl = -1,		/* CL/TSX line error */
	rcncskt = -1,		/* RCNCT socket number */
	rfstate = 0,		/* current process state */
	retstate = 0,		/* return state */
	waitpos = 0,		/* incoming command index */
	echo = 1,		/* echo flag */
	cnctopen = 0,		/* connection open flag */
	cnctclose = 0,		/* connection to be closed flag */
	logincnt = 0;		/* login retry counter */

int	yflag = 0,		/* login timeout flag */
	zflag = 0;		/* inactivity timeout flag */

long	lzaptime = 0L,		/* login zap time in ticks */
	izaptime = 0L;		/* inactivity zap time in ticks */

struct	socket			/* socket structure */
	*skt = NULL;

char	outbuffer[512];

int	outcnt = 0,		/* count to transfer */
	outotal = 0,		/* count left to transfer */
	outidx = 0,		/* array index */
	outdly = 0;		/* output delay parameter */

char	inpbuffer[256];

int	inpcnt = 0,		/* count to transfer */
	rdidx = 0,		/* read array index */
	wrtidx = 0;		/* write array index */

char	*pass = "PAS:paswrd.fil";	/* password file */
char	*mesg = "TCP:rcnct.msg";	/* message file */
char	*help = "TCP:rcnct.hlp";	/* help file */


/*
 *  printout text
 */
VOID printtxt(txt)
char **txt;
{
	register char **dp;

	for (dp = txt; *dp; dp++) {
		if (**dp == '_') {
			kb_puts(*dp + 1);
		} else {
			kb_puts(*dp);
			kb_nline();
		}
	}
}

main(argc,argv)
int argc;
char *argv[];
{
	int ev,i,j,k,c;

	/*
	 * Initialize for TSX+ clients
	 */
	inicli();

	/*
	 * Initialize kb handler
	 * Set the break character to ^C
	 */
	kb_init(0x03);

	/*
	 * Verbose Mode Off
	 */
	kb_prnt = 0;

	/*
	 * parse arguments
	 */
	for(i=1; i<argc; i++) {
		if(argv[i][0] == '?') {
		    kb_prnt = 1;
		    printtxt(usetxt);
		    exit(0);
		} else
		if(argv[i][0] == '-') {
		    j = i;
		    k = 1;
		    while((c = argv[j][k]) != '\0') {
			switch(tolower(c)) {
#if ts$sys
			case 'a':	/* attach to service */
				aflag = 1;
				break;
#endif
			/*
			 * This is a 'hidden' option for bypassing
			 * password requirements for rcnct.
			 */
			case 'b':	/* bypass password processing */
				pswdreqd = 0;
				break;

			case 'c':	/* CLn unit select */
				sscanf(argv[++i],"%d",&clunit);
				break;
#ifdef	DEBUGOPTION
			case 'd':	/* debug, optional level */
				if(sscanf(argv[++i],"%d",&debug) <= 0)
					debug = -1;
				break;
#endif
			case 'e':	/* enable RCNCT monitoring */
				mflag = 1;
				break;

			case 'h':	/* help file */
				help = argv[++i];
				break;
#if ts$sys
			case 'l':	/* CL/TSX line pairs */
				sscanf(argv[++i],"%d",&ctpairs);
				break;
#endif
			case 'm':	/* message file */
				mesg = argv[++i];
				break;

			case 'p':	/* password file */
				pass = argv[++i];
				break;

			case 'r':	/* enable RCNCT restarting */
				rflag = 1;
				break;
#if ts$sys
			/*
			 * This is a 'hidden' option for setting the
			 * the default subdirectory base 'ld' unit
			 * and setting the maximum subdirectory nesting
			 *	note:	subdbase + subdnest <= 8
			 */
			case 's':
				sscanf(argv[++i],"%d",&subdbase);
				sscanf(argv[++i],"%d",&subdnest);
				break;
#endif
			case 't':	/* TSX line number */
				sscanf(argv[++i],"%d",&tsxline);
				break;

			case 'v':	/* verbose mode on */
				kb_prnt = 1;
				break;

			case 'y':	/* login timeout flag */
				sscanf(argv[++i],"%d",&yflag);
				lzaptime = 60L * yflag;
				break;

			case 'z':	/* inactivity timeout flag */
				sscanf(argv[++i],"%d",&zflag);
				izaptime = 60L * zflag;
				break;

			default:	/* unknown option */
				printf(
				"Unrecognized option -%c ignored\r\n", c);
				break;
			}
			k++;
		    }
		}
	}

#ifdef	DEBUGOPTION
	if (debug)
		kb_prnt = 1;
#endif

	/*
	 * identify self
	 */
	printtxt(vrstxt);

	/*
	 *  Get the CL line and associated TSX line
	 */

	cltl = cltsxline();
	if(cltl) {
		fndbrk = 1;
	}

	/*
	 *  Start listening to the RCNCT port
	 */
	while(!fndbrk && (setrtel()<0)) {
		/*
		 * Could not get a socket, wait 5 seconds
		 */
		suspnd(300);
	}

	while(!fndbrk && ev != -1) {
		ev = dosess();
		if(ev==0)
			suspnd(0);
	}

	cd("dk:");

	if(fndbrk) 
		kb_puts("\r\n^C\r\n");

	if(!cltl) {
		skclose(rcncskt);
		skrelease(rcncskt,1);

		suspnd(0);
		errhandle();

		sl_abort();

		killjob(tline);
	}

	kb_puts("\r\nEscaping from RCNCT\r\n");
	exit(0);
}

/*
 *	try to get a CL line and associated TSX line
 */
int cltsxline()
{
	int i;

	if((clunit == -1) || (tsxline == -1)) {
		return(-1);
	}

	for(i=0,cline=clunit,tline=tsxline; i<ctpairs; i++,cline++,tline++) {
		if(!sl_init(cline)) {
			jobmon(tline,5);
			return(0);
		}
	}
	return(-1);
}

/*
 *	set up to receive a rcnct connection
 */
int setrtel()
{
	int sknum;

	rfstate = 0;		/* state of the control channel */
	retstate = 0;		/* to emulate a subroutine call */
	logincnt = 0;		/* reset login counter */

	/*
	 * Initialize various things
	 */
	Snetinit();

	/*
	 * Empty CL unit buffer
	 */
	while(sl_gets(outbuffer,1)) {
		suspnd(1);
	}

	/*
	 * aflag = 1	indicates attach mode
	 * aflag = 0	indicates listen mode
	 */
	if(aflag) {
		/*
		 * Attach job to connection opened by TCPIP
		 */
		sknum = attach(0,HCNCT);
		if(sknum==-1) {
			fndbrk++;
			return(-1);
		} else {
			Stmrset(ABORTCLASS,CLIENT,sknum,CONNWAITTIME);
		}
	} else {
		/*
		 * Create socket for control connection
		 */
		sknum = socket(0);
		if(sknum==-1)
			return(-1);
		/*
		 * default port
		 */
		listen(sknum,HCNCT);
	}

	rcncskt = sknum;
	skt = (struct socket *) mapskt(sknum);

	return(sknum);

}

/*
 *  dosess
 *
 *  dosess is an infinite loop serving
 *  incoming messages from TCPIP
 */
int dosess()
{
	int  cl,ev,dat;

	/*
	 * Check for any relevant messages
	 * that need to be handled by me
	 */
	ev = Sgetevent(SCKTCLASS | CONCLASS | USERCLASS |
			ERRCLASS | MSGCLASS | ABORTCLASS, &cl, &dat);
	if(ev!=0) {
	  switch(cl) {
	    case CONCLASS:
	      /*
	       * RCNCT Connection Socket
	       */
	      rcnctd(ev);
	      break;

	    case MSGCLASS:	/* messages */
	    case ERRCLASS:	/* error message */
	      kb_puts(skerrstring(ev));
	      kb_nline();
	      break;

	    case ABORTCLASS:	/* abort */
	      switch(ev) {
		case CLIENT:
		  kbprintf("\r\nRCNCT session aborted by TCPIP\r\n");
		  Stmrset(ABORTCLASS,EXITABORT,dat,5);

		case USERABORT:
		  if(skrelease(dat,0) < 0) {
		    skptuev(CONCLASS,CONDATA,dat);
		  } else {
		    skclose(dat);
		    Stmrset(ABORTCLASS,USERABORT,dat,1);
		  }
		  break;

		case EXITABORT:
		  return(-1);
		  break;

		default:
		  break;
	      }
	      break;

	    default:
	      break;
	  }
	} else {
	  rcnctd(0);
	}

	return(ev);
}

/*
 * Dump response to client
 */
VOID rctresp(s)
register char *s;
{
	skwrite(rcncskt, s, strlen(s));
	skenque(rcncskt, 1);
	if(mflag) {
		kbprintf(" {%d} ", strlen(s));
		kb_puts(s);
	}
}

/*
 * transfer
 *
 * Transfer Message File
 */
transfer(fp)
FILE *fp;
{
	int fini;

	fini = FALSE;
	sprintf(rsp,"    ");
	do {
		if(skroom(rcncskt) > LOWWATER) {
			if(fgetss(rsp+4,sizeof(rsp)-7,fp) != NULL) {
				strcat(rsp,"\r\n");
				rctresp(rsp);
			} else {
				fini = TRUE;
			}
		} else {
			suspnd(6);
		}
	} while(fini != TRUE);
}

/*
 * This is the error print routine for TSXUTL.C
 * It will be called only if there is an internal error
 */
VOID lsterr()
{
	if(*errstr) {
		kb_puts(errstr);
		kb_nline();
		errstr[0] = '\0';
	}
}

/*
 * This routine is a dumby routine for TSXUTL.C
 * It should never be called, but returns a 1 [ABORT]
 */
int rtresp()
{
	kb_puts("rtresp: This dumby routine should never be called");
	return(1);
}

char *stptok( p, toword, ilen, delim)
register char *p;
char *toword;
int ilen;
char *delim;
{
	register char *adv;
	register int i;
	int j,end;
 
	adv = toword;
	end = 0;
	j = strlen(delim);

 	do { 
 		for(i=0; i<j; i++)
 			if(*p == delim[i] || (!*p))
				end++;
 		if(!end) {
 			if(adv >= (toword+ilen-1)) 
				end++;
 			*adv++=*p++;
 		}
 	} while(!end);
 	*adv='\0';
 	return(p);
}
 
char *stpblk(ch)
register char *ch;
{
 	while(*ch == ' ' || *ch == '\t') ch++;
 	return(ch);
}

VOID strlwr(st)
register char *st;
{
	while(*st) {
		*st = tolower(*st);
		*st++;
	}
}

/*
 * getword: remove a word from a string.  Things within quotes are
 * assumed to be one word.
 * return TRUE on success, FALSE on end of string
 */

int getword(string,word)
char *string;
register char *word;
{
	register char *p;
	register int i;
	char *q;

	i = 0;

	/*
	 * skip leading blanks
	 */
	p = stpblk(string);
	if(!(*p)) {
		/*
		 * no words in string
		 */
		word[0] = '\0';
		return(FALSE);
	}
	if(*p == '\"') {
		/*
		 * word delimited by quotes
		 */
		while(p[++i] && p[i] != '\"')
			word[i-1] = p[i];
		word[i-1] = '\0';
		if(!p[i]) {
			/*
			 * Missing \". Assumed at end of string.
			 */
		} else {
			i++;
		}
		q = p+i;
	} else {
		/*
		 * get word, max len 79
		 */
		q = stptok(p, word, 79, " \t\r\n");
	}
     	/*
	 * remove trailing blanks
	 */
	p = stpblk(q);
	/*
	 * remove extracted stuff
	 */
	strcpy(string,p);
	return(TRUE);
}

/*
 *	Remote CNCT Server
 */
VOID rcnctd(code)
int code;
{
	register int c,cnt,i;
	char word[80],*p,s[80];
	FILE *fp;

	if(rcncskt < 0)
		return;

	/* 
	 * Take incoming data and process it.
	 */
	if(cnctopen) {
		cnt = skread(rcncskt,s,80);
		if(cnt > 0) {
			skdeque(rcncskt);
			for(p=s,i=0; i<cnt; i++,p++) {
				c = parse(*p);
				if(c && (inpcnt < sizeof(inpbuffer))) {
					inpbuffer[wrtidx] = c;
					wrtidx += 1;
					inpcnt += 1;
					if(wrtidx >= sizeof(inpbuffer)) {
						wrtidx = 0;
					}
				}
			}
		}
		if(cnt < 0) {
			cnctclose = 1;
		}
		if((rfstate == 3) && (retstate == 3)) {
			/*
			 * Process Inactivity Timeout
			 */
			if((zflag != 0) &&
			   (skquetime != 0L) &&
			   (elapsed(skquetime) > izaptime)) {
				rctresp(
	/*Net*/
	"\r\n\r\nInactivity Timeout\r\n"
	/*Net*/
					);
				cnctclose = 1;
			}
		} else {
			/*
			 * Process Login Timeout
			 */
			if((yflag != 0) &&
			   (skquetime != 0L) &&
			   (elapsed(skquetime) > lzaptime)) {
				rctresp(
	/*Net*/
	"\r\n\r\nLogin Timeout\r\n"
	/*Net*/
					);
				cnctclose = 1;
			}
		}
	}

	/*
	 * close this session, if over
	 */
	if((code == CONCLOSE) || (code == CONFAIL) ||
	   ((jbabrt() & 0xFF) == tline) || cnctclose) {
		/*
		 * Connection not open
		 */
		cnctopen = 0;
		cnctclose = 0;

		/*
		 * Kill the TSX job attached through the CL unit
		 */
		killjob(tline);

		if(rcncskt >= 0) {
			sksendwait(rcncskt,(long) SENDWAIT);
			skclose(rcncskt);
			rcncskt = skrelease(rcncskt,1);
		}
		if(rflag && !aflag) {
			/*
			 *  Start listening to the remote CNCT port
			 */
			while((setrtel()<0) && !fndbrk) {
				/*
				 * Could not get a socket, wait 5 seconds
				 */
				suspnd(300);
			}
		} else {
			fndbrk = 1;
		}
	}

	switch(rfstate) {
	case 0:
		if(code!=CONOPEN)
			break;

		Stmrunset(ABORTCLASS,CLIENT,rcncskt);

		/*
		 * Enable Timeout
		 */
		cticks(&skquetime);

		/*
		 * Connection open
		 */
		cnctopen = 1;

		p = skt->tcpout.i.ipsource;

		sprintf(rsp,
	/*Net*/
	"    %s%s\r\n", vrstxt[1]+1, vrstxt[2]
	/*Net*/
			);
		rctresp(rsp);
		sprintf(rsp,
	/*Net*/
	"    Remote CNCT Server @%s [%d.%d.%d.%d]\r\n", skt->hostname,
		*(p+0)&0xFF, *(p+1)&0xFF, *(p+2)&0xFF, *(p+3)&0xFF
	/*Net*/
			);
		rctresp(rsp);

		p = skt->tcpout.i.ipdest;

		sprintf(rsp,
	/*Net*/
	"    Initiated from host: %d.%d.%d.%d\r\n",
		*(p+0)&0xFF, *(p+1)&0xFF, *(p+2)&0xFF, *(p+3)&0xFF
	/*Net*/
			);
		rctresp(rsp);

		if((fp = rtopen(mesg,"r",0,0)) != NULL) {
			transfer(fp);
			rtclose(fp);
		}

		if(pswdreqd) {
			/*
			 * Request Username
			 */
			rctresp(
	/*Net*/
	"Username> "
	/*Net*/
			);
			rfstate = 50;
			retstate = 1;
			echo = 1;
		} else {
			if((fp = rtopen(help,"r",0,0)) != NULL) {
				transfer(fp);
				rtclose(fp);
			}
			/*
			 * Log Session
			 */
			logsession(rcncskt,"RCNCT:");
			sl_putc('\r');
			rfstate = 3;
			retstate = 3;
			echo = 0;
		}

		waitpos = 0; 
		break;

	case 1:
		if(getword(command,word) == FALSE) {
			/*
			 * Request Username Again
			 */
			rctresp(
	/*Net*/
	"Username> "
	/*Net*/
			);
			rfstate = 50;  
			retstate = 1;
			waitpos = 0;  
			echo = 1;
			break;
		}

#ifdef	DEBUGOPTION
if(debug&0x04) {
	printf("rcnctd(%d): %s %s\r\n", code,word,command);
}
#endif

		logincnt += 1;
		/*
		 * keep user name
		 */
		username[0] = '\0';
		strncat(username,word,USERPASSLEN);
		strlwr(username);

		/*
		 * Request Password
		 */

		rctresp(
	/*Net*/
	"Password> "
	/*Net*/
			);

		rfstate = 50;  
		retstate = 2;
		waitpos = 0;  
		echo = 0;
		break;

	case 2:
		/*
		 * keep password
		 */
		password[0] = '\0';
		strncat(password,command,USERPASSLEN);
		strlwr(password);

		if(Scheckpass(username,password)) {
	/*
	 * User Specific Message File
	 */
	if(user.msgfil.path[0] != '\0' &&
		(fp = rtopen(&user.msgfil.path,"r",0,0)) != NULL) {
		sprintf(rsp,
	/*Net*/
	"    Message to User %s\r\n", username
	/*Net*/
			);
		rctresp(rsp);
		transfer(fp);
		rtclose(fp);
	}
			/*
			 * Help File
			 */
			if((fp = rtopen(help,"r",0,0)) != NULL) {
				transfer(fp);
				rtclose(fp);
			}
			/*
			 * Log Session
			 */
			sprintf(scratch,
	/*Log*/
	"RCNCT: %s", username
	/*Log*/
				);
			logsession(rcncskt,scratch);
			sl_putc('\r');
			rfstate = 3;
			retstate = 3;
			waitpos = 0;  
		} else {
			if(logincnt >= 3) {
				cnctclose = 1;
				rfstate = 0;
				retstate = 0;
				break;
			}				
			/*
			 * Request Username Again
			 */
			rctresp(
	/*Net*/
	"Invalid Username/Password\r\n\r\nUsername> "
	/*Net*/
			);
			rfstate = 50;  
			retstate = 1;
			waitpos = 0;  
			echo = 1;
		}
		break;

	case 3:
		/*
		 * transfer incoming characters to the CL line
		 */
		while(inpcnt) {
			if(sl_putc(inpbuffer[rdidx]) != EOF) {
				rdidx  += 1;
				if(rdidx >= sizeof(inpbuffer)) {
					rdidx = 0;
				}
				inpcnt -= 1;
				if(inpcnt == 0) {
					suspnd(6);
				}
			} else {
				break;
			}
		}
		/*
		 * transfer CL line characters
		 * to the other host via the NET
		 */
		if(outotal <= outidx) {
			/*
			 * need to read again
			 */
			outcnt = sl_gets(outbuffer,sizeof(outbuffer));
			outotal = outcnt;
			outidx = 0;
		}
		outcnt = outotal - outidx;
		if(outcnt>0) {
			outcnt = skwrite(rcncskt,&outbuffer[outidx],outcnt);
		}
		if(outcnt>0) {
			/*
			 * send successful, adjust counts
			 */
			outidx += outcnt;
			skenque(rcncskt,1);
		}
		outdly = (outcnt + outdly + outdly + outdly) >> 2;
		if(outdly > 15) {
			suspnd(12);
			suspnd(-1);
		}
		break;

	case 50:
		/*
		 * subroutine to wait
		 * for a particular character
		 */
		while(inpcnt) {
			c = inpbuffer[rdidx];
			command[waitpos] = c;
			rdidx  += 1;
			inpcnt -= 1;
			if(rdidx >= sizeof(inpbuffer)) {
				rdidx = 0;
			}
			if((c == '\177') || (c == '\010')) {
				if(echo && waitpos) {
					skwrite(rcncskt,"\010\040\010",3);
					skenque(rcncskt,1);
				}
				if(waitpos) {
					--waitpos;
				}
				continue;
			} else {
				if(echo) {
					skwchar(rcncskt,c);
					skenque(rcncskt,1);
				}
			}
			if(command[waitpos] == '\r') {
				skwrite(rcncskt,"\r\n",2);
				skenque(rcncskt,1);
				rfstate = retstate;
				/*
				 * find end of string
				 */
				while (	(command[waitpos] < 33) &&
					(waitpos >= 0) )
					waitpos--;
				/*
				 * put in terminator
				 */
				command[++waitpos] = '\0';
				break;
			} else {
				if(waitpos < sizeof(inpbuffer)-1)
					waitpos += 1;
			}
		}
		break;

	default:
		break;
	}
}

/*
 *  parse
 *
 *  Parse the incoming date for specific telnet style commands
 */
int parse(c)
register int c;
{
	register int *telstate;

	c &= 0xFF;

	/*
	 * telnet modes
	 */
	telstate = &(skt->session.telstate);

	switch(*telstate) {
	case CRFOUND:
		*telstate = STNORM;
		if(c == '\012') {
			return('\0');
		}

	case STNORM:
		if(c == IAC) {
			*telstate = IACFOUND;
			return('\0');
		} else
		if(c == '\015') {
			*telstate = CRFOUND;
		}
		return(c);

	case IACFOUND:
		switch(c) {
		case IP:
			c = 'C' & 0x1F;
			break;

		case AO:
			c = 'O' & 0x1F;
			break;

		case AYT:
			rctresp(
	/*Net*/
	"Remote CNCT Running\r\n"
	/*Net*/
			);

		default:
			c = '\0';
			break;
			
		}
		break;

	default:
		break;
	}

	*telstate = STNORM;
	return(c);
}

/*
 *  Scheckpass ( us, ps )
 *
 *  Check the password file for the user/password
 *  combination. An inaccessable password file
 *  results in an invalid return.
 *
 *  If the user/password is invalid or the
 *  default directory is not accessable
 *  Scheckpass returns invalid.
 *
 *  Returns valid(1)/invalid(0)
 */
int Scheckpass(us,ps)
char *us,*ps;
{
	FILE *fp;
	
	if(NULL==(fp = rtopen(pass,"rn",0,0))) {
		return(0);
	}
	while (NULL != fread(&user,sizeof(struct userblock),1,fp)) {
		/*
		 * does password check ?
		 */
		if(!strncmp(us,&user.username,USERPASSLEN) &&
			(PASSNOTREQUIRED & user.userflag[0]  ||
				Scompass(ps,&user.password))) {
			rtclose(fp);
			if(!(RCNCT_PRIV & user.userflag[1])) {
				sprintf(rsp,
	/*Net*/
	"User '%s' does not have remote CNCT privilege\r\n", username
	/*Net*/
					);
				rctresp(rsp);
				return(0);
			}

			/*
			 * Verify Users default directory
			 */
			getpath(pathname);
			if(cd(&user.defdir.path)) {
				/*
				 * failed
				 */
				sprintf(rsp,
	/*Net*/
	"%s\r\n", errstr
	/*Net*/
					);
				rctresp(rsp);
				cd(pathname);
				errstr[0] = '\0';
				return(0);
			} else {
				/*
				 * success
				 */
				cd(pathname);
				return(1);
			}
		}
	}
	rtclose(fp);
	return(0);
}

/*
 *  Scompass ( ps, en )
 *
 *  Compute and check the encrypted password
 */
int Scompass(ps,en)
char *ps,*en;
{
	int i,ck;
	char *p,c;

	ck = 0;
	p = ps;
	/*
	 * checksum the string
	 */
	while (*p)
		ck += *p++;
	c = ck;
	/*
	 * XOR with checksum
	 */
	i = USERPASSLEN;
	while (i--) {
		if((((*ps ^ c)|32)&127)!=*en)
			return(0);
		/*
		 * increment checksum to hide length
		 */
		if(*ps) {
			ps++;
		} else {
			c++;
		}
		en++;
	}
	return(1);
}

                                                                                                                                          