#include "V.h"
#include "sys_fcntl.h"
#include "sys_signal.h"

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*	conn port1 [port0]
*
* Connect two ports together.  This program forks, and each process then
* tries to copy data as fast as it can between the two ports.
* The program can produce audit trails of the conversations by using
* the V_conn or DBGconn environment variables.
*
* This program also works if either or both of the files is a fifo.
*
* This is still a bit experimental...
*/
#define IBUF 10

	int   bytesize = 8;		/* How big are the bytes? */
	char  cmdchr = '~';		/* Interactive command character */
	char *dir = "?";
	int   openopt = O_RDWR;	/* |O_NONBLOCK */
	char  pd[] = "/dev/tty";	/* Default port name */
	char *p0 = pd;
	char *p1 = pd;
	int   f0 = -1;
	int   f1 = -1;
	int   parity = 0;	/* What type of parity */
	int   pid1 = 0;		/* file1 -> file2 id, if there is one */
	int   pid2 = 0;		/* file2 -> file1 id, if there is one */

char *
baseName(p)
	char *p;
{	char *r;

	for (r=p; *r; r++)
		if (*r == '/')
			p = r + 1;
	return p;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copy data from fi to fo.
*/
copy(fi,pi,fo,po)
	int   fi,  fo;	/* Input and output file handles */
	char *pi, *po;	/* Input and output file names */
{	int  i, n;
	char ibuf[IBUF];
	char*li, *lo;
	char mi[50], mo[50];
	Fenter("copy");
	V4 "From %d=%s to %d=%s",fi,Dsps(pi,-1),fo,Dsps(po,-1) D;
	li = baseName(pi); sprintf(mi,"<%s\0",li);
	lo = baseName(po); sprintf(mo,">%s\0",lo);

	for (;;) {
		if (Vlvl > 3)
			Sleep(1);
		if ((n=Read(fi,ibuf,IBUF) > 0)) {
			V6 "Got %d bytes:",n D;
			H5(ibuf,n,mi);
			switch (bytesize) {
			  case  7:
				V5 "Trim to 7 bits." D;
				for (i=0; i<n; i++) {
					switch(parity) {
					  case 0:	ibuf[n] = B7(ibuf[n]); break;
					  case 1:	ibuf[n] |= 0x080; break;
					}
				}
				break;
			  case  8:
			  default:
				V8 "No byte changes." D;
			}
			if (ibuf[0] == cmdchr) {
				if (n < 2)
					n += Read(fi,ibuf+1,IBUF-1);
				if (n < 2 || ibuf[1]=='q') {
					connexit(0);
				}
				continue;
			}
			V5 "Write %d bytes to file %d...",n,fo D;
			Write(fo,ibuf,n);
			V6 "Put %d bytes:",n D;
			H5(ibuf,n,mo);
		}
	}
	/*NOTREACHED*/
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
die(n)
{
	P2 "%s\tProcess %d [%s] exiting.",Vtime(),mypid,pname D;
	Exit(n);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
main(ac,av)
	char **av;
{	int  a, c0, c1;
	char *p;

	ac = Vinit(ac,av);
	mypid = getpid();
	V5 "Process %d started.  There are %d args.",mypid,ac D;
	for (a=1; a<ac; a++) {	/* Process the command line */
		V4 "Arg%3d=\"%s\"",a,av[a] D;
		c0 = av[a][0];
		switch (c0) {
		case '-':
		case '+':
			V4 "Opt%3d=\"%s\"",a,av[a] D;
			switch (c1 = av[a][1]) {
			  case '8':		/* Byte-size options */
			  case '7':
				bytesize = c1 - '0';
				V3 "Byte size: %d.",bytesize D;
				continue;
			  default:
				V1 "Unknown option \"%s\" ignored.",av[a] D;
			}

			continue;
		default:
			p0 = p1;
			p1 = av[a];
			V3 "p0=\"%s\" p1=\"%s\"",p0,p1 D;
		}

	}

	connsig();		/* Catch interesting signals */
	V2 "p0=%s p1=%s",Dsps(p0,-1),Dsps(p1,-1) D;
	V5 "before Open3(%s,0%o,0)",Dsps(p0,-1),openopt D;
	if ((f0 = Open3(p0,openopt,0)) < 0) {
		V1 "Can't open %s [Err %d=%s=%s]",Dsps(p0,-1),Errinfo D;
		Exit(errno);
	}

	V5 "before Open3(%s,0%o,0)",Dsps(p1,-1),openopt D;
	if ((f1 = Open3(p1,openopt,0)) < 1) {
		V1 "Can't open %s [Err %d=%s=%s]",Dsps(p1,-1),Errinfo D;
		Exit(errno);
	}

	V3 "Opened %d=%s and %d=%s",f0,Dsps(p0,-1),f1,Dsps(p1,-1) D;
	if (isatty(f0)) MakeRaw(f0,p0);
	if (isatty(f1)) MakeRaw(f1,p1);
	V5 "Fork ..." D;
	if ((pid1 = Fork()) <= 0) {
		pname = dir = "==>";
		Strcpy(av[0],pname);
		Voptstr.v[Voptstr.l-1] = '1';
		Vopt(0L);
		mypid = getpid();
		Voptstr.v[Voptstr.l-1] = '1';
		Vopt(0L);
		V4 "Process %d [%s] started.",mypid,dir D;
		connsig();		/* Catch interesting signals */
		V5 "copy(%d,%s,%d,%s) ...",f0,Dsps(Dsps(p0,-1),-1),f1,Dsps(Dsps(p1,-1),-1) D;
		copy(f0,p0,f1,p1);		/* process 1 is p0 -> p1 */
		V5 "copy(%d,%s,%d,%s) returned!",f0,Dsps(p0,-1),f1,Dsps(p1,-1) D;
		Exit(0);
	}
	V2 "pid1=%d [Err %d=%s=%s]",pid1,Errinfo D;
	Sleep(Vlvl);
	if ((pid2 = Fork()) <= 0) {
		pname = dir = "<==";
		Strcpy(av[0],pname);
		Voptstr.v[Voptstr.l-1] = '2';
		Vopt(0L);
		mypid = getpid();
		V4 "Process %d [%s] started.",mypid,dir D;
		connsig();		/* Catch interesting signals */
		V5 "copy(%d,%s,%d,%s) ...",f1,Dsps(p1,-1),f0,Dsps(p0,-1) D;
		copy(f1,p1,f0,p0);		/* process 2  is p1 -> p0 */
		V5 "copy(%d,%s,%d,%s) returned!",f1,Dsps(p1,-1),f0,Dsps(p0,-1) D;
		Exit(0);
	}
	V2 "pid2=%d [Err %d=%s=%s]",pid2,Errinfo D;
	Sleep(Vlvl);
	Vflvl = -1;
	Sleep(1000000);
	Kill(pid1,SIGTERM); Kill(pid2,SIGTERM); Sleep(2);
/*
	Kill(pid1,SIGHUP);  Kill(pid2,SIGHUP);  Sleep(2);
	Kill(pid1,SIGQUIT); Kill(pid2,SIGQUIT); Sleep(2);
	Kill(pid1,SIGKILL); Kill(pid2,SIGKILL);
*/
	Exit(0);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
connexit(s)
{
	Fenter("connexit");
	if (isatty(f0)) MakeSane(f0,p0);
	if (isatty(f1)) MakeSane(f1,p1);
	if (pid1) {
		V5 "Kill process %d.",pid1 D;
		Kill(pid1,SIGTERM);
	}
	if (pid2) {
		V5 "Kill process %d.",pid2 D;
		Kill(pid2,SIGTERM);
	}
	Sleep(Vlvl);
	V2 "Exit with status %d.",s D;
	Exit(s);
	exit(s);
	_exit(s);
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
conncfg(s)
{
	Fenter("conncfg");
	Fexit;
}

