/*	@(#)tty.c	1.2	7/3/85	*/

#include "kermit.h"
#include "errors.h"

#ifdef unix
#  ifdef VER7
#    include <sgtty.h>
#    define TERM sgttyb 
#  else
#    include <termio.h>
#    define TERM termio
#  endif
#else
struct termio {
    int speed;				/* Not really used yet */
};
#define TERM termio
#endif	/* unix */

static struct TERM host_raw;		/* Host tty "raw" mode */
static struct TERM host_cooked;		/* Host tty "cooked" mode */
static struct TERM rem_raw;		/* remote tty line "raw" mode */
static struct TERM rem_cooked;		/* remote tty line "cooked" mode */

static VOID ShowMode ();


VOID GetModes ()
{
    DBUG_ENTER ("GetModes");
#ifdef unix
#ifdef VER7
    if (cflg) {
	gtty (0, &host_cooked);		/* save tty mode for later */
	gtty (0, &host_raw);		/* host_raw for connect, send, rcv */
	host_raw.sg_flags |= (RAW | TANDEM);
	host_raw.sg_flags &= ~(ECHO | CRMOD);
    }
    gtty (remfd, &rem_raw);
    rem_raw.sg_flags |= (RAW | TANDEM);
    rem_raw.sg_flags &= ~(ECHO | CRMOD);
    rem_raw.sg_ispeed = speed;
    rem_raw.sg_ospeed = speed;
#else
    if (cflg) {
	if (ioctl (0, TCGETA, &host_cooked) == -1) {
	    Error (HOST_TCGETA);
	    WrapUp (1);
	} else {
	    host_raw = host_cooked;
	    host_raw.c_iflag = IGNBRK;
	    host_raw.c_oflag = 0;
	    host_raw.c_lflag &= ~(ISIG | ECHO | ICANON);
	    host_raw.c_cc[VMIN] = 1;
	    host_raw.c_cc[VTIME] = 1;
	    ShowMode ("initial host tty modes", &host_cooked);
	    ShowMode ("raw host tty modes", &host_raw);
	}
    }
    if (remfd) {
	if (ioctl (remfd, TCGETA, &rem_cooked) == -1) {
	    Error (REMOTE_TCGETA);
	    WrapUp (1);
	} else {
	    rem_cooked.c_cflag &= ~HUPCL;	/* HACK! */
	    rem_raw = rem_cooked;
	    rem_raw.c_iflag = IGNBRK;
	    rem_raw.c_oflag = 0;
	    rem_raw.c_lflag &= ~(ISIG | ECHO | ICANON);
	    rem_raw.c_cc[VMIN] = 1;
	    rem_raw.c_cc[VTIME] = 1;
	    rem_raw.c_cflag = speed | CS8 | CREAD;
	    ShowMode ("initial remote tty modes", &rem_cooked);
	    ShowMode ("raw remote tty modes", &rem_raw);
	}
    }
#endif
#endif	/* unix */
    DBUG_VOID_RETURN;
}


static VOID ShowMode (cp, tp)
char *cp;
struct TERM *tp;
{
    DBUG_ENTER ("ShowMode");
#ifdef unix
#ifndef VER7
    DBUG_3 ("tty","%s",cp);
    DBUG_3 ("tty", "c_iflag is %o", tp -> c_iflag);
    DBUG_3 ("tty", "c_oflag is %o", tp -> c_oflag);
    DBUG_3 ("tty", "c_cflag is %o", tp -> c_cflag);
    DBUG_3 ("tty", "c_lflag is %o", tp -> c_lflag);
#endif
#endif	/* unix */
    DBUG_VOID_RETURN;
}


SetTtyMode (fildes, mode)
int fildes;
struct TERM *mode;
{
    register int    status;

    DBUG_ENTER ("SetTtyMode");
#ifdef unix
    status = FALSE;
#ifdef VER7
    stty (fildes, mode);
    status = TRUE;
#else
    if (ioctl (fildes, TCSETAW, mode) != -1) {
	if (ioctl (fildes, TCXONC, 1) != -1) {
	    status = TRUE;
	}
    }
#endif
#else
    DBUG_2 ("ttymode", "setting tty modes currently a NOP");
    status = TRUE;
#endif	/* unix */
    DBUG_RETURN (status);
}


VOID HostRaw ()
{
    DBUG_ENTER ("HostRaw");
    if (cflg && !SetTtyMode (0, &host_raw)) {
	Error (HOST_RAW);
	WrapUp (1);
    }
    DBUG_VOID_RETURN;
}


VOID HostCooked ()
{
    DBUG_ENTER ("HostCooked");
    if (cflg && !SetTtyMode (0, &host_cooked)) {
	Error (HOST_COOKED);
	WrapUp (1);
    }
    DBUG_VOID_RETURN;
}


VOID SetSpeed()
{
    DBUG_ENTER ("SetSpeed");
    if (speed) {		/* user specified a speed? */
#ifdef AMIGA
	printf ("warning -- speed currently ignored, use 'preferences'\n");
#else
	switch (speed) {	/* get internal system code */
	    case 110: 
		speed = B110;
		break;
	    case 150: 
		speed = B150;
		break;
	    case 300: 
		speed = B300;
		break;
	    case 1200: 
		speed = B1200;
		break;
	    case 2400: 
		speed = B2400;
		break;
	    case 4800: 
		speed = B4800;
		break;
	    case 9600: 
		speed = B9600;
		break;
	    case EXTA:
	    case 19200:
	        speed = EXTA;
		break;
 	    case EXTB:
	        speed = EXTB;
		break;
	    default: 
		Error (SPEED, speed);
		break;
	}
#endif	/* AMIGA */
    }
    DBUG_VOID_RETURN;
}


VOID SetUp ()
{
    DBUG_ENTER ("SetUp");
    if (remfd) {
	DBUG_2 ("remtty", "set modes on communications line");
	if (!SetTtyMode (remfd, &rem_raw)) {
	    Error (REMOTE_RAW);
	    WrapUp (1);
	}
    }
    DBUG_VOID_RETURN;
}


VOID CleanUp ()
{
    DBUG_ENTER ("CleanUp");
    if (remfd) {
	if (!SetTtyMode (remfd, &rem_cooked)) {
	    Error (REMOTE_COOKED);
	    WrapUp (1);
	}
    }
    DBUG_VOID_RETURN;
}


VOID NewSpeed (nspeed)
int nspeed;
{
    DBUG_ENTER ("NewSpeed");
    speed = nspeed;
    DBUG_VOID_RETURN;
}
