/*			:ts=8						*/

/*
 * These are the new interfaces between vt100 and the new Kermit protocol
 * module.
 */

#include "vt100.h"			/* Get defines and so on	*/
/*
 * Here are the declarations for our communication with kermitproto.c
 */

extern int	cx, cz;			/* Abort flags			*/

extern char	start;			/* Start state for Kermit	*/
char		*cmarg;			/* Command argument for server	*/ 

/*
 * The below variables have to do with the status of the communcation
 * so far.  They should be maintained over in kermitproto.w so that
 * things like the number of bytes sent and the packet type can be
 * printed as status.
 */
static int	npackets,		/* Number of packets sent so far */
		naks;			/* Number of naks		*/


static char message[80];		/* Message line to output	*/

/*
 * Do Kermit sending.  This expands wild cards into local variables for
 * gnfile() below.
 */

static int nfiles, wild;
static char **lp, **list;

doksend(file,more)
char *file;
int more;
{
    char *p;

    list = NULL;
    p = file;
    while(*p && *p != '*' && *p != '?') p++;
    if (*p) {
	wild = 1;
	list = expand(file, &nfiles);
	if (list == NULL) {
	    InfoMsg1Line("KERMIT: No wild card match");
	    return FALSE;
	}
    }
    else {
	nfiles = 1;
	wild = 0;
	list = (char **) malloc(sizeof(char *));
	*list = (char *) malloc(strlen(file) + 1);
	strcpy(*list, file);
    }
    lp = list;
    start = 's';			/* Set start state to send	*/
    npackets = naks = 0;
    message[0] = '\0';
    proto();				/* Call protocol		*/
    if (wild == 1)
	free_expand(list);
    else {
	free((void *) *list);
	free((void *) list);
    }
    return TRUE;
}

/*
 * gnfile(s, n)  char *s; int n;
 *
 * Returns in string s the name of the next file for Kermit to process,
 * which can be up to n characters in length.  Returns a positive value
 * if there are more files, 0 if not.
 */
int
gnfile(s, n)
char *s;
int n;
{
    if (--nfiles >= 0) {
	strncpy(s, *lp, n);
	lp++;
	return 1;
    } else
	return 0;
}

/*
 * Do Kermit receiving.  The file and more arguments in this routine are
 * for Get'ting files when the remote machine is the server.
 */
dokreceive(file,more)
char *file;
int more;
{
    naks = npackets = 0;
    message[0] = '\0';			/* Initialize			*/
    if (!server)
	start = 'v';			/* Start state to receive	*/
    else {
	cmarg = file;			/* Files to get from remote	*/
	start = 'r';			/* Start state to get		*/
    }
    proto();
    return TRUE;
}

/* kermit_directory()--request a remote directory from a Kermit server.
 */

#define tochar(c) ((c) + 32)

void
kermit_directory(dir)
char *dir;
{
    char command[80];

    strcpy(command, "D");		/* Generic directory command */
    command[1] = tochar(strlen(dir));	/* Length of directory name */
    strcpy(&command[2], dir);		/* The directory itself */
    cmarg = command;
    start = 'g';			/* Generic command start state */
    naks = npackets = 0;
    proto();
}

/*
 * saybye()--send a FINISH command to a remote Kermit server.  This is
 * in fact what the original VT100 saybye() does.  A true Kermit BYE
 * command would mean changing the "F" below to "L", and it would actually
 * log out the remote host as well as shut down the Kermit server.
 */
void
saybye()
{
    static char bye_command[] = "F";

    cmarg = &bye_command[0];
    start = 'g';			/* Generic command start state	*/
    naks = npackets = 0;
    proto();
    return /* TRUE */;
}

/*
 * ttinl(dest, max, eol, timelimit)
 *
 * Read up to max characters from serial port into the array pointed
 * to by dest.  Return value is the number of characters received.
 *    If eol is greater than 0, terminate read upon first
 * eol character received.  If timelimit is greater than 0, wait at
 * most timelimit seconds for the characters.  The array is null
 * terminated;  in addition, if we do see an eol, we overwrite it
 * with the NULL and the returned character count does not include it.
 * (This behavior is required by the code in the C Kermit book but is
 * not explicitly stated there.)
 *
 * This version is most unsatisfactory as it does I/O one character
 * at a time, but extensive changes in the rest of VT100 would be
 * needed in order to use a multi-character read.
 */

static int pushedser = -1;			/* pushed character	*/

