File:  [MW Coherent from dump] / coherent / a / usr / bob / uusrc / dcp / dcpxfer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:34 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * dcpxfer.c 
 *
 * Revised edition of dcp 
 *
 * Stuart Lynne May/87 
 *
 * Copyright (c) Richard H. Lamb 1985, 1986, 1987 Changes Copyright (c) Stuart
 * Lynne 1987 
 *
 * "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987
 * file send routines
 */

#include "dcp.h"
#include <signal.h>
#include <ctype.h>
#include <sys/timeb.h>
#include <sys/stat.h>
#include <access.h>
#include "perm.h" 

extern int (*getpkt)(), (*sendpkt)(), (*openpk)(), (*closepk)();

extern	int errno;
extern	char *sys_errlist[];
extern	char	*strtok();
extern	char	*rebuildfn();
static	char	tempname[] =	"/usr/spool/uucp/TM.XXXXXX";
static	unsigned char rpacket[MAXPACK];
static	unsigned char spacket[MAXPACK];
char	reason [80];
static	char	S_record [BUFSIZ];
static	int	lstat;
extern	int	canwrite();
#define	BIGBUFSZ (BUFSIZ * 20)
static	char	bigreadbuf [BIGBUFSZ];

struct timeb	transferstart;	/* transfer start time */
struct timeb	transferstop;	/* transfer stop time */

/*
 * s d a t a 
 *
 * Send File Data 
 */
sdata()
{
	for (;;) {
		if ((size = read(fpfd, spacket, pktsize)) <= 0) /* Get data */
			return 'Z';		/* If EOF set state to that */
		bytecount += size;
		if ((*sendpkt) (spacket, size, 0))
			return cantsend();		/* send data */
	}
}

/*
 * s b r e a k 
 *
 */
sbreak()
{
	if (sendmsg("H") < 0) 
		return cantsend();
	if (getmsg(spacket) < 0) {
		plog(M_CONVERSE, "Cannot get reply to H (sbreak)");
		terminatelevel++;
		return 'Y';	/* was return 0 */
	}
	printmsg(M_CONVERSE, "Switch modes: %s", spacket);
	if (spacket[1] == 'N') 
		return 'G';
	return 'Y';
}

/*
 * s e o f 
 *
 * Send End-Of-File. 
 */
seof()
{
	double	elapsed;

	close(fpfd);
	fpfd = -1;
	printmsg(M_TRANSFER, "seof");
	if ((*sendpkt) (spacket, 0, 0) < 0)
		return cantsend();	/* length zero packet indicates EOF */
	if (getmsg(spacket) < 0)
		return cantread();	/* was plog; termlev++, no ret*/
	printmsg(M_TRANSFER, "seof: spacket is %s.", spacket);
	if (strncmp(spacket, "CY", 2) != 0) {
		sprintf(reason, "Remote would not accept file %s", fromfilep);
		plog(M_TRANSFER, reason);
		notifystatus(fromfilep, tofilep, 1, 0, lstat);
		return 'F';
	}
	if (lstat && (index(optionp, 'c') == NULL)) {
		unlink(xfromfile);
		/* plog("unlinking %s", xfromfile);	 */
		printmsg(M_TRANSFER, "unlinking %s.", xfromfile);
	}
	printmsg(M_TRANSFER, "seof: Transfer of %s completed.",
		fromfilep);
	ftime(&transferstop);
	printmsg(M_TRANSFER, "Stop time is  %ld.%03d\n",
		transferstop.time, transferstop.millitm);
		elapsed =
			(double)transferstop.time - (double)transferstart.time;
		elapsed += 
			((double)transferstop.millitm -
			(double)transferstart.millitm) / 1000.0;
	if (total_errors > 0) 
		plog(M_TRANSFER,
		     "S (OK) %ld bytes, %5.2f seconds, %5.1f Bps, %d error%c", 
			bytecount, elapsed, (double) bytecount / elapsed,
			total_errors, total_errors == 1 ? ' ' : 's'); 
	else
		plog(M_TRANSFER, "S (OK) %ld bytes, %5.2f seconds, %5.1f Bps", 
			bytecount, elapsed, (double) bytecount / elapsed); 
	notifystatus(fromfilep, tofilep, 1, 1, lstat);
	return 'F';		/* go get the next file to send */
}

/*
 * s f i l e 
 *
 * Send File Header. 
 * This needs to respond to:
 *	1) commands from a C. file
 *	2) requests from remote.
 */
