/*
 *	dcpxfer.c
 *
 *	Revised edition of DCP
 *
 *	Stuart Lynne May/87
 *	Copyright (c) Richard H. Lamb 1985, 1986, 1987
 *	Changes Copyright (c) Stuart Lynne 1987
 *
 *	$Id: dcpxfer.c,v 1.2 90/01/16 10:25:25 crash Exp Locker: crash $
 */

#ifndef lint
static char RCSid[] = "$Id: dcpxfer.c,v 1.2 90/01/16 10:25:25 crash Exp Locker: crash $";
#endif /* lint */

/*
 *	"DCP" is a uucp clone.  Copyright Richard H. Lamb 1985, 1986, 1987
 *
 *	file send/receive routines
 */

#include "dcp.h"

#ifndef _U
# include <ctype.h>
#endif

#ifdef AMIGA
void *IntuitionBase = 0, *OpenLibrary();
void CloseLibrary();
static unsigned long fileSecs, fileMicro;	/* For xmit logging purposes */
#endif /* AMIGA */

int filecount;
static long filetime, filesize;
static char file_buf[256];			/* buffer used by rfile() & sfile() */
static char *file_flds[10];			/* (ditto) */

static unsigned char	rpacket[MAXPACK];
static unsigned char	spacket[MAXPACK];


int closelibs(x)
int x;
{
	if (IntuitionBase)	CloseLibrary(IntuitionBase), IntuitionBase = 0;
	return( x );
}


void logtime(dir)
char *dir;
{
	register struct tm *tim;	/* Start time in fields for display */
#ifdef AMIGA
	unsigned long Secs, Micro;	/* Current time (for calculating duration) */
	register unsigned long thousandths;
	register int msd;
#else
	long Secs, Micro;			/* Current time (for calculating duration) */
	register unsigned long thousandths;
	register int msd;
#endif /* AMIGA */

	tim = localtime( &filetime );

#ifdef AMIGA
	if (!IntuitionBase)
		IntuitionBase = OpenLibrary("intuition.library", 0L);
	if (IntuitionBase) {
		CurrentTime( &Secs, &Micro );
		if (Micro < fileMicro)
			Secs -= fileSecs+1, Micro += 1000000L - fileMicro;
		else
			Secs -= fileSecs,   Micro -= fileMicro;
		Micro /= 100000L;
		thousandths = (100 * filesize) / (10 * Secs + Micro);
	} else {
		Secs = time( 0L ) - filetime;
		Micro = 0;
		thousandths = (10 * filesize) / Secs;
	}
#else /* !AMIGA */
	Secs = time( 0L ) - filetime;
	Micro = 0;
	thousandths = (10 * filesize) / Secs;
#endif /* AMIGA */

	msd = (int) (thousandths / 10L);
	fprintf(syslog,					/* 68 characters (usually) */
"%s!%-6s %c (%02d/%02d-%02d:%02d:%02d) (C,PID,%02d) [SER:] %s %6ld bytes / %4ld.%01d secs, %3d.%01d baud\n",
		rmtname, file_flds[3], remote == MASTER ? 'M' : 'S',
		(int) tim->tm_mon+1, (int) tim->tm_mday,
		(int) tim->tm_hour, (int) tim->tm_min, (int) tim->tm_sec,
		++filecount,
		dir,
		filesize, Secs, (int) Micro,		/* Faster than modulus?? */
		msd, (int) (thousandths - msd * 10L)
		);
	closelibs(0);
}


/***************SEND PROTOCOL***************************/
/*
 *  sdata
 *		send file data
 */
sdata()
{
	while( TRUE ) {
		filesize += (long) size;
		if ((*sendpkt) ( spacket, size, 0 ))
			return (0 );						/* send data */
		if (( size = bufill( spacket )) == 0 )  /* Get data from file */
			return( 'Z' ); 					/* If EOF set state to that */
	}
	return('D');							/* Got data, stay in state D */
}


/*
 *  bufill
 *		Get a bufferful of data from the file that's being sent.
 *		8-bit & repeat count prefixes are not handled.
 */
bufill(buffer)
char *buffer;
{
	return( read(fp, buffer, pktsize) );	/* Handle partial buffer */
}


/*
 *  sbreak
 *  	send hangup request
 */
