/* pe7pta.c */
/* Include external declarations */
#include "pe7inc.h"

/*
 *	g i n i t
 *
 *	Get receive Initialization
 *
 */

TEXT ginit(l, file)
int l;				/* Length of the filename */
TEXT *file;			/* File name pointer */
{
	int len, num, slen;			/* Packet length, number */

	if (numtry++ > MAXTRY) return ('A'); /* If too many tries, "abort" */
	flushinput();			/* Clear out the i/o channel */

	spack('R',n,l,file);		/* Send the requested file name */
	switch(rpack(&len,&num,recpkt)) /* Get a packet */
	{
	case 'S':				/* Send-Init packet */
		if ( n != num)
		{
	case 'N':
	case FALSE:
			nxi++;
			return (state);
		}
		if (!rpar(recpkt,&len))	/* Get the other side's init data */
			return ('A');	/* error with the packet parameters */
		slen = spar(packet0);	/* Fill up packet with my init info */
		spack('Y',n,slen,packet0);/* ACK with my parameters */
		oldtry = numtry;	/* Save old try count */
		nxtpkt();
		return ('F');		/* Enter File-Receive state */

	case 'E':				/* Error packet received */
		prerrpkt(recpkt);	/* Print it out and */
	default:
		return ('A');		/* Some other packet type, "abort" */
	}
}

/*
 *	x i n i t
 *
 *	Server command scanning
 */
	
TEXT xinit()
{
	int i,					/* A counter */
		search,				/* Filename search state flag */
		len, num, slen;			/* Packet length, number */
	TEXT *filep;		/* Pointer to input buffer */

	switch(rpack(&len,&num,recpkt)) /* Get a packet */
	{
	case 'S':				/* Send-Init packet */
		if (!rpar(recpkt,&len))	/* Get the other side's init data */
			return ('A');		/* error with the packet parameters */
		slen = spar(packet0);		/* Fill up packet with my init info */
		spack('Y',n,slen,packet0); /* ACK with my parameters */
		oldtry = numtry;	/* Save old try count */
		nxtpkt();
		return ('F');		/* Enter File-Receive state */

	case 'I':				/* Send-Init packet */
		if (!rpar(recpkt,&len))	/* Get the other side's init data */
			return ('A');		/* error with the packet parameters */
		slen = spar(packet0);		/* Fill up packet with my init info */
		spack('Y',n,slen,packet0); /* ACK with my parameters */
		oldtry = numtry;	/* Save old try count */
		n = 0;
		numtry = 0;
		return (state);		/* Say we got our parameters */

	case 'E':				/* Error packet received */
		prerrpkt(recpkt);	/* Print it out and */
		return ('A');		/* abort */

	case FALSE:				/* Didn't get packet */
		nxi++;
		spack('N',n,0,0);	/* Return a NAK */
	case 'N':
		return (state);		/* Keep trying */

	case 'R':
		/* copy the packet data into a filename_buffer */
		/* cpystr(&filename_buffer, &recpkt, NULL); /* */
		btobemp(filename_buffer, recpkt, MAXPACKSIZ); /* Uncode packet */
		filecount = 0;
		filelist = &files;
		filep = &filename_buffer;
		search = 2;
		while (*filep != NULL && filecount < 10)
		{
			switch (search)
			{
			case 1:		/* Looking for next filename */
				if (iswhite(*filep))
					break;
				search = 2;
			case 2:		/* Looking for filename */
				if (iswhite(*filep))
					break;
				files[filecount++] = filep;
				search = 3;
			case 3:		/* Looking for end of filename */
				if (!iswhite(*filep))
					break;
				*filep = NULL;
				search = 1;
			}
			filep++;
		}
		if (debug) printf("Xinit 1: Request for %d files...\n", filecount);
		if (gnxtfl() == FALSE)	/* Any files to send? */
			return ('B');	/* if not, break, EOT, all done */
		return ('S');		/* Start sending files, switch state to S */
	case 'G':
		if (recpkt[0] == 'F')
		{
			spack('Y',n,0,0);	/* say ok */
			return ('G');
		}
		else
		{
			error("Invalid server command");
			return (state);	/* keep trying */
		}
	default:
		error("Unknown packet type");
		return (state);
	}
}

