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

/*  File KSEND.C  -  Send procedures for RML Kermit;
		Chris Kennington,	RML.	1st July 1985	*/

#define  DEFS2	1
#define	 DEFS4	1

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


/* static externals for this file only			*/
static char  cannot[]  = "Cannot open <%s>; ";
static char  mainhas[] = "Mainframe has ";
static char  unable[]  = "Nothing from mainframe. ";
static int   num, len;		/* Packet number & length	*/




gnxtfl()
/*  Get next file in a file group; if wildcard, expand it into
      cmdline.  Return TRUE or FALSE.				*/
{
    char	ret;

    if (filecount-- == 0) {
	filnam = 0;
	return(FALSE);			/* If no more, fail	*/
    }
    else {
	vtline(LOCFILE,filblank);
	vtline(LOCFILE,(filnam = *(filelist++)));
	printmsg(null);
	if ( ( (ret = fileok(filnam))&(char)0x07 ) != 0 ) {
	    txtout("not sent.");	/* no file	*/
	    return(gnxtfl());		/* recursive call	*/
	}
	else if ( (ret&(char)0x40) != 0 ) {	/* wildcards	*/
	    printf("Expanding wildcards ...");
	    ret = wildex(filnam,cmdline);
	    printmsg("Will send: %s",cmdline);
	    if (ret > (char)8)
		txtout(" (more on disk)");
	    filecount = decol8(cmdline,cmdparm,8);
	    filelist = cmdparm;
	    return(gnxtfl());		/* recursive call	*/
	}
	else {
	    return(TRUE);
}   }	}		/* end of gnxtfl()		*/




char sbreak()		/*  Send Break (EOT)		*/
{
    if (numtry++ > MAXTRY) return('A');	/* If too many tries "abort"	*/

    spack('B',n,0,0);		/* Send a B packet	*/
    switch (rpack(&len,&num,recpkt))	/* What was the reply?	*/
    {
	case 'N':			/* NAK, just stay in this state,	*/
	    num = (--num<0 ? 63:num);	/* unless NAK for previous packet,	*/

	case 'Y':			/* ACK	*/
	    if (n != num) return(state); /* If wrong ACK, fail	*/
	    inctry();			/* ++n%64 & ++tries	*/
	    printmsg("** All files sent OK. ");
	    return('C');		/* Switch state to Complete	*/

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

	case FALSE: return(state);	/* Receive failure, stay in B	*/

	default:			/* Other, "abort"	*/
	    printmsg(badmsg,'Y',type);
	    return('A');
   }
}			/* end of sbreak()			*/




char sdata()		/*  Send File Data	*/
{
    if (numtry++ > MAXTRY) return('A');	/* If too many tries, give up	*/

    spack('D',n,size,packet);		/* Send a D packet	*/
    if (abtflag != 0) {
	sendfail();
	return('A');
    }
    switch(rpack(&len,&num,recpkt))	/* What was the reply?	*/
    {		
	case 'N':			/* NAK, just stay in this state,	*/
	    if (list > 2)
		printf("\rDbg: NAK for packet %c.", tochar(num));
	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet, */
  /* which is just like an ACK for this packet so fall thru to...	*/

	case 'Y':			/* ACK				*/
	    if (n != num)
		return(state);		/* If wrong ACK, repeat	*/
	    inctry();			/* ++n%64 & ++tries		*/
	    if (len != 0) switch (*recpkt) {	/* truncation		*/
	      case 'X':				/*  single file		*/
		printmsg("%struncated file",mainhas);
		return('Z');
	      case 'Z':				/*  file group		*/
		printmsg("%scancelled transfer",mainhas);
		seclose();
		return('B');
	      default:
		if (list > 2)
		    printf("\rDbg: Bad ACK <%s>",recpkt);
		break;
	    }
	    if ((size = bufill(packet)) == EOF)	/* Get data from file	*/
		if (errno == 0)
		    return('Z');	/* If EOF set state to that	*/
		else {			/* error			*/
		    error(diskfail,errno);
		    return('A');
		}
	    else
		return('D');		/* Got data, stay in state D	*/

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

	case FALSE:
	    return(state);		/* Receive failure, stay in D	*/

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

	default:			/* Anything else, just "abort"	*/
	    printmsg(badmsg,'Y',type);
	    return('A');
    }
}			/* end of sdata()			*/



seclose()		/* close send-file			*/
{
    if (fp != 0) {
	kclose(fp);
	fp = 0;
	filnam = 0;
    }
    return;
}			/* end of seclose()			*/



sendfail()		/* process user abort			*/
{
    abtflag = 0;
    rpack(&len,&num,recpkt);	/* ignore next packet		*/
    error(errmsg);		/*  then abort			*/
    seclose();
    return;
}				/* end of sendfail()		*/




sendsw(ist)		/* Send files			*/
int	ist;			/* initial state	*/
{
    state = ist;
    n = 0;
    numtry = 0;
    while(TRUE) {
	if (list > 2) {
	    outc(CR);
	    printf("Dbg: sendsw() state: %c, ",state);
	}
	errdisp();			/* update error display	*/
	switch(state) {
	    case 'S':
			txtout(dots);
			state = sinit();  
			break;		/* Send-Init		*/
	    case 'F':   state = sfile();  
			break;		/* Send file-init	*/
	    case 'D':   state = sdata();  
			break;		/* Send-Data		*/
	    case 'Z':   state = seof();   
			break;		/* Send-End-of-File	*/
	    case 'B':   state = sbreak();
			break;		/* Send-Break		*/
	    case 'C':
		seclose();
		return (TRUE);				/* Complete	*/
	    case 'A':					/* "Abort"	*/
	    default:					/* Unknown, fail */
		seclose();
		return (FALSE);
    }	}
}			/* end sendsw()				*/




