/*			dcp.c

			Revised edition of dcp

			Stuart Lynne May/87

			Copyright (c) Richard H. Lamb 1985, 1986, 1987
			Changes Copyright (c) Stuart Lynne 1987
Maintenance Notes:
  25Aug87 - Added a version number - Jal
  25Aug87 - Return 0 if contact made with host, or 5 otherwise.
  04Sep87 - Bug causing premature sysend() fixed. - Randall Jessup.

*/
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* This program implements a uucico type file transfer and remote 
execution type protocol. 
*/
#define  VERSION "1.0"
#include "dcp.h"
/**/
int	pktsize;                	/* packet size for pro */
FILE	*logfile;            	/* system log file */
FILE	*syslog;            	/* system log file */
FILE	*fw;                 	/* cfile pointer */
char	state;					/* system state*/
char	cfile[80];              /* work file pointer */
int		remote;                 /* -1 means we're remote ..7*/
int		msgtime;                /* timout setting */
char	fromfile[132];
char	hostfile[132];		/* host version of fromfile */
char	tofile[132];
int		fp;                     /* current disk file ptr */
int		size;                   /* nbytes in buff */
FILE	*fsys;
char	Rmtname[20];
char	rmtname[20];
char	* cctime;
char	proto[5];
/* char	loginseq[256]; */
char 	sysline[BUFSIZ];
char	s_systems[64];
char	s_logfile[64];
char	s_syslog[64];
char 	*flds[60];
int 	kflds;
int		debuglevel;		/* debugging flag */

unsigned int	checksum();


/**/
/* new usage

	dcp	[-xn] -r0		slave mode
	dcp	[-xn] -shost 		call host
	dcp	[-xn] -sall		call all hosts
	
	dcp	[-xn] 		call any hosts as required by C. files
		
*/

complain( s )
char *s;
{
	fprintf( stderr, "Please set your %s environment variable.", s );
}

static void cant( file )
char *file;
{
	fprintf( stderr, "Can't open: \"%s\"\n", file );
	exit( 8 );
}

dcpmain( argc, argv )
int	argc;
char*argv[];
{
	FILE	*ftmp;
	char	line[132];
	int	Contact = FALSE;

	if ( name == NULL || *name == '\0' ) {
		complain( NAME );
		exit( -1 );
	}
	if ( nodename == NULL || *nodename == '\0' ) {
		complain( NODENAME );
		exit( -1 );
	}
		

	mkfilename( s_logfile, spooldir, LOGFILE );
	mkfilename( s_syslog,  spooldir, SYSLOG  );
	mkfilename( s_systems, confdir,  SYSTEMS );

	if ( (logfile = FOPEN( s_logfile, "a", 't' )) == NULL )
	   cant( s_logfile );
	if ( (syslog  = FOPEN( s_syslog,  "a", 't' )) == NULL )
	   cant( s_syslog );
	
	fp = -1;
	fw = (FILE *)NULL;
	remote = MASTER;
	strcpy( Rmtname, "any" );
	debuglevel = 1;
	remote = MASTER;
	printmsg(0, "\f\t\t\tUUPC Version %s\n", VERSION );


	while ( --argc ) {
		if ( **++argv == '-') {
			switch(argv[0][1]) {
			case 'x':
				debuglevel = atoi( &argv[0][2] );
				break;
			case 's':
				sprintf( Rmtname, "%.7s", &argv[0][2] );
				break;
			case 'r':
				remote = atoi( &argv[0][2] );
				break;
				
			default:
				break;
			}
		}
	}
		

	if ( remote == MASTER ) {
		printmsg( 0, "Calling %s    %d", Rmtname, debuglevel );
		if (( fsys = FOPEN( s_systems, "r", 't' )) == (char *)NULL ) 
			exit( FAILED );
		state = 'I';
		

		while (TRUE) {
			printmsg( 4, "Mstate = %c", state );
			switch (state) {
			case 'I': 
				state = getsystem();    
				break;
			case 'S': 
				state = callup();       
				break;
			case 'P': 
				state = startup();      
				break;
			case 'D': 
				state = master();       
				Contact = TRUE;
				break;
			case 'Y': 
				state = sysend();       
				break;
			case 'G': 
				if ( strcmp( Rmtname, "any" ) == SAME )
					state = 'Y';
				else
					state = 'I';            
				break;
			}
			if (state == 'A') 
				break;
		}
		fclose( fsys );
	} else
	 {
		if (openline( device, speed ) == -1) 
			return(FALSE);
		state = 'L';
		while (TRUE) {
			printmsg( 4, "Sstate = %c", state );
			switch (state) {
			case 'L':
				state = login();     
				break;
			case 'I':
				state = startup();   
				break;
			case 'R':
				state = slave();     
				break;
			case 'Y':
				state = sysend();    
				break;
			}
			if (state == 'A') 
				break;
		}
		closeline();
	}


	/* fprintf( stderr, "calling dcxqt\n" ); */
	if (dcxqt()) 
		printmsg( 0, "ERROR in DCXQT" );
			
	/* scan and process any recieved files */

	fclose( syslog );
	fclose( logfile );
	if (Contact )
	   return 0;
	else
	   return 5;
}