/*
 *	s f i l e
 *
 *	Send File Header.
 */

TEXT sfile()
{
	TEXT filnam1[MAXFNAME],		/* Converted file name */
	*newfilnam,				/* Pointer to file name to send */
	*cp;					/* char pointer */
	int num, len;			/* Packet number, length */
	ULONG time();

	if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */
	
	if (fd == NULL)			/* If not already open, */
	{
		if (debug) printf("Sfile 1: Opening %s for sending.\n",filnam);
		/* Open file to be sent */
		if ((fd = fopen(&pfio, filnam, READ)) == NULL)
							/* If bad file pointer, give up */
		{
			printmsg("Cannot open file %s\n",filnam);
			return ('A');
		}

		/* cpystr(filnam1, filnam, NULL);	/* Copy file name */
		btobemp(filnam1, filnam, MAXFNAME);	/* Copy file name */
		newfilnam = cp = filnam1;
		while (*cp != '\0')		/* Strip off all leading directory */
			if (*cp++ == '/')		/* names (ie. up to the last /). */
				newfilnam = cp;

		if (filnamcnv)			/* Convert lower case to upper */
			for (cp = newfilnam; *cp != '\0'; cp++)
				*cp = toupper(*cp);

		len = cp - newfilnam;		/* Compute length of new filename */

		if (vflg)
			printmsg("Sending %s as %s",filnam,newfilnam);
	}
	dostat(2);
	spack('F',n,len,newfilnam); /* Send an F packet */
	switch(rpack(&len,&num,recpkt)) /* What was the reply? */
	{
	case 'N':				/* NAK, just stay in this state, */
		num = (--num<0 ? 63 : num);/* unless it's NAK for next packet */
	case 'Y':
		if (n != num)		/* which is just like an ACK for */ 
		{					/* Wrong packet number */
	case FALSE:				/* Receive failure, stay in F state */
			nxi++;
			return (state);
		}
		nxtpkt();
		dostat(4);
		repeat_count = 0;	/* Reset repeat character counter */
		empty[1-pknum] = 0;	/* Make other buffer empty */
		if ((empty[pknum] = size[pknum] = bufill (packet[pknum])) != EOF)
			return ('E');	/* Switch to data state */
		return ('Z');		/* Must be end of file */

	case 'E':				/* Error packet received */
		prerrpkt(recpkt);	/* Print it out and */
	default:
		return ('A');		/* Something else, just "abort" */
	}
}

/*
 *	r f i l e
 *
 *	Receive File Header
 */

