#include "LYCurses.h"
#include "HTUtils.h"
#include "LYUtils.h"
#include "LYGlobalDefs.h"
#include "LYSignal.h"
#include "LYClean.h"
/*
 * These are routines to start and stop curses and to cleanup
 * the screen at the end
 *
 */

PRIVATE dumbterm PARAMS((char *terminal));

PUBLIC void start_curses ()
{
#ifndef VMS
    static BOOLEAN first_time = TRUE;

	/* if were not VMS then only do initsrc() one time
	 * and one time only!
	 * if we are VMS then do initsrc() everytime start_curses()
	 * is called!
	 */
    if(first_time) {
        initscr();	/* start curses */
        first_time = FALSE;
    }

#else
    initscr();	/* start curses */
#endif VMS

    /* nonl();   *//* seems to slow things down */

#ifdef VMS
    crmode();
    raw();
#endif VMS

#ifdef UNIX
    cbreak();
    signal(SIGINT, cleanup_sig);
#endif UNIX

    noecho();

    fflush(stdin);
    fflush(stdout);

}


PUBLIC void stop_curses()
{
    echo();

    endwin();	/* stop curses */

    fflush(stdout);

#ifndef VMS
    signal(SIGINT, SIG_IGN);
#endif /* not VMS */

}


#ifdef VMS
/*
 * check terminal type, start curses & setup terminal
 */
PUBLIC BOOLEAN setup ARGS1(char *,terminal)
{
    int c;
    char *dummy, *cp, term[81];

    /*
     * get terminal type, and convert to lower case
     */
    longname(dummy, term);
    for (cp=term; *cp!='\0'; cp++)
	if (isupper(*cp))
	    *cp = tolower(*cp);

    printf("Terminal = %s\n", term);
    sleep(1);
    if (strncmp(term, "vt1", 3) != 0 &&
	strncmp(term, "vt2", 3) != 0 &&
	strncmp(term, "vt3", 3) != 0 &&
	strncmp(term, "vt4", 3) != 0 &&
	strncmp(term, "vt52", 4) != 0 ) {
	printf(
	    "You must use a vt100, 200, etc. terminal with this program.\n");
	printf("Proceed (n/y)? ");
	c = getchar();
	if (c != 'y' && c != 'Y') {
	    printf("\n");
	    return(FALSE);
	}
    }

    ttopen();
    start_curses();

    return(TRUE);
}

#else	/* not VMS */
/*
 * check terminal type, start curses & setup terminal
 */
PUBLIC BOOLEAN setup ARGS1(char *,terminal)
{
#ifndef MSDOS
    static char term_putenv[120];
    char term[120];
    char buffer[120];

 /* if the display was not set by a command line option then see 
  * if it is available from the environment 
  */
    display = getenv("DISPLAY");

    if(terminal != NULL) {
	sprintf(term_putenv,"TERM=%s",terminal);
	(void) putenv(term_putenv);
    }

	/* query the terminal type */
    if(dumbterm(getenv("TERM"))) {
	printf("\n\n  Your Terminal type is unknown!\n\n");
	printf("  Enter a terminal type: [vt100] ");
	gets(buffer);

	if(strlen(buffer) == 0)
	    strcpy(buffer,"vt100"); 
	
	sprintf(term_putenv,"TERM=%s", buffer);
	putenv(term_putenv);  /* */
	printf("\nTERMINAL TYPE IS SET TO %s\n",getenv("TERM"));
    }


    start_curses();

    /* get terminal type (strip 'dec-' from vms style types) */
    if (strncmp(ttytype, "dec-vt", 6) == 0) {
	strcpy(term, ttytype+4);
	(void) setterm(term);
    }
#else
    start_curses();
#endif MSDOS

    return(1);
}