/**/
/*
**
**
**master
**
**
*/
master()
{
	state = 'I';
	while (TRUE) {
		printmsg( 4, "Top level state (master mode) %c", state );
		switch (state) {
		case 'I':
			state = sinit();      
			break;
		case 'B':
			state = scandir();    
			break;
		case 'S':
			state = send();       
			break;
		case 'Q':
			state = sbreak();     
			break;
		case 'G':
			state = receive();    
			break;
		case 'C':
			state = 'Y';          
			break;
		case 'Y':
			state = endp();       
			break;
		case 'P':
			return('Y');
		case 'A':
			return('A');
		default:
			return('A');
		}
	}
}


/**/
/*
**
**
**slave
**
**
*/
slave()
{
	state = 'I';
	while (TRUE) {
		printmsg( 4, "Top level state (slave mode) %c", state );
		switch (state) {
		case 'I':
			state = rinit();      
			break;
		case 'F':
			state = receive();    
			break;
		case 'C':
			state = schkdir();    
			break;
		case 'T':
			state = 'B';          
			break;
		case 'B':
			state = scandir();    
			break;
		case 'S':
			state = send();       
			break;
		case 'Q':
			state = sbreak();     
			break;
		case 'G':
			return('Y');
		case 'Y':
			state = endp();       
			break;
		case 'P':
			return('Y');
		case 'A':
			return('A');
		default:
			return('A');
		}
	}
}


/**/
/*
 *  r e c e i v e
 *
 *  This is the state table switcher for receiving files.
 */

receive()
{

	state = 'F';/* Receive-Init is the start state */

	while (TRUE) {
		printmsg( 4, " receive state: %c", state );
		switch (state)/* Do until done */ {
		case 'F':
			state = rfile(); 
			break; /* Receive-File */
		case 'D':
			state = rdata(); 
			break; /* Receive-Data */
		case 'C':
			return('C');/* Complete state */
		case 'A':
			return('Y');/* "Abort" state */
		default:
			return('Y');
		}
	}
}


/**/
/*
 *  s e n d 
 *
 *  Sendsw is the state table switcher for sending files.  It loops until
 *  either it finishes, or an error is encountered.  The routines called
 *  by sendsw are responsible for changing the state.
 *
 */
send()
{
	fp = -1;                /* reset file getter/opener */
	state = 'F';/* Send initiate is the start state */
	while (TRUE)/* Do this as long as necessary */ {
		printmsg( 4, "send state: %c", state );
		switch (state) {
		case 'F':
			state = sfile();  
			break; /* Send-File */
		case 'D':
			state = sdata();  
			break; /* Send-Data */
		case 'Z':
			state = seof();  
			break; /* Send-End-of-File */
		case 'B':
			return ('B'); /* Complete */
		case 'A':
			return ('Y'); /* "Abort" */
		default:
			return ('Y'); /* Unknown, fail */
		}
	}
}


/**/
/* A command formatter for DCP. RH Lamb */
/* sets up stdin and stdout on various machines */
/* There is NO command checking so watch what you send and who you */
/* let accsess your machine. "C rm /usr/*.*" could be executed. */
dcxqt()
{
	int	i;
	char	command[60], input[60], output[60], line[BUFSIZ];
	char	*cp;
	
	while (dscandir()) {
		strcpy( line, cfile );
		fw = FOPEN( line, "r", 'b' );/* imported X file */
		strcpy(cfile, line);
		printmsg( 2, "dcxqt:%s %ld", cfile, fw );
		input[0]   = '\0';
		output[0]  = '\0';
		command[0] = '\0';
		while ( fgets( line, BUFSIZ, fw ) != (char *)NULL ) {

			cp = index( line, '\n' );
			if ( cp != (char *)NULL )
				*cp = '\0';

			printmsg( 8, "dcxqt: %s", line );
			switch (line[0]) {
			case 'U':       
				break;
			case 'I':
				strcpy( input,   &line[2] );
				break;
			case 'O':       
				strcpy( output,  &line[2] );
				break;
			case 'C':
				strcpy( command, &line[2] );
				break;
			case 'R':       
				break;
			default :       
				break;
			}
		}
		fclose( fw );

		printmsg( 0, "xqt: %s\n", command );
			
		shell( command, input, output, (char *)NULL );
		
		
		unlink(cfile);
 		importpath( hostfile, input );
 		unlink(hostfile);
		importpath( hostfile, output );
 		unlink(hostfile);
	}
	return(0);
}

/**/
/*
 *  p r i n t m s g
 *
 *  Print error message on standard output if not remote.
 */
/*VARARGS1*/
printmsg(level, fmt, a1, a2, a3, a4, a5)
int 	level;
char	*fmt;
char	*a1, *a2, *a3, *a4, *a5;
{
	char	msg[256];

	if ( debuglevel > level ) {
		sprintf( msg, fmt, a1, a2, a3, a4, a5 );
		strcat( msg, "\n" );
		if ( remote == MASTER ) 
			fputs( msg, stdout );
		fputs( msg, logfile );
	}
}