TEXT rfile()
{
	TEXT filnam1[MAXFNAME];		/* Holds the converted file name */
	int num, len, slen;			/* Packet number, length */
	int dum;				/* Holds array pointer */
	ULONG time();

	if (numtry++ > MAXTRY) return ('A'); /* "abort" if too many tries */
	dostat(2);
	switch(rpack(&len,&num,recpkt)) /* Get a packet */
	{
	case 'S':			/* Send-Init, maybe our ACK lost */
		if (oldtry++ > MAXTRY) return ('A'); /* If too many tries "abort" */
		if (num == ((n==0) ? 63 : n-1)) /* Previous packet, mod 64? */
		{
			/* Yes, ACK it again with	*/
			slen = spar(packet0);/* our Send-Init parameters */
			spack('Y',num,slen,packet0);
			numtry = 0; /* Reset try counter */
			return (state);	/* Stay in this state */
		}
		else return ('A');	/* Not previous packet, "abort" */

	case 'Z':			/* End-Of-File */
		if (oldtry++ > MAXTRY) return ('A');
		if (num == ((n==0) ? 63 : n-1)) /* Previous packet, mod 64? */
		{
			/* Yes, ACK it again. */
			spack('Y',num,0,0);
			numtry = 0;
			return (state);	/* Stay in this state */
		}
		else return ('A');	/* Not previous packet, "abort" */

	case 'F':			/* File Header (just what we want) */
		if (num != n) return ('A');/* The packet number must be right */
		/* cpystr(filnam1, recpkt, NULL);	/* Copy the file name */
		btobemp(filnam1, recpkt, MAXFNAME);	/* Copy the file name */

		if (filnamcnv)		/* Convert upper case to lower */
			for (filnam=filnam1; *filnam != '\0'; filnam++)
				*filnam = tolower(*filnam);

		/* Create the file for writing into */
		if ((fd = fcreate(&pfio, filnam1, WRITE)) == NULL)
		{
			error("Cannot create %s",filnam1); /* Give up if can't */
			return ('A');
		}
		if (vflg)
			printmsg("Receiving %s as %s",recpkt,filnam1);
		spack('Y',n,0,0);	/* Acknowledge the file header */
		oldtry = numtry;	/* Reset try counters */
		nxtpkt();
		dostat(4);
		return ('D');		/* Switch to Data state */

	case 'B':			/* Break transmission (EOT) */
		if (num != n) return ('A'); /* Need right packet number here */
		spack('Y',n,0,0);	/* Say OK */
		return ('C');		/* Go to complete state */

	case FALSE:			/* Didn't get packet */
		nxi++;
		spack('N',n,0,0);	/* Return a NAK */
		return (state);		/* Keep trying */

	case 'E':			/* Error packet received */
		prerrpkt(recpkt);	/* Print it out and */
	default:
		return ('A');		/* Some other packet, "abort" */
	}
}

/*
 * Checksum computations
 *
 * chk1 - Compute a type 1 Kermit 6 bit checksum
 * chk2 - Compute a type 2 Kermit block check
 * chk3 - Compute a type 3 Kermit block check
 *
 */
chk1(packet)
	char *packet;
{
	int checksum;
	checksum = chk2(packet);
	return ((((checksum & 0300) >> 6) + checksum) & 077);
}

chk2(packet)
	char *packet;
{
	ULONG checksum;

	for (checksum = 0; *packet != '\0' ; packet++)
		checksum += pflg ? *packet & 0177 : *packet;
	return (checksum);
}

chk3(packet)
	char *packet;
{
	int c, checksum, q;

	checksum = 0;
	while ((c = pflg ? *packet & 0177 : *packet) != '\0')
	{
		q = (checksum ^ c) & 017;		/* Low order nibble */
		checksum = (checksum >> 4) ^ (q * 010201);
		q = (checksum ^ (c >> 4)) & 017;	/* High order nibble */
		checksum = (checksum >> 4) ^ (q * 010201);
		packet++;
	}
	return (checksum);
}

/*
 *	s p a r
 *
 *	Fill the data array with my send-init parameters
 *
 */