PRIVATE dumbterm ARGS1(char *,terminal)
{
    int dumb = FALSE;

    if (!strcasecomp(terminal, "network") ||
	!strcasecomp(terminal, "unknown") ||
	!strcasecomp(terminal, "dialup")  ||
	!strcasecomp(terminal, "dumb")    ||
	!strcasecomp(terminal, "switch")  ||
	!strcasecomp(terminal, "ethernet")  )
	dumb = TRUE;
    return(dumb);
}
#endif

#ifdef VMS
/*
 *	Cut-down termio --
 *		Do character-oriented stream input for Jeff.
 *		Code ripped off from Micro-Emacs 3.7 by Daniel Lawrence.
 *
 *		Ever-so-slightly modified by Kathryn Huxtable.  29-Jan-1991.
 *		Cut down for Lou.  8 Sep 1992.
 *		Cut down farther for Lou.  19 Apr 1993.
 *			We don't set PASSALL or PASTHRU since we don't
 *			want to block CTRL/C, CTRL/Y, CTRL/S or CTRL/Q.
 *			Simply setting NOECHO and doing timed reads
 *			is sufficient.
 *              Further mods by Fote.  29-June-1993
 *			ttopen() and ttclose() are now terminal initialization
 *			 and restoration procedures, called once at startup
 *			 and at exit, respectively, of the LYNX image.
 *			ttclose() should be called before an exit from LYNX
 *			 no matter how the exit is invoked.
 *			setup(terminal) does the ttopen().
 *			cleanup() calls cleanup_files() and ttclose().
 *			ttgetc() now handles NOECHO and NOFLITR (instead of
 *			 setting the terminal itself to NOECHO in ttopen()).
 *			vsignal() added for handling both Ctrl-C *and* Ctrl-Y
 *			 interrupts, and disabling system response to Ctrl-T.
 *              Further mods by Fote.  15-Dec-1993
 *			Added edit handler in ttopen() which will invoke
 *			 VMSexit() and behave intelligently on ACCVIO's.
 *			
 */

#include <descrip.h>
#include <iodef.h>
#include <ssdef.h>
#include <stdlib.h>
#include <msgdef.h>
#include <ttdef.h>
#include <tt2def.h>
#include <libclidef.h>


#define	TRUE	1			/* True value			*/
#define	FALSE	0			/* False value			*/

#define MAXIBUF 128			/* Input buffer size		*/
#define MAXOBUF 1024			/* MM says bug buffers win!	*/
#define EFN	0			/* Event flag			*/

static	char	ibuf[MAXIBUF];		/* Input buffer			*/
static	int	nibuf;			/* # of bytes in above		*/
static	int	ibufi;			/* Read index			*/
static	int	oldmode[3];		/* Old TTY mode bits		*/
static	int	newmode[3];		/* New TTY mode bits		*/
static	short	iochan;			/* TTY I/O channel		*/
static  $DESCRIPTOR(term_nam_dsc,"TT"); /* Descriptor for iochan	*/
static	int	mask = LIB$M_CLI_CTRLY|LIB$M_CLI_CTRLT; /* ^Y and ^T	*/
static	int 	old_msk;		/* Saved control mask		*/
static	short	trap_flag = FALSE;	/* TRUE if AST is set		*/
BOOLEAN DidCleanup = FALSE;		/* Exit handler flag		*/

PUBLIC void VMSexit()
{
    /*
     * If we get here and DidCleanup is not set, it was via an
     *  ACCVIO, so make *sure* we attempt a cleanup and reset
     *  the terminal.
     */
     if (!DidCleanup) {
          fprintf(stderr,"\nPlease report this error to Lou Montulli:");
          fprintf(stderr,"\n    montulli@ukanaix.cc.ukans.edu");
          fprintf(stderr,"\nPress RETURN to clean up: ");
	  (void) getchar();
          cleanup();
     }
}

/*
 *	TTOPEN --
 *		This function is called once to set up the terminal
 *		device streams.	 It translates TT until it finds
 *		the terminal, then assigns a channel to it, sets it
 *		to EDIT, and sets up the Ctrl-C and Ctrl-Y interrupt
 *		handling.
 */