sfile()
{
	printmsg(M_SPOOL, "Sending %s as %s,\n\tspool %s",
		fromfilep, tofilep, xfromfile);
	plog(M_SPOOL, "S (%s)->(%s)", fromfilep, tofilep);
	bytecount = 0;
	total_errors = 0;
	ftime(&transferstart);
	printmsg(M_TRANSFER, "Start time is %ld.%03d\n",
		transferstart.time, transferstart.millitm);
	return 'D';
}

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

/*
 * cdotcmd
 * read commands from C. file, and dispatch accordingly.
 * This routine and the corresponding routine rmtcmd need to set up
 * the following global variables.
 *	fromfilep	pointer to file name that is source.
 *	tofilep		pointer to file name that is destination.
 *	xfromfile	file name that is actual source,  eg, spool file.
 *	optionp		pointer to option string.
 *	modep		pointer to octal mode string.
 *	notifyp		pointer to user to be notified
 * These control the action of sendf, sfile and seof.
 *
 */
cdotcmd()
{
	char	*cp;

	lstat	= 1;
	printmsg(M_SPOOL, "cdotcmd enter");
	if (fpfd != -1) {		/* If not already open, */
		plog(M_SPOOL, "File already open");
		terminatelevel++;
		return 'A';	/* If something's already open, we' trouble */
	}
	printmsg(M_SPOOL, "looking for next file...");
	if (getcline()) {	/* get next file from current work */
		fclose(cfp);
		printmsg(M_SPOOL, "unlinking %s", cfile);
		unlink(cfile); /* close and delete completed workfile */
		cfp = NULL;
		return 'B';	/* end controlling session */
	}
	if (*clinep [1] == 'R') {	/* ask for file */
		int	permerr = 0;
		printmsg(M_SPOOL, "getcline gave us an 'R' rec");
		if ((cp = rebuildfn(tofilep)) == NULL) {
			sprintf(reason, "No such user as referenced in \"%s\"",
				tofilep);
			permerr = 1;
		} else
			strcpy(xtofile, cp);
		if (!permerr && !perm_write(xtofile)) {
			sprintf(reason, "No permission to write file \"%s\"",
				xtofile);
			permerr = 1;
		}
		if (!permerr && !canwrite(xtofile)) {
			sprintf(reason, "Unable to create \"%s\"; %s",
				xtofile, sys_errlist[errno]);
			permerr = 1;
		}
		if (permerr) {
			plog(M_SPOOL, reason);
			notifystatus(fromfilep, xtofile, 0, 0, lstat);
			return 'F';	/* Give up if can't */
		}			
		if (sendmsg(S_record) < 0)	/* really S&R_record */
			return cantsend();
		if (getmsg(spacket) < 0)
			return cantread();
		printmsg(M_SPOOL, "spacket is %s", spacket);
		if ((spacket [0] != 'R') || (spacket [1] != 'Y')) {
			sprintf(reason, "Remote won't send file \"%s\".",
				fromfilep);
			plog(M_SPOOL, reason);
			notifystatus(fromfilep, xtofile, 0, 0, lstat);
			return 'F';	/* was return 'A' */
		}
		return rfile();
	}
	if (strcmp(clinep [1], "S") == 0) {
		int	noperm;
		noperm = 0;
		printmsg(M_SPOOL, "Opening \"%s\" for sending.", xfromfile);
		if ((strcmp(perm_value(sendfiles_e), "call") == 0) ||
			!perm_read(xfromfile)) {
			if (role != MASTER) {
				sprintf(reason, 
				"No permission to send as remote \"%s\"",
					xfromfile);
				noperm = 1;
			}
		} else if ((strcmp(perm_value(sendfiles_e), "yes") != 0) ||
			!perm_read(xfromfile)) {
			sprintf(reason,"No permission to send file\"%s\"",
				xfromfile);
			noperm = 1;
		}
		if (noperm) {
			plog(M_TRANSFER, reason);
			notifystatus(xfromfile, xtofile, 0, 0, lstat);
			return 'F';
		}
		fpfd = open(xfromfile, 0);	/* open the file to be sent */
		if (fpfd == -1) { 
			sprintf(reason, "Unable to read \"%s\"; %s",
				xfromfile, sys_errlist[errno]);
			plog(M_TRANSFER, reason);
			notifystatus(xfromfile, xtofile, 0, 0, lstat);
			return 'F';
		}
		/* send 'S fromfile tofile user - tofile <perms>'. */
		if (sendmsg(S_record) < 0)
			return cantsend();	/* was return 0 */
		if (getmsg(spacket) < 0)
			return cantread();	/* was return 0 */
		printmsg(M_SPOOL, "spacket is %s", spacket);
		if (spacket[1] != 'Y') {
			sprintf(reason, "Remote won't accept file \"%s\"",
				xfromfile);
			plog(M_TRANSFER, reason);
			notifystatus(xfromfile, xtofile, 1, 0, lstat);
			close(fpfd);
			fpfd = -1;
			return 'F';
		}
		return sfile();
	}
	plog(M_SPOOL, "unknown record in \"%s\" of \"%s\"", cfile, clinep[1]);
	return 'Y';
}