spar(data)
TEXT data[];
{
	int len;
	data[0] = tochar(MAXPACKSIZ);/* Biggest packet I can receive */
	data[1] = tochar(MYTIME);	/* When I want to be timed out */
	data[2] = tochar(MYPAD);	/* How much padding I need */
	data[3] = ctl(MYPCHAR);		/* Padding character I want */
	data[4] = tochar(MYEOL);	/* End-Of-Line character I want */
	data[5] = MYQUOTE;			/* Control-Quote character I send */
	if (state == 'S')
	{
		/* Set up the startup parameters */
		/* The other side may call the shots if we are a server */
		data[6] = sqbin = image ? pflg ? MYQBIN : DEFQBIN : 'N';
		data[7] = DEFCHKT;		/* I will use this check sum */
		data[8] = DEFREPT;		/* This is my repeat character */
		data[9] = tochar(NULL); /* No bit mask at this time */
		data[10] = tochar(NULL);
		data[11] = tochar(NULL);
		data[12] = tochar(NULL);
		data[13] = tochar(NULL);
		/* Tell the other side what we set up in the start */
		data[14] = image ? tochar( 1 ) : tochar ( NULL );
		data[15] = pflg ? pflg : tochar(NULL);
		len = 16;
	}
	else		/* Receive flag must be on. We are not the starters */
	{
		data[6] = rqbin;		/* Quote character both sides will use */
		data[7] = chkt;			/* Checksum type */
		data[8] = rrept;		/* Set My repeat character */
		data[9] = tochar(NULL); /* No bit mask at this time */
		len = 10;
	}
	if (debug > 1)
	{
		printf("Spar: spsiz=%d, timint=%d\n", spsiz, timint);
		printf("      pad=%d, padchar=%d, eol=%d, ", pad, padchar, eol);
		printf("quote=%d, qbin=%d, chkt=%d, ", quote, qbin, chkt);
		printf("rept=%d\n", rept);
		if (len > 10)
			printf("      image= %d, pflg= %c, iflg= %d, spflg= %c\n",
				image,pflg,iflg,spflg);
	}
	return ( len );
}

/*	r p a r
 *
 *	Get the other host's send-init parameters
 *
 */

rpar(data,len)
TEXT data[];
int *len;
{
	TEXT chkchar();

/* Maximum send packet size */
	spsiz = *len < 1 ? DEFPACKSIZ : unchar(data[0]);

/* When I should time out */
	timint = *len < 2 ? MYTIME : unchar(data[1]);

/* Number of pads to send */
	pad = *len < 3 ? 0 : unchar(data[2]);

/* Padding character to send */
	padchar = dopar(*len < 4 ? NULL : ctl(data[3]));

/* EOL character I must send */
	eol = *len < 5 ? CR : unchar(data[4]);

/* Incoming data quote character */
	quote = *len < 6 ? '#' : data[5];

/* Force to a type one check sum */
	chkt = *len < 8 ? DEFCHKT : data[7] != MYCHKT ? DEFCHKT : MYCHKT;

/* Set up the multi repeat char */
	rrept = *len < 9 ? ' ' : data[8];

	if (state != 'S')
	{
/* Determine the state of image and parity flags from the other side */
		image = *len < 15 ? iflg : data[14] == SP ? FALSE : TRUE;
		pflg = *len < 16 ? spflg : data[15] == SP ? FALSE : data[15];

/* Determine the state of the sqbin */
		sqbin = image ? pflg ? MYQBIN : DEFQBIN : 'N';

/* Determine the quoting mode we will use based on what the other side
 * allows and what we are capable of */
		rqbin = *len < 7 ? 'N' : data[6] == DEFQBIN ? sqbin : data[6];
		qbin  = chkchar(rqbin);

/* Determine the repeat mode based on what the other side allows */
		rept = chkchar(rrept);

	}
	else
	{
/* Determine the final quoting mode based on what the other side allows */
		rqbin = *len < 7 ? 'N' : data[6];
		qbin = sqbin == DEFQBIN ?
			chkchar(rqbin) : rqbin == MYQBIN ? MYQBIN : FALSE;

/* Determine the final repeat mode based on what the other side allows */
		rept = rrept == DEFREPT ? rrept : FALSE;
	}

/* Force 8 bit quoting if requested and we are not generating parity */
	if (qbin && !pflg)
		pflg = 'n';
	/* Maybe we can not do image because the other end can
		not support binary quote */
	if (image && rqbin == 'N')
	{
		error("Binary file transfer not supported");
		return (FALSE);
	}

	if (debug > 1)
	{
		printf("Rpar: spsiz=%d, timint=%d\n", spsiz, timint);
		printf("      pad=%d, padchar=%d, eol=%d, ", pad, padchar, eol);
		printf("quote=%d, qbin=%d, chkt=%d, ", quote, qbin, chkt);
		printf("rept=%d\n", rept);
		if (*len > 14 )
			printf("      image=%d, pflg=%c\n",image,pflg);
	}
	return (TRUE);
}
 