char seof()		/*  Send End-Of-File.		*/
{
    if (numtry++ > MAXTRY) return('A');	/* If too many tries, "abort"	*/

    spack('Z',n,0,0);			/* Send a 'Z' packet	*/
    if (fp != 0)
	printmsg("** File %s sent OK. ",filnam);
    seclose();				/* close file		*/
    switch(rpack(&len,&num,recpkt)) {

	case 'N':			/* NAK, just stay in this state,	*/
	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet,	*/

	case 'Y':			/* ACK	*/
	    if (n != num) return(state); /* If wrong ACK, hold out	*/
	    inctry();			/* ++n%64 & ++tries	*/
	    fp = NULL;			/* Set flag indicating no file open	*/ 
	    if (gnxtfl() == FALSE)	/* No more files go?	*/
		return('B');		/* if not, break, EOT, all done	*/
	    return('F');		/* More files, switch state to F	*/

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

	case FALSE:
	    return(state);		/* Receive failure, stay in Z	*/

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

	default:			/* Anything else, just "abort"	*/
	    printmsg(badmsg,'Y',type);
	    return('A');
    }
}		/* End of seof()				*/




char sfile()			/*  Send File Header.		*/
{
    char   wk[14], *newfilnam,	/* Pointer to file name to send	*/
	   c, *cp;			/* char, pointer	*/

    if (numtry++ > MAXTRY) {
	txtout(unable);
	return('A');
    }
    if ( (fp == NULL) && ( (fp = kropen(filnam)) == NULL) ) {
  /* trouble opening file					*/
	if (filecount != 0) {		/* if more to go	*/
	    printf(cannot,filnam);
	    gnxtfl();
	    numtry = 0;			/* permit name message	*/
	    return('F');		/*  send next one	*/
	}
	else {
	    error(cannot,filnam);
	    return('A');
    }	}

    strcpy(wk, filnam);			/* Copy file name	*/
    newfilnam = &wk;
    if (newfilnam[1] == ':')
	newfilnam += 2;			/* strip CP/M disk-letter	*/

  /* Filenames are always u.c. under CP/M		 	*/
    len = strlen(newfilnam);
    if (numtry == 1)			/* once per file only	*/
	printf("Sending <%s> as <%s>\r",filnam,newfilnam);
    if (abtflag != 0) {
	sendfail();
	return('A');
    }
    spack('F',n,len,newfilnam);		/* Send an F packet	*/

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

	case 'N':			/* NAK, just stay in this state,	*/
	    num = (--num<0 ? 63:num);
	    printmsg("Trouble exchanging params");
/* unless it's NAK for next packet which is just like an ACK for this packet so fall thru to...	*/

	case 'Y':			/* ACK	*/
	    if (n != num) return(state); /* If wrong ACK, stay in F state	*/
	    inctry();			/* ++n%64 & ++tries	*/
	    softeof = FALSE;
	    if ( (size = bufill(packet)) == EOF ) { /* null file */
		if (errno == 0) {
		    printmsg("File empty.");
		    return('Z');	/* on to next		*/
		}
		else {			/* error			*/
		    error(diskfail,errno);
		    return('A');
	    }	}
	    else
		return('D');		/* Switch state to D	*/

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

	case FALSE:
	    if (list != 1)
		txtout(trying);
	    return(state);		/* Receive failure, stay in F state */

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

	default:			/* Anything else, just "abort"	*/
	    printmsg(badmsg,'Y',type);
	    return('A');
    }
}			/* end of sfile()			*/




char sinit()		/*  Send Initiate		*/
/* send this host's parameters and get other side's back.*/
{
    if (numtry++ > MAXTRY) {		/* If too many tries, give up	*/
	txtout(unable);
	return('A');
    }
    len = spar(packet);			/* Fill up init info packet	*/
    flushinput();			/* Flush pending input	*/
    spack('S',n,len,packet);		/* Send an S packet	*/
    if (abtflag != 0) {
	sendfail();
	return('A');
    }
    switch(rpack(&len,&num,recpkt))	/* What was the reply?	*/
    {

	case 'Y':			/* ACK	*/
	    if (n != num)		/* If wrong ACK, stay in S state	*/
		return(state);		/* and try again	*/
	    rpar(recpkt,len);		/* Get other side's init info	*/
	    compmode();			/* tell user		*/
	    if (eol == 0) eol = '\n';	/* Check and set defaults	*/
	    if (quote == 0) quote = '#';
	    inctry();			/* ++n%64 & ++tries	*/
	    return('F');		/* OK, switch state to F	*/

	case 'I':			/* Info-exchange		*/
	    rpar(recpkt,len);
	    len = spar(packet);
	    compmode();
	    spack('Y',n,len,packet);
	    rpack(&len,&num,recpkt);	/* ignore response	*/
	    return('S');

	case 'R':			/* Get-packet		*/
	    txtout("R-packet from remote Kermit ");
	    rpar(recpkt,len);
	    return(state);		/* causes retransmission of 'S' */

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

	case FALSE:			/* Receive failure	*/
	    if (list != 1)
		txtout(trying);
	case 'N':			/* NAK, try it again	*/
	    return(state);

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

	default:		/* Anything else, just "abort"	*/
	    printmsg(badmsg,'Y',type);
	    return('A');
    }
 }		/* end of sinit()				*/



/*********************  END of KSEND.C  ****************************/


