/*
Tom Jennings
15 March 89


Sample MODEM7 file name handshake. Please feel free to steal these
without the slightest twinge of guilt. 

My coding practices probably aren't yours, and you might not use C, but
for the nitty gritty program flow of this truly obnoxious protocol this
is extremely robust. It pre-dates Fido by a year or two.


Here's what some of the more important routines do:

modin(n)	Returns a character available, else -1 if more that N
		times 10 milliseconds.

modout(c)	Outputs C to the modem.

flush(n)	Flush the modem until it is clear for n centiseconds.

*/

#define NUL 0
#define SOH 1
#define EOT 4
#define ACK 6
#define NAK 21
#define SYN 22
#define CAN 24
#define SUB 26
#define ESC 27

/* Transmit a filename for batch mode tranmission. Return -1 if cant do it,
or OK if sent properly. It is assumed that the receiver is ready to receive
the filename we have to send. -2 means the other end sent five Control-Xs. */

sendfn(name)
char *name;
{
char chksum;
char c,localname[SS];
int i;

	chksum= 0;				/* mis-use as Control-X counter */
	for (i= 1; i <= 30; i++) {		/* get initial character */
		c= modin(200);			/* 60 sec max */
		if (c == NAK) break;		/* got name NAK */
		if (c == 'C') return('C');	/* spoof to SEALINK? */
		if (c == CAN) {			/* if Control-X */
			if (++chksum > 4) return(-2);
		}
		if (c != -1) xferstat(3,0L + i,"SendFN got 0x%02x",c);
		flush(0);			/* flush built-up garbage */
	}
	if (i <= 0) return(-1);			/* timeout */

	cvt_to_fcb(name,localname);		/* convert name, */
	chksum= 0;				/* start checksum, */
	modout(ACK);				/* all ready, */
	for (i= 0; i < 11; i++) {
		c= localname[i];		/* get name char, */
		chksum += c;			/* maintain checksum, */
		modout(c);			/* send name char, */
		if (modin(1000) != ACK) break;	/* if not an ACK */
	}
	if (i >= 11) {				/* if all sent OK */	
		modout(SUB);			/* end of name, */
		chksum += SUB;			/* stupid protocol */
		if (modin(1000) == (chksum & 0xff)) { /* get recvr's checksum, */
			modout(ACK);		/* if good, say so, */
			return(0);		/* return happy :-), */
		}
	}
	xferstat(3,0L,"Filename checksum error");
	modout('u');				/* else not sent OK, */
	return(-1);				/* return sad :-( */
}

/* Get a filename from the sender. */

getfn(name)
char *name;
{
int i;
int c;			/* NOTE: 'c' is an integer !!! */
char chksum;
char newname[SS];

/* This is now done in getfname() 
	modout(NAK);					/* sync sender, */
	modout('C');					/* or this to spoof to SEALINK */
*/
	c= modin(200);					/* get sync character, */
	if (c != ACK) return(c);

	chksum= 0;
	for (i= 0; i < 11; i++) {			/* 11 char max, */
		c= modin(1000);				/* get a char, */
		switch (c) {
			case -1: return(-1);		/* timeout */
			case 'u': return(-1);		/* error */
			case EOT: return(EOT);		/* no more files */
			case SUB: break;		/* end of name */
			default:
				chksum += c;		/* file name char I guess */
				newname[i]= c;		/* stash it */
				modout(ACK);		/* say "ok" */
				break;
		}
	}
	if (modin(1000) == SUB) {			/* if end of name, */
		chksum += SUB;				/* stupid protocol, */
		modout(chksum);				/* send check sum, */
		if (modin(1000) == ACK) {
			cvt_from_fcb(newname,name);	/* fix name, */
			return(OK);
		}
	}
	return(-1);					/* filename too long */
}

/* Convert a CP/M like filename to a normal ASCIZ name. */

cvt_from_fcb(inname,outname)
char *inname,*outname;
{
int i;
char c;

	for (i= 8; i > 0; --i) {
		c= fnc(*inname++);
		if (c != ' ') *outname++= c;	/* ignore spaces */
	}					/* but do all 8 */
	*outname++= '.';			/* add the dot, */

	for (i= 3; i > 0; --i) {
		c= fnc(*inname++);
		if (c == ' ') break;
		*outname++= c;
	}
	*outname= NUL;				/* terminate it, */
}

/* Convert a normal asciz string to MSDOS/CPM FCB format. Make the filename
portion 8 characters, extention 3 maximum. Supports wildcards, skips drive
specs. */

cvt_to_fcb(inname,outname)
char *inname;
char outname[];
{
char c;
int i;

	if (inname[1] == ':') inname= &inname[2];
	for (i= 0; i < 11; i++)
		outname[i]= ' ';		/* clear out name, */
	_cvt2(inname,outname,8);		/* do name portion, */
	while (*inname) {			/* skip to dot, if any */
		if (*inname++ == '.') break;
	}
	_cvt2(inname,&outname[8],3);		/* do extention, */
}
/* Do part of a name. */

_cvt2(inname,outname,n)
char *inname,*outname;
int n;
{
int i;
	for (i= 0; i < n; i++) {		/* NAME PART */
		if (*inname == '\0')		/* if null, */
			break;			/* quit, */
		else if (*inname == '*')	/* if *, fill with ?, */
			outname[i]= '?';
		else if (*inname == '.')	/* if a dot, */
			break;			/* skip to extention, */
		else {
			outname[i]= toupper(*inname);
			++inname;
		}
	}
}

/* Fix this filename character */

fnc(c)
char c;
{
	if ((c < ' ') || (c == '\\') || (c == '/')) c= '$';
	return(c);
}