/*
 *	b u f i l l
 *
 *	Get a bufferful of data from the file that's being sent.
 *
 */

bufill(buffer)
TEXT buffer[];			/* Buffer */
{
	int i;				/* Loop index */
	METACH t;			/* Character that may be output */
	static METACH tt {0}; /* For the comparisions of the repeat count */

	i = 0;			/* Init data buffer pointer */

	while ((t = getc(&pfio)) != EOF)	/* fetch till end */
	{
		file.fc++;
		if (rept)		/* If rept set then true */
		{
			if (repeat_count)		/* If r..c.. set then true */
			{
				/* Check for repeat character and not too many of them */
				if ((tt == t) && (++repeat_count < 95))
					continue;
				/* The characters were different or we ran out of
						repeat count */
				if (repeat_count > 3) /* Output repeat string */
				{
					buffer[i++] = rept;
					if (repeat_count >= 95) repeat_count = 94;
					buffer[i++] = tochar(repeat_count);
					repeat_count = 1;		/* Set for next */
				}
				for (; repeat_count ; repeat_count -= 1)
					store_in_buffer(tt, buffer, &i);
			/* We have output the repeat count and the repeat character */
			}
			/* End of repeat_count test */
			tt = t;		/* Set up temps for next character */
			repeat_count = 1;
		}
		/* End of non NULL rept */
		else		/* rept = 0 */
			store_in_buffer(t, buffer, &i);

		if (i >= spsiz-SPOVER) return (i);		/* Check length */
	}
	/* End of while loop */
	/* Test if there is an repeat count outstanding.
		It could be that we have not inserted any data into
		output buffer */
	if (repeat_count > 3)
	{
		buffer[i++] = rept;
		buffer[i++] = tochar(repeat_count);
		repeat_count = 1;		/* Set for next */
	}
	for (; repeat_count ; --repeat_count)
		store_in_buffer(tt, buffer, &i);

	if (i==0) return (EOF);		/* Wind up here only on EOF */
		/* We need to split the packet. Scan backwards for a natural
			* break, and then send of the packet. When we return point
			* to the data and move to the front the rest and fetch more
			* more data. */
		/* Natural breaks are the quote character, repeat character
			* and the binary character */
	return (i);			/* Handle partial buffer */
}

/*
 *	b u f e m p
 *
 *	Put data from an incoming packet into a file.
 *
 */

bufemp(buffer,len)
register TEXT	buffer[];				/* Buffer */
int len;				/* Length */
{
	register int i;		/* Counter for number of characters */
		int ri;			/* Repeat counter for repeated characters */
	TEXT t, t7, tm;	/* Character holders */

	for (i = 0; i < len; i++)		/* Loop thru the data field */
	{
		tm = 0;				/* Preset for next */
		t = buffer[i];			/* Get character */
		ri = 1;			/* Set repeat count to one (do at least one) */
		/* At this point we check for a repeat character
			* if the rept char is set then the condition will be tested
			* else we can not get here since the character t may
			* not be a NULL */
		if (t == rept)		/* Repeated character? */
		{
			ri = unchar(buffer[++i]);	/* Fetch repeat count */
			t = buffer[++i];	/* Fetch next character */
		}
		if (t == qbin)	/* Next character have high bit on? */
		{
			tm = 0200;		/* Set mask to high bit on */
			t = buffer[++i];/* Fetch next character */
		}
		if (t == quote)		/* Control quote? */
		{
			/* Yes */
			t = buffer[++i];	/* Get the quoted character */
			t7 = t & 0177;	/* make a match character */
			if (t7 != quote && t7 != rept && t7 != qbin) /* Low bits
								match quote, rept or qbin? */
			t = ctl(t);		/* No, uncontrollify it */
		}
		if (t==CR && !image)		/* Pass CR if in image mode */
			continue;

		t |= tm;
		for (; ri ; --ri) /* We put at least one character away */
		{
			putc(&pfio, t);
			file.fc++;
		}
	}
}