/*
 *	getcline()
 *	get one line from the C. file and split it apart.
 */
getcline()
{
	char	*p;
	static char line[BUFSIZ];
	if (fgets(line, BUFSIZ, cfp) == (char *) NULL)
		return 1;
	if ((p = index(line, '\n')) != NULL)
		*p = '\0';
	strcpy(cline, line);
	return sepcline();

}

sepcline()
{
	char	*sp;
	int	i;

	printmsg(M_SPOOL, "sepcline: line is %s", cline);
	strcpy(S_record, cline);
	sp = cline;
	for (i=0; i<10; i++)
		clinep[i] = NULL;
	for (i=1; i<10; i++) {
		if ( (clinep[i]=strtok(sp, " \t\n")) == NULL )
			break;
		printmsg(M_SPOOL, "cline[%d]:\t%\"%s\"", i, clinep[i]);
		sp = NULL;
	}


	/* If the last field of a parsed command line is NOT null, then
	 * there is something wrong with the line parsed. Leave a  message
	 * to this affect in the logs, and print the offending line there
	 * as well. Abort processing this file.

	 * It has not yet been determined what affects this will have.
	 * It may keep other requests from the site which is expecting to 
	 * receive files from receving all of the files it expects.

	 * the following is a short description of how this was called:

		sendf() -> calls cdotcmd() until 'complete'	(dcp.c)
		cdotcmd() -> calls getcline() until a non-zero
			     value is returned. When a non zero
			     value is returned, the C. file being
			     read is closed and deleted. A 'B' is
			     then returned back to sendf()
		getcline() -> calls sepcline (breaks out the C. fields)

	 * Bob Hemedinger 01/27/92
	 */

	/* 01/30/92: removed the return statement. We WANT to continue
	 * if we don't see the NULL terminator for compatibility with
	 * other variants.
	 */

	if (clinep[9] != NULL) {
		plog(M_SPOOL, "Error parsing command 'C.' file");
		plog(M_SPOOL, "last sepcline field not null");
		plog(M_SPOOL, "Actually parsed: ");
		plog(M_SPOOL, " %s %s %s %s %s %s %s %s %s",
				clinep[1], clinep[2], clinep[3],
				clinep[4], clinep[5], clinep[6],
				clinep[7], clinep[8], clinep[9]);
	}
	nclinep = i;
	fromfilep = clinep[2];
	tofilep = clinep[3];
	usernamep = clinep[4];
	optionp = clinep[5];
	spoolfilep = clinep[6];
	modep = clinep[7];
	notifyp = clinep[8];
	if (strcmp(clinep[1], "S") == 0) {
		sprintf(xfromfile, "%s/%s/%s", SPOOLDIR, rmtname, spoolfilep);
		if (index(optionp, 'c') != NULL)	/* this looks weak */
			strcpy(xfromfile, fromfilep);
	} else if (strcmp(clinep[1], "R") == 0) {
		strcpy(xfromfile, fromfilep);
	} else if (*clinep[1] == 'H') {
		;
	} else {
		plog(M_SPOOL, "Unrecog record type %s", cline);
		printmsg(M_SPOOL, "Unrecog type %s %s %s", cline[1],
			cline[2], cline[3]);
		return 1;
	}
	return 0;
}

/*********************** MISC SUB SUB PROTOCOL *************************/

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

	c = scandir();

	if (c == 'Q') {
		return ('Y');
	}
	if (c == 'S') {
		sprintf(rpacket, "HN");
		if ((*sendpkt) (rpacket, 0, 1))
			return cantsend();
	}
	return ('B');
}

/* 
 * endp() end protocol 
 *
 */
endp()
{

	(void) sendmsg("HY");
	(*closepk) ();
	return 'P';
}