sbreak()
{
	int	len, i;
	strcpy(spacket, "H");
	if ((*sendpkt)(spacket, 0, 1))
		return(0);
	if ((*getpkt)(spacket, &len))
		return(0);
	printmsg( 1, "\n********************************\nSwitch modes" );
	if (spacket[1] == 'N')
		return('G');
	return('Y');
}


/*
 *  seof
 *		send end-of-file.
 */
seof()
{
	int	len;

	if ((*sendpkt)(spacket, 0, 0))
		return(0);
	if ((*getpkt)(spacket, &len))
		return(0);					/* receive CY or CN */
	if (strncmp(spacket, "CY", 2) != SAME)
		return(0);					/* couldn't copy file */

	close(fp);
	fp = (-1);
 	importpath( hostfile, fromfile );
	unlink(hostfile);
	logtime("->");
	printmsg( 0, "Transfer of %s (%s) completed.", fromfile, hostfile );
	return('F');                    /* go get the next file to send */
}


/*
 *  sfile
 *		send file header
 */
sfile()
{
	int	i, len;
	char * cp;
	if (fp == -1) {					/* If not already open, */
		printmsg( 3, "looking for next file..." );
		if (getfile()) {			/* get next file from current work */
			fclose( fw );
			unlink( cfile );		/* close and delete completed workfile */
			fw = (FILE *) NULL;
			return('B');			/* end sending session */
		}
 		importpath( hostfile, fromfile );

		printmsg( 3, "Opening %s (%s) for sending", fromfile, hostfile );
		fp = open(hostfile, 0);		/* open the file to be sent */
		if (fp == -1) {				/* If bad file pointer, give up */
			printmsg( 0, "Cannot open file %s (%s)", fromfile, hostfile );
			return('A');
		}
	} else
		return('A');	/* If something's already open, we're in trouble */

	printmsg( 1, "Sending %s (%s)\n\t%s", fromfile, hostfile, tofile );
	strcpy(spacket, tofile);
	if ((*sendpkt)(spacket, 0, 1))
		return(0);				/* S fromfile tofile user - tofile 0666 */
	if ((*getpkt)(spacket, &len))
		return(0);
	if (spacket[1] != 'Y')
		return('A'); 			/* If otherside says NO, quit */
	filetime = time( (long *) 0 );
	filesize = 0L;
#ifdef AMIGA
	if (!IntuitionBase)
		IntuitionBase = OpenLibrary("intuition.library", 0L);
	if (IntuitionBase)
		CurrentTime( &fileSecs, &fileMicro );
#endif /* AMIGA */

	file_flds[3] = mailbox;
	size = bufill(spacket);
	return('D');
}


/*
 *  sinit
 *		send init:  send this host's parameters and get other side's back.
 */
sinit()
{
	if ((*openpk)())
		return('A');
	return('B');
}


/*
 *	getfile
 *
 *	getfile reads the next line from the presently open workfile
 *	(cfile) and determines from this the next file to be sent
 *	(file). If there are no more, TRUE is returned.
 *
 *	--	A fix for "R from to 0666" should be done here to receive files
 *		in addition to sending them.  The appropriate "state letter",
 *		i.e. "R", should be returned to the "master" or "slave" state
 *		switching table in "dcp.c"
 *
 *		I did not implement this since the majority of uucp transactions
 *		appear to be "S from to 0666" type. RHLamb 1/87
 *
 *	[FJE]
 *		Except when attempting to download from an anonymous uucp site!!
 */
getfile()
{
	int	i;
	char	line[132];
	register char * cp;

	if ( fgets( line, BUFSIZ, fw ) == (char *)NULL )
		return(TRUE);

	sscanf(&line[2], "%s ", fromfile);
	for ( i = 0, cp = line; *cp!='\0'; i++, cp++ ) {
		if ( strncmp( cp, "0666", 4 ) == 0)
			break;
	}
	cp += 4;
	*cp = '\0';
	strcpy(tofile, line);
 	printmsg(3, "\tgetfile: fromfile=%s;\n\t\ttofile=%s.", fromfile, tofile);
	return(FALSE);
}


/*********************** MISC SUB SUB PROTOCOL *************************/
/*
 *	schkdir
 *		scan the dir
 */
schkdir()
{
	char c;

	c = scandir();
	if (c == 'Q') return('Y');			/* No files available */
	if (c == 'S') {
		strcpy(rpacket, "HN");
		if ((*sendpkt)(rpacket, 0, 1))
			return(0);
	}
	return('B');
}


