
/***********************************************************************/

/*  File KREC.C  -  Receive-procedures for RML Kermit;
		Chris Kennington,	RML.	9th July 1985.	*/

#define	 DEFS1	1
#define	 DEFS2	1
#define	 DEFS4	1

#include  "stdio.h"
#include  "b:kext.h"

static char *ptr2;	/* Pointer to converted file name	*/
static int  len;



char cpmunge(len,new,old)
/*  Convert supplied name to a (similar) one which is legal
 *	for CP/M; all alphabetics to upper case, all punctuation
 *	deleted except for a single dot (the first if more than
 *	one in input), colon taken as restarting the munge, all
 *	controls deleted, length limited to 8.3, if input is
 *	> 8 without a dot, dot inserted and next 3 chars used
 *	as suffix.  Munge terminated by 0 as a C-string. 
 *  Returns length of munged name (not including terminating 0). */
char  *old, *new;
int   len;
{
    char  c, i, j, p2, dotty;

    j = p2 = dotty = 0;
    for (i=0; i<len; ++i) {		/* step thro' old	*/
  /* unwanted chars, continue the loop; wanted chars, store at end. */	
	if (p2 > 3)
	    goto Exit;			/* suffix full		*/
	c = old[i] & 0x7f;
	if (c > '@') {			/* ordinaries		*/
	    c &= 0x5f;			/* upper case		*/
	    if (c > 0x5a)
		continue;		/* illegal chars	*/
	}
	else if (c > SP) switch(c) { /* punctuation & numerals	*/
	      case'0':		/* accept all numerals		*/
	      case'1':
	      case'2':
	      case'3':
	      case'4':
	      case'5':
	      case'6':
	      case'7':
	      case'8':
	      case'9':
	      case'$':
		break;

	      case ':':		    /* previous was disk-letter	*/
		j = 0;			/* start afresh		*/
		dotty = 0;
		continue;
	      case '.':			/* CP/M divider		*/
		if (dotty != 0)
		    continue;		/* two dots illegal	*/
		if (j == 0)
		    continue;		/* leading dot illegal	*/
		++dotty;
		break;
	      default:			/* all others ignored	*/
		continue;
	}			/* end else-if-switch		*/
	else			/* controls etc.		*/
	    continue;
  /* anything that reaches here must be stored			*/
	if (dotty == 0) {	/* in main name			*/
	    if (j > 7) {	/*  but it's full		*/
		++dotty;
		new[j++] = '.'; /* rest as suffix		*/
		++p2;
	}   }
	else			/* in suffix			*/
	    ++p2;
	new[j++] = c;
    }				/* end for			*/
    if (j == 0) {		/* no valid chars in "old"	*/
	strcpy(new,DEFNAM);	/*  so replace with default	*/
	j = DEFLEN;		/*   length of default		*/
    }
Exit:
    new[j] = 0;			/* close as string		*/
    return(j);
}			/* end of cpmunge()			*/	    