/***********************RECEIVE PROTOCOL**********************/

/*
 * r d a t a 
 *
 * Receive Data 
 */
rdata()
{
	int	len;

	if ((*getpkt) (rpacket, &len))
		return cantread();
	if (len == 0) 
		return reof();
	if (write(fpfd, rpacket, len) != len)	/* Write the data to the file */
		return 'Y';
	bytecount += len;
	return 'J';			/* Remain in data state */
				/* changed to J */
}

/*
 *	reof
 *	handle eof on read.
 *	try to link the temp file to the new name;
 *	if not successful, then copy it.
 */
reof()
{
	int	tfpfd;
	int	noperm;
	double	elapsed;
	int	mode;
	int	bytes;

	noperm = 0;
	tfpfd = -1;
	close(fpfd);
	fpfd = -1;
	unlink(xtofile);
	if (link(tempname, xtofile) == -1) {
		if ((tfpfd = open(tempname, 0)) == -1) {
			sprintf(reason, "Unable to reread \"%s\"; %s",
				tempname, sys_errlist[errno]);
			noperm = 1;
		} else if ((fpfd = creat(xtofile, 0644)) == -1) {
			sprintf(reason, "Unable to create \"%s\"; %s (rdata)",
				xtofile, sys_errlist[errno]);
			noperm = 1;
		} 
		if (noperm) {
			plog(M_TRANSFER, reason);
			notifystatus(fromfilep, tempname, 0, 0, lstat);
			if (sendmsg("CN") < 0) {
				plog(M_SPOOL, "Message CN refused");
				return cantsend();
			}
			if (tfpfd != -1)
				close(tfpfd);
			if (fpfd != -1)
				close(fpfd);
			return 'F';
		}
		while ((bytes = read(tfpfd, bigreadbuf, BIGBUFSZ)) > 0)
			write(fpfd, bigreadbuf, bytes);
		close(tfpfd);
		close(fpfd);
		fpfd = -1;
	}
	unlink(tempname);
	if ((strlen(modep) > 0) && (mode = getoct(modep)) != 0 &&
		(chmod(xtofile, getoct(modep)) == -1)) {
		printmsg(M_TRANSFER, "Unable to change permission");
		plog(M_TRANSFER, 
			"Unable to change permission to \"%s\" on file \"%s\"",
			modep, xtofile);
	}
	/* now, do the copy. rewind the above file and reread it */
	/* we ought to do the copy in a temp file, and move it here */
	printmsg(M_TRANSFER, "transfer complete");
	ftime(&transferstop);
	printmsg(M_TRANSFER, "Stop time is  %ld.%03d\n",
		transferstop.time, transferstop.millitm);
	elapsed =
		(double)transferstop.time -
			(double)transferstart.time;
	elapsed += 
		((double)transferstop.millitm -
		(double)transferstart.millitm) / 1000.0;
	if (total_errors > 0)
		plog(M_TRANSFER, 
		     "R (OK) %ld bytes, %5.2f seconds, %5.1f Bps, %d error%c", 
			bytecount, (double)elapsed, bytecount / elapsed,
			total_errors, total_errors == 1 ? ' ' : 's'); 
	else
		plog(M_TRANSFER, "R (OK) %ld bytes, %5.2f seconds, %5.1f Bps", 
			bytecount, (double)elapsed, bytecount / elapsed); 
	notifystatus(fromfilep, xtofile, 0, 1, lstat);
	printmsg(M_TRANSFER, "returning from rdata");
	if (sendmsg("CY") < 0) {
		strcpy(reason, "Message CY refused.");
		plog(M_TRANSFER, reason);
		return cantsend();
	} 
	return 'F';
}

/*
 *	Analog of cdotcmd.  This takes 'S' records or 'R' records
 *	from the other end and dispatches them properly.
 */