int ttinl(dest, max, eol, timelimit)
char *dest;
int max, eol, timelimit;
{
    int i;
    void ttflui();

    if (timelimit > 0)
	ttime = timelimit;
    else
	ttime = 30;			/* Maximum timeout if not given	*/
    for (i = 0; i < max; i++) {
	dest[i] = readchar();
	if (timeout != GOODREAD) {
	    if (timeout == USERABORT) {	/* User abort requested		*/
		if (cx == 1)
		    start = 'a';	/* Second escape--abort mess	*/
		else
		    cx = cz = 1;	/* Set abort flags		*/
		continue;		/* Continue receiving anyway	*/
	    } else {
		i = -1;			/* Some other error.		*/
		break;
	    }
	}
	if (eol > 0 && dest[i] == eol)
	    break;
	ttime = 2;			/* Intrapacket timeout		*/
    }
    if (i >= 0)
	dest[i] = '\0';			/* Null terminate what we got	*/
    else
	dest[0] = '\0';
    return i;				/* Return length or failure	*/
}

/*
 * ttol(out, n)
 *
 * Send n characters pointed to by out through the serial port using
 * current settings of word length, parity, and flow control. Return
 * 
 *
 * Here I bypass sendchar() and go direct to the low level.
 */
int
ttol(out, n)
char *out;
int n;
{
    int retval;

    Write_Request->IOSer.io_Data = (APTR) out;
    Write_Request->IOSer.io_Length = n;
    Write_Request->IOSer.io_Command = CMD_WRITE;
    SendIO((struct IORequest *)Write_Request);
    retval = WaitIO((struct IORequest *)Write_Request);
    /*
     * Restore old values.
     */
    Write_Request->IOSer.io_Data = (APTR) rs_out;
    Write_Request->IOSer.io_Length = 1;
    if (retval != 0)
	return -1;
    else
	return ((int)Write_Request->IOSer.io_Actual);
}

/*
 * ttflui()
 *
 * Remove any pending characters from the serial port.
 *
 * Even worse than ttinl() and ttol(), this reads characters with a minimal
 * timeout until there aren't any more.  Note that I also changed readchar()
 * in xmodem.c to check if ttime is 0, and if it is, to set its timeout to
 * 100,000 ticks (0.1 seconds).  I also removed the InfoMsg1Line call which
 * warned about timeouts so this would work.  Ideally, ttinl() should do
 * a single CMD_READ in ReadRequest, and ttflui() should AbortIO() it.
 */
void
ttflui()
{
    int c;

    ttime = 0;
    do {
	c = readchar();
    } while (timeout == GOODREAD);
}

void
sleep(seconds) int seconds;
{
    if (seconds > 0)
	Delay(seconds*TICKS_PER_SECOND);
}

/*
 * Now here are tmsg() and tchar() for putting out warnings.  What I've done
 * is to use tchar()'s argument as a flag to put out whatever status we need.
 * tmsg()'s argument is put out as a message line.
 */

/*
 * tchar(c)--put the single character c onto the user's screen as part
 * of Kermit's communication to said user.
 */
void
tchar(c)
char c;
{
    char status[80];
    void tmsg();

    switch (c) {
	case '.':
	    npackets++;
	    break;
	case '%':
	    naks++;
	    break;
	default:
	    status[0] = c;
	    status[1] = '\0';
	    tmsg(status);			/* Output unknown chars */
	    return;
    }
    sprintf(status, "Packets: %4d Retries: %4d", npackets, naks);
    InfoMsgNoScroll(status);
}

/*
 * tmsg(s) char *s;--Put a message string onto the user's screen as part
 * of the communication from Kermit.
 *
 * I put out a message using InfoMsg.  We store it up until we get a newline,
 * then we scroll and put it out.
 */

void
tmsg(more_message)
char *more_message;
{
    /*
     * If new message won't fit, put out message so far and copy it.
     * Otherwise, just catenate new message to old.
     */
    if (strlen(more_message) + strlen(message) < sizeof(message)) {
	strcat(message,more_message);
    } else {
	InfoMsg1Line(message);
	strcpy(message,more_message);
    }
}

/*
 * tmsgl(s) char *s;--Put out a newline-terminated message to the user's
 * screen as part of Kermit communication.
 */
void
tmsgl(more_message)
char *more_message;
{
    tmsg(more_message);
    InfoMsg1Line(message);
    message[0] = '\0';
}