char rdata()		/*  Receive Data		*/
{
    int		fail, num;
    char	typ;

    if (numtry++ > MAXTRY)
	return('A');		/* abort if too many tries */

    typ = rpack(&len,&num,recpkt);
    switch(typ) {

	case 'D':			/* Data			*/
	    if (num != n) {		/* not right packet	*/
		if (oldtry++ > MAXTRY)
		    return('A');
		if (num == ((n==0) ? 63:n-1)) {
		    spack('Y',num,0,0);	/* re-ACK previous	*/
		    numtry = 0;
		    if (list == 1)
			outc('D');
		    if (list > 2)
			printf("\rDbg: Duplicate (%c).",tochar(num));
		    return(state);      /* Don't write out data! */
		}
		else return('A');	/* sorry, wrong number */
	    }
	    if ( (fail = bufemp(recpkt,len)) != 0 ) {
		error(diskfail,fail);
		return('A');
	    }
	    spack('Y',n,0,0);
	    inctry();			/* ++n%64 & mod tries	*/
	    return('D');		/* Remain in data state */

	case 'F':			/* Got a File Header	*/
	case 'X':			/*  or a text header	*/
	    if (oldtry++ > MAXTRY)
		return('A');		/* If too many tries, "abort" */
	    if (num == ((n==0) ? 63:n-1)) {
		spack('Y',num,0,0);     /* ACK previous again	*/
		numtry = 0;
		return(state);		/* Stay in Data state */
	    }
	    else return('A');		/* Not previous packet, "abort" */

	case 'Z':			/* End-Of-File */
	    if (num != n)
		return('A');
	    if (fp != 0)
		printmsg("** File <%s> received. ",ptr2);
	    kclose(fp);			/* Close the file */
	    spack('Y',n,0,0);
	    fp = 0;
	    n = (n+1)%64;
	    return('F');		/* Go back to Receive File state */

	case 'E':			/* Error packet received */
	    prerrpkt(recpkt);
	    reclose();
	    return('A');		/* abort */

	case 'A':			/* user aborted transfer	*/
	    recfail();
	    reclose();
	    return('A');

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

	default:			/* Some other; abort	*/
	    error(badmsg,'D',typ);
	    return('A');
    }
}			/* end of rdata()		*/



static recfail()	/* process user abort		*/
{
    char  num;

    abtflag = 0;
    rpack(&len,&num,recpkt);	/* wait for next packet	*/
    error(errmsg);		/*  then abort		*/
    return;
}			/* end of recfail()		*/



static reclose()	/* close file if open		*/
{
    if (fp != 0) {
	kclose(fp);
	fp = 0;
	printmsg("File <%s> partially received; last data was:",ptr2);
	oldpkt[len] = 0;
	printf("\r  \"%s\". ",oldpkt);
    }
    return;
}			/* end of reclose()		*/



recsw(ist,ipkt)			/* Receive files.		*/
int	ist;				/* initial state	*/
char	ipkt;				/* initial packet-type	*/
{
    fp = 0;
    numtry = 0;
    state = ist;	

    forever {
	if (list > 2) {
	    outc(CR);
	    printf("Dbg: recsw() state: %c",state);
	}
	errdisp();
	if (abtflag != 0) {
	    recfail();
	    reclose();
	    return(FALSE);
	}		/* catch user aborts during spack()	*/
	switch(state) {

  /* special initial states (message already in packet[]):-	*/
	    case RMH:		/* send command and display	*/
	    case RMSV:		/*  anything sent back		*/
	    case GET:		/* get files			*/
		spack(ipkt,n,strlen(packet),packet);
		state = rinit();
		break;		

  /* normal staes during reception:-				*/
	    case 'R':
		state = rinit();
		break;				/* Receive-Init */
	    case 'F':
		state = rfile();
		break;				/* Receive-File */
	    case 'D':
		state = rdata();
		break;				/* Receive-Data */
	    case 'C':
		reclose();
		return(TRUE);			/* Complete state */
	    case 'A':
		reclose();
		return(FALSE);			/* "Abort" state */
    }	}
}			/* end of recsw()			*/