rmtcmd()
{
	static	char	buf[256];
	char	*cp;
	int	noperm;

	lstat = 0;
	if (getmsg(buf) < 0) {
		printmsg(M_LOWPROTO, "in rmtcmd, getmsg says -1");
		return cantread();	/* was return 0 */
	}
	printmsg(M_TRANSFER, "buf[0] is %c", buf[0]);
	strcpy(cline, buf);
	sepcline();
	if (*clinep [1] == 'H') {	/* used to be buf [0] */
		printmsg(M_TRANSFER, "rmtcmd got H, returning C");
		return 'C';
	}
	printmsg(M_TRANSFER, "rmtcmd: buf %d \"%s\"", strlen(S_record),
		S_record);
	if (strcmp (clinep [1], "R") == 0) {
		printmsg(M_INFO, "rmdcmd: send file R");
		printmsg(M_SPOOL, "Opening %s for sending.", xfromfile);
		if ((strcmp(perm_value(request_e), "yes") != 0) ||
			!perm_read(xfromfile)) {
			sprintf(reason, "Request permission denied: \"%s\"",
				xfromfile);
			plog(M_TRANSFER, reason);
			sendmsg("RN");
			notifystatus(fromfilep, xtofile, 0, 0, lstat);
			return 'F';
		} else {
			fpfd = open(xfromfile, 0);
				/* open the file to be sent */
			if (fpfd == -1) { /* If bad file pointer, give up */
				sprintf(reason,
					"Cannot open file \"%s\".", xfromfile);
				plog(M_TRANSFER, reason);
				sendmsg("RN");
				notifystatus(fromfilep, xtofile, 0, 0, lstat);
				return  'F';	/* was return 'A' */
			}
			sendmsg("RY");
			return sfile();
		}
	}
	printmsg(M_INFO, "rmtcmd: receive file \"%s\"", tofilep);
	if ((cp = index(optionp, 'c')) != NULL) 	/* oops, not allowd*/
 		*cp = ' ';
	noperm = 0;
	if ((cp = rebuildfn(tofilep)) == NULL) {
		noperm = 1;
		sprintf(reason, "No such user as referenced in \"%s\"",
			tofilep);
	} else
		strcpy(xtofile, rebuildfn(tofilep));
	if (!noperm && !perm_write(xtofile)) {
		sprintf(reason, "No permission to write file \"%s\"", xtofile);
		noperm = 1;
	}
	if (!noperm && !canwrite(xtofile)) {
		sprintf(reason, "rmtcmd: Unable to create file \"%s\": %s",
	 		xtofile, sys_errlist[errno]);
		noperm = 1;
	}
	if (noperm) {
		plog(M_TRANSFER, reason);
		notifystatus(fromfilep, xtofile, 0, 0, lstat);
		if (sendmsg("SN") < 0) 
			return cantsend();
		return 'F';
	}
	if (sendmsg("SY") < 0) {
		plog(M_TRANSFER, "Can't send SY");
		return 'Y';
	}
	return rfile();
}

/*
 * r f i l e 
 *
 * Receive File Header 
 */
rfile()
{
	printmsg(M_TRANSFER, "Receiving %s as %s", fromfilep, xtofile);
	/* create temp file name, open it for output */
	if ((fpfd = creat(mktemp(tempname), 0644)) == -1) {
		sprintf(reason, "Unable to create \"%s\"; %s",
			tempname, sys_errlist[errno]);
		plog(M_TRANSFER, reason);
		notifystatus(fromfilep, xtofile, 0, 0, lstat);
		return 'F';	/* Give up if can't */
	}
	plog(M_TRANSFER, "R (%s)<-(%s)", xtofile, fromfilep);
	bytecount = 0;
	total_errors = 0;
	ftime(&transferstart);
	printmsg(M_TRANSFER, "Start time is %ld.%03d\n",
		transferstart.time, transferstart.millitm);
	return 'J';		/* Switch to data state */
}

/*
 * r i n i t 
 *
 * Receive Initialization 
 */
rinit()
{
	if ((*openpk) ()) {
		plog(M_TRANSFER, "Unable to get opening packet");
		return 'Y';
	}
	return ('F');
}

/*
 * |getmsg()| recieves a null-terminated "conversation-level" message
 * from the communications channel. This may require one or more packets,
 * but all of them will be "long-data" packets containing a full 64 bytes.
 */
int getmsg(dest)
char *dest;
{
	int len;

	while(1) {
		if ((*getpkt)(dest, &len) < 0)
			return(-1);
		*(dest + len) = '\0';		/* make sure it's terminated */
		if (strlen(dest) != len)
			break;			/* we reached the terminator */
		dest += len;
	}
	return( 0 );
}

/*
 * |sendmsg(message)| sends a null-terminated "conversation-level" message.
 */
int sendmsg(message)
char *message;
{
	int len;
	len = strlen(message) + 1;	/* total length including '\0' */

	while(1) {
		if ((*sendpkt)(message, 0, 1) < 0) /* send with padding */
			return -1;
		if ((len -= pktsize) <= 0)
			break;
		message += pktsize;
	}
	return 0;
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.