PUBLIC int ttopen()
{
	extern	void cleanup_sig();
	int	iosb[2];
	int	status;
	static unsigned long condition;
	static struct _exit_block {
	    unsigned long forward;
	    unsigned long address;
	    unsigned long zero;
	    unsigned long condition;
	} exit_handler_block;

	status = SYS$ASSIGN( &term_nam_dsc, &iochan, 0, 0 );
	if( status != SS$_NORMAL )
		exit( status );

	status = SYS$QIOW( EFN, iochan, IO$_SENSEMODE, &iosb, 0, 0,
			  &oldmode, sizeof(oldmode), 0, 0, 0, 0 );
	if( status != SS$_NORMAL )
		exit( status );

	status = iosb[0] & 0xFFFF;
	if( status != SS$_NORMAL )
		exit( status );

	newmode[0] = oldmode[0];
	newmode[1] = oldmode[1];
	newmode[2] = oldmode[2] | TT2$M_EDIT;

	status = SYS$QIOW( EFN, iochan, IO$_SETMODE, &iosb, 0, 0,
			  &newmode, sizeof(newmode), 0, 0, 0, 0 );
	if( status != SS$_NORMAL )
		exit( status );

	status = iosb[0] & 0xFFFF;
	if( status != SS$_NORMAL )
		exit( status );

	/* declare the exit handler block */
	exit_handler_block.forward   = 0;
	exit_handler_block.address   = (unsigned long) &VMSexit;
	exit_handler_block.zero      = 0;
	exit_handler_block.condition = (unsigned long) &condition;
	status = sys$dclexh(&exit_handler_block);
	if (status != SS$_NORMAL)
		exit( status );

	/* set the AST */
	lib$disable_ctrl(&mask, &old_msk);
	trap_flag = TRUE;
	status = SYS$QIOW ( EFN, iochan,
			    IO$_SETMODE|IO$M_CTRLCAST|IO$M_CTRLYAST,
			    &iosb, 0, 0,
			    &cleanup_sig, SIGINT, 0, 0, 0, 0 );
	if ( status != SS$_NORMAL ) {
		lib$enable_ctrl(&old_msk);
		exit ( status );
	}
	return(0);
}	/*  ttopen  */

/*
 *	TTCLOSE --
 *		This function gets called just before we go back home
 *		to the command interpreter.  It puts the terminal back
 *		in a reasonable state.
 */

PUBLIC int ttclose()
{
	int	status;
	int	iosb[1];

	status = SYS$QIOW( EFN, iochan, IO$_SETMODE, &iosb, 0, 0,
			  &oldmode, sizeof(oldmode), 0, 0, 0, 0 );

	if( status != SS$_NORMAL || (iosb[0] & 0xFFFF) != SS$_NORMAL )
		exit( status );

	if (trap_flag) {
	    status = SYS$DASSGN (iochan);
	    status = lib$enable_ctrl(&old_msk);
	    trap_flag = FALSE;
	}
	return(0);
}	/*  ttclose  */

/*
 *	TTGETC --
 *		Read a character from the terminal, with NOECHO and NOFILTR.
 */

PUBLIC int ttgetc()
{
	int	status;
	int	iosb[2];
	int	term[2];

	while( ibufi >= nibuf ) {
		ibufi = 0;
		term[0] = 0;
		term[1] = 0;

		status = SYS$QIOW( EFN, iochan,
			     IO$_READLBLK|IO$M_TIMED|IO$M_NOECHO|IO$M_NOFILTR,
			     &iosb, 0, 0,
			     &ibuf, MAXIBUF, 0, term, 0, 0 );
		if( status != SS$_NORMAL )
			exit( status );

		status = iosb[0] & 0xFFFF;
		if( status != SS$_NORMAL && status != SS$_TIMEOUT )
			exit( status );

		nibuf = (iosb[0]>>16) + (iosb[1]>>16);		/* Huh?	 KAH */

		if( nibuf == 0 ) {
			status = SYS$QIOW( EFN, iochan,
				     IO$_READLBLK|IO$M_NOECHO|IO$M_NOFILTR,
				     &iosb, 0, 0, 
				     &ibuf, 1, 0, term, 0, 0 );
			if( status != SS$_NORMAL ||
			    (status = (iosb[0]&0xFFFF)) != SS$_NORMAL )
				exit( status );

			nibuf = (iosb[0]>>16) + (iosb[1]>>16);
		}
	}

	return( ibuf[ibufi++] & 0xFF );	  /* Allow multinational  */
}	/*  ttgetc  */