/*
 *	endp
 *		end protocol
 */
endp()
{
	strcpy(rpacket, "HY");
	(*sendpkt)(rpacket, 0, 2);			/* don't wait for ACK */
	(*closepk)();
	return('P');
}


/*********************  RECEIVE PROTOCOL  ********************/
/*
 *  rdata
 *		receive data
 */
rdata()
{
	int	len;

	if ((*getpkt)(rpacket, &len))
		return(0);
	if (len == 0) {
		close(fp);
		strcpy(rpacket, "CY");
		if ((*sendpkt)(rpacket, 0, 1))
			return(0);
		logtime("<-");
		printmsg( 2, "Transfer complete\n" );
		return('F');
	}
	filesize += write(fp, rpacket, len);	/* Write the data to the file */
	return('D');							/* Remain in data state */
}


/*
 *  rfile
 *		receive file header
 */
rfile()
{
	int		numflds;
	int		len, i;
	char	tmpfilename[256];		/* Holds the converted file name */
	char	*cp, *index();

	printmsg( 3, "rfile entered" );
	cp = file_buf;
	while ( TRUE ) {
		if ((*getpkt)( rpacket, &len )) {
			printmsg( 5, "end connection" );
			return( 0 );
		}
		strncpy( cp, rpacket, len );
		cp += len;
		if ( *(cp - 1) == '\0' ) break;
	}
	if (( file_buf[0] & 0x7f ) == 'H' ) /* FJE: Hangup mean all done?! */
		return( 'C' );

	/* Convert upper case to lower [FJE: Why?  Does it matter?] */
	for (cp = file_buf; *cp != '\0';cp++)
		if (isupper(*cp)) *cp = tolower(*cp);

	/*
	 * Fields:
	 *  0        1            2        3  4        5        6
	 *
	 *	x D.ckctpab0008 D.boake20008 uucp - D.ckctpab0008 0666
	 *
	 *  |        |            |        |  |        |        |
	 *  |        |            |       who |        |        |
	 * What   src file    dest file  que'd|        |      file
	 *  to   (his name)   (my name)   it  |       ???     modes
	 *  do                               ???           (rw-rw-rw-)
	 */

	numflds = getargs( file_buf, file_flds );
	cp = file_flds[2];
	/*
	 *	Check for the funky stuff in the destination filename...
	 *
	 *	~				-> $PUBDIR
	 *	~uucp			-> $PUBDIR
	 *
	 *	~/pathname		-> $PUBDIR/pathname		"pathname" may be empty
	 *	~uucp/pathname	-> $PUBDIR/pathname
	 */
	if (strcmp( cp, "~" ) == SAME || strcmp( cp, "~uucp" ) == SAME ) {
		sprintf( tmpfilename, "%s/", pubdir );
	} else if (!strncmp( cp, "~/", 2 ) || !strncmp( cp, "~uucp/", 6 )) {
		sprintf( tmpfilename, "%s%s", pubdir, index(cp, '/'));
	} else {
		strcpy( tmpfilename, cp );
	}
	/* check for dirname only */
	cp = tmpfilename + strlen( tmpfilename ) - 1;
	if ( *cp == '\n' )
		*cp-- = '\0';

	if ( *cp == '/' ) {
		cp = rindex( file_flds[1], '/' );
		if ( cp == (char *) NULL )
			cp = file_flds[1];
		else
			cp++;
		strcat( tmpfilename, cp );
	} else
		cp = file_flds[1];

	/* let host munge filename as appropriate */
	importpath( tofile, tmpfilename );

	if ((fp = CREAT(tofile, 0775, 'b')) == -1) {	/* open a new file */
		printmsg( 0, "cannot create %s", tofile );	/* Give up if can't */
		return('A');
	}
	printmsg( 1, "Receiving %s as %s", file_flds[1], tofile );
	strcpy(rpacket, "SY");
	if ((*sendpkt)(rpacket, 0, 1))
		return(0);
	filetime = time( (long *) 0 );
	filesize = 0L;
#ifdef AMIGA
	if (!IntuitionBase)
		IntuitionBase = OpenLibrary("intuition.library", 0L);
	if (IntuitionBase)
		CurrentTime( &fileSecs, &fileMicro );
#endif /* AMIGA */
	return('D');								/* Switch to data state */
}


/*
 *  rinit
 *		receive init
 */
rinit()
{
	if ((*openpk)())
		return(0);
	return('F');
}