char rfile()		/*  Receive File Header			*/
{
    char disk, *ptr1;
    int  num;

    if (numtry++ > MAXTRY)
	return('A');

    switch(rpack(&len,&num,recpkt)) {

	case 'S':			/* Send-Init, maybe our ACK lost */
	    if (oldtry++ > MAXTRY)
		return('A');
	    if (num == ((n==0) ? 63:n-1)) {	/* Previous packet?	*/
		len = spar(packet);
		spack('Y',num,len,packet);
		numtry = 0;
		return(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?	*/
		spack('Y',num,0,0);
		numtry = 0;
		return(state);
	    }
	    else return('A');		/* Not previous packet, "abort" */

	case 'F':			/* File Header		*/
	    if (num != n)
		 return('A');
	    vtline(LOCFILE,filblank);
	    ptr2 = fname + 2;		/* leave room for disk-letter	*/
	    cpmunge(len,ptr2,recpkt);	/* validate file name received	*/
	    if (filecount) {		/* if override name or disk	*/
		disk = 0;
		ptr1 = *filelist;
		if (*(ptr1+1) == ':') {	/* if disk-letter present	*/
		    disk = *ptr1;
		    ptr1 += 2;		/* up to start of filename	*/
		}
		if (*ptr1 != 0) {	/* if filename present		*/
		    cpmunge(strlen(ptr1),ptr2,ptr1);
		    --filecount;	/* substitute for name received	*/
		    ++filelist;		/*  & advance parm-counters	*/
		}
		if (disk != 0) {	/* if disk-letter specified	*/
		    *(--ptr2) = ':';	/*  put it into fname		*/
		    *(--ptr2) = disk;	/*   in front of filename	*/
	    }	}		/* end if, if				*/		    
  /* fname[] now contains correct validated name, including any disk-letter,
	and ptr2 => either its beginning or third char.			*/
	    vtline(LOCFILE,ptr2);
	    s4sleep();
	    if ( (ptr1 = avoid(ptr2)) != 0 ) {
		error(ptr1,ptr2);
		return('A');
	    }
	    if ((fp=kwopen(ptr2))==NULL) {
		error("Cant create <%s> - cancelled",ptr2);
		return('A');
	    }
	    else
		printmsg("Receiving <%s> as <%s>\r",recpkt,ptr2);
	    spack('Y',n,0,0);
	    inctry();			/* ++n%64 & mod tries		*/
	    return('D');		/* Switch to Data state 	*/

	case 'Y':			/* short reply			*/
	    recpkt[*len] = 0;
	    printmsg("%s\r%s", mainsays,recpkt);
	    return('C');

	case 'X':			/* long reply			*/
	    vtline(LOCFILE,mainsays);
	    printmsg("%s\r",mainsays);
	    spack('Y',n,0,0);
	    inctry();
	    return('D');

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

	case 'E':			/* Error packet received 	*/
	    prerrpkt(recpkt);
	    return('A');

	case 'A':			/* user aborted transfer	*/
	    return('A');

	case FALSE:			/* Didn't get packet		*/
	    if (list != 1)
		txtout(trying);
	    spack('N',n,0,0);
	    return(state);

	default:			/* Some other type, abort	*/
	    error(badmsg,'F',type);
	    return('A');
    }
}			/* end of rfile()				*/




char rinit()		/*  Receive Initialization	*/
{
    int num;

  /* unlimited retries in this state			*/
    switch(rpack(&len,&num,recpkt))
    {
	case 'S':			/* Send-Init 		*/
	    n = num;			/* accept their number	*/
	    rpar(recpkt,len);
	    len = spar(packet);
	    spack('Y',n,len,packet);
	    compmode();
	    inctry();			/* ++n%64 & mod tries	*/
	    return('F');

	case 'I':			/* Info-exchange	*/
	    rpar(recpkt,len);
	    len = spar(packet);
	    spack('Y',n,len,packet);
	    compmode();
	    return('R');

	case 'Y':			/* short reply		*/
	    recpkt[*len] = 0;
	    printmsg("%s\r%s", mainsays,recpkt);
	    return('C');

	case 'X':			/* long reply		*/
	    vtline(LOCFILE,mainsays);
	    printmsg("%s\r",mainsays);
	    n = num;
	    spack('Y',n,0,0);
	    inctry();
	    return('D');

	case 'E':			/* Error packet received */
	    prerrpkt(recpkt);
	case 'N':			/* NAK			*/
	    return('A');

	case 'A':			/* User abort		*/
	    return('A');

	case FALSE:			/* Didn't get packet */
	    if (list != 1)
		txtout(trying);
	    if (state == 'R')		/* normal receive	*/
		spack('N',n,0,0);
	    return(state);

	default:			/* Some other type, abort */
	    error(badmsg,'S',type);
	    return('A');
    }
}			/* end of rinit()		*/



/************  END of file KREC.C  ***************************/