/*
 *	TYPAHEAD --
 *		Check to see if any characters are already in the
 *		keyboard buffer.  (Not used. -- Fote)
 */

PUBLIC int typahead()
{
	int	status;
	int	iosb[2];
	int	term[2];

	if( ibufi < nibuf )
		return( TRUE );

	ibufi = 0;
	term[0] = 0;
	term[1] = 0;

	status = SYS$QIOW( EFN, iochan,
			   IO$_READLBLK|IO$M_TIMED|IO$M_NOECHO|IO$M_NOFILTR,
			   &iosb, 0, 0,
			   &ibuf, MAXIBUF, 0, term, 0, 0 );
	if( status != SS$_NORMAL )
		exit( status );

	status = iosb[0] & 0xFFFF;
	if( status != SS$_NORMAL && status != SS$_TIMEOUT )
		exit( status );

	nibuf = (iosb[0]>>16) + (iosb[1]>>16);

	if( nibuf == 0 )
		return( FALSE );

	return( TRUE );			/* Allow multinational	*/
}	/*  typeahead  */


/*
 *	VSIGNAL -- Fote Macrides 29-Jun-1993
 *		Sets up AST for both Ctrl-C and Ctrl-Y, with system response
 *		 to Ctrl-T disabled.  If called with a sig other than SIGINT,
 *		 it will use the C library's system(sig, func).
 *              The equivalent of vsignal(SIGINT, cleanup_sig) is done on
 *               intialization by ttopen(), so don't do it again.
 *		vsignal(SIGINT, SIG_DFL) is treated as a call to ttclose().
 *              Call vsignal(SIGINT, SIG_IGN) before system() calls to
 *               enable Ctrl-C and Ctrl-Y in the subprocess, and then call
 *               vsignal(SIG_INT, cleanup_sig) on return from the subprocess.
 *		For func's which set flags and do not invoke an exit from
 *		 LYNX, the func should reassert itself.
 *              The VMS signal() calls do not fully emulate the Unix calls,
 *		 and vsignal() is just a "helper", also not a full emulation.
 */
#ifdef signal
#undef signal
#endif

PUBLIC void *vsignal (sig, func)
int sig;
void (*func)();
{
	int status;
	short iosb[4];
	static int SIG_IGN_flag;

	/* pass all signals other than SIGINT to signal() */
	if (sig != SIGINT) {
	    signal(sig, func);
	    return;
	}

	/* if func is SIG_DFL, treat it as ttclose() */
	if (func == SIG_DFL) {
	    ttclose();
	    return;
	}

	/* Clear any previous AST */
	if (trap_flag) {
	    status = SYS$DASSGN (iochan);
	    status = lib$enable_ctrl(&old_msk);
	    trap_flag = FALSE;
	}

	/* if func is SIG_IGN, leave the TT channel closed and the  */
	/* system response to interrupts enabled for system() calls */
	if (func == SIG_IGN)
	    return;

	/* if we get to here, we have a LYNX func, so set the AST */
	lib$disable_ctrl(&mask, &old_msk);
	trap_flag = TRUE;
	status = SYS$ASSIGN (&term_nam_dsc, &iochan, 0, 0 );
	status = SYS$QIOW ( EFN, iochan,
			    IO$_SETMODE|IO$M_CTRLCAST|IO$M_CTRLYAST,
			    &iosb, 0, 0,
			    func, SIGINT, 0, 0, 0, 0 );

}	/* vsignal */
#endif VMS