/*
 *	b t o b e m p
 *
 *	Put data from an incoming packet into a buffer.
 *
 */

btobemp(bout,buffer,len)
register TEXT	buffer[];				/* Buffer */
register TEXT	bout[];				/* Output Buffer */
int len;				/* Length */
{
	register int i;		/* Counter for number of characters */
	register int j;     /* Output buffer counter */
		int ri;			/* Repeat counter for repeated characters */
	TEXT t, t7, tm;	/* Character holders */

	j = 0;							/* Initialize output buffer pointer */
	if(debug) printf("[btobemp] buffer=>>>%s<<<\n",buffer);
	/* for (i = 0; i < len; i++)		/* Loop thru the data field */
	for (i = 0;  buffer[i] != '\0'; i++)		/* Loop thru the data field */
	{
		tm = 0;				/* Preset for next */
		t = buffer[i];			/* Get character */
		ri = 1;			/* Set repeat count to one (do at least one) */
		/* At this point we check for a repeat character
			* if the rept char is set then the condition will be tested
			* else we can not get here since the character t may
			* not be a NULL */
		if (t == rept)		/* Repeated character? */
		{
			ri = unchar(buffer[++i]);	/* Fetch repeat count */
			t = buffer[++i];	/* Fetch next character */
		}
		if (t == qbin)	/* Next character have high bit on? */
		{
			tm = 0200;		/* Set mask to high bit on */
			t = buffer[++i];/* Fetch next character */
		}
		if (t == quote)		/* Control quote? */
		{
			/* Yes */
			t = buffer[++i];	/* Get the quoted character */
			t7 = t & 0177;	/* make a match character */
			if (t7 != quote && t7 != rept && t7 != qbin) /* Low bits
								match quote, rept or qbin? */
			t = ctl(t);		/* No, uncontrollify it */
		}
		if (t==CR && !image)		/* Pass CR if in image mode */
			continue;

		t |= tm;
		for (; ri ; --ri) /* We put at least one character away */
		{
			if( j >= (len) ) {
			printf("Kermit: [btobemp] Expanded packet overflows buffer\
\n         j=%d     MAXFNAME=%d\n",j,(MAXFNAME));
			error("Kermit: [btobemp] Expanded packet overflows buffer\n");
			break;
			}
			bout[j] = t;
			j++;
		}
	}
	if( j < len )
		bout[j] = '\0';
}

/*
 * s t o r e _ i n _ b u f f e r
 *
 * This routine stores the character into the output buffer
 *
 */

store_in_buffer(t, buffer, i)
TEXT t;
register TEXT buffer[];
register int *i;
{
	TEXT t7,tm;

	t7 = t & 0177;				/* Strip high bit */

	if (t7 == '\n' && !image)
	{
		/* Do LF->CRLF mapping if !image */
		buffer[(*i)++] = MYQUOTE;
		buffer[(*i)++] = ctl('\r');
	}
	if (qbin != 0 && (pflg ? t & 0200 : 0) != 0) /* Binary quote on? */
		buffer[(*i)++] = MYQBIN;		/* Output a flag char */

	/* Does this character need special handling? */
	if (t7 < SP || t7 == DEL)
	{
		/* Yes this character need some changes */
		buffer[(*i)++] = MYQUOTE;	/* Quote the character */
		t7 = ctl(t7);		/* and uncontrolify */
		t = ctl(t);
	}
	else	/* it is not a special character */
	{
		if (t7 == MYQUOTE || t7 == rept || t7 == qbin)
			buffer[(*i)++] = MYQUOTE;	/* Quote the character */
	}

	buffer[(*i)++] = pflg ? t7 : t;
}
/* pe7pta.c End-of-file */